Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #430 from github/http-advertise
Browse files Browse the repository at this point in the history
Introducing HTTPAdvertise config
  • Loading branch information
Shlomi Noach authored Mar 7, 2018
2 parents 63277c8 + 1c9ec6a commit e2922c4
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 7 deletions.
14 changes: 13 additions & 1 deletion docs/configuration-raft.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,19 @@ as well as this:
],
```

If your orchestrator/raft nodes need to communicate via NAT gateways, you can additionally set "RaftAdvertise" to IP or hostname which other nodes should contact. Otherwise other nodes would try to talk to the "RaftBind" address and fail.
### NAT, firewalls, routing

If your orchestrator/raft nodes need to communicate via NAT gateways, you can additionally set:

- `"RaftAdvertise": "<ip.or.fqdn.visible.to.other.nodes>"`

to IP or hostname which other nodes should contact. Otherwise other nodes would try to talk to the "RaftBind" address and fail.

Raft nodes will reverse proxy HTTP requests to the leader. `orchestrator` will attempt to heuristically compute the leader's URL to which redirect requests. If behind NAT, rerouting ports etc., `orchestrator` may not be able to compute that URL. You may configure:

- `"HTTPAdvertise": "scheme://hostname:port"`

to explicitly specify where a node, assuming it were the leader, would be accessed through HTTP API. As example, you would: `"HTTPAdvertise": "http://my.public.hostname:3000"`

### Backend DB

Expand Down
30 changes: 27 additions & 3 deletions go/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package config
import (
"encoding/json"
"fmt"
"net/url"
"os"
"regexp"
"strings"
Expand Down Expand Up @@ -86,6 +87,7 @@ type Configuration struct {
EnableSyslog bool // Should logs be directed (in addition) to syslog daemon?
ListenAddress string // Where orchestrator HTTP should listen for TCP
ListenSocket string // Where orchestrator HTTP should listen for unix socket (default: empty; when given, TCP is disabled)
HTTPAdvertise string // optional, for raft setups, what is the HTTP address this node will advertise to its peers (potentially use where behind NAT or when rerouting ports; example: "http://11.22.33.44:3030")
AgentsServerPort string // port orchestrator agents talk back to
MySQLTopologyUser string
MySQLTopologyPassword string // my.cnf style configuration file from where to pick credentials. Expecting `user`, `password` under `[client]` section
Expand Down Expand Up @@ -266,6 +268,7 @@ func newConfiguration() *Configuration {
EnableSyslog: false,
ListenAddress: ":3000",
ListenSocket: "",
HTTPAdvertise: "",
AgentsServerPort: ":3001",
StatusEndpoint: "/api/status",
StatusOUVerify: false,
Expand Down Expand Up @@ -519,12 +522,15 @@ func (this *Configuration) postReadAdjustments() error {
if this.RemoteSSHForMasterFailover && this.RemoteSSHCommand == "" {
return fmt.Errorf("RemoteSSHCommand is required when RemoteSSHForMasterFailover is set")
}
if this.RaftAdvertise == "" {
this.RaftAdvertise = this.RaftBind
}
if this.RaftEnabled && this.RaftDataDir == "" {
return fmt.Errorf("RaftDataDir must be defined since raft is enabled (RaftEnabled)")
}
if this.RaftEnabled && this.RaftBind == "" {
return fmt.Errorf("RaftBind must be defined since raft is enabled (RaftEnabled)")
}
if this.RaftAdvertise == "" {
this.RaftAdvertise = this.RaftBind
}
if this.KVClusterMasterPrefix != "/" {
// "/" remains "/"
// "prefix" turns to "prefix/"
Expand All @@ -542,6 +548,24 @@ func (this *Configuration) postReadAdjustments() error {
this.DetectPseudoGTIDQuery = SelectTrueQuery
this.PseudoGTIDPreferIndependentMultiMatch = true
}
if this.HTTPAdvertise != "" {
u, err := url.Parse(this.HTTPAdvertise)
if err != nil {
return fmt.Errorf("Failed parsing HTTPAdvertise %s: %s", this.HTTPAdvertise, err.Error)
}
if u.Scheme == "" {
return fmt.Errorf("If specified, HTTPAdvertise must include scheme (http:// or https://)")
}
if u.Hostname() == "" {
return fmt.Errorf("If specified, HTTPAdvertise must include host name")
}
if u.Port() == "" {
return fmt.Errorf("If specified, HTTPAdvertise must include port number")
}
if u.Path != "" {
return fmt.Errorf("If specified, HTTPAdvertise must not specify a path")
}
}
return nil
}

Expand Down
65 changes: 65 additions & 0 deletions go/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,68 @@ func TestRecoveryPeriodBlock(t *testing.T) {
test.S(t).ExpectEquals(c.RecoveryPeriodBlockSeconds, 15)
}
}

func TestRaft(t *testing.T) {
{
c := newConfiguration()
c.RaftBind = "1.2.3.4:1008"
c.RaftDataDir = "/path/to/somewhere"
err := c.postReadAdjustments()
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(c.RaftAdvertise, c.RaftBind)
}
{
c := newConfiguration()
c.RaftEnabled = true
err := c.postReadAdjustments()
test.S(t).ExpectNotNil(err)
}
{
c := newConfiguration()
c.RaftEnabled = true
c.RaftDataDir = "/path/to/somewhere"
err := c.postReadAdjustments()
test.S(t).ExpectNil(err)
}
{
c := newConfiguration()
c.RaftEnabled = true
c.RaftDataDir = "/path/to/somewhere"
c.RaftBind = ""
err := c.postReadAdjustments()
test.S(t).ExpectNotNil(err)
}
}

func TestHttpAdvertise(t *testing.T) {
{
c := newConfiguration()
c.HTTPAdvertise = ""
err := c.postReadAdjustments()
test.S(t).ExpectNil(err)
}
{
c := newConfiguration()
c.HTTPAdvertise = "http://127.0.0.1:1234"
err := c.postReadAdjustments()
test.S(t).ExpectNil(err)
}
{
c := newConfiguration()
c.HTTPAdvertise = "http://127.0.0.1"
err := c.postReadAdjustments()
test.S(t).ExpectNotNil(err)
}
{
c := newConfiguration()
c.HTTPAdvertise = "127.0.0.1:1234"
err := c.postReadAdjustments()
test.S(t).ExpectNotNil(err)
}
{
c := newConfiguration()
c.HTTPAdvertise = "http://127.0.0.1:1234/mypath"
err := c.postReadAdjustments()
test.S(t).ExpectNotNil(err)
}
}
11 changes: 8 additions & 3 deletions go/raft/raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,22 @@ func FatalRaftError(err error) error {
}

func computeLeaderURI() (uri string, err error) {
protocol := "http"
if config.Config.HTTPAdvertise != "" {
// Explicitly given
return config.Config.HTTPAdvertise, nil
}
// Not explicitly given. Let's heuristically compute using RaftAdvertise
scheme := "http"
if config.Config.UseSSL {
protocol = "https"
scheme = "https"
}
hostname := config.Config.RaftAdvertise
listenTokens := strings.Split(config.Config.ListenAddress, ":")
if len(listenTokens) < 2 {
return uri, fmt.Errorf("computeLeaderURI: cannot determine listen port out of config.Config.ListenAddress: %+v", config.Config.ListenAddress)
}
port := listenTokens[1]
uri = fmt.Sprintf("%s://%s:%s", protocol, hostname, port)
uri = fmt.Sprintf("%s://%s:%s", scheme, hostname, port)
return uri, nil
}

Expand Down

0 comments on commit e2922c4

Please sign in to comment.