From 94d909ae4981434e58ee02986597108a99c993ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 09:50:28 +0200 Subject: [PATCH 01/16] move portmappings out of docker definition, network definition into new structure --- application.go | 41 +++- application_test.go | 14 +- docker.go | 65 +++---- docker_test.go | 8 +- group_test.go | 8 +- task.go | 2 +- .../TestApplicationString-output.json | 34 ++-- tests/rest-api/methods.yml | 184 ++++++++++-------- 8 files changed, 210 insertions(+), 146 deletions(-) diff --git a/application.go b/application.go index 4ab5ddb..6ccfba3 100644 --- a/application.go +++ b/application.go @@ -54,6 +54,11 @@ type Port struct { Protocol string `json:"protocol,omitempty"` } +// Network providers info about application networking +type Network struct { + Mode string `json:"mode,omitempty"` +} + // Application is the definition for an application in marathon type Application struct { ID string `json:"id,omitempty"` @@ -64,6 +69,8 @@ type Application struct { CPUs float64 `json:"cpus,omitempty"` GPUs *float64 `json:"gpus,omitempty"` Disk *float64 `json:"disk,omitempty"` + Networks *[]Network `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"` @@ -493,7 +500,7 @@ func (r *Application) CheckHTTP(path string, port, interval int) (*Application, return nil, ErrNoApplicationContainer } // step: get the port index - portIndex, err := r.Container.Docker.ServicePortIndex(port) + portIndex, err := r.Container.ServicePortIndex(port) if err != nil { return nil, err } @@ -516,7 +523,7 @@ func (r *Application) CheckTCP(port, interval int) (*Application, error) { return nil, ErrNoApplicationContainer } // step: get the port index - portIndex, err := r.Container.Docker.ServicePortIndex(port) + portIndex, err := r.Container.ServicePortIndex(port) if err != nil { return nil, err } @@ -973,3 +980,33 @@ func (d *Discovery) AddPort(port Port) *Discovery { d.Ports = &ports return d } + +// EmptyNetworks explicitly empties networks +func (r *Application) EmptyNetworks() *Application { + r.Networks = &[]Network{} + return r +} + +// Bridged sets the networking mode to bridged +func (r *Application) Bridged() *Application { + if r.Networks == nil { + r.EmptyNetworks() + } + network := Network{Mode: "container/bridge"} + networks := *r.Networks + networks = append(networks, network) + r.Networks = &networks + return r +} + +// Host sets the networking mode to host +func (r *Application) Host() *Application { + if r.Networks == nil { + r.EmptyNetworks() + } + network := Network{Mode: "host"} + networks := *r.Networks + networks = append(networks, network) + r.Networks = &networks + return r +} diff --git a/application_test.go b/application_test.go index fba61af..f76835a 100644 --- a/application_test.go +++ b/application_test.go @@ -49,14 +49,14 @@ func TestApplicationString(t *testing.T) { Memory(64). Storage(0.0). Count(2). + Bridged(). AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). AddEnv("NAME", "frontend_http"). AddEnv("SERVICE_80_NAME", "test_http") app. - Container.Docker.Container("quay.io/gambol99/apache-php:latest"). - Bridged(). - Expose(80). - Expose(443) + Container.Expose(80).Expose(443). + Docker.Container("quay.io/gambol99/apache-php:latest") + app, err := app.CheckHTTP("/health", 80, 5) assert.Nil(t, err) @@ -292,7 +292,7 @@ func TestApplicationPortDefinitions(t *testing.T) { func TestHasHealthChecks(t *testing.T) { app := NewDockerApplication() assert.False(t, app.HasHealthChecks()) - app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + app.Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") _, err := app.CheckTCP(80, 10) assert.NoError(t, err) assert.True(t, app.HasHealthChecks()) @@ -304,7 +304,7 @@ func TestApplicationCheckTCP(t *testing.T) { _, err := app.CheckTCP(80, 10) assert.Error(t, err) assert.False(t, app.HasHealthChecks()) - app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + app.Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") _, err = app.CheckTCP(80, 10) assert.NoError(t, err) assert.True(t, app.HasHealthChecks()) @@ -320,7 +320,7 @@ func TestApplicationCheckHTTP(t *testing.T) { _, err := app.CheckHTTP("/", 80, 10) assert.Error(t, err) assert.False(t, app.HasHealthChecks()) - app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + app.Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") _, err = app.CheckHTTP("/health", 80, 10) assert.NoError(t, err) assert.True(t, app.HasHealthChecks()) diff --git a/docker.go b/docker.go index 217d3bb..9ce1559 100644 --- a/docker.go +++ b/docker.go @@ -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 @@ -122,12 +123,10 @@ type ExternalVolume struct { // Docker is the docker definition from a marathon application type Docker struct { - ForcePullImage *bool `json:"forcePullImage,omitempty"` - Image string `json:"image,omitempty"` - Network string `json:"network,omitempty"` - Parameters *[]Parameters `json:"parameters,omitempty"` - PortMappings *[]PortMapping `json:"portMappings,omitempty"` - Privileged *bool `json:"privileged,omitempty"` + ForcePullImage *bool `json:"forcePullImage,omitempty"` + Image string `json:"image,omitempty"` + Parameters *[]Parameters `json:"parameters,omitempty"` + Privileged *bool `json:"privileged,omitempty"` } // Volume attachs a volume to the container @@ -243,63 +242,51 @@ func (docker *Docker) Container(image string) *Docker { return docker } -// Bridged sets the networking mode to bridged -func (docker *Docker) Bridged() *Docker { - docker.Network = "BRIDGE" - return docker -} - -// Host sets the networking mode to host -func (docker *Docker) Host() *Docker { - docker.Network = "HOST" - return docker -} - // 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 { +func (container *Container) Expose(ports ...int) *Container { for _, port := range ports { - docker.ExposePort(PortMapping{ + container.ExposePort(PortMapping{ ContainerPort: port, HostPort: 0, ServicePort: 0, Protocol: "tcp"}) } - return docker + 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 { +func (container *Container) ExposeUDP(ports ...int) *Container { for _, port := range ports { - docker.ExposePort(PortMapping{ + container.ExposePort(PortMapping{ ContainerPort: port, HostPort: 0, ServicePort: 0, Protocol: "udp"}) } - return docker + return container } // ExposePort exposes an port in the container -func (docker *Docker) ExposePort(portMapping PortMapping) *Docker { - if docker.PortMappings == nil { - docker.EmptyPortMappings() +func (container *Container) ExposePort(portMapping PortMapping) *Container { + if container.PortMappings == nil { + container.EmptyPortMappings() } - portMappings := *docker.PortMappings + portMappings := *container.PortMappings portMappings = append(portMappings, portMapping) - docker.PortMappings = &portMappings + container.PortMappings = &portMappings - return docker + 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) -func (docker *Docker) EmptyPortMappings() *Docker { - docker.PortMappings = &[]PortMapping{} - return docker +func (container *Container) EmptyPortMappings() *Container { + container.PortMappings = &[]PortMapping{} + return container } // AddLabel adds a label to a PortMapping @@ -351,13 +338,13 @@ func (docker *Docker) EmptyParameters() *Docker { // 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) { - if docker.PortMappings == nil || len(*docker.PortMappings) == 0 { +func (container *Container) ServicePortIndex(port int) (int, error) { + if container.PortMappings == nil || len(*container.PortMappings) == 0 { return 0, errors.New("The docker does not contain any port mappings to search") } // step: iterate and find the port - for index, containerPort := range *docker.PortMappings { + for index, containerPort := range *container.PortMappings { if containerPort.ContainerPort == port { return index, nil } diff --git a/docker_test.go b/docker_test.go index 417d5bc..9cf55ad 100644 --- a/docker_test.go +++ b/docker_test.go @@ -49,9 +49,9 @@ func TestDockerAddParameter(t *testing.T) { func TestDockerExpose(t *testing.T) { app := NewDockerApplication() - app.Container.Docker.Expose(8080).Expose(80, 443) + app.Container.Expose(8080).Expose(80, 443) - portMappings := app.Container.Docker.PortMappings + portMappings := app.Container.PortMappings assert.Equal(t, 3, len(*portMappings)) assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMappings)[0]) @@ -61,9 +61,9 @@ func TestDockerExpose(t *testing.T) { func TestDockerExposeUDP(t *testing.T) { app := NewDockerApplication() - app.Container.Docker.ExposeUDP(53).ExposeUDP(5060, 6881) + app.Container.ExposeUDP(53).ExposeUDP(5060, 6881) - portMappings := app.Container.Docker.PortMappings + portMappings := app.Container.PortMappings assert.Equal(t, 3, len(*portMappings)) assert.Equal(t, *createPortMapping(53, "udp"), (*portMappings)[0]) assert.Equal(t, *createPortMapping(5060, "udp"), (*portMappings)[1]) diff --git a/group_test.go b/group_test.go index a809c8f..ae5c284 100644 --- a/group_test.go +++ b/group_test.go @@ -17,6 +17,7 @@ limitations under the License. package marathon import ( + "log" "testing" "github.com/stretchr/testify/assert" @@ -58,8 +59,11 @@ func TestGroup(t *testing.T) { for _, app := range frontend.Apps { assert.NotNil(t, app.Container) assert.NotNil(t, app.Container.Docker) - assert.Equal(t, app.Container.Docker.Network, "BRIDGE") - if len(*app.Container.Docker.PortMappings) == 0 { + log.Println(app) + for _, network := range *app.Networks { + assert.Equal(t, network.Mode, "container/bridge") + } + if len(*app.Container.PortMappings) == 0 { t.Fail() } } diff --git a/task.go b/task.go index 194319a..a28be78 100644 --- a/task.go +++ b/task.go @@ -184,7 +184,7 @@ 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) + portIndex, err := application.Container.ServicePortIndex(port) if err != nil { return nil, err } diff --git a/tests/app-definitions/TestApplicationString-output.json b/tests/app-definitions/TestApplicationString-output.json index 0725dc6..1667f19 100644 --- a/tests/app-definitions/TestApplicationString-output.json +++ b/tests/app-definitions/TestApplicationString-output.json @@ -8,24 +8,28 @@ "container": { "type": "DOCKER", "docker": { - "image": "quay.io/gambol99/apache-php:latest", - "network": "BRIDGE", - "portMappings": [ - { - "containerPort": 80, - "hostPort": 0, - "protocol": "tcp" - }, - { - "containerPort": 443, - "hostPort": 0, - "protocol": "tcp" - } - ] - } + "image": "quay.io/gambol99/apache-php:latest" + }, + "portMappings": [ + { + "containerPort": 80, + "hostPort": 0, + "protocol": "tcp" + }, + { + "containerPort": 443, + "hostPort": 0, + "protocol": "tcp" + } + ] }, "cpus": 0.1, "disk": 0, + "networks": [ + { + "mode": "container/bridge" + } + ], "healthChecks": [ { "portIndex": 0, diff --git a/tests/rest-api/methods.yml b/tests/rest-api/methods.yml index 05fb1b9..ed2da2a 100644 --- a/tests/rest-api/methods.yml +++ b/tests/rest-api/methods.yml @@ -87,22 +87,21 @@ "constraints": [], "container": { "docker": { - "image": "python:3", - "network": "BRIDGE", - "portMappings": [ - { - "containerPort": 8080, - "hostPort": 0, - "servicePort": 9000, - "protocol": "tcp" - }, - { - "containerPort": 161, - "hostPort": 0, - "protocol": "udp" - } - ] + "image": "python:3" }, + "portMappings": [ + { + "containerPort": 8080, + "hostPort": 0, + "servicePort": 9000, + "protocol": "tcp" + }, + { + "containerPort": 161, + "hostPort": 0, + "protocol": "udp" + } + ], "type": "DOCKER", "volumes": [] }, @@ -110,6 +109,11 @@ "dependencies": [], "deployments": [], "disk": 0.0, + "networks": [ + { + "mode": "container/bridge" + } + ], "env": { "VAR": "VALUE", "SECRET1": { @@ -160,22 +164,21 @@ "constraints": [], "container": { "docker": { - "image": "python:3", - "network": "BRIDGE", - "portMappings": [ - { - "containerPort": 8080, - "hostPort": 0, - "servicePort": 9000, - "protocol": "tcp" - }, - { - "containerPort": 161, - "hostPort": 0, - "protocol": "udp" - } - ] + "image": "python:3" }, + "portMappings": [ + { + "containerPort": 8080, + "hostPort": 0, + "servicePort": 9000, + "protocol": "tcp" + }, + { + "containerPort": 161, + "hostPort": 0, + "protocol": "udp" + } + ], "type": "DOCKER", "volumes": [] }, @@ -183,6 +186,11 @@ "dependencies": [], "deployments": [], "disk": 0.0, + "networks": [ + { + "mode": "container/bridge" + } + ], "env": {}, "executor": "", "healthChecks": [ @@ -313,17 +321,16 @@ "constraints": [], "container": { "docker": { - "image": "python:3", - "network": "BRIDGE", - "portMappings": [ - { - "containerPort": 8080, - "hostPort": 0, - "servicePort": 9000, - "protocol": "tcp" - } - ] + "image": "python:3" }, + "portMappings": [ + { + "containerPort": 8080, + "hostPort": 0, + "servicePort": 9000, + "protocol": "tcp" + } + ], "type": "DOCKER", "volumes": [] }, @@ -331,6 +338,11 @@ "dependencies": [], "deployments": [], "disk": 0.0, + "networks": [ + { + "mode": "container/bridge" + } + ], "env": {}, "executor": "", "healthChecks": [ @@ -434,17 +446,16 @@ "constraints": [], "container": { "docker": { - "image": "python:3", - "network": "BRIDGE", - "portMappings": [ - { - "containerPort": 8080, - "hostPort": 0, - "servicePort": 9000, - "protocol": "tcp" - } - ] + "image": "python:3" }, + "portMappings": [ + { + "containerPort": 8080, + "hostPort": 0, + "servicePort": 9000, + "protocol": "tcp" + } + ], "type": "DOCKER", "volumes": [] }, @@ -452,6 +463,11 @@ "dependencies": [], "deployments": [], "disk": 0.0, + "networks": [ + { + "mode": "container/bridge" + } + ], "env": {}, "executor": "", "healthChecks": [ @@ -568,17 +584,16 @@ "constraints": [], "container": { "docker": { - "image": "python:3", - "network": "BRIDGE", - "portMappings": [ - { - "containerPort": 8080, - "hostPort": 0, - "servicePort": 9000, - "protocol": "tcp" - } - ] + "image": "python:3" }, + "portMappings": [ + { + "containerPort": 8080, + "hostPort": 0, + "servicePort": 9000, + "protocol": "tcp" + } + ], "type": "DOCKER", "volumes": [] }, @@ -586,6 +601,11 @@ "dependencies": [], "deployments": [], "disk": 0.0, + "networks": [ + { + "mode": "container/bridge" + } + ], "env": {}, "executor": "", "healthChecks": [ @@ -801,9 +821,9 @@ "container": { "type": "DOCKER", "docker": { - "image": "quay.io/gambol99/apache-php:latest", - "network": "BRIDGE", - "portMappings": [ + "image": "quay.io/gambol99/apache-php:latest" + }, + "portMappings": [ { "containerPort": 80, "hostPort": 0, @@ -814,8 +834,7 @@ "hostPort": 0, "protocol": "tcp" } - ] - } + ] }, "healthChecks": [ { @@ -831,6 +850,11 @@ "id": "apache", "mem": 64, "args": [], + "networks": [ + { + "mode": "container/bridge" + } + ], "env": { "ENVIRONMENT": "qa", "SERVICE_80_NAME": "apache_http-qa-1", @@ -848,12 +872,11 @@ "container": { "type": "DOCKER", "docker": { - "image": "tutum/mysql", - "network": "BRIDGE", - "portMappings": [ - { "containerPort": 3306, "hostPort": 0, "protocol": "tcp" } - ] - } + "image": "tutum/mysql" + }, + "portMappings": [ + { "containerPort": 3306, "hostPort": 0, "protocol": "tcp" } + ] }, "healthChecks": [ { @@ -868,6 +891,11 @@ "id": "mysql", "mem": 1024, "cmd": "", + "networks": [ + { + "mode": "container/bridge" + } + ], "env": { "ENVIRONMENT": "qa", "SERVICE_NAME": "dbmaster", @@ -881,16 +909,15 @@ "container": { "type": "DOCKER", "docker": { - "image": "redis", - "network": "BRIDGE", - "portMappings": [ + "image": "redis" + }, + "portMappings": [ { "containerPort": 6379, "hostPort": 0, "protocol": "tcp" } - ] - } + ] }, "healthChecks": [ { @@ -905,6 +932,11 @@ "id": "caching", "cmd": "", "mem": 128, + "networks": [ + { + "mode": "container/bridge" + } + ], "env": { "ENVIRONMENT": "qa", "SERVICE_6379_NAME": "redis-qa-1" From 8bca4a21692cb1c570891685e928822b8c00c1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 10:03:12 +0200 Subject: [PATCH 02/16] remove ip per task --- application.go | 66 --------------------------------------------- application_test.go | 52 ----------------------------------- 2 files changed, 118 deletions(-) diff --git a/application.go b/application.go index 6ccfba3..91cde15 100644 --- a/application.go +++ b/application.go @@ -34,14 +34,6 @@ type Applications struct { Apps []Application `json:"apps"` } -// IPAddressPerTask is used by IP-per-task functionality https://mesosphere.github.io/marathon/docs/ip-per-task.html -type IPAddressPerTask struct { - Groups *[]string `json:"groups,omitempty"` - Labels *map[string]string `json:"labels,omitempty"` - Discovery *Discovery `json:"discovery,omitempty"` - NetworkName string `json:"networkName,omitempty"` -} - // Discovery provides info about ports expose by IP-per-task functionality type Discovery struct { Ports *[]Port `json:"ports,omitempty"` @@ -106,7 +98,6 @@ type Application struct { AcceptedResourceRoles []string `json:"acceptedResourceRoles,omitempty"` LastTaskFailure *LastTaskFailure `json:"lastTaskFailure,omitempty"` Fetch *[]Fetch `json:"fetch,omitempty"` - IPAddressPerTask *IPAddressPerTask `json:"ipAddress,omitempty"` Residency *Residency `json:"residency,omitempty"` Secrets *map[string]Secret `json:"-"` } @@ -167,17 +158,6 @@ type Secret struct { Source string } -// SetIPAddressPerTask defines that the application will have a IP address defines by a external agent. -// This configuration is not allowed to be used with Port or PortDefinitions. Thus, the implementation -// clears both. -func (r *Application) SetIPAddressPerTask(ipAddressPerTask IPAddressPerTask) *Application { - r.Ports = make([]int, 0) - r.EmptyPortDefinitions() - r.IPAddressPerTask = &ipAddressPerTask - - return r -} - // NewDockerApplication creates a default docker application func NewDockerApplication() *Application { application := new(Application) @@ -915,52 +895,6 @@ func buildPath(path string) string { return fmt.Sprintf("%s/%s", marathonAPIApps, trimRootPath(path)) } -// EmptyLabels explicitly empties labels -- use this if you need to empty -// labels of an application that already has IP per task with labels defined -func (i *IPAddressPerTask) EmptyLabels() *IPAddressPerTask { - i.Labels = &map[string]string{} - return i -} - -// AddLabel adds a label to an IPAddressPerTask -// name: The label name -// value: The label value -func (i *IPAddressPerTask) AddLabel(name, value string) *IPAddressPerTask { - if i.Labels == nil { - i.EmptyLabels() - } - (*i.Labels)[name] = value - return i -} - -// EmptyGroups explicitly empties groups -- use this if you need to empty -// groups of an application that already has IP per task with groups defined -func (i *IPAddressPerTask) EmptyGroups() *IPAddressPerTask { - i.Groups = &[]string{} - return i -} - -// AddGroup adds a group to an IPAddressPerTask -// group: The group name -func (i *IPAddressPerTask) AddGroup(group string) *IPAddressPerTask { - if i.Groups == nil { - i.EmptyGroups() - } - - groups := *i.Groups - groups = append(groups, group) - i.Groups = &groups - - return i -} - -// SetDiscovery define the discovery to an IPAddressPerTask -// discovery: The discovery struct -func (i *IPAddressPerTask) SetDiscovery(discovery Discovery) *IPAddressPerTask { - i.Discovery = &discovery - return i -} - // EmptyPorts explicitly empties discovey port -- use this if you need to empty // discovey port of an application that already has IP per task with discovey ports // defined diff --git a/application_test.go b/application_test.go index f76835a..da2c12a 100644 --- a/application_test.go +++ b/application_test.go @@ -694,58 +694,6 @@ func TestAppExistAndRunning(t *testing.T) { assert.False(t, client.appExistAndRunning("no_such_app")) } -func TestSetIPPerTask(t *testing.T) { - app := Application{} - app.Ports = append(app.Ports, 10) - app.AddPortDefinition(PortDefinition{}) - assert.Nil(t, app.IPAddressPerTask) - assert.Equal(t, 1, len(app.Ports)) - assert.Equal(t, 1, len(*app.PortDefinitions)) - - app.SetIPAddressPerTask(IPAddressPerTask{}) - assert.NotNil(t, app.IPAddressPerTask) - assert.Equal(t, 0, len(app.Ports)) - assert.Equal(t, 0, len(*app.PortDefinitions)) -} - -func TestIPAddressPerTask(t *testing.T) { - ipPerTask := IPAddressPerTask{} - assert.Nil(t, ipPerTask.Groups) - assert.Nil(t, ipPerTask.Labels) - assert.Nil(t, ipPerTask.Discovery) - - ipPerTask. - AddGroup("label"). - AddLabel("key", "value"). - SetDiscovery(Discovery{}) - - assert.Equal(t, 1, len(*ipPerTask.Groups)) - assert.Equal(t, "label", (*ipPerTask.Groups)[0]) - assert.Equal(t, "value", (*ipPerTask.Labels)["key"]) - assert.NotEmpty(t, ipPerTask.Discovery) - - ipPerTask.EmptyGroups() - assert.Equal(t, 0, len(*ipPerTask.Groups)) - - ipPerTask.EmptyLabels() - assert.Equal(t, 0, len(*ipPerTask.Labels)) - -} - -func TestIPAddressPerTaskDiscovery(t *testing.T) { - disc := Discovery{} - assert.Nil(t, disc.Ports) - - disc.AddPort(Port{}) - assert.NotNil(t, disc.Ports) - assert.Equal(t, 1, len(*disc.Ports)) - - disc.EmptyPorts() - assert.NotNil(t, disc.Ports) - assert.Equal(t, 0, len(*disc.Ports)) - -} - func TestUpgradeStrategy(t *testing.T) { app := Application{} assert.Nil(t, app.UpgradeStrategy) From 6b06f58a0f28616b00d0e410fd30a7bb0e2d3137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 10:32:16 +0200 Subject: [PATCH 03/16] add network name --- application.go | 21 +++++++++++++++++---- application_test.go | 2 +- docker.go | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/application.go b/application.go index 91cde15..a7809b5 100644 --- a/application.go +++ b/application.go @@ -48,6 +48,7 @@ type Port struct { // Network providers info about application networking type Network struct { + Name string `json:"name,omitempty"` Mode string `json:"mode,omitempty"` } @@ -922,11 +923,23 @@ func (r *Application) EmptyNetworks() *Application { } // Bridged sets the networking mode to bridged -func (r *Application) Bridged() *Application { +func (r *Application) BridgedNetwork(name string) *Application { if r.Networks == nil { r.EmptyNetworks() } - network := Network{Mode: "container/bridge"} + network := Network{Name: name, Mode: "container/bridge"} + networks := *r.Networks + networks = append(networks, network) + r.Networks = &networks + return r +} + +// Bridged sets the networking mode to container +func (r *Application) ContainerNetwork(name string) *Application { + if r.Networks == nil { + r.EmptyNetworks() + } + network := Network{Name: name, Mode: "container"} networks := *r.Networks networks = append(networks, network) r.Networks = &networks @@ -934,11 +947,11 @@ func (r *Application) Bridged() *Application { } // Host sets the networking mode to host -func (r *Application) Host() *Application { +func (r *Application) HostNetwork(name string) *Application { if r.Networks == nil { r.EmptyNetworks() } - network := Network{Mode: "host"} + network := Network{Name: name, Mode: "host"} networks := *r.Networks networks = append(networks, network) r.Networks = &networks diff --git a/application_test.go b/application_test.go index da2c12a..7ff3616 100644 --- a/application_test.go +++ b/application_test.go @@ -49,7 +49,7 @@ func TestApplicationString(t *testing.T) { Memory(64). Storage(0.0). Count(2). - Bridged(). + BridgedNetwork(""). AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). AddEnv("NAME", "frontend_http"). AddEnv("SERVICE_80_NAME", "test_http") diff --git a/docker.go b/docker.go index 9ce1559..ab48eaf 100644 --- a/docker.go +++ b/docker.go @@ -37,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 @@ -353,3 +354,24 @@ func (container *Container) 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") } + +// // 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 +// } + +// // EmptyLabels explicitly empties the labels -- use this if you need to empty +// // the labels of a port mapping that already has labels set (setting labels to +// // nil will keep the current value) +// func (p *PortMapping) EmptyNetworkNames() *PortMapping { +// p.NetworkNames = &[]string + +// return p +// } From 109dc0825409cf9ee87c1e2e68ab54893bb8dbd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 10:35:44 +0200 Subject: [PATCH 04/16] fix docs --- application.go | 6 +++--- residency.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application.go b/application.go index a7809b5..6e25796 100644 --- a/application.go +++ b/application.go @@ -922,7 +922,7 @@ func (r *Application) EmptyNetworks() *Application { return r } -// Bridged sets the networking mode to bridged +// BridgedNetwork sets the networking mode to bridged func (r *Application) BridgedNetwork(name string) *Application { if r.Networks == nil { r.EmptyNetworks() @@ -934,7 +934,7 @@ func (r *Application) BridgedNetwork(name string) *Application { return r } -// Bridged sets the networking mode to container +// ContainerNetwork sets the networking mode to container func (r *Application) ContainerNetwork(name string) *Application { if r.Networks == nil { r.EmptyNetworks() @@ -946,7 +946,7 @@ func (r *Application) ContainerNetwork(name string) *Application { return r } -// Host sets the networking mode to host +// HostNetwork sets the networking mode to host func (r *Application) HostNetwork(name string) *Application { if r.Networks == nil { r.EmptyNetworks() diff --git a/residency.go b/residency.go index ea9d72d..9fc94ce 100644 --- a/residency.go +++ b/residency.go @@ -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" ) From 1867d924e4ed3d5ac6cfcf0ada5492ab49101144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 10:38:44 +0200 Subject: [PATCH 05/16] addnetwork and emptynetworknames --- docker.go | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/docker.go b/docker.go index ab48eaf..a38ed98 100644 --- a/docker.go +++ b/docker.go @@ -37,7 +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"` + NetworkNames *[]string `json:"networkNames,omitempty"` } // Parameters is the parameters to pass to the docker client when creating the container @@ -355,23 +355,22 @@ func (container *Container) ServicePortIndex(port int) (int, error) { return 0, fmt.Errorf("The container port required was not found in the container port mappings") } -// // 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 -// } - -// // EmptyLabels explicitly empties the labels -- use this if you need to empty -// // the labels of a port mapping that already has labels set (setting labels to -// // nil will keep the current value) -// func (p *PortMapping) EmptyNetworkNames() *PortMapping { -// p.NetworkNames = &[]string - -// return p -// } +// 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 +} From 494a09b4354950a5c3efcca05111af2aa7889692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 10:42:49 +0200 Subject: [PATCH 06/16] port mapping network names tests --- docker_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docker_test.go b/docker_test.go index 9cf55ad..8321dd8 100644 --- a/docker_test.go +++ b/docker_test.go @@ -85,6 +85,20 @@ func TestPortMappingLabels(t *testing.T) { assert.Equal(t, 0, len(*pm.Labels)) } +func TestPortMappingNetworkNames(t *testing.T) { + pm := createPortMapping(80, "tcp") + + pm.AddNetwork("test") + + assert.Equal(t, 1, len(*pm.NetworkNames)) + assert.Equal(t, "test", (*pm.NetworkNames)[0]) + + pm.EmptyNetworkNames() + + assert.NotNil(t, pm.NetworkNames) + assert.Equal(t, 0, len(*pm.NetworkNames)) +} + func TestVolume(t *testing.T) { container := NewDockerApplication().Container From 093bf3de63b690a0d368f38f68a434fc6f5af37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 20 Oct 2017 10:53:35 +0200 Subject: [PATCH 07/16] networking tests --- application_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/application_test.go b/application_test.go index 7ff3616..acef6d8 100644 --- a/application_test.go +++ b/application_test.go @@ -710,3 +710,24 @@ func TestUpgradeStrategy(t *testing.T) { assert.Nil(t, us.MinimumHealthCapacity) assert.Nil(t, us.MaximumOverCapacity) } + +func TestBridgedNetworking(t *testing.T) { + app := NewDockerApplication().BridgedNetwork("") + networks := *app.Networks + + assert.Equal(t, networks[0].Mode, "container/bridge") +} + +func TestContainerNetworking(t *testing.T) { + app := NewDockerApplication().ContainerNetwork("test") + networks := *app.Networks + + assert.Equal(t, networks[0].Mode, "container") +} + +func TestHostNetworking(t *testing.T) { + app := NewDockerApplication().HostNetwork("") + networks := *app.Networks + + assert.Equal(t, networks[0].Mode, "host") +} From d973696612788f1439b68cc3b392eb159aed7520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Tue, 24 Oct 2017 10:19:42 +0200 Subject: [PATCH 08/16] remove uris/ports --- application.go | 25 -------- application_marshalling_test.go | 2 +- application_test.go | 20 +------ group_test.go | 2 - .../TestApplicationString-output.json | 1 - tests/rest-api/methods.yml | 57 ------------------- 6 files changed, 4 insertions(+), 103 deletions(-) diff --git a/application.go b/application.go index 6e25796..916c963 100644 --- a/application.go +++ b/application.go @@ -72,7 +72,6 @@ type Application struct { Instances *int `json:"instances,omitempty"` Mem *float64 `json:"mem,omitempty"` Tasks []*Task `json:"tasks,omitempty"` - Ports []int `json:"ports"` PortDefinitions *[]PortDefinition `json:"portDefinitions,omitempty"` RequirePorts *bool `json:"requirePorts,omitempty"` BackoffSeconds *float64 `json:"backoffSeconds,omitempty"` @@ -92,7 +91,6 @@ type Application struct { UpgradeStrategy *UpgradeStrategy `json:"upgradeStrategy,omitempty"` UnreachableStrategy *UnreachableStrategy `json:"unreachableStrategy,omitempty"` KillSelection string `json:"killSelection,omitempty"` - Uris *[]string `json:"uris,omitempty"` Version string `json:"version,omitempty"` VersionInfo *VersionInfo `json:"versionInfo,omitempty"` Labels *map[string]string `json:"labels,omitempty"` @@ -518,29 +516,6 @@ func (r *Application) CheckTCP(port, interval int) (*Application, error) { return r, nil } -// AddUris adds one or more uris to the applications -// arguments: the uri(s) you are adding -func (r *Application) AddUris(newUris ...string) *Application { - if r.Uris == nil { - r.EmptyUris() - } - - uris := *r.Uris - uris = append(uris, newUris...) - r.Uris = &uris - - return r -} - -// EmptyUris explicitly empties uris -- use this if you need to empty -// uris of an application that already has uris set (setting uris to nil will -// keep the current value) -func (r *Application) EmptyUris() *Application { - r.Uris = &[]string{} - - return r -} - // AddFetchURIs adds one or more fetch URIs to the application. // fetchURIs: the fetch URI(s) to add. func (r *Application) AddFetchURIs(fetchURIs ...Fetch) *Application { diff --git a/application_marshalling_test.go b/application_marshalling_test.go index b581794..964fa93 100644 --- a/application_marshalling_test.go +++ b/application_marshalling_test.go @@ -89,7 +89,7 @@ func TestMalformedPayloadUnmarshal(t *testing.T) { func TestEnvironmentVariableMarshal(t *testing.T) { testApp := new(Application) - targetString := []byte(`{"ports":null,"dependencies":null,"env":{"FOO":"bar","TOP":{"secret":"secret1"}},"secrets":{"secret1":{"source":"/path/to/secret"}}}`) + targetString := []byte(`{"dependencies":null,"env":{"FOO":"bar","TOP":{"secret":"secret1"}},"secrets":{"secret1":{"source":"/path/to/secret"}}}`) testApp.AddEnv("FOO", "bar") testApp.AddSecret("TOP", "secret1", "/path/to/secret") diff --git a/application_test.go b/application_test.go index acef6d8..a9c7d8b 100644 --- a/application_test.go +++ b/application_test.go @@ -459,20 +459,6 @@ func TestRestartApplication(t *testing.T) { assert.Nil(t, id) } -func TestApplicationUris(t *testing.T) { - app := NewDockerApplication() - assert.Nil(t, app.Uris) - app.AddUris("file://uri1.tar.gz").AddUris("file://uri2.tar.gz", "file://uri3.tar.gz") - assert.Equal(t, 3, len(*app.Uris)) - assert.Equal(t, "file://uri1.tar.gz", (*app.Uris)[0]) - assert.Equal(t, "file://uri2.tar.gz", (*app.Uris)[1]) - assert.Equal(t, "file://uri3.tar.gz", (*app.Uris)[2]) - - app.EmptyUris() - assert.NotNil(t, app.Uris) - assert.Equal(t, 0, len(*app.Uris)) -} - func TestApplicationFetchURIs(t *testing.T) { app := NewDockerApplication() assert.Nil(t, app.Fetch) @@ -483,9 +469,9 @@ func TestApplicationFetchURIs(t *testing.T) { assert.Equal(t, Fetch{URI: "file://uri2.tar.gz"}, (*app.Fetch)[1]) assert.Equal(t, Fetch{URI: "file://uri3.tar.gz"}, (*app.Fetch)[2]) - app.EmptyUris() - assert.NotNil(t, app.Uris) - assert.Equal(t, 0, len(*app.Uris)) + app.EmptyFetchURIs() + assert.NotNil(t, app.Fetch) + assert.Equal(t, 0, len(*app.Fetch)) } func TestSetApplicationVersion(t *testing.T) { diff --git a/group_test.go b/group_test.go index ae5c284..e5e6cb1 100644 --- a/group_test.go +++ b/group_test.go @@ -17,7 +17,6 @@ limitations under the License. package marathon import ( - "log" "testing" "github.com/stretchr/testify/assert" @@ -59,7 +58,6 @@ func TestGroup(t *testing.T) { for _, app := range frontend.Apps { assert.NotNil(t, app.Container) assert.NotNil(t, app.Container.Docker) - log.Println(app) for _, network := range *app.Networks { assert.Equal(t, network.Mode, "container/bridge") } diff --git a/tests/app-definitions/TestApplicationString-output.json b/tests/app-definitions/TestApplicationString-output.json index 1667f19..e79cb73 100644 --- a/tests/app-definitions/TestApplicationString-output.json +++ b/tests/app-definitions/TestApplicationString-output.json @@ -43,7 +43,6 @@ ], "instances": 2, "mem": 64, - "ports": null, "dependencies": null, "env": { "NAME": "frontend_http", diff --git a/tests/rest-api/methods.yml b/tests/rest-api/methods.yml index ed2da2a..cf4a93f 100644 --- a/tests/rest-api/methods.yml +++ b/tests/rest-api/methods.yml @@ -57,9 +57,6 @@ "id": "/fake-app", "instances": 2, "mem": 50.0, - "ports": [ - 0 - ], "requirePorts": false, "residency" : { "taskLostBehavior" : "RELAUNCH_AFTER_TIMEOUT", @@ -70,7 +67,6 @@ "minimumHealthCapacity": 0.5, "maximumOverCapacity": 0.5 }, - "uris": [], "user": null, "version": "2014-08-18T22:36:41.451Z" } @@ -136,10 +132,6 @@ "id": "/fake-app", "instances": 2, "mem": 64.0, - "ports": [ - 10000, - 10001 - ], "requirePorts": false, "secrets": { "secret0": { @@ -152,7 +144,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [], "user": null, "version": "2014-09-25T02:26:59.256Z" }, @@ -208,10 +199,6 @@ "id": "/fake-app-broken", "instances": 2, "mem": 64.0, - "ports": [ - 10000, - 10001 - ], "requirePorts": false, "residency" : { "taskLostBehavior" : "RELAUNCH_AFTER_TIMEOUT", @@ -223,7 +210,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [], "user": null, "version": "2014-09-25T02:26:59.256Z" } @@ -370,9 +356,6 @@ "version": "2014-09-12T23:28:21.737Z" }, "mem": 32.0, - "ports": [ - 10000 - ], "requirePorts": false, "residency" : { "taskLostBehavior" : "RELAUNCH_AFTER_TIMEOUT", @@ -428,9 +411,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [ - "http://downloads.mesosphere.com/misc/toggle.tgz" - ], "user": null, "version": "2014-09-12T23:28:21.737Z" } @@ -495,9 +475,6 @@ "version": "2014-09-12T23:28:21.737Z" }, "mem": 32.0, - "ports": [ - 10000 - ], "requirePorts": false, "residency" : { "taskLostBehavior" : "RELAUNCH_AFTER_TIMEOUT", @@ -553,9 +530,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [ - "http://downloads.mesosphere.com/misc/toggle.tgz" - ], "user": null, "version": "2014-09-12T23:28:21.737Z" } @@ -632,9 +606,6 @@ "version": "2014-09-12T23:28:21.737Z" }, "mem": 32.0, - "ports": [ - 10000 - ], "requirePorts": false, "residency" : { "taskLostBehavior" : "RELAUNCH_AFTER_TIMEOUT", @@ -690,9 +661,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [ - "http://downloads.mesosphere.com/misc/toggle.tgz" - ], "user": null, "version": "2014-09-12T23:28:21.737Z" } @@ -745,15 +713,11 @@ "id": "/test/app", "instances": 1, "mem": 128.0, - "ports": [ - 10000 - ], "requirePorts": false, "storeUrls": [], "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [], "user": null, "version": "2014-08-28T01:05:40.586Z" } @@ -789,15 +753,11 @@ "id": "/test/app", "instances": 1, "mem": 128.0, - "ports": [ - 10000 - ], "requirePorts": false, "storeUrls": [], "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [], "user": null, "version": "2014-08-28T01:05:40.586Z" } @@ -1164,15 +1124,11 @@ "id": "/test", "instances": 3, "mem": 32.0, - "ports": [10000], "requirePorts": false, "storeUrls": [], "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [ - "http://downloads.mesosphere.com/misc/toggle.tgz" - ], "user": null, "version": "2014-08-26T05:04:49.766Z" } @@ -1297,10 +1253,6 @@ "id": "/fake-app", "instances": 2, "mem": 64.0, - "ports": [ - 10000, - 10001 - ], "requirePorts": false, "residency" : { "taskLostBehavior" : "RELAUNCH_AFTER_TIMEOUT", @@ -1312,7 +1264,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [], "user": null, "version": "2014-09-25T02:26:59.256Z" }, @@ -1364,10 +1315,6 @@ "id": "/fake-app-broken", "instances": 2, "mem": 64.0, - "ports": [ - 10000, - 10001 - ], "requirePorts": false, "storeUrls": [], "tasksRunning": 2, @@ -1375,7 +1322,6 @@ "upgradeStrategy": { "minimumHealthCapacity": 1.0 }, - "uris": [], "user": null, "version": "2014-09-25T02:26:59.256Z" } @@ -1401,9 +1347,6 @@ "id": "/no-health-check-results-app", "instances": 2, "mem": 32.0, - "ports": [ - 10000 - ], "tasks": [ { "appId": "/no-health-check-results-app", From dd67f7c5fee68e396de06c5159c57973bb558f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 23 Nov 2017 16:13:24 +0100 Subject: [PATCH 09/16] restore compatibility with marathon < 1.5 --- application.go | 122 ++++++++++++++---- application_marshalling_test.go | 2 +- application_test.go | 82 ++++++++++-- docker.go | 107 +++++++++++++-- docker_test.go | 31 ++++- .../TestApplicationString-output.json | 1 + 6 files changed, 291 insertions(+), 54 deletions(-) diff --git a/application.go b/application.go index 916c963..5aafd65 100644 --- a/application.go +++ b/application.go @@ -34,6 +34,14 @@ type Applications struct { Apps []Application `json:"apps"` } +// IPAddressPerTask is used by IP-per-task functionality https://mesosphere.github.io/marathon/docs/ip-per-task.html +type IPAddressPerTask struct { + Groups *[]string `json:"groups,omitempty"` + Labels *map[string]string `json:"labels,omitempty"` + Discovery *Discovery `json:"discovery,omitempty"` + NetworkName string `json:"networkName,omitempty"` +} + // Discovery provides info about ports expose by IP-per-task functionality type Discovery struct { Ports *[]Port `json:"ports,omitempty"` @@ -46,7 +54,7 @@ type Port struct { Protocol string `json:"protocol,omitempty"` } -// Network providers info about application networking +// Network provides info about application networking type Network struct { Name string `json:"name,omitempty"` Mode string `json:"mode,omitempty"` @@ -72,6 +80,7 @@ type Application struct { Instances *int `json:"instances,omitempty"` Mem *float64 `json:"mem,omitempty"` Tasks []*Task `json:"tasks,omitempty"` + Ports []int `json:"ports"` PortDefinitions *[]PortDefinition `json:"portDefinitions,omitempty"` RequirePorts *bool `json:"requirePorts,omitempty"` BackoffSeconds *float64 `json:"backoffSeconds,omitempty"` @@ -91,6 +100,7 @@ type Application struct { UpgradeStrategy *UpgradeStrategy `json:"upgradeStrategy,omitempty"` UnreachableStrategy *UnreachableStrategy `json:"unreachableStrategy,omitempty"` KillSelection string `json:"killSelection,omitempty"` + Uris *[]string `json:"uris,omitempty"` Version string `json:"version,omitempty"` VersionInfo *VersionInfo `json:"versionInfo,omitempty"` Labels *map[string]string `json:"labels,omitempty"` @@ -98,6 +108,7 @@ type Application struct { LastTaskFailure *LastTaskFailure `json:"lastTaskFailure,omitempty"` Fetch *[]Fetch `json:"fetch,omitempty"` Residency *Residency `json:"residency,omitempty"` + IPAddressPerTask *IPAddressPerTask `json:"ipAddress,omitempty"` Secrets *map[string]Secret `json:"-"` } @@ -157,6 +168,17 @@ type Secret struct { Source string } +// SetIPAddressPerTask defines that the application will have a IP address defines by a external agent. +// This configuration is not allowed to be used with Port or PortDefinitions. Thus, the implementation +// clears both. +func (r *Application) SetIPAddressPerTask(ipAddressPerTask IPAddressPerTask) *Application { + r.Ports = make([]int, 0) + r.EmptyPortDefinitions() + r.IPAddressPerTask = &ipAddressPerTask + + return r +} + // NewDockerApplication creates a default docker application func NewDockerApplication() *Application { application := new(Application) @@ -516,6 +538,29 @@ func (r *Application) CheckTCP(port, interval int) (*Application, error) { return r, nil } +// AddUris adds one or more uris to the applications +// arguments: the uri(s) you are adding +func (r *Application) AddUris(newUris ...string) *Application { + if r.Uris == nil { + r.EmptyUris() + } + + uris := *r.Uris + uris = append(uris, newUris...) + r.Uris = &uris + + return r +} + +// EmptyUris explicitly empties uris -- use this if you need to empty +// uris of an application that already has uris set (setting uris to nil will +// keep the current value) +func (r *Application) EmptyUris() *Application { + r.Uris = &[]string{} + + return r +} + // AddFetchURIs adds one or more fetch URIs to the application. // fetchURIs: the fetch URI(s) to add. func (r *Application) AddFetchURIs(fetchURIs ...Fetch) *Application { @@ -871,6 +916,52 @@ func buildPath(path string) string { return fmt.Sprintf("%s/%s", marathonAPIApps, trimRootPath(path)) } +// EmptyLabels explicitly empties labels -- use this if you need to empty +// labels of an application that already has IP per task with labels defined +func (i *IPAddressPerTask) EmptyLabels() *IPAddressPerTask { + i.Labels = &map[string]string{} + return i +} + +// AddLabel adds a label to an IPAddressPerTask +// name: The label name +// value: The label value +func (i *IPAddressPerTask) AddLabel(name, value string) *IPAddressPerTask { + if i.Labels == nil { + i.EmptyLabels() + } + (*i.Labels)[name] = value + return i +} + +// EmptyGroups explicitly empties groups -- use this if you need to empty +// groups of an application that already has IP per task with groups defined +func (i *IPAddressPerTask) EmptyGroups() *IPAddressPerTask { + i.Groups = &[]string{} + return i +} + +// AddGroup adds a group to an IPAddressPerTask +// group: The group name +func (i *IPAddressPerTask) AddGroup(group string) *IPAddressPerTask { + if i.Groups == nil { + i.EmptyGroups() + } + + groups := *i.Groups + groups = append(groups, group) + i.Groups = &groups + + return i +} + +// SetDiscovery define the discovery to an IPAddressPerTask +// discovery: The discovery struct +func (i *IPAddressPerTask) SetDiscovery(discovery Discovery) *IPAddressPerTask { + i.Discovery = &discovery + return i +} + // EmptyPorts explicitly empties discovey port -- use this if you need to empty // discovey port of an application that already has IP per task with discovey ports // defined @@ -897,36 +988,13 @@ func (r *Application) EmptyNetworks() *Application { return r } -// BridgedNetwork sets the networking mode to bridged -func (r *Application) BridgedNetwork(name string) *Application { - if r.Networks == nil { - r.EmptyNetworks() - } - network := Network{Name: name, Mode: "container/bridge"} - networks := *r.Networks - networks = append(networks, network) - r.Networks = &networks - return r -} - -// ContainerNetwork sets the networking mode to container -func (r *Application) ContainerNetwork(name string) *Application { +// SetNetwork sets the networking mode +func (r *Application) SetNetwork(name string, mode string) *Application { if r.Networks == nil { r.EmptyNetworks() } - network := Network{Name: name, Mode: "container"} - networks := *r.Networks - networks = append(networks, network) - r.Networks = &networks - return r -} -// HostNetwork sets the networking mode to host -func (r *Application) HostNetwork(name string) *Application { - if r.Networks == nil { - r.EmptyNetworks() - } - network := Network{Name: name, Mode: "host"} + network := Network{Name: name, Mode: mode} networks := *r.Networks networks = append(networks, network) r.Networks = &networks diff --git a/application_marshalling_test.go b/application_marshalling_test.go index 964fa93..b581794 100644 --- a/application_marshalling_test.go +++ b/application_marshalling_test.go @@ -89,7 +89,7 @@ func TestMalformedPayloadUnmarshal(t *testing.T) { func TestEnvironmentVariableMarshal(t *testing.T) { testApp := new(Application) - targetString := []byte(`{"dependencies":null,"env":{"FOO":"bar","TOP":{"secret":"secret1"}},"secrets":{"secret1":{"source":"/path/to/secret"}}}`) + targetString := []byte(`{"ports":null,"dependencies":null,"env":{"FOO":"bar","TOP":{"secret":"secret1"}},"secrets":{"secret1":{"source":"/path/to/secret"}}}`) testApp.AddEnv("FOO", "bar") testApp.AddSecret("TOP", "secret1", "/path/to/secret") diff --git a/application_test.go b/application_test.go index a9c7d8b..f9107ce 100644 --- a/application_test.go +++ b/application_test.go @@ -49,12 +49,12 @@ func TestApplicationString(t *testing.T) { Memory(64). Storage(0.0). Count(2). - BridgedNetwork(""). + SetNetwork("", "container/bridge"). AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). AddEnv("NAME", "frontend_http"). AddEnv("SERVICE_80_NAME", "test_http") app. - Container.Expose(80).Expose(443). + Container.ExposeContainer(80).ExposeContainer(443). Docker.Container("quay.io/gambol99/apache-php:latest") app, err := app.CheckHTTP("/health", 80, 5) @@ -292,7 +292,7 @@ func TestApplicationPortDefinitions(t *testing.T) { func TestHasHealthChecks(t *testing.T) { app := NewDockerApplication() assert.False(t, app.HasHealthChecks()) - app.Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") + app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") _, err := app.CheckTCP(80, 10) assert.NoError(t, err) assert.True(t, app.HasHealthChecks()) @@ -304,7 +304,7 @@ func TestApplicationCheckTCP(t *testing.T) { _, err := app.CheckTCP(80, 10) assert.Error(t, err) assert.False(t, app.HasHealthChecks()) - app.Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") + app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") _, err = app.CheckTCP(80, 10) assert.NoError(t, err) assert.True(t, app.HasHealthChecks()) @@ -320,7 +320,7 @@ func TestApplicationCheckHTTP(t *testing.T) { _, err := app.CheckHTTP("/", 80, 10) assert.Error(t, err) assert.False(t, app.HasHealthChecks()) - app.Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") + app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") _, err = app.CheckHTTP("/health", 80, 10) assert.NoError(t, err) assert.True(t, app.HasHealthChecks()) @@ -459,6 +459,20 @@ func TestRestartApplication(t *testing.T) { assert.Nil(t, id) } +func TestApplicationUris(t *testing.T) { + app := NewDockerApplication() + assert.Nil(t, app.Uris) + app.AddUris("file://uri1.tar.gz").AddUris("file://uri2.tar.gz", "file://uri3.tar.gz") + assert.Equal(t, 3, len(*app.Uris)) + assert.Equal(t, "file://uri1.tar.gz", (*app.Uris)[0]) + assert.Equal(t, "file://uri2.tar.gz", (*app.Uris)[1]) + assert.Equal(t, "file://uri3.tar.gz", (*app.Uris)[2]) + + app.EmptyUris() + assert.NotNil(t, app.Uris) + assert.Equal(t, 0, len(*app.Uris)) +} + func TestApplicationFetchURIs(t *testing.T) { app := NewDockerApplication() assert.Nil(t, app.Fetch) @@ -680,6 +694,58 @@ func TestAppExistAndRunning(t *testing.T) { assert.False(t, client.appExistAndRunning("no_such_app")) } +func TestSetIPPerTask(t *testing.T) { + app := Application{} + app.Ports = append(app.Ports, 10) + app.AddPortDefinition(PortDefinition{}) + assert.Nil(t, app.IPAddressPerTask) + assert.Equal(t, 1, len(app.Ports)) + assert.Equal(t, 1, len(*app.PortDefinitions)) + + app.SetIPAddressPerTask(IPAddressPerTask{}) + assert.NotNil(t, app.IPAddressPerTask) + assert.Equal(t, 0, len(app.Ports)) + assert.Equal(t, 0, len(*app.PortDefinitions)) +} + +func TestIPAddressPerTask(t *testing.T) { + ipPerTask := IPAddressPerTask{} + assert.Nil(t, ipPerTask.Groups) + assert.Nil(t, ipPerTask.Labels) + assert.Nil(t, ipPerTask.Discovery) + + ipPerTask. + AddGroup("label"). + AddLabel("key", "value"). + SetDiscovery(Discovery{}) + + assert.Equal(t, 1, len(*ipPerTask.Groups)) + assert.Equal(t, "label", (*ipPerTask.Groups)[0]) + assert.Equal(t, "value", (*ipPerTask.Labels)["key"]) + assert.NotEmpty(t, ipPerTask.Discovery) + + ipPerTask.EmptyGroups() + assert.Equal(t, 0, len(*ipPerTask.Groups)) + + ipPerTask.EmptyLabels() + assert.Equal(t, 0, len(*ipPerTask.Labels)) + +} + +func TestIPAddressPerTaskDiscovery(t *testing.T) { + disc := Discovery{} + assert.Nil(t, disc.Ports) + + disc.AddPort(Port{}) + assert.NotNil(t, disc.Ports) + assert.Equal(t, 1, len(*disc.Ports)) + + disc.EmptyPorts() + assert.NotNil(t, disc.Ports) + assert.Equal(t, 0, len(*disc.Ports)) + +} + func TestUpgradeStrategy(t *testing.T) { app := Application{} assert.Nil(t, app.UpgradeStrategy) @@ -698,21 +764,21 @@ func TestUpgradeStrategy(t *testing.T) { } func TestBridgedNetworking(t *testing.T) { - app := NewDockerApplication().BridgedNetwork("") + app := NewDockerApplication().SetNetwork("test", "container/bridge") networks := *app.Networks assert.Equal(t, networks[0].Mode, "container/bridge") } func TestContainerNetworking(t *testing.T) { - app := NewDockerApplication().ContainerNetwork("test") + app := NewDockerApplication().SetNetwork("test", "container") networks := *app.Networks assert.Equal(t, networks[0].Mode, "container") } func TestHostNetworking(t *testing.T) { - app := NewDockerApplication().HostNetwork("") + app := NewDockerApplication().SetNetwork("test", "host") networks := *app.Networks assert.Equal(t, networks[0].Mode, "host") diff --git a/docker.go b/docker.go index a38ed98..a43374f 100644 --- a/docker.go +++ b/docker.go @@ -124,10 +124,12 @@ type ExternalVolume struct { // Docker is the docker definition from a marathon application type Docker struct { - ForcePullImage *bool `json:"forcePullImage,omitempty"` - Image string `json:"image,omitempty"` - Parameters *[]Parameters `json:"parameters,omitempty"` - Privileged *bool `json:"privileged,omitempty"` + ForcePullImage *bool `json:"forcePullImage,omitempty"` + Image string `json:"image,omitempty"` + Network string `json:"network,omitempty"` + Parameters *[]Parameters `json:"parameters,omitempty"` + PortMappings *[]PortMapping `json:"portMappings,omitempty"` + Privileged *bool `json:"privileged,omitempty"` } // Volume attachs a volume to the container @@ -243,36 +245,74 @@ func (docker *Docker) Container(image string) *Docker { return docker } +// Bridged sets the networking mode to bridged +func (docker *Docker) Bridged() *Docker { + docker.Network = "BRIDGE" + return docker +} + +// Host sets the networking mode to host +func (docker *Docker) Host() *Docker { + docker.Network = "HOST" + return docker +} + +// ExposeContainer sets the container to expose the following TCP ports +// ports: the TCP ports the container is exposing +func (container *Container) ExposeContainer(ports ...int) *Container { + for _, port := range ports { + container.ExposeContainerPort(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 (container *Container) Expose(ports ...int) *Container { +func (docker *Docker) Expose(ports ...int) *Docker { for _, port := range ports { - container.ExposePort(PortMapping{ + docker.ExposePort(PortMapping{ ContainerPort: port, HostPort: 0, ServicePort: 0, Protocol: "tcp"}) } + return docker +} + +// ExposeContainerUDP sets the container to expose the following UDP ports +// ports: the UDP ports the container is exposing +func (container *Container) ExposeContainerUDP(ports ...int) *Container { + for _, port := range ports { + container.ExposeContainerPort(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 (container *Container) ExposeUDP(ports ...int) *Container { +func (docker *Docker) ExposeUDP(ports ...int) *Docker { for _, port := range ports { - container.ExposePort(PortMapping{ + docker.ExposePort(PortMapping{ ContainerPort: port, HostPort: 0, ServicePort: 0, Protocol: "udp"}) } - return container + return docker } -// ExposePort exposes an port in the container -func (container *Container) ExposePort(portMapping PortMapping) *Container { +// ExposeContainerPort exposes an port in the container +func (container *Container) ExposeContainerPort(portMapping PortMapping) *Container { if container.PortMappings == nil { - container.EmptyPortMappings() + container.EmptyContainerPortMappings() } portMappings := *container.PortMappings @@ -282,14 +322,35 @@ func (container *Container) ExposePort(portMapping PortMapping) *Container { return container } -// EmptyPortMappings explicitly empties the port mappings -- use this if you need to empty +// ExposePort exposes an port in the container +func (docker *Docker) ExposePort(portMapping PortMapping) *Docker { + if docker.PortMappings == nil { + docker.EmptyPortMappings() + } + + portMappings := *docker.PortMappings + portMappings = append(portMappings, portMapping) + docker.PortMappings = &portMappings + + return docker +} + +// EmptyContainerPortMappings 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 { +func (container *Container) EmptyContainerPortMappings() *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) +func (docker *Docker) EmptyPortMappings() *Docker { + docker.PortMappings = &[]PortMapping{} + return docker +} + // AddLabel adds a label to a PortMapping // name: the name of the label // value: value for this label @@ -355,6 +416,24 @@ func (container *Container) ServicePortIndex(port int) (int, error) { return 0, fmt.Errorf("The container port required was not found in the container port mappings") } +// ContainerServicePortIndex finds the service port index of the exposed port +// port: the port you are looking for +func (docker *Docker) ContainerServicePortIndex(port int) (int, error) { + if docker.PortMappings == nil || len(*docker.PortMappings) == 0 { + return 0, errors.New("The docker does not contain any port mappings to search") + } + + // step: iterate and find the port + for index, containerPort := range *docker.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 required was not found in the container port mappings") +} + // AddNetwork adds a network name to a PortMapping // name: the name of the network func (p *PortMapping) AddNetwork(name string) *PortMapping { diff --git a/docker_test.go b/docker_test.go index 8321dd8..7a5ed18 100644 --- a/docker_test.go +++ b/docker_test.go @@ -47,9 +47,9 @@ func TestDockerAddParameter(t *testing.T) { assert.Equal(t, 0, len(*docker.Parameters)) } -func TestDockerExpose(t *testing.T) { +func TestDockerExposeContainer(t *testing.T) { app := NewDockerApplication() - app.Container.Expose(8080).Expose(80, 443) + app.Container.ExposeContainer(8080).ExposeContainer(80, 443) portMappings := app.Container.PortMappings assert.Equal(t, 3, len(*portMappings)) @@ -59,9 +59,21 @@ func TestDockerExpose(t *testing.T) { assert.Equal(t, *createPortMapping(443, "tcp"), (*portMappings)[2]) } -func TestDockerExposeUDP(t *testing.T) { +func TestDockerExpose(t *testing.T) { app := NewDockerApplication() - app.Container.ExposeUDP(53).ExposeUDP(5060, 6881) + app.Container.Docker.Expose(8080).Expose(80, 443) + + portMappings := app.Container.Docker.PortMappings + assert.Equal(t, 3, len(*portMappings)) + + assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMappings)[0]) + assert.Equal(t, *createPortMapping(80, "tcp"), (*portMappings)[1]) + assert.Equal(t, *createPortMapping(443, "tcp"), (*portMappings)[2]) +} + +func TestDockerExposeContainerUDP(t *testing.T) { + app := NewDockerApplication() + app.Container.ExposeContainerUDP(53).ExposeContainerUDP(5060, 6881) portMappings := app.Container.PortMappings assert.Equal(t, 3, len(*portMappings)) @@ -70,6 +82,17 @@ func TestDockerExposeUDP(t *testing.T) { assert.Equal(t, *createPortMapping(6881, "udp"), (*portMappings)[2]) } +func TestDockerExposeUDP(t *testing.T) { + app := NewDockerApplication() + app.Container.Docker.ExposeUDP(53).ExposeUDP(5060, 6881) + + portMappings := app.Container.Docker.PortMappings + assert.Equal(t, 3, len(*portMappings)) + assert.Equal(t, *createPortMapping(53, "udp"), (*portMappings)[0]) + assert.Equal(t, *createPortMapping(5060, "udp"), (*portMappings)[1]) + assert.Equal(t, *createPortMapping(6881, "udp"), (*portMappings)[2]) +} + func TestPortMappingLabels(t *testing.T) { pm := createPortMapping(80, "tcp") diff --git a/tests/app-definitions/TestApplicationString-output.json b/tests/app-definitions/TestApplicationString-output.json index e79cb73..1667f19 100644 --- a/tests/app-definitions/TestApplicationString-output.json +++ b/tests/app-definitions/TestApplicationString-output.json @@ -43,6 +43,7 @@ ], "instances": 2, "mem": 64, + "ports": null, "dependencies": null, "env": { "NAME": "frontend_http", From 13b9fbd664146dd6c16d76e544254608521aba39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 23 Nov 2017 16:19:30 +0100 Subject: [PATCH 10/16] fix service port index function --- application.go | 16 +++++++++++----- docker.go | 8 ++++---- task.go | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/application.go b/application.go index 5aafd65..b6f3027 100644 --- a/application.go +++ b/application.go @@ -107,8 +107,8 @@ type Application struct { AcceptedResourceRoles []string `json:"acceptedResourceRoles,omitempty"` LastTaskFailure *LastTaskFailure `json:"lastTaskFailure,omitempty"` Fetch *[]Fetch `json:"fetch,omitempty"` - Residency *Residency `json:"residency,omitempty"` IPAddressPerTask *IPAddressPerTask `json:"ipAddress,omitempty"` + Residency *Residency `json:"residency,omitempty"` Secrets *map[string]Secret `json:"-"` } @@ -501,9 +501,12 @@ func (r *Application) CheckHTTP(path string, port, interval int) (*Application, return nil, ErrNoApplicationContainer } // step: get the port index - portIndex, err := r.Container.ServicePortIndex(port) + portIndex, err := r.Container.Docker.ServicePortIndex(port) if err != nil { - return nil, err + portIndex, err = r.Container.ContainerServicePortIndex(port) + if err != nil { + return nil, err + } } health := NewDefaultHealthCheck() health.IntervalSeconds = interval @@ -524,9 +527,12 @@ func (r *Application) CheckTCP(port, interval int) (*Application, error) { return nil, ErrNoApplicationContainer } // step: get the port index - portIndex, err := r.Container.ServicePortIndex(port) + portIndex, err := r.Container.Docker.ServicePortIndex(port) if err != nil { - return nil, err + portIndex, err = r.Container.ContainerServicePortIndex(port) + if err != nil { + return nil, err + } } health := NewDefaultHealthCheck() health.Protocol = "TCP" diff --git a/docker.go b/docker.go index a43374f..19d3a14 100644 --- a/docker.go +++ b/docker.go @@ -398,9 +398,9 @@ func (docker *Docker) EmptyParameters() *Docker { return docker } -// ServicePortIndex finds the service port index of the exposed port +// ContainerServicePortIndex finds the service port index of the exposed port // port: the port you are looking for -func (container *Container) ServicePortIndex(port int) (int, error) { +func (container *Container) ContainerServicePortIndex(port int) (int, error) { if container.PortMappings == nil || len(*container.PortMappings) == 0 { return 0, errors.New("The docker does not contain any port mappings to search") } @@ -416,9 +416,9 @@ func (container *Container) ServicePortIndex(port int) (int, error) { return 0, fmt.Errorf("The container port required was not found in the container port mappings") } -// ContainerServicePortIndex finds the service port index of the exposed port +// ServicePortIndex finds the service port index of the exposed port // port: the port you are looking for -func (docker *Docker) ContainerServicePortIndex(port int) (int, error) { +func (docker *Docker) ServicePortIndex(port int) (int, error) { if docker.PortMappings == nil || len(*docker.PortMappings) == 0 { return 0, errors.New("The docker does not contain any port mappings to search") } diff --git a/task.go b/task.go index a28be78..807d383 100644 --- a/task.go +++ b/task.go @@ -184,7 +184,7 @@ 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.ServicePortIndex(port) + portIndex, err := application.Container.ContainerServicePortIndex(port) if err != nil { return nil, err } From c50aabe28301c5d644ab59f80b5a0658d43eee57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Thu, 23 Nov 2017 16:21:01 +0100 Subject: [PATCH 11/16] fix retrieving service port in tasks --- task.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/task.go b/task.go index 807d383..d5bbca2 100644 --- a/task.go +++ b/task.go @@ -184,9 +184,12 @@ 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.ContainerServicePortIndex(port) + portIndex, err := application.Container.Docker.ServicePortIndex(port) if err != nil { - return nil, err + portIndex, err = application.Container.ContainerServicePortIndex(port) + if err != nil { + return nil, err + } } // step: do we have any tasks? From f9dea271a4022bd38d1214dd2c61a41dea159007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Fri, 24 Nov 2017 12:09:54 +0100 Subject: [PATCH 12/16] fix tests --- application_test.go | 77 +++++++++++++++++-- group_test.go | 52 ++++++++++--- .../TestApplicationString-1.5-output.json | 52 +++++++++++++ .../TestApplicationString-output.json | 34 ++++---- 4 files changed, 181 insertions(+), 34 deletions(-) create mode 100644 tests/app-definitions/TestApplicationString-1.5-output.json diff --git a/application_test.go b/application_test.go index f9107ce..ddbaa6b 100644 --- a/application_test.go +++ b/application_test.go @@ -42,7 +42,7 @@ func TestApplicationMemory(t *testing.T) { assert.Equal(t, 50.0, *app.Mem) } -func TestApplicationString(t *testing.T) { +func TestNewApplicationString(t *testing.T) { app := NewDockerApplication(). Name("my-app"). CPU(0.1). @@ -60,7 +60,7 @@ func TestApplicationString(t *testing.T) { app, err := app.CheckHTTP("/health", 80, 5) assert.Nil(t, err) - expectedAppJSONBytes, err := ioutil.ReadFile("tests/app-definitions/TestApplicationString-output.json") + expectedAppJSONBytes, err := ioutil.ReadFile("tests/app-definitions/TestApplicationString-1.5-output.json") if err != nil { panic(err) } @@ -68,6 +68,31 @@ func TestApplicationString(t *testing.T) { assert.Equal(t, expectedAppJSON, app.String()) } +func TestApplicationString(t *testing.T) { + app := NewDockerApplication(). + Name("my-app"). + CPU(0.1). + Memory(64). + Storage(0.0). + Count(2). + AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). + AddEnv("NAME", "frontend_http"). + AddEnv("SERVICE_80_NAME", "test_http") + app. + Container.Docker.Container("quay.io/gambol99/apache-php:latest"). + Bridged(). + Expose(80). + Expose(443) + app, err := app.CheckHTTP("/health", 80, 5) + assert.Nil(t, err) + + expectedAppJSONBytes, err := ioutil.ReadFile("tests/app-definitions/TestApplicationString-output.json") + if err != nil { + panic(err) + } + expectedAppJSON := strings.TrimSpace(string(expectedAppJSONBytes)) + assert.Equal(t, expectedAppJSON, app.String()) +} func TestApplicationCount(t *testing.T) { app := NewDockerApplication() assert.Nil(t, app.Instances) @@ -289,7 +314,7 @@ func TestApplicationPortDefinitions(t *testing.T) { assert.Equal(t, 0, len(*app.PortDefinitions)) } -func TestHasHealthChecks(t *testing.T) { +func TestNewHasHealthChecks(t *testing.T) { app := NewDockerApplication() assert.False(t, app.HasHealthChecks()) app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") @@ -298,7 +323,16 @@ func TestHasHealthChecks(t *testing.T) { assert.True(t, app.HasHealthChecks()) } -func TestApplicationCheckTCP(t *testing.T) { +func TestHasHealthChecks(t *testing.T) { + app := NewDockerApplication() + assert.False(t, app.HasHealthChecks()) + app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + _, err := app.CheckTCP(80, 10) + assert.NoError(t, err) + assert.True(t, app.HasHealthChecks()) +} + +func TestNewApplicationCheckTCP(t *testing.T) { app := NewDockerApplication() assert.False(t, app.HasHealthChecks()) _, err := app.CheckTCP(80, 10) @@ -314,7 +348,23 @@ func TestApplicationCheckTCP(t *testing.T) { assert.Equal(t, 0, *check.PortIndex) } -func TestApplicationCheckHTTP(t *testing.T) { +func TestApplicationCheckTCP(t *testing.T) { + app := NewDockerApplication() + assert.False(t, app.HasHealthChecks()) + _, err := app.CheckTCP(80, 10) + assert.Error(t, err) + assert.False(t, app.HasHealthChecks()) + app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + _, err = app.CheckTCP(80, 10) + assert.NoError(t, err) + assert.True(t, app.HasHealthChecks()) + check := (*app.HealthChecks)[0] + assert.Equal(t, "TCP", check.Protocol) + assert.Equal(t, 10, check.IntervalSeconds) + assert.Equal(t, 0, *check.PortIndex) +} + +func TestNewApplicationCheckHTTP(t *testing.T) { app := NewDockerApplication() assert.False(t, app.HasHealthChecks()) _, err := app.CheckHTTP("/", 80, 10) @@ -331,6 +381,23 @@ func TestApplicationCheckHTTP(t *testing.T) { assert.Equal(t, 0, *check.PortIndex) } +func TestApplicationCheckHTTP(t *testing.T) { + app := NewDockerApplication() + assert.False(t, app.HasHealthChecks()) + _, err := app.CheckHTTP("/", 80, 10) + assert.Error(t, err) + assert.False(t, app.HasHealthChecks()) + app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + _, err = app.CheckHTTP("/health", 80, 10) + assert.NoError(t, err) + assert.True(t, app.HasHealthChecks()) + check := (*app.HealthChecks)[0] + assert.Equal(t, "HTTP", check.Protocol) + assert.Equal(t, 10, check.IntervalSeconds) + assert.Equal(t, "/health", *check.Path) + assert.Equal(t, 0, *check.PortIndex) +} + func TestCreateApplication(t *testing.T) { endpoint := newFakeMarathonEndpoint(t, nil) defer endpoint.Close() diff --git a/group_test.go b/group_test.go index e5e6cb1..d9af8c6 100644 --- a/group_test.go +++ b/group_test.go @@ -29,40 +29,72 @@ func TestGroups(t *testing.T) { groups, err := endpoint.Client.Groups() assert.NoError(t, err) assert.NotNil(t, groups) - assert.Equal(t, len(groups.Groups), 1) + assert.Equal(t, 1, len(groups.Groups)) group := groups.Groups[0] - assert.Equal(t, group.ID, fakeGroupName) + assert.Equal(t, fakeGroupName, group.ID) } -func TestGroup(t *testing.T) { +func TestNewGroup(t *testing.T) { endpoint := newFakeMarathonEndpoint(t, nil) defer endpoint.Close() group, err := endpoint.Client.Group(fakeGroupName) assert.NoError(t, err) assert.NotNil(t, group) - assert.Equal(t, len(group.Apps), 1) - assert.Equal(t, group.ID, fakeGroupName) + assert.Equal(t, 1, len(group.Apps)) + assert.Equal(t, fakeGroupName, group.ID) group, err = endpoint.Client.Group(fakeGroupName1) assert.NoError(t, err) assert.NotNil(t, group) - assert.Equal(t, group.ID, fakeGroupName1) + assert.Equal(t, fakeGroupName1, group.ID) assert.NotNil(t, group.Groups) - assert.Equal(t, len(group.Groups), 1) + assert.Equal(t, 1, len(group.Groups)) frontend := group.Groups[0] - assert.Equal(t, frontend.ID, "frontend") - assert.Equal(t, len(frontend.Apps), 3) + assert.Equal(t, "frontend", frontend.ID) + assert.Equal(t, 3, len(frontend.Apps)) for _, app := range frontend.Apps { assert.NotNil(t, app.Container) assert.NotNil(t, app.Container.Docker) for _, network := range *app.Networks { - assert.Equal(t, network.Mode, "container/bridge") + assert.Equal(t, "container/bridge", network.Mode) } if len(*app.Container.PortMappings) == 0 { t.Fail() } } } + +// TODO @kamsz: How to work with old and new endpoints from methods.yml? +// func TestGroup(t *testing.T) { +// endpoint := newFakeMarathonEndpoint(t, nil) +// defer endpoint.Close() + +// group, err := endpoint.Client.Group(fakeGroupName) +// assert.NoError(t, err) +// assert.NotNil(t, group) +// assert.Equal(t, 1, len(group.Apps)) +// assert.Equal(t, fakeGroupName, group.ID) + +// group, err = endpoint.Client.Group(fakeGroupName1) + +// assert.NoError(t, err) +// assert.NotNil(t, group) +// assert.Equal(t, fakeGroupName1, group.ID) +// assert.NotNil(t, group.Groups) +// assert.Equal(t, 1, len(group.Groups)) + +// frontend := group.Groups[0] +// assert.Equal(t, "frontend", frontend.ID) +// assert.Equal(t, 3, len(frontend.Apps)) +// for _, app := range frontend.Apps { +// assert.NotNil(t, app.Container) +// assert.NotNil(t, app.Container.Docker) +// assert.Equal(t, "BRIDGE", app.Container.Docker.Network) +// if len(*app.Container.Docker.PortMappings) == 0 { +// t.Fail() +// } +// } +// } diff --git a/tests/app-definitions/TestApplicationString-1.5-output.json b/tests/app-definitions/TestApplicationString-1.5-output.json new file mode 100644 index 0000000..1667f19 --- /dev/null +++ b/tests/app-definitions/TestApplicationString-1.5-output.json @@ -0,0 +1,52 @@ +{ + "id": "/my-app", + "args": [ + "/usr/sbin/apache2ctl", + "-D", + "FOREGROUND" + ], + "container": { + "type": "DOCKER", + "docker": { + "image": "quay.io/gambol99/apache-php:latest" + }, + "portMappings": [ + { + "containerPort": 80, + "hostPort": 0, + "protocol": "tcp" + }, + { + "containerPort": 443, + "hostPort": 0, + "protocol": "tcp" + } + ] + }, + "cpus": 0.1, + "disk": 0, + "networks": [ + { + "mode": "container/bridge" + } + ], + "healthChecks": [ + { + "portIndex": 0, + "path": "/health", + "maxConsecutiveFailures": 3, + "protocol": "HTTP", + "gracePeriodSeconds": 30, + "intervalSeconds": 5, + "timeoutSeconds": 5 + } + ], + "instances": 2, + "mem": 64, + "ports": null, + "dependencies": null, + "env": { + "NAME": "frontend_http", + "SERVICE_80_NAME": "test_http" + } +} diff --git a/tests/app-definitions/TestApplicationString-output.json b/tests/app-definitions/TestApplicationString-output.json index 1667f19..0725dc6 100644 --- a/tests/app-definitions/TestApplicationString-output.json +++ b/tests/app-definitions/TestApplicationString-output.json @@ -8,28 +8,24 @@ "container": { "type": "DOCKER", "docker": { - "image": "quay.io/gambol99/apache-php:latest" - }, - "portMappings": [ - { - "containerPort": 80, - "hostPort": 0, - "protocol": "tcp" - }, - { - "containerPort": 443, - "hostPort": 0, - "protocol": "tcp" - } - ] + "image": "quay.io/gambol99/apache-php:latest", + "network": "BRIDGE", + "portMappings": [ + { + "containerPort": 80, + "hostPort": 0, + "protocol": "tcp" + }, + { + "containerPort": 443, + "hostPort": 0, + "protocol": "tcp" + } + ] + } }, "cpus": 0.1, "disk": 0, - "networks": [ - { - "mode": "container/bridge" - } - ], "healthChecks": [ { "portIndex": 0, From 9004fe0ae29ada52b2eedf18f55366f4002e838c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Mon, 27 Nov 2017 15:53:00 +0100 Subject: [PATCH 13/16] fix tests, rename new methods to match old ones --- application.go | 4 +- application_test.go | 235 ++++++++++++++++++++++---------------------- docker.go | 30 +++--- docker_test.go | 76 +++++++------- task.go | 2 +- 5 files changed, 178 insertions(+), 169 deletions(-) diff --git a/application.go b/application.go index b6f3027..41273d7 100644 --- a/application.go +++ b/application.go @@ -503,7 +503,7 @@ 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 { - portIndex, err = r.Container.ContainerServicePortIndex(port) + portIndex, err = r.Container.ServicePortIndex(port) if err != nil { return nil, err } @@ -529,7 +529,7 @@ func (r *Application) CheckTCP(port, interval int) (*Application, error) { // step: get the port index portIndex, err := r.Container.Docker.ServicePortIndex(port) if err != nil { - portIndex, err = r.Container.ContainerServicePortIndex(port) + portIndex, err = r.Container.ServicePortIndex(port) if err != nil { return nil, err } diff --git a/application_test.go b/application_test.go index ddbaa6b..6de79ec 100644 --- a/application_test.go +++ b/application_test.go @@ -42,56 +42,61 @@ func TestApplicationMemory(t *testing.T) { assert.Equal(t, 50.0, *app.Mem) } -func TestNewApplicationString(t *testing.T) { - app := NewDockerApplication(). - Name("my-app"). - CPU(0.1). - Memory(64). - Storage(0.0). - Count(2). - SetNetwork("", "container/bridge"). - AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). - AddEnv("NAME", "frontend_http"). - AddEnv("SERVICE_80_NAME", "test_http") - app. - Container.ExposeContainer(80).ExposeContainer(443). - Docker.Container("quay.io/gambol99/apache-php:latest") - - app, err := app.CheckHTTP("/health", 80, 5) - assert.Nil(t, err) - - expectedAppJSONBytes, err := ioutil.ReadFile("tests/app-definitions/TestApplicationString-1.5-output.json") - if err != nil { - panic(err) +func TestApplicationString(t *testing.T) { + tests := []struct { + app *Application + expectedAppJSONPath string + }{ + { + app: NewDockerApplication(). + Name("my-app"). + CPU(0.1). + Memory(64). + Storage(0.0). + Count(2). + AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). + AddEnv("NAME", "frontend_http"). + AddEnv("SERVICE_80_NAME", "test_http"), + expectedAppJSONPath: "tests/app-definitions/TestApplicationString-output.json", + }, + { + app: NewDockerApplication(). + Name("my-app"). + CPU(0.1). + Memory(64). + Storage(0.0). + Count(2). + SetNetwork("", "container/bridge"). + AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). + AddEnv("NAME", "frontend_http"). + AddEnv("SERVICE_80_NAME", "test_http"), + expectedAppJSONPath: "tests/app-definitions/TestApplicationString-1.5-output.json", + }, } - expectedAppJSON := strings.TrimSpace(string(expectedAppJSONBytes)) - assert.Equal(t, expectedAppJSON, app.String()) -} -func TestApplicationString(t *testing.T) { - app := NewDockerApplication(). - Name("my-app"). - CPU(0.1). - Memory(64). - Storage(0.0). - Count(2). - AddArgs("/usr/sbin/apache2ctl", "-D", "FOREGROUND"). - AddEnv("NAME", "frontend_http"). - AddEnv("SERVICE_80_NAME", "test_http") - app. + // Marathon < 1.5 + tests[0].app. Container.Docker.Container("quay.io/gambol99/apache-php:latest"). Bridged(). Expose(80). Expose(443) - app, err := app.CheckHTTP("/health", 80, 5) - assert.Nil(t, err) - expectedAppJSONBytes, err := ioutil.ReadFile("tests/app-definitions/TestApplicationString-output.json") - if err != nil { - panic(err) + // Marathon >= 1.5 + tests[1].app. + Container.Expose(80).Expose(443). + Docker.Container("quay.io/gambol99/apache-php:latest") + + for i := range tests { + _, err := tests[i].app.CheckHTTP("/health", 80, 5) + assert.Nil(t, err) + + expectedAppJSONBytes, err := ioutil.ReadFile(tests[i].expectedAppJSONPath) + if err != nil { + panic(err) + } + expectedAppJSON := strings.TrimSpace(string(expectedAppJSONBytes)) + assert.Equal(t, expectedAppJSON, tests[i].app.String()) } - expectedAppJSON := strings.TrimSpace(string(expectedAppJSONBytes)) - assert.Equal(t, expectedAppJSON, app.String()) } func TestApplicationCount(t *testing.T) { app := NewDockerApplication() @@ -314,88 +319,88 @@ func TestApplicationPortDefinitions(t *testing.T) { assert.Equal(t, 0, len(*app.PortDefinitions)) } -func TestNewHasHealthChecks(t *testing.T) { - app := NewDockerApplication() - assert.False(t, app.HasHealthChecks()) - app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") - _, err := app.CheckTCP(80, 10) - assert.NoError(t, err) - assert.True(t, app.HasHealthChecks()) -} - func TestHasHealthChecks(t *testing.T) { - app := NewDockerApplication() - assert.False(t, app.HasHealthChecks()) - app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) - _, err := app.CheckTCP(80, 10) - assert.NoError(t, err) - assert.True(t, app.HasHealthChecks()) -} + apps := []*Application{ + NewDockerApplication(), + NewDockerApplication(), + } -func TestNewApplicationCheckTCP(t *testing.T) { - app := NewDockerApplication() - assert.False(t, app.HasHealthChecks()) - _, err := app.CheckTCP(80, 10) - assert.Error(t, err) - assert.False(t, app.HasHealthChecks()) - app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") - _, err = app.CheckTCP(80, 10) - assert.NoError(t, err) - assert.True(t, app.HasHealthChecks()) - check := (*app.HealthChecks)[0] - assert.Equal(t, "TCP", check.Protocol) - assert.Equal(t, 10, check.IntervalSeconds) - assert.Equal(t, 0, *check.PortIndex) + for i := range apps { + assert.False(t, apps[i].HasHealthChecks()) + } + + // Marathon < 1.5 + apps[0].Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + + // Marathon >= 1.5 + apps[1].Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") + + for i := range apps { + _, err := apps[i].CheckTCP(80, 10) + assert.NoError(t, err) + assert.True(t, apps[i].HasHealthChecks()) + } } func TestApplicationCheckTCP(t *testing.T) { - app := NewDockerApplication() - assert.False(t, app.HasHealthChecks()) - _, err := app.CheckTCP(80, 10) - assert.Error(t, err) - assert.False(t, app.HasHealthChecks()) - app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) - _, err = app.CheckTCP(80, 10) - assert.NoError(t, err) - assert.True(t, app.HasHealthChecks()) - check := (*app.HealthChecks)[0] - assert.Equal(t, "TCP", check.Protocol) - assert.Equal(t, 10, check.IntervalSeconds) - assert.Equal(t, 0, *check.PortIndex) -} + apps := []*Application{ + NewDockerApplication(), + NewDockerApplication(), + } -func TestNewApplicationCheckHTTP(t *testing.T) { - app := NewDockerApplication() - assert.False(t, app.HasHealthChecks()) - _, err := app.CheckHTTP("/", 80, 10) - assert.Error(t, err) - assert.False(t, app.HasHealthChecks()) - app.Container.ExposeContainer(80).Docker.Container("quay.io/gambol99/apache-php:latest") - _, err = app.CheckHTTP("/health", 80, 10) - assert.NoError(t, err) - assert.True(t, app.HasHealthChecks()) - check := (*app.HealthChecks)[0] - assert.Equal(t, "HTTP", check.Protocol) - assert.Equal(t, 10, check.IntervalSeconds) - assert.Equal(t, "/health", *check.Path) - assert.Equal(t, 0, *check.PortIndex) + for i := range apps { + assert.False(t, apps[i].HasHealthChecks()) + _, err := apps[i].CheckTCP(80, 10) + assert.Error(t, err) + assert.False(t, apps[i].HasHealthChecks()) + } + + // Marathon < 1.5 + apps[0].Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + + // Marathon >= 1.5 + apps[1].Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") + + for i := range apps { + _, err := apps[i].CheckTCP(80, 10) + assert.NoError(t, err) + assert.True(t, apps[i].HasHealthChecks()) + check := (*apps[i].HealthChecks)[0] + assert.Equal(t, "TCP", check.Protocol) + assert.Equal(t, 10, check.IntervalSeconds) + assert.Equal(t, 0, *check.PortIndex) + } } func TestApplicationCheckHTTP(t *testing.T) { - app := NewDockerApplication() - assert.False(t, app.HasHealthChecks()) - _, err := app.CheckHTTP("/", 80, 10) - assert.Error(t, err) - assert.False(t, app.HasHealthChecks()) - app.Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) - _, err = app.CheckHTTP("/health", 80, 10) - assert.NoError(t, err) - assert.True(t, app.HasHealthChecks()) - check := (*app.HealthChecks)[0] - assert.Equal(t, "HTTP", check.Protocol) - assert.Equal(t, 10, check.IntervalSeconds) - assert.Equal(t, "/health", *check.Path) - assert.Equal(t, 0, *check.PortIndex) + apps := []*Application{ + NewDockerApplication(), + NewDockerApplication(), + } + + for i := range apps { + assert.False(t, apps[i].HasHealthChecks()) + _, err := apps[i].CheckHTTP("/", 80, 10) + assert.Error(t, err) + assert.False(t, apps[i].HasHealthChecks()) + } + + // Marathon < 1.5 + apps[0].Container.Docker.Container("quay.io/gambol99/apache-php:latest").Expose(80) + + // Marathon >= 1.5 + apps[1].Container.Expose(80).Docker.Container("quay.io/gambol99/apache-php:latest") + + for i := range apps { + _, err := apps[i].CheckHTTP("/health", 80, 10) + assert.NoError(t, err) + assert.True(t, apps[i].HasHealthChecks()) + check := (*apps[i].HealthChecks)[0] + assert.Equal(t, "HTTP", check.Protocol) + assert.Equal(t, 10, check.IntervalSeconds) + assert.Equal(t, "/health", *check.Path) + assert.Equal(t, 0, *check.PortIndex) + } } func TestCreateApplication(t *testing.T) { diff --git a/docker.go b/docker.go index 19d3a14..367044c 100644 --- a/docker.go +++ b/docker.go @@ -257,11 +257,11 @@ func (docker *Docker) Host() *Docker { return docker } -// ExposeContainer sets the container to expose the following TCP ports +// Expose sets the container to expose the following TCP ports // ports: the TCP ports the container is exposing -func (container *Container) ExposeContainer(ports ...int) *Container { +func (container *Container) Expose(ports ...int) *Container { for _, port := range ports { - container.ExposeContainerPort(PortMapping{ + container.ExposePort(PortMapping{ ContainerPort: port, HostPort: 0, ServicePort: 0, @@ -283,11 +283,11 @@ func (docker *Docker) Expose(ports ...int) *Docker { return docker } -// ExposeContainerUDP sets the container to expose the following UDP ports +// ExposeUDP sets the container to expose the following UDP ports // ports: the UDP ports the container is exposing -func (container *Container) ExposeContainerUDP(ports ...int) *Container { +func (container *Container) ExposeUDP(ports ...int) *Container { for _, port := range ports { - container.ExposeContainerPort(PortMapping{ + container.ExposePort(PortMapping{ ContainerPort: port, HostPort: 0, ServicePort: 0, @@ -309,10 +309,10 @@ func (docker *Docker) ExposeUDP(ports ...int) *Docker { return docker } -// ExposeContainerPort exposes an port in the container -func (container *Container) ExposeContainerPort(portMapping PortMapping) *Container { +// ExposePort exposes an port in the container +func (container *Container) ExposePort(portMapping PortMapping) *Container { if container.PortMappings == nil { - container.EmptyContainerPortMappings() + container.EmptyPortMappings() } portMappings := *container.PortMappings @@ -335,10 +335,10 @@ func (docker *Docker) ExposePort(portMapping PortMapping) *Docker { return docker } -// EmptyContainerPortMappings explicitly empties the port mappings -- use this if you need to empty +// 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) EmptyContainerPortMappings() *Container { +func (container *Container) EmptyPortMappings() *Container { container.PortMappings = &[]PortMapping{} return container } @@ -398,11 +398,11 @@ func (docker *Docker) EmptyParameters() *Docker { return docker } -// ContainerServicePortIndex finds the service port index of the exposed port +// ServicePortIndex finds the service port index of the exposed port // port: the port you are looking for -func (container *Container) ContainerServicePortIndex(port int) (int, error) { +func (container *Container) ServicePortIndex(port int) (int, error) { if container.PortMappings == nil || len(*container.PortMappings) == 0 { - return 0, errors.New("The docker does not contain any port mappings to search") + return 0, errors.New("The container does not contain any port mappings to search") } // step: iterate and find the port @@ -431,7 +431,7 @@ 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 required was not found in the container port mappings") } // AddNetwork adds a network name to a PortMapping diff --git a/docker_test.go b/docker_test.go index 7a5ed18..cd07fb8 100644 --- a/docker_test.go +++ b/docker_test.go @@ -46,51 +46,55 @@ func TestDockerAddParameter(t *testing.T) { assert.NotNil(t, docker.Parameters) assert.Equal(t, 0, len(*docker.Parameters)) } +func TestDockerExpose(t *testing.T) { + apps := []*Application{ + NewDockerApplication(), + NewDockerApplication(), + } -func TestDockerExposeContainer(t *testing.T) { - app := NewDockerApplication() - app.Container.ExposeContainer(8080).ExposeContainer(80, 443) - - portMappings := app.Container.PortMappings - assert.Equal(t, 3, len(*portMappings)) + // Marathon < 1.5 + apps[0].Container.Docker.Expose(8080).Expose(80, 443) - assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMappings)[0]) - assert.Equal(t, *createPortMapping(80, "tcp"), (*portMappings)[1]) - assert.Equal(t, *createPortMapping(443, "tcp"), (*portMappings)[2]) -} + // Marathon >= 1.5 + apps[1].Container.Expose(8080).Expose(80, 443) -func TestDockerExpose(t *testing.T) { - app := NewDockerApplication() - app.Container.Docker.Expose(8080).Expose(80, 443) + portMappings := []*[]PortMapping{ + apps[0].Container.Docker.PortMappings, + apps[1].Container.PortMappings, + } - portMappings := app.Container.Docker.PortMappings - assert.Equal(t, 3, len(*portMappings)) + for i := range portMappings { + assert.Equal(t, 3, len(*portMappings[i])) - assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMappings)[0]) - assert.Equal(t, *createPortMapping(80, "tcp"), (*portMappings)[1]) - assert.Equal(t, *createPortMapping(443, "tcp"), (*portMappings)[2]) + assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMappings[i])[0]) + assert.Equal(t, *createPortMapping(80, "tcp"), (*portMappings[i])[1]) + assert.Equal(t, *createPortMapping(443, "tcp"), (*portMappings[i])[2]) + } } -func TestDockerExposeContainerUDP(t *testing.T) { - app := NewDockerApplication() - app.Container.ExposeContainerUDP(53).ExposeContainerUDP(5060, 6881) +func TestDockerExposeUDP(t *testing.T) { + apps := []*Application{ + NewDockerApplication(), + NewDockerApplication(), + } - portMappings := app.Container.PortMappings - assert.Equal(t, 3, len(*portMappings)) - assert.Equal(t, *createPortMapping(53, "udp"), (*portMappings)[0]) - assert.Equal(t, *createPortMapping(5060, "udp"), (*portMappings)[1]) - assert.Equal(t, *createPortMapping(6881, "udp"), (*portMappings)[2]) -} + // Marathon < 1.5 + apps[0].Container.Docker.ExposeUDP(53).ExposeUDP(5060, 6881) -func TestDockerExposeUDP(t *testing.T) { - app := NewDockerApplication() - app.Container.Docker.ExposeUDP(53).ExposeUDP(5060, 6881) - - portMappings := app.Container.Docker.PortMappings - assert.Equal(t, 3, len(*portMappings)) - assert.Equal(t, *createPortMapping(53, "udp"), (*portMappings)[0]) - assert.Equal(t, *createPortMapping(5060, "udp"), (*portMappings)[1]) - assert.Equal(t, *createPortMapping(6881, "udp"), (*portMappings)[2]) + // Marathon >= 1.5 + apps[1].Container.ExposeUDP(53).ExposeUDP(5060, 6881) + + portMappings := []*[]PortMapping{ + apps[0].Container.Docker.PortMappings, + apps[1].Container.PortMappings, + } + + for i := range portMappings { + assert.Equal(t, 3, len(*portMappings[i])) + assert.Equal(t, *createPortMapping(53, "udp"), (*portMappings[i])[0]) + assert.Equal(t, *createPortMapping(5060, "udp"), (*portMappings[i])[1]) + assert.Equal(t, *createPortMapping(6881, "udp"), (*portMappings[i])[2]) + } } func TestPortMappingLabels(t *testing.T) { diff --git a/task.go b/task.go index d5bbca2..77a2936 100644 --- a/task.go +++ b/task.go @@ -186,7 +186,7 @@ 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 { - portIndex, err = application.Container.ContainerServicePortIndex(port) + portIndex, err = application.Container.ServicePortIndex(port) if err != nil { return nil, err } From 5b880b02eea4a5eb385db47a9da4d4b6be115441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Szczygie=C5=82?= Date: Mon, 27 Nov 2017 15:55:13 +0100 Subject: [PATCH 14/16] mention port number in error message --- docker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker.go b/docker.go index 367044c..9c39dca 100644 --- a/docker.go +++ b/docker.go @@ -413,7 +413,7 @@ func (container *Container) 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 container port %d was not found in the container port mappings", port) } // ServicePortIndex finds the service port index of the exposed port @@ -431,7 +431,7 @@ func (docker *Docker) ServicePortIndex(port int) (int, error) { } // step: we didn't find the port in the mappings - return 0, fmt.Errorf("The docker 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 From 63b99347c8d4048d90d277ea39ed8a2ced499126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B6ll=2C=20Sebastian?= Date: Sun, 28 Jan 2018 03:46:45 +0100 Subject: [PATCH 15/16] ~ adding fixing tests and linting for marathon 1.5 --- application_test.go | 49 +++++++++++++--------- client.go | 2 +- docker.go | 8 +++- docker_test.go | 20 ++++----- examples/events_callback_transport/main.go | 4 +- examples/events_sse_transport/main.go | 4 +- examples/groups/main.go | 2 +- queue.go | 2 +- subscription.go | 2 +- unreachable_strategy.go | 1 + 10 files changed, 55 insertions(+), 39 deletions(-) diff --git a/application_test.go b/application_test.go index 6de79ec..64c776e 100644 --- a/application_test.go +++ b/application_test.go @@ -43,11 +43,16 @@ func TestApplicationMemory(t *testing.T) { } func TestApplicationString(t *testing.T) { - tests := []struct { + type test struct { + name string app *Application expectedAppJSONPath string - }{ + setup func(*Application) + } + + tests := []test{ { + name: "marathon < 1.5", app: NewDockerApplication(). Name("my-app"). CPU(0.1). @@ -58,8 +63,16 @@ func TestApplicationString(t *testing.T) { AddEnv("NAME", "frontend_http"). AddEnv("SERVICE_80_NAME", "test_http"), expectedAppJSONPath: "tests/app-definitions/TestApplicationString-output.json", + setup: func(app *Application) { + app. + Container.Docker.Container("quay.io/gambol99/apache-php:latest"). + Bridged(). + Expose(80). + Expose(443) + }, }, { + name: "marathon > 1.5", app: NewDockerApplication(). Name("my-app"). CPU(0.1). @@ -71,31 +84,27 @@ func TestApplicationString(t *testing.T) { AddEnv("NAME", "frontend_http"). AddEnv("SERVICE_80_NAME", "test_http"), expectedAppJSONPath: "tests/app-definitions/TestApplicationString-1.5-output.json", + setup: func(app *Application) { + app. + Container.Expose(80).Expose(443). + Docker.Container("quay.io/gambol99/apache-php:latest") + }, }, } - // Marathon < 1.5 - tests[0].app. - Container.Docker.Container("quay.io/gambol99/apache-php:latest"). - Bridged(). - Expose(80). - Expose(443) - - // Marathon >= 1.5 - tests[1].app. - Container.Expose(80).Expose(443). - Docker.Container("quay.io/gambol99/apache-php:latest") + for _, test := range tests { + label := fmt.Sprintf("test: %s", test.name) - for i := range tests { - _, err := tests[i].app.CheckHTTP("/health", 80, 5) + test.setup(test.app) + _, err := test.app.CheckHTTP("/health", 80, 5) assert.Nil(t, err) - expectedAppJSONBytes, err := ioutil.ReadFile(tests[i].expectedAppJSONPath) + expectedAppJSONBytes, err := ioutil.ReadFile(test.expectedAppJSONPath) if err != nil { panic(err) } expectedAppJSON := strings.TrimSpace(string(expectedAppJSONBytes)) - assert.Equal(t, expectedAppJSON, tests[i].app.String()) + assert.Equal(t, expectedAppJSON, test.app.String(), label) } } func TestApplicationCount(t *testing.T) { @@ -789,12 +798,14 @@ func TestIPAddressPerTask(t *testing.T) { ipPerTask. AddGroup("label"). AddLabel("key", "value"). - SetDiscovery(Discovery{}) + SetDiscovery(Discovery{ + Ports: &[]Port{}, + }) assert.Equal(t, 1, len(*ipPerTask.Groups)) assert.Equal(t, "label", (*ipPerTask.Groups)[0]) assert.Equal(t, "value", (*ipPerTask.Labels)["key"]) - assert.NotEmpty(t, ipPerTask.Discovery) + assert.NotEmpty(t, *ipPerTask.Discovery) ipPerTask.EmptyGroups() assert.Equal(t, 0, len(*ipPerTask.Groups)) diff --git a/client.go b/client.go index e87eca1..f0e0d23 100644 --- a/client.go +++ b/client.go @@ -325,7 +325,7 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{}) r.debugLog.Printf("apiCall(): %v %v returned %v %s\n", 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 { diff --git a/docker.go b/docker.go index 9c39dca..20bc1b7 100644 --- a/docker.go +++ b/docker.go @@ -55,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" ) diff --git a/docker_test.go b/docker_test.go index cd07fb8..9127947 100644 --- a/docker_test.go +++ b/docker_test.go @@ -63,12 +63,12 @@ func TestDockerExpose(t *testing.T) { apps[1].Container.PortMappings, } - for i := range portMappings { - assert.Equal(t, 3, len(*portMappings[i])) + for _, portMapping := range portMappings { + assert.Equal(t, 3, len(*portMapping)) - assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMappings[i])[0]) - assert.Equal(t, *createPortMapping(80, "tcp"), (*portMappings[i])[1]) - assert.Equal(t, *createPortMapping(443, "tcp"), (*portMappings[i])[2]) + assert.Equal(t, *createPortMapping(8080, "tcp"), (*portMapping)[0]) + assert.Equal(t, *createPortMapping(80, "tcp"), (*portMapping)[1]) + assert.Equal(t, *createPortMapping(443, "tcp"), (*portMapping)[2]) } } @@ -89,11 +89,11 @@ func TestDockerExposeUDP(t *testing.T) { apps[1].Container.PortMappings, } - for i := range portMappings { - assert.Equal(t, 3, len(*portMappings[i])) - assert.Equal(t, *createPortMapping(53, "udp"), (*portMappings[i])[0]) - assert.Equal(t, *createPortMapping(5060, "udp"), (*portMappings[i])[1]) - assert.Equal(t, *createPortMapping(6881, "udp"), (*portMappings[i])[2]) + for _, portMapping := range portMappings { + assert.Equal(t, 3, len(*portMapping)) + assert.Equal(t, *createPortMapping(53, "udp"), (*portMapping)[0]) + assert.Equal(t, *createPortMapping(5060, "udp"), (*portMapping)[1]) + assert.Equal(t, *createPortMapping(6881, "udp"), (*portMapping)[2]) } } diff --git a/examples/events_callback_transport/main.go b/examples/events_callback_transport/main.go index c9073e0..7e77bdc 100644 --- a/examples/events_callback_transport/main.go +++ b/examples/events_callback_transport/main.go @@ -71,9 +71,9 @@ func main() { log.Printf("Exiting the loop") done = true case event := <-events: - log.Printf("Recieved application event: %s", event) + log.Printf("Received application event: %s", event) case event := <-deployments: - log.Printf("Recieved deployment event: %v", event) + log.Printf("Received deployment event: %v", event) var deployment *marathon.EventDeploymentStepSuccess deployment = event.Event.(*marathon.EventDeploymentStepSuccess) log.Printf("deployment step: %v", deployment.CurrentStep) diff --git a/examples/events_sse_transport/main.go b/examples/events_sse_transport/main.go index b982eb0..ff72436 100644 --- a/examples/events_sse_transport/main.go +++ b/examples/events_sse_transport/main.go @@ -66,9 +66,9 @@ func main() { log.Printf("Exiting the loop") done = true case event := <-events: - log.Printf("Recieved application event: %s", event) + log.Printf("Received application event: %s", event) case event := <-deployments: - log.Printf("Recieved deployment event: %v", event) + log.Printf("Received deployment event: %v", event) var deployment *marathon.EventDeploymentStepSuccess deployment = event.Event.(*marathon.EventDeploymentStepSuccess) log.Printf("deployment step: %v", deployment.CurrentStep) diff --git a/examples/groups/main.go b/examples/groups/main.go index c04d350..fb494d8 100644 --- a/examples/groups/main.go +++ b/examples/groups/main.go @@ -107,7 +107,7 @@ func main() { assert(client.CreateGroup(group)) log.Printf("Successfully created the group: %s", group.ID) - log.Printf("Updating the group paramaters") + log.Printf("Updating the group parameters") frontend.Count(4) id, err := client.UpdateGroup(groupName, group, true) diff --git a/queue.go b/queue.go index 29e8c13..ade2c74 100644 --- a/queue.go +++ b/queue.go @@ -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"` diff --git a/subscription.go b/subscription.go index d686176..b624c92 100644 --- a/subscription.go +++ b/subscription.go @@ -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. diff --git a/unreachable_strategy.go b/unreachable_strategy.go index 9ed02df..6563239 100644 --- a/unreachable_strategy.go +++ b/unreachable_strategy.go @@ -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. From e2b51e3c0e0ebfba148f05abe9548fe25b8580a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B6ll=2C=20Sebastian?= Date: Sun, 28 Jan 2018 11:51:45 +0100 Subject: [PATCH 16/16] ~ adding go report card --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6f32da6..bcf7010 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Build Status](https://travis-ci.org/gambol99/go-marathon.svg?branch=master)](https://travis-ci.org/gambol99/go-marathon) [![GoDoc](http://godoc.org/github.com/gambol99/go-marathon?status.png)](http://godoc.org/github.com/gambol99/go-marathon) +[![Go Report Card](https://goreportcard.com/badge/github.com/katallaxie/go-marathon)](https://goreportcard.com/report/github.com/katallaxie/go-marathon) [![Coverage Status](https://coveralls.io/repos/github/gambol99/go-marathon/badge.svg?branch=master)](https://coveralls.io/github/gambol99/go-marathon?branch=master) # Go-Marathon