Skip to content

Commit

Permalink
Issue 364 (#391)
Browse files Browse the repository at this point in the history
* Switched over to using a buffer for stdout,stderr on execute #364 (#367)

Instead of using Combinedout, switched to using a pipe for stdout and stderr. It seems like running a command on HAProxy doesn't capture the entire stdout and stderr. This will ensure we get everything and see what is actually going if there is an error.

* Fixes #364

* Fixes #364

* Fixed #336

* Fix exit status on verify haproxy config

This commit will check for an exit status on verifying the haproxy.cfg. HAproxy may output warnings as an error, but overall it would be considered a valid text and wouldn't stop HAproxy from running.

* Removed obsolete test for pr #384
  • Loading branch information
vfarcic authored Dec 2, 2017
1 parent 3eb12d6 commit 7cdf978
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 21 deletions.
2 changes: 1 addition & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The following query parameters can be used only when `reqMode` is set to `http`
|outboundHostname|The hostname where the service is running, for instance on a separate swarm. If specified, the proxy will dispatch requests to that domain. The parameter can be prefixed with an index thus allowing definition of multiple destinations for a single service (e.g. `outboundHostname.1`, `outboundHostname.2`, and so on).<br>**Example:** `ecme.com`|
|pathType |The ACL derivative. Defaults to *path_beg*. See [HAProxy path](https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#7.3.6-path) for more info.<br>**Example:** `path_beg`|
|redirectFromDomain|If a request is sent to one of the domains in this list, it will be redirected to one of the values of the `serviceDomain`. Multiple domains can be separated with comma (e.g. `acme.com,something.acme.com`). The parameter can be prefixed with an index thus allowing definition of multiple destinations for a single service.<br>**Example:** `acme.com,something.acme.com`|
|redirectWhenHttpProto|**This parameter is temporarily disabled until the problems around it are solved**. Whether to redirect to https when X-Forwarded-Proto is set and the request is made over an HTTP port.<br>**Example:** `true`<br>**Default Value:** `false`|
|redirectWhenHttpProto|Whether to redirect to https when X-Forwarded-Proto is set and the request is made over an HTTP port.<br>**Example:** `true`<br>**Default Value:** `false`|
|serviceCert |Content of the PEM-encoded certificate to be used by the proxy when serving traffic over SSL.|
|serviceDomain |The domain of the service. If set, the proxy will allow access only to requests coming to that domain. Multiple domains can be separated with comma (e.g. `acme.com,something.else.com`). The parameter can be prefixed with an index thus allowing definition of multiple destinations for a single service (e.g. `serviceDomain.1`, `serviceDomain.2`, and so on). Asterisk sign can be placed to beginning of value and in this case **serviceDomainAlgo** parameter will be **replaced** to `hdr_end(host)`. This parameter is **mandatory** if `servicePath` is not specified.<br>**Example:** `ecme.com`|
|serviceDomainAlgo|Algorithm that should be applied to domain ACLs. Any ACL works only with one flag: `-i : ignore case during matching of all subsequent patterns`. If not set, the value of the environment variable `SERVICE_DOMAIN_ALGO` will be used instead. If defaults to `hdr_beg(host)`<br>**Examples:**<br>`hdr(host)`: matches only if domain is the same as `serviceDomain`<br>`hdr_dom(host)`: matches the specified `serviceDomain` and any subdomain (a string either isolated or delimited by dots). **Example:** if `hdr_dom(host)` contains `www.ecme.com` and `serviceDomain` equals `ecme.com` the rule will be passed.<br>`req.ssl_sni`: matches Server Name TLS extension|
Expand Down
42 changes: 32 additions & 10 deletions proxy/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,41 @@ import (
var haProxyCmd = "haproxy"

var cmdRunHa = func(args []string) error {
var stdoutBuf, stderrBuf bytes.Buffer
cmd := exec.Command(haProxyCmd, args...)
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
err := cmd.Run()
var stdoutBuf, stderrBuf bytes.Buffer
cmd := exec.Command(haProxyCmd, args...)

stdOut, stdErr := stdoutBuf.String(), stderrBuf.String()
stdoutIn, _ := cmd.StdoutPipe()
stderrIn, _ := cmd.StderrPipe()

if strings.Contains(stdOut, "could not resolve address") || stdErr != "" || err != nil {
return fmt.Errorf("out:\n%s\nerr:\n%s\n", stdOut, stdErr)
}
stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
stderr := io.MultiWriter(os.Stderr, &stderrBuf)
cmd.Start()

go func() {
io.Copy(stdout, stdoutIn)
}()

go func() {
io.Copy(stderr, stderrIn)
}()

err := cmd.Wait()

outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
combinedOut := fmt.Sprintf("\nstdout:\n%s\nstderr:\n%s\n", outStr, errStr)

return nil
if exitError, ok := err.(*exec.ExitError); ok {
waitStatus := exitError.Sys().(syscall.WaitStatus)
fmt.Printf("Exit Status: %s\n", []byte(fmt.Sprintf("%d", waitStatus.ExitStatus())))
return fmt.Errorf(combinedOut)
}

if errStr != "" {
fmt.Println("The configuration file is valid, but there still may be a misconfiguration",
"somewhere that will give unexpected results, please verify:", combinedOut)
}

return nil
}

var cmdValidateHa = func(args []string) error {
Expand Down
12 changes: 2 additions & 10 deletions proxy/util_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package proxy

import (
"github.com/stretchr/testify/suite"
"os"
"testing"

"github.com/stretchr/testify/suite"
)

type UtilTestSuite struct {
Expand All @@ -28,15 +29,6 @@ func (s *UtilTestSuite) Test_HaProxyCmd_DoesNotReturnErrorWhenStdErrIsEmpty() {
s.NoError(err)
}

func (s *UtilTestSuite) Test_HaProxyCmd_ReturnsError_WhenOutputContainsCouldNotResolveAddress() {
haProxyCmdOrig := haProxyCmd
defer func() { haProxyCmd = haProxyCmdOrig }()
haProxyCmd = "echo"
err := cmdRunHa([]string{"'I really could not resolve address and something else'"})

s.Error(err)
}

func (s *UtilTestSuite) Test_HaProxyCmd_ReturnsError_WhenStdErrIsNotEmpty() {
haProxyCmdOrig := haProxyCmd
defer func() { haProxyCmd = haProxyCmdOrig }()
Expand Down

0 comments on commit 7cdf978

Please sign in to comment.