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

Introducing HTTPAdvertise config #430

Merged
merged 4 commits into from
Mar 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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