Adding compatibility for marathon 1.5
This commit is contained in:
parent
461ebf6d88
commit
04d8b5d483
35 changed files with 2257 additions and 63 deletions
2
Gopkg.lock
generated
2
Gopkg.lock
generated
|
@ -540,7 +540,7 @@
|
|||
[[projects]]
|
||||
name = "github.com/gambol99/go-marathon"
|
||||
packages = ["."]
|
||||
revision = "03b46169666c53b9cc953b875ac5714e5103e064"
|
||||
revision = "99a156b96fb2f9dbe6465affa51bbdccdd37174d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/ghodss/yaml"
|
||||
|
|
|
@ -55,6 +55,7 @@ func init() {
|
|||
check.Suite(&HTTPSSuite{})
|
||||
check.Suite(&LogRotationSuite{})
|
||||
check.Suite(&MarathonSuite{})
|
||||
check.Suite(&MarathonSuite15{})
|
||||
check.Suite(&MesosSuite{})
|
||||
check.Suite(&RateLimitSuite{})
|
||||
check.Suite(&RetrySuite{})
|
||||
|
|
134
integration/marathon15_test.go
Normal file
134
integration/marathon15_test.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/integration/try"
|
||||
"github.com/containous/traefik/provider/label"
|
||||
"github.com/gambol99/go-marathon"
|
||||
"github.com/go-check/check"
|
||||
checker "github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// Marathon test suites (using libcompose)
|
||||
type MarathonSuite15 struct {
|
||||
BaseSuite
|
||||
marathonURL string
|
||||
}
|
||||
|
||||
func (s *MarathonSuite15) SetUpSuite(c *check.C) {
|
||||
s.createComposeProject(c, "marathon15")
|
||||
s.composeProject.Start(c)
|
||||
|
||||
marathonIPAddr := s.composeProject.Container(c, containerNameMarathon).NetworkSettings.IPAddress
|
||||
c.Assert(marathonIPAddr, checker.Not(checker.HasLen), 0)
|
||||
s.marathonURL = "http://" + marathonIPAddr + ":8080"
|
||||
|
||||
// Wait for Marathon readiness prior to creating the client so that we
|
||||
// don't run into the "all cluster members down" state right from the
|
||||
// start.
|
||||
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Add entry for Mesos slave container IP address in the hosts file so
|
||||
// that Traefik can properly forward traffic.
|
||||
// This is necessary as long as we are still using the docker-compose v1
|
||||
// spec. Once we switch to v2 or higher, we can have both the test/builder
|
||||
// container and the Mesos slave container join the same custom network and
|
||||
// enjoy DNS-discoverable container host names.
|
||||
mesosSlaveIPAddr := s.composeProject.Container(c, containerNameMesosSlave).NetworkSettings.IPAddress
|
||||
c.Assert(mesosSlaveIPAddr, checker.Not(checker.HasLen), 0)
|
||||
err = s.extendDockerHostsFile(containerNameMesosSlave, mesosSlaveIPAddr)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// extendDockerHostsFile extends the hosts file (/etc/hosts) by the given
|
||||
// host/IP address mapping if we are running inside a container.
|
||||
func (s *MarathonSuite15) extendDockerHostsFile(host, ipAddr string) error {
|
||||
const hostsFile = "/etc/hosts"
|
||||
|
||||
// Determine if the run inside a container. The most reliable way to
|
||||
// do this is to inject an indicator, which we do in terms of an
|
||||
// environment variable.
|
||||
// (See also https://groups.google.com/d/topic/docker-user/JOGE7AnJ3Gw/discussion.)
|
||||
if os.Getenv("CONTAINER") == "DOCKER" {
|
||||
// We are running inside a container -- extend the hosts file.
|
||||
file, err := os.OpenFile(hostsFile, os.O_APPEND|os.O_WRONLY, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = file.WriteString(fmt.Sprintf("%s\t%s\n", ipAddr, host)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MarathonSuite15) TestConfigurationUpdate(c *check.C) {
|
||||
// Start Traefik.
|
||||
file := s.adaptFile(c, "fixtures/marathon/simple.toml", struct {
|
||||
MarathonURL string
|
||||
}{s.marathonURL})
|
||||
defer os.Remove(file)
|
||||
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||
defer display(c)
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// Wait for Traefik to turn ready.
|
||||
err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Prepare Marathon client.
|
||||
config := marathon.NewDefaultConfig()
|
||||
config.URL = s.marathonURL
|
||||
client, err := marathon.NewClient(config)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Create test application to be deployed.
|
||||
app := marathon.NewDockerApplication().
|
||||
Name("/whoami").
|
||||
CPU(0.1).
|
||||
Memory(32).
|
||||
EmptyNetworks().
|
||||
AddLabel(label.TraefikFrontendRule, "PathPrefix:/service")
|
||||
app.Container.
|
||||
Expose(80).
|
||||
Docker.
|
||||
Container("emilevauge/whoami")
|
||||
*app.Networks = append(*app.Networks, *marathon.NewBridgePodNetwork())
|
||||
|
||||
// Deploy the test application.
|
||||
deployApplication(c, client, app)
|
||||
|
||||
// Query application via Traefik.
|
||||
err = try.GetRequest("http://127.0.0.1:8000/service", 30*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
// Create test application with services to be deployed.
|
||||
app = marathon.NewDockerApplication().
|
||||
Name("/whoami").
|
||||
CPU(0.1).
|
||||
Memory(32).
|
||||
EmptyNetworks().
|
||||
AddLabel(label.GetServiceLabel(label.TraefikFrontendRule, "app"), "PathPrefix:/app")
|
||||
app.Container.
|
||||
Expose(80).
|
||||
Docker.
|
||||
Container("emilevauge/whoami")
|
||||
*app.Networks = append(*app.Networks, *marathon.NewBridgePodNetwork())
|
||||
|
||||
// Deploy the test application.
|
||||
deployApplication(c, client, app)
|
||||
|
||||
// Query application via Traefik.
|
||||
err = try.GetRequest("http://127.0.0.1:8000/app", 30*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
55
integration/resources/compose/marathon15.yml
Normal file
55
integration/resources/compose/marathon15.yml
Normal file
|
@ -0,0 +1,55 @@
|
|||
zookeeper:
|
||||
image: zookeeper:3.4.10
|
||||
|
||||
mesos-master:
|
||||
links:
|
||||
- zookeeper
|
||||
image: mesosphere/mesos-master:1.4.1
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5050:5050"
|
||||
environment:
|
||||
- MESOS_HOSTNAME=mesos-master
|
||||
- MESOS_CLUSTER=local
|
||||
- MESOS_REGISTRY=in_memory
|
||||
- MESOS_LOG_DIR=/var/log
|
||||
- MESOS_WORK_DIR=/var/lib/mesos
|
||||
- MESOS_ZK=zk://zookeeper:2181/mesos
|
||||
|
||||
mesos-slave:
|
||||
links:
|
||||
- zookeeper
|
||||
- mesos-master
|
||||
image: mesosphere/mesos-slave-dind:0.4.0_mesos-1.4.1_docker-17.05.0_ubuntu-16.04.3
|
||||
privileged: true
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "5051:5051"
|
||||
environment:
|
||||
- MESOS_HOSTNAME=mesos-slave
|
||||
- MESOS_CONTAINERIZERS=docker,mesos
|
||||
- MESOS_ISOLATOR=cgroups/cpu,cgroups/mem
|
||||
- MESOS_LOG_DIR=/var/log
|
||||
- MESOS_MASTER=zk://zookeeper:2181/mesos
|
||||
- MESOS_PORT=5051
|
||||
- MESOS_WORK_DIR=/var/lib/mesos
|
||||
- MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins
|
||||
- MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs
|
||||
- MESOS_DOCKER_STOP_TIMEOUT=60secs
|
||||
- MESOS_RESOURCES=cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]
|
||||
- MESOS_SYSTEMD_ENABLE_SUPPORT=false
|
||||
|
||||
marathon:
|
||||
links:
|
||||
- zookeeper
|
||||
- mesos-master
|
||||
- mesos-slave
|
||||
image: mesosphere/marathon:v1.5.9
|
||||
# Uncomment published ports for interactive debugging.
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
extra_hosts:
|
||||
- "mesos-slave:172.17.0.1"
|
||||
environment:
|
||||
- MARATHON_ZK=zk://zookeeper:2181/marathon
|
||||
- MARATHON_MASTER=zk://zookeeper:2181/mesos
|
|
@ -83,6 +83,24 @@ func portDefinition(port int) func(*marathon.Application) {
|
|||
}
|
||||
}
|
||||
|
||||
func bridgeNetwork() func(*marathon.Application) {
|
||||
return func(app *marathon.Application) {
|
||||
app.SetNetwork("bridge", marathon.BridgeNetworkMode)
|
||||
}
|
||||
}
|
||||
|
||||
func containerNetwork() func(*marathon.Application) {
|
||||
return func(app *marathon.Application) {
|
||||
app.SetNetwork("cni", marathon.ContainerNetworkMode)
|
||||
}
|
||||
}
|
||||
|
||||
func hostNetwork() func(*marathon.Application) {
|
||||
return func(app *marathon.Application) {
|
||||
app.SetNetwork("host", marathon.HostNetworkMode)
|
||||
}
|
||||
}
|
||||
|
||||
func ipAddrPerTask(port int) func(*marathon.Application) {
|
||||
return func(app *marathon.Application) {
|
||||
p := marathon.Port{
|
||||
|
|
|
@ -347,7 +347,16 @@ func (p *Provider) getServer(app appData, task marathon.Task) (string, *types.Se
|
|||
}
|
||||
|
||||
func (p *Provider) getServerHost(task marathon.Task, app appData) (string, error) {
|
||||
if app.IPAddressPerTask == nil || p.ForceTaskHostname {
|
||||
networks := app.Networks
|
||||
var hostFlag bool
|
||||
|
||||
if networks == nil {
|
||||
hostFlag = app.IPAddressPerTask == nil
|
||||
} else {
|
||||
hostFlag = (*networks)[0].Mode != marathon.ContainerNetworkMode
|
||||
}
|
||||
|
||||
if hostFlag || p.ForceTaskHostname {
|
||||
if len(task.Host) == 0 {
|
||||
return "", fmt.Errorf("host is undefined for task %q app %q", task.ID, app.ID)
|
||||
}
|
||||
|
|
|
@ -1289,7 +1289,30 @@ func TestGetServers(t *testing.T) {
|
|||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks",
|
||||
desc: "with 3 tasks and hosts set",
|
||||
application: application(
|
||||
withTasks(
|
||||
task(ipAddresses("1.1.1.1"), host("2.2.2.2"), withTaskID("A"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.2"), host("2.2.2.2"), withTaskID("B"), taskPorts(81)),
|
||||
task(ipAddresses("1.1.1.3"), host("2.2.2.2"), withTaskID("C"), taskPorts(82))),
|
||||
),
|
||||
expected: map[string]types.Server{
|
||||
"server-A": {
|
||||
URL: "http://2.2.2.2:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-B": {
|
||||
URL: "http://2.2.2.2:81",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-C": {
|
||||
URL: "http://2.2.2.2:82",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks and ipAddrPerTask set",
|
||||
application: application(
|
||||
ipAddrPerTask(80),
|
||||
withTasks(
|
||||
|
@ -1312,20 +1335,66 @@ func TestGetServers(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks and bridge network",
|
||||
application: application(
|
||||
bridgeNetwork(),
|
||||
withTasks(
|
||||
task(ipAddresses("1.1.1.1"), host("2.2.2.2"), withTaskID("A"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.2"), host("2.2.2.2"), withTaskID("B"), taskPorts(81)),
|
||||
task(ipAddresses("1.1.1.3"), host("2.2.2.2"), withTaskID("C"), taskPorts(82))),
|
||||
),
|
||||
expected: map[string]types.Server{
|
||||
"server-A": {
|
||||
URL: "http://2.2.2.2:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-B": {
|
||||
URL: "http://2.2.2.2:81",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-C": {
|
||||
URL: "http://2.2.2.2:82",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks and cni set",
|
||||
application: application(
|
||||
containerNetwork(),
|
||||
withTasks(
|
||||
task(ipAddresses("1.1.1.1"), withTaskID("A"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.2"), withTaskID("B"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.3"), withTaskID("C"), taskPorts(80))),
|
||||
),
|
||||
expected: map[string]types.Server{
|
||||
"server-A": {
|
||||
URL: "http://1.1.1.1:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-B": {
|
||||
URL: "http://1.1.1.2:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-C": {
|
||||
URL: "http://1.1.1.3:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p := &Provider{}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
if test.desc == "should return nil when all hosts are empty" {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := p.getServers(withAppData(test.application, test.segmentName))
|
||||
actual := p.getServers(withAppData(test.application, test.segmentName))
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,11 +147,21 @@ func (p *Provider) getFrontendRuleV1(application marathon.Application, serviceNa
|
|||
|
||||
// Deprecated
|
||||
func (p *Provider) getBackendServerV1(task marathon.Task, application marathon.Application) string {
|
||||
if application.IPAddressPerTask == nil || p.ForceTaskHostname {
|
||||
networks := application.Networks
|
||||
var hostFlag bool
|
||||
|
||||
if networks == nil {
|
||||
hostFlag = application.IPAddressPerTask == nil
|
||||
} else {
|
||||
hostFlag = (*networks)[0].Mode != marathon.ContainerNetworkMode
|
||||
}
|
||||
|
||||
if hostFlag || p.ForceTaskHostname {
|
||||
return task.Host
|
||||
}
|
||||
|
||||
numTaskIPAddresses := len(task.IPAddresses)
|
||||
|
||||
switch numTaskIPAddresses {
|
||||
case 0:
|
||||
log.Errorf("Missing IP address for Marathon application %s on task %s", application.ID, task.ID)
|
||||
|
|
|
@ -784,7 +784,30 @@ func TestGetServersV1(t *testing.T) {
|
|||
expected: nil,
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks",
|
||||
desc: "with 3 tasks and hosts set",
|
||||
application: application(
|
||||
withTasks(
|
||||
task(ipAddresses("1.1.1.1"), host("2.2.2.2"), withTaskID("A"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.2"), host("2.2.2.2"), withTaskID("B"), taskPorts(81)),
|
||||
task(ipAddresses("1.1.1.3"), host("2.2.2.2"), withTaskID("C"), taskPorts(82))),
|
||||
),
|
||||
expected: map[string]types.Server{
|
||||
"server-A": {
|
||||
URL: "http://2.2.2.2:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-B": {
|
||||
URL: "http://2.2.2.2:81",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-C": {
|
||||
URL: "http://2.2.2.2:82",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks and ipAddrPerTask set",
|
||||
application: application(
|
||||
ipAddrPerTask(80),
|
||||
withTasks(
|
||||
|
@ -807,20 +830,66 @@ func TestGetServersV1(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks and bridge network",
|
||||
application: application(
|
||||
bridgeNetwork(),
|
||||
withTasks(
|
||||
task(ipAddresses("1.1.1.1"), host("2.2.2.2"), withTaskID("A"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.2"), host("2.2.2.2"), withTaskID("B"), taskPorts(81)),
|
||||
task(ipAddresses("1.1.1.3"), host("2.2.2.2"), withTaskID("C"), taskPorts(82))),
|
||||
),
|
||||
expected: map[string]types.Server{
|
||||
"server-A": {
|
||||
URL: "http://2.2.2.2:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-B": {
|
||||
URL: "http://2.2.2.2:81",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-C": {
|
||||
URL: "http://2.2.2.2:82",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "with 3 tasks and cni set",
|
||||
application: application(
|
||||
containerNetwork(),
|
||||
withTasks(
|
||||
task(ipAddresses("1.1.1.1"), withTaskID("A"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.2"), withTaskID("B"), taskPorts(80)),
|
||||
task(ipAddresses("1.1.1.3"), withTaskID("C"), taskPorts(80))),
|
||||
),
|
||||
expected: map[string]types.Server{
|
||||
"server-A": {
|
||||
URL: "http://1.1.1.1:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-B": {
|
||||
URL: "http://1.1.1.2:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
"server-C": {
|
||||
URL: "http://1.1.1.3:80",
|
||||
Weight: label.DefaultWeight,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p := &Provider{}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
if test.desc == "should return nil when all hosts are empty" {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := p.getServersV1(test.application, test.segmentName)
|
||||
actual := p.getServersV1(test.application, test.segmentName)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Package mocks Code generated by mockery v1.0.0
|
||||
// Package mocks Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
// mockery -recursive -dir=vendor/github.com/gambol99/ -name=Marathon -output=provider/marathon/mocks
|
||||
package mocks
|
||||
|
||||
|
@ -278,6 +278,29 @@ func (_m *Marathon) CreateGroup(group *marathon.Group) error {
|
|||
return r0
|
||||
}
|
||||
|
||||
// CreatePod provides a mock function with given fields: pod
|
||||
func (_m *Marathon) CreatePod(pod *marathon.Pod) (*marathon.Pod, error) {
|
||||
ret := _m.Called(pod)
|
||||
|
||||
var r0 *marathon.Pod
|
||||
if rf, ok := ret.Get(0).(func(*marathon.Pod) *marathon.Pod); ok {
|
||||
r0 = rf(pod)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.Pod)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*marathon.Pod) error); ok {
|
||||
r1 = rf(pod)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteApplication provides a mock function with given fields: name, force
|
||||
func (_m *Marathon) DeleteApplication(name string, force bool) (*marathon.DeploymentID, error) {
|
||||
ret := _m.Called(name, force)
|
||||
|
@ -347,6 +370,75 @@ func (_m *Marathon) DeleteGroup(name string, force bool) (*marathon.DeploymentID
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// DeletePod provides a mock function with given fields: name, force
|
||||
func (_m *Marathon) DeletePod(name string, force bool) (*marathon.DeploymentID, error) {
|
||||
ret := _m.Called(name, force)
|
||||
|
||||
var r0 *marathon.DeploymentID
|
||||
if rf, ok := ret.Get(0).(func(string, bool) *marathon.DeploymentID); ok {
|
||||
r0 = rf(name, force)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.DeploymentID)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, bool) error); ok {
|
||||
r1 = rf(name, force)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeletePodInstance provides a mock function with given fields: name, instance
|
||||
func (_m *Marathon) DeletePodInstance(name string, instance string) (*marathon.PodInstance, error) {
|
||||
ret := _m.Called(name, instance)
|
||||
|
||||
var r0 *marathon.PodInstance
|
||||
if rf, ok := ret.Get(0).(func(string, string) *marathon.PodInstance); ok {
|
||||
r0 = rf(name, instance)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.PodInstance)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(name, instance)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeletePodInstances provides a mock function with given fields: name, instances
|
||||
func (_m *Marathon) DeletePodInstances(name string, instances []string) ([]*marathon.PodInstance, error) {
|
||||
ret := _m.Called(name, instances)
|
||||
|
||||
var r0 []*marathon.PodInstance
|
||||
if rf, ok := ret.Get(0).(func(string, []string) []*marathon.PodInstance); ok {
|
||||
r0 = rf(name, instances)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*marathon.PodInstance)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, []string) error); ok {
|
||||
r1 = rf(name, instances)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// DeleteQueueDelay provides a mock function with given fields: appID
|
||||
func (_m *Marathon) DeleteQueueDelay(appID string) error {
|
||||
ret := _m.Called(appID)
|
||||
|
@ -701,6 +793,158 @@ func (_m *Marathon) Ping() (bool, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// Pod provides a mock function with given fields: name
|
||||
func (_m *Marathon) Pod(name string) (*marathon.Pod, error) {
|
||||
ret := _m.Called(name)
|
||||
|
||||
var r0 *marathon.Pod
|
||||
if rf, ok := ret.Get(0).(func(string) *marathon.Pod); ok {
|
||||
r0 = rf(name)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.Pod)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// PodByVersion provides a mock function with given fields: name, version
|
||||
func (_m *Marathon) PodByVersion(name string, version string) (*marathon.Pod, error) {
|
||||
ret := _m.Called(name, version)
|
||||
|
||||
var r0 *marathon.Pod
|
||||
if rf, ok := ret.Get(0).(func(string, string) *marathon.Pod); ok {
|
||||
r0 = rf(name, version)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.Pod)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(name, version)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// PodIsRunning provides a mock function with given fields: name
|
||||
func (_m *Marathon) PodIsRunning(name string) bool {
|
||||
ret := _m.Called(name)
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func(string) bool); ok {
|
||||
r0 = rf(name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// PodStatus provides a mock function with given fields: name
|
||||
func (_m *Marathon) PodStatus(name string) (*marathon.PodStatus, error) {
|
||||
ret := _m.Called(name)
|
||||
|
||||
var r0 *marathon.PodStatus
|
||||
if rf, ok := ret.Get(0).(func(string) *marathon.PodStatus); ok {
|
||||
r0 = rf(name)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.PodStatus)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// PodStatuses provides a mock function with given fields:
|
||||
func (_m *Marathon) PodStatuses() ([]*marathon.PodStatus, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []*marathon.PodStatus
|
||||
if rf, ok := ret.Get(0).(func() []*marathon.PodStatus); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*marathon.PodStatus)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// PodVersions provides a mock function with given fields: name
|
||||
func (_m *Marathon) PodVersions(name string) ([]string, error) {
|
||||
ret := _m.Called(name)
|
||||
|
||||
var r0 []string
|
||||
if rf, ok := ret.Get(0).(func(string) []string); ok {
|
||||
r0 = rf(name)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Pods provides a mock function with given fields:
|
||||
func (_m *Marathon) Pods() ([]marathon.Pod, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []marathon.Pod
|
||||
if rf, ok := ret.Get(0).(func() []marathon.Pod); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]marathon.Pod)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Queue provides a mock function with given fields:
|
||||
func (_m *Marathon) Queue() (*marathon.Queue, error) {
|
||||
ret := _m.Called()
|
||||
|
@ -835,6 +1079,27 @@ func (_m *Marathon) Subscriptions() (*marathon.Subscriptions, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// SupportsPods provides a mock function with given fields:
|
||||
func (_m *Marathon) SupportsPods() (bool, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// TaskEndpoints provides a mock function with given fields: name, port, healthCheck
|
||||
func (_m *Marathon) TaskEndpoints(name string, port int, healthCheck bool) ([]string, error) {
|
||||
ret := _m.Called(name, port, healthCheck)
|
||||
|
@ -941,6 +1206,29 @@ func (_m *Marathon) UpdateGroup(id string, group *marathon.Group, force bool) (*
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdatePod provides a mock function with given fields: pod, force
|
||||
func (_m *Marathon) UpdatePod(pod *marathon.Pod, force bool) (*marathon.Pod, error) {
|
||||
ret := _m.Called(pod, force)
|
||||
|
||||
var r0 *marathon.Pod
|
||||
if rf, ok := ret.Get(0).(func(*marathon.Pod, bool) *marathon.Pod); ok {
|
||||
r0 = rf(pod, force)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*marathon.Pod)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*marathon.Pod, bool) error); ok {
|
||||
r1 = rf(pod, force)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// WaitOnApplication provides a mock function with given fields: name, timeout
|
||||
func (_m *Marathon) WaitOnApplication(name string, timeout time.Duration) error {
|
||||
ret := _m.Called(name, timeout)
|
||||
|
@ -982,3 +1270,17 @@ func (_m *Marathon) WaitOnGroup(name string, timeout time.Duration) error {
|
|||
|
||||
return r0
|
||||
}
|
||||
|
||||
// WaitOnPod provides a mock function with given fields: name, timeout
|
||||
func (_m *Marathon) WaitOnPod(name string, timeout time.Duration) error {
|
||||
ret := _m.Called(name, timeout)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, time.Duration) error); ok {
|
||||
r0 = rf(name, timeout)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
|
66
vendor/github.com/gambol99/go-marathon/application.go
generated
vendored
66
vendor/github.com/gambol99/go-marathon/application.go
generated
vendored
|
@ -56,14 +56,16 @@ type Port struct {
|
|||
|
||||
// Application is the definition for an application in marathon
|
||||
type Application struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Cmd *string `json:"cmd,omitempty"`
|
||||
Args *[]string `json:"args,omitempty"`
|
||||
Constraints *[][]string `json:"constraints,omitempty"`
|
||||
Container *Container `json:"container,omitempty"`
|
||||
CPUs float64 `json:"cpus,omitempty"`
|
||||
GPUs *float64 `json:"gpus,omitempty"`
|
||||
Disk *float64 `json:"disk,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Cmd *string `json:"cmd,omitempty"`
|
||||
Args *[]string `json:"args,omitempty"`
|
||||
Constraints *[][]string `json:"constraints,omitempty"`
|
||||
Container *Container `json:"container,omitempty"`
|
||||
CPUs float64 `json:"cpus,omitempty"`
|
||||
GPUs *float64 `json:"gpus,omitempty"`
|
||||
Disk *float64 `json:"disk,omitempty"`
|
||||
Networks *[]PodNetwork `json:"networks,omitempty"`
|
||||
|
||||
// Contains non-secret environment variables. Secrets environment variables are part of the Secrets map.
|
||||
Env *map[string]string `json:"-"`
|
||||
Executor *string `json:"executor,omitempty"`
|
||||
|
@ -495,7 +497,10 @@ func (r *Application) CheckHTTP(path string, port, interval int) (*Application,
|
|||
// step: get the port index
|
||||
portIndex, err := r.Container.Docker.ServicePortIndex(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
portIndex, err = r.Container.ServicePortIndex(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
health := NewDefaultHealthCheck()
|
||||
health.IntervalSeconds = interval
|
||||
|
@ -518,7 +523,10 @@ func (r *Application) CheckTCP(port, interval int) (*Application, error) {
|
|||
// step: get the port index
|
||||
portIndex, err := r.Container.Docker.ServicePortIndex(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
portIndex, err = r.Container.ServicePortIndex(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
health := NewDefaultHealthCheck()
|
||||
health.Protocol = "TCP"
|
||||
|
@ -810,24 +818,7 @@ func (r *marathonClient) CreateApplication(application *Application) (*Applicati
|
|||
// name: the id of the application
|
||||
// timeout: a duration of time to wait for an application to deploy
|
||||
func (r *marathonClient) WaitOnApplication(name string, timeout time.Duration) error {
|
||||
if r.appExistAndRunning(name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
timeoutTimer := time.After(timeout)
|
||||
ticker := time.NewTicker(r.config.PollingWaitTime)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-timeoutTimer:
|
||||
return ErrTimeoutError
|
||||
case <-ticker.C:
|
||||
if r.appExistAndRunning(name) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return r.wait(name, timeout, r.appExistAndRunning)
|
||||
}
|
||||
|
||||
func (r *marathonClient) appExistAndRunning(name string) bool {
|
||||
|
@ -973,3 +964,22 @@ func (d *Discovery) AddPort(port Port) *Discovery {
|
|||
d.Ports = &ports
|
||||
return d
|
||||
}
|
||||
|
||||
// EmptyNetworks explicitly empties networks
|
||||
func (r *Application) EmptyNetworks() *Application {
|
||||
r.Networks = &[]PodNetwork{}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetNetwork sets the networking mode
|
||||
func (r *Application) SetNetwork(name string, mode PodNetworkMode) *Application {
|
||||
if r.Networks == nil {
|
||||
r.EmptyNetworks()
|
||||
}
|
||||
|
||||
network := PodNetwork{Name: name, Mode: mode}
|
||||
networks := *r.Networks
|
||||
networks = append(networks, network)
|
||||
r.Networks = &networks
|
||||
return r
|
||||
}
|
||||
|
|
2
vendor/github.com/gambol99/go-marathon/application_marshalling.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/application_marshalling.go
generated
vendored
|
@ -61,7 +61,7 @@ func (app *Application) UnmarshalJSON(b []byte) error {
|
|||
(*secrets)[secStore] = Secret{EnvVar: envName}
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("unexpected secret field %v or value type %T", secret, envValOrSecret[secret])
|
||||
return fmt.Errorf("unexpected secret field %v of value type %T", secret, envValOrSecret[secret])
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unexpected environment variable type %T", envValOrSecret)
|
||||
|
|
80
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
80
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
|
@ -70,6 +70,40 @@ type Marathon interface {
|
|||
// wait of application
|
||||
WaitOnApplication(name string, timeout time.Duration) error
|
||||
|
||||
// -- PODS ---
|
||||
// whether this version of Marathon supports pods
|
||||
SupportsPods() (bool, error)
|
||||
|
||||
// get pod status
|
||||
PodStatus(name string) (*PodStatus, error)
|
||||
// get all pod statuses
|
||||
PodStatuses() ([]*PodStatus, error)
|
||||
|
||||
// get pod
|
||||
Pod(name string) (*Pod, error)
|
||||
// get all pods
|
||||
Pods() ([]Pod, error)
|
||||
// create pod
|
||||
CreatePod(pod *Pod) (*Pod, error)
|
||||
// update pod
|
||||
UpdatePod(pod *Pod, force bool) (*Pod, error)
|
||||
// delete pod
|
||||
DeletePod(name string, force bool) (*DeploymentID, error)
|
||||
// wait on pod to be deployed
|
||||
WaitOnPod(name string, timeout time.Duration) error
|
||||
// check if a pod is running
|
||||
PodIsRunning(name string) bool
|
||||
|
||||
// get versions of a pod
|
||||
PodVersions(name string) ([]string, error)
|
||||
// get pod by version
|
||||
PodByVersion(name, version string) (*Pod, error)
|
||||
|
||||
// delete instances of a pod
|
||||
DeletePodInstances(name string, instances []string) ([]*PodInstance, error)
|
||||
// delete pod instance
|
||||
DeletePodInstance(name, instance string) (*PodInstance, error)
|
||||
|
||||
// -- TASKS ---
|
||||
|
||||
// get a list of tasks for a specific application
|
||||
|
@ -273,6 +307,10 @@ func (r *marathonClient) Ping() (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (r *marathonClient) apiHead(path string, result interface{}) error {
|
||||
return r.apiCall("HEAD", path, nil, result)
|
||||
}
|
||||
|
||||
func (r *marathonClient) apiGet(path string, post, result interface{}) error {
|
||||
return r.apiCall("GET", path, post, result)
|
||||
}
|
||||
|
@ -290,6 +328,8 @@ func (r *marathonClient) apiDelete(path string, post, result interface{}) error
|
|||
}
|
||||
|
||||
func (r *marathonClient) apiCall(method, path string, body, result interface{}) error {
|
||||
const deploymentHeader = "Marathon-Deployment-Id"
|
||||
|
||||
for {
|
||||
// step: marshall the request to json
|
||||
var requestBody []byte
|
||||
|
@ -328,11 +368,24 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
|||
r.debugLog("apiCall(): %v %v returned %v %s", request.Method, request.URL.String(), response.Status, oneLogLine(respBody))
|
||||
}
|
||||
|
||||
// step: check for a successfull response
|
||||
// step: check for a successful response
|
||||
if response.StatusCode >= 200 && response.StatusCode <= 299 {
|
||||
if result != nil {
|
||||
if err := json.Unmarshal(respBody, result); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal response from Marathon: %s", err)
|
||||
// If we have a deployment ID header and no response body, give them that
|
||||
// This specifically handles the use case of a DELETE on an app/pod
|
||||
// We need a way to retrieve the deployment ID
|
||||
deploymentID := response.Header.Get(deploymentHeader)
|
||||
if len(respBody) == 0 && deploymentID != "" {
|
||||
d := DeploymentID{
|
||||
DeploymentID: deploymentID,
|
||||
}
|
||||
if deployID, ok := result.(*DeploymentID); ok {
|
||||
*deployID = d
|
||||
}
|
||||
} else {
|
||||
if err := json.Unmarshal(respBody, result); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal response from Marathon: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -350,6 +403,27 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
|||
}
|
||||
}
|
||||
|
||||
// wait waits until the provided function returns true (or times out)
|
||||
func (r *marathonClient) wait(name string, timeout time.Duration, fn func(string) bool) error {
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
ticker := time.NewTicker(r.config.PollingWaitTime)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
if fn(name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
return ErrTimeoutError
|
||||
case <-ticker.C:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
|
1
vendor/github.com/gambol99/go-marathon/const.go
generated
vendored
1
vendor/github.com/gambol99/go-marathon/const.go
generated
vendored
|
@ -24,6 +24,7 @@ const (
|
|||
marathonAPIEventStream = marathonAPIVersion + "/events"
|
||||
marathonAPISubscription = marathonAPIVersion + "/eventSubscriptions"
|
||||
marathonAPIApps = marathonAPIVersion + "/apps"
|
||||
marathonAPIPods = marathonAPIVersion + "/pods"
|
||||
marathonAPITasks = marathonAPIVersion + "/tasks"
|
||||
marathonAPIDeployments = marathonAPIVersion + "/deployments"
|
||||
marathonAPIGroups = marathonAPIVersion + "/groups"
|
||||
|
|
12
vendor/github.com/gambol99/go-marathon/deployment.go
generated
vendored
12
vendor/github.com/gambol99/go-marathon/deployment.go
generated
vendored
|
@ -29,6 +29,7 @@ type Deployment struct {
|
|||
CurrentStep int `json:"currentStep"`
|
||||
TotalSteps int `json:"totalSteps"`
|
||||
AffectedApps []string `json:"affectedApps"`
|
||||
AffectedPods []string `json:"affectedPods"`
|
||||
Steps [][]*DeploymentStep `json:"-"`
|
||||
XXStepsRaw json.RawMessage `json:"steps"` // Holds raw steps JSON to unmarshal later
|
||||
CurrentActions []*DeploymentStep `json:"currentActions"`
|
||||
|
@ -107,8 +108,17 @@ func (r *marathonClient) Deployments() ([]*Deployment, error) {
|
|||
// id: the deployment id you wish to delete
|
||||
// force: whether or not to force the deletion
|
||||
func (r *marathonClient) DeleteDeployment(id string, force bool) (*DeploymentID, error) {
|
||||
path := fmt.Sprintf("%s/%s", marathonAPIDeployments, id)
|
||||
|
||||
// if force=true, no body is returned
|
||||
if force {
|
||||
path += "?force=true"
|
||||
return nil, r.apiDelete(path, nil, nil)
|
||||
}
|
||||
|
||||
deployment := new(DeploymentID)
|
||||
err := r.apiDelete(fmt.Sprintf("%s/%s", marathonAPIDeployments, id), nil, deployment)
|
||||
err := r.apiDelete(path, nil, deployment)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
103
vendor/github.com/gambol99/go-marathon/docker.go
generated
vendored
103
vendor/github.com/gambol99/go-marathon/docker.go
generated
vendored
|
@ -23,9 +23,10 @@ import (
|
|||
|
||||
// Container is the definition for a container type in marathon
|
||||
type Container struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Docker *Docker `json:"docker,omitempty"`
|
||||
Volumes *[]Volume `json:"volumes,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Docker *Docker `json:"docker,omitempty"`
|
||||
Volumes *[]Volume `json:"volumes,omitempty"`
|
||||
PortMappings *[]PortMapping `json:"portMappings,omitempty"`
|
||||
}
|
||||
|
||||
// PortMapping is the portmapping structure between container and mesos
|
||||
|
@ -36,6 +37,7 @@ type PortMapping struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
ServicePort int `json:"servicePort,omitempty"`
|
||||
Protocol string `json:"protocol,omitempty"`
|
||||
NetworkNames *[]string `json:"networkNames,omitempty"`
|
||||
}
|
||||
|
||||
// Parameters is the parameters to pass to the docker client when creating the container
|
||||
|
@ -53,11 +55,15 @@ type Volume struct {
|
|||
Persistent *PersistentVolume `json:"persistent,omitempty"`
|
||||
}
|
||||
|
||||
// PersistentVolumeType is the a persistent docker volume to be mounted
|
||||
type PersistentVolumeType string
|
||||
|
||||
const (
|
||||
PersistentVolumeTypeRoot PersistentVolumeType = "root"
|
||||
PersistentVolumeTypePath PersistentVolumeType = "path"
|
||||
// PersistentVolumeTypeRoot is the root path of the persistent volume
|
||||
PersistentVolumeTypeRoot PersistentVolumeType = "root"
|
||||
// PersistentVolumeTypePath is the mount path of the persistent volume
|
||||
PersistentVolumeTypePath PersistentVolumeType = "path"
|
||||
// PersistentVolumeTypeMount is the mount type of the persistent volume
|
||||
PersistentVolumeTypeMount PersistentVolumeType = "mount"
|
||||
)
|
||||
|
||||
|
@ -255,6 +261,19 @@ func (docker *Docker) Host() *Docker {
|
|||
return docker
|
||||
}
|
||||
|
||||
// Expose sets the container to expose the following TCP ports
|
||||
// ports: the TCP ports the container is exposing
|
||||
func (container *Container) Expose(ports ...int) *Container {
|
||||
for _, port := range ports {
|
||||
container.ExposePort(PortMapping{
|
||||
ContainerPort: port,
|
||||
HostPort: 0,
|
||||
ServicePort: 0,
|
||||
Protocol: "tcp"})
|
||||
}
|
||||
return container
|
||||
}
|
||||
|
||||
// Expose sets the container to expose the following TCP ports
|
||||
// ports: the TCP ports the container is exposing
|
||||
func (docker *Docker) Expose(ports ...int) *Docker {
|
||||
|
@ -268,6 +287,19 @@ func (docker *Docker) Expose(ports ...int) *Docker {
|
|||
return docker
|
||||
}
|
||||
|
||||
// ExposeUDP sets the container to expose the following UDP ports
|
||||
// ports: the UDP ports the container is exposing
|
||||
func (container *Container) ExposeUDP(ports ...int) *Container {
|
||||
for _, port := range ports {
|
||||
container.ExposePort(PortMapping{
|
||||
ContainerPort: port,
|
||||
HostPort: 0,
|
||||
ServicePort: 0,
|
||||
Protocol: "udp"})
|
||||
}
|
||||
return container
|
||||
}
|
||||
|
||||
// ExposeUDP sets the container to expose the following UDP ports
|
||||
// ports: the UDP ports the container is exposing
|
||||
func (docker *Docker) ExposeUDP(ports ...int) *Docker {
|
||||
|
@ -281,6 +313,19 @@ func (docker *Docker) ExposeUDP(ports ...int) *Docker {
|
|||
return docker
|
||||
}
|
||||
|
||||
// ExposePort exposes an port in the container
|
||||
func (container *Container) ExposePort(portMapping PortMapping) *Container {
|
||||
if container.PortMappings == nil {
|
||||
container.EmptyPortMappings()
|
||||
}
|
||||
|
||||
portMappings := *container.PortMappings
|
||||
portMappings = append(portMappings, portMapping)
|
||||
container.PortMappings = &portMappings
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
// ExposePort exposes an port in the container
|
||||
func (docker *Docker) ExposePort(portMapping PortMapping) *Docker {
|
||||
if docker.PortMappings == nil {
|
||||
|
@ -294,6 +339,14 @@ func (docker *Docker) ExposePort(portMapping PortMapping) *Docker {
|
|||
return docker
|
||||
}
|
||||
|
||||
// EmptyPortMappings explicitly empties the port mappings -- use this if you need to empty
|
||||
// port mappings of an application that already has port mappings set (setting port mappings to nil will
|
||||
// keep the current value)
|
||||
func (container *Container) EmptyPortMappings() *Container {
|
||||
container.PortMappings = &[]PortMapping{}
|
||||
return container
|
||||
}
|
||||
|
||||
// EmptyPortMappings explicitly empties the port mappings -- use this if you need to empty
|
||||
// port mappings of an application that already has port mappings set (setting port mappings to nil will
|
||||
// keep the current value)
|
||||
|
@ -349,6 +402,24 @@ func (docker *Docker) EmptyParameters() *Docker {
|
|||
return docker
|
||||
}
|
||||
|
||||
// ServicePortIndex finds the service port index of the exposed port
|
||||
// port: the port you are looking for
|
||||
func (container *Container) ServicePortIndex(port int) (int, error) {
|
||||
if container.PortMappings == nil || len(*container.PortMappings) == 0 {
|
||||
return 0, errors.New("The container does not contain any port mappings to search")
|
||||
}
|
||||
|
||||
// step: iterate and find the port
|
||||
for index, containerPort := range *container.PortMappings {
|
||||
if containerPort.ContainerPort == port {
|
||||
return index, nil
|
||||
}
|
||||
}
|
||||
|
||||
// step: we didn't find the port in the mappings
|
||||
return 0, fmt.Errorf("The container port %d was not found in the container port mappings", port)
|
||||
}
|
||||
|
||||
// ServicePortIndex finds the service port index of the exposed port
|
||||
// port: the port you are looking for
|
||||
func (docker *Docker) ServicePortIndex(port int) (int, error) {
|
||||
|
@ -364,5 +435,25 @@ func (docker *Docker) ServicePortIndex(port int) (int, error) {
|
|||
}
|
||||
|
||||
// step: we didn't find the port in the mappings
|
||||
return 0, fmt.Errorf("The container port required was not found in the container port mappings")
|
||||
return 0, fmt.Errorf("The docker port %d was not found in the container port mappings", port)
|
||||
}
|
||||
|
||||
// AddNetwork adds a network name to a PortMapping
|
||||
// name: the name of the network
|
||||
func (p *PortMapping) AddNetwork(name string) *PortMapping {
|
||||
if p.NetworkNames == nil {
|
||||
p.EmptyNetworkNames()
|
||||
}
|
||||
networks := *p.NetworkNames
|
||||
networks = append(networks, name)
|
||||
p.NetworkNames = &networks
|
||||
return p
|
||||
}
|
||||
|
||||
// EmptyNetworkNames explicitly empties the network names -- use this if you need to empty
|
||||
// the network names of a port mapping that already has network names set
|
||||
func (p *PortMapping) EmptyNetworkNames() *PortMapping {
|
||||
p.NetworkNames = &[]string{}
|
||||
|
||||
return p
|
||||
}
|
||||
|
|
4
vendor/github.com/gambol99/go-marathon/error.go
generated
vendored
4
vendor/github.com/gambol99/go-marathon/error.go
generated
vendored
|
@ -42,6 +42,8 @@ const (
|
|||
ErrCodeServer
|
||||
// ErrCodeUnknown specifies an unknown error.
|
||||
ErrCodeUnknown
|
||||
// ErrCodeMethodNotAllowed specifies a 405 Method Not Allowed.
|
||||
ErrCodeMethodNotAllowed
|
||||
)
|
||||
|
||||
// InvalidEndpointError indicates a endpoint error in the marathon urls
|
||||
|
@ -82,6 +84,8 @@ func NewAPIError(code int, content []byte) error {
|
|||
errDef = &simpleErrDef{code: ErrCodeForbidden}
|
||||
case code == http.StatusNotFound:
|
||||
errDef = &simpleErrDef{code: ErrCodeNotFound}
|
||||
case code == http.StatusMethodNotAllowed:
|
||||
errDef = &simpleErrDef{code: ErrCodeMethodNotAllowed}
|
||||
case code == http.StatusConflict:
|
||||
errDef = &conflictDef{}
|
||||
case code == 422:
|
||||
|
|
29
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
29
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
|
@ -30,6 +30,35 @@ type HealthCheck struct {
|
|||
IgnoreHTTP1xx *bool `json:"ignoreHttp1xx,omitempty"`
|
||||
}
|
||||
|
||||
// HTTPHealthCheck describes an HTTP based health check
|
||||
type HTTPHealthCheck struct {
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
}
|
||||
|
||||
// TCPHealthCheck describes a TCP based health check
|
||||
type TCPHealthCheck struct {
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
}
|
||||
|
||||
// CommandHealthCheck describes a shell-based health check
|
||||
type CommandHealthCheck struct {
|
||||
Command PodCommand `json:"command,omitempty"`
|
||||
}
|
||||
|
||||
// PodHealthCheck describes how to determine a pod's health
|
||||
type PodHealthCheck struct {
|
||||
HTTP *HTTPHealthCheck `json:"http,omitempty"`
|
||||
TCP *TCPHealthCheck `json:"tcp,omitempty"`
|
||||
Exec *CommandHealthCheck `json:"exec,omitempty"`
|
||||
GracePeriodSeconds *int `json:"gracePeriodSeconds,omitempty"`
|
||||
IntervalSeconds *int `json:"intervalSeconds,omitempty"`
|
||||
MaxConsecutiveFailures *int `json:"maxConsecutiveFailures,omitempty"`
|
||||
TimeoutSeconds *int `json:"timeoutSeconds,omitempty"`
|
||||
DelaySeconds *int `json:"delaySeconds,omitempty"`
|
||||
}
|
||||
|
||||
// SetCommand sets the given command on the health check.
|
||||
func (h *HealthCheck) SetCommand(c Command) *HealthCheck {
|
||||
h.Command = &c
|
||||
|
|
124
vendor/github.com/gambol99/go-marathon/network.go
generated
vendored
Normal file
124
vendor/github.com/gambol99/go-marathon/network.go
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// PodNetworkMode is the mode of a network descriptor
|
||||
type PodNetworkMode string
|
||||
|
||||
const (
|
||||
ContainerNetworkMode PodNetworkMode = "container"
|
||||
BridgeNetworkMode PodNetworkMode = "container/bridge"
|
||||
HostNetworkMode PodNetworkMode = "host"
|
||||
)
|
||||
|
||||
// PodNetwork contains network descriptors for a pod
|
||||
type PodNetwork struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Mode PodNetworkMode `json:"mode,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// PodEndpoint describes an endpoint for a pod's container
|
||||
type PodEndpoint struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
ContainerPort int `json:"containerPort,omitempty"`
|
||||
HostPort int `json:"hostPort,omitempty"`
|
||||
Protocol []string `json:"protocol,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// NewPodNetwork creates an empty PodNetwork
|
||||
func NewPodNetwork(name string) *PodNetwork {
|
||||
return &PodNetwork{
|
||||
Name: name,
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewPodEndpoint creates an empty PodEndpoint
|
||||
func NewPodEndpoint() *PodEndpoint {
|
||||
return &PodEndpoint{
|
||||
Protocol: []string{},
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewBridgePodNetwork creates a PodNetwork for a container in bridge mode
|
||||
func NewBridgePodNetwork() *PodNetwork {
|
||||
pn := NewPodNetwork("")
|
||||
return pn.SetMode(BridgeNetworkMode)
|
||||
}
|
||||
|
||||
// NewContainerPodNetwork creates a PodNetwork for a container
|
||||
func NewContainerPodNetwork(name string) *PodNetwork {
|
||||
pn := NewPodNetwork(name)
|
||||
return pn.SetMode(ContainerNetworkMode)
|
||||
}
|
||||
|
||||
// NewHostPodNetwork creates a PodNetwork for a container in host mode
|
||||
func NewHostPodNetwork() *PodNetwork {
|
||||
pn := NewPodNetwork("")
|
||||
return pn.SetMode(HostNetworkMode)
|
||||
}
|
||||
|
||||
// SetName sets the name of a PodNetwork
|
||||
func (n *PodNetwork) SetName(name string) *PodNetwork {
|
||||
n.Name = name
|
||||
return n
|
||||
}
|
||||
|
||||
// SetMode sets the mode of a PodNetwork
|
||||
func (n *PodNetwork) SetMode(mode PodNetworkMode) *PodNetwork {
|
||||
n.Mode = mode
|
||||
return n
|
||||
}
|
||||
|
||||
// Label sets a label of a PodNetwork
|
||||
func (n *PodNetwork) Label(key, value string) *PodNetwork {
|
||||
n.Labels[key] = value
|
||||
return n
|
||||
}
|
||||
|
||||
// SetName sets the name for a PodEndpoint
|
||||
func (e *PodEndpoint) SetName(name string) *PodEndpoint {
|
||||
e.Name = name
|
||||
return e
|
||||
}
|
||||
|
||||
// SetContainerPort sets the container port for a PodEndpoint
|
||||
func (e *PodEndpoint) SetContainerPort(port int) *PodEndpoint {
|
||||
e.ContainerPort = port
|
||||
return e
|
||||
}
|
||||
|
||||
// SetHostPort sets the host port for a PodEndpoint
|
||||
func (e *PodEndpoint) SetHostPort(port int) *PodEndpoint {
|
||||
e.HostPort = port
|
||||
return e
|
||||
}
|
||||
|
||||
// AddProtocol appends a protocol for a PodEndpoint
|
||||
func (e *PodEndpoint) AddProtocol(protocol string) *PodEndpoint {
|
||||
e.Protocol = append(e.Protocol, protocol)
|
||||
return e
|
||||
}
|
||||
|
||||
// Label sets a label for a PodEndpoint
|
||||
func (e *PodEndpoint) Label(key, value string) *PodEndpoint {
|
||||
e.Labels[key] = value
|
||||
return e
|
||||
}
|
277
vendor/github.com/gambol99/go-marathon/pod.go
generated
vendored
Normal file
277
vendor/github.com/gambol99/go-marathon/pod.go
generated
vendored
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Pod is the definition for an pod in marathon
|
||||
type Pod struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
// Non-secret environment variables. Actual secrets are stored in Secrets
|
||||
// Magic happens at marshaling/unmarshaling to get them into the correct schema
|
||||
Env map[string]string `json:"-"`
|
||||
Secrets map[string]Secret `json:"-"`
|
||||
Containers []*PodContainer `json:"containers,omitempty"`
|
||||
Volumes []*PodVolume `json:"volumes,omitempty"`
|
||||
Networks []*PodNetwork `json:"networks,omitempty"`
|
||||
Scaling *PodScalingPolicy `json:"scaling,omitempty"`
|
||||
Scheduling *PodSchedulingPolicy `json:"scheduling,omitempty"`
|
||||
ExecutorResources *ExecutorResources `json:"executorResources,omitempty"`
|
||||
}
|
||||
|
||||
// PodScalingPolicy is the scaling policy of the pod
|
||||
type PodScalingPolicy struct {
|
||||
Kind string `json:"kind"`
|
||||
Instances int `json:"instances"`
|
||||
MaxInstances int `json:"maxInstances,omitempty"`
|
||||
}
|
||||
|
||||
// NewPod create an empty pod
|
||||
func NewPod() *Pod {
|
||||
return &Pod{
|
||||
Labels: map[string]string{},
|
||||
Env: map[string]string{},
|
||||
Containers: []*PodContainer{},
|
||||
Secrets: map[string]Secret{},
|
||||
Volumes: []*PodVolume{},
|
||||
Networks: []*PodNetwork{},
|
||||
}
|
||||
}
|
||||
|
||||
// Name sets the name / ID of the pod i.e. the identifier for this pod
|
||||
func (p *Pod) Name(id string) *Pod {
|
||||
p.ID = validateID(id)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetUser sets the user to run the pod as
|
||||
func (p *Pod) SetUser(user string) *Pod {
|
||||
p.User = user
|
||||
return p
|
||||
}
|
||||
|
||||
// EmptyLabels empties the labels in a pod
|
||||
func (p *Pod) EmptyLabels() *Pod {
|
||||
p.Labels = make(map[string]string)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddLabel adds a label to a pod
|
||||
func (p *Pod) AddLabel(key, value string) *Pod {
|
||||
p.Labels[key] = value
|
||||
return p
|
||||
}
|
||||
|
||||
// SetLabels sets the labels for a pod
|
||||
func (p *Pod) SetLabels(labels map[string]string) *Pod {
|
||||
p.Labels = labels
|
||||
return p
|
||||
}
|
||||
|
||||
// EmptyEnvs empties the environment variables for a pod
|
||||
func (p *Pod) EmptyEnvs() *Pod {
|
||||
p.Env = make(map[string]string)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddEnv adds an environment variable to a pod
|
||||
func (p *Pod) AddEnv(name, value string) *Pod {
|
||||
if p.Env == nil {
|
||||
p = p.EmptyEnvs()
|
||||
}
|
||||
p.Env[name] = value
|
||||
return p
|
||||
}
|
||||
|
||||
// ExtendEnv extends the environment with the new environment variables
|
||||
func (p *Pod) ExtendEnv(env map[string]string) *Pod {
|
||||
if p.Env == nil {
|
||||
p = p.EmptyEnvs()
|
||||
}
|
||||
|
||||
for k, v := range env {
|
||||
p.AddEnv(k, v)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// AddContainer adds a container to a pod
|
||||
func (p *Pod) AddContainer(container *PodContainer) *Pod {
|
||||
p.Containers = append(p.Containers, container)
|
||||
return p
|
||||
}
|
||||
|
||||
// EmptySecrets empties the secret sources in a pod
|
||||
func (p *Pod) EmptySecrets() *Pod {
|
||||
p.Secrets = make(map[string]Secret)
|
||||
return p
|
||||
}
|
||||
|
||||
// GetSecretSource gets the source of the named secret
|
||||
func (p *Pod) GetSecretSource(name string) (string, error) {
|
||||
if val, ok := p.Secrets[name]; ok {
|
||||
return val.Source, nil
|
||||
}
|
||||
return "", fmt.Errorf("secret does not exist")
|
||||
}
|
||||
|
||||
// AddSecret adds the secret to the pod
|
||||
func (p *Pod) AddSecret(envVar, secretName, sourceName string) *Pod {
|
||||
if p.Secrets == nil {
|
||||
p = p.EmptySecrets()
|
||||
}
|
||||
p.Secrets[secretName] = Secret{EnvVar: envVar, Source: sourceName}
|
||||
return p
|
||||
}
|
||||
|
||||
// AddVolume adds a volume to a pod
|
||||
func (p *Pod) AddVolume(vol *PodVolume) *Pod {
|
||||
p.Volumes = append(p.Volumes, vol)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddNetwork adds a PodNetwork to a pod
|
||||
func (p *Pod) AddNetwork(net *PodNetwork) *Pod {
|
||||
p.Networks = append(p.Networks, net)
|
||||
return p
|
||||
}
|
||||
|
||||
// Count sets the count of the pod
|
||||
func (p *Pod) Count(count int) *Pod {
|
||||
p.Scaling = &PodScalingPolicy{
|
||||
Kind: "fixed",
|
||||
Instances: count,
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// SetPodSchedulingPolicy sets the PodSchedulingPolicy of a pod
|
||||
func (p *Pod) SetPodSchedulingPolicy(policy *PodSchedulingPolicy) *Pod {
|
||||
p.Scheduling = policy
|
||||
return p
|
||||
}
|
||||
|
||||
// SetExecutorResources sets the resources for the pod executor
|
||||
func (p *Pod) SetExecutorResources(resources *ExecutorResources) *Pod {
|
||||
p.ExecutorResources = resources
|
||||
return p
|
||||
}
|
||||
|
||||
// SupportsPods determines if this version of marathon supports pods
|
||||
// If HEAD returns 200 it does
|
||||
func (r *marathonClient) SupportsPods() (bool, error) {
|
||||
if err := r.apiHead(marathonAPIPods, nil); err != nil {
|
||||
// If we get a 404 we can return a strict false, otherwise it could be
|
||||
// a valid error
|
||||
if apiErr, ok := err.(*APIError); ok && apiErr.ErrCode == ErrCodeNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Pod gets a pod object from marathon by name
|
||||
func (r *marathonClient) Pod(name string) (*Pod, error) {
|
||||
uri := buildPodURI(name)
|
||||
result := new(Pod)
|
||||
if err := r.apiGet(uri, nil, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Pods gets all pods from marathon
|
||||
func (r *marathonClient) Pods() ([]Pod, error) {
|
||||
var result []Pod
|
||||
if err := r.apiGet(marathonAPIPods, nil, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CreatePod creates a new pod in Marathon
|
||||
func (r *marathonClient) CreatePod(pod *Pod) (*Pod, error) {
|
||||
result := new(Pod)
|
||||
if err := r.apiPost(marathonAPIPods, &pod, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeletePod deletes a pod from marathon
|
||||
func (r *marathonClient) DeletePod(name string, force bool) (*DeploymentID, error) {
|
||||
uri := fmt.Sprintf("%s?force=%v", buildPodURI(name), force)
|
||||
|
||||
deployID := new(DeploymentID)
|
||||
if err := r.apiDelete(uri, nil, deployID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deployID, nil
|
||||
}
|
||||
|
||||
// UpdatePod creates a new pod in Marathon
|
||||
func (r *marathonClient) UpdatePod(pod *Pod, force bool) (*Pod, error) {
|
||||
uri := fmt.Sprintf("%s?force=%v", buildPodURI(pod.ID), force)
|
||||
result := new(Pod)
|
||||
|
||||
if err := r.apiPut(uri, pod, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PodVersions gets all the deployed versions of a pod
|
||||
func (r *marathonClient) PodVersions(name string) ([]string, error) {
|
||||
uri := buildPodVersionURI(name)
|
||||
var result []string
|
||||
if err := r.apiGet(uri, nil, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PodByVersion gets a pod by a version identifier
|
||||
func (r *marathonClient) PodByVersion(name, version string) (*Pod, error) {
|
||||
uri := fmt.Sprintf("%s/%s", buildPodVersionURI(name), version)
|
||||
result := new(Pod)
|
||||
if err := r.apiGet(uri, nil, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func buildPodVersionURI(name string) string {
|
||||
return fmt.Sprintf("%s/%s::versions", marathonAPIPods, trimRootPath(name))
|
||||
}
|
||||
|
||||
func buildPodURI(path string) string {
|
||||
return fmt.Sprintf("%s/%s", marathonAPIPods, trimRootPath(path))
|
||||
}
|
193
vendor/github.com/gambol99/go-marathon/pod_container.go
generated
vendored
Normal file
193
vendor/github.com/gambol99/go-marathon/pod_container.go
generated
vendored
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// PodContainer describes a container in a pod
|
||||
type PodContainer struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Exec *PodExec `json:"exec,omitempty"`
|
||||
Resources *Resources `json:"resources,omitempty"`
|
||||
Endpoints []*PodEndpoint `json:"endpoints,omitempty"`
|
||||
Image *PodContainerImage `json:"image,omitempty"`
|
||||
Env map[string]string `json:"-"`
|
||||
Secrets map[string]Secret `json:"-"`
|
||||
User string `json:"user,omitempty"`
|
||||
HealthCheck *PodHealthCheck `json:"healthCheck,omitempty"`
|
||||
VolumeMounts []*PodVolumeMount `json:"volumeMounts,omitempty"`
|
||||
Artifacts []*PodArtifact `json:"artifacts,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Lifecycle PodLifecycle `json:"lifecycle,omitempty"`
|
||||
}
|
||||
|
||||
// PodLifecycle describes the lifecycle of a pod
|
||||
type PodLifecycle struct {
|
||||
KillGracePeriodSeconds *float64 `json:"killGracePeriodSeconds,omitempty"`
|
||||
}
|
||||
|
||||
// PodCommand is the command to run as the entrypoint of the container
|
||||
type PodCommand struct {
|
||||
Shell string `json:"shell,omitempty"`
|
||||
}
|
||||
|
||||
// PodExec contains the PodCommand
|
||||
type PodExec struct {
|
||||
Command PodCommand `json:"command,omitempty"`
|
||||
}
|
||||
|
||||
// PodArtifact describes how to obtain a generic artifact for a pod
|
||||
type PodArtifact struct {
|
||||
URI string `json:"uri,omitempty"`
|
||||
Extract bool `json:"extract,omitempty"`
|
||||
Executable bool `json:"executable,omitempty"`
|
||||
Cache bool `json:"cache,omitempty"`
|
||||
DestPath string `json:"destPath,omitempty"`
|
||||
}
|
||||
|
||||
// NewPodContainer creates an empty PodContainer
|
||||
func NewPodContainer() *PodContainer {
|
||||
return &PodContainer{
|
||||
Endpoints: []*PodEndpoint{},
|
||||
Env: map[string]string{},
|
||||
VolumeMounts: []*PodVolumeMount{},
|
||||
Artifacts: []*PodArtifact{},
|
||||
Labels: map[string]string{},
|
||||
Resources: NewResources(),
|
||||
}
|
||||
}
|
||||
|
||||
// SetName sets the name of a pod container
|
||||
func (p *PodContainer) SetName(name string) *PodContainer {
|
||||
p.Name = name
|
||||
return p
|
||||
}
|
||||
|
||||
// SetCommand sets the shell command of a pod container
|
||||
func (p *PodContainer) SetCommand(name string) *PodContainer {
|
||||
p.Exec = &PodExec{
|
||||
Command: PodCommand{
|
||||
Shell: name,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// CPUs sets the CPUs of a pod container
|
||||
func (p *PodContainer) CPUs(cpu float64) *PodContainer {
|
||||
p.Resources.Cpus = cpu
|
||||
return p
|
||||
}
|
||||
|
||||
// Memory sets the memory of a pod container
|
||||
func (p *PodContainer) Memory(memory float64) *PodContainer {
|
||||
p.Resources.Mem = memory
|
||||
return p
|
||||
}
|
||||
|
||||
// Storage sets the storage capacity of a pod container
|
||||
func (p *PodContainer) Storage(disk float64) *PodContainer {
|
||||
p.Resources.Disk = disk
|
||||
return p
|
||||
}
|
||||
|
||||
// GPUs sets the GPU requirements of a pod container
|
||||
func (p *PodContainer) GPUs(gpu int32) *PodContainer {
|
||||
p.Resources.Gpus = gpu
|
||||
return p
|
||||
}
|
||||
|
||||
// AddEndpoint appends an endpoint for a pod container
|
||||
func (p *PodContainer) AddEndpoint(endpoint *PodEndpoint) *PodContainer {
|
||||
p.Endpoints = append(p.Endpoints, endpoint)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetImage sets the image of a pod container
|
||||
func (p *PodContainer) SetImage(image *PodContainerImage) *PodContainer {
|
||||
p.Image = image
|
||||
return p
|
||||
}
|
||||
|
||||
// EmptyEnvironment initialized env to empty
|
||||
func (p *PodContainer) EmptyEnvs() *PodContainer {
|
||||
p.Env = make(map[string]string)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddEnvironment adds an environment variable for a pod container
|
||||
func (p *PodContainer) AddEnv(name, value string) *PodContainer {
|
||||
if p.Env == nil {
|
||||
p = p.EmptyEnvs()
|
||||
}
|
||||
p.Env[name] = value
|
||||
return p
|
||||
}
|
||||
|
||||
// ExtendEnvironment extends the environment for a pod container
|
||||
func (p *PodContainer) ExtendEnv(env map[string]string) *PodContainer {
|
||||
if p.Env == nil {
|
||||
p = p.EmptyEnvs()
|
||||
}
|
||||
for k, v := range env {
|
||||
p.AddEnv(k, v)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// AddSecret adds a secret to the environment for a pod container
|
||||
func (p *PodContainer) AddSecret(name, secretName string) *PodContainer {
|
||||
if p.Env == nil {
|
||||
p = p.EmptyEnvs()
|
||||
}
|
||||
p.Env[name] = secretName
|
||||
return p
|
||||
}
|
||||
|
||||
// SetUser sets the user to run the pod as
|
||||
func (p *PodContainer) SetUser(user string) *PodContainer {
|
||||
p.User = user
|
||||
return p
|
||||
}
|
||||
|
||||
// SetHealthCheck sets the health check of a pod container
|
||||
func (p *PodContainer) SetHealthCheck(healthcheck *PodHealthCheck) *PodContainer {
|
||||
p.HealthCheck = healthcheck
|
||||
return p
|
||||
}
|
||||
|
||||
// AddVolumeMount appends a volume mount to a pod container
|
||||
func (p *PodContainer) AddVolumeMount(mount *PodVolumeMount) *PodContainer {
|
||||
p.VolumeMounts = append(p.VolumeMounts, mount)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddArtifact appends an artifact to a pod container
|
||||
func (p *PodContainer) AddArtifact(artifact *PodArtifact) *PodContainer {
|
||||
p.Artifacts = append(p.Artifacts, artifact)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddLabel adds a label to a pod container
|
||||
func (p *PodContainer) AddLabel(key, value string) *PodContainer {
|
||||
p.Labels[key] = value
|
||||
return p
|
||||
}
|
||||
|
||||
// SetLifecycle sets the lifecycle of a pod container
|
||||
func (p *PodContainer) SetLifecycle(lifecycle PodLifecycle) *PodContainer {
|
||||
p.Lifecycle = lifecycle
|
||||
return p
|
||||
}
|
57
vendor/github.com/gambol99/go-marathon/pod_container_image.go
generated
vendored
Normal file
57
vendor/github.com/gambol99/go-marathon/pod_container_image.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// ImageType represents the image format type
|
||||
type ImageType string
|
||||
|
||||
const (
|
||||
// ImageTypeDocker is the docker format
|
||||
ImageTypeDocker ImageType = "DOCKER"
|
||||
|
||||
// ImageTypeAppC is the appc format
|
||||
ImageTypeAppC ImageType = "APPC"
|
||||
)
|
||||
|
||||
// PodContainerImage describes how to retrieve the container image
|
||||
type PodContainerImage struct {
|
||||
Kind ImageType `json:"kind,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
ForcePull bool `json:"forcePull,omitempty"`
|
||||
}
|
||||
|
||||
// NewPodContainerImage creates an empty PodContainerImage
|
||||
func NewPodContainerImage() *PodContainerImage {
|
||||
return &PodContainerImage{}
|
||||
}
|
||||
|
||||
// SetKind sets the Kind of the image
|
||||
func (i *PodContainerImage) SetKind(typ ImageType) *PodContainerImage {
|
||||
i.Kind = typ
|
||||
return i
|
||||
}
|
||||
|
||||
// SetID sets the ID of the image
|
||||
func (i *PodContainerImage) SetID(id string) *PodContainerImage {
|
||||
i.ID = id
|
||||
return i
|
||||
}
|
||||
|
||||
// NewDockerPodContainerImage creates a docker PodContainerImage
|
||||
func NewDockerPodContainerImage() *PodContainerImage {
|
||||
return NewPodContainerImage().SetKind(ImageTypeDocker)
|
||||
}
|
94
vendor/github.com/gambol99/go-marathon/pod_container_marshalling.go
generated
vendored
Normal file
94
vendor/github.com/gambol99/go-marathon/pod_container_marshalling.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PodContainerAlias aliases the PodContainer struct so that it will be marshaled/unmarshaled automatically
|
||||
type PodContainerAlias PodContainer
|
||||
|
||||
// UnmarshalJSON unmarshals the given PodContainer JSON as expected except for environment variables and secrets.
|
||||
// Environment variables are stored in the Env field. Secrets, including the environment variable part,
|
||||
// are stored in the Secrets field.
|
||||
func (p *PodContainer) UnmarshalJSON(b []byte) error {
|
||||
aux := &struct {
|
||||
*PodContainerAlias
|
||||
Env map[string]interface{} `json:"environment"`
|
||||
}{
|
||||
PodContainerAlias: (*PodContainerAlias)(p),
|
||||
}
|
||||
if err := json.Unmarshal(b, aux); err != nil {
|
||||
return fmt.Errorf("malformed pod container definition %v", err)
|
||||
}
|
||||
env := map[string]string{}
|
||||
secrets := map[string]Secret{}
|
||||
|
||||
for envName, genericEnvValue := range aux.Env {
|
||||
switch envValOrSecret := genericEnvValue.(type) {
|
||||
case string:
|
||||
env[envName] = envValOrSecret
|
||||
case map[string]interface{}:
|
||||
for secret, secretStore := range envValOrSecret {
|
||||
if secStore, ok := secretStore.(string); ok && secret == "secret" {
|
||||
secrets[secStore] = Secret{EnvVar: envName}
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("unexpected secret field %v of value type %T", secret, envValOrSecret[secret])
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unexpected environment variable type %T", envValOrSecret)
|
||||
}
|
||||
}
|
||||
p.Env = env
|
||||
for k, v := range aux.Secrets {
|
||||
tmp := secrets[k]
|
||||
tmp.Source = v.Source
|
||||
secrets[k] = tmp
|
||||
}
|
||||
p.Secrets = secrets
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the given PodContainer as expected except for environment variables and secrets,
|
||||
// which are marshaled from specialized structs. The environment variable piece of the secrets and other
|
||||
// normal environment variables are combined and marshaled to the env field. The secrets and the related
|
||||
// source are marshaled into the secrets field.
|
||||
func (p *PodContainer) MarshalJSON() ([]byte, error) {
|
||||
env := make(map[string]interface{})
|
||||
secrets := make(map[string]TmpSecret)
|
||||
|
||||
if p.Env != nil {
|
||||
for k, v := range p.Env {
|
||||
env[string(k)] = string(v)
|
||||
}
|
||||
}
|
||||
if p.Secrets != nil {
|
||||
for k, v := range p.Secrets {
|
||||
env[v.EnvVar] = TmpEnvSecret{Secret: k}
|
||||
secrets[k] = TmpSecret{v.Source}
|
||||
}
|
||||
}
|
||||
aux := &struct {
|
||||
*PodContainerAlias
|
||||
Env map[string]interface{} `json:"environment,omitempty"`
|
||||
}{PodContainerAlias: (*PodContainerAlias)(p), Env: env}
|
||||
|
||||
return json.Marshal(aux)
|
||||
}
|
105
vendor/github.com/gambol99/go-marathon/pod_instance.go
generated
vendored
Normal file
105
vendor/github.com/gambol99/go-marathon/pod_instance.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PodInstance is the representation of an instance as returned by deleting an instance
|
||||
type PodInstance struct {
|
||||
InstanceID PodInstanceID `json:"instanceId"`
|
||||
AgentInfo PodAgentInfo `json:"agentInfo"`
|
||||
TasksMap map[string]PodTask `json:"tasksMap"`
|
||||
RunSpecVersion time.Time `json:"runSpecVersion"`
|
||||
State PodInstanceStateHistory `json:"state"`
|
||||
UnreachableStrategy EnabledUnreachableStrategy `json:"unreachableStrategy"`
|
||||
}
|
||||
|
||||
// PodInstanceStateHistory is the pod instance's state
|
||||
type PodInstanceStateHistory struct {
|
||||
Condition PodTaskCondition `json:"condition"`
|
||||
Since time.Time `json:"since"`
|
||||
ActiveSince time.Time `json:"activeSince"`
|
||||
}
|
||||
|
||||
// PodInstanceID contains the instance ID
|
||||
type PodInstanceID struct {
|
||||
ID string `json:"idString"`
|
||||
}
|
||||
|
||||
// PodAgentInfo contains info about the agent the instance is running on
|
||||
type PodAgentInfo struct {
|
||||
Host string `json:"host"`
|
||||
AgentID string `json:"agentId"`
|
||||
Attributes []string `json:"attributes"`
|
||||
}
|
||||
|
||||
// PodTask contains the info about the specific task within the instance
|
||||
type PodTask struct {
|
||||
TaskID string `json:"taskId"`
|
||||
RunSpecVersion time.Time `json:"runSpecVersion"`
|
||||
Status PodTaskStatus `json:"status"`
|
||||
}
|
||||
|
||||
// PodTaskStatus is the current status of the task
|
||||
type PodTaskStatus struct {
|
||||
StagedAt time.Time `json:"stagedAt"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
MesosStatus string `json:"mesosStatus"`
|
||||
Condition PodTaskCondition `json:"condition"`
|
||||
NetworkInfo PodNetworkInfo `json:"networkInfo"`
|
||||
}
|
||||
|
||||
// PodTaskCondition contains a string representation of the condition
|
||||
type PodTaskCondition struct {
|
||||
Str string `json:"str"`
|
||||
}
|
||||
|
||||
// PodNetworkInfo contains the network info for a task
|
||||
type PodNetworkInfo struct {
|
||||
HostName string `json:"hostName"`
|
||||
HostPorts []int `json:"hostPorts"`
|
||||
IPAddresses []IPAddress `json:"ipAddresses"`
|
||||
}
|
||||
|
||||
// DeletePodInstances deletes all instances of the named pod
|
||||
func (r *marathonClient) DeletePodInstances(name string, instances []string) ([]*PodInstance, error) {
|
||||
uri := buildPodInstancesURI(name)
|
||||
var result []*PodInstance
|
||||
if err := r.apiDelete(uri, instances, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeletePodInstance deletes a specific instance of a pod
|
||||
func (r *marathonClient) DeletePodInstance(name, instance string) (*PodInstance, error) {
|
||||
uri := fmt.Sprintf("%s/%s", buildPodInstancesURI(name), instance)
|
||||
result := new(PodInstance)
|
||||
if err := r.apiDelete(uri, nil, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func buildPodInstancesURI(path string) string {
|
||||
return fmt.Sprintf("%s/%s::instances", marathonAPIPods, trimRootPath(path))
|
||||
}
|
89
vendor/github.com/gambol99/go-marathon/pod_instance_status.go
generated
vendored
Normal file
89
vendor/github.com/gambol99/go-marathon/pod_instance_status.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// PodInstanceState is the state of a specific pod instance
|
||||
type PodInstanceState string
|
||||
|
||||
const (
|
||||
// PodInstanceStatePending is when an instance is pending scheduling
|
||||
PodInstanceStatePending PodInstanceState = "PENDING"
|
||||
|
||||
// PodInstanceStateStaging is when an instance is staged to be scheduled
|
||||
PodInstanceStateStaging PodInstanceState = "STAGING"
|
||||
|
||||
// PodInstanceStateStable is when an instance is stably running
|
||||
PodInstanceStateStable PodInstanceState = "STABLE"
|
||||
|
||||
// PodInstanceStateDegraded is when an instance is degraded status
|
||||
PodInstanceStateDegraded PodInstanceState = "DEGRADED"
|
||||
|
||||
// PodInstanceStateTerminal is when an instance is terminal
|
||||
PodInstanceStateTerminal PodInstanceState = "TERMINAL"
|
||||
)
|
||||
|
||||
// PodInstanceStatus is the status of a pod instance
|
||||
type PodInstanceStatus struct {
|
||||
AgentHostname string `json:"agentHostname,omitempty"`
|
||||
Conditions []*StatusCondition `json:"conditions,omitempty"`
|
||||
Containers []*ContainerStatus `json:"containers,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
LastChanged string `json:"lastChanged,omitempty"`
|
||||
LastUpdated string `json:"lastUpdated,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Networks []*PodNetworkStatus `json:"networks,omitempty"`
|
||||
Resources *Resources `json:"resources,omitempty"`
|
||||
SpecReference string `json:"specReference,omitempty"`
|
||||
Status PodInstanceState `json:"status,omitempty"`
|
||||
StatusSince string `json:"statusSince,omitempty"`
|
||||
}
|
||||
|
||||
// PodNetworkStatus is the networks attached to a pod instance
|
||||
type PodNetworkStatus struct {
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// StatusCondition describes info about a status change
|
||||
type StatusCondition struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
LastChanged string `json:"lastChanged,omitempty"`
|
||||
LastUpdated string `json:"lastUpdated,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerStatus contains all status information for a container instance
|
||||
type ContainerStatus struct {
|
||||
Conditions []*StatusCondition `json:"conditions,omitempty"`
|
||||
ContainerID string `json:"containerId,omitempty"`
|
||||
Endpoints []*PodEndpoint `json:"endpoints,omitempty"`
|
||||
LastChanged string `json:"lastChanged,omitempty"`
|
||||
LastUpdated string `json:"lastUpdated,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Resources *Resources `json:"resources,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
StatusSince string `json:"statusSince,omitempty"`
|
||||
Termination *ContainerTerminationState `json:"termination,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerTerminationState describes why a container terminated
|
||||
type ContainerTerminationState struct {
|
||||
ExitCode int `json:"exitCode,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
100
vendor/github.com/gambol99/go-marathon/pod_marshalling.go
generated
vendored
Normal file
100
vendor/github.com/gambol99/go-marathon/pod_marshalling.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PodAlias aliases the Pod struct so that it will be marshaled/unmarshaled automatically
|
||||
type PodAlias Pod
|
||||
|
||||
// UnmarshalJSON unmarshals the given Pod JSON as expected except for environment variables and secrets.
|
||||
// Environment variables are stored in the Env field. Secrets, including the environment variable part,
|
||||
// are stored in the Secrets field.
|
||||
func (p *Pod) UnmarshalJSON(b []byte) error {
|
||||
aux := &struct {
|
||||
*PodAlias
|
||||
Env map[string]interface{} `json:"environment"`
|
||||
Secrets map[string]TmpSecret `json:"secrets"`
|
||||
}{
|
||||
PodAlias: (*PodAlias)(p),
|
||||
}
|
||||
if err := json.Unmarshal(b, aux); err != nil {
|
||||
return fmt.Errorf("malformed pod definition %v", err)
|
||||
}
|
||||
env := map[string]string{}
|
||||
secrets := map[string]Secret{}
|
||||
|
||||
for envName, genericEnvValue := range aux.Env {
|
||||
switch envValOrSecret := genericEnvValue.(type) {
|
||||
case string:
|
||||
env[envName] = envValOrSecret
|
||||
case map[string]interface{}:
|
||||
for secret, secretStore := range envValOrSecret {
|
||||
if secStore, ok := secretStore.(string); ok && secret == "secret" {
|
||||
secrets[secStore] = Secret{EnvVar: envName}
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("unexpected secret field %v of value type %T", secret, envValOrSecret[secret])
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unexpected environment variable type %T", envValOrSecret)
|
||||
}
|
||||
}
|
||||
p.Env = env
|
||||
for k, v := range aux.Secrets {
|
||||
tmp := secrets[k]
|
||||
tmp.Source = v.Source
|
||||
secrets[k] = tmp
|
||||
}
|
||||
p.Secrets = secrets
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the given Pod as expected except for environment variables and secrets,
|
||||
// which are marshaled from specialized structs. The environment variable piece of the secrets and other
|
||||
// normal environment variables are combined and marshaled to the env field. The secrets and the related
|
||||
// source are marshaled into the secrets field.
|
||||
func (p *Pod) MarshalJSON() ([]byte, error) {
|
||||
env := make(map[string]interface{})
|
||||
secrets := make(map[string]TmpSecret)
|
||||
|
||||
if p.Env != nil {
|
||||
for k, v := range p.Env {
|
||||
env[string(k)] = string(v)
|
||||
}
|
||||
}
|
||||
if p.Secrets != nil {
|
||||
for k, v := range p.Secrets {
|
||||
// Only add it to the root level pod environment if it's used
|
||||
// Otherwise it's likely in one of the container environments
|
||||
if v.EnvVar != "" {
|
||||
env[v.EnvVar] = TmpEnvSecret{Secret: k}
|
||||
}
|
||||
secrets[k] = TmpSecret{v.Source}
|
||||
}
|
||||
}
|
||||
aux := &struct {
|
||||
*PodAlias
|
||||
Env map[string]interface{} `json:"environment,omitempty"`
|
||||
Secrets map[string]TmpSecret `json:"secrets,omitempty"`
|
||||
}{PodAlias: (*PodAlias)(p), Env: env, Secrets: secrets}
|
||||
|
||||
return json.Marshal(aux)
|
||||
}
|
75
vendor/github.com/gambol99/go-marathon/pod_scheduling.go
generated
vendored
Normal file
75
vendor/github.com/gambol99/go-marathon/pod_scheduling.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// PodBackoff describes the backoff for re-run attempts of a pod
|
||||
type PodBackoff struct {
|
||||
Backoff *int `json:"backoff,omitempty"`
|
||||
BackoffFactor *float64 `json:"backoffFactor,omitempty"`
|
||||
MaxLaunchDelay *int `json:"maxLaunchDelay,omitempty"`
|
||||
}
|
||||
|
||||
// PodUpgrade describes the policy for upgrading a pod in-place
|
||||
type PodUpgrade struct {
|
||||
MinimumHealthCapacity *float64 `json:"minimumHealthCapacity,omitempty"`
|
||||
MaximumOverCapacity *float64 `json:"maximumOverCapacity,omitempty"`
|
||||
}
|
||||
|
||||
// PodPlacement supports constraining which hosts a pod is placed on
|
||||
type PodPlacement struct {
|
||||
Constraints *[]Constraint `json:"constraints"`
|
||||
AcceptedResourceRoles []string `json:"acceptedResourceRoles,omitempty"`
|
||||
}
|
||||
|
||||
// PodSchedulingPolicy is the overarching pod scheduling policy
|
||||
type PodSchedulingPolicy struct {
|
||||
Backoff *PodBackoff `json:"backoff,omitempty"`
|
||||
Upgrade *PodUpgrade `json:"upgrade,omitempty"`
|
||||
Placement *PodPlacement `json:"placement,omitempty"`
|
||||
}
|
||||
|
||||
// Constraint describes the constraint for pod placement
|
||||
type Constraint struct {
|
||||
FieldName string `json:"fieldName"`
|
||||
Operator string `json:"operator"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// NewPodPlacement creates an empty PodPlacement
|
||||
func NewPodPlacement() *PodPlacement {
|
||||
return &PodPlacement{
|
||||
Constraints: &[]Constraint{},
|
||||
AcceptedResourceRoles: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddConstraint adds a new constraint
|
||||
// constraints: the constraint definition, one constraint per array element
|
||||
func (r *PodPlacement) AddConstraint(constraint Constraint) *PodPlacement {
|
||||
c := *r.Constraints
|
||||
c = append(c, constraint)
|
||||
r.Constraints = &c
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// NewPodSchedulingPolicy creates an empty PodSchedulingPolicy
|
||||
func NewPodSchedulingPolicy() *PodSchedulingPolicy {
|
||||
return &PodSchedulingPolicy{
|
||||
Placement: NewPodPlacement(),
|
||||
}
|
||||
}
|
108
vendor/github.com/gambol99/go-marathon/pod_status.go
generated
vendored
Normal file
108
vendor/github.com/gambol99/go-marathon/pod_status.go
generated
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PodState defines the state of a pod
|
||||
type PodState string
|
||||
|
||||
const (
|
||||
// PodStateDegraded is a degraded pod
|
||||
PodStateDegraded PodState = "DEGRADED"
|
||||
|
||||
// PodStateStable is a stable pod
|
||||
PodStateStable PodState = "STABLE"
|
||||
|
||||
// PodStateTerminal is a terminal pod
|
||||
PodStateTerminal PodState = "TERMINAL"
|
||||
)
|
||||
|
||||
// PodStatus describes the pod status
|
||||
type PodStatus struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Spec *Pod `json:"spec,omitempty"`
|
||||
Status PodState `json:"status,omitempty"`
|
||||
StatusSince string `json:"statusSince,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Instances []*PodInstanceStatus `json:"instances,omitempty"`
|
||||
TerminationHistory []*PodTerminationHistory `json:"terminationHistory,omitempty"`
|
||||
LastUpdated string `json:"lastUpdated,omitempty"`
|
||||
LastChanged string `json:"lastChanged,omitempty"`
|
||||
}
|
||||
|
||||
// PodTerminationHistory is the termination history of the pod
|
||||
type PodTerminationHistory struct {
|
||||
InstanceID string `json:"instanceId,omitempty"`
|
||||
StartedAt string `json:"startedAt,omitempty"`
|
||||
TerminatedAt string `json:"terminatedAt,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Containers []*ContainerTerminationHistory `json:"containers,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerTerminationHistory is the termination history of a container in a pod
|
||||
type ContainerTerminationHistory struct {
|
||||
ContainerID string `json:"containerId,omitempty"`
|
||||
LastKnownState string `json:"lastKnownState,omitempty"`
|
||||
Termination *ContainerTerminationState `json:"termination,omitempty"`
|
||||
}
|
||||
|
||||
// PodStatus retrieves the pod configuration from marathon
|
||||
func (r *marathonClient) PodStatus(name string) (*PodStatus, error) {
|
||||
var podStatus PodStatus
|
||||
|
||||
if err := r.apiGet(buildPodStatusURI(name), nil, &podStatus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &podStatus, nil
|
||||
}
|
||||
|
||||
// PodStatuses retrieves all pod configuration from marathon
|
||||
func (r *marathonClient) PodStatuses() ([]*PodStatus, error) {
|
||||
var podStatuses []*PodStatus
|
||||
|
||||
if err := r.apiGet(buildPodStatusURI(""), nil, &podStatuses); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return podStatuses, nil
|
||||
}
|
||||
|
||||
// WaitOnPod blocks until a pod to be deployed
|
||||
func (r *marathonClient) WaitOnPod(name string, timeout time.Duration) error {
|
||||
return r.wait(name, timeout, r.PodIsRunning)
|
||||
}
|
||||
|
||||
// PodIsRunning returns whether the pod is stably running
|
||||
func (r *marathonClient) PodIsRunning(name string) bool {
|
||||
podStatus, err := r.PodStatus(name)
|
||||
if apiErr, ok := err.(*APIError); ok && apiErr.ErrCode == ErrCodeNotFound {
|
||||
return false
|
||||
}
|
||||
if err == nil && podStatus.Status == PodStateStable {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func buildPodStatusURI(path string) string {
|
||||
return fmt.Sprintf("%s/%s::status", marathonAPIPods, trimRootPath(path))
|
||||
}
|
2
vendor/github.com/gambol99/go-marathon/queue.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/queue.go
generated
vendored
|
@ -32,7 +32,7 @@ type Item struct {
|
|||
Application Application `json:"app"`
|
||||
}
|
||||
|
||||
// Delay cotains the application postpone infomation
|
||||
// Delay cotains the application postpone information
|
||||
type Delay struct {
|
||||
Overdue bool `json:"overdue"`
|
||||
TimeLeftSeconds int `json:"timeLeftSeconds"`
|
||||
|
|
2
vendor/github.com/gambol99/go-marathon/residency.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/residency.go
generated
vendored
|
@ -24,7 +24,7 @@ type TaskLostBehaviorType string
|
|||
const (
|
||||
// TaskLostBehaviorTypeWaitForever indicates to not take any action when the resident task is lost
|
||||
TaskLostBehaviorTypeWaitForever TaskLostBehaviorType = "WAIT_FOREVER"
|
||||
// TaskLostBehaviorTypeWaitForever indicates to try relaunching the lost resident task on
|
||||
// TaskLostBehaviorTypeRelaunchAfterTimeout indicates to try relaunching the lost resident task on
|
||||
// another node after the relaunch escalation timeout has elapsed
|
||||
TaskLostBehaviorTypeRelaunchAfterTimeout TaskLostBehaviorType = "RELAUNCH_AFTER_TIMEOUT"
|
||||
)
|
||||
|
|
37
vendor/github.com/gambol99/go-marathon/resources.go
generated
vendored
Normal file
37
vendor/github.com/gambol99/go-marathon/resources.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// ExecutorResources are the resources supported by an executor (a task running a pod)
|
||||
type ExecutorResources struct {
|
||||
Cpus float64 `json:"cpus,omitempty"`
|
||||
Mem float64 `json:"mem,omitempty"`
|
||||
Disk float64 `json:"disk,omitempty"`
|
||||
}
|
||||
|
||||
// Resources are the full set of resources for a task
|
||||
type Resources struct {
|
||||
Cpus float64 `json:"cpus"`
|
||||
Mem float64 `json:"mem"`
|
||||
Disk float64 `json:"disk,omitempty"`
|
||||
Gpus int32 `json:"gpus,omitempty"`
|
||||
}
|
||||
|
||||
// NewResources creates an empty Resources
|
||||
func NewResources() *Resources {
|
||||
return &Resources{}
|
||||
}
|
2
vendor/github.com/gambol99/go-marathon/subscription.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/subscription.go
generated
vendored
|
@ -162,7 +162,7 @@ func (r *marathonClient) registerCallbackSubscription() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// registerSSESubscription starts a go routine that continously tries to
|
||||
// registerSSESubscription starts a go routine that continuously 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.
|
||||
|
|
5
vendor/github.com/gambol99/go-marathon/task.go
generated
vendored
5
vendor/github.com/gambol99/go-marathon/task.go
generated
vendored
|
@ -186,7 +186,10 @@ func (r *marathonClient) TaskEndpoints(name string, port int, healthCheck bool)
|
|||
// step: we need to get the port index of the service we are interested in
|
||||
portIndex, err := application.Container.Docker.ServicePortIndex(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
portIndex, err = application.Container.ServicePortIndex(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// step: do we have any tasks?
|
||||
|
|
1
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
1
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// UnreachableStrategyAbsenceReasonDisabled signifies the reason of disabled unreachable strategy
|
||||
const UnreachableStrategyAbsenceReasonDisabled = "disabled"
|
||||
|
||||
// UnreachableStrategy is the unreachable strategy applied to an application.
|
||||
|
|
45
vendor/github.com/gambol99/go-marathon/volume.go
generated
vendored
Normal file
45
vendor/github.com/gambol99/go-marathon/volume.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2017 The go-marathon Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package marathon
|
||||
|
||||
// PodVolume describes a volume on the host
|
||||
type PodVolume struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
}
|
||||
|
||||
// PodVolumeMount describes how to mount a volume into a task
|
||||
type PodVolumeMount struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
MountPath string `json:"mountPath,omitempty"`
|
||||
}
|
||||
|
||||
// NewPodVolume creates a new PodVolume
|
||||
func NewPodVolume(name, path string) *PodVolume {
|
||||
return &PodVolume{
|
||||
Name: name,
|
||||
Host: path,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPodVolumeMount creates a new PodVolumeMount
|
||||
func NewPodVolumeMount(name, mount string) *PodVolumeMount {
|
||||
return &PodVolumeMount{
|
||||
Name: name,
|
||||
MountPath: mount,
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue