Skip to content

Commit ebb617c

Browse files
szabolcs-horvathkeyki
authored andcommitted
CB-28369: Add fallback to HTTP if target saltboot is not listening on the HTTPS port
1 parent e7a9c29 commit ebb617c

File tree

5 files changed

+455
-55
lines changed

5 files changed

+455
-55
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
BINARY=salt-bootstrap
22

3-
VERSION=0.14.0
3+
VERSION=0.14.1
44
BUILD_TIME=$(shell date +%FT%T)
55
LDFLAGS=-ldflags "-X github.com/hortonworks/salt-bootstrap/saltboot.Version=${VERSION} -X github.com/hortonworks/salt-bootstrap/saltboot.BuildTime=${BUILD_TIME}"
66
GOFILES_NOVENDOR = $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./.git/*")

saltboot/distributor.go

+43-26
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import (
44
"bytes"
55
"crypto/tls"
66
"encoding/json"
7+
"errors"
78
"io/ioutil"
89
"log"
910
"net/http"
1011
"strconv"
1112
"strings"
1213
"sync"
14+
"syscall"
1315

1416
"fmt"
1517
"io"
@@ -18,16 +20,16 @@ import (
1820
"github.com/hortonworks/salt-bootstrap/saltboot/model"
1921
)
2022

21-
func determineProtocol() string {
22-
if HttpsEnabled() {
23+
func determineProtocol(httpsEnabled bool) string {
24+
if httpsEnabled {
2325
return "https://"
2426
} else {
2527
return "http://"
2628
}
2729
}
2830

29-
func getHttpClient() *http.Client {
30-
if HttpsEnabled() {
31+
func getHttpClient(httpsEnabled bool) *http.Client {
32+
if httpsEnabled {
3133
return &http.Client{
3234
Transport: &http.Transport{
3335
TLSClientConfig: &tls.Config{
@@ -40,57 +42,71 @@ func getHttpClient() *http.Client {
4042
}
4143
}
4244

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+
4358
func DistributeRequest(clients []string, endpoint, user, pass string, requestBody RequestBody) <-chan model.Response {
44-
protocol := determineProtocol()
59+
httpsEnabled := HttpsEnabled()
60+
protocol := determineProtocol(httpsEnabled)
4561
var wg sync.WaitGroup
4662
wg.Add(len(clients))
4763
c := make(chan model.Response, len(clients))
4864

4965
for idx, client := range clients {
5066
go func(client string, index int) {
5167
defer wg.Done()
52-
log.Printf("[distribute] Send request to client: %s", client)
68+
log.Printf("[DistributeRequest] Send request to client: %s", client)
5369

5470
var clientAddr string
5571
if strings.Contains(client, ":") {
5672
clientAddr = client
5773
} else {
58-
clientAddr = client + ":" + strconv.Itoa(DetermineBootstrapPort())
74+
clientAddr = client + ":" + strconv.Itoa(DetermineBootstrapPort(httpsEnabled))
5975
}
6076

6177
var req *http.Request
6278
if len(requestBody.Signature) > 0 {
6379
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)
6581
req, _ = http.NewRequest("POST", protocol+clientAddr+endpoint+"?index="+indexString, bytes.NewBufferString(requestBody.SignedPayload))
6682
req.Header.Set(SIGNATURE, requestBody.Signature)
6783
} else {
68-
log.Printf("[distribute] Send plain request to client: %s", client)
84+
log.Printf("[DistributeRequest] Send plain request to client: %s", client)
6985
req, _ = http.NewRequest("POST", protocol+clientAddr+endpoint, bytes.NewBuffer(requestBody.PlainPayload))
7086
}
7187
req.Header.Set("Content-Type", "application/json")
7288
req.SetBasicAuth(user, pass)
7389

74-
httpClient := getHttpClient()
75-
resp, err := httpClient.Do(req)
90+
httpClient := getHttpClient(httpsEnabled)
91+
respHost, resp, err := sendRequestWithFallback(httpClient, req, httpsEnabled)
7692
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}
7995
return
8096
}
8197

8298
body, _ := ioutil.ReadAll(resp.Body)
8399
decoder := json.NewDecoder(strings.NewReader(string(body)))
84100
var response model.Response
85101
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())
87103
}
88-
response.Address = client
104+
response.Address = respHost
89105

90106
if response.StatusCode == 0 {
91107
response.StatusCode = resp.StatusCode
92108
}
93-
log.Printf("[distribute] Request to: %s result: %s", client, response.String())
109+
log.Printf("[DistributeRequest] Request to: %s result: %s", client, response.String())
94110
c <- response
95111
defer closeIt(resp.Body)
96112
}(client, idx)
@@ -105,7 +121,8 @@ func DistributeRequest(clients []string, endpoint, user, pass string, requestBod
105121
func DistributeFileUploadRequest(endpoint string, user string, pass string, targets []string, path string,
106122
permissions string, file multipart.File, header *multipart.FileHeader, signature string) <-chan model.Response {
107123

108-
protocol := determineProtocol()
124+
httpsEnabled := HttpsEnabled()
125+
protocol := determineProtocol(httpsEnabled)
109126
var wg sync.WaitGroup
110127
wg.Add(len(targets))
111128
c := make(chan model.Response, len(targets))
@@ -145,31 +162,31 @@ func DistributeFileUploadRequest(endpoint string, user string, pass string, targ
145162
if strings.Contains(target, ":") {
146163
targetAddress = target
147164
} else {
148-
targetAddress = target + ":" + strconv.Itoa(DetermineBootstrapPort())
165+
targetAddress = target + ":" + strconv.Itoa(DetermineBootstrapPort(httpsEnabled))
149166
}
150167

151168
req, err := http.NewRequest("POST", protocol+targetAddress+endpoint, bytes.NewReader(fileContent))
152169
req.Header.Set(SIGNATURE, signature)
153170
req.Header.Set("Content-Type", bodyWriter.FormDataContentType())
154171
req.SetBasicAuth(user, pass)
155172

156-
httpClient := getHttpClient()
157-
resp, err := httpClient.Do(req)
173+
httpClient := getHttpClient(httpsEnabled)
174+
respHost, resp, err := sendRequestWithFallback(httpClient, req, httpsEnabled)
158175
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}
161178
return
162179
}
163180

164181
body, _ := ioutil.ReadAll(resp.Body)
165182
defer closeIt(resp.Body)
166183
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}
169186
return
170187
} 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}
173190
}
174191
}(target, i)
175192
}

0 commit comments

Comments
 (0)