Upgrade go-marathon to dd6cbd4.
Fixes a problem with UnreachableStrategy being available now in two type-incompatible formats (object and string). We also upgrade the transitive dependency github.com/donovanhide/eventsource.
This commit is contained in:
parent
7a34303593
commit
9fbe21c534
9 changed files with 206 additions and 48 deletions
15
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
15
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
|
@ -150,8 +150,6 @@ type Marathon interface {
|
|||
}
|
||||
|
||||
var (
|
||||
// ErrInvalidResponse is thrown when marathon responds with invalid or error response
|
||||
ErrInvalidResponse = errors.New("invalid response from Marathon")
|
||||
// ErrMarathonDown is thrown when all the marathon endpoints are down
|
||||
ErrMarathonDown = errors.New("all the Marathon hosts are presently down")
|
||||
// ErrTimeoutError is thrown when the operation has timed out
|
||||
|
@ -190,6 +188,11 @@ type httpClient struct {
|
|||
config Config
|
||||
}
|
||||
|
||||
// newRequestError signals that creating a new http.Request failed
|
||||
type newRequestError struct {
|
||||
error
|
||||
}
|
||||
|
||||
// NewClient creates a new marathon client
|
||||
// config: the configuration to use
|
||||
func NewClient(config Config) (Marathon, error) {
|
||||
|
@ -298,8 +301,7 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
|||
if response.StatusCode >= 200 && response.StatusCode <= 299 {
|
||||
if result != nil {
|
||||
if err := json.Unmarshal(respBody, result); err != nil {
|
||||
r.debugLog.Printf("apiCall(): failed to unmarshall the response from marathon, error: %s\n", err)
|
||||
return ErrInvalidResponse
|
||||
return fmt.Errorf("failed to unmarshal response from Marathon: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -317,7 +319,8 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
|||
}
|
||||
}
|
||||
|
||||
// buildAPIRequest creates a default API request
|
||||
// buildAPIRequest creates a default API request.
|
||||
// It fails when there is no available member in the cluster anymore or when the request can not be built.
|
||||
func (r *marathonClient) buildAPIRequest(method, path string, reader io.Reader) (request *http.Request, member string, err error) {
|
||||
// Grab a member from the cluster
|
||||
member, err = r.hosts.getMember()
|
||||
|
@ -328,7 +331,7 @@ func (r *marathonClient) buildAPIRequest(method, path string, reader io.Reader)
|
|||
// Build the HTTP request to Marathon
|
||||
request, err = r.client.buildMarathonRequest(method, member, path, reader)
|
||||
if err != nil {
|
||||
return nil, member, err
|
||||
return nil, member, newRequestError{err}
|
||||
}
|
||||
return request, member, nil
|
||||
}
|
||||
|
|
8
vendor/github.com/gambol99/go-marathon/group.go
generated
vendored
8
vendor/github.com/gambol99/go-marathon/group.go
generated
vendored
|
@ -209,7 +209,9 @@ func (r *marathonClient) WaitOnGroup(name string, timeout time.Duration) error {
|
|||
func (r *marathonClient) DeleteGroup(name string, force bool) (*DeploymentID, error) {
|
||||
version := new(DeploymentID)
|
||||
path := fmt.Sprintf("%s/%s", marathonAPIGroups, trimRootPath(name))
|
||||
path = buildPathWithForceParam(path, force)
|
||||
if force {
|
||||
path += "?force=true"
|
||||
}
|
||||
if err := r.apiDelete(path, nil, version); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -224,7 +226,9 @@ func (r *marathonClient) DeleteGroup(name string, force bool) (*DeploymentID, er
|
|||
func (r *marathonClient) UpdateGroup(name string, group *Group, force bool) (*DeploymentID, error) {
|
||||
deploymentID := new(DeploymentID)
|
||||
path := fmt.Sprintf("%s/%s", marathonAPIGroups, trimRootPath(name))
|
||||
path = buildPathWithForceParam(path, force)
|
||||
if force {
|
||||
path += "?force=true"
|
||||
}
|
||||
if err := r.apiPut(path, group, deploymentID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
2
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
|
@ -27,7 +27,7 @@ type HealthCheck struct {
|
|||
GracePeriodSeconds int `json:"gracePeriodSeconds,omitempty"`
|
||||
IntervalSeconds int `json:"intervalSeconds,omitempty"`
|
||||
TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
|
||||
IgnoreHTTP1xx *bool `json:"ignoreHttp1xx,ommitempty"`
|
||||
IgnoreHTTP1xx *bool `json:"ignoreHttp1xx,omitempty"`
|
||||
}
|
||||
|
||||
// SetCommand sets the given command on the health check.
|
||||
|
|
92
vendor/github.com/gambol99/go-marathon/subscription.go
generated
vendored
92
vendor/github.com/gambol99/go-marathon/subscription.go
generated
vendored
|
@ -103,7 +103,8 @@ func (r *marathonClient) registerSubscription() error {
|
|||
case EventsTransportCallback:
|
||||
return r.registerCallbackSubscription()
|
||||
case EventsTransportSSE:
|
||||
return r.registerSSESubscription()
|
||||
r.registerSSESubscription()
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("the events transport: %d is not supported", r.config.EventsTransport)
|
||||
}
|
||||
|
@ -162,40 +163,81 @@ func (r *marathonClient) registerCallbackSubscription() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *marathonClient) registerSSESubscription() error {
|
||||
// Prevent multiple SSE subscriptions
|
||||
// registerSSESubscription starts a go routine that continously tries to
|
||||
// connect to the SSE stream and to process the received events. To establish
|
||||
// the connection it tries the active cluster members until no more member is
|
||||
// active. When this happens it will retry to get a connection every 5 seconds.
|
||||
func (r *marathonClient) registerSSESubscription() {
|
||||
if r.subscribedToSSE {
|
||||
return nil
|
||||
}
|
||||
|
||||
request, _, err := r.buildAPIRequest("GET", marathonAPIEventStream, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Try to connect to stream, reusing the http client settings
|
||||
stream, err := eventsource.SubscribeWith("", r.config.HTTPClient, request)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case ev := <-stream.Events:
|
||||
if err := r.handleEvent(ev.Data()); err != nil {
|
||||
// TODO let the user handle this error instead of logging it here
|
||||
r.debugLog.Printf("registerSSESubscription(): failed to handle event: %v\n", err)
|
||||
}
|
||||
case err := <-stream.Errors:
|
||||
// TODO let the user handle this error instead of logging it here
|
||||
r.debugLog.Printf("registerSSESubscription(): failed to receive event: %v\n", err)
|
||||
stream, err := r.connectToSSE()
|
||||
if err != nil {
|
||||
r.debugLog.Printf("Error connecting SSE subscription: %s", err)
|
||||
<-time.After(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
err = r.listenToSSE(stream)
|
||||
stream.Close()
|
||||
r.debugLog.Printf("Error on SSE subscription: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
r.subscribedToSSE = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// connectToSSE tries to establish an *eventsource.Stream to any of the Marathon cluster members, marking the
|
||||
// member as down on connection failure, until there is no more active member in the cluster.
|
||||
// Given the http request can not be built, it will panic as this case should never happen.
|
||||
func (r *marathonClient) connectToSSE() (*eventsource.Stream, error) {
|
||||
for {
|
||||
request, member, err := r.buildAPIRequest("GET", marathonAPIEventStream, nil)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case newRequestError:
|
||||
panic(fmt.Sprintf("Requests for SSE subscriptions should never fail to be created: %s", err.Error()))
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// The event source library manipulates the HTTPClient. So we create a new one and copy
|
||||
// its underlying fields for performance reasons. See note that at least the Transport
|
||||
// should be reused here: https://golang.org/pkg/net/http/#Client
|
||||
httpClient := &http.Client{
|
||||
Transport: r.config.HTTPClient.Transport,
|
||||
CheckRedirect: r.config.HTTPClient.CheckRedirect,
|
||||
Jar: r.config.HTTPClient.Jar,
|
||||
Timeout: r.config.HTTPClient.Timeout,
|
||||
}
|
||||
|
||||
stream, err := eventsource.SubscribeWith("", httpClient, request)
|
||||
if err != nil {
|
||||
r.debugLog.Printf("Error subscribing to Marathon event stream: %s", err)
|
||||
r.hosts.markDown(member)
|
||||
continue
|
||||
}
|
||||
|
||||
return stream, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (r *marathonClient) listenToSSE(stream *eventsource.Stream) error {
|
||||
for {
|
||||
select {
|
||||
case ev := <-stream.Events:
|
||||
if err := r.handleEvent(ev.Data()); err != nil {
|
||||
r.debugLog.Printf("listenToSSE(): failed to handle event: %v", err)
|
||||
}
|
||||
case err := <-stream.Errors:
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe adds a URL to Marathon's callback facility
|
||||
|
|
42
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
42
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
|
@ -16,12 +16,54 @@ limitations under the License.
|
|||
|
||||
package marathon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const UnreachableStrategyAbsenceReasonDisabled = "disabled"
|
||||
|
||||
// UnreachableStrategy is the unreachable strategy applied to an application.
|
||||
type UnreachableStrategy struct {
|
||||
EnabledUnreachableStrategy
|
||||
AbsenceReason string
|
||||
}
|
||||
|
||||
// EnabledUnreachableStrategy covers parameters pertaining to present unreachable strategies.
|
||||
type EnabledUnreachableStrategy struct {
|
||||
InactiveAfterSeconds *float64 `json:"inactiveAfterSeconds,omitempty"`
|
||||
ExpungeAfterSeconds *float64 `json:"expungeAfterSeconds,omitempty"`
|
||||
}
|
||||
|
||||
type unreachableStrategy UnreachableStrategy
|
||||
|
||||
// UnmarshalJSON unmarshals the given JSON into an UnreachableStrategy. It
|
||||
// populates parameters for present strategies, and otherwise only sets the
|
||||
// absence reason.
|
||||
func (us *UnreachableStrategy) UnmarshalJSON(b []byte) error {
|
||||
var u unreachableStrategy
|
||||
var errEnabledUS, errNonEnabledUS error
|
||||
if errEnabledUS = json.Unmarshal(b, &u); errEnabledUS == nil {
|
||||
*us = UnreachableStrategy(u)
|
||||
return nil
|
||||
}
|
||||
|
||||
if errNonEnabledUS = json.Unmarshal(b, &us.AbsenceReason); errNonEnabledUS == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to unmarshal unreachable strategy: unmarshaling into enabled returned error '%s'; unmarshaling into non-enabled returned error '%s'", errEnabledUS, errNonEnabledUS)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the unreachable strategy.
|
||||
func (us *UnreachableStrategy) MarshalJSON() ([]byte, error) {
|
||||
if us.AbsenceReason == "" {
|
||||
return json.Marshal(us.EnabledUnreachableStrategy)
|
||||
}
|
||||
|
||||
return json.Marshal(us.AbsenceReason)
|
||||
}
|
||||
|
||||
// SetInactiveAfterSeconds sets the period after which instance will be marked as inactive.
|
||||
func (us UnreachableStrategy) SetInactiveAfterSeconds(cap float64) UnreachableStrategy {
|
||||
us.InactiveAfterSeconds = &cap
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue