Skip to content
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
2 changes: 1 addition & 1 deletion go/logic/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ func (this *Migrator) initiateInspector() (err error) {
this.migrationContext.Log.Infof("Master found to be %+v", *this.migrationContext.ApplierConnectionConfig.ImpliedKey)
} else {
// Forced master host.
key, err := mysql.ParseRawInstanceKeyLoose(this.migrationContext.AssumeMasterHostname)
key, err := mysql.ParseInstanceKey(this.migrationContext.AssumeMasterHostname)
if err != nil {
return err
}
Expand Down
42 changes: 30 additions & 12 deletions go/mysql/instance_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package mysql

import (
"fmt"
"regexp"
"strconv"
"strings"
)
Expand All @@ -15,6 +16,13 @@ const (
DefaultInstancePort = 3306
)

var (
ipv4HostPortRegexp = regexp.MustCompile("^([^:]+):([0-9]+)$")
ipv4HostRegexp = regexp.MustCompile("^([^:]+)$")
ipv6HostPortRegexp = regexp.MustCompile("^\\[([:0-9a-fA-F]+)\\]:([0-9]+)$") // e.g. [2001:db8:1f70::999:de8:7648:6e8]:3308
ipv6HostRegexp = regexp.MustCompile("^([:0-9a-fA-F]+)$") // e.g. 2001:db8:1f70::999:de8:7648:6e8
)

// InstanceKey is an instance indicator, identified by hostname and port
type InstanceKey struct {
Hostname string
Expand All @@ -25,25 +33,35 @@ const detachHint = "//"

// ParseInstanceKey will parse an InstanceKey from a string representation such as 127.0.0.1:3306
func NewRawInstanceKey(hostPort string) (*InstanceKey, error) {
tokens := strings.SplitN(hostPort, ":", 2)
if len(tokens) != 2 {
return nil, fmt.Errorf("Cannot parse InstanceKey from %s. Expected format is host:port", hostPort)
hostname := ""
port := ""
if submatch := ipv4HostPortRegexp.FindStringSubmatch(hostPort); len(submatch) > 0 {
hostname = submatch[1]
port = submatch[2]
} else if submatch := ipv4HostRegexp.FindStringSubmatch(hostPort); len(submatch) > 0 {
hostname = submatch[1]
} else if submatch := ipv6HostPortRegexp.FindStringSubmatch(hostPort); len(submatch) > 0 {
hostname = submatch[1]
port = submatch[2]
} else if submatch := ipv6HostRegexp.FindStringSubmatch(hostPort); len(submatch) > 0 {
hostname = submatch[1]
} else {
return nil, fmt.Errorf("Cannot parse address: %s", hostPort)
}
instanceKey := &InstanceKey{Hostname: tokens[0]}
var err error
if instanceKey.Port, err = strconv.Atoi(tokens[1]); err != nil {
return instanceKey, fmt.Errorf("Invalid port: %s", tokens[1])
instanceKey := &InstanceKey{Hostname: hostname, Port: DefaultInstancePort}
if port != "" {
var err error
if instanceKey.Port, err = strconv.Atoi(port); err != nil {
return instanceKey, fmt.Errorf("Invalid port: %s", port)
}
}

return instanceKey, nil
}

// ParseRawInstanceKeyLoose will parse an InstanceKey from a string representation such as 127.0.0.1:3306.
// ParseInstanceKey will parse an InstanceKey from a string representation such as 127.0.0.1:3306.
// The port part is optional; there will be no name resolve
func ParseRawInstanceKeyLoose(hostPort string) (*InstanceKey, error) {
if !strings.Contains(hostPort, ":") {
return &InstanceKey{Hostname: hostPort, Port: DefaultInstancePort}, nil
}
func ParseInstanceKey(hostPort string) (*InstanceKey, error) {
return NewRawInstanceKey(hostPort)
}

Expand Down
2 changes: 1 addition & 1 deletion go/mysql/instance_key_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (this *InstanceKeyMap) ReadCommaDelimitedList(list string) error {
}
tokens := strings.Split(list, ",")
for _, token := range tokens {
key, err := ParseRawInstanceKeyLoose(token)
key, err := ParseInstanceKey(token)
if err != nil {
return err
}
Expand Down
74 changes: 74 additions & 0 deletions go/mysql/instance_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright 2016 GitHub Inc.
See https://github.com/github/gh-ost/blob/master/LICENSE
*/

package mysql

import (
"testing"

"github.com/outbrain/golib/log"
test "github.com/outbrain/golib/tests"
)

func init() {
log.SetLevel(log.ERROR)
}

func TestParseInstanceKey(t *testing.T) {
{
key, err := ParseInstanceKey("myhost:1234")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "myhost")
test.S(t).ExpectEquals(key.Port, 1234)
}
{
key, err := ParseInstanceKey("myhost")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "myhost")
test.S(t).ExpectEquals(key.Port, 3306)
}
{
key, err := ParseInstanceKey("10.0.0.3:3307")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "10.0.0.3")
test.S(t).ExpectEquals(key.Port, 3307)
}
{
key, err := ParseInstanceKey("10.0.0.3")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "10.0.0.3")
test.S(t).ExpectEquals(key.Port, 3306)
}
{
key, err := ParseInstanceKey("[2001:db8:1f70::999:de8:7648:6e8]:3308")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "2001:db8:1f70::999:de8:7648:6e8")
test.S(t).ExpectEquals(key.Port, 3308)
}
{
key, err := ParseInstanceKey("::1")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "::1")
test.S(t).ExpectEquals(key.Port, 3306)
}
{
key, err := ParseInstanceKey("0:0:0:0:0:0:0:0")
test.S(t).ExpectNil(err)
test.S(t).ExpectEquals(key.Hostname, "0:0:0:0:0:0:0:0")
test.S(t).ExpectEquals(key.Port, 3306)
}
{
_, err := ParseInstanceKey("[2001:xxxx:1f70::999:de8:7648:6e8]:3308")
test.S(t).ExpectNotNil(err)
}
{
_, err := ParseInstanceKey("10.0.0.4:")
test.S(t).ExpectNotNil(err)
}
{
_, err := ParseInstanceKey("10.0.0.4:5.6.7")
test.S(t).ExpectNotNil(err)
}
}