refactor(mesos) be testable.

This commit is contained in:
Fernandez Ludovic 2018-01-10 04:05:33 +01:00 committed by Traefiker
parent e9d2124885
commit 17137ba3e7
4 changed files with 466 additions and 302 deletions

View file

@ -6,56 +6,48 @@ import (
"strconv"
"strings"
"text/template"
"time"
"github.com/BurntSushi/ty/fun"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/types"
"github.com/mesosphere/mesos-dns/records"
"github.com/mesosphere/mesos-dns/records/state"
)
func (p *Provider) buildConfiguration() *types.Configuration {
func (p *Provider) buildConfiguration(tasks []state.Task) *types.Configuration {
var mesosFuncMap = template.FuncMap{
"getBackend": getBackend,
"getPort": p.getPort,
"getHost": p.getHost,
"getWeight": getFuncApplicationStringValue(label.TraefikWeight, label.DefaultWeight),
"getDomain": getFuncStringValue(label.TraefikDomain, p.Domain),
"getProtocol": getFuncApplicationStringValue(label.TraefikProtocol, label.DefaultProtocol),
"getDomain": getFuncStringValue(label.TraefikDomain, p.Domain),
"getID": getID,
// Backend functions
"getProtocol": getFuncApplicationStringValue(label.TraefikProtocol, label.DefaultProtocol),
"getPort": p.getPort,
"getHost": p.getHost,
"getWeight": getFuncApplicationStringValue(label.TraefikWeight, label.DefaultWeight),
"getBackend": getBackend,
// Frontend functions
"getPassHostHeader": getFuncStringValue(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
"getPriority": getFuncStringValue(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
"getEntryPoints": getFuncSliceStringValue(label.TraefikFrontendEntryPoints),
"getFrontendRule": p.getFrontendRule,
"getFrontendBackend": getFrontendBackend,
"getID": getID,
"getFrontEndName": getFrontEndName,
}
rg := records.NewRecordGenerator(time.Duration(p.StateTimeoutSecond) * time.Second)
st, err := rg.FindMaster(p.Masters...)
if err != nil {
log.Errorf("Failed to create a client for Mesos, error: %v", err)
return nil
}
tasks := taskRecords(st)
// filter tasks
filteredTasks := fun.Filter(func(task state.Task) bool {
return taskFilter(task, p.ExposedByDefault)
}, tasks).([]state.Task)
uniqueApps := make(map[string]state.Task)
for _, value := range filteredTasks {
if _, ok := uniqueApps[value.DiscoveryInfo.Name]; !ok {
uniqueApps[value.DiscoveryInfo.Name] = value
}
}
var filteredApps []state.Task
for _, value := range uniqueApps {
filteredApps = append(filteredApps, value)
uniqueApps := make(map[string]struct{})
for _, task := range filteredTasks {
if _, ok := uniqueApps[task.DiscoveryInfo.Name]; !ok {
uniqueApps[task.DiscoveryInfo.Name] = struct{}{}
filteredApps = append(filteredApps, task)
}
}
templateObjects := struct {
@ -75,31 +67,12 @@ func (p *Provider) buildConfiguration() *types.Configuration {
return configuration
}
func taskRecords(st state.State) []state.Task {
var tasks []state.Task
for _, f := range st.Frameworks {
for _, task := range f.Tasks {
for _, slave := range st.Slaves {
if task.SlaveID == slave.ID {
task.SlaveIP = slave.PID.Host
}
}
// only do running and discoverable tasks
if task.State == "TASK_RUNNING" {
tasks = append(tasks, task)
}
}
}
return tasks
}
func taskFilter(task state.Task, exposedByDefaultFlag bool) bool {
if len(task.DiscoveryInfo.Ports.DiscoveryPorts) == 0 {
log.Debugf("Filtering Mesos task without port %s", task.Name)
return false
}
if !isEnabled(task, exposedByDefaultFlag) {
log.Debugf("Filtering disabled Mesos task %s", task.DiscoveryInfo.Name)
return false
@ -140,7 +113,7 @@ func taskFilter(task state.Task, exposedByDefaultFlag bool) bool {
}
}
//filter healthChecks
// filter healthChecks
if task.Statuses != nil && len(task.Statuses) > 0 && task.Statuses[0].Healthy != nil && !*task.Statuses[0].Healthy {
log.Debugf("Filtering Mesos task %s with bad healthCheck", task.DiscoveryInfo.Name)
return false
@ -166,7 +139,7 @@ func getFrontendBackend(task state.Task) string {
if value := getStringValue(task, label.TraefikBackend, ""); len(value) > 0 {
return value
}
return "-" + provider.Normalize(task.DiscoveryInfo.Name)
return provider.Normalize(task.DiscoveryInfo.Name)
}
func getFrontEndName(task state.Task) string {

View file

@ -1,8 +1,6 @@
package mesos
import (
"reflect"
"strconv"
"testing"
"github.com/containous/traefik/provider/label"
@ -10,238 +8,362 @@ import (
"github.com/mesos/mesos-go/upid"
"github.com/mesosphere/mesos-dns/records/state"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// FIXME fill this test!!
func TestBuildConfiguration(t *testing.T) {
cases := []struct {
applicationsError bool
tasksError bool
mesosTask state.Task
expected bool
exposedByDefault bool
expectedNil bool
p := &Provider{
Domain: "docker.localhost",
ExposedByDefault: true,
IPSources: "host",
}
testCases := []struct {
desc string
tasks []state.Task
expectedFrontends map[string]*types.Frontend
expectedBackends map[string]*types.Backend
}{}
}{
{
desc: "should return an empty configuration when no task",
tasks: []state.Task{},
expectedFrontends: map[string]*types.Frontend{},
expectedBackends: map[string]*types.Backend{},
},
{
desc: "2 applications with 2 tasks",
tasks: []state.Task{
// App 1
aTask("ID1",
withIP("10.10.10.10"),
withInfo("name1",
withPorts(withPort("TCP", 80, "WEB"))),
withStatus(withHealthy(true), withState("TASK_RUNNING")),
),
aTask("ID2",
withIP("10.10.10.11"),
withInfo("name1",
withPorts(withPort("TCP", 81, "WEB"))),
withStatus(withHealthy(true), withState("TASK_RUNNING")),
),
// App 2
aTask("ID3",
withIP("20.10.10.10"),
withInfo("name2",
withPorts(withPort("TCP", 80, "WEB"))),
withStatus(withHealthy(true), withState("TASK_RUNNING")),
),
aTask("ID4",
withIP("20.10.10.11"),
withInfo("name2",
withPorts(withPort("TCP", 81, "WEB"))),
withStatus(withHealthy(true), withState("TASK_RUNNING")),
),
},
expectedFrontends: map[string]*types.Frontend{
"frontend-ID1": {
Backend: "backend-name1",
EntryPoints: []string{},
PassHostHeader: true,
Routes: map[string]types.Route{
"route-host-ID1": {
Rule: "Host:name1.docker.localhost",
},
},
},
"frontend-ID3": {
Backend: "backend-name2",
EntryPoints: []string{},
PassHostHeader: true,
Routes: map[string]types.Route{
"route-host-ID3": {
Rule: "Host:name2.docker.localhost",
},
},
},
},
expectedBackends: map[string]*types.Backend{
"backend-name1": {
Servers: map[string]types.Server{
"server-ID1": {
URL: "http://10.10.10.10:80",
Weight: 0,
},
"server-ID2": {
URL: "http://10.10.10.11:81",
Weight: 0,
},
},
},
"backend-name2": {
Servers: map[string]types.Server{
"server-ID3": {
URL: "http://20.10.10.10:80",
Weight: 0,
},
"server-ID4": {
URL: "http://20.10.10.11:81",
Weight: 0,
},
},
},
},
},
{
desc: "with all labels",
tasks: []state.Task{
aTask("ID1",
withLabel(label.TraefikPort, "666"),
withLabel(label.TraefikProtocol, "https"),
withLabel(label.TraefikWeight, "12"),
for _, c := range cases {
provider := &Provider{
Domain: "docker.localhost",
ExposedByDefault: true,
}
actualConfig := provider.buildConfiguration()
if c.expectedNil {
if actualConfig != nil {
t.Fatalf("Should have been nil, got %v", actualConfig)
}
} else {
// Compare backends
if !reflect.DeepEqual(actualConfig.Backends, c.expectedBackends) {
t.Fatalf("Expected %#v, got %#v", c.expectedBackends, actualConfig.Backends)
}
if !reflect.DeepEqual(actualConfig.Frontends, c.expectedFrontends) {
t.Fatalf("Expected %#v, got %#v", c.expectedFrontends, actualConfig.Frontends)
}
}
withLabel(label.TraefikBackend, "foobar"),
withLabel(label.TraefikFrontendEntryPoints, "http,https"),
withLabel(label.TraefikFrontendPassHostHeader, "true"),
withLabel(label.TraefikFrontendPassTLSCert, "true"),
withLabel(label.TraefikFrontendPriority, "666"),
withLabel(label.TraefikFrontendRule, "Host:traefik.io"),
withIP("10.10.10.10"),
withInfo("name1", withPorts(
withPortTCP(80, "n"),
withPortTCP(666, "n"))),
withStatus(withHealthy(true), withState("TASK_RUNNING")),
),
},
expectedFrontends: map[string]*types.Frontend{
"frontend-ID1": {
EntryPoints: []string{
"http",
"https",
},
Backend: "backend-foobar",
Routes: map[string]types.Route{
"route-host-ID1": {
Rule: "Host:traefik.io",
},
},
PassHostHeader: true,
Priority: 666,
},
},
expectedBackends: map[string]*types.Backend{
"backend-foobar": {
Servers: map[string]types.Server{
"server-ID1": {
URL: "https://10.10.10.10:666",
Weight: 12,
},
},
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
actualConfig := p.buildConfiguration(test.tasks)
require.NotNil(t, actualConfig)
assert.Equal(t, test.expectedBackends, actualConfig.Backends)
assert.Equal(t, test.expectedFrontends, actualConfig.Frontends)
})
}
}
func TestTaskFilter(t *testing.T) {
testCases := []struct {
desc string
mesosTask state.Task
expected bool
exposedByDefault bool
expected bool
}{
{
desc: "no task",
mesosTask: state.Task{},
exposedByDefault: true,
expected: false,
exposedByDefault: true,
},
{
mesosTask: task(statuses(status(setState("TASK_RUNNING")))),
desc: "task not healthy",
mesosTask: aTask("test", withStatus(withState("TASK_RUNNING"))),
exposedByDefault: true,
expected: false,
exposedByDefault: true,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "false"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
desc: "exposedByDefault false and traefik.enable false",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "false"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: false, // because label traefik.enable = false
exposedByDefault: false,
expected: false,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
desc: "traefik.enable = true",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: true,
exposedByDefault: false,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
),
expected: true,
exposedByDefault: true,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "false"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
desc: "exposedByDefault true and traefik.enable true",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: false, // because label traefik.enable = false (even wherek exposedByDefault = true)
exposedByDefault: true,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPortIndex, "1",
label.TraefikPort, "80"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
),
expected: false, // traefik.portIndex & traefik.port cannot be set both
exposedByDefault: true,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPortIndex, "1"),
discovery(setDiscoveryPorts("TCP", 80, "WEB HTTP", "TCP", 443, "WEB HTTPS")),
),
expected: true,
exposedByDefault: true,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true"),
discovery(setDiscoveryPorts("TCP", 80, "WEB HTTP", "TCP", 443, "WEB HTTPS")),
desc: "exposedByDefault true and traefik.enable false",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "false"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: true, // Default to first index
exposedByDefault: true,
expected: false,
},
{
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPortIndex, "1"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
desc: "traefik.portIndex and traefik.port both set",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPortIndex, "1"),
withLabel(label.TraefikEnable, "80"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: false, // traefik.portIndex and discoveryPorts don't correspond
exposedByDefault: true,
}, {
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPortIndex, "0"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
expected: false,
},
{
desc: "valid traefik.portIndex",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPortIndex, "1"),
withInfo("test", withPorts(
withPortTCP(80, "WEB"),
withPortTCP(443, "WEB HTTPS"),
)),
),
expected: true, // traefik.portIndex and discoveryPorts correspond
exposedByDefault: true,
}, {
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPort, "TRAEFIK"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
expected: true,
},
{
desc: "default to first port index",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withInfo("test", withPorts(
withPortTCP(80, "WEB"),
withPortTCP(443, "WEB HTTPS"),
)),
),
expected: false, // traefik.port is not an integer
exposedByDefault: true,
}, {
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPort, "443"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
expected: true,
},
{
desc: "traefik.portIndex and discoveryPorts don't correspond",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPortIndex, "1"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: false, // traefik.port is not the same as discovery.port
exposedByDefault: true,
}, {
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(true))),
setLabels(label.TraefikEnable, "true",
label.TraefikPort, "80"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
expected: false,
},
{
desc: "traefik.portIndex and discoveryPorts correspond",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPortIndex, "0"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: true, // traefik.port is the same as discovery.port
exposedByDefault: true,
}, {
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"))),
setLabels(label.TraefikEnable, "true",
label.TraefikPort, "80"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
expected: true,
},
{
desc: "traefik.port is not an integer",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPort, "TRAEFIK"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: true, // No healthCheck
exposedByDefault: true,
}, {
mesosTask: task(
statuses(
status(
setState("TASK_RUNNING"),
setHealthy(false))),
setLabels(label.TraefikEnable, "true",
label.TraefikPort, "80"),
discovery(setDiscoveryPort("TCP", 80, "WEB")),
expected: false,
},
{
desc: "traefik.port is not the same as discovery.port",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPort, "443"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
expected: false, // HealthCheck at false
exposedByDefault: true,
expected: false,
},
{
desc: "traefik.port is the same as discovery.port",
mesosTask: aTask("test",
withDefaultStatus(),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPort, "80"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
exposedByDefault: true,
expected: true,
},
{
desc: "healthy nil",
mesosTask: aTask("test",
withStatus(
withState("TASK_RUNNING"),
),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPort, "80"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
exposedByDefault: true,
expected: true,
},
{
desc: "healthy false",
mesosTask: aTask("test",
withStatus(
withState("TASK_RUNNING"),
withHealthy(false),
),
withLabel(label.TraefikEnable, "true"),
withLabel(label.TraefikPort, "80"),
withInfo("test", withPorts(withPortTCP(80, "WEB"))),
),
exposedByDefault: true,
expected: false,
},
}
for index, test := range testCases {
t.Run(strconv.Itoa(index), func(t *testing.T) {
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual := taskFilter(test.mesosTask, test.exposedByDefault)
if actual != test.expected {
ok := assert.Equal(t, test.expected, actual)
if !ok {
t.Logf("Statuses : %v", test.mesosTask.Statuses)
t.Logf("Label : %v", test.mesosTask.Labels)
t.Logf("DiscoveryInfo : %v", test.mesosTask.DiscoveryInfo)
@ -303,7 +425,7 @@ func TestGetSubDomain(t *testing.T) {
for _, test := range testCases {
test := test
t.Run("", func(t *testing.T) {
t.Run(test.path, func(t *testing.T) {
t.Parallel()
actual := test.provider.getSubDomain(test.path)

View file

@ -12,6 +12,9 @@ import (
"github.com/containous/traefik/safe"
"github.com/containous/traefik/types"
"github.com/mesos/mesos-go/detector"
"github.com/mesosphere/mesos-dns/records"
"github.com/mesosphere/mesos-dns/records/state"
// Register mesos zoo the detector
_ "github.com/mesos/mesos-go/detector/zoo"
"github.com/mesosphere/mesos-dns/detect"
@ -76,7 +79,8 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
for {
select {
case <-reload.C:
configuration := p.buildConfiguration()
tasks := p.getTasks()
configuration := p.buildConfiguration(tasks)
if configuration != nil {
configurationChan <- types.ConfigMessage{
ProviderName: "mesos",
@ -92,7 +96,8 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
}
log.Debugf("new masters detected: %v", masters)
p.Masters = masters
configuration := p.buildConfiguration()
tasks := p.getTasks()
configuration := p.buildConfiguration(tasks)
if configuration != nil {
configurationChan <- types.ConfigMessage{
ProviderName: "mesos",
@ -129,3 +134,35 @@ func detectMasters(zk string, masters []string) <-chan []string {
}
return changed
}
func (p *Provider) getTasks() []state.Task {
rg := records.NewRecordGenerator(time.Duration(p.StateTimeoutSecond) * time.Second)
st, err := rg.FindMaster(p.Masters...)
if err != nil {
log.Errorf("Failed to create a client for Mesos, error: %v", err)
return nil
}
return taskRecords(st)
}
func taskRecords(st state.State) []state.Task {
var tasks []state.Task
for _, f := range st.Frameworks {
for _, task := range f.Tasks {
for _, slave := range st.Slaves {
if task.SlaveID == slave.ID {
task.SlaveIP = slave.PID.Host
}
}
// only do running and discoverable tasks
if task.State == "TASK_RUNNING" {
tasks = append(tasks, task)
}
}
}
return tasks
}

View file

@ -1,113 +1,145 @@
package mesos
import (
"github.com/containous/traefik/log"
"testing"
"github.com/mesosphere/mesos-dns/records/state"
"github.com/stretchr/testify/assert"
)
// test helpers
type (
taskOpt func(*state.Task)
statusOpt func(*state.Status)
)
func TestBuilder(t *testing.T) {
result := aTask("ID1",
withIP("10.10.10.10"),
withLabel("foo", "bar"),
withLabel("fii", "bar"),
withLabel("fuu", "bar"),
withInfo("name1",
withPorts(withPort("TCP", 80, "p"),
withPortTCP(81, "n"))),
withStatus(withHealthy(true), withState("a")))
func task(opts ...taskOpt) state.Task {
var t state.Task
for _, opt := range opts {
opt(&t)
}
return t
expected := state.Task{
FrameworkID: "",
ID: "ID1",
SlaveIP: "10.10.10.10",
Name: "",
SlaveID: "",
State: "",
Statuses: []state.Status{{
State: "a",
Healthy: Bool(true),
ContainerStatus: state.ContainerStatus{},
}},
DiscoveryInfo: state.DiscoveryInfo{
Name: "name1",
Labels: struct {
Labels []state.Label "json:\"labels\""
}{},
Ports: state.Ports{DiscoveryPorts: []state.DiscoveryPort{
{Protocol: "TCP", Number: 80, Name: "p"},
{Protocol: "TCP", Number: 81, Name: "n"}}}},
Labels: []state.Label{
{Key: "foo", Value: "bar"},
{Key: "fii", Value: "bar"},
{Key: "fuu", Value: "bar"}}}
assert.Equal(t, expected, result)
}
func statuses(st ...state.Status) taskOpt {
return func(t *state.Task) {
t.Statuses = append(t.Statuses, st...)
func aTask(id string, ops ...func(*state.Task)) state.Task {
ts := &state.Task{ID: id}
for _, op := range ops {
op(ts)
}
return *ts
}
func withIP(ip string) func(*state.Task) {
return func(task *state.Task) {
task.SlaveIP = ip
}
}
func discovery(dp state.DiscoveryInfo) taskOpt {
return func(t *state.Task) {
t.DiscoveryInfo = dp
func withInfo(name string, ops ...func(*state.DiscoveryInfo)) func(*state.Task) {
return func(task *state.Task) {
info := &state.DiscoveryInfo{Name: name}
for _, op := range ops {
op(info)
}
task.DiscoveryInfo = *info
}
}
func setLabels(kvs ...string) taskOpt {
return func(t *state.Task) {
if len(kvs)%2 != 0 {
panic("odd number")
func withPorts(ops ...func(port *state.DiscoveryPort)) func(*state.DiscoveryInfo) {
return func(info *state.DiscoveryInfo) {
var ports []state.DiscoveryPort
for _, op := range ops {
pt := &state.DiscoveryPort{}
op(pt)
ports = append(ports, *pt)
}
for i := 0; i < len(kvs); i += 2 {
var label = state.Label{Key: kvs[i], Value: kvs[i+1]}
log.Debugf("Label1.1 : %v", label)
t.Labels = append(t.Labels, label)
log.Debugf("Label1.2 : %v", t.Labels)
info.Ports = state.Ports{
DiscoveryPorts: ports,
}
}
}
func status(opts ...statusOpt) state.Status {
var s state.Status
for _, opt := range opts {
opt(&s)
}
return s
}
func setDiscoveryPort(proto string, port int, name string) state.DiscoveryInfo {
dp := state.DiscoveryPort{
Protocol: proto,
Number: port,
Name: name,
}
discoveryPorts := []state.DiscoveryPort{dp}
ports := state.Ports{
DiscoveryPorts: discoveryPorts,
}
return state.DiscoveryInfo{
Ports: ports,
func withPort(proto string, port int, name string) func(port *state.DiscoveryPort) {
return func(p *state.DiscoveryPort) {
p.Protocol = proto
p.Number = port
p.Name = name
}
}
func setDiscoveryPorts(proto1 string, port1 int, name1 string, proto2 string, port2 int, name2 string) state.DiscoveryInfo {
func withPortTCP(port int, name string) func(port *state.DiscoveryPort) {
return withPort("TCP", port, name)
}
dp1 := state.DiscoveryPort{
Protocol: proto1,
Number: port1,
Name: name1,
func withStatus(ops ...func(*state.Status)) func(*state.Task) {
return func(task *state.Task) {
st := &state.Status{}
for _, op := range ops {
op(st)
}
task.Statuses = append(task.Statuses, *st)
}
dp2 := state.DiscoveryPort{
Protocol: proto2,
Number: port2,
Name: name2,
}
discoveryPorts := []state.DiscoveryPort{dp1, dp2}
ports := state.Ports{
DiscoveryPorts: discoveryPorts,
}
return state.DiscoveryInfo{
Ports: ports,
}
func withDefaultStatus(ops ...func(*state.Status)) func(*state.Task) {
return func(task *state.Task) {
for _, op := range ops {
st := &state.Status{
State: "TASK_RUNNING",
Healthy: Bool(true),
}
op(st)
task.Statuses = append(task.Statuses, *st)
}
}
}
func setState(st string) statusOpt {
return func(s *state.Status) {
s.State = st
func withHealthy(st bool) func(*state.Status) {
return func(status *state.Status) {
status.Healthy = Bool(st)
}
}
func setHealthy(b bool) statusOpt {
return func(s *state.Status) {
s.Healthy = &b
func withState(st string) func(*state.Status) {
return func(status *state.Status) {
status.State = st
}
}
func withLabel(key, value string) func(*state.Task) {
return func(task *state.Task) {
lbl := state.Label{Key: key, Value: value}
task.Labels = append(task.Labels, lbl)
}
}
func Bool(v bool) *bool {
return &v
}