Commit 1f0b10bd authored by Mike Danese's avatar Mike Danese

Merge pull request #19538 from mesosphere/jdef_mesos_026_compat

MESOS: compatibility w/ mesos v0.26
parents 87bce640 ad1803a4
...@@ -19,6 +19,7 @@ package mesos ...@@ -19,6 +19,7 @@ package mesos
import ( import (
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net" "net"
...@@ -37,7 +38,7 @@ import ( ...@@ -37,7 +38,7 @@ import (
const defaultClusterName = "mesos" const defaultClusterName = "mesos"
var noLeadingMasterError = fmt.Errorf("there is no current leading master available to query") var noLeadingMasterError = errors.New("there is no current leading master available to query")
type mesosClient struct { type mesosClient struct {
masterLock sync.RWMutex masterLock sync.RWMutex
...@@ -136,17 +137,11 @@ func createMesosClient( ...@@ -136,17 +137,11 @@ func createMesosClient(
client.state.refill = client.pollMasterForState client.state.refill = client.pollMasterForState
first := true first := true
if err := md.Detect(detector.OnMasterChanged(func(info *mesos.MasterInfo) { if err := md.Detect(detector.OnMasterChanged(func(info *mesos.MasterInfo) {
host, port := extractMasterAddress(info)
if len(host) > 0 {
client.masterLock.Lock() client.masterLock.Lock()
defer client.masterLock.Unlock() defer client.masterLock.Unlock()
if info == nil { client.master = fmt.Sprintf("%s:%d", host, port)
client.master = ""
} else if host := info.GetHostname(); host != "" {
client.master = host
} else {
client.master = unpackIPv4(info.GetIp())
}
if len(client.master) > 0 {
client.master = fmt.Sprintf("%s:%d", client.master, info.GetPort())
if first { if first {
first = false first = false
close(initialMaster) close(initialMaster)
...@@ -160,6 +155,28 @@ func createMesosClient( ...@@ -160,6 +155,28 @@ func createMesosClient(
return client, nil return client, nil
} }
func extractMasterAddress(info *mesos.MasterInfo) (host string, port int) {
if info != nil {
host = info.GetAddress().GetHostname()
if host == "" {
host = info.GetAddress().GetIp()
}
if host != "" {
// use port from Address
port = int(info.GetAddress().GetPort())
} else {
// deprecated: get host and port directly from MasterInfo (and not Address)
host = info.GetHostname()
if host == "" {
host = unpackIPv4(info.GetIp())
}
port = int(info.GetPort())
}
}
return
}
func unpackIPv4(ip uint32) string { func unpackIPv4(ip uint32) string {
octets := make([]byte, 4, 4) octets := make([]byte, 4, 4)
binary.BigEndian.PutUint32(octets, ip) binary.BigEndian.PutUint32(octets, ip)
...@@ -198,29 +215,60 @@ func (c *mesosClient) pollMasterForState(ctx context.Context) (*mesosState, erro ...@@ -198,29 +215,60 @@ func (c *mesosClient) pollMasterForState(ctx context.Context) (*mesosState, erro
//TODO(jdef) should not assume master uses http (what about https?) //TODO(jdef) should not assume master uses http (what about https?)
uri := fmt.Sprintf("http://%s/state.json", master) var state *mesosState
req, err := http.NewRequest("GET", uri, nil) successHandler := func(res *http.Response) error {
blob, err1 := ioutil.ReadAll(res.Body)
if err1 != nil {
return err1
}
log.V(3).Infof("Got mesos state, content length %v", len(blob))
state, err1 = parseMesosState(blob)
return err1
}
// thinking here is that we may get some other status codes from mesos at some point:
// - authentication
// - redirection (possibly from http to https)
// ...
for _, tt := range []struct {
uri string
handlers map[int]func(*http.Response) error
}{
{
uri: fmt.Sprintf("http://%s/state", master),
handlers: map[int]func(*http.Response) error{
200: successHandler,
},
},
{
uri: fmt.Sprintf("http://%s/state.json", master),
handlers: map[int]func(*http.Response) error{
200: successHandler,
},
},
} {
req, err := http.NewRequest("GET", tt.uri, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var state *mesosState
err = c.httpDo(ctx, req, func(res *http.Response, err error) error { err = c.httpDo(ctx, req, func(res *http.Response, err error) error {
if err != nil { if err != nil {
return err return err
} }
defer res.Body.Close() defer res.Body.Close()
if res.StatusCode != 200 { if handler, ok := tt.handlers[res.StatusCode]; ok {
return fmt.Errorf("HTTP request failed with code %d: %v", res.StatusCode, res.Status) err1 := handler(res)
}
blob, err1 := ioutil.ReadAll(res.Body)
if err1 != nil { if err1 != nil {
return err1 return err1
} }
log.V(3).Infof("Got mesos state, content length %v", len(blob)) }
state, err1 = parseMesosState(blob) // no handler for this error code, proceed to the next connection type
return err1 return nil
}) })
if state != nil || err != nil {
return state, err return state, err
}
}
return nil, errors.New("failed to sync with Mesos master")
} }
func parseMesosState(blob []byte) (*mesosState, error) { func parseMesosState(blob []byte) (*mesosState, error) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment