@@ -4,12 +4,14 @@ import (
4
4
"bytes"
5
5
"crypto/tls"
6
6
"encoding/json"
7
+ "errors"
7
8
"io/ioutil"
8
9
"log"
9
10
"net/http"
10
11
"strconv"
11
12
"strings"
12
13
"sync"
14
+ "syscall"
13
15
14
16
"fmt"
15
17
"io"
@@ -18,16 +20,16 @@ import (
18
20
"github.com/hortonworks/salt-bootstrap/saltboot/model"
19
21
)
20
22
21
- func determineProtocol () string {
22
- if HttpsEnabled () {
23
+ func determineProtocol (httpsEnabled bool ) string {
24
+ if httpsEnabled {
23
25
return "https://"
24
26
} else {
25
27
return "http://"
26
28
}
27
29
}
28
30
29
- func getHttpClient () * http.Client {
30
- if HttpsEnabled () {
31
+ func getHttpClient (httpsEnabled bool ) * http.Client {
32
+ if httpsEnabled {
31
33
return & http.Client {
32
34
Transport : & http.Transport {
33
35
TLSClientConfig : & tls.Config {
@@ -40,57 +42,71 @@ func getHttpClient() *http.Client {
40
42
}
41
43
}
42
44
45
+ func sendRequestWithFallback (httpClient * http.Client , request * http.Request , httpsEnabled bool ) (string , * http.Response , error ) {
46
+ resp , err := httpClient .Do (request )
47
+ if httpsEnabled && err != nil && errors .Is (err , syscall .ECONNREFUSED ) {
48
+ log .Printf ("[sendRequestWithFallback] Could not reach the target using HTTPS. Falling back to HTTP." )
49
+ newRequest := request .Clone (request .Context ())
50
+ newRequest .URL .Scheme = "http"
51
+ newRequest .URL .Host = newRequest .URL .Hostname () + ":" + strconv .Itoa (DetermineHttpPort ())
52
+ resp , err = httpClient .Do (newRequest )
53
+ return newRequest .URL .Host , resp , err
54
+ }
55
+ return request .URL .Host , resp , err
56
+ }
57
+
43
58
func DistributeRequest (clients []string , endpoint , user , pass string , requestBody RequestBody ) <- chan model.Response {
44
- protocol := determineProtocol ()
59
+ httpsEnabled := HttpsEnabled ()
60
+ protocol := determineProtocol (httpsEnabled )
45
61
var wg sync.WaitGroup
46
62
wg .Add (len (clients ))
47
63
c := make (chan model.Response , len (clients ))
48
64
49
65
for idx , client := range clients {
50
66
go func (client string , index int ) {
51
67
defer wg .Done ()
52
- log .Printf ("[distribute ] Send request to client: %s" , client )
68
+ log .Printf ("[DistributeRequest ] Send request to client: %s" , client )
53
69
54
70
var clientAddr string
55
71
if strings .Contains (client , ":" ) {
56
72
clientAddr = client
57
73
} else {
58
- clientAddr = client + ":" + strconv .Itoa (DetermineBootstrapPort ())
74
+ clientAddr = client + ":" + strconv .Itoa (DetermineBootstrapPort (httpsEnabled ))
59
75
}
60
76
61
77
var req * http.Request
62
78
if len (requestBody .Signature ) > 0 {
63
79
indexString := strconv .Itoa (index )
64
- log .Printf ("[distribute ] Send signed request to client: %s with index: %s" , client , indexString )
80
+ log .Printf ("[DistributeRequest ] Send signed request to client: %s with index: %s" , client , indexString )
65
81
req , _ = http .NewRequest ("POST" , protocol + clientAddr + endpoint + "?index=" + indexString , bytes .NewBufferString (requestBody .SignedPayload ))
66
82
req .Header .Set (SIGNATURE , requestBody .Signature )
67
83
} else {
68
- log .Printf ("[distribute ] Send plain request to client: %s" , client )
84
+ log .Printf ("[DistributeRequest ] Send plain request to client: %s" , client )
69
85
req , _ = http .NewRequest ("POST" , protocol + clientAddr + endpoint , bytes .NewBuffer (requestBody .PlainPayload ))
70
86
}
71
87
req .Header .Set ("Content-Type" , "application/json" )
72
88
req .SetBasicAuth (user , pass )
73
89
74
- httpClient := getHttpClient ()
75
- resp , err := httpClient . Do ( req )
90
+ httpClient := getHttpClient (httpsEnabled )
91
+ respHost , resp , err := sendRequestWithFallback ( httpClient , req , httpsEnabled )
76
92
if err != nil {
77
- log .Printf ("[distribute ] [ERROR] Failed to send request to: %s, error: %s" , client , err .Error ())
78
- c <- model.Response {StatusCode : http .StatusInternalServerError , ErrorText : err .Error (), Address : client }
93
+ log .Printf ("[DistributeRequest ] [ERROR] Failed to send request to: %s, error: %s" , client , err .Error ())
94
+ c <- model.Response {StatusCode : http .StatusInternalServerError , ErrorText : err .Error (), Address : respHost }
79
95
return
80
96
}
81
97
82
98
body , _ := ioutil .ReadAll (resp .Body )
83
99
decoder := json .NewDecoder (strings .NewReader (string (body )))
84
100
var response model.Response
85
101
if err := decoder .Decode (& response ); err != nil {
86
- log .Printf ("[distribute ] [ERROR] Failed to decode response, error: %s" , err .Error ())
102
+ log .Printf ("[DistributeRequest ] [ERROR] Failed to decode response, error: %s" , err .Error ())
87
103
}
88
- response .Address = client
104
+ response .Address = respHost
89
105
90
106
if response .StatusCode == 0 {
91
107
response .StatusCode = resp .StatusCode
92
108
}
93
- log .Printf ("[distribute ] Request to: %s result: %s" , client , response .String ())
109
+ log .Printf ("[DistributeRequest ] Request to: %s result: %s" , client , response .String ())
94
110
c <- response
95
111
defer closeIt (resp .Body )
96
112
}(client , idx )
@@ -105,7 +121,8 @@ func DistributeRequest(clients []string, endpoint, user, pass string, requestBod
105
121
func DistributeFileUploadRequest (endpoint string , user string , pass string , targets []string , path string ,
106
122
permissions string , file multipart.File , header * multipart.FileHeader , signature string ) <- chan model.Response {
107
123
108
- protocol := determineProtocol ()
124
+ httpsEnabled := HttpsEnabled ()
125
+ protocol := determineProtocol (httpsEnabled )
109
126
var wg sync.WaitGroup
110
127
wg .Add (len (targets ))
111
128
c := make (chan model.Response , len (targets ))
@@ -145,31 +162,31 @@ func DistributeFileUploadRequest(endpoint string, user string, pass string, targ
145
162
if strings .Contains (target , ":" ) {
146
163
targetAddress = target
147
164
} else {
148
- targetAddress = target + ":" + strconv .Itoa (DetermineBootstrapPort ())
165
+ targetAddress = target + ":" + strconv .Itoa (DetermineBootstrapPort (httpsEnabled ))
149
166
}
150
167
151
168
req , err := http .NewRequest ("POST" , protocol + targetAddress + endpoint , bytes .NewReader (fileContent ))
152
169
req .Header .Set (SIGNATURE , signature )
153
170
req .Header .Set ("Content-Type" , bodyWriter .FormDataContentType ())
154
171
req .SetBasicAuth (user , pass )
155
172
156
- httpClient := getHttpClient ()
157
- resp , err := httpClient . Do ( req )
173
+ httpClient := getHttpClient (httpsEnabled )
174
+ respHost , resp , err := sendRequestWithFallback ( httpClient , req , httpsEnabled )
158
175
if err != nil {
159
- log .Printf ("[DistributeFileUploadRequest] [ERROR] Failed to send request to: %s, error: %s" , target , err .Error ())
160
- c <- model.Response {StatusCode : http .StatusInternalServerError , ErrorText : err .Error (), Address : target }
176
+ log .Printf ("[DistributeFileUploadRequest] [ERROR] Failed to send request to: %s, error: %s" , respHost , err .Error ())
177
+ c <- model.Response {StatusCode : http .StatusInternalServerError , ErrorText : err .Error (), Address : respHost }
161
178
return
162
179
}
163
180
164
181
body , _ := ioutil .ReadAll (resp .Body )
165
182
defer closeIt (resp .Body )
166
183
if resp .StatusCode != http .StatusCreated {
167
- log .Printf ("[DistributeFileUploadRequest] Error response from: %s, error: %s" , target , body )
168
- c <- model.Response {StatusCode : resp .StatusCode , ErrorText : string (body ), Address : target }
184
+ log .Printf ("[DistributeFileUploadRequest] Error response from: %s, error: %s" , respHost , body )
185
+ c <- model.Response {StatusCode : resp .StatusCode , ErrorText : string (body ), Address : respHost }
169
186
return
170
187
} else {
171
- log .Printf ("[DistributeFileUploadRequest] Request to: %s result: %s" , target , body )
172
- c <- model.Response {StatusCode : http .StatusCreated , Status : string (body ), Address : target }
188
+ log .Printf ("[DistributeFileUploadRequest] Request to: %s result: %s" , respHost , body )
189
+ c <- model.Response {StatusCode : http .StatusCreated , Status : string (body ), Address : respHost }
173
190
}
174
191
}(target , i )
175
192
}
0 commit comments