Skip to content

Commit

Permalink
Fixes for tls-no-verify
Browse files Browse the repository at this point in the history
1. fix bug where `invoke` command was ignoring the --tls-no-verify
command line argument

2. add --tls-no-verify command line argument to the `remove` command

3. fix bug where `login` does not respect environment proxy variable `http_proxy`

4. add better error message if login fails, useful to explain certificate errors etc...

5. `deploy` command not respecting environment proxy variable `http_proxy` during a replace

6. add default time out const for majority of functions

7. make func `makeHTTPClientWithDisableKeepAlives` private not used outside of proxy package

8. version supports basic auth

Signed-off-by: Edward Wilde <[email protected]>
  • Loading branch information
ewilde authored and alexellis committed Nov 10, 2018
1 parent 904c148 commit b24c576
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 48 deletions.
1 change: 1 addition & 0 deletions commands/faas.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (
image string
imagePrefix string
language string
tlsInsecure bool
)

var stat = func(filename string) (os.FileInfo, error) {
Expand Down
16 changes: 5 additions & 11 deletions commands/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
package commands

import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"

"github.com/openfaas/faas-cli/proxy"

"github.com/openfaas/faas-cli/config"
"github.com/spf13/cobra"
)
Expand All @@ -20,7 +21,6 @@ var (
username string
password string
passwordStdin bool
tlsInsecure bool
)

func init() {
Expand Down Expand Up @@ -99,14 +99,8 @@ func runLogin(cmd *cobra.Command, args []string) error {
}

func validateLogin(gatewayURL string, user string, pass string) error {
tr := &http.Transport{
DisableKeepAlives: false,
TLSClientConfig: &tls.Config{InsecureSkipVerify: tlsInsecure},
}
client := &http.Client{
Transport: tr,
Timeout: time.Duration(5 * time.Second),
}
timeout := time.Duration(5 * time.Second)
client := proxy.MakeHTTPClient(&timeout, tlsInsecure)

req, err := http.NewRequest("GET", gatewayURL+"/system/functions", nil)
if err != nil {
Expand All @@ -116,7 +110,7 @@ func validateLogin(gatewayURL string, user string, pass string) error {
req.SetBasicAuth(user, pass)
res, err := client.Do(req)
if err != nil {
return fmt.Errorf("cannot connect to OpenFaaS on URL: %s", gatewayURL)
return fmt.Errorf("cannot connect to OpenFaaS on URL: %s. %v", gatewayURL, err)
}

if res.Body != nil {
Expand Down
5 changes: 3 additions & 2 deletions commands/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
func init() {
// Setup flags that are used by multiple commands (variables defined in faas.go)
removeCmd.Flags().StringVarP(&gateway, "gateway", "g", defaultGateway, "Gateway URL starting with http(s)://")
removeCmd.Flags().BoolVar(&tlsInsecure, "tls-no-verify", false, "Disable TLS validation")

faasCmd.AddCommand(removeCmd)
}
Expand Down Expand Up @@ -64,7 +65,7 @@ func runDelete(cmd *cobra.Command, args []string) error {
function.Name = k
fmt.Printf("Deleting: %s.\n", function.Name)

proxy.DeleteFunction(gatewayAddress, function.Name)
proxy.DeleteFunction(gatewayAddress, function.Name, tlsInsecure)
}
} else {
if len(args) < 1 {
Expand All @@ -73,7 +74,7 @@ func runDelete(cmd *cobra.Command, args []string) error {

functionName = args[0]
fmt.Printf("Deleting: %s.\n", functionName)
proxy.DeleteFunction(gatewayAddress, functionName)
proxy.DeleteFunction(gatewayAddress, functionName, tlsInsecure)
}

return nil
Expand Down
4 changes: 2 additions & 2 deletions proxy/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import (
)

// DeleteFunction delete a function from the FaaS server
func DeleteFunction(gateway string, functionName string) error {
func DeleteFunction(gateway string, functionName string, tlsInsecure bool) error {
gateway = strings.TrimRight(gateway, "/")
delReq := requests.DeleteFunctionRequest{FunctionName: functionName}
reqBytes, _ := json.Marshal(&delReq)
reader := bytes.NewReader(reqBytes)

c := http.Client{}
c := MakeHTTPClient(&defaultCommandTimeout, tlsInsecure)
req, err := http.NewRequest("DELETE", gateway+"/system/functions", reader)
if err != nil {
fmt.Println(err)
Expand Down
8 changes: 4 additions & 4 deletions proxy/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func Test_DeleteFunction(t *testing.T) {
defer s.Close()

stdout := test.CaptureStdout(func() {
DeleteFunction(s.URL, "function-to-delete")
DeleteFunction(s.URL, "function-to-delete", false)
})

r := regexp.MustCompile(`(?m:Removing old function.)`)
Expand All @@ -33,7 +33,7 @@ func Test_DeleteFunction_404(t *testing.T) {
defer s.Close()

stdout := test.CaptureStdout(func() {
DeleteFunction(s.URL, "function-to-delete")
DeleteFunction(s.URL, "function-to-delete", false)
})

r := regexp.MustCompile(`(?m:No existing function to remove)`)
Expand All @@ -47,7 +47,7 @@ func Test_DeleteFunction_Not2xxAnd404(t *testing.T) {
defer s.Close()

stdout := test.CaptureStdout(func() {
DeleteFunction(s.URL, "function-to-delete")
DeleteFunction(s.URL, "function-to-delete", false)
})

r := regexp.MustCompile(`(?m:Server returned unexpected status code)`)
Expand All @@ -60,7 +60,7 @@ func Test_DeleteFunction_MissingURLPrefix(t *testing.T) {
url := "127.0.0.1:8080"

stdout := test.CaptureStdout(func() {
DeleteFunction(url, "function-to-delete")
DeleteFunction(url, "function-to-delete", false)
})

expectedErrMsg := "first path segment in URL cannot contain colon"
Expand Down
9 changes: 6 additions & 3 deletions proxy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import (
"github.com/openfaas/faas/gateway/requests"
)

var (
defaultCommandTimeout = 60 * time.Second
)

// FunctionResourceRequest defines a request to set function resources
type FunctionResourceRequest struct {
Limits *stack.FunctionResources
Expand Down Expand Up @@ -83,7 +87,7 @@ func Deploy(spec *DeployFunctionSpec, update bool, warnInsecureGateway bool) (in
gateway := strings.TrimRight(spec.Gateway, "/")

if spec.Replace {
DeleteFunction(gateway, spec.FunctionName)
DeleteFunction(gateway, spec.FunctionName, spec.TLSInsecure)
}

req := requests.CreateFunctionRequest{
Expand Down Expand Up @@ -133,8 +137,7 @@ func Deploy(spec *DeployFunctionSpec, update bool, warnInsecureGateway bool) (in
reader := bytes.NewReader(reqBytes)
var request *http.Request

timeout := 60 * time.Second
client := MakeHTTPClient(&timeout, spec.TLSInsecure)
client := MakeHTTPClient(&defaultCommandTimeout, spec.TLSInsecure)

method := http.MethodPost
// "application/json"
Expand Down
4 changes: 1 addition & 3 deletions proxy/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"net/http"
"net/url"
"path"
"time"

"github.com/openfaas/faas/gateway/requests"
)
Expand All @@ -19,8 +18,7 @@ import (
func GetFunctionInfo(gateway string, functionName string, tlsInsecure bool) (requests.Function, error) {
var result requests.Function

timeout := 60 * time.Second
client := MakeHTTPClient(&timeout, tlsInsecure)
client := MakeHTTPClient(&defaultCommandTimeout, tlsInsecure)

gatewayURL, err := url.Parse(gateway)
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions proxy/invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ func InvokeFunction(gateway string, name string, bytesIn *[]byte, contentType st

reader := bytes.NewReader(*bytesIn)

var timeout *time.Duration
disableKeepAlives := false
client := MakeHTTPClientWithDisableKeepAlives(timeout, tlsInsecure, &disableKeepAlives)
var disableFunctionTimeout *time.Duration
client := MakeHTTPClient(disableFunctionTimeout, tlsInsecure)

qs, qsErr := buildQueryString(query)
if qsErr != nil {
Expand Down
4 changes: 1 addition & 3 deletions proxy/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"io/ioutil"
"net/http"
"strings"
"time"

"github.com/openfaas/faas/gateway/requests"
)
Expand All @@ -20,8 +19,7 @@ func ListFunctions(gateway string, tlsInsecure bool) ([]requests.Function, error
var results []requests.Function

gateway = strings.TrimRight(gateway, "/")
timeout := 60 * time.Second
client := MakeHTTPClient(&timeout, tlsInsecure)
client := MakeHTTPClient(&defaultCommandTimeout, tlsInsecure)

getRequest, err := http.NewRequest(http.MethodGet, gateway+"/system/functions", nil)
SetAuth(getRequest, gateway)
Expand Down
41 changes: 24 additions & 17 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,39 @@ import (
"time"
)

// MakeHTTPClientWithDisableKeepAlives makes a HTTP client with good defaults for timeouts.
func MakeHTTPClientWithDisableKeepAlives(timeout *time.Duration, tlsInsecure bool, disableKeepAlives *bool) http.Client {
if timeout != nil {
// makeHTTPClientWithDisableKeepAlives makes a HTTP client with good defaults for timeouts.
func makeHTTPClientWithDisableKeepAlives(timeout *time.Duration, tlsInsecure bool, disableKeepAlives bool) http.Client {
client := http.Client{}

if timeout != nil || tlsInsecure {
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Proxy: http.ProxyFromEnvironment,
DisableKeepAlives: disableKeepAlives,
}

if timeout != nil {
client.Timeout = *timeout
tr.DialContext = (&net.Dialer{
Timeout: *timeout,
}).DialContext,
}).DialContext

IdleConnTimeout: 120 * time.Millisecond,
ExpectContinueTimeout: 1500 * time.Millisecond,
TLSClientConfig: &tls.Config{InsecureSkipVerify: tlsInsecure},
}
if disableKeepAlives != nil {
tr.DisableKeepAlives = *disableKeepAlives
tr.IdleConnTimeout = 120 * time.Millisecond
tr.ExpectContinueTimeout = 1500 * time.Millisecond
}

return http.Client{
Timeout: *timeout,
Transport: tr,
if tlsInsecure {
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: tlsInsecure}
}

tr.DisableKeepAlives = disableKeepAlives

client.Transport = tr
}
return http.Client{}

return client
}

// MakeHTTPClient makes a HTTP client with good defaults for timeouts.
func MakeHTTPClient(timeout *time.Duration, tlsInsecure bool) http.Client {
return MakeHTTPClientWithDisableKeepAlives(timeout, tlsInsecure, nil)
return makeHTTPClientWithDisableKeepAlives(timeout, tlsInsecure, false)
}
78 changes: 78 additions & 0 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package proxy

import (
"net/http"
"testing"
"time"
)

func Test_MakeHTTPClientWithDisableKeepAlives_(t *testing.T) {
cases := []struct {
name string
timeout *time.Duration
tlsInsecure bool
disableKeepAlives bool
match func(http.Client, *http.Transport) bool
}{
{name: "no timeout, secure, keep-alive", timeout: nil, tlsInsecure: false, disableKeepAlives: false, match: func(client http.Client, transport *http.Transport) bool {
return transport == nil
}},
{name: "no timeout, insecure, keep-alive", timeout: nil, tlsInsecure: true, disableKeepAlives: false, match: func(client http.Client, transport *http.Transport) bool {
return transport != nil &&
transport.TLSClientConfig.InsecureSkipVerify &&
transport.DisableKeepAlives == false &&
transport.Proxy != nil
}},
{name: "no timeout, insecure, disable keep-alive", timeout: nil, tlsInsecure: true, disableKeepAlives: true, match: func(client http.Client, transport *http.Transport) bool {
return transport != nil &&
transport.TLSClientConfig.InsecureSkipVerify &&
transport.DisableKeepAlives == true &&
transport.Proxy != nil
}},
{name: "timeout, secure, keep-alive", timeout: durationPtr(time.Second * 30), tlsInsecure: false, disableKeepAlives: false, match: func(client http.Client, transport *http.Transport) bool {
return client.Timeout == time.Second*30 &&
transport != nil &&
transport.DialContext != nil &&
transport.TLSClientConfig == nil &&
transport.DisableKeepAlives == false &&
transport.Proxy != nil
}},
{name: "timeout, secure, disable keep-alive", timeout: durationPtr(time.Second * 30), tlsInsecure: false, disableKeepAlives: true, match: func(client http.Client, transport *http.Transport) bool {
return client.Timeout == time.Second*30 &&
transport != nil &&
transport.DialContext != nil &&
transport.TLSClientConfig == nil &&
transport.DisableKeepAlives == true &&
transport.Proxy != nil
}},
{name: "timeout, insecure, disable keep-alive", timeout: durationPtr(time.Second * 30), tlsInsecure: true, disableKeepAlives: true, match: func(client http.Client, transport *http.Transport) bool {
return client.Timeout == time.Second*30 &&
transport != nil &&
transport.DialContext != nil &&
transport.TLSClientConfig.InsecureSkipVerify &&
transport.DisableKeepAlives == true &&
transport.Proxy != nil
}},
}

for _, v := range cases {
t.Run(v.name, func(t *testing.T) {
client := makeHTTPClientWithDisableKeepAlives(v.timeout, v.tlsInsecure, v.disableKeepAlives)
var transport *http.Transport
if client.Transport != nil {
transport = client.Transport.(*http.Transport)
}
if !v.match(client, transport) {
t.Logf("%s did not match", v.name)
t.Fail()
}
})
}
}

func durationPtr(duration time.Duration) *time.Duration {
return &duration
}
2 changes: 2 additions & 0 deletions proxy/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ func GetSystemInfo(gateway string, tlsInsecure bool) (map[string]interface{}, er
return nil, fmt.Errorf("invalid HTTP method or invalid URL")
}

SetAuth(req, gateway)

response, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("cannot connect to OpenFaaS on URL: %s", gateway)
Expand Down

0 comments on commit b24c576

Please sign in to comment.