From 48c52a9b13e7c3d6b2c432e5fe9155ca18dcfbe2 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 06:30:49 +0100 Subject: [PATCH 01/27] Add health to standalone container --- metricbeat/metricbeat.yml | 31 ++++++++++++------- .../module/docker/container/_meta/data.json | 10 +++++- .../module/docker/container/_meta/fields.yml | 20 ++++++++++++ .../module/docker/container/container.go | 2 +- metricbeat/module/docker/container/data.go | 23 ++++++++++++-- .../fsouza/go-dockerclient/container.go | 16 ++++++++++ 6 files changed, 85 insertions(+), 17 deletions(-) diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index 657ea61828d2..2582770b65d0 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -10,14 +10,21 @@ #========================== Modules configuration ============================ metricbeat.modules: +#------------------------------- Docker Module ------------------------------- +- module: docker + metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + hosts: ["unix:///var/run/docker.sock"] + enabled: true + period: 10s + #------------------------------- System Module ------------------------------- -- module: system - metricsets: +#- module: system + #metricsets: # CPU stats - - cpu + #- cpu # System Load stats - - load + #- load # Per CPU core stats #- core @@ -26,25 +33,25 @@ metricbeat.modules: #- diskio # Per filesystem stats - - filesystem + #- filesystem # File system summary stats - - fsstat + #- fsstat # Memory stats - - memory + #- memory # Network stats - - network + #- network # Per process stats - - process + #- process # Sockets (linux only) #- socket - enabled: true - period: 10s - processes: ['.*'] + #enabled: true + #period: 10s + #processes: ['.*'] diff --git a/metricbeat/module/docker/container/_meta/data.json b/metricbeat/module/docker/container/_meta/data.json index 83ca1c4849df..3e36df399d65 100644 --- a/metricbeat/module/docker/container/_meta/data.json +++ b/metricbeat/module/docker/container/_meta/data.json @@ -31,5 +31,13 @@ "name": "container", "rtt": 115 }, + "health": { + "event_end_date": "2017-01-09T20:38:13.080472813+01:00", + "event_exit_code": 0, + "event_output": "0.005", + "event_start_date": "2017-01-09T20:38:12.999970865+01:00", + "failingstreak": 0, + "status": "healthy" + }, "type": "metricsets" -} \ No newline at end of file +} diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index cf56b0a142f8..032cdb8f17b1 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -40,3 +40,23 @@ type: long description: > Size of the files that have been created or changed since creation. + - name: health + type: group + description: > + Container health metrics. + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: long + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/container/container.go b/metricbeat/module/docker/container/container.go index 0606072cdfca..bfc0c32fa095 100644 --- a/metricbeat/module/docker/container/container.go +++ b/metricbeat/module/docker/container/container.go @@ -48,5 +48,5 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { if err != nil { return nil, err } - return eventsMapping(containers), nil + return eventsMapping(containers, m), nil } diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 86d4d17dd876..0ead59a039fa 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -6,18 +6,19 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/module/docker" + "strings" dc "github.com/fsouza/go-dockerclient" ) -func eventsMapping(containersList []dc.APIContainers) []common.MapStr { +func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} for _, container := range containersList { - myEvents = append(myEvents, eventMapping(&container)) + myEvents = append(myEvents, eventMapping(&container, m)) } return myEvents } -func eventMapping(cont *dc.APIContainers) common.MapStr { +func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { event := common.MapStr{ "created": common.Time(time.Unix(cont.Created, 0)), "id": cont.ID, @@ -31,7 +32,23 @@ func eventMapping(cont *dc.APIContainers) common.MapStr { "status": cont.Status, } + if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log)-1 + + health := common.MapStr{ + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event_start_date": container.State.Health.Log[last_event].Start, + "event_end_date": container.State.Health.Log[last_event].End, + "event_exit_code": container.State.Health.Log[last_event].ExitCode, + "event_output": container.State.Health.Log[last_event].Output, + } + event["health"] = health + } + labels := docker.DeDotLabels(cont.Labels) + if len(labels) > 0 { event["labels"] = labels } diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/container.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/container.go index e98e8a1951aa..bc5092f23434 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/container.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/container.go @@ -99,6 +99,21 @@ func (p Port) Proto() string { return parts[1] } +// HealthCheck represents one check of health. +type HealthCheck struct { + Start time.Time `json:"Start,omitempty" yaml:"Start,omitempty"` + End time.Time `json:"End,omitempty" yaml:"End,omitempty"` + ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty"` + Output string `json:"Output,omitempty" yaml:"Output,omitempty"` +} + +// Health represents the health of a container. +type Health struct { + Status string `json:"Status,omitempty" yaml:"Status,omitempty"` + FailingStreak int `json:"FailingStreak,omitempty" yaml:"FailingStreak,omitempty"` + Log []HealthCheck `json:"Log,omitempty" yaml:"Log,omitempty"` +} + // State represents the state of a container. type State struct { Status string `json:"Status,omitempty" yaml:"Status,omitempty"` @@ -113,6 +128,7 @@ type State struct { Error string `json:"Error,omitempty" yaml:"Error,omitempty"` StartedAt time.Time `json:"StartedAt,omitempty" yaml:"StartedAt,omitempty"` FinishedAt time.Time `json:"FinishedAt,omitempty" yaml:"FinishedAt,omitempty"` + Health Health `json:"Health,omitempty" yaml:"Health,omitempty"` } // String returns a human-readable description of the state From cef2bc86219fea1424ba2594feed05091a972eb8 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 11:42:43 +0100 Subject: [PATCH 02/27] Add node metricset --- metricbeat/docs/fields.asciidoc | 154 ++++++++ metricbeat/docs/modules/docker.asciidoc | 4 + metricbeat/docs/modules/docker/node.asciidoc | 19 + metricbeat/include/list.go | 1 + metricbeat/metricbeat.yml | 7 + .../module/docker/container/_meta/fields.yml | 33 +- metricbeat/module/docker/container/data.go | 4 + metricbeat/module/docker/node/_meta/data.json | 60 ++++ .../module/docker/node/_meta/docs.asciidoc | 4 + .../module/docker/node/_meta/fields.yml | 62 ++++ .../module/docker/node/_meta/fields0.yml | 103 ++++++ metricbeat/module/docker/node/container.go | 52 +++ .../docker/node/container_integration_test.go | 25 ++ metricbeat/module/docker/node/data.go | 57 +++ .../docker/api/types/container/config.go | 62 ++++ .../api/types/container/container_create.go | 21 ++ .../api/types/container/container_update.go | 17 + .../api/types/container/container_wait.go | 17 + .../docker/api/types/container/host_config.go | 333 ++++++++++++++++++ .../api/types/container/hostconfig_unix.go | 81 +++++ .../api/types/container/hostconfig_windows.go | 87 +++++ .../docker/api/types/mount/mount.go | 113 ++++++ .../docker/api/types/swarm/common.go | 27 ++ .../docker/api/types/swarm/container.go | 46 +++ .../docker/api/types/swarm/network.go | 111 ++++++ .../github.com/docker/api/types/swarm/node.go | 114 ++++++ .../docker/api/types/swarm/secret.go | 31 ++ .../docker/api/types/swarm/service.go | 105 ++++++ .../docker/api/types/swarm/swarm.go | 197 +++++++++++ .../github.com/docker/api/types/swarm/task.go | 128 +++++++ .../github.com/fsouza/go-dockerclient/node.go | 68 ++++ .../fsouza/go-dockerclient/service.go | 150 ++++++++ 32 files changed, 2277 insertions(+), 16 deletions(-) create mode 100644 metricbeat/docs/modules/docker/node.asciidoc create mode 100644 metricbeat/module/docker/node/_meta/data.json create mode 100644 metricbeat/module/docker/node/_meta/docs.asciidoc create mode 100644 metricbeat/module/docker/node/_meta/fields.yml create mode 100644 metricbeat/module/docker/node/_meta/fields0.yml create mode 100644 metricbeat/module/docker/node/container.go create mode 100644 metricbeat/module/docker/node/container_integration_test.go create mode 100644 metricbeat/module/docker/node/data.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index ffe2c2acce7a..e85dd704a9e2 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1071,6 +1071,44 @@ type: long Size of the files that have been created or changed since creation. +[float] +== health Fields + +Container health metrics. + + +[float] +=== docker.container.event_end_date + +type: date + +Healthcheck end date + + +[float] +=== docker.container.event_start_date + +type: date + +Healthcheck start date + + +[float] +=== docker.container.event_output + +type: long + +Healthcheck output + + +[float] +=== docker.container.event_exit_code + +type: integer + +Healthcheck status code + + [float] == cpu Fields @@ -1416,6 +1454,122 @@ type: long Total number of outgoing packets. +[float] +== container Fields + +Docker container metrics. + + + +[float] +=== docker.container.command + +type: keyword + +Command that was executed in the Docker container. + + +[float] +=== docker.container.created + +type: date + +Date when the container was created. + + +[float] +=== docker.container.id + +type: keyword + +Unique container id. + + +[float] +=== docker.container.image + +type: keyword + +Name of the image the container was built on. + + +[float] +=== docker.container.name + +type: keyword + +Container name. + + +[float] +=== docker.container.status + +type: keyword + +Container status. + + +[float] +== size Fields + +Container size metrics. + + + +[float] +=== docker.container.size.root_fs + +type: long + +Total size of all the files in the container. + + +[float] +=== docker.container.size.rw + +type: long + +Size of the files that have been created or changed since creation. + + +[float] +== health Fields + +Container health metrics. + + +[float] +=== docker.container.event_end_date + +type: date + +Healthcheck end date + + +[float] +=== docker.container.event_start_date + +type: date + +Healthcheck start date + + +[float] +=== docker.container.event_output + +type: long + +Healthcheck output + + +[float] +=== docker.container.event_exit_code + +type: integer + +Healthcheck status code + + [[exported-fields-haproxy]] == haproxy Fields diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index e743c67e7037..a50007adc8b9 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -50,6 +50,8 @@ The following metricsets are available: * <> +* <> + include::docker/container.asciidoc[] include::docker/cpu.asciidoc[] @@ -62,3 +64,5 @@ include::docker/memory.asciidoc[] include::docker/network.asciidoc[] +include::docker/node.asciidoc[] + diff --git a/metricbeat/docs/modules/docker/node.asciidoc b/metricbeat/docs/modules/docker/node.asciidoc new file mode 100644 index 000000000000..e1d2341d0d22 --- /dev/null +++ b/metricbeat/docs/modules/docker/node.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-docker-node]] +include::../../../module/docker/node/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/docker/node/_meta/data.json[] +---- diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 8d0782555c14..960b2e9a3135 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -21,6 +21,7 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/info" _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" + _ "github.com/elastic/beats/metricbeat/module/docker/node" _ "github.com/elastic/beats/metricbeat/module/haproxy" _ "github.com/elastic/beats/metricbeat/module/haproxy/info" _ "github.com/elastic/beats/metricbeat/module/haproxy/stat" diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index 2582770b65d0..e024185f5ce6 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -17,6 +17,13 @@ metricbeat.modules: enabled: true period: 10s + # To connect to Docker over TLS you must specify a client and CA certificate. + #ssl: + #certificate_authority: "/etc/pki/root/ca.pem" + #certificate: "/etc/pki/client/cert.pem" + #key: "/etc/pki/client/cert.key" + + #------------------------------- System Module ------------------------------- #- module: system #metricsets: diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index 032cdb8f17b1..d6ad46412f4b 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -44,19 +44,20 @@ type: group description: > Container health metrics. - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: long - description: > - Healthcheck output - - name: event_exit_code - type: integer - description: > - Healthcheck status code + fields: + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: long + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 0ead59a039fa..783b8e6debf3 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -8,6 +8,7 @@ import ( "strings" dc "github.com/fsouza/go-dockerclient" + "fmt" ) func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { @@ -33,6 +34,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { } if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + fmt.Println("HealthCheck !!\n") container, _ := m.dockerClient.InspectContainer(cont.ID) last_event := len(container.State.Health.Log)-1 @@ -45,6 +47,8 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "event_output": container.State.Health.Log[last_event].Output, } event["health"] = health + } else { + fmt.Println("No health check lets continue\n") } labels := docker.DeDotLabels(cont.Labels) diff --git a/metricbeat/module/docker/node/_meta/data.json b/metricbeat/module/docker/node/_meta/data.json new file mode 100644 index 000000000000..349a01e87e3e --- /dev/null +++ b/metricbeat/module/docker/node/_meta/data.json @@ -0,0 +1,60 @@ +{ + "@timestamp": "2016-05-23T08:05:34.853Z", + "beat": { + "hostname": "host.example.com", + "name": "host.example.com" + }, + "docker": { + "node": { + "createdat": "2017-01-10T05:37:07.548757912Z", + "updatedat": "2017-01-10T05:37:08.159552729Z", + "id": "4be260de8fc1213c9ff58789b8221e70c53f5af5d5a3915ff7de4b81b357d851", + "hostname": "thisisatest", + "spec": { + "role": "manager", + "avaiability": "active" + }, + "platform": { + "architecture": "x86_64", + "os": "Linux" + }, + "ressources": { + "nanocpus": 4000000000, + "memorybytes": 8115884032 + }, + "engine": { + "engine_version": "1.13.0-rc5", + "plugin": [ + { + "type": "Network", + "name": "bridge" + }, + { + "type": "Network", + "name": "host" + }, + { + "type": "volume", + "name": "local" + } + ] + }, + "status": { + "state": "ready", + "addr": "127.0.0.1" + }, + "managerstatus": { + "leader": true, + "reachability": "reachable", + "addr": "192.168.1.38:2377" + } + } + }, + "metricset": { + "host": "/var/run/docker.sock", + "module": "docker", + "name": "node", + "rtt": 115 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/docker/node/_meta/docs.asciidoc b/metricbeat/module/docker/node/_meta/docs.asciidoc new file mode 100644 index 000000000000..4d0dca8a7c43 --- /dev/null +++ b/metricbeat/module/docker/node/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +=== Docker Swarm Node Metricset + +The Docker Swarm `node` metricset collects information and statistics about +running nodes in Docker cluster. diff --git a/metricbeat/module/docker/node/_meta/fields.yml b/metricbeat/module/docker/node/_meta/fields.yml new file mode 100644 index 000000000000..032cdb8f17b1 --- /dev/null +++ b/metricbeat/module/docker/node/_meta/fields.yml @@ -0,0 +1,62 @@ +- name: container + type: group + description: > + Docker container metrics. + fields: + - name: command + type: keyword + description: > + Command that was executed in the Docker container. + - name: created + type: date + description: > + Date when the container was created. + - name: id + type: keyword + description: > + Unique container id. + - name: image + type: keyword + description: > + Name of the image the container was built on. + - name: name + type: keyword + description: > + Container name. + - name: status + type: keyword + description: > + Container status. + - name: size + type: group + description: > + Container size metrics. + fields: + - name: root_fs + type: long + description: > + Total size of all the files in the container. + - name: rw + type: long + description: > + Size of the files that have been created or changed since creation. + - name: health + type: group + description: > + Container health metrics. + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: long + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/node/_meta/fields0.yml b/metricbeat/module/docker/node/_meta/fields0.yml new file mode 100644 index 000000000000..dcd3bb44ac49 --- /dev/null +++ b/metricbeat/module/docker/node/_meta/fields0.yml @@ -0,0 +1,103 @@ +- name: node + type: group + description: > + Docker node metrics. + fields: + - name: createdat + type: date + description: > + date where the node has been added to the cluster + - name: updatedad + type: date + description: > + last gossip message + - name: id + type: keyword + description: > + Unique node id. + - name: hostname + type: keyword + description: > + hostname of the node + #- name: spec + # type: group + # description: > + # Configured status + #fields: + # - name: role + # type: keyword + # description: > + # wanted role. + # - name: avaiability + # type: keyword + # description: > + # wanted status. + - name: platform + type: group + description: > + Node information hardware and system + fields: + - name: architecture + type: keyword + description: > + Cpu architecture of the node. + - name: os + type: keyword + description: > + OS node. + - name: ressources + type: group + description: > + available ressources on the node + fields: + - name: nanocpus + type: long + description: > + available CPU ressources + - name: memorybytes + type: long + description: > + available Memory ressources + - name: engine + type: group + description: > + docker engine information + fields: + - name: engine_version + type: keyword + description: > + Docker engine version number + - name: plugin + type: keyword + description: > + Docker plugin installed on the node + - name: status + type: group + description: > + docker swarm node status + fields: + - name: state + type: keyword + description: > + Docker engine state + - name: addr + type: keyword + description: > + docker + - name: managerstatus + type: group + description: > + docker swarm manager status + fields: + - name: leader + type: boolean + description: > + Docker engine manager state + - name: reachability + type: keyword + description: > + docker + - name: addr + type: keyword + description: > + docker manager listenning addr diff --git a/metricbeat/module/docker/node/container.go b/metricbeat/module/docker/node/container.go new file mode 100644 index 000000000000..d15c40a27ffe --- /dev/null +++ b/metricbeat/module/docker/node/container.go @@ -0,0 +1,52 @@ +package container + +import ( + dc "github.com/fsouza/go-dockerclient" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" +) + +func init() { + if err := mb.Registry.AddMetricSet("docker", "node", New, docker.HostParser); err != nil { + panic(err) + } +} + +type MetricSet struct { + mb.BaseMetricSet + dockerClient *dc.Client +} + +// New creates a new instance of the docker container MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("EXPERIMENTAL: The docker container metricset is experimental") + + config := docker.Config{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + client, err := docker.NewDockerClient(base.HostData().URI, config) + if err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + dockerClient: client, + }, nil +} + +// Fetch returns a list of all containers as events. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + // Fetch a list of all containers. + containers, err := m.dockerClient.ListContainers(dc.ListContainersOptions{}) + if err != nil { + return nil, err + } + return eventsMapping(containers, m), nil +} diff --git a/metricbeat/module/docker/node/container_integration_test.go b/metricbeat/module/docker/node/container_integration_test.go new file mode 100644 index 000000000000..0233f340f89e --- /dev/null +++ b/metricbeat/module/docker/node/container_integration_test.go @@ -0,0 +1,25 @@ +// +build integration + +package container + +import ( + "testing" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "docker", + "metricsets": []string{"container"}, + "hosts": []string{"unix:///var/run/docker.sock"}, + } +} diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go new file mode 100644 index 000000000000..0ead59a039fa --- /dev/null +++ b/metricbeat/module/docker/node/data.go @@ -0,0 +1,57 @@ +package container + +import ( + "time" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/module/docker" + + "strings" + dc "github.com/fsouza/go-dockerclient" +) + +func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { + myEvents := []common.MapStr{} + for _, container := range containersList { + myEvents = append(myEvents, eventMapping(&container, m)) + } + return myEvents +} + +func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { + event := common.MapStr{ + "created": common.Time(time.Unix(cont.Created, 0)), + "id": cont.ID, + "name": docker.ExtractContainerName(cont.Names), + "command": cont.Command, + "image": cont.Image, + "size": common.MapStr{ + "root_fs": cont.SizeRootFs, + "rw": cont.SizeRw, + }, + "status": cont.Status, + } + + if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log)-1 + + health := common.MapStr{ + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event_start_date": container.State.Health.Log[last_event].Start, + "event_end_date": container.State.Health.Log[last_event].End, + "event_exit_code": container.State.Health.Log[last_event].ExitCode, + "event_output": container.State.Health.Log[last_event].Output, + } + event["health"] = health + } + + labels := docker.DeDotLabels(cont.Labels) + + if len(labels) > 0 { + event["labels"] = labels + } + + return event +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go new file mode 100644 index 000000000000..fc050e5dba9d --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go @@ -0,0 +1,62 @@ +package container + +import ( + "time" + + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" +) + +// HealthConfig holds configuration settings for the HEALTHCHECK feature. +type HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `json:",omitempty"` + + // Zero means to inherit. Durations are expressed as integer nanoseconds. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + + // Retries is the number of consecutive failures needed to consider a container as unhealthy. + // Zero means inherit. + Retries int `json:",omitempty"` +} + +// Config contains the configuration data about a container. +// It should hold only portable information about the container. +// Here, "portable" means "independent from the host we are running on". +// Non-portable information *should* appear in HostConfig. +// All fields added to this struct must be marked `omitempty` to keep getting +// predictable hashes from the old `v1Compatibility` configuration. +type Config struct { + Hostname string // Hostname + Domainname string // Domainname + User string // User that will run the command(s) inside the container, also support user:group + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStdout bool // Attach the standard output + AttachStderr bool // Attach the standard error + ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports + Tty bool // Attach standard streams to a tty, including stdin if it is not closed. + OpenStdin bool // Open stdin + StdinOnce bool // If true, close stdin after the 1 attached client disconnects. + Env []string // List of environment variable to set in the container + Cmd strslice.StrSlice // Command to run when starting the container + Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy + ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific) + Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) + Volumes map[string]struct{} // List of volumes (mounts) used for the container + WorkingDir string // Current directory (PWD) in the command will be launched + Entrypoint strslice.StrSlice // Entrypoint to run when starting the container + NetworkDisabled bool `json:",omitempty"` // Is network disabled + MacAddress string `json:",omitempty"` // Mac Address of the container + OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile + Labels map[string]string // List of labels set to this container + StopSignal string `json:",omitempty"` // Signal to stop a container + StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container + Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go new file mode 100644 index 000000000000..c95023b814dc --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go @@ -0,0 +1,21 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerCreateCreatedBody container create created body +// swagger:model ContainerCreateCreatedBody +type ContainerCreateCreatedBody struct { + + // The ID of the created container + // Required: true + ID string `json:"Id"` + + // Warnings encountered when creating the container + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go new file mode 100644 index 000000000000..2339366fbd19 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go @@ -0,0 +1,17 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerUpdateOKBody container update o k body +// swagger:model ContainerUpdateOKBody +type ContainerUpdateOKBody struct { + + // warnings + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go new file mode 100644 index 000000000000..77ecdbaf7aed --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go @@ -0,0 +1,17 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerWaitOKBody container wait o k body +// swagger:model ContainerWaitOKBody +type ContainerWaitOKBody struct { + + // Exit code of the container + // Required: true + StatusCode int64 `json:"StatusCode"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go new file mode 100644 index 000000000000..d34fa1405cf0 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go @@ -0,0 +1,333 @@ +package container + +import ( + "strings" + + "github.com/docker/docker/api/types/blkiodev" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" + "github.com/docker/go-units" +) + +// NetworkMode represents the container network stack. +type NetworkMode string + +// Isolation represents the isolation technology of a container. The supported +// values are platform specific +type Isolation string + +// IsDefault indicates the default isolation technology of a container. On Linux this +// is the native driver. On Windows, this is a Windows Server Container. +func (i Isolation) IsDefault() bool { + return strings.ToLower(string(i)) == "default" || string(i) == "" +} + +// IpcMode represents the container ipc stack. +type IpcMode string + +// IsPrivate indicates whether the container uses its private ipc stack. +func (n IpcMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsHost indicates whether the container uses the host's ipc stack. +func (n IpcMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether the container uses a container's ipc stack. +func (n IpcMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the ipc stack is valid. +func (n IpcMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + case "container": + if len(parts) != 2 || parts[1] == "" { + return false + } + default: + return false + } + return true +} + +// Container returns the name of the container ipc stack is going to be used. +func (n IpcMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UsernsMode represents userns mode in the container. +type UsernsMode string + +// IsHost indicates whether the container uses the host's userns. +func (n UsernsMode) IsHost() bool { + return n == "host" +} + +// IsPrivate indicates whether the container uses the a private userns. +func (n UsernsMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// Valid indicates whether the userns is valid. +func (n UsernsMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// CgroupSpec represents the cgroup to use for the container. +type CgroupSpec string + +// IsContainer indicates whether the container is using another container cgroup +func (c CgroupSpec) IsContainer() bool { + parts := strings.SplitN(string(c), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the cgroup spec is valid. +func (c CgroupSpec) Valid() bool { + return c.IsContainer() || c == "" +} + +// Container returns the name of the container whose cgroup will be used. +func (c CgroupSpec) Container() string { + parts := strings.SplitN(string(c), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UTSMode represents the UTS namespace of the container. +type UTSMode string + +// IsPrivate indicates whether the container uses its private UTS namespace. +func (n UTSMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// IsHost indicates whether the container uses the host's UTS namespace. +func (n UTSMode) IsHost() bool { + return n == "host" +} + +// Valid indicates whether the UTS namespace is valid. +func (n UTSMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// PidMode represents the pid namespace of the container. +type PidMode string + +// IsPrivate indicates whether the container uses its own new pid namespace. +func (n PidMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsHost indicates whether the container uses the host's pid namespace. +func (n PidMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether the container uses a container's pid namespace. +func (n PidMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the pid namespace is valid. +func (n PidMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + case "container": + if len(parts) != 2 || parts[1] == "" { + return false + } + default: + return false + } + return true +} + +// Container returns the name of the container whose pid namespace is going to be used. +func (n PidMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// DeviceMapping represents the device mapping between the host and the container. +type DeviceMapping struct { + PathOnHost string + PathInContainer string + CgroupPermissions string +} + +// RestartPolicy represents the restart policies of the container. +type RestartPolicy struct { + Name string + MaximumRetryCount int +} + +// IsNone indicates whether the container has the "no" restart policy. +// This means the container will not automatically restart when exiting. +func (rp *RestartPolicy) IsNone() bool { + return rp.Name == "no" || rp.Name == "" +} + +// IsAlways indicates whether the container has the "always" restart policy. +// This means the container will automatically restart regardless of the exit status. +func (rp *RestartPolicy) IsAlways() bool { + return rp.Name == "always" +} + +// IsOnFailure indicates whether the container has the "on-failure" restart policy. +// This means the container will automatically restart of exiting with a non-zero exit status. +func (rp *RestartPolicy) IsOnFailure() bool { + return rp.Name == "on-failure" +} + +// IsUnlessStopped indicates whether the container has the +// "unless-stopped" restart policy. This means the container will +// automatically restart unless user has put it to stopped state. +func (rp *RestartPolicy) IsUnlessStopped() bool { + return rp.Name == "unless-stopped" +} + +// IsSame compares two RestartPolicy to see if they are the same +func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { + return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount +} + +// LogConfig represents the logging configuration of the container. +type LogConfig struct { + Type string + Config map[string]string +} + +// Resources contains container's resources (cgroups config, ulimits...) +type Resources struct { + // Applicable to all platforms + CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) + Memory int64 // Memory limit (in bytes) + NanoCPUs int64 `json:"NanoCpus"` // CPU quota in units of 10-9 CPUs. + + // Applicable to UNIX platforms + CgroupParent string // Parent cgroup. + BlkioWeight uint16 // Block IO weight (relative weight vs. other containers) + BlkioWeightDevice []*blkiodev.WeightDevice + BlkioDeviceReadBps []*blkiodev.ThrottleDevice + BlkioDeviceWriteBps []*blkiodev.ThrottleDevice + BlkioDeviceReadIOps []*blkiodev.ThrottleDevice + BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice + CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period + CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota + CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` // CPU real-time period + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` // CPU real-time runtime + CpusetCpus string // CpusetCpus 0-2, 0,1 + CpusetMems string // CpusetMems 0-2, 0,1 + Devices []DeviceMapping // List of devices to map inside the container + DiskQuota int64 // Disk limit (in bytes) + KernelMemory int64 // Kernel memory limit (in bytes) + MemoryReservation int64 // Memory soft limit (in bytes) + MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap + MemorySwappiness *int64 // Tuning container memory swappiness behaviour + OomKillDisable *bool // Whether to disable OOM Killer or not + PidsLimit int64 // Setting pids limit for a container + Ulimits []*units.Ulimit // List of ulimits to be set in the container + + // Applicable to Windows + CPUCount int64 `json:"CpuCount"` // CPU count + CPUPercent int64 `json:"CpuPercent"` // CPU percent + IOMaximumIOps uint64 // Maximum IOps for the container system drive + IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive +} + +// UpdateConfig holds the mutable attributes of a Container. +// Those attributes can be updated at runtime. +type UpdateConfig struct { + // Contains container's resources (cgroups, ulimits) + Resources + RestartPolicy RestartPolicy +} + +// HostConfig the non-portable Config structure of a container. +// Here, "non-portable" means "dependent of the host we are running on". +// Portable information *should* appear in Config. +type HostConfig struct { + // Applicable to all platforms + Binds []string // List of volume bindings for this container + ContainerIDFile string // File (path) where the containerId is written + LogConfig LogConfig // Configuration of the logs for this container + NetworkMode NetworkMode // Network mode to use for the container + PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host + RestartPolicy RestartPolicy // Restart policy to be used for the container + AutoRemove bool // Automatically remove container when it exits + VolumeDriver string // Name of the volume driver used to mount volumes + VolumesFrom []string // List of volumes to take from other container + + // Applicable to UNIX platforms + CapAdd strslice.StrSlice // List of kernel capabilities to add to the container + CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container + DNS []string `json:"Dns"` // List of DNS server to lookup + DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for + DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for + ExtraHosts []string // List of extra hosts + GroupAdd []string // List of additional groups that the container process will run as + IpcMode IpcMode // IPC namespace to use for the container + Cgroup CgroupSpec // Cgroup to use for the container + Links []string // List of links (in the name:alias form) + OomScoreAdj int // Container preference for OOM-killing + PidMode PidMode // PID namespace to use for the container + Privileged bool // Is the container in privileged mode + PublishAllPorts bool // Should docker publish all exposed port for the container + ReadonlyRootfs bool // Is the container root filesystem in read-only + SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. + StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. + Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container + UTSMode UTSMode // UTS namespace to use for the container + UsernsMode UsernsMode // The user namespace to use for the container + ShmSize int64 // Total shm memory usage + Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container + Runtime string `json:",omitempty"` // Runtime to use with this container + + // Applicable to Windows + ConsoleSize [2]uint // Initial console size (height,width) + Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) + + // Contains container's resources (cgroups, ulimits) + Resources + + // Mounts specs used by the container + Mounts []mount.Mount `json:",omitempty"` + + // Run a custom init inside the container, if null, use the daemon's configured settings + Init *bool `json:",omitempty"` + + // Custom init path + InitPath string `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go new file mode 100644 index 000000000000..9fb79bed6f39 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go @@ -0,0 +1,81 @@ +// +build !windows + +package container + +import "strings" + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() +} + +// IsPrivate indicates whether container uses its private network stack. +func (n NetworkMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsDefault indicates whether container uses the default network stack. +func (n NetworkMode) IsDefault() bool { + return n == "default" +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsBridge() { + return "bridge" + } else if n.IsHost() { + return "host" + } else if n.IsContainer() { + return "container" + } else if n.IsNone() { + return "none" + } else if n.IsDefault() { + return "default" + } else if n.IsUserDefined() { + return n.UserDefined() + } + return "" +} + +// IsBridge indicates whether container uses the bridge network stack +func (n NetworkMode) IsBridge() bool { + return n == "bridge" +} + +// IsHost indicates whether container uses the host network stack. +func (n NetworkMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether container uses a container network stack. +func (n NetworkMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// IsNone indicates whether container isn't using a network stack. +func (n NetworkMode) IsNone() bool { + return n == "none" +} + +// ConnectedContainer is the id of the container which network this container is connected to. +func (n NetworkMode) ConnectedContainer() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() +} + +//UserDefined indicates user-created network +func (n NetworkMode) UserDefined() string { + if n.IsUserDefined() { + return string(n) + } + return "" +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go new file mode 100644 index 000000000000..0ee332ba6899 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go @@ -0,0 +1,87 @@ +package container + +import ( + "strings" +) + +// IsDefault indicates whether container uses the default network stack. +func (n NetworkMode) IsDefault() bool { + return n == "default" +} + +// IsNone indicates whether container isn't using a network stack. +func (n NetworkMode) IsNone() bool { + return n == "none" +} + +// IsContainer indicates whether container uses a container network stack. +// Returns false as windows doesn't support this mode +func (n NetworkMode) IsContainer() bool { + return false +} + +// IsBridge indicates whether container uses the bridge network stack +// in windows it is given the name NAT +func (n NetworkMode) IsBridge() bool { + return n == "nat" +} + +// IsHost indicates whether container uses the host network stack. +// returns false as this is not supported by windows +func (n NetworkMode) IsHost() bool { + return false +} + +// IsPrivate indicates whether container uses its private network stack. +func (n NetworkMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// ConnectedContainer is the id of the container which network this container is connected to. +// Returns blank string on windows +func (n NetworkMode) ConnectedContainer() string { + return "" +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsNone() && !n.IsBridge() +} + +// IsHyperV indicates the use of a Hyper-V partition for isolation +func (i Isolation) IsHyperV() bool { + return strings.ToLower(string(i)) == "hyperv" +} + +// IsProcess indicates the use of process isolation +func (i Isolation) IsProcess() bool { + return strings.ToLower(string(i)) == "process" +} + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() || i.IsHyperV() || i.IsProcess() +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsDefault() { + return "default" + } else if n.IsBridge() { + return "nat" + } else if n.IsNone() { + return "none" + } else if n.IsUserDefined() { + return n.UserDefined() + } + + return "" +} + +//UserDefined indicates user-created network +func (n NetworkMode) UserDefined() string { + if n.IsUserDefined() { + return string(n) + } + return "" +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go new file mode 100644 index 000000000000..31f2365b8ec0 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go @@ -0,0 +1,113 @@ +package mount + +import ( + "os" +) + +// Type represents the type of a mount. +type Type string + +// Type constants +const ( + // TypeBind is the type for mounting host dir + TypeBind Type = "bind" + // TypeVolume is the type for remote storage volumes + TypeVolume Type = "volume" + // TypeTmpfs is the type for mounting tmpfs + TypeTmpfs Type = "tmpfs" +) + +// Mount represents a mount (volume). +type Mount struct { + Type Type `json:",omitempty"` + // Source specifies the name of the mount. Depending on mount type, this + // may be a volume name or a host path, or even ignored. + // Source is not supported for tmpfs (must be an empty value) + Source string `json:",omitempty"` + Target string `json:",omitempty"` + ReadOnly bool `json:",omitempty"` + + BindOptions *BindOptions `json:",omitempty"` + VolumeOptions *VolumeOptions `json:",omitempty"` + TmpfsOptions *TmpfsOptions `json:",omitempty"` +} + +// Propagation represents the propagation of a mount. +type Propagation string + +const ( + // PropagationRPrivate RPRIVATE + PropagationRPrivate Propagation = "rprivate" + // PropagationPrivate PRIVATE + PropagationPrivate Propagation = "private" + // PropagationRShared RSHARED + PropagationRShared Propagation = "rshared" + // PropagationShared SHARED + PropagationShared Propagation = "shared" + // PropagationRSlave RSLAVE + PropagationRSlave Propagation = "rslave" + // PropagationSlave SLAVE + PropagationSlave Propagation = "slave" +) + +// Propagations is the list of all valid mount propagations +var Propagations = []Propagation{ + PropagationRPrivate, + PropagationPrivate, + PropagationRShared, + PropagationShared, + PropagationRSlave, + PropagationSlave, +} + +// BindOptions defines options specific to mounts of type "bind". +type BindOptions struct { + Propagation Propagation `json:",omitempty"` +} + +// VolumeOptions represents the options for a mount of type volume. +type VolumeOptions struct { + NoCopy bool `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + DriverConfig *Driver `json:",omitempty"` +} + +// Driver represents a volume driver. +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} + +// TmpfsOptions defines options specific to mounts of type "tmpfs". +type TmpfsOptions struct { + // Size sets the size of the tmpfs, in bytes. + // + // This will be converted to an operating system specific value + // depending on the host. For example, on linux, it will be convered to + // use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with + // docker, uses a straight byte value. + // + // Percentages are not supported. + SizeBytes int64 `json:",omitempty"` + // Mode of the tmpfs upon creation + Mode os.FileMode `json:",omitempty"` + + // TODO(stevvooe): There are several more tmpfs flags, specified in the + // daemon, that are accepted. Only the most basic are added for now. + // + // From docker/docker/pkg/mount/flags.go: + // + // var validFlags = map[string]bool{ + // "": true, + // "size": true, X + // "mode": true, X + // "uid": true, + // "gid": true, + // "nr_inodes": true, + // "nr_blocks": true, + // "mpol": true, + // } + // + // Some of these may be straightforward to add, but others, such as + // uid/gid have implications in a clustered system. +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go new file mode 100644 index 000000000000..64a648bad15a --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go @@ -0,0 +1,27 @@ +package swarm + +import "time" + +// Version represents the internal object version. +type Version struct { + Index uint64 `json:",omitempty"` +} + +// Meta is a base object inherited by most of the other once. +type Meta struct { + Version Version `json:",omitempty"` + CreatedAt time.Time `json:",omitempty"` + UpdatedAt time.Time `json:",omitempty"` +} + +// Annotations represents how to describe an object. +type Annotations struct { + Name string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` +} + +// Driver represents a driver (network, logging). +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go new file mode 100644 index 000000000000..4ab476ccc392 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go @@ -0,0 +1,46 @@ +package swarm + +import ( + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" +) + +// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) +// Detailed documentation is available in: +// http://man7.org/linux/man-pages/man5/resolv.conf.5.html +// `nameserver`, `search`, `options` have been supported. +// TODO: `domain` is not supported yet. +type DNSConfig struct { + // Nameservers specifies the IP addresses of the name servers + Nameservers []string `json:",omitempty"` + // Search specifies the search list for host-name lookup + Search []string `json:",omitempty"` + // Options allows certain internal resolver variables to be modified + Options []string `json:",omitempty"` +} + +// ContainerSpec represents the spec of a container. +type ContainerSpec struct { + Image string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Command []string `json:",omitempty"` + Args []string `json:",omitempty"` + Hostname string `json:",omitempty"` + Env []string `json:",omitempty"` + Dir string `json:",omitempty"` + User string `json:",omitempty"` + Groups []string `json:",omitempty"` + TTY bool `json:",omitempty"` + OpenStdin bool `json:",omitempty"` + Mounts []mount.Mount `json:",omitempty"` + StopGracePeriod *time.Duration `json:",omitempty"` + Healthcheck *container.HealthConfig `json:",omitempty"` + // The format of extra hosts on swarmkit is specified in: + // http://man7.org/linux/man-pages/man5/hosts.5.html + // IP_address canonical_hostname [aliases...] + Hosts []string `json:",omitempty"` + DNSConfig *DNSConfig `json:",omitempty"` + Secrets []*SecretReference `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go new file mode 100644 index 000000000000..5a5e11bdba59 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go @@ -0,0 +1,111 @@ +package swarm + +// Endpoint represents an endpoint. +type Endpoint struct { + Spec EndpointSpec `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` + VirtualIPs []EndpointVirtualIP `json:",omitempty"` +} + +// EndpointSpec represents the spec of an endpoint. +type EndpointSpec struct { + Mode ResolutionMode `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` +} + +// ResolutionMode represents a resolution mode. +type ResolutionMode string + +const ( + // ResolutionModeVIP VIP + ResolutionModeVIP ResolutionMode = "vip" + // ResolutionModeDNSRR DNSRR + ResolutionModeDNSRR ResolutionMode = "dnsrr" +) + +// PortConfig represents the config of a port. +type PortConfig struct { + Name string `json:",omitempty"` + Protocol PortConfigProtocol `json:",omitempty"` + // TargetPort is the port inside the container + TargetPort uint32 `json:",omitempty"` + // PublishedPort is the port on the swarm hosts + PublishedPort uint32 `json:",omitempty"` + // PublishMode is the mode in which port is published + PublishMode PortConfigPublishMode `json:",omitempty"` +} + +// PortConfigPublishMode represents the mode in which the port is to +// be published. +type PortConfigPublishMode string + +const ( + // PortConfigPublishModeIngress is used for ports published + // for ingress load balancing using routing mesh. + PortConfigPublishModeIngress PortConfigPublishMode = "ingress" + // PortConfigPublishModeHost is used for ports published + // for direct host level access on the host where the task is running. + PortConfigPublishModeHost PortConfigPublishMode = "host" +) + +// PortConfigProtocol represents the protocol of a port. +type PortConfigProtocol string + +const ( + // TODO(stevvooe): These should be used generally, not just for PortConfig. + + // PortConfigProtocolTCP TCP + PortConfigProtocolTCP PortConfigProtocol = "tcp" + // PortConfigProtocolUDP UDP + PortConfigProtocolUDP PortConfigProtocol = "udp" +) + +// EndpointVirtualIP represents the virtual ip of a port. +type EndpointVirtualIP struct { + NetworkID string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Network represents a network. +type Network struct { + ID string + Meta + Spec NetworkSpec `json:",omitempty"` + DriverState Driver `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` +} + +// NetworkSpec represents the spec of a network. +type NetworkSpec struct { + Annotations + DriverConfiguration *Driver `json:",omitempty"` + IPv6Enabled bool `json:",omitempty"` + Internal bool `json:",omitempty"` + Attachable bool `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` +} + +// NetworkAttachmentConfig represents the configuration of a network attachment. +type NetworkAttachmentConfig struct { + Target string `json:",omitempty"` + Aliases []string `json:",omitempty"` +} + +// NetworkAttachment represents a network attachment. +type NetworkAttachment struct { + Network Network `json:",omitempty"` + Addresses []string `json:",omitempty"` +} + +// IPAMOptions represents ipam options. +type IPAMOptions struct { + Driver Driver `json:",omitempty"` + Configs []IPAMConfig `json:",omitempty"` +} + +// IPAMConfig represents ipam configuration. +type IPAMConfig struct { + Subnet string `json:",omitempty"` + Range string `json:",omitempty"` + Gateway string `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go new file mode 100644 index 000000000000..379e17a779ac --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go @@ -0,0 +1,114 @@ +package swarm + +// Node represents a node. +type Node struct { + ID string + Meta + // Spec defines the desired state of the node as specified by the user. + // The system will honor this and will *never* modify it. + Spec NodeSpec `json:",omitempty"` + // Description encapsulates the properties of the Node as reported by the + // agent. + Description NodeDescription `json:",omitempty"` + // Status provides the current status of the node, as seen by the manager. + Status NodeStatus `json:",omitempty"` + // ManagerStatus provides the current status of the node's manager + // component, if the node is a manager. + ManagerStatus *ManagerStatus `json:",omitempty"` +} + +// NodeSpec represents the spec of a node. +type NodeSpec struct { + Annotations + Role NodeRole `json:",omitempty"` + Availability NodeAvailability `json:",omitempty"` +} + +// NodeRole represents the role of a node. +type NodeRole string + +const ( + // NodeRoleWorker WORKER + NodeRoleWorker NodeRole = "worker" + // NodeRoleManager MANAGER + NodeRoleManager NodeRole = "manager" +) + +// NodeAvailability represents the availability of a node. +type NodeAvailability string + +const ( + // NodeAvailabilityActive ACTIVE + NodeAvailabilityActive NodeAvailability = "active" + // NodeAvailabilityPause PAUSE + NodeAvailabilityPause NodeAvailability = "pause" + // NodeAvailabilityDrain DRAIN + NodeAvailabilityDrain NodeAvailability = "drain" +) + +// NodeDescription represents the description of a node. +type NodeDescription struct { + Hostname string `json:",omitempty"` + Platform Platform `json:",omitempty"` + Resources Resources `json:",omitempty"` + Engine EngineDescription `json:",omitempty"` +} + +// Platform represents the platform (Arch/OS). +type Platform struct { + Architecture string `json:",omitempty"` + OS string `json:",omitempty"` +} + +// EngineDescription represents the description of an engine. +type EngineDescription struct { + EngineVersion string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Plugins []PluginDescription `json:",omitempty"` +} + +// PluginDescription represents the description of an engine plugin. +type PluginDescription struct { + Type string `json:",omitempty"` + Name string `json:",omitempty"` +} + +// NodeStatus represents the status of a node. +type NodeStatus struct { + State NodeState `json:",omitempty"` + Message string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Reachability represents the reachability of a node. +type Reachability string + +const ( + // ReachabilityUnknown UNKNOWN + ReachabilityUnknown Reachability = "unknown" + // ReachabilityUnreachable UNREACHABLE + ReachabilityUnreachable Reachability = "unreachable" + // ReachabilityReachable REACHABLE + ReachabilityReachable Reachability = "reachable" +) + +// ManagerStatus represents the status of a manager. +type ManagerStatus struct { + Leader bool `json:",omitempty"` + Reachability Reachability `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// NodeState represents the state of a node. +type NodeState string + +const ( + // NodeStateUnknown UNKNOWN + NodeStateUnknown NodeState = "unknown" + // NodeStateDown DOWN + NodeStateDown NodeState = "down" + // NodeStateReady READY + NodeStateReady NodeState = "ready" + // NodeStateDisconnected DISCONNECTED + NodeStateDisconnected NodeState = "disconnected" +) diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go new file mode 100644 index 000000000000..fdb2388888d9 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go @@ -0,0 +1,31 @@ +package swarm + +import "os" + +// Secret represents a secret. +type Secret struct { + ID string + Meta + Spec SecretSpec +} + +// SecretSpec represents a secret specification from a secret in swarm +type SecretSpec struct { + Annotations + Data []byte `json:",omitempty"` +} + +// SecretReferenceFileTarget is a file target in a secret reference +type SecretReferenceFileTarget struct { + Name string + UID string + GID string + Mode os.FileMode +} + +// SecretReference is a reference to a secret in swarm +type SecretReference struct { + File *SecretReferenceFileTarget + SecretID string + SecretName string +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go new file mode 100644 index 000000000000..04f59de862e5 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go @@ -0,0 +1,105 @@ +package swarm + +import "time" + +// Service represents a service. +type Service struct { + ID string + Meta + Spec ServiceSpec `json:",omitempty"` + PreviousSpec *ServiceSpec `json:",omitempty"` + Endpoint Endpoint `json:",omitempty"` + UpdateStatus *UpdateStatus `json:",omitempty"` +} + +// ServiceSpec represents the spec of a service. +type ServiceSpec struct { + Annotations + + // TaskTemplate defines how the service should construct new tasks when + // orchestrating this service. + TaskTemplate TaskSpec `json:",omitempty"` + Mode ServiceMode `json:",omitempty"` + UpdateConfig *UpdateConfig `json:",omitempty"` + + // Networks field in ServiceSpec is deprecated. The + // same field in TaskSpec should be used instead. + // This field will be removed in a future release. + Networks []NetworkAttachmentConfig `json:",omitempty"` + EndpointSpec *EndpointSpec `json:",omitempty"` +} + +// ServiceMode represents the mode of a service. +type ServiceMode struct { + Replicated *ReplicatedService `json:",omitempty"` + Global *GlobalService `json:",omitempty"` +} + +// UpdateState is the state of a service update. +type UpdateState string + +const ( + // UpdateStateUpdating is the updating state. + UpdateStateUpdating UpdateState = "updating" + // UpdateStatePaused is the paused state. + UpdateStatePaused UpdateState = "paused" + // UpdateStateCompleted is the completed state. + UpdateStateCompleted UpdateState = "completed" +) + +// UpdateStatus reports the status of a service update. +type UpdateStatus struct { + State UpdateState `json:",omitempty"` + StartedAt *time.Time `json:",omitempty"` + CompletedAt *time.Time `json:",omitempty"` + Message string `json:",omitempty"` +} + +// ReplicatedService is a kind of ServiceMode. +type ReplicatedService struct { + Replicas *uint64 `json:",omitempty"` +} + +// GlobalService is a kind of ServiceMode. +type GlobalService struct{} + +const ( + // UpdateFailureActionPause PAUSE + UpdateFailureActionPause = "pause" + // UpdateFailureActionContinue CONTINUE + UpdateFailureActionContinue = "continue" +) + +// UpdateConfig represents the update configuration. +type UpdateConfig struct { + // Maximum number of tasks to be updated in one iteration. + // 0 means unlimited parallelism. + Parallelism uint64 + + // Amount of time between updates. + Delay time.Duration `json:",omitempty"` + + // FailureAction is the action to take when an update failures. + FailureAction string `json:",omitempty"` + + // Monitor indicates how long to monitor a task for failure after it is + // created. If the task fails by ending up in one of the states + // REJECTED, COMPLETED, or FAILED, within Monitor from its creation, + // this counts as a failure. If it fails after Monitor, it does not + // count as a failure. If Monitor is unspecified, a default value will + // be used. + Monitor time.Duration `json:",omitempty"` + + // MaxFailureRatio is the fraction of tasks that may fail during + // an update before the failure action is invoked. Any task created by + // the current update which ends up in one of the states REJECTED, + // COMPLETED or FAILED within Monitor from its creation counts as a + // failure. The number of failures is divided by the number of tasks + // being updated, and if this fraction is greater than + // MaxFailureRatio, the failure action is invoked. + // + // If the failure action is CONTINUE, there is no effect. + // If the failure action is PAUSE, no more tasks will be updated until + // another update is started. + MaxFailureRatio float32 +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go new file mode 100644 index 000000000000..0b4221969605 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go @@ -0,0 +1,197 @@ +package swarm + +import "time" + +// ClusterInfo represents info about the cluster for outputing in "info" +// it contains the same information as "Swarm", but without the JoinTokens +type ClusterInfo struct { + ID string + Meta + Spec Spec +} + +// Swarm represents a swarm. +type Swarm struct { + ClusterInfo + JoinTokens JoinTokens +} + +// JoinTokens contains the tokens workers and managers need to join the swarm. +type JoinTokens struct { + // Worker is the join token workers may use to join the swarm. + Worker string + // Manager is the join token managers may use to join the swarm. + Manager string +} + +// Spec represents the spec of a swarm. +type Spec struct { + Annotations + + Orchestration OrchestrationConfig `json:",omitempty"` + Raft RaftConfig `json:",omitempty"` + Dispatcher DispatcherConfig `json:",omitempty"` + CAConfig CAConfig `json:",omitempty"` + TaskDefaults TaskDefaults `json:",omitempty"` + EncryptionConfig EncryptionConfig `json:",omitempty"` +} + +// OrchestrationConfig represents orchestration configuration. +type OrchestrationConfig struct { + // TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or + // node. If negative, never remove completed or failed tasks. + TaskHistoryRetentionLimit *int64 `json:",omitempty"` +} + +// TaskDefaults parameterizes cluster-level task creation with default values. +type TaskDefaults struct { + // LogDriver selects the log driver to use for tasks created in the + // orchestrator if unspecified by a service. + // + // Updating this value will only have an affect on new tasks. Old tasks + // will continue use their previously configured log driver until + // recreated. + LogDriver *Driver `json:",omitempty"` +} + +// EncryptionConfig controls at-rest encryption of data and keys. +type EncryptionConfig struct { + // AutoLockManagers specifies whether or not managers TLS keys and raft data + // should be encrypted at rest in such a way that they must be unlocked + // before the manager node starts up again. + AutoLockManagers bool +} + +// RaftConfig represents raft configuration. +type RaftConfig struct { + // SnapshotInterval is the number of log entries between snapshots. + SnapshotInterval uint64 `json:",omitempty"` + + // KeepOldSnapshots is the number of snapshots to keep beyond the + // current snapshot. + KeepOldSnapshots *uint64 `json:",omitempty"` + + // LogEntriesForSlowFollowers is the number of log entries to keep + // around to sync up slow followers after a snapshot is created. + LogEntriesForSlowFollowers uint64 `json:",omitempty"` + + // ElectionTick is the number of ticks that a follower will wait for a message + // from the leader before becoming a candidate and starting an election. + // ElectionTick must be greater than HeartbeatTick. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + ElectionTick int + + // HeartbeatTick is the number of ticks between heartbeats. Every + // HeartbeatTick ticks, the leader will send a heartbeat to the + // followers. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + HeartbeatTick int +} + +// DispatcherConfig represents dispatcher configuration. +type DispatcherConfig struct { + // HeartbeatPeriod defines how often agent should send heartbeats to + // dispatcher. + HeartbeatPeriod time.Duration `json:",omitempty"` +} + +// CAConfig represents CA configuration. +type CAConfig struct { + // NodeCertExpiry is the duration certificates should be issued for + NodeCertExpiry time.Duration `json:",omitempty"` + + // ExternalCAs is a list of CAs to which a manager node will make + // certificate signing requests for node certificates. + ExternalCAs []*ExternalCA `json:",omitempty"` +} + +// ExternalCAProtocol represents type of external CA. +type ExternalCAProtocol string + +// ExternalCAProtocolCFSSL CFSSL +const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" + +// ExternalCA defines external CA to be used by the cluster. +type ExternalCA struct { + // Protocol is the protocol used by this external CA. + Protocol ExternalCAProtocol + + // URL is the URL where the external CA can be reached. + URL string + + // Options is a set of additional key/value pairs whose interpretation + // depends on the specified CA type. + Options map[string]string `json:",omitempty"` +} + +// InitRequest is the request used to init a swarm. +type InitRequest struct { + ListenAddr string + AdvertiseAddr string + ForceNewCluster bool + Spec Spec + AutoLockManagers bool +} + +// JoinRequest is the request used to join a swarm. +type JoinRequest struct { + ListenAddr string + AdvertiseAddr string + RemoteAddrs []string + JoinToken string // accept by secret +} + +// UnlockRequest is the request used to unlock a swarm. +type UnlockRequest struct { + // UnlockKey is the unlock key in ASCII-armored format. + UnlockKey string +} + +// LocalNodeState represents the state of the local node. +type LocalNodeState string + +const ( + // LocalNodeStateInactive INACTIVE + LocalNodeStateInactive LocalNodeState = "inactive" + // LocalNodeStatePending PENDING + LocalNodeStatePending LocalNodeState = "pending" + // LocalNodeStateActive ACTIVE + LocalNodeStateActive LocalNodeState = "active" + // LocalNodeStateError ERROR + LocalNodeStateError LocalNodeState = "error" + // LocalNodeStateLocked LOCKED + LocalNodeStateLocked LocalNodeState = "locked" +) + +// Info represents generic information about swarm. +type Info struct { + NodeID string + NodeAddr string + + LocalNodeState LocalNodeState + ControlAvailable bool + Error string + + RemoteManagers []Peer + Nodes int + Managers int + + Cluster ClusterInfo +} + +// Peer represents a peer. +type Peer struct { + NodeID string + Addr string +} + +// UpdateFlags contains flags for SwarmUpdate. +type UpdateFlags struct { + RotateWorkerToken bool + RotateManagerToken bool + RotateManagerUnlockKey bool +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go new file mode 100644 index 000000000000..ace12cc89fa3 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go @@ -0,0 +1,128 @@ +package swarm + +import "time" + +// TaskState represents the state of a task. +type TaskState string + +const ( + // TaskStateNew NEW + TaskStateNew TaskState = "new" + // TaskStateAllocated ALLOCATED + TaskStateAllocated TaskState = "allocated" + // TaskStatePending PENDING + TaskStatePending TaskState = "pending" + // TaskStateAssigned ASSIGNED + TaskStateAssigned TaskState = "assigned" + // TaskStateAccepted ACCEPTED + TaskStateAccepted TaskState = "accepted" + // TaskStatePreparing PREPARING + TaskStatePreparing TaskState = "preparing" + // TaskStateReady READY + TaskStateReady TaskState = "ready" + // TaskStateStarting STARTING + TaskStateStarting TaskState = "starting" + // TaskStateRunning RUNNING + TaskStateRunning TaskState = "running" + // TaskStateComplete COMPLETE + TaskStateComplete TaskState = "complete" + // TaskStateShutdown SHUTDOWN + TaskStateShutdown TaskState = "shutdown" + // TaskStateFailed FAILED + TaskStateFailed TaskState = "failed" + // TaskStateRejected REJECTED + TaskStateRejected TaskState = "rejected" +) + +// Task represents a task. +type Task struct { + ID string + Meta + Annotations + + Spec TaskSpec `json:",omitempty"` + ServiceID string `json:",omitempty"` + Slot int `json:",omitempty"` + NodeID string `json:",omitempty"` + Status TaskStatus `json:",omitempty"` + DesiredState TaskState `json:",omitempty"` + NetworksAttachments []NetworkAttachment `json:",omitempty"` +} + +// TaskSpec represents the spec of a task. +type TaskSpec struct { + ContainerSpec ContainerSpec `json:",omitempty"` + Resources *ResourceRequirements `json:",omitempty"` + RestartPolicy *RestartPolicy `json:",omitempty"` + Placement *Placement `json:",omitempty"` + Networks []NetworkAttachmentConfig `json:",omitempty"` + + // LogDriver specifies the LogDriver to use for tasks created from this + // spec. If not present, the one on cluster default on swarm.Spec will be + // used, finally falling back to the engine default if not specified. + LogDriver *Driver `json:",omitempty"` + + // ForceUpdate is a counter that triggers an update even if no relevant + // parameters have been changed. + ForceUpdate uint64 +} + +// Resources represents resources (CPU/Memory). +type Resources struct { + NanoCPUs int64 `json:",omitempty"` + MemoryBytes int64 `json:",omitempty"` +} + +// ResourceRequirements represents resources requirements. +type ResourceRequirements struct { + Limits *Resources `json:",omitempty"` + Reservations *Resources `json:",omitempty"` +} + +// Placement represents orchestration parameters. +type Placement struct { + Constraints []string `json:",omitempty"` +} + +// RestartPolicy represents the restart policy. +type RestartPolicy struct { + Condition RestartPolicyCondition `json:",omitempty"` + Delay *time.Duration `json:",omitempty"` + MaxAttempts *uint64 `json:",omitempty"` + Window *time.Duration `json:",omitempty"` +} + +// RestartPolicyCondition represents when to restart. +type RestartPolicyCondition string + +const ( + // RestartPolicyConditionNone NONE + RestartPolicyConditionNone RestartPolicyCondition = "none" + // RestartPolicyConditionOnFailure ON_FAILURE + RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure" + // RestartPolicyConditionAny ANY + RestartPolicyConditionAny RestartPolicyCondition = "any" +) + +// TaskStatus represents the status of a task. +type TaskStatus struct { + Timestamp time.Time `json:",omitempty"` + State TaskState `json:",omitempty"` + Message string `json:",omitempty"` + Err string `json:",omitempty"` + ContainerStatus ContainerStatus `json:",omitempty"` + PortStatus PortStatus `json:",omitempty"` +} + +// ContainerStatus represents the status of a container. +type ContainerStatus struct { + ContainerID string `json:",omitempty"` + PID int `json:",omitempty"` + ExitCode int `json:",omitempty"` +} + +// PortStatus represents the port status of a task's host ports whose +// service has published host ports +type PortStatus struct { + Ports []PortConfig `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go new file mode 100644 index 000000000000..3d790ff54c85 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go @@ -0,0 +1,68 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "encoding/json" + "net/http" + + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" +) + +// NoSuchNode is the error returned when a given node does not exist. +type NoSuchNode struct { + ID string + Err error +} + +func (err *NoSuchNode) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such node: " + err.ID +} + +// ListNodesOptions specify parameters to the ListNodes function. +// +// See http://goo.gl/3K4GwU for more details. +type ListNodesOptions struct { + Filters map[string][]string +} + +// ListNodes returns a slice of nodes matching the given criteria. +// +// See http://goo.gl/3K4GwU for more details. +func (c *Client) ListNodes(opts ListNodesOptions) ([]swarm.Node, error) { + path := "/nodes?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var nodes []swarm.Node + if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil { + return nil, err + } + return nodes, nil +} + +// InspectNode returns information about a node by its ID. +// +// See http://goo.gl/WjkTOk for more details. +func (c *Client) InspectNode(id string) (*swarm.Node, error) { + resp, err := c.do("GET", "/nodes/"+id, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchNode{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var node swarm.Node + if err := json.NewDecoder(resp.Body).Decode(&node); err != nil { + return nil, err + } + return &node, nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go new file mode 100644 index 000000000000..18beb008c5a2 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go @@ -0,0 +1,150 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "encoding/json" + "net/http" + "net/url" + "strconv" + + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" +) + +// NoSuchService is the error returned when a given service does not exist. +type NoSuchService struct { + ID string + Err error +} + +func (err *NoSuchService) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such service: " + err.ID +} + +// CreateServiceOptions specify parameters to the CreateService function. +// +// See https://goo.gl/KrVjHz for more details. +type CreateServiceOptions struct { + swarm.ServiceSpec +} + +// CreateService creates a new service, returning the service instance +// or an error in case of failure. +// +// See https://goo.gl/KrVjHz for more details. +func (c *Client) CreateService(opts CreateServiceOptions) (*swarm.Service, error) { + path := "/services/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.ServiceSpec, + forceJSON: true, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var service swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { + return nil, err + } + return &service, nil +} + +// RemoveServiceOptions encapsulates options to remove a service. +// +// See https://goo.gl/Tqrtya for more details. +type RemoveServiceOptions struct { + ID string `qs:"-"` +} + +// RemoveService removes a service, returning an error in case of failure. +// +// See https://goo.gl/Tqrtya for more details. +func (c *Client) RemoveService(opts RemoveServiceOptions) error { + path := "/services/" + opts.ID + resp, err := c.do("DELETE", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchService{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} + +// UpdateServiceOptions specify parameters to the UpdateService function. +// +// See https://goo.gl/wu3MmS for more details. +type UpdateServiceOptions struct { + swarm.ServiceSpec + Version uint64 +} + +// UpdateService updates the service at ID with the options +// +// See https://goo.gl/wu3MmS for more details. +func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { + params := make(url.Values) + params.Set("version", strconv.FormatUint(opts.Version, 10)) + resp, err := c.do("POST", "/services/"+id+"/update?"+params.Encode(), doOptions{ + data: opts.ServiceSpec, + forceJSON: true, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchService{ID: id} + } + return err + } + defer resp.Body.Close() + return nil +} + +// InspectService returns information about a service by its ID. +// +// See https://goo.gl/dHmr75 for more details. +func (c *Client) InspectService(id string) (*swarm.Service, error) { + path := "/services/" + id + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchService{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var service swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { + return nil, err + } + return &service, nil +} + +// ListServicesOptions specify parameters to the ListServices function. +// +// See https://goo.gl/DwvNMd for more details. +type ListServicesOptions struct { + Filters map[string][]string +} + +// ListServices returns a slice of services matching the given criteria. +// +// See https://goo.gl/DwvNMd for more details. +func (c *Client) ListServices(opts ListServicesOptions) ([]swarm.Service, error) { + path := "/services?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var services []swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&services); err != nil { + return nil, err + } + return services, nil +} From 016868229552ce7623b815f5e4ad2f56bb63b408 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 22:27:57 +0100 Subject: [PATCH 03/27] Add node module for docker metricset --- metricbeat/docs/fields.asciidoc | 150 +++++++++++++----- metricbeat/metricbeat.template-es2x.json | 121 ++++++++++++++ metricbeat/metricbeat.template.json | 108 +++++++++++++ metricbeat/metricbeat.yml | 38 ++--- .../module/docker/container/_meta/fields.yml | 2 +- metricbeat/module/docker/container/data.go | 4 - metricbeat/module/docker/node/_meta/data.json | 34 ++-- .../module/docker/node/_meta/docs.asciidoc | 2 +- .../module/docker/node/_meta/fields.yml | 118 +++++++++----- .../module/docker/node/_meta/fields0.yml | 103 ------------ metricbeat/module/docker/node/data.go | 76 +++++---- .../docker/node/{container.go => node.go} | 11 +- ...ation_test.go => node_integration_test.go} | 4 +- 13 files changed, 497 insertions(+), 274 deletions(-) delete mode 100644 metricbeat/module/docker/node/_meta/fields0.yml rename metricbeat/module/docker/node/{container.go => node.go} (81%) rename metricbeat/module/docker/node/{container_integration_test.go => node_integration_test.go} (88%) diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index e85dd704a9e2..f414e7247677 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1077,8 +1077,9 @@ Size of the files that have been created or changed since creation. Container health metrics. + [float] -=== docker.container.event_end_date +=== docker.container.health.event_end_date type: date @@ -1086,7 +1087,7 @@ Healthcheck end date [float] -=== docker.container.event_start_date +=== docker.container.health.event_start_date type: date @@ -1094,15 +1095,15 @@ Healthcheck start date [float] -=== docker.container.event_output +=== docker.container.health.event_output -type: long +type: keyword Healthcheck output [float] -=== docker.container.event_exit_code +=== docker.container.health.event_exit_code type: integer @@ -1455,119 +1456,188 @@ Total number of outgoing packets. [float] -== container Fields +== node Fields -Docker container metrics. +Docker node metrics. [float] -=== docker.container.command +=== docker.node.createdat -type: keyword +type: date -Command that was executed in the Docker container. +date where the node has been added to the cluster [float] -=== docker.container.created +=== docker.node.updatedad type: date -Date when the container was created. +last gossip message [float] -=== docker.container.id +=== docker.node.id type: keyword -Unique container id. +Unique node id. [float] -=== docker.container.image +=== docker.node.hostname type: keyword -Name of the image the container was built on. +hostname of the node [float] -=== docker.container.name +== spec Fields + +Configured status + + + +[float] +=== docker.node.spec.role type: keyword -Container name. +Wanted role [float] -=== docker.container.status +=== docker.node.spec.avaiability type: keyword -Container status. +wanted status. [float] -== size Fields +== platform Fields -Container size metrics. +Node information hardware and system [float] -=== docker.container.size.root_fs +=== docker.node.platform.architecture + +type: keyword + +Cpu architecture of the node. + + +[float] +=== docker.node.platform.os + +type: keyword + +OS node. + + +[float] +== ressources Fields + +available ressources on the node + + + +[float] +=== docker.node.ressources.nanocpus type: long -Total size of all the files in the container. +available CPU ressources [float] -=== docker.container.size.rw +=== docker.node.ressources.memorybytes type: long -Size of the files that have been created or changed since creation. +available Memory ressources [float] -== health Fields +== engine Fields + +docker engine information -Container health metrics. [float] -=== docker.container.event_end_date +=== docker.node.engine.engine_version -type: date +type: keyword -Healthcheck end date +Docker engine version number [float] -=== docker.container.event_start_date +=== docker.node.engine.plugin -type: date +type: keyword -Healthcheck start date +Docker plugin installed on the node [float] -=== docker.container.event_output +== status Fields -type: long +docker swarm node status -Healthcheck output [float] -=== docker.container.event_exit_code +=== docker.node.status.state -type: integer +type: keyword -Healthcheck status code +Docker engine state + + +[float] +=== docker.node.status.addr + +type: keyword + +docker + + +[float] +== managerstatus Fields + +docker swarm manager status + + + +[float] +=== docker.node.managerstatus.leader + +type: boolean + +Docker engine manager state + + +[float] +=== docker.node.managerstatus.reachability + +type: keyword + +docker + + +[float] +=== docker.node.managerstatus.addr + +type: keyword + +docker manager listenning addr [[exported-fields-haproxy]] diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index 7eabc2993a0a..2fc3f519381d 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -582,6 +582,24 @@ "created": { "type": "date" }, + "health": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "event_start_date": { + "type": "date" + } + } + }, "id": { "ignore_above": 1024, "index": "not_analyzed", @@ -773,6 +791,109 @@ } } } + }, + "node": { + "properties": { + "createdat": { + "type": "date" + }, + "engine": { + "properties": { + "engine_version": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "plugin": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "hostname": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "id": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "managerstatus": { + "properties": { + "addr": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "leader": { + "type": "boolean" + }, + "reachability": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "platform": { + "properties": { + "architecture": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "os": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "ressources": { + "properties": { + "memorybytes": { + "type": "long" + }, + "nanocpus": { + "type": "long" + } + } + }, + "spec": { + "properties": { + "avaiability": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "role": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "status": { + "properties": { + "addr": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "state": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "updatedad": { + "type": "date" + } + } } } }, diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index 01aab4c3775a..1f254fddd61b 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -584,6 +584,23 @@ "created": { "type": "date" }, + "health": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "type": "keyword" + }, + "event_start_date": { + "type": "date" + } + } + }, "id": { "ignore_above": 1024, "type": "keyword" @@ -781,6 +798,97 @@ } } } + }, + "node": { + "properties": { + "createdat": { + "type": "date" + }, + "engine": { + "properties": { + "engine_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "plugin": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "managerstatus": { + "properties": { + "addr": { + "ignore_above": 1024, + "type": "keyword" + }, + "leader": { + "type": "boolean" + }, + "reachability": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "platform": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ressources": { + "properties": { + "memorybytes": { + "type": "long" + }, + "nanocpus": { + "type": "long" + } + } + }, + "spec": { + "properties": { + "avaiability": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "status": { + "properties": { + "addr": { + "ignore_above": 1024, + "type": "keyword" + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "updatedad": { + "type": "date" + } + } } } }, diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index e024185f5ce6..657ea61828d2 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -10,28 +10,14 @@ #========================== Modules configuration ============================ metricbeat.modules: -#------------------------------- Docker Module ------------------------------- -- module: docker - metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] - hosts: ["unix:///var/run/docker.sock"] - enabled: true - period: 10s - - # To connect to Docker over TLS you must specify a client and CA certificate. - #ssl: - #certificate_authority: "/etc/pki/root/ca.pem" - #certificate: "/etc/pki/client/cert.pem" - #key: "/etc/pki/client/cert.key" - - #------------------------------- System Module ------------------------------- -#- module: system - #metricsets: +- module: system + metricsets: # CPU stats - #- cpu + - cpu # System Load stats - #- load + - load # Per CPU core stats #- core @@ -40,25 +26,25 @@ metricbeat.modules: #- diskio # Per filesystem stats - #- filesystem + - filesystem # File system summary stats - #- fsstat + - fsstat # Memory stats - #- memory + - memory # Network stats - #- network + - network # Per process stats - #- process + - process # Sockets (linux only) #- socket - #enabled: true - #period: 10s - #processes: ['.*'] + enabled: true + period: 10s + processes: ['.*'] diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index d6ad46412f4b..d70523ecea60 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -54,7 +54,7 @@ description: > Healthcheck start date - name: event_output - type: long + type: keyword description: > Healthcheck output - name: event_exit_code diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 783b8e6debf3..0ead59a039fa 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -8,7 +8,6 @@ import ( "strings" dc "github.com/fsouza/go-dockerclient" - "fmt" ) func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { @@ -34,7 +33,6 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { } if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - fmt.Println("HealthCheck !!\n") container, _ := m.dockerClient.InspectContainer(cont.ID) last_event := len(container.State.Health.Log)-1 @@ -47,8 +45,6 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "event_output": container.State.Health.Log[last_event].Output, } event["health"] = health - } else { - fmt.Println("No health check lets continue\n") } labels := docker.DeDotLabels(cont.Labels) diff --git a/metricbeat/module/docker/node/_meta/data.json b/metricbeat/module/docker/node/_meta/data.json index 349a01e87e3e..f03d1b95fb89 100644 --- a/metricbeat/module/docker/node/_meta/data.json +++ b/metricbeat/module/docker/node/_meta/data.json @@ -10,9 +10,13 @@ "updatedat": "2017-01-10T05:37:08.159552729Z", "id": "4be260de8fc1213c9ff58789b8221e70c53f5af5d5a3915ff7de4b81b357d851", "hostname": "thisisatest", + "labels": { + "swarm_labels_toto": "valueoftotolabel", + "swarm_number": "1" + }, "spec": { - "role": "manager", - "avaiability": "active" + "role": "manager", + "avaiability": "active" }, "platform": { "architecture": "x86_64", @@ -22,31 +26,21 @@ "nanocpus": 4000000000, "memorybytes": 8115884032 }, - "engine": { - "engine_version": "1.13.0-rc5", - "plugin": [ - { - "type": "Network", - "name": "bridge" - }, - { - "type": "Network", - "name": "host" - }, - { - "type": "volume", - "name": "local" - } - ] - }, "status": { "state": "ready", "addr": "127.0.0.1" }, - "managerstatus": { + "manager": { "leader": true, "reachability": "reachable", "addr": "192.168.1.38:2377" + }, + "engine": { + "version": "1.13.0-rc5", + "labels": + { + "enginelabel1=enginelabel1value" + } } } }, diff --git a/metricbeat/module/docker/node/_meta/docs.asciidoc b/metricbeat/module/docker/node/_meta/docs.asciidoc index 4d0dca8a7c43..cf4f9f984d02 100644 --- a/metricbeat/module/docker/node/_meta/docs.asciidoc +++ b/metricbeat/module/docker/node/_meta/docs.asciidoc @@ -1,4 +1,4 @@ -=== Docker Swarm Node Metricset +=== Docker Node Metricset The Docker Swarm `node` metricset collects information and statistics about running nodes in Docker cluster. diff --git a/metricbeat/module/docker/node/_meta/fields.yml b/metricbeat/module/docker/node/_meta/fields.yml index 032cdb8f17b1..383f67c88bcc 100644 --- a/metricbeat/module/docker/node/_meta/fields.yml +++ b/metricbeat/module/docker/node/_meta/fields.yml @@ -1,62 +1,104 @@ -- name: container +- name: node type: group description: > - Docker container metrics. + Docker node metrics. fields: - - name: command - type: keyword + + - name: createdat + type: date description: > - Command that was executed in the Docker container. - - name: created + date where the node has been added to the cluster + - name: updatedad type: date description: > - Date when the container was created. + last gossip message - name: id type: keyword description: > - Unique container id. - - name: image + Unique node id. + - name: hostname type: keyword description: > - Name of the image the container was built on. - - name: name - type: keyword + hostname of the node + - name: spec + type: group description: > - Container name. - - name: status - type: keyword + Configured status + fields: + - name: role + type: keyword + description: > + Wanted role + - name: avaiability + type: keyword + description: > + wanted status. + - name: platform + type: group description: > - Container status. - - name: size + Node information hardware and system + fields: + - name: architecture + type: keyword + description: > + Cpu architecture of the node. + - name: os + type: keyword + description: > + OS node. + - name: ressources type: group description: > - Container size metrics. + available ressources on the node fields: - - name: root_fs + - name: nanocpus type: long description: > - Total size of all the files in the container. - - name: rw + available CPU ressources + - name: memorybytes type: long description: > - Size of the files that have been created or changed since creation. - - name: health + available Memory ressources + - name: engine type: group description: > - Container health metrics. - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: long + docker engine information + fields: + - name: engine_version + type: keyword + description: > + Docker engine version number + - name: plugin + type: keyword + description: > + Docker plugin installed on the node + - name: status + type: group description: > - Healthcheck output - - name: event_exit_code - type: integer + docker swarm node status + fields: + - name: state + type: keyword + description: > + Docker engine state + - name: addr + type: keyword + description: > + docker + - name: managerstatus + type: group description: > - Healthcheck status code + docker swarm manager status + fields: + - name: leader + type: boolean + description: > + Docker engine manager state + - name: reachability + type: keyword + description: > + docker + - name: addr + type: keyword + description: > + docker manager listenning addr diff --git a/metricbeat/module/docker/node/_meta/fields0.yml b/metricbeat/module/docker/node/_meta/fields0.yml deleted file mode 100644 index dcd3bb44ac49..000000000000 --- a/metricbeat/module/docker/node/_meta/fields0.yml +++ /dev/null @@ -1,103 +0,0 @@ -- name: node - type: group - description: > - Docker node metrics. - fields: - - name: createdat - type: date - description: > - date where the node has been added to the cluster - - name: updatedad - type: date - description: > - last gossip message - - name: id - type: keyword - description: > - Unique node id. - - name: hostname - type: keyword - description: > - hostname of the node - #- name: spec - # type: group - # description: > - # Configured status - #fields: - # - name: role - # type: keyword - # description: > - # wanted role. - # - name: avaiability - # type: keyword - # description: > - # wanted status. - - name: platform - type: group - description: > - Node information hardware and system - fields: - - name: architecture - type: keyword - description: > - Cpu architecture of the node. - - name: os - type: keyword - description: > - OS node. - - name: ressources - type: group - description: > - available ressources on the node - fields: - - name: nanocpus - type: long - description: > - available CPU ressources - - name: memorybytes - type: long - description: > - available Memory ressources - - name: engine - type: group - description: > - docker engine information - fields: - - name: engine_version - type: keyword - description: > - Docker engine version number - - name: plugin - type: keyword - description: > - Docker plugin installed on the node - - name: status - type: group - description: > - docker swarm node status - fields: - - name: state - type: keyword - description: > - Docker engine state - - name: addr - type: keyword - description: > - docker - - name: managerstatus - type: group - description: > - docker swarm manager status - fields: - - name: leader - type: boolean - description: > - Docker engine manager state - - name: reachability - type: keyword - description: > - docker - - name: addr - type: keyword - description: > - docker manager listenning addr diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go index 0ead59a039fa..a6718242084d 100644 --- a/metricbeat/module/docker/node/data.go +++ b/metricbeat/module/docker/node/data.go @@ -1,56 +1,64 @@ -package container +package node import ( - "time" - "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/module/docker" - "strings" - dc "github.com/fsouza/go-dockerclient" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" ) -func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { +func eventsMapping(nodesList []swarm.Node, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} - for _, container := range containersList { - myEvents = append(myEvents, eventMapping(&container, m)) + + for _, node := range nodesList { + myEvents = append(myEvents, eventMapping(&node, m)) } + return myEvents } -func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { +func eventMapping(node *swarm.Node, m *MetricSet) common.MapStr { event := common.MapStr{ - "created": common.Time(time.Unix(cont.Created, 0)), - "id": cont.ID, - "name": docker.ExtractContainerName(cont.Names), - "command": cont.Command, - "image": cont.Image, - "size": common.MapStr{ - "root_fs": cont.SizeRootFs, - "rw": cont.SizeRw, + "createdat": node.Meta.CreatedAt, + "updatedat": node.Meta.UpdatedAt, + "id": node.ID, + "hostname": node.Description.Hostname, + "spec": common.MapStr{ + "role": node.Spec.Role, + "avaiability": node.Spec.Availability, + }, + "platform": common.MapStr{ + "architecture": node.Description.Platform.Architecture, + "os": node.Description.Platform.OS, }, - "status": cont.Status, + "status": common.MapStr{ + "state": node.Status.State, + "addr": node.Status.Addr, + }, + "ressources": common.MapStr{ + "nanocpus": node.Description.Resources.NanoCPUs, + "memorybytes": node.Description.Resources.MemoryBytes, + }, + "engine.version": node.Description.Engine.EngineVersion, } - if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - container, _ := m.dockerClient.InspectContainer(cont.ID) - last_event := len(container.State.Health.Log)-1 - - health := common.MapStr{ - "status": container.State.Health.Status, - "failingstreak": container.State.Health.FailingStreak, - "event_start_date": container.State.Health.Log[last_event].Start, - "event_end_date": container.State.Health.Log[last_event].End, - "event_exit_code": container.State.Health.Log[last_event].ExitCode, - "event_output": container.State.Health.Log[last_event].Output, + if node.Spec.Role == "manager" { + //fmt.Println("this is a manager ",node.ManagerStatus.Leader) + manager := common.MapStr{ + "leader": node.ManagerStatus.Leader, + "reachability": node.ManagerStatus.Reachability, + "addr": node.ManagerStatus.Addr, } - event["health"] = health + event["manager"] = manager } - labels := docker.DeDotLabels(cont.Labels) - - if len(labels) > 0 { - event["labels"] = labels + swarm_labels := docker.DeDotLabels(node.Spec.Annotations.Labels) + if len(swarm_labels) > 0 { + event["labels"] = swarm_labels + } + engine_labels := docker.DeDotLabels(node.Description.Engine.Labels) + if len(engine_labels) > 0 { + event["engine.labels"] = engine_labels } return event diff --git a/metricbeat/module/docker/node/container.go b/metricbeat/module/docker/node/node.go similarity index 81% rename from metricbeat/module/docker/node/container.go rename to metricbeat/module/docker/node/node.go index d15c40a27ffe..6381c53b6364 100644 --- a/metricbeat/module/docker/node/container.go +++ b/metricbeat/module/docker/node/node.go @@ -1,4 +1,4 @@ -package container +package node import ( dc "github.com/fsouza/go-dockerclient" @@ -22,7 +22,7 @@ type MetricSet struct { // New creates a new instance of the docker container MetricSet. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - logp.Warn("EXPERIMENTAL: The docker container metricset is experimental") + logp.Warn("EXPERIMENTAL: The docker node metricset is experimental") config := docker.Config{} if err := base.Module().UnpackConfig(&config); err != nil { @@ -43,10 +43,11 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { // Fetch returns a list of all containers as events. // This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. func (m *MetricSet) Fetch() ([]common.MapStr, error) { - // Fetch a list of all containers. - containers, err := m.dockerClient.ListContainers(dc.ListContainersOptions{}) + // Fetch a list of all nodes. + nodes, err := m.dockerClient.ListNodes(dc.ListNodesOptions{}) if err != nil { return nil, err } - return eventsMapping(containers, m), nil + + return eventsMapping(nodes, m), nil } diff --git a/metricbeat/module/docker/node/container_integration_test.go b/metricbeat/module/docker/node/node_integration_test.go similarity index 88% rename from metricbeat/module/docker/node/container_integration_test.go rename to metricbeat/module/docker/node/node_integration_test.go index 0233f340f89e..5a35029ef229 100644 --- a/metricbeat/module/docker/node/container_integration_test.go +++ b/metricbeat/module/docker/node/node_integration_test.go @@ -1,6 +1,6 @@ // +build integration -package container +package node import ( "testing" @@ -19,7 +19,7 @@ func TestData(t *testing.T) { func getConfig() map[string]interface{} { return map[string]interface{}{ "module": "docker", - "metricsets": []string{"container"}, + "metricsets": []string{"node"}, "hosts": []string{"unix:///var/run/docker.sock"}, } } From 8f0ed13422e870a48d967441e6c2ea2444326bbd Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 22:51:15 +0100 Subject: [PATCH 04/27] Fix docker dependency issue --- metricbeat/metricbeat.full.yml | 3 +- .../docker/api/types/blkiodev/blkio.go | 23 + .../docker/api/types/container/config.go | 6 +- .../docker/api/types/container/host_config.go | 15 +- .../docker/api/types/strslice/strslice.go | 30 + .../api/types/strslice/strslice_test.go | 86 +++ .../docker/api/types/swarm/container.go | 6 +- .../docker/go-connections/nat/nat.go | 242 ++++++++ .../docker/go-connections/nat/nat_test.go | 583 ++++++++++++++++++ .../docker/go-connections/nat/parse.go | 57 ++ .../docker/go-connections/nat/parse_test.go | 54 ++ .../docker/go-connections/nat/sort.go | 96 +++ .../docker/go-connections/nat/sort_test.go | 85 +++ 13 files changed, 1275 insertions(+), 11 deletions(-) create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 9ee2061376d4..fa74f1316ec8 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -99,7 +99,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -862,4 +862,3 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 - diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go new file mode 100644 index 000000000000..931ae10ab1ef --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go @@ -0,0 +1,23 @@ +package blkiodev + +import "fmt" + +// WeightDevice is a structure that holds device:weight pair +type WeightDevice struct { + Path string + Weight uint16 +} + +func (w *WeightDevice) String() string { + return fmt.Sprintf("%s:%d", w.Path, w.Weight) +} + +// ThrottleDevice is a structure that holds device:rate_per_second pair +type ThrottleDevice struct { + Path string + Rate uint64 +} + +func (t *ThrottleDevice) String() string { + return fmt.Sprintf("%s:%d", t.Path, t.Rate) +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go index fc050e5dba9d..e5ddd70665de 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go @@ -3,8 +3,10 @@ package container import ( "time" - "github.com/docker/docker/api/types/strslice" - "github.com/docker/go-connections/nat" + //"github.com/docker/docker/api/types/strslice" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice" + "github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat" + //"github.com/docker/go-connections/nat" ) // HealthConfig holds configuration settings for the HEALTHCHECK feature. diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go index d34fa1405cf0..889fc9356edb 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go @@ -3,11 +3,16 @@ package container import ( "strings" - "github.com/docker/docker/api/types/blkiodev" - "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/api/types/strslice" - "github.com/docker/go-connections/nat" - "github.com/docker/go-units" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount" + "github.com/fsouza/go-dockerclient/external/github.com/docker/go-units" + "github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat" + //"github.com/docker/docker/api/types/blkiodev" + //"github.com/docker/docker/api/types/mount" + //"github.com/docker/docker/api/types/strslice" + //"github.com/docker/go-connections/nat" + //"github.com/docker/go-units" ) // NetworkMode represents the container network stack. diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go new file mode 100644 index 000000000000..bad493fb89fd --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go @@ -0,0 +1,30 @@ +package strslice + +import "encoding/json" + +// StrSlice represents a string or an array of strings. +// We need to override the json decoder to accept both options. +type StrSlice []string + +// UnmarshalJSON decodes the byte slice whether it's a string or an array of +// strings. This method is needed to implement json.Unmarshaler. +func (e *StrSlice) UnmarshalJSON(b []byte) error { + if len(b) == 0 { + // With no input, we preserve the existing value by returning nil and + // leaving the target alone. This allows defining default values for + // the type. + return nil + } + + p := make([]string, 0, 1) + if err := json.Unmarshal(b, &p); err != nil { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + p = append(p, s) + } + + *e = p + return nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go new file mode 100644 index 000000000000..1163b3652c98 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go @@ -0,0 +1,86 @@ +package strslice + +import ( + "encoding/json" + "reflect" + "testing" +) + +func TestStrSliceMarshalJSON(t *testing.T) { + for _, testcase := range []struct { + input StrSlice + expected string + }{ + // MADNESS(stevvooe): No clue why nil would be "" but empty would be + // "null". Had to make a change here that may affect compatibility. + {input: nil, expected: "null"}, + {StrSlice{}, "[]"}, + {StrSlice{"/bin/sh", "-c", "echo"}, `["/bin/sh","-c","echo"]`}, + } { + data, err := json.Marshal(testcase.input) + if err != nil { + t.Fatal(err) + } + if string(data) != testcase.expected { + t.Fatalf("%#v: expected %v, got %v", testcase.input, testcase.expected, string(data)) + } + } +} + +func TestStrSliceUnmarshalJSON(t *testing.T) { + parts := map[string][]string{ + "": {"default", "values"}, + "[]": {}, + `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"}, + } + for json, expectedParts := range parts { + strs := StrSlice{"default", "values"} + if err := strs.UnmarshalJSON([]byte(json)); err != nil { + t.Fatal(err) + } + + actualParts := []string(strs) + if !reflect.DeepEqual(actualParts, expectedParts) { + t.Fatalf("%#v: expected %v, got %v", json, expectedParts, actualParts) + } + + } +} + +func TestStrSliceUnmarshalString(t *testing.T) { + var e StrSlice + echo, err := json.Marshal("echo") + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(echo, &e); err != nil { + t.Fatal(err) + } + + if len(e) != 1 { + t.Fatalf("expected 1 element after unmarshal: %q", e) + } + + if e[0] != "echo" { + t.Fatalf("expected `echo`, got: %q", e[0]) + } +} + +func TestStrSliceUnmarshalSlice(t *testing.T) { + var e StrSlice + echo, err := json.Marshal([]string{"echo"}) + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(echo, &e); err != nil { + t.Fatal(err) + } + + if len(e) != 1 { + t.Fatalf("expected 1 element after unmarshal: %q", e) + } + + if e[0] != "echo" { + t.Fatalf("expected `echo`, got: %q", e[0]) + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go index 4ab476ccc392..0b823eb24772 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go @@ -3,8 +3,10 @@ package swarm import ( "time" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/mount" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount" + //"github.com/docker/docker/api/types/container" + //"github.com/docker/docker/api/types/mount" ) // DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go new file mode 100644 index 000000000000..4d5f5ae63afd --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go @@ -0,0 +1,242 @@ +// Package nat is a convenience package for manipulation of strings describing network ports. +package nat + +import ( + "fmt" + "net" + "strconv" + "strings" +) + +const ( + // portSpecTemplate is the expected format for port specifications + portSpecTemplate = "ip:hostPort:containerPort" +) + +// PortBinding represents a binding between a Host IP address and a Host Port +type PortBinding struct { + // HostIP is the host IP Address + HostIP string `json:"HostIp"` + // HostPort is the host port number + HostPort string +} + +// PortMap is a collection of PortBinding indexed by Port +type PortMap map[Port][]PortBinding + +// PortSet is a collection of structs indexed by Port +type PortSet map[Port]struct{} + +// Port is a string containing port number and protocol in the format "80/tcp" +type Port string + +// NewPort creates a new instance of a Port given a protocol and port number or port range +func NewPort(proto, port string) (Port, error) { + // Check for parsing issues on "port" now so we can avoid having + // to check it later on. + + portStartInt, portEndInt, err := ParsePortRangeToInt(port) + if err != nil { + return "", err + } + + if portStartInt == portEndInt { + return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil + } + return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil +} + +// ParsePort parses the port number string and returns an int +func ParsePort(rawPort string) (int, error) { + if len(rawPort) == 0 { + return 0, nil + } + port, err := strconv.ParseUint(rawPort, 10, 16) + if err != nil { + return 0, err + } + return int(port), nil +} + +// ParsePortRangeToInt parses the port range string and returns start/end ints +func ParsePortRangeToInt(rawPort string) (int, int, error) { + if len(rawPort) == 0 { + return 0, 0, nil + } + start, end, err := ParsePortRange(rawPort) + if err != nil { + return 0, 0, err + } + return int(start), int(end), nil +} + +// Proto returns the protocol of a Port +func (p Port) Proto() string { + proto, _ := SplitProtoPort(string(p)) + return proto +} + +// Port returns the port number of a Port +func (p Port) Port() string { + _, port := SplitProtoPort(string(p)) + return port +} + +// Int returns the port number of a Port as an int +func (p Port) Int() int { + portStr := p.Port() + // We don't need to check for an error because we're going to + // assume that any error would have been found, and reported, in NewPort() + port, _ := ParsePort(portStr) + return port +} + +// Range returns the start/end port numbers of a Port range as ints +func (p Port) Range() (int, int, error) { + return ParsePortRangeToInt(p.Port()) +} + +// SplitProtoPort splits a port in the format of proto/port +func SplitProtoPort(rawPort string) (string, string) { + parts := strings.Split(rawPort, "/") + l := len(parts) + if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 { + return "", "" + } + if l == 1 { + return "tcp", rawPort + } + if len(parts[1]) == 0 { + return "tcp", parts[0] + } + return parts[1], parts[0] +} + +func validateProto(proto string) bool { + for _, availableProto := range []string{"tcp", "udp"} { + if availableProto == proto { + return true + } + } + return false +} + +// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses +// these in to the internal types +func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) { + var ( + exposedPorts = make(map[Port]struct{}, len(ports)) + bindings = make(map[Port][]PortBinding) + ) + for _, rawPort := range ports { + portMappings, err := ParsePortSpec(rawPort) + if err != nil { + return nil, nil, err + } + + for _, portMapping := range portMappings { + port := portMapping.Port + if _, exists := exposedPorts[port]; !exists { + exposedPorts[port] = struct{}{} + } + bslice, exists := bindings[port] + if !exists { + bslice = []PortBinding{} + } + bindings[port] = append(bslice, portMapping.Binding) + } + } + return exposedPorts, bindings, nil +} + +// PortMapping is a data object mapping a Port to a PortBinding +type PortMapping struct { + Port Port + Binding PortBinding +} + +func splitParts(rawport string) (string, string, string) { + parts := strings.Split(rawport, ":") + n := len(parts) + containerport := parts[n-1] + + switch n { + case 1: + return "", "", containerport + case 2: + return "", parts[0], containerport + case 3: + return parts[0], parts[1], containerport + default: + return strings.Join(parts[:n-2], ":"), parts[n-2], containerport + } +} + +// ParsePortSpec parses a port specification string into a slice of PortMappings +func ParsePortSpec(rawPort string) ([]PortMapping, error) { + var proto string + rawIP, hostPort, containerPort := splitParts(rawPort) + proto, containerPort = SplitProtoPort(containerPort) + + // Strip [] from IPV6 addresses + ip, _, err := net.SplitHostPort(rawIP + ":") + if err != nil { + return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err) + } + if ip != "" && net.ParseIP(ip) == nil { + return nil, fmt.Errorf("Invalid ip address: %s", ip) + } + if containerPort == "" { + return nil, fmt.Errorf("No port specified: %s", rawPort) + } + + startPort, endPort, err := ParsePortRange(containerPort) + if err != nil { + return nil, fmt.Errorf("Invalid containerPort: %s", containerPort) + } + + var startHostPort, endHostPort uint64 = 0, 0 + if len(hostPort) > 0 { + startHostPort, endHostPort, err = ParsePortRange(hostPort) + if err != nil { + return nil, fmt.Errorf("Invalid hostPort: %s", hostPort) + } + } + + if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) { + // Allow host port range iff containerPort is not a range. + // In this case, use the host port range as the dynamic + // host port range to allocate into. + if endPort != startPort { + return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort) + } + } + + if !validateProto(strings.ToLower(proto)) { + return nil, fmt.Errorf("Invalid proto: %s", proto) + } + + ports := []PortMapping{} + for i := uint64(0); i <= (endPort - startPort); i++ { + containerPort = strconv.FormatUint(startPort+i, 10) + if len(hostPort) > 0 { + hostPort = strconv.FormatUint(startHostPort+i, 10) + } + // Set hostPort to a range only if there is a single container port + // and a dynamic host port. + if startPort == endPort && startHostPort != endHostPort { + hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10)) + } + port, err := NewPort(strings.ToLower(proto), containerPort) + if err != nil { + return nil, err + } + + binding := PortBinding{ + HostIP: ip, + HostPort: hostPort, + } + ports = append(ports, PortMapping{Port: port, Binding: binding}) + } + return ports, nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go new file mode 100644 index 000000000000..787d5ac2338e --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go @@ -0,0 +1,583 @@ +package nat + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParsePort(t *testing.T) { + var ( + p int + err error + ) + + p, err = ParsePort("1234") + + if err != nil || p != 1234 { + t.Fatal("Parsing '1234' did not succeed") + } + + // FIXME currently this is a valid port. I don't think it should be. + // I'm leaving this test commented out until we make a decision. + // - erikh + + /* + p, err = ParsePort("0123") + + if err != nil { + t.Fatal("Successfully parsed port '0123' to '123'") + } + */ + + p, err = ParsePort("asdf") + + if err == nil || p != 0 { + t.Fatal("Parsing port 'asdf' succeeded") + } + + p, err = ParsePort("1asdf") + + if err == nil || p != 0 { + t.Fatal("Parsing port '1asdf' succeeded") + } +} + +func TestParsePortRangeToInt(t *testing.T) { + var ( + begin int + end int + err error + ) + + type TestRange struct { + Range string + Begin int + End int + } + validRanges := []TestRange{ + {"1234", 1234, 1234}, + {"1234-1234", 1234, 1234}, + {"1234-1235", 1234, 1235}, + {"8000-9000", 8000, 9000}, + {"0", 0, 0}, + {"0-0", 0, 0}, + } + + for _, r := range validRanges { + begin, end, err = ParsePortRangeToInt(r.Range) + + if err != nil || begin != r.Begin { + t.Fatalf("Parsing port range '%s' did not succeed. Expected begin %d, got %d", r.Range, r.Begin, begin) + } + if err != nil || end != r.End { + t.Fatalf("Parsing port range '%s' did not succeed. Expected end %d, got %d", r.Range, r.End, end) + } + } + + invalidRanges := []string{ + "asdf", + "1asdf", + "9000-8000", + "9000-", + "-8000", + "-8000-", + } + + for _, r := range invalidRanges { + begin, end, err = ParsePortRangeToInt(r) + + if err == nil || begin != 0 || end != 0 { + t.Fatalf("Parsing port range '%s' succeeded", r) + } + } +} + +func TestPort(t *testing.T) { + p, err := NewPort("tcp", "1234") + + if err != nil { + t.Fatalf("tcp, 1234 had a parsing issue: %v", err) + } + + if string(p) != "1234/tcp" { + t.Fatal("tcp, 1234 did not result in the string 1234/tcp") + } + + if p.Proto() != "tcp" { + t.Fatal("protocol was not tcp") + } + + if p.Port() != "1234" { + t.Fatal("port string value was not 1234") + } + + if p.Int() != 1234 { + t.Fatal("port int value was not 1234") + } + + p, err = NewPort("tcp", "asd1234") + if err == nil { + t.Fatal("tcp, asd1234 was supposed to fail") + } + + p, err = NewPort("tcp", "1234-1230") + if err == nil { + t.Fatal("tcp, 1234-1230 was supposed to fail") + } + + p, err = NewPort("tcp", "1234-1242") + if err != nil { + t.Fatalf("tcp, 1234-1242 had a parsing issue: %v", err) + } + + if string(p) != "1234-1242/tcp" { + t.Fatal("tcp, 1234-1242 did not result in the string 1234-1242/tcp") + } +} + +func TestSplitProtoPort(t *testing.T) { + var ( + proto string + port string + ) + + proto, port = SplitProtoPort("1234/tcp") + + if proto != "tcp" || port != "1234" { + t.Fatal("Could not split 1234/tcp properly") + } + + proto, port = SplitProtoPort("") + + if proto != "" || port != "" { + t.Fatal("parsing an empty string yielded surprising results", proto, port) + } + + proto, port = SplitProtoPort("1234") + + if proto != "tcp" || port != "1234" { + t.Fatal("tcp is not the default protocol for portspec '1234'", proto, port) + } + + proto, port = SplitProtoPort("1234/") + + if proto != "tcp" || port != "1234" { + t.Fatal("parsing '1234/' yielded:" + port + "/" + proto) + } + + proto, port = SplitProtoPort("/tcp") + + if proto != "" || port != "" { + t.Fatal("parsing '/tcp' yielded:" + port + "/" + proto) + } +} + +func TestParsePortSpecFull(t *testing.T) { + portMappings, err := ParsePortSpec("0.0.0.0:1234-1235:3333-3334/tcp") + assert.Nil(t, err) + + expected := []PortMapping{ + { + Port: "3333/tcp", + Binding: PortBinding{ + HostIP: "0.0.0.0", + HostPort: "1234", + }, + }, + { + Port: "3334/tcp", + Binding: PortBinding{ + HostIP: "0.0.0.0", + HostPort: "1235", + }, + }, + } + + assert.Equal(t, expected, portMappings) +} + +func TestPartPortSpecIPV6(t *testing.T) { + portMappings, err := ParsePortSpec("[2001:4860:0:2001::68]::333") + assert.Nil(t, err) + + expected := []PortMapping{ + { + Port: "333/tcp", + Binding: PortBinding{ + HostIP: "2001:4860:0:2001::68", + HostPort: "", + }, + }, + } + assert.Equal(t, expected, portMappings) +} + +func TestPartPortSpecIPV6WithHostPort(t *testing.T) { + portMappings, err := ParsePortSpec("[::1]:80:80") + assert.Nil(t, err) + + expected := []PortMapping{ + { + Port: "80/tcp", + Binding: PortBinding{ + HostIP: "::1", + HostPort: "80", + }, + }, + } + assert.Equal(t, expected, portMappings) +} + +func TestParsePortSpecs(t *testing.T) { + var ( + portMap map[Port]struct{} + bindingMap map[Port][]PortBinding + err error + ) + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234/tcp", "2345/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1234/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2345/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != "" { + t.Fatalf("HostPort should not be set for %s", portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234:1234/tcp", "2345:2345/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1234/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2345/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != port { + t.Fatalf("HostPort should be %s for %s", port, portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234:1234/tcp", "0.0.0.0:2345:2345/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1234/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2345/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "0.0.0.0" { + t.Fatalf("HostIP is not 0.0.0.0 for %s", portspec) + } + + if bindings[0].HostPort != port { + t.Fatalf("HostPort should be %s for %s", port, portspec) + } + } + + _, _, err = ParsePortSpecs([]string{"localhost:1234:1234/tcp"}) + + if err == nil { + t.Fatal("Received no error while trying to parse a hostname instead of ip") + } +} + +func TestParsePortSpecsWithRange(t *testing.T) { + var ( + portMap map[Port]struct{} + bindingMap map[Port][]PortBinding + err error + ) + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236/tcp", "2345-2347/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1235/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2346/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != "" { + t.Fatalf("HostPort should not be set for %s", portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236:1234-1236/tcp", "2345-2347:2345-2347/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1235/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2346/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != port { + t.Fatalf("HostPort should be %s for %s", port, portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234-1236:1234-1236/tcp", "0.0.0.0:2345-2347:2345-2347/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1235/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2346/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + if len(bindings) != 1 || bindings[0].HostIP != "0.0.0.0" || bindings[0].HostPort != port { + t.Fatalf("Expect single binding to port %s but found %s", port, bindings) + } + } + + _, _, err = ParsePortSpecs([]string{"localhost:1234-1236:1234-1236/tcp"}) + + if err == nil { + t.Fatal("Received no error while trying to parse a hostname instead of ip") + } +} + +func TestParseNetworkOptsPrivateOnly(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::80"}) + if err != nil { + t.Fatal(err) + } + if len(ports) != 1 { + t.Logf("Expected 1 got %d", len(ports)) + t.FailNow() + } + if len(bindings) != 1 { + t.Logf("Expected 1 got %d", len(bindings)) + t.FailNow() + } + for k := range ports { + if k.Proto() != "tcp" { + t.Logf("Expected tcp got %s", k.Proto()) + t.Fail() + } + if k.Port() != "80" { + t.Logf("Expected 80 got %s", k.Port()) + t.Fail() + } + b, exists := bindings[k] + if !exists { + t.Log("Binding does not exist") + t.FailNow() + } + if len(b) != 1 { + t.Logf("Expected 1 got %d", len(b)) + t.FailNow() + } + s := b[0] + if s.HostPort != "" { + t.Logf("Expected \"\" got %s", s.HostPort) + t.Fail() + } + if s.HostIP != "192.168.1.100" { + t.Fail() + } + } +} + +func TestParseNetworkOptsPublic(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:8080:80"}) + if err != nil { + t.Fatal(err) + } + if len(ports) != 1 { + t.Logf("Expected 1 got %d", len(ports)) + t.FailNow() + } + if len(bindings) != 1 { + t.Logf("Expected 1 got %d", len(bindings)) + t.FailNow() + } + for k := range ports { + if k.Proto() != "tcp" { + t.Logf("Expected tcp got %s", k.Proto()) + t.Fail() + } + if k.Port() != "80" { + t.Logf("Expected 80 got %s", k.Port()) + t.Fail() + } + b, exists := bindings[k] + if !exists { + t.Log("Binding does not exist") + t.FailNow() + } + if len(b) != 1 { + t.Logf("Expected 1 got %d", len(b)) + t.FailNow() + } + s := b[0] + if s.HostPort != "8080" { + t.Logf("Expected 8080 got %s", s.HostPort) + t.Fail() + } + if s.HostIP != "192.168.1.100" { + t.Fail() + } + } +} + +func TestParseNetworkOptsPublicNoPort(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100"}) + + if err == nil { + t.Logf("Expected error Invalid containerPort") + t.Fail() + } + if ports != nil { + t.Logf("Expected nil got %s", ports) + t.Fail() + } + if bindings != nil { + t.Logf("Expected nil got %s", bindings) + t.Fail() + } +} + +func TestParseNetworkOptsNegativePorts(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:-1:-1"}) + + if err == nil { + t.Fail() + } + if len(ports) != 0 { + t.Logf("Expected nil got %d", len(ports)) + t.Fail() + } + if len(bindings) != 0 { + t.Logf("Expected 0 got %d", len(bindings)) + t.Fail() + } +} + +func TestParseNetworkOptsUdp(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::6000/udp"}) + if err != nil { + t.Fatal(err) + } + if len(ports) != 1 { + t.Logf("Expected 1 got %d", len(ports)) + t.FailNow() + } + if len(bindings) != 1 { + t.Logf("Expected 1 got %d", len(bindings)) + t.FailNow() + } + for k := range ports { + if k.Proto() != "udp" { + t.Logf("Expected udp got %s", k.Proto()) + t.Fail() + } + if k.Port() != "6000" { + t.Logf("Expected 6000 got %s", k.Port()) + t.Fail() + } + b, exists := bindings[k] + if !exists { + t.Log("Binding does not exist") + t.FailNow() + } + if len(b) != 1 { + t.Logf("Expected 1 got %d", len(b)) + t.FailNow() + } + s := b[0] + if s.HostPort != "" { + t.Logf("Expected \"\" got %s", s.HostPort) + t.Fail() + } + if s.HostIP != "192.168.1.100" { + t.Fail() + } + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go new file mode 100644 index 000000000000..892adf8c6673 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go @@ -0,0 +1,57 @@ +package nat + +import ( + "fmt" + "strconv" + "strings" +) + +// PartParser parses and validates the specified string (data) using the specified template +// e.g. ip:public:private -> 192.168.0.1:80:8000 +// DEPRECATED: do not use, this function may be removed in a future version +func PartParser(template, data string) (map[string]string, error) { + // ip:public:private + var ( + templateParts = strings.Split(template, ":") + parts = strings.Split(data, ":") + out = make(map[string]string, len(templateParts)) + ) + if len(parts) != len(templateParts) { + return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template) + } + + for i, t := range templateParts { + value := "" + if len(parts) > i { + value = parts[i] + } + out[t] = value + } + return out, nil +} + +// ParsePortRange parses and validates the specified string as a port-range (8000-9000) +func ParsePortRange(ports string) (uint64, uint64, error) { + if ports == "" { + return 0, 0, fmt.Errorf("Empty string specified for ports.") + } + if !strings.Contains(ports, "-") { + start, err := strconv.ParseUint(ports, 10, 16) + end := start + return start, end, err + } + + parts := strings.Split(ports, "-") + start, err := strconv.ParseUint(parts[0], 10, 16) + if err != nil { + return 0, 0, err + } + end, err := strconv.ParseUint(parts[1], 10, 16) + if err != nil { + return 0, 0, err + } + if end < start { + return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports) + } + return start, end, nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go new file mode 100644 index 000000000000..2ac204a05bfd --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go @@ -0,0 +1,54 @@ +package nat + +import ( + "strings" + "testing" +) + +func TestParsePortRange(t *testing.T) { + if start, end, err := ParsePortRange("8000-8080"); err != nil || start != 8000 || end != 8080 { + t.Fatalf("Error: %s or Expecting {start,end} values {8000,8080} but found {%d,%d}.", err, start, end) + } +} + +func TestParsePortRangeEmpty(t *testing.T) { + if _, _, err := ParsePortRange(""); err == nil || err.Error() != "Empty string specified for ports." { + t.Fatalf("Expected error 'Empty string specified for ports.', got %v", err) + } +} + +func TestParsePortRangeWithNoRange(t *testing.T) { + start, end, err := ParsePortRange("8080") + if err != nil { + t.Fatal(err) + } + if start != 8080 || end != 8080 { + t.Fatalf("Expected start and end to be the same and equal to 8080, but were %v and %v", start, end) + } +} + +func TestParsePortRangeIncorrectRange(t *testing.T) { + if _, _, err := ParsePortRange("9000-8080"); err == nil || !strings.Contains(err.Error(), "Invalid range specified for the Port") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } +} + +func TestParsePortRangeIncorrectEndRange(t *testing.T) { + if _, _, err := ParsePortRange("8000-a"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } + + if _, _, err := ParsePortRange("8000-30a"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } +} + +func TestParsePortRangeIncorrectStartRange(t *testing.T) { + if _, _, err := ParsePortRange("a-8000"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } + + if _, _, err := ParsePortRange("30a-8000"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go new file mode 100644 index 000000000000..ce950171e315 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go @@ -0,0 +1,96 @@ +package nat + +import ( + "sort" + "strings" +) + +type portSorter struct { + ports []Port + by func(i, j Port) bool +} + +func (s *portSorter) Len() int { + return len(s.ports) +} + +func (s *portSorter) Swap(i, j int) { + s.ports[i], s.ports[j] = s.ports[j], s.ports[i] +} + +func (s *portSorter) Less(i, j int) bool { + ip := s.ports[i] + jp := s.ports[j] + + return s.by(ip, jp) +} + +// Sort sorts a list of ports using the provided predicate +// This function should compare `i` and `j`, returning true if `i` is +// considered to be less than `j` +func Sort(ports []Port, predicate func(i, j Port) bool) { + s := &portSorter{ports, predicate} + sort.Sort(s) +} + +type portMapEntry struct { + port Port + binding PortBinding +} + +type portMapSorter []portMapEntry + +func (s portMapSorter) Len() int { return len(s) } +func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// sort the port so that the order is: +// 1. port with larger specified bindings +// 2. larger port +// 3. port with tcp protocol +func (s portMapSorter) Less(i, j int) bool { + pi, pj := s[i].port, s[j].port + hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort) + return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp") +} + +// SortPortMap sorts the list of ports and their respected mapping. The ports +// will explicit HostPort will be placed first. +func SortPortMap(ports []Port, bindings PortMap) { + s := portMapSorter{} + for _, p := range ports { + if binding, ok := bindings[p]; ok { + for _, b := range binding { + s = append(s, portMapEntry{port: p, binding: b}) + } + bindings[p] = []PortBinding{} + } else { + s = append(s, portMapEntry{port: p}) + } + } + + sort.Sort(s) + var ( + i int + pm = make(map[Port]struct{}) + ) + // reorder ports + for _, entry := range s { + if _, ok := pm[entry.port]; !ok { + ports[i] = entry.port + pm[entry.port] = struct{}{} + i++ + } + // reorder bindings for this port + if _, ok := bindings[entry.port]; ok { + bindings[entry.port] = append(bindings[entry.port], entry.binding) + } + } +} + +func toInt(s string) uint64 { + i, _, err := ParsePortRange(s) + if err != nil { + i = 0 + } + return i +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go new file mode 100644 index 000000000000..88ed911156a8 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go @@ -0,0 +1,85 @@ +package nat + +import ( + "fmt" + "reflect" + "testing" +) + +func TestSortUniquePorts(t *testing.T) { + ports := []Port{ + Port("6379/tcp"), + Port("22/tcp"), + } + + Sort(ports, func(ip, jp Port) bool { + return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp") + }) + + first := ports[0] + if fmt.Sprint(first) != "22/tcp" { + t.Log(fmt.Sprint(first)) + t.Fail() + } +} + +func TestSortSamePortWithDifferentProto(t *testing.T) { + ports := []Port{ + Port("8888/tcp"), + Port("8888/udp"), + Port("6379/tcp"), + Port("6379/udp"), + } + + Sort(ports, func(ip, jp Port) bool { + return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp") + }) + + first := ports[0] + if fmt.Sprint(first) != "6379/tcp" { + t.Fail() + } +} + +func TestSortPortMap(t *testing.T) { + ports := []Port{ + Port("22/tcp"), + Port("22/udp"), + Port("8000/tcp"), + Port("6379/tcp"), + Port("9999/tcp"), + } + + portMap := PortMap{ + Port("22/tcp"): []PortBinding{ + {}, + }, + Port("8000/tcp"): []PortBinding{ + {}, + }, + Port("6379/tcp"): []PortBinding{ + {}, + {HostIP: "0.0.0.0", HostPort: "32749"}, + }, + Port("9999/tcp"): []PortBinding{ + {HostIP: "0.0.0.0", HostPort: "40000"}, + }, + } + + SortPortMap(ports, portMap) + if !reflect.DeepEqual(ports, []Port{ + Port("9999/tcp"), + Port("6379/tcp"), + Port("8000/tcp"), + Port("22/tcp"), + Port("22/udp"), + }) { + t.Errorf("failed to prioritize port with explicit mappings, got %v", ports) + } + if pm := portMap[Port("6379/tcp")]; !reflect.DeepEqual(pm, []PortBinding{ + {HostIP: "0.0.0.0", HostPort: "32749"}, + {}, + }) { + t.Errorf("failed to prioritize bindings with explicit mappings, got %v", pm) + } +} From bebac8f47fb567fcc0dbbfe43aa3dceb644b20bd Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Wed, 11 Jan 2017 17:09:53 +0100 Subject: [PATCH 05/27] Add docker service metricset --- metricbeat/_meta/beat.full.yml | 2 +- metricbeat/docs/fields.asciidoc | 110 ++++++++++++++++++ metricbeat/docs/modules/docker.asciidoc | 6 +- .../docs/modules/docker/service.asciidoc | 19 +++ metricbeat/include/list.go | 1 + metricbeat/metricbeat.full.yml | 3 +- metricbeat/metricbeat.template-es2x.json | 56 +++++++++ metricbeat/metricbeat.template.json | 49 ++++++++ metricbeat/module/docker/_meta/config.yml | 2 +- metricbeat/module/docker/container/data.go | 8 +- metricbeat/module/docker/node/data.go | 6 +- metricbeat/module/docker/node/node.go | 4 +- .../module/docker/service/_meta/data.json | 30 +++++ .../module/docker/service/_meta/docs.asciidoc | 4 + .../module/docker/service/_meta/fields.yml | 59 ++++++++++ metricbeat/module/docker/service/data.go | 80 +++++++++++++ metricbeat/module/docker/service/service.go | 53 +++++++++ .../service/service_integration_test.go | 25 ++++ .../fsouza/go-dockerclient/service.go | 81 ------------- 19 files changed, 505 insertions(+), 93 deletions(-) create mode 100644 metricbeat/docs/modules/docker/service.asciidoc create mode 100644 metricbeat/module/docker/service/_meta/data.json create mode 100644 metricbeat/module/docker/service/_meta/docs.asciidoc create mode 100644 metricbeat/module/docker/service/_meta/fields.yml create mode 100644 metricbeat/module/docker/service/data.go create mode 100644 metricbeat/module/docker/service/service.go create mode 100644 metricbeat/module/docker/service/service_integration_test.go diff --git a/metricbeat/_meta/beat.full.yml b/metricbeat/_meta/beat.full.yml index 586eb4c81df5..92d4dc428108 100644 --- a/metricbeat/_meta/beat.full.yml +++ b/metricbeat/_meta/beat.full.yml @@ -99,7 +99,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index f414e7247677..f30de4a2ead2 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1640,6 +1640,116 @@ type: keyword docker manager listenning addr +[float] +== service Fields + +Docker service metrics. + + + +[float] +=== docker.service.id + +type: keyword + +service id + + +[float] +=== docker.service.createdat + +type: date + +date where the service has been created + + +[float] +=== docker.service.name + +type: keyword + +service name + + +[float] +=== docker.service.updatedad + +type: date + +last service specification change date + + +[float] +=== docker.service.mode + +type: keyword + +Service mode (replicated or global) + + +[float] +=== docker.service.replicas + +type: integer + +number of replicas if service mode is replicated + + +[float] +=== docker.service.healtcheck_enabled + +type: boolean + +check if healthcheck is activated in container specifications + + +[float] +=== docker.service.version + +type: integer + +service update versionning + + +[float] +== updatestatus Fields + +check update status + + + +[float] +=== docker.service.updatestatus.state + +type: keyword + +update state + + +[float] +=== docker.service.updatestatus.startedat + +type: date + +update started date + + +[float] +=== docker.service.updatestatus.completedat + +type: date + +update completed date + + +[float] +=== docker.service.updatestatus.message + +type: text + +update message + + [[exported-fields-haproxy]] == haproxy Fields diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index a50007adc8b9..6a27ca8f4bdf 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -21,7 +21,7 @@ in <>. Here is an example configuration: ---- metricbeat.modules: #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -52,6 +52,8 @@ The following metricsets are available: * <> +* <> + include::docker/container.asciidoc[] include::docker/cpu.asciidoc[] @@ -66,3 +68,5 @@ include::docker/network.asciidoc[] include::docker/node.asciidoc[] +include::docker/service.asciidoc[] + diff --git a/metricbeat/docs/modules/docker/service.asciidoc b/metricbeat/docs/modules/docker/service.asciidoc new file mode 100644 index 000000000000..05af931e7b64 --- /dev/null +++ b/metricbeat/docs/modules/docker/service.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-docker-service]] +include::../../../module/docker/service/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/docker/service/_meta/data.json[] +---- diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 960b2e9a3135..78d4f70d741e 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -22,6 +22,7 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" _ "github.com/elastic/beats/metricbeat/module/docker/node" + _ "github.com/elastic/beats/metricbeat/module/docker/service" _ "github.com/elastic/beats/metricbeat/module/haproxy" _ "github.com/elastic/beats/metricbeat/module/haproxy/info" _ "github.com/elastic/beats/metricbeat/module/haproxy/stat" diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index fa74f1316ec8..0c4fd3d80102 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -99,7 +99,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -862,3 +862,4 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 + diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index 2fc3f519381d..47e24f9206f2 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -894,6 +894,62 @@ "type": "date" } } + }, + "service": { + "properties": { + "createdat": { + "type": "date" + }, + "healtcheck_enabled": { + "type": "boolean" + }, + "id": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "mode": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "name": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "replicas": { + "type": "long" + }, + "updatedad": { + "type": "date" + }, + "updatestatus": { + "properties": { + "completedat": { + "type": "date" + }, + "message": { + "index": "analyzed", + "norms": { + "enabled": false + }, + "type": "string" + }, + "startedat": { + "type": "date" + }, + "state": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "version": { + "type": "long" + } + } } } }, diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index 1f254fddd61b..ad1294db6044 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -889,6 +889,55 @@ "type": "date" } } + }, + "service": { + "properties": { + "createdat": { + "type": "date" + }, + "healtcheck_enabled": { + "type": "boolean" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "replicas": { + "type": "long" + }, + "updatedad": { + "type": "date" + }, + "updatestatus": { + "properties": { + "completedat": { + "type": "date" + }, + "message": { + "norms": false, + "type": "text" + }, + "startedat": { + "type": "date" + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "type": "long" + } + } } } }, diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index 745c6c91e590..ba7bc2f041e0 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -1,5 +1,5 @@ #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 0ead59a039fa..0a848ec55c93 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -32,10 +32,11 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "status": cont.Status, } - if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - container, _ := m.dockerClient.InspectContainer(cont.ID) - last_event := len(container.State.Health.Log)-1 +if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log)-1 + if last_event >= 0 { health := common.MapStr{ "status": container.State.Health.Status, "failingstreak": container.State.Health.FailingStreak, @@ -46,6 +47,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { } event["health"] = health } +} labels := docker.DeDotLabels(cont.Labels) diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go index a6718242084d..e1b5e9205186 100644 --- a/metricbeat/module/docker/node/data.go +++ b/metricbeat/module/docker/node/data.go @@ -7,17 +7,17 @@ import ( "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" ) -func eventsMapping(nodesList []swarm.Node, m *MetricSet) []common.MapStr { +func eventsMapping(nodesList []swarm.Node) []common.MapStr { myEvents := []common.MapStr{} for _, node := range nodesList { - myEvents = append(myEvents, eventMapping(&node, m)) + myEvents = append(myEvents, eventMapping(&node)) } return myEvents } -func eventMapping(node *swarm.Node, m *MetricSet) common.MapStr { +func eventMapping(node *swarm.Node) common.MapStr { event := common.MapStr{ "createdat": node.Meta.CreatedAt, "updatedat": node.Meta.UpdatedAt, diff --git a/metricbeat/module/docker/node/node.go b/metricbeat/module/docker/node/node.go index 6381c53b6364..40799a15ec0b 100644 --- a/metricbeat/module/docker/node/node.go +++ b/metricbeat/module/docker/node/node.go @@ -41,7 +41,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { } // Fetch returns a list of all containers as events. -// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-nodes. func (m *MetricSet) Fetch() ([]common.MapStr, error) { // Fetch a list of all nodes. nodes, err := m.dockerClient.ListNodes(dc.ListNodesOptions{}) @@ -49,5 +49,5 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { return nil, err } - return eventsMapping(nodes, m), nil + return eventsMapping(nodes), nil } diff --git a/metricbeat/module/docker/service/_meta/data.json b/metricbeat/module/docker/service/_meta/data.json new file mode 100644 index 000000000000..d7d27ffe8f88 --- /dev/null +++ b/metricbeat/module/docker/service/_meta/data.json @@ -0,0 +1,30 @@ +{ + "@timestamp": "2017-01-11T15:45:19.162Z", + "beat": { + "hostname": "smusso-ThinkPad", + "name": "smusso-ThinkPad", + "version": "6.0.0-alpha1" + }, + "docker": { + "service": { + "Replicas": 2, + "createdat": "2017-01-11T11:35:53.432238684Z", + "healtcheck_enabled": true, + "id": "1vyemp33ktfmk7xpfmlg29ns0", + "labels": { + "label1": "thisisatest" + }, + "mode": "Replicated", + "name": "elasticsearch", + "updatedat": "2017-01-11T15:45:03.726977327Z", + "version": 905 + } + }, + "metricset": { + "host": "/var/run/docker.sock", + "module": "docker", + "name": "service", + "rtt": 3967 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/docker/service/_meta/docs.asciidoc b/metricbeat/module/docker/service/_meta/docs.asciidoc new file mode 100644 index 000000000000..1d1858fabb24 --- /dev/null +++ b/metricbeat/module/docker/service/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +=== Docker Service Metricset + +The Docker Swarm `service` metricset collects information and statistics about +running services in Docker cluster. diff --git a/metricbeat/module/docker/service/_meta/fields.yml b/metricbeat/module/docker/service/_meta/fields.yml new file mode 100644 index 000000000000..4d16dcc426bc --- /dev/null +++ b/metricbeat/module/docker/service/_meta/fields.yml @@ -0,0 +1,59 @@ +- name: service + type: group + description: > + Docker service metrics. + fields: + + - name: id + type: keyword + description: > + service id + - name: createdat + type: date + description: > + date where the service has been created + - name: name + type: keyword + description: > + service name + - name: updatedad + type: date + description: > + last service specification change date + - name: mode + type: keyword + description: > + Service mode (replicated or global) + - name: replicas + type: integer + description: > + number of replicas if service mode is replicated + - name: healtcheck_enabled + type: boolean + description: > + check if healthcheck is activated in container specifications + - name: version + type: integer + description: > + service update versionning + - name: updatestatus + type: group + description: > + check update status + fields: + - name: "state" + type: keyword + description: > + update state + - name: "startedat" + type: date + description: > + update started date + - name: "completedat" + type: date + description: > + update completed date + - name: "message" + type: "text" + description: > + update message diff --git a/metricbeat/module/docker/service/data.go b/metricbeat/module/docker/service/data.go new file mode 100644 index 000000000000..3604fccdeeb5 --- /dev/null +++ b/metricbeat/module/docker/service/data.go @@ -0,0 +1,80 @@ +package service + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/module/docker" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" + "reflect" +) + +func eventsMapping(serviceList []swarm.Service) []common.MapStr { + myEvents := []common.MapStr{} + + for _, service := range serviceList { + myEvents = append(myEvents, eventMapping(&service)) + } + + return myEvents +} + +func eventMapping(service *swarm.Service) common.MapStr { + + event := common.MapStr{ + "id": service.ID, + "version": service.Meta.Version.Index, + "createdat": service.Meta.CreatedAt, + "updatedat": service.Meta.UpdatedAt, + "name": service.Spec.Annotations.Name, + } + + if service.UpdateStatus.Message != "" { + updatestatus := common.MapStr{ + "state": service.UpdateStatus.State, + "startedat": service.UpdateStatus.StartedAt, + "completedat": service.UpdateStatus.CompletedAt, + "message": service.UpdateStatus.Message, + } + event["updatestatus"] = updatestatus + } + + if service.Spec.Mode.Replicated != nil { + event["mode"] = "Replicated" + event["replicas"] = service.Spec.Mode.Replicated.Replicas + } else { + event["mode"] = "Global" + } + + previousspec_labels := common.MapStr{} + spec_labels := common.MapStr{} + + if service.PreviousSpec != nil && service.PreviousSpec.Annotations.Labels != nil { + previousspec_labels = docker.DeDotLabels(service.PreviousSpec.Annotations.Labels) + } + + if service.Spec.Annotations.Labels != nil { + spec_labels = docker.DeDotLabels(service.Spec.Annotations.Labels) + } + + if len(spec_labels) != 0 || len(previousspec_labels) != 0 { + if len(spec_labels) != 0 && len(previousspec_labels) != 0 { + if reflect.DeepEqual(spec_labels, previousspec_labels) { + event["labels"] = spec_labels + } else { + event["previousspec.labels"] = previousspec_labels + event["labels"] = spec_labels + } + } else if len(spec_labels) == 0 && len(previousspec_labels) != 0 { + event["previousspec.labels"] = previousspec_labels + } else { + event["labels"] = spec_labels + } + } + + if service.Spec.TaskTemplate.ContainerSpec.Healthcheck != nil { + event["healtcheck_enabled"] = true + } else { + event["healtcheck_enabled"] = false + } + + return event +} diff --git a/metricbeat/module/docker/service/service.go b/metricbeat/module/docker/service/service.go new file mode 100644 index 000000000000..f43389348bef --- /dev/null +++ b/metricbeat/module/docker/service/service.go @@ -0,0 +1,53 @@ +package service + +import ( + dc "github.com/fsouza/go-dockerclient" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" +) + +func init() { + if err := mb.Registry.AddMetricSet("docker", "service", New, docker.HostParser); err != nil { + panic(err) + } +} + +type MetricSet struct { + mb.BaseMetricSet + dockerClient *dc.Client +} + +// New creates a new instance of the docker services MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("EXPERIMENTAL: The docker service metricset is experimental") + + config := docker.Config{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + client, err := docker.NewDockerClient(base.HostData().URI, config) + if err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + dockerClient: client, + }, nil +} + +// Fetch returns a list of all services as events. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-services. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + // Fetch a list of all services. + services, err := m.dockerClient.ListServices(dc.ListServicesOptions{}) + if err != nil { + return nil, err + } + + return eventsMapping(services), nil +} diff --git a/metricbeat/module/docker/service/service_integration_test.go b/metricbeat/module/docker/service/service_integration_test.go new file mode 100644 index 000000000000..e3a5a5369a7e --- /dev/null +++ b/metricbeat/module/docker/service/service_integration_test.go @@ -0,0 +1,25 @@ +// +build integration + +package service + +import ( + "testing" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "docker", + "metricsets": []string{"service"}, + "hosts": []string{"unix:///var/run/docker.sock"}, + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go index 18beb008c5a2..7ace1a366b24 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go @@ -7,8 +7,6 @@ package docker import ( "encoding/json" "net/http" - "net/url" - "strconv" "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" ) @@ -26,85 +24,6 @@ func (err *NoSuchService) Error() string { return "No such service: " + err.ID } -// CreateServiceOptions specify parameters to the CreateService function. -// -// See https://goo.gl/KrVjHz for more details. -type CreateServiceOptions struct { - swarm.ServiceSpec -} - -// CreateService creates a new service, returning the service instance -// or an error in case of failure. -// -// See https://goo.gl/KrVjHz for more details. -func (c *Client) CreateService(opts CreateServiceOptions) (*swarm.Service, error) { - path := "/services/create?" + queryString(opts) - resp, err := c.do("POST", path, doOptions{ - data: opts.ServiceSpec, - forceJSON: true, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var service swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { - return nil, err - } - return &service, nil -} - -// RemoveServiceOptions encapsulates options to remove a service. -// -// See https://goo.gl/Tqrtya for more details. -type RemoveServiceOptions struct { - ID string `qs:"-"` -} - -// RemoveService removes a service, returning an error in case of failure. -// -// See https://goo.gl/Tqrtya for more details. -func (c *Client) RemoveService(opts RemoveServiceOptions) error { - path := "/services/" + opts.ID - resp, err := c.do("DELETE", path, doOptions{}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchService{ID: opts.ID} - } - return err - } - resp.Body.Close() - return nil -} - -// UpdateServiceOptions specify parameters to the UpdateService function. -// -// See https://goo.gl/wu3MmS for more details. -type UpdateServiceOptions struct { - swarm.ServiceSpec - Version uint64 -} - -// UpdateService updates the service at ID with the options -// -// See https://goo.gl/wu3MmS for more details. -func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - resp, err := c.do("POST", "/services/"+id+"/update?"+params.Encode(), doOptions{ - data: opts.ServiceSpec, - forceJSON: true, - }) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchService{ID: id} - } - return err - } - defer resp.Body.Close() - return nil -} - // InspectService returns information about a service by its ID. // // See https://goo.gl/dHmr75 for more details. From 1009222781fc41f3dae13baadc77fe9ee5f155f6 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Wed, 11 Jan 2017 19:07:57 +0100 Subject: [PATCH 06/27] Fix service index mapping and add comment --- metricbeat/module/docker/container/data.go | 1 + metricbeat/module/docker/service/_meta/data.json | 2 +- metricbeat/module/docker/service/data.go | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 0a848ec55c93..ea6dd77f6356 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -32,6 +32,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "status": cont.Status, } +// Check id container have health metrics configured if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { container, _ := m.dockerClient.InspectContainer(cont.ID) diff --git a/metricbeat/module/docker/service/_meta/data.json b/metricbeat/module/docker/service/_meta/data.json index d7d27ffe8f88..14dcbe4bc927 100644 --- a/metricbeat/module/docker/service/_meta/data.json +++ b/metricbeat/module/docker/service/_meta/data.json @@ -7,7 +7,7 @@ }, "docker": { "service": { - "Replicas": 2, + "replicas": 2, "createdat": "2017-01-11T11:35:53.432238684Z", "healtcheck_enabled": true, "id": "1vyemp33ktfmk7xpfmlg29ns0", diff --git a/metricbeat/module/docker/service/data.go b/metricbeat/module/docker/service/data.go index 3604fccdeeb5..fa2445ce2974 100644 --- a/metricbeat/module/docker/service/data.go +++ b/metricbeat/module/docker/service/data.go @@ -27,6 +27,7 @@ func eventMapping(service *swarm.Service) common.MapStr { "name": service.Spec.Annotations.Name, } + // Do not insert updatestatus map if no updatestatus is present if service.UpdateStatus.Message != "" { updatestatus := common.MapStr{ "state": service.UpdateStatus.State, @@ -37,6 +38,7 @@ func eventMapping(service *swarm.Service) common.MapStr { event["updatestatus"] = updatestatus } + // Check service mode if service.Spec.Mode.Replicated != nil { event["mode"] = "Replicated" event["replicas"] = service.Spec.Mode.Replicated.Replicas @@ -55,6 +57,7 @@ func eventMapping(service *swarm.Service) common.MapStr { spec_labels = docker.DeDotLabels(service.Spec.Annotations.Labels) } + // Print previous label only if they have been modify if len(spec_labels) != 0 || len(previousspec_labels) != 0 { if len(spec_labels) != 0 && len(previousspec_labels) != 0 { if reflect.DeepEqual(spec_labels, previousspec_labels) { From b95e76a4b445571c20da597a7554403d0a9478ec Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:36:04 +0100 Subject: [PATCH 07/27] add healthcheck metricset in docker module --- metricbeat/_meta/beat.full.yml | 2 +- metricbeat/docs/fields.asciidoc | 389 +++--------------- metricbeat/docs/modules/docker.asciidoc | 14 +- metricbeat/docs/modules/docker/node.asciidoc | 19 - .../docs/modules/docker/service.asciidoc | 19 - metricbeat/include/list.go | 3 +- metricbeat/metricbeat.full.yml | 10 +- metricbeat/metricbeat.template-es2x.json | 203 ++------- metricbeat/metricbeat.template.json | 181 ++------ metricbeat/module/docker/_meta/config.yml | 2 +- .../module/docker/container/_meta/data.json | 8 - .../module/docker/container/_meta/fields.yml | 21 - .../module/docker/container/container.go | 2 +- metricbeat/module/docker/container/data.go | 25 +- metricbeat/module/docker/glide.yaml | 10 +- metricbeat/module/docker/node/_meta/data.json | 54 --- .../module/docker/node/_meta/docs.asciidoc | 4 - .../module/docker/node/_meta/fields.yml | 104 ----- metricbeat/module/docker/node/data.go | 65 --- metricbeat/module/docker/node/node.go | 53 --- .../docker/node/node_integration_test.go | 25 -- .../module/docker/service/_meta/data.json | 30 -- .../module/docker/service/_meta/docs.asciidoc | 4 - .../module/docker/service/_meta/fields.yml | 59 --- metricbeat/module/docker/service/data.go | 83 ---- metricbeat/module/docker/service/service.go | 53 --- .../service/service_integration_test.go | 25 -- 27 files changed, 131 insertions(+), 1336 deletions(-) delete mode 100644 metricbeat/docs/modules/docker/node.asciidoc delete mode 100644 metricbeat/docs/modules/docker/service.asciidoc delete mode 100644 metricbeat/module/docker/node/_meta/data.json delete mode 100644 metricbeat/module/docker/node/_meta/docs.asciidoc delete mode 100644 metricbeat/module/docker/node/_meta/fields.yml delete mode 100644 metricbeat/module/docker/node/data.go delete mode 100644 metricbeat/module/docker/node/node.go delete mode 100644 metricbeat/module/docker/node/node_integration_test.go delete mode 100644 metricbeat/module/docker/service/_meta/data.json delete mode 100644 metricbeat/module/docker/service/_meta/docs.asciidoc delete mode 100644 metricbeat/module/docker/service/_meta/fields.yml delete mode 100644 metricbeat/module/docker/service/data.go delete mode 100644 metricbeat/module/docker/service/service.go delete mode 100644 metricbeat/module/docker/service/service_integration_test.go diff --git a/metricbeat/_meta/beat.full.yml b/metricbeat/_meta/beat.full.yml index 92d4dc428108..05fc3d3d9dec 100644 --- a/metricbeat/_meta/beat.full.yml +++ b/metricbeat/_meta/beat.full.yml @@ -99,7 +99,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index f30de4a2ead2..4366557204fd 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1071,45 +1071,6 @@ type: long Size of the files that have been created or changed since creation. -[float] -== health Fields - -Container health metrics. - - - -[float] -=== docker.container.health.event_end_date - -type: date - -Healthcheck end date - - -[float] -=== docker.container.health.event_start_date - -type: date - -Healthcheck start date - - -[float] -=== docker.container.health.event_output - -type: keyword - -Healthcheck output - - -[float] -=== docker.container.health.event_exit_code - -type: integer - -Healthcheck status code - - [float] == cpu Fields @@ -1210,6 +1171,61 @@ type: scaled_float Number of reads and writes combined. +[float] +== healthcheck Fields + +Docker container metrics. + + + +[float] +=== docker.healthcheck.event_end_date + +type: date + +Healthcheck end date + + +[float] +=== docker.healthcheck.event_start_date + +type: date + +Healthcheck start date + + +[float] +=== docker.healthcheck.event_output + +type: keyword + +Healthcheck output + + +[float] +=== docker.healthcheck.event_exit_code + +type: integer + +Healthcheck status code + + +[float] +=== docker.healthcheck.failingstreak + +type: integer + +concurent failed check + + +[float] +=== docker.healthcheck.status + +type: keyword + +Healthcheck status code + + [float] == info Fields @@ -1455,301 +1471,6 @@ type: long Total number of outgoing packets. -[float] -== node Fields - -Docker node metrics. - - - -[float] -=== docker.node.createdat - -type: date - -date where the node has been added to the cluster - - -[float] -=== docker.node.updatedad - -type: date - -last gossip message - - -[float] -=== docker.node.id - -type: keyword - -Unique node id. - - -[float] -=== docker.node.hostname - -type: keyword - -hostname of the node - - -[float] -== spec Fields - -Configured status - - - -[float] -=== docker.node.spec.role - -type: keyword - -Wanted role - - -[float] -=== docker.node.spec.avaiability - -type: keyword - -wanted status. - - -[float] -== platform Fields - -Node information hardware and system - - - -[float] -=== docker.node.platform.architecture - -type: keyword - -Cpu architecture of the node. - - -[float] -=== docker.node.platform.os - -type: keyword - -OS node. - - -[float] -== ressources Fields - -available ressources on the node - - - -[float] -=== docker.node.ressources.nanocpus - -type: long - -available CPU ressources - - -[float] -=== docker.node.ressources.memorybytes - -type: long - -available Memory ressources - - -[float] -== engine Fields - -docker engine information - - - -[float] -=== docker.node.engine.engine_version - -type: keyword - -Docker engine version number - - -[float] -=== docker.node.engine.plugin - -type: keyword - -Docker plugin installed on the node - - -[float] -== status Fields - -docker swarm node status - - - -[float] -=== docker.node.status.state - -type: keyword - -Docker engine state - - -[float] -=== docker.node.status.addr - -type: keyword - -docker - - -[float] -== managerstatus Fields - -docker swarm manager status - - - -[float] -=== docker.node.managerstatus.leader - -type: boolean - -Docker engine manager state - - -[float] -=== docker.node.managerstatus.reachability - -type: keyword - -docker - - -[float] -=== docker.node.managerstatus.addr - -type: keyword - -docker manager listenning addr - - -[float] -== service Fields - -Docker service metrics. - - - -[float] -=== docker.service.id - -type: keyword - -service id - - -[float] -=== docker.service.createdat - -type: date - -date where the service has been created - - -[float] -=== docker.service.name - -type: keyword - -service name - - -[float] -=== docker.service.updatedad - -type: date - -last service specification change date - - -[float] -=== docker.service.mode - -type: keyword - -Service mode (replicated or global) - - -[float] -=== docker.service.replicas - -type: integer - -number of replicas if service mode is replicated - - -[float] -=== docker.service.healtcheck_enabled - -type: boolean - -check if healthcheck is activated in container specifications - - -[float] -=== docker.service.version - -type: integer - -service update versionning - - -[float] -== updatestatus Fields - -check update status - - - -[float] -=== docker.service.updatestatus.state - -type: keyword - -update state - - -[float] -=== docker.service.updatestatus.startedat - -type: date - -update started date - - -[float] -=== docker.service.updatestatus.completedat - -type: date - -update completed date - - -[float] -=== docker.service.updatestatus.message - -type: text - -update message - - [[exported-fields-haproxy]] == haproxy Fields diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index 6a27ca8f4bdf..44697ff78e57 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -21,7 +21,7 @@ in <>. Here is an example configuration: ---- metricbeat.modules: #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -44,29 +44,25 @@ The following metricsets are available: * <> +* <> + * <> * <> * <> -* <> - -* <> - include::docker/container.asciidoc[] include::docker/cpu.asciidoc[] include::docker/diskio.asciidoc[] +include::docker/healthcheck.asciidoc[] + include::docker/info.asciidoc[] include::docker/memory.asciidoc[] include::docker/network.asciidoc[] -include::docker/node.asciidoc[] - -include::docker/service.asciidoc[] - diff --git a/metricbeat/docs/modules/docker/node.asciidoc b/metricbeat/docs/modules/docker/node.asciidoc deleted file mode 100644 index e1d2341d0d22..000000000000 --- a/metricbeat/docs/modules/docker/node.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -//// -This file is generated! See scripts/docs_collector.py -//// - -[[metricbeat-metricset-docker-node]] -include::../../../module/docker/node/_meta/docs.asciidoc[] - - -==== Fields - -For a description of each field in the metricset, see the -<> section. - -Here is an example document generated by this metricset: - -[source,json] ----- -include::../../../module/docker/node/_meta/data.json[] ----- diff --git a/metricbeat/docs/modules/docker/service.asciidoc b/metricbeat/docs/modules/docker/service.asciidoc deleted file mode 100644 index 05af931e7b64..000000000000 --- a/metricbeat/docs/modules/docker/service.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -//// -This file is generated! See scripts/docs_collector.py -//// - -[[metricbeat-metricset-docker-service]] -include::../../../module/docker/service/_meta/docs.asciidoc[] - - -==== Fields - -For a description of each field in the metricset, see the -<> section. - -Here is an example document generated by this metricset: - -[source,json] ----- -include::../../../module/docker/service/_meta/data.json[] ----- diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 78d4f70d741e..39662b365397 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -18,11 +18,10 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/container" _ "github.com/elastic/beats/metricbeat/module/docker/cpu" _ "github.com/elastic/beats/metricbeat/module/docker/diskio" + _ "github.com/elastic/beats/metricbeat/module/docker/healthcheck" _ "github.com/elastic/beats/metricbeat/module/docker/info" _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" - _ "github.com/elastic/beats/metricbeat/module/docker/node" - _ "github.com/elastic/beats/metricbeat/module/docker/service" _ "github.com/elastic/beats/metricbeat/module/haproxy" _ "github.com/elastic/beats/metricbeat/module/haproxy/info" _ "github.com/elastic/beats/metricbeat/module/haproxy/stat" diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 0c4fd3d80102..aae0233851d1 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -98,11 +98,11 @@ metricbeat.modules: #hosts: ["localhost:8091"] #------------------------------- Docker Module ------------------------------- -#- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] - #hosts: ["unix:///var/run/docker.sock"] - #enabled: true - #period: 10s +- module: docker + metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + hosts: ["unix:///var/run/docker.sock"] + enabled: true + period: 10s # To connect to Docker over TLS you must specify a client and CA certificate. #ssl: diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index 47e24f9206f2..c69a7bf09d0a 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -582,24 +582,6 @@ "created": { "type": "date" }, - "health": { - "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "event_start_date": { - "type": "date" - } - } - }, "id": { "ignore_above": 1024, "index": "not_analyzed", @@ -686,6 +668,32 @@ } } }, + "healthcheck": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "event_start_date": { + "type": "date" + }, + "failingstreak": { + "type": "long" + }, + "status": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, "info": { "properties": { "containers": { @@ -791,165 +799,6 @@ } } } - }, - "node": { - "properties": { - "createdat": { - "type": "date" - }, - "engine": { - "properties": { - "engine_version": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "plugin": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "hostname": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "id": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "managerstatus": { - "properties": { - "addr": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "leader": { - "type": "boolean" - }, - "reachability": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "platform": { - "properties": { - "architecture": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "os": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "ressources": { - "properties": { - "memorybytes": { - "type": "long" - }, - "nanocpus": { - "type": "long" - } - } - }, - "spec": { - "properties": { - "avaiability": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "role": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "status": { - "properties": { - "addr": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "state": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "updatedad": { - "type": "date" - } - } - }, - "service": { - "properties": { - "createdat": { - "type": "date" - }, - "healtcheck_enabled": { - "type": "boolean" - }, - "id": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "mode": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "name": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "replicas": { - "type": "long" - }, - "updatedad": { - "type": "date" - }, - "updatestatus": { - "properties": { - "completedat": { - "type": "date" - }, - "message": { - "index": "analyzed", - "norms": { - "enabled": false - }, - "type": "string" - }, - "startedat": { - "type": "date" - }, - "state": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "version": { - "type": "long" - } - } } } }, diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index ad1294db6044..8e209829c5fc 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -584,23 +584,6 @@ "created": { "type": "date" }, - "health": { - "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "type": "keyword" - }, - "event_start_date": { - "type": "date" - } - } - }, "id": { "ignore_above": 1024, "type": "keyword" @@ -690,6 +673,30 @@ } } }, + "healthcheck": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "type": "keyword" + }, + "event_start_date": { + "type": "date" + }, + "failingstreak": { + "type": "long" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "info": { "properties": { "containers": { @@ -798,146 +805,6 @@ } } } - }, - "node": { - "properties": { - "createdat": { - "type": "date" - }, - "engine": { - "properties": { - "engine_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "plugin": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "managerstatus": { - "properties": { - "addr": { - "ignore_above": 1024, - "type": "keyword" - }, - "leader": { - "type": "boolean" - }, - "reachability": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "platform": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ressources": { - "properties": { - "memorybytes": { - "type": "long" - }, - "nanocpus": { - "type": "long" - } - } - }, - "spec": { - "properties": { - "avaiability": { - "ignore_above": 1024, - "type": "keyword" - }, - "role": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "status": { - "properties": { - "addr": { - "ignore_above": 1024, - "type": "keyword" - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "updatedad": { - "type": "date" - } - } - }, - "service": { - "properties": { - "createdat": { - "type": "date" - }, - "healtcheck_enabled": { - "type": "boolean" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "replicas": { - "type": "long" - }, - "updatedad": { - "type": "date" - }, - "updatestatus": { - "properties": { - "completedat": { - "type": "date" - }, - "message": { - "norms": false, - "type": "text" - }, - "startedat": { - "type": "date" - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "type": "long" - } - } } } }, diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index ba7bc2f041e0..587a4c56f4f6 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -1,5 +1,5 @@ #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/module/docker/container/_meta/data.json b/metricbeat/module/docker/container/_meta/data.json index 3e36df399d65..5fec882399e7 100644 --- a/metricbeat/module/docker/container/_meta/data.json +++ b/metricbeat/module/docker/container/_meta/data.json @@ -31,13 +31,5 @@ "name": "container", "rtt": 115 }, - "health": { - "event_end_date": "2017-01-09T20:38:13.080472813+01:00", - "event_exit_code": 0, - "event_output": "0.005", - "event_start_date": "2017-01-09T20:38:12.999970865+01:00", - "failingstreak": 0, - "status": "healthy" - }, "type": "metricsets" } diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index d70523ecea60..cf56b0a142f8 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -40,24 +40,3 @@ type: long description: > Size of the files that have been created or changed since creation. - - name: health - type: group - description: > - Container health metrics. - fields: - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: keyword - description: > - Healthcheck output - - name: event_exit_code - type: integer - description: > - Healthcheck status code diff --git a/metricbeat/module/docker/container/container.go b/metricbeat/module/docker/container/container.go index bfc0c32fa095..0606072cdfca 100644 --- a/metricbeat/module/docker/container/container.go +++ b/metricbeat/module/docker/container/container.go @@ -48,5 +48,5 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { if err != nil { return nil, err } - return eventsMapping(containers, m), nil + return eventsMapping(containers), nil } diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index ea6dd77f6356..199cb4df2aef 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -6,19 +6,18 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/module/docker" - "strings" dc "github.com/fsouza/go-dockerclient" ) -func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { +func eventsMapping(containersList []dc.APIContainers) []common.MapStr { myEvents := []common.MapStr{} for _, container := range containersList { - myEvents = append(myEvents, eventMapping(&container, m)) + myEvents = append(myEvents, eventMapping(&container)) } return myEvents } -func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { +func eventMapping(cont *dc.APIContainers) common.MapStr { event := common.MapStr{ "created": common.Time(time.Unix(cont.Created, 0)), "id": cont.ID, @@ -32,24 +31,6 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "status": cont.Status, } -// Check id container have health metrics configured -if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - container, _ := m.dockerClient.InspectContainer(cont.ID) - - last_event := len(container.State.Health.Log)-1 - if last_event >= 0 { - health := common.MapStr{ - "status": container.State.Health.Status, - "failingstreak": container.State.Health.FailingStreak, - "event_start_date": container.State.Health.Log[last_event].Start, - "event_end_date": container.State.Health.Log[last_event].End, - "event_exit_code": container.State.Health.Log[last_event].ExitCode, - "event_output": container.State.Health.Log[last_event].Output, - } - event["health"] = health - } -} - labels := docker.DeDotLabels(cont.Labels) if len(labels) > 0 { diff --git a/metricbeat/module/docker/glide.yaml b/metricbeat/module/docker/glide.yaml index 7d3f1ac108be..0f1adf26d4e7 100644 --- a/metricbeat/module/docker/glide.yaml +++ b/metricbeat/module/docker/glide.yaml @@ -1,4 +1,12 @@ package: github.com/elastic/beats/metricbeat/module/docker import: - package: github.com/fsouza/go-dockerclient - version: 23c589186c2a92a8742da55f19aec4997dae5cbb + version: e085edda407c05214cc6e71e4881de47667e77ec +- package: github.com/docker/docker + version: 8bc7e193464b5b59a2019a4a429a48526f71bc40 +- package: github.com/docker/go-units + version: e30f1e79f3cd72542f2026ceec18d3bd67ab859c +- package: github.com/hashicorp/go-cleanhttp + version: ad28ea4487f05916463e2423a55166280e8254b5 +- package: github.com/Microsoft/go-winio + version: v0.3.7 diff --git a/metricbeat/module/docker/node/_meta/data.json b/metricbeat/module/docker/node/_meta/data.json deleted file mode 100644 index f03d1b95fb89..000000000000 --- a/metricbeat/module/docker/node/_meta/data.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "@timestamp": "2016-05-23T08:05:34.853Z", - "beat": { - "hostname": "host.example.com", - "name": "host.example.com" - }, - "docker": { - "node": { - "createdat": "2017-01-10T05:37:07.548757912Z", - "updatedat": "2017-01-10T05:37:08.159552729Z", - "id": "4be260de8fc1213c9ff58789b8221e70c53f5af5d5a3915ff7de4b81b357d851", - "hostname": "thisisatest", - "labels": { - "swarm_labels_toto": "valueoftotolabel", - "swarm_number": "1" - }, - "spec": { - "role": "manager", - "avaiability": "active" - }, - "platform": { - "architecture": "x86_64", - "os": "Linux" - }, - "ressources": { - "nanocpus": 4000000000, - "memorybytes": 8115884032 - }, - "status": { - "state": "ready", - "addr": "127.0.0.1" - }, - "manager": { - "leader": true, - "reachability": "reachable", - "addr": "192.168.1.38:2377" - }, - "engine": { - "version": "1.13.0-rc5", - "labels": - { - "enginelabel1=enginelabel1value" - } - } - } - }, - "metricset": { - "host": "/var/run/docker.sock", - "module": "docker", - "name": "node", - "rtt": 115 - }, - "type": "metricsets" -} diff --git a/metricbeat/module/docker/node/_meta/docs.asciidoc b/metricbeat/module/docker/node/_meta/docs.asciidoc deleted file mode 100644 index cf4f9f984d02..000000000000 --- a/metricbeat/module/docker/node/_meta/docs.asciidoc +++ /dev/null @@ -1,4 +0,0 @@ -=== Docker Node Metricset - -The Docker Swarm `node` metricset collects information and statistics about -running nodes in Docker cluster. diff --git a/metricbeat/module/docker/node/_meta/fields.yml b/metricbeat/module/docker/node/_meta/fields.yml deleted file mode 100644 index 383f67c88bcc..000000000000 --- a/metricbeat/module/docker/node/_meta/fields.yml +++ /dev/null @@ -1,104 +0,0 @@ -- name: node - type: group - description: > - Docker node metrics. - fields: - - - name: createdat - type: date - description: > - date where the node has been added to the cluster - - name: updatedad - type: date - description: > - last gossip message - - name: id - type: keyword - description: > - Unique node id. - - name: hostname - type: keyword - description: > - hostname of the node - - name: spec - type: group - description: > - Configured status - fields: - - name: role - type: keyword - description: > - Wanted role - - name: avaiability - type: keyword - description: > - wanted status. - - name: platform - type: group - description: > - Node information hardware and system - fields: - - name: architecture - type: keyword - description: > - Cpu architecture of the node. - - name: os - type: keyword - description: > - OS node. - - name: ressources - type: group - description: > - available ressources on the node - fields: - - name: nanocpus - type: long - description: > - available CPU ressources - - name: memorybytes - type: long - description: > - available Memory ressources - - name: engine - type: group - description: > - docker engine information - fields: - - name: engine_version - type: keyword - description: > - Docker engine version number - - name: plugin - type: keyword - description: > - Docker plugin installed on the node - - name: status - type: group - description: > - docker swarm node status - fields: - - name: state - type: keyword - description: > - Docker engine state - - name: addr - type: keyword - description: > - docker - - name: managerstatus - type: group - description: > - docker swarm manager status - fields: - - name: leader - type: boolean - description: > - Docker engine manager state - - name: reachability - type: keyword - description: > - docker - - name: addr - type: keyword - description: > - docker manager listenning addr diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go deleted file mode 100644 index e1b5e9205186..000000000000 --- a/metricbeat/module/docker/node/data.go +++ /dev/null @@ -1,65 +0,0 @@ -package node - -import ( - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/metricbeat/module/docker" - - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" -) - -func eventsMapping(nodesList []swarm.Node) []common.MapStr { - myEvents := []common.MapStr{} - - for _, node := range nodesList { - myEvents = append(myEvents, eventMapping(&node)) - } - - return myEvents -} - -func eventMapping(node *swarm.Node) common.MapStr { - event := common.MapStr{ - "createdat": node.Meta.CreatedAt, - "updatedat": node.Meta.UpdatedAt, - "id": node.ID, - "hostname": node.Description.Hostname, - "spec": common.MapStr{ - "role": node.Spec.Role, - "avaiability": node.Spec.Availability, - }, - "platform": common.MapStr{ - "architecture": node.Description.Platform.Architecture, - "os": node.Description.Platform.OS, - }, - "status": common.MapStr{ - "state": node.Status.State, - "addr": node.Status.Addr, - }, - "ressources": common.MapStr{ - "nanocpus": node.Description.Resources.NanoCPUs, - "memorybytes": node.Description.Resources.MemoryBytes, - }, - "engine.version": node.Description.Engine.EngineVersion, - } - - if node.Spec.Role == "manager" { - //fmt.Println("this is a manager ",node.ManagerStatus.Leader) - manager := common.MapStr{ - "leader": node.ManagerStatus.Leader, - "reachability": node.ManagerStatus.Reachability, - "addr": node.ManagerStatus.Addr, - } - event["manager"] = manager - } - - swarm_labels := docker.DeDotLabels(node.Spec.Annotations.Labels) - if len(swarm_labels) > 0 { - event["labels"] = swarm_labels - } - engine_labels := docker.DeDotLabels(node.Description.Engine.Labels) - if len(engine_labels) > 0 { - event["engine.labels"] = engine_labels - } - - return event -} diff --git a/metricbeat/module/docker/node/node.go b/metricbeat/module/docker/node/node.go deleted file mode 100644 index 40799a15ec0b..000000000000 --- a/metricbeat/module/docker/node/node.go +++ /dev/null @@ -1,53 +0,0 @@ -package node - -import ( - dc "github.com/fsouza/go-dockerclient" - - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/metricbeat/mb" - "github.com/elastic/beats/metricbeat/module/docker" -) - -func init() { - if err := mb.Registry.AddMetricSet("docker", "node", New, docker.HostParser); err != nil { - panic(err) - } -} - -type MetricSet struct { - mb.BaseMetricSet - dockerClient *dc.Client -} - -// New creates a new instance of the docker container MetricSet. -func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - logp.Warn("EXPERIMENTAL: The docker node metricset is experimental") - - config := docker.Config{} - if err := base.Module().UnpackConfig(&config); err != nil { - return nil, err - } - - client, err := docker.NewDockerClient(base.HostData().URI, config) - if err != nil { - return nil, err - } - - return &MetricSet{ - BaseMetricSet: base, - dockerClient: client, - }, nil -} - -// Fetch returns a list of all containers as events. -// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-nodes. -func (m *MetricSet) Fetch() ([]common.MapStr, error) { - // Fetch a list of all nodes. - nodes, err := m.dockerClient.ListNodes(dc.ListNodesOptions{}) - if err != nil { - return nil, err - } - - return eventsMapping(nodes), nil -} diff --git a/metricbeat/module/docker/node/node_integration_test.go b/metricbeat/module/docker/node/node_integration_test.go deleted file mode 100644 index 5a35029ef229..000000000000 --- a/metricbeat/module/docker/node/node_integration_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build integration - -package node - -import ( - "testing" - - mbtest "github.com/elastic/beats/metricbeat/mb/testing" -) - -func TestData(t *testing.T) { - f := mbtest.NewEventsFetcher(t, getConfig()) - err := mbtest.WriteEvents(f, t) - if err != nil { - t.Fatal("write", err) - } -} - -func getConfig() map[string]interface{} { - return map[string]interface{}{ - "module": "docker", - "metricsets": []string{"node"}, - "hosts": []string{"unix:///var/run/docker.sock"}, - } -} diff --git a/metricbeat/module/docker/service/_meta/data.json b/metricbeat/module/docker/service/_meta/data.json deleted file mode 100644 index 14dcbe4bc927..000000000000 --- a/metricbeat/module/docker/service/_meta/data.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "@timestamp": "2017-01-11T15:45:19.162Z", - "beat": { - "hostname": "smusso-ThinkPad", - "name": "smusso-ThinkPad", - "version": "6.0.0-alpha1" - }, - "docker": { - "service": { - "replicas": 2, - "createdat": "2017-01-11T11:35:53.432238684Z", - "healtcheck_enabled": true, - "id": "1vyemp33ktfmk7xpfmlg29ns0", - "labels": { - "label1": "thisisatest" - }, - "mode": "Replicated", - "name": "elasticsearch", - "updatedat": "2017-01-11T15:45:03.726977327Z", - "version": 905 - } - }, - "metricset": { - "host": "/var/run/docker.sock", - "module": "docker", - "name": "service", - "rtt": 3967 - }, - "type": "metricsets" -} diff --git a/metricbeat/module/docker/service/_meta/docs.asciidoc b/metricbeat/module/docker/service/_meta/docs.asciidoc deleted file mode 100644 index 1d1858fabb24..000000000000 --- a/metricbeat/module/docker/service/_meta/docs.asciidoc +++ /dev/null @@ -1,4 +0,0 @@ -=== Docker Service Metricset - -The Docker Swarm `service` metricset collects information and statistics about -running services in Docker cluster. diff --git a/metricbeat/module/docker/service/_meta/fields.yml b/metricbeat/module/docker/service/_meta/fields.yml deleted file mode 100644 index 4d16dcc426bc..000000000000 --- a/metricbeat/module/docker/service/_meta/fields.yml +++ /dev/null @@ -1,59 +0,0 @@ -- name: service - type: group - description: > - Docker service metrics. - fields: - - - name: id - type: keyword - description: > - service id - - name: createdat - type: date - description: > - date where the service has been created - - name: name - type: keyword - description: > - service name - - name: updatedad - type: date - description: > - last service specification change date - - name: mode - type: keyword - description: > - Service mode (replicated or global) - - name: replicas - type: integer - description: > - number of replicas if service mode is replicated - - name: healtcheck_enabled - type: boolean - description: > - check if healthcheck is activated in container specifications - - name: version - type: integer - description: > - service update versionning - - name: updatestatus - type: group - description: > - check update status - fields: - - name: "state" - type: keyword - description: > - update state - - name: "startedat" - type: date - description: > - update started date - - name: "completedat" - type: date - description: > - update completed date - - name: "message" - type: "text" - description: > - update message diff --git a/metricbeat/module/docker/service/data.go b/metricbeat/module/docker/service/data.go deleted file mode 100644 index fa2445ce2974..000000000000 --- a/metricbeat/module/docker/service/data.go +++ /dev/null @@ -1,83 +0,0 @@ -package service - -import ( - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/metricbeat/module/docker" - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" - "reflect" -) - -func eventsMapping(serviceList []swarm.Service) []common.MapStr { - myEvents := []common.MapStr{} - - for _, service := range serviceList { - myEvents = append(myEvents, eventMapping(&service)) - } - - return myEvents -} - -func eventMapping(service *swarm.Service) common.MapStr { - - event := common.MapStr{ - "id": service.ID, - "version": service.Meta.Version.Index, - "createdat": service.Meta.CreatedAt, - "updatedat": service.Meta.UpdatedAt, - "name": service.Spec.Annotations.Name, - } - - // Do not insert updatestatus map if no updatestatus is present - if service.UpdateStatus.Message != "" { - updatestatus := common.MapStr{ - "state": service.UpdateStatus.State, - "startedat": service.UpdateStatus.StartedAt, - "completedat": service.UpdateStatus.CompletedAt, - "message": service.UpdateStatus.Message, - } - event["updatestatus"] = updatestatus - } - - // Check service mode - if service.Spec.Mode.Replicated != nil { - event["mode"] = "Replicated" - event["replicas"] = service.Spec.Mode.Replicated.Replicas - } else { - event["mode"] = "Global" - } - - previousspec_labels := common.MapStr{} - spec_labels := common.MapStr{} - - if service.PreviousSpec != nil && service.PreviousSpec.Annotations.Labels != nil { - previousspec_labels = docker.DeDotLabels(service.PreviousSpec.Annotations.Labels) - } - - if service.Spec.Annotations.Labels != nil { - spec_labels = docker.DeDotLabels(service.Spec.Annotations.Labels) - } - - // Print previous label only if they have been modify - if len(spec_labels) != 0 || len(previousspec_labels) != 0 { - if len(spec_labels) != 0 && len(previousspec_labels) != 0 { - if reflect.DeepEqual(spec_labels, previousspec_labels) { - event["labels"] = spec_labels - } else { - event["previousspec.labels"] = previousspec_labels - event["labels"] = spec_labels - } - } else if len(spec_labels) == 0 && len(previousspec_labels) != 0 { - event["previousspec.labels"] = previousspec_labels - } else { - event["labels"] = spec_labels - } - } - - if service.Spec.TaskTemplate.ContainerSpec.Healthcheck != nil { - event["healtcheck_enabled"] = true - } else { - event["healtcheck_enabled"] = false - } - - return event -} diff --git a/metricbeat/module/docker/service/service.go b/metricbeat/module/docker/service/service.go deleted file mode 100644 index f43389348bef..000000000000 --- a/metricbeat/module/docker/service/service.go +++ /dev/null @@ -1,53 +0,0 @@ -package service - -import ( - dc "github.com/fsouza/go-dockerclient" - - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/metricbeat/mb" - "github.com/elastic/beats/metricbeat/module/docker" -) - -func init() { - if err := mb.Registry.AddMetricSet("docker", "service", New, docker.HostParser); err != nil { - panic(err) - } -} - -type MetricSet struct { - mb.BaseMetricSet - dockerClient *dc.Client -} - -// New creates a new instance of the docker services MetricSet. -func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - logp.Warn("EXPERIMENTAL: The docker service metricset is experimental") - - config := docker.Config{} - if err := base.Module().UnpackConfig(&config); err != nil { - return nil, err - } - - client, err := docker.NewDockerClient(base.HostData().URI, config) - if err != nil { - return nil, err - } - - return &MetricSet{ - BaseMetricSet: base, - dockerClient: client, - }, nil -} - -// Fetch returns a list of all services as events. -// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-services. -func (m *MetricSet) Fetch() ([]common.MapStr, error) { - // Fetch a list of all services. - services, err := m.dockerClient.ListServices(dc.ListServicesOptions{}) - if err != nil { - return nil, err - } - - return eventsMapping(services), nil -} diff --git a/metricbeat/module/docker/service/service_integration_test.go b/metricbeat/module/docker/service/service_integration_test.go deleted file mode 100644 index e3a5a5369a7e..000000000000 --- a/metricbeat/module/docker/service/service_integration_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build integration - -package service - -import ( - "testing" - - mbtest "github.com/elastic/beats/metricbeat/mb/testing" -) - -func TestData(t *testing.T) { - f := mbtest.NewEventsFetcher(t, getConfig()) - err := mbtest.WriteEvents(f, t) - if err != nil { - t.Fatal("write", err) - } -} - -func getConfig() map[string]interface{} { - return map[string]interface{}{ - "module": "docker", - "metricsets": []string{"service"}, - "hosts": []string{"unix:///var/run/docker.sock"}, - } -} From cd0cebcabd59c9b54aae62ae848cd745b57e7f5c Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:36:27 +0100 Subject: [PATCH 08/27] add healthcheck metricset in docker module --- .../docs/modules/docker/healthcheck.asciidoc | 19 +++++++ .../module/docker/healthcheck/_meta/data.json | 24 +++++++++ .../docker/healthcheck/_meta/docs.asciidoc | 4 ++ .../docker/healthcheck/_meta/fields.yml | 29 +++++++++++ .../healthcheck/container_integration_test.go | 25 +++++++++ metricbeat/module/docker/healthcheck/data.go | 50 ++++++++++++++++++ .../module/docker/healthcheck/healthcheck.go | 52 +++++++++++++++++++ 7 files changed, 203 insertions(+) create mode 100644 metricbeat/docs/modules/docker/healthcheck.asciidoc create mode 100644 metricbeat/module/docker/healthcheck/_meta/data.json create mode 100644 metricbeat/module/docker/healthcheck/_meta/docs.asciidoc create mode 100644 metricbeat/module/docker/healthcheck/_meta/fields.yml create mode 100644 metricbeat/module/docker/healthcheck/container_integration_test.go create mode 100644 metricbeat/module/docker/healthcheck/data.go create mode 100644 metricbeat/module/docker/healthcheck/healthcheck.go diff --git a/metricbeat/docs/modules/docker/healthcheck.asciidoc b/metricbeat/docs/modules/docker/healthcheck.asciidoc new file mode 100644 index 000000000000..220ba07630d9 --- /dev/null +++ b/metricbeat/docs/modules/docker/healthcheck.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-docker-healthcheck]] +include::../../../module/docker/healthcheck/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/docker/healthcheck/_meta/data.json[] +---- diff --git a/metricbeat/module/docker/healthcheck/_meta/data.json b/metricbeat/module/docker/healthcheck/_meta/data.json new file mode 100644 index 000000000000..16e91a84feba --- /dev/null +++ b/metricbeat/module/docker/healthcheck/_meta/data.json @@ -0,0 +1,24 @@ +{ + "@timestamp": "2016-05-23T08:05:34.853Z", + "beat": { + "hostname": "host.example.com", + "name": "host.example.com" + }, + "docker": { + "healthcheck": { + "event_end_date": "2017-01-09T20:38:13.080472813+01:00", + "event_exit_code": 0, + "event_output": "this is an event output", + "event_start_date": "2017-01-09T20:38:12.999970865+01:00", + "failingstreak": 0, + "status": "healthy" + } + }, + "metricset": { + "host": "/var/run/docker.sock", + "module": "docker", + "name": "container", + "rtt": 115 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc new file mode 100644 index 000000000000..3c095e4e9c0e --- /dev/null +++ b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +=== Docker Container Metricset + +The Docker `container` metricset collects information and statistics about +running Docker containers. diff --git a/metricbeat/module/docker/healthcheck/_meta/fields.yml b/metricbeat/module/docker/healthcheck/_meta/fields.yml new file mode 100644 index 000000000000..4cd5c8dc5ba2 --- /dev/null +++ b/metricbeat/module/docker/healthcheck/_meta/fields.yml @@ -0,0 +1,29 @@ +- name: healthcheck + type: group + description: > + Docker container metrics. + fields: + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: keyword + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code + - name: failingstreak + type: integer + description: > + concurent failed check + - name: status + type: keyword + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/healthcheck/container_integration_test.go b/metricbeat/module/docker/healthcheck/container_integration_test.go new file mode 100644 index 000000000000..8c1356f7366c --- /dev/null +++ b/metricbeat/module/docker/healthcheck/container_integration_test.go @@ -0,0 +1,25 @@ +// +build integration + +package healthcheck + +import ( + "testing" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "docker", + "metricsets": []string{"healthcheck"}, + "hosts": []string{"unix:///var/run/docker.sock"}, + } +} diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go new file mode 100644 index 000000000000..d436092c2cb8 --- /dev/null +++ b/metricbeat/module/docker/healthcheck/data.go @@ -0,0 +1,50 @@ +package healthcheck + +import ( + //"time" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" + + dc "github.com/fsouza/go-dockerclient" + "reflect" + "strings" +) + +func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { + myEvents := []common.MapStr{} + emptyEvent := common.MapStr{} + for _, container := range containersList { + returnevent := eventMapping(&container, m) + if !reflect.DeepEqual(emptyEvent, returnevent) { + myEvents = append(myEvents, eventMapping(&container, m)) + } + } + return myEvents +} + +func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { + event := common.MapStr{} + if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log) - 1 + if last_event >= 0 { + event = common.MapStr{ + mb.ModuleData: common.MapStr{ + "container": common.MapStr{ + "name": docker.ExtractContainerName(cont.Names), + }, + }, + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event_start_date": common.Time(container.State.Health.Log[last_event].Start), + "event_end_date": common.Time(container.State.Health.Log[last_event].End), + "event_exit_code": container.State.Health.Log[last_event].ExitCode, + "event_output": container.State.Health.Log[last_event].Output, + } + } + } + + return event +} diff --git a/metricbeat/module/docker/healthcheck/healthcheck.go b/metricbeat/module/docker/healthcheck/healthcheck.go new file mode 100644 index 000000000000..0c775056e105 --- /dev/null +++ b/metricbeat/module/docker/healthcheck/healthcheck.go @@ -0,0 +1,52 @@ +package healthcheck + +import ( + dc "github.com/fsouza/go-dockerclient" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" +) + +func init() { + if err := mb.Registry.AddMetricSet("docker", "healthcheck", New, docker.HostParser); err != nil { + panic(err) + } +} + +type MetricSet struct { + mb.BaseMetricSet + dockerClient *dc.Client +} + +// New creates a new instance of the docker container MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("EXPERIMENTAL: The docker healthcheck metricset is experimental") + + config := docker.Config{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + client, err := docker.NewDockerClient(base.HostData().URI, config) + if err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + dockerClient: client, + }, nil +} + +// Fetch returns a list of all containers as events. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + // Fetch a list of all containers. + containers, err := m.dockerClient.ListContainers(dc.ListContainersOptions{}) + if err != nil { + return nil, err + } + return eventsMapping(containers, m), nil +} From 3d743aa58bd4172adfd79bd7ccbe0cbe7ddfb6ab Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:47:01 +0100 Subject: [PATCH 09/27] delete old fsouza lib (node.go and service.go) --- .../github.com/fsouza/go-dockerclient/node.go | 68 ------------------ .../fsouza/go-dockerclient/service.go | 69 ------------------- 2 files changed, 137 deletions(-) delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go deleted file mode 100644 index 3d790ff54c85..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "encoding/json" - "net/http" - - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" -) - -// NoSuchNode is the error returned when a given node does not exist. -type NoSuchNode struct { - ID string - Err error -} - -func (err *NoSuchNode) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such node: " + err.ID -} - -// ListNodesOptions specify parameters to the ListNodes function. -// -// See http://goo.gl/3K4GwU for more details. -type ListNodesOptions struct { - Filters map[string][]string -} - -// ListNodes returns a slice of nodes matching the given criteria. -// -// See http://goo.gl/3K4GwU for more details. -func (c *Client) ListNodes(opts ListNodesOptions) ([]swarm.Node, error) { - path := "/nodes?" + queryString(opts) - resp, err := c.do("GET", path, doOptions{}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var nodes []swarm.Node - if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil { - return nil, err - } - return nodes, nil -} - -// InspectNode returns information about a node by its ID. -// -// See http://goo.gl/WjkTOk for more details. -func (c *Client) InspectNode(id string) (*swarm.Node, error) { - resp, err := c.do("GET", "/nodes/"+id, doOptions{}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return nil, &NoSuchNode{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var node swarm.Node - if err := json.NewDecoder(resp.Body).Decode(&node); err != nil { - return nil, err - } - return &node, nil -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go deleted file mode 100644 index 7ace1a366b24..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "encoding/json" - "net/http" - - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" -) - -// NoSuchService is the error returned when a given service does not exist. -type NoSuchService struct { - ID string - Err error -} - -func (err *NoSuchService) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such service: " + err.ID -} - -// InspectService returns information about a service by its ID. -// -// See https://goo.gl/dHmr75 for more details. -func (c *Client) InspectService(id string) (*swarm.Service, error) { - path := "/services/" + id - resp, err := c.do("GET", path, doOptions{}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return nil, &NoSuchService{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var service swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { - return nil, err - } - return &service, nil -} - -// ListServicesOptions specify parameters to the ListServices function. -// -// See https://goo.gl/DwvNMd for more details. -type ListServicesOptions struct { - Filters map[string][]string -} - -// ListServices returns a slice of services matching the given criteria. -// -// See https://goo.gl/DwvNMd for more details. -func (c *Client) ListServices(opts ListServicesOptions) ([]swarm.Service, error) { - path := "/services?" + queryString(opts) - resp, err := c.do("GET", path, doOptions{}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var services []swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&services); err != nil { - return nil, err - } - return services, nil -} From 2e2962944de6cb878b4a3ac98347feb3f99886ab Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:53:21 +0100 Subject: [PATCH 10/27] Set metricbeat.full.yml to default value --- metricbeat/metricbeat.full.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index aae0233851d1..884b5effa3c0 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -98,11 +98,11 @@ metricbeat.modules: #hosts: ["localhost:8091"] #------------------------------- Docker Module ------------------------------- -- module: docker - metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] - hosts: ["unix:///var/run/docker.sock"] - enabled: true - period: 10s +#- module: docker + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #hosts: ["unix:///var/run/docker.sock"] + #enabled: true + #period: 10s # To connect to Docker over TLS you must specify a client and CA certificate. #ssl: @@ -862,4 +862,3 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 - From 6ff4edff87ca2d1e08220fac8f8a026c309b357e Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 12:00:03 +0100 Subject: [PATCH 11/27] Fix shell in metricbeat.full.yml --- metricbeat/metricbeat.full.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 884b5effa3c0..c289dd0f9a8a 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -862,3 +862,4 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 + From 2e9ab408f8ae991a26fe8109082d9393f67118d0 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 13:28:35 +0100 Subject: [PATCH 12/27] Last commit, add comment --- metricbeat/module/docker/healthcheck/_meta/docs.asciidoc | 4 ++-- metricbeat/module/docker/healthcheck/data.go | 4 ++++ metricbeat/module/docker/healthcheck/healthcheck.go | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc index 3c095e4e9c0e..bfcf644a1069 100644 --- a/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc +++ b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc @@ -1,4 +1,4 @@ -=== Docker Container Metricset +=== Docker healthcheck Metricset -The Docker `container` metricset collects information and statistics about +The Docker `healthcheck` metricset collects information and statistics about running Docker containers. diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go index d436092c2cb8..4a8d630f2c5c 100644 --- a/metricbeat/module/docker/healthcheck/data.go +++ b/metricbeat/module/docker/healthcheck/data.go @@ -14,9 +14,11 @@ import ( func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} + // Set an empty map in order to detect empty healthcheck event emptyEvent := common.MapStr{} for _, container := range containersList { returnevent := eventMapping(&container, m) + // Compare event to empty event if !reflect.DeepEqual(emptyEvent, returnevent) { myEvents = append(myEvents, eventMapping(&container, m)) } @@ -26,9 +28,11 @@ func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.Map func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { event := common.MapStr{} + // Detect if healthcheck is available for container if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { container, _ := m.dockerClient.InspectContainer(cont.ID) last_event := len(container.State.Health.Log) - 1 + // Detect if an healthcheck already occured if last_event >= 0 { event = common.MapStr{ mb.ModuleData: common.MapStr{ diff --git a/metricbeat/module/docker/healthcheck/healthcheck.go b/metricbeat/module/docker/healthcheck/healthcheck.go index 0c775056e105..f487e2708bbe 100644 --- a/metricbeat/module/docker/healthcheck/healthcheck.go +++ b/metricbeat/module/docker/healthcheck/healthcheck.go @@ -20,7 +20,7 @@ type MetricSet struct { dockerClient *dc.Client } -// New creates a new instance of the docker container MetricSet. +// New creates a new instance of the docker healthcheck MetricSet. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { logp.Warn("EXPERIMENTAL: The docker healthcheck metricset is experimental") From d8e7256d6a2ecac6e7be56ea41f5def2e6e4f694 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 15:34:08 +0100 Subject: [PATCH 13/27] set metricset list in alphabetical order, remap event healtcheck data, compare eventMapping to nil --- metricbeat/_meta/beat.full.yml | 2 +- metricbeat/docs/fields.asciidoc | 39 +++++++++++-------- metricbeat/docs/modules/docker.asciidoc | 2 +- metricbeat/metricbeat.full.yml | 2 +- metricbeat/metricbeat.template-es2x.json | 30 +++++++------- metricbeat/metricbeat.template.json | 28 +++++++------ metricbeat/module/docker/_meta/config.yml | 2 +- .../module/docker/healthcheck/_meta/data.json | 14 ++++--- .../docker/healthcheck/_meta/fields.yml | 37 ++++++++++-------- metricbeat/module/docker/healthcheck/data.go | 26 ++++++------- 10 files changed, 102 insertions(+), 80 deletions(-) diff --git a/metricbeat/_meta/beat.full.yml b/metricbeat/_meta/beat.full.yml index 05fc3d3d9dec..2389495f199d 100644 --- a/metricbeat/_meta/beat.full.yml +++ b/metricbeat/_meta/beat.full.yml @@ -99,7 +99,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 4366557204fd..863918244fe6 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1179,50 +1179,57 @@ Docker container metrics. [float] -=== docker.healthcheck.event_end_date +=== docker.healthcheck.failingstreak -type: date +type: integer -Healthcheck end date +concurent failed check [float] -=== docker.healthcheck.event_start_date +=== docker.healthcheck.status -type: date +type: keyword -Healthcheck start date +Healthcheck status code [float] -=== docker.healthcheck.event_output +== event Fields -type: keyword +event fields. -Healthcheck output [float] -=== docker.healthcheck.event_exit_code +=== docker.healthcheck.event.end_date -type: integer +type: date -Healthcheck status code +Healthcheck end date [float] -=== docker.healthcheck.failingstreak +=== docker.healthcheck.event.start_date -type: integer +type: date -concurent failed check +Healthcheck start date [float] -=== docker.healthcheck.status +=== docker.healthcheck.event.output type: keyword +Healthcheck output + + +[float] +=== docker.healthcheck.event.exit_code + +type: integer + Healthcheck status code diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index 44697ff78e57..2388f6ea9e0b 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -21,7 +21,7 @@ in <>. Here is an example configuration: ---- metricbeat.modules: #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index c289dd0f9a8a..5699ac3c3a2c 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -99,7 +99,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index c69a7bf09d0a..2e2cf6b9ddd6 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -670,19 +670,23 @@ }, "healthcheck": { "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "event_start_date": { - "type": "date" + "event": { + "properties": { + "end_date": { + "type": "date" + }, + "exit_code": { + "type": "long" + }, + "output": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "start_date": { + "type": "date" + } + } }, "failingstreak": { "type": "long" diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index 8e209829c5fc..81d328aa238d 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -675,18 +675,22 @@ }, "healthcheck": { "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "type": "keyword" - }, - "event_start_date": { - "type": "date" + "event": { + "properties": { + "end_date": { + "type": "date" + }, + "exit_code": { + "type": "long" + }, + "output": { + "ignore_above": 1024, + "type": "keyword" + }, + "start_date": { + "type": "date" + } + } }, "failingstreak": { "type": "long" diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index 587a4c56f4f6..f2440a78afdf 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -1,5 +1,5 @@ #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/module/docker/healthcheck/_meta/data.json b/metricbeat/module/docker/healthcheck/_meta/data.json index 16e91a84feba..73978d883839 100644 --- a/metricbeat/module/docker/healthcheck/_meta/data.json +++ b/metricbeat/module/docker/healthcheck/_meta/data.json @@ -6,12 +6,16 @@ }, "docker": { "healthcheck": { - "event_end_date": "2017-01-09T20:38:13.080472813+01:00", - "event_exit_code": 0, - "event_output": "this is an event output", - "event_start_date": "2017-01-09T20:38:12.999970865+01:00", "failingstreak": 0, - "status": "healthy" + "status": "healthy", + "healthcheck": { + "event": { + "end_date": "2017-01-09T20:38:13.080472813+01:00", + "exit_code": 0, + "output": "this is an event output", + "start_date": "2017-01-09T20:38:12.999970865+01:00", + } + } } }, "metricset": { diff --git a/metricbeat/module/docker/healthcheck/_meta/fields.yml b/metricbeat/module/docker/healthcheck/_meta/fields.yml index 4cd5c8dc5ba2..0b37d42f13b8 100644 --- a/metricbeat/module/docker/healthcheck/_meta/fields.yml +++ b/metricbeat/module/docker/healthcheck/_meta/fields.yml @@ -3,22 +3,6 @@ description: > Docker container metrics. fields: - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: keyword - description: > - Healthcheck output - - name: event_exit_code - type: integer - description: > - Healthcheck status code - name: failingstreak type: integer description: > @@ -27,3 +11,24 @@ type: keyword description: > Healthcheck status code + - name: event + type: group + description: > + event fields. + fields: + - name: end_date + type: date + description: > + Healthcheck end date + - name: start_date + type: date + description: > + Healthcheck start date + - name: output + type: keyword + description: > + Healthcheck output + - name: exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go index 4a8d630f2c5c..8fca6f4babe2 100644 --- a/metricbeat/module/docker/healthcheck/data.go +++ b/metricbeat/module/docker/healthcheck/data.go @@ -1,8 +1,6 @@ package healthcheck import ( - //"time" - "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/mb" "github.com/elastic/beats/metricbeat/module/docker" @@ -14,13 +12,11 @@ import ( func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} - // Set an empty map in order to detect empty healthcheck event - emptyEvent := common.MapStr{} for _, container := range containersList { returnevent := eventMapping(&container, m) // Compare event to empty event - if !reflect.DeepEqual(emptyEvent, returnevent) { - myEvents = append(myEvents, eventMapping(&container, m)) + if !reflect.ValueOf(returnevent).IsNil() { + myEvents = append(myEvents, returnevent) } } return myEvents @@ -40,15 +36,17 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "name": docker.ExtractContainerName(cont.Names), }, }, - "status": container.State.Health.Status, - "failingstreak": container.State.Health.FailingStreak, - "event_start_date": common.Time(container.State.Health.Log[last_event].Start), - "event_end_date": common.Time(container.State.Health.Log[last_event].End), - "event_exit_code": container.State.Health.Log[last_event].ExitCode, - "event_output": container.State.Health.Log[last_event].Output, + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event": common.MapStr{ + "start_date": common.Time(container.State.Health.Log[last_event].Start), + "end_date": common.Time(container.State.Health.Log[last_event].End), + "exit_code": container.State.Health.Log[last_event].ExitCode, + "output": container.State.Health.Log[last_event].Output, + }, } + return event } } - - return event + return nil } From 2e8d78e4a9eec2b438c5b4afed7d293a6550de9d Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 06:30:49 +0100 Subject: [PATCH 14/27] Add health to standalone container --- metricbeat/metricbeat.yml | 31 ++++++++++++------- .../module/docker/container/_meta/data.json | 10 +++++- .../module/docker/container/_meta/fields.yml | 20 ++++++++++++ .../module/docker/container/container.go | 2 +- metricbeat/module/docker/container/data.go | 23 ++++++++++++-- 5 files changed, 69 insertions(+), 17 deletions(-) diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index 657ea61828d2..2582770b65d0 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -10,14 +10,21 @@ #========================== Modules configuration ============================ metricbeat.modules: +#------------------------------- Docker Module ------------------------------- +- module: docker + metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + hosts: ["unix:///var/run/docker.sock"] + enabled: true + period: 10s + #------------------------------- System Module ------------------------------- -- module: system - metricsets: +#- module: system + #metricsets: # CPU stats - - cpu + #- cpu # System Load stats - - load + #- load # Per CPU core stats #- core @@ -26,25 +33,25 @@ metricbeat.modules: #- diskio # Per filesystem stats - - filesystem + #- filesystem # File system summary stats - - fsstat + #- fsstat # Memory stats - - memory + #- memory # Network stats - - network + #- network # Per process stats - - process + #- process # Sockets (linux only) #- socket - enabled: true - period: 10s - processes: ['.*'] + #enabled: true + #period: 10s + #processes: ['.*'] diff --git a/metricbeat/module/docker/container/_meta/data.json b/metricbeat/module/docker/container/_meta/data.json index 83ca1c4849df..3e36df399d65 100644 --- a/metricbeat/module/docker/container/_meta/data.json +++ b/metricbeat/module/docker/container/_meta/data.json @@ -31,5 +31,13 @@ "name": "container", "rtt": 115 }, + "health": { + "event_end_date": "2017-01-09T20:38:13.080472813+01:00", + "event_exit_code": 0, + "event_output": "0.005", + "event_start_date": "2017-01-09T20:38:12.999970865+01:00", + "failingstreak": 0, + "status": "healthy" + }, "type": "metricsets" -} \ No newline at end of file +} diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index cf56b0a142f8..032cdb8f17b1 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -40,3 +40,23 @@ type: long description: > Size of the files that have been created or changed since creation. + - name: health + type: group + description: > + Container health metrics. + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: long + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/container/container.go b/metricbeat/module/docker/container/container.go index 0606072cdfca..bfc0c32fa095 100644 --- a/metricbeat/module/docker/container/container.go +++ b/metricbeat/module/docker/container/container.go @@ -48,5 +48,5 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { if err != nil { return nil, err } - return eventsMapping(containers), nil + return eventsMapping(containers, m), nil } diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 86d4d17dd876..0ead59a039fa 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -6,18 +6,19 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/module/docker" + "strings" dc "github.com/fsouza/go-dockerclient" ) -func eventsMapping(containersList []dc.APIContainers) []common.MapStr { +func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} for _, container := range containersList { - myEvents = append(myEvents, eventMapping(&container)) + myEvents = append(myEvents, eventMapping(&container, m)) } return myEvents } -func eventMapping(cont *dc.APIContainers) common.MapStr { +func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { event := common.MapStr{ "created": common.Time(time.Unix(cont.Created, 0)), "id": cont.ID, @@ -31,7 +32,23 @@ func eventMapping(cont *dc.APIContainers) common.MapStr { "status": cont.Status, } + if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log)-1 + + health := common.MapStr{ + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event_start_date": container.State.Health.Log[last_event].Start, + "event_end_date": container.State.Health.Log[last_event].End, + "event_exit_code": container.State.Health.Log[last_event].ExitCode, + "event_output": container.State.Health.Log[last_event].Output, + } + event["health"] = health + } + labels := docker.DeDotLabels(cont.Labels) + if len(labels) > 0 { event["labels"] = labels } From 3e83526c1bcdb644cb69d580e9586513b48b5757 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 17:02:55 +0100 Subject: [PATCH 15/27] Rebase on top of elastic/beats:master --- metricbeat/docs/fields.asciidoc | 154 ++++++++ metricbeat/docs/modules/docker.asciidoc | 4 + metricbeat/docs/modules/docker/node.asciidoc | 19 + metricbeat/include/list.go | 1 + metricbeat/metricbeat.yml | 7 + .../module/docker/container/_meta/fields.yml | 33 +- metricbeat/module/docker/container/data.go | 4 + .../docker/api/types/container/config.go | 62 ++++ .../api/types/container/container_create.go | 21 ++ .../api/types/container/container_update.go | 17 + .../api/types/container/container_wait.go | 17 + .../docker/api/types/container/host_config.go | 333 ++++++++++++++++++ .../api/types/container/hostconfig_unix.go | 81 +++++ .../api/types/container/hostconfig_windows.go | 87 +++++ .../docker/api/types/mount/mount.go | 113 ++++++ .../docker/api/types/swarm/common.go | 27 ++ .../docker/api/types/swarm/container.go | 46 +++ .../docker/api/types/swarm/network.go | 111 ++++++ .../github.com/docker/api/types/swarm/node.go | 114 ++++++ .../docker/api/types/swarm/secret.go | 31 ++ .../docker/api/types/swarm/service.go | 105 ++++++ .../docker/api/types/swarm/swarm.go | 197 +++++++++++ .../github.com/docker/api/types/swarm/task.go | 128 +++++++ .../github.com/fsouza/go-dockerclient/node.go | 128 ------- .../fsouza/go-dockerclient/service.go | 157 --------- 25 files changed, 1696 insertions(+), 301 deletions(-) create mode 100644 metricbeat/docs/modules/docker/node.asciidoc create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 1afc271c34d4..40103b1cf38c 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1071,6 +1071,44 @@ type: long Size of the files that have been created or changed since creation. +[float] +== health Fields + +Container health metrics. + + +[float] +=== docker.container.event_end_date + +type: date + +Healthcheck end date + + +[float] +=== docker.container.event_start_date + +type: date + +Healthcheck start date + + +[float] +=== docker.container.event_output + +type: long + +Healthcheck output + + +[float] +=== docker.container.event_exit_code + +type: integer + +Healthcheck status code + + [float] == cpu Fields @@ -1416,6 +1454,122 @@ type: long Total number of outgoing packets. +[float] +== container Fields + +Docker container metrics. + + + +[float] +=== docker.container.command + +type: keyword + +Command that was executed in the Docker container. + + +[float] +=== docker.container.created + +type: date + +Date when the container was created. + + +[float] +=== docker.container.id + +type: keyword + +Unique container id. + + +[float] +=== docker.container.image + +type: keyword + +Name of the image the container was built on. + + +[float] +=== docker.container.name + +type: keyword + +Container name. + + +[float] +=== docker.container.status + +type: keyword + +Container status. + + +[float] +== size Fields + +Container size metrics. + + + +[float] +=== docker.container.size.root_fs + +type: long + +Total size of all the files in the container. + + +[float] +=== docker.container.size.rw + +type: long + +Size of the files that have been created or changed since creation. + + +[float] +== health Fields + +Container health metrics. + + +[float] +=== docker.container.event_end_date + +type: date + +Healthcheck end date + + +[float] +=== docker.container.event_start_date + +type: date + +Healthcheck start date + + +[float] +=== docker.container.event_output + +type: long + +Healthcheck output + + +[float] +=== docker.container.event_exit_code + +type: integer + +Healthcheck status code + + [[exported-fields-haproxy]] == HAProxy Fields diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index e743c67e7037..a50007adc8b9 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -50,6 +50,8 @@ The following metricsets are available: * <> +* <> + include::docker/container.asciidoc[] include::docker/cpu.asciidoc[] @@ -62,3 +64,5 @@ include::docker/memory.asciidoc[] include::docker/network.asciidoc[] +include::docker/node.asciidoc[] + diff --git a/metricbeat/docs/modules/docker/node.asciidoc b/metricbeat/docs/modules/docker/node.asciidoc new file mode 100644 index 000000000000..e1d2341d0d22 --- /dev/null +++ b/metricbeat/docs/modules/docker/node.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-docker-node]] +include::../../../module/docker/node/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/docker/node/_meta/data.json[] +---- diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 3d88f2937d8d..2c3111f6cc48 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -21,6 +21,7 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/info" _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" + _ "github.com/elastic/beats/metricbeat/module/docker/node" _ "github.com/elastic/beats/metricbeat/module/haproxy" _ "github.com/elastic/beats/metricbeat/module/haproxy/info" _ "github.com/elastic/beats/metricbeat/module/haproxy/stat" diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index 2582770b65d0..e024185f5ce6 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -17,6 +17,13 @@ metricbeat.modules: enabled: true period: 10s + # To connect to Docker over TLS you must specify a client and CA certificate. + #ssl: + #certificate_authority: "/etc/pki/root/ca.pem" + #certificate: "/etc/pki/client/cert.pem" + #key: "/etc/pki/client/cert.key" + + #------------------------------- System Module ------------------------------- #- module: system #metricsets: diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index 032cdb8f17b1..d6ad46412f4b 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -44,19 +44,20 @@ type: group description: > Container health metrics. - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: long - description: > - Healthcheck output - - name: event_exit_code - type: integer - description: > - Healthcheck status code + fields: + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: long + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 0ead59a039fa..783b8e6debf3 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -8,6 +8,7 @@ import ( "strings" dc "github.com/fsouza/go-dockerclient" + "fmt" ) func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { @@ -33,6 +34,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { } if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + fmt.Println("HealthCheck !!\n") container, _ := m.dockerClient.InspectContainer(cont.ID) last_event := len(container.State.Health.Log)-1 @@ -45,6 +47,8 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "event_output": container.State.Health.Log[last_event].Output, } event["health"] = health + } else { + fmt.Println("No health check lets continue\n") } labels := docker.DeDotLabels(cont.Labels) diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go new file mode 100644 index 000000000000..fc050e5dba9d --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go @@ -0,0 +1,62 @@ +package container + +import ( + "time" + + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" +) + +// HealthConfig holds configuration settings for the HEALTHCHECK feature. +type HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `json:",omitempty"` + + // Zero means to inherit. Durations are expressed as integer nanoseconds. + Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. + Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. + + // Retries is the number of consecutive failures needed to consider a container as unhealthy. + // Zero means inherit. + Retries int `json:",omitempty"` +} + +// Config contains the configuration data about a container. +// It should hold only portable information about the container. +// Here, "portable" means "independent from the host we are running on". +// Non-portable information *should* appear in HostConfig. +// All fields added to this struct must be marked `omitempty` to keep getting +// predictable hashes from the old `v1Compatibility` configuration. +type Config struct { + Hostname string // Hostname + Domainname string // Domainname + User string // User that will run the command(s) inside the container, also support user:group + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStdout bool // Attach the standard output + AttachStderr bool // Attach the standard error + ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports + Tty bool // Attach standard streams to a tty, including stdin if it is not closed. + OpenStdin bool // Open stdin + StdinOnce bool // If true, close stdin after the 1 attached client disconnects. + Env []string // List of environment variable to set in the container + Cmd strslice.StrSlice // Command to run when starting the container + Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy + ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific) + Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) + Volumes map[string]struct{} // List of volumes (mounts) used for the container + WorkingDir string // Current directory (PWD) in the command will be launched + Entrypoint strslice.StrSlice // Entrypoint to run when starting the container + NetworkDisabled bool `json:",omitempty"` // Is network disabled + MacAddress string `json:",omitempty"` // Mac Address of the container + OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile + Labels map[string]string // List of labels set to this container + StopSignal string `json:",omitempty"` // Signal to stop a container + StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container + Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go new file mode 100644 index 000000000000..c95023b814dc --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go @@ -0,0 +1,21 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerCreateCreatedBody container create created body +// swagger:model ContainerCreateCreatedBody +type ContainerCreateCreatedBody struct { + + // The ID of the created container + // Required: true + ID string `json:"Id"` + + // Warnings encountered when creating the container + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go new file mode 100644 index 000000000000..2339366fbd19 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go @@ -0,0 +1,17 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerUpdateOKBody container update o k body +// swagger:model ContainerUpdateOKBody +type ContainerUpdateOKBody struct { + + // warnings + // Required: true + Warnings []string `json:"Warnings"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go new file mode 100644 index 000000000000..77ecdbaf7aed --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go @@ -0,0 +1,17 @@ +package container + +// ---------------------------------------------------------------------------- +// DO NOT EDIT THIS FILE +// This file was generated by `swagger generate operation` +// +// See hack/generate-swagger-api.sh +// ---------------------------------------------------------------------------- + +// ContainerWaitOKBody container wait o k body +// swagger:model ContainerWaitOKBody +type ContainerWaitOKBody struct { + + // Exit code of the container + // Required: true + StatusCode int64 `json:"StatusCode"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go new file mode 100644 index 000000000000..d34fa1405cf0 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go @@ -0,0 +1,333 @@ +package container + +import ( + "strings" + + "github.com/docker/docker/api/types/blkiodev" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/go-connections/nat" + "github.com/docker/go-units" +) + +// NetworkMode represents the container network stack. +type NetworkMode string + +// Isolation represents the isolation technology of a container. The supported +// values are platform specific +type Isolation string + +// IsDefault indicates the default isolation technology of a container. On Linux this +// is the native driver. On Windows, this is a Windows Server Container. +func (i Isolation) IsDefault() bool { + return strings.ToLower(string(i)) == "default" || string(i) == "" +} + +// IpcMode represents the container ipc stack. +type IpcMode string + +// IsPrivate indicates whether the container uses its private ipc stack. +func (n IpcMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsHost indicates whether the container uses the host's ipc stack. +func (n IpcMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether the container uses a container's ipc stack. +func (n IpcMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the ipc stack is valid. +func (n IpcMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + case "container": + if len(parts) != 2 || parts[1] == "" { + return false + } + default: + return false + } + return true +} + +// Container returns the name of the container ipc stack is going to be used. +func (n IpcMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UsernsMode represents userns mode in the container. +type UsernsMode string + +// IsHost indicates whether the container uses the host's userns. +func (n UsernsMode) IsHost() bool { + return n == "host" +} + +// IsPrivate indicates whether the container uses the a private userns. +func (n UsernsMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// Valid indicates whether the userns is valid. +func (n UsernsMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// CgroupSpec represents the cgroup to use for the container. +type CgroupSpec string + +// IsContainer indicates whether the container is using another container cgroup +func (c CgroupSpec) IsContainer() bool { + parts := strings.SplitN(string(c), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the cgroup spec is valid. +func (c CgroupSpec) Valid() bool { + return c.IsContainer() || c == "" +} + +// Container returns the name of the container whose cgroup will be used. +func (c CgroupSpec) Container() string { + parts := strings.SplitN(string(c), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// UTSMode represents the UTS namespace of the container. +type UTSMode string + +// IsPrivate indicates whether the container uses its private UTS namespace. +func (n UTSMode) IsPrivate() bool { + return !(n.IsHost()) +} + +// IsHost indicates whether the container uses the host's UTS namespace. +func (n UTSMode) IsHost() bool { + return n == "host" +} + +// Valid indicates whether the UTS namespace is valid. +func (n UTSMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + default: + return false + } + return true +} + +// PidMode represents the pid namespace of the container. +type PidMode string + +// IsPrivate indicates whether the container uses its own new pid namespace. +func (n PidMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsHost indicates whether the container uses the host's pid namespace. +func (n PidMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether the container uses a container's pid namespace. +func (n PidMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// Valid indicates whether the pid namespace is valid. +func (n PidMode) Valid() bool { + parts := strings.Split(string(n), ":") + switch mode := parts[0]; mode { + case "", "host": + case "container": + if len(parts) != 2 || parts[1] == "" { + return false + } + default: + return false + } + return true +} + +// Container returns the name of the container whose pid namespace is going to be used. +func (n PidMode) Container() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// DeviceMapping represents the device mapping between the host and the container. +type DeviceMapping struct { + PathOnHost string + PathInContainer string + CgroupPermissions string +} + +// RestartPolicy represents the restart policies of the container. +type RestartPolicy struct { + Name string + MaximumRetryCount int +} + +// IsNone indicates whether the container has the "no" restart policy. +// This means the container will not automatically restart when exiting. +func (rp *RestartPolicy) IsNone() bool { + return rp.Name == "no" || rp.Name == "" +} + +// IsAlways indicates whether the container has the "always" restart policy. +// This means the container will automatically restart regardless of the exit status. +func (rp *RestartPolicy) IsAlways() bool { + return rp.Name == "always" +} + +// IsOnFailure indicates whether the container has the "on-failure" restart policy. +// This means the container will automatically restart of exiting with a non-zero exit status. +func (rp *RestartPolicy) IsOnFailure() bool { + return rp.Name == "on-failure" +} + +// IsUnlessStopped indicates whether the container has the +// "unless-stopped" restart policy. This means the container will +// automatically restart unless user has put it to stopped state. +func (rp *RestartPolicy) IsUnlessStopped() bool { + return rp.Name == "unless-stopped" +} + +// IsSame compares two RestartPolicy to see if they are the same +func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { + return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount +} + +// LogConfig represents the logging configuration of the container. +type LogConfig struct { + Type string + Config map[string]string +} + +// Resources contains container's resources (cgroups config, ulimits...) +type Resources struct { + // Applicable to all platforms + CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) + Memory int64 // Memory limit (in bytes) + NanoCPUs int64 `json:"NanoCpus"` // CPU quota in units of 10-9 CPUs. + + // Applicable to UNIX platforms + CgroupParent string // Parent cgroup. + BlkioWeight uint16 // Block IO weight (relative weight vs. other containers) + BlkioWeightDevice []*blkiodev.WeightDevice + BlkioDeviceReadBps []*blkiodev.ThrottleDevice + BlkioDeviceWriteBps []*blkiodev.ThrottleDevice + BlkioDeviceReadIOps []*blkiodev.ThrottleDevice + BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice + CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period + CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota + CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` // CPU real-time period + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` // CPU real-time runtime + CpusetCpus string // CpusetCpus 0-2, 0,1 + CpusetMems string // CpusetMems 0-2, 0,1 + Devices []DeviceMapping // List of devices to map inside the container + DiskQuota int64 // Disk limit (in bytes) + KernelMemory int64 // Kernel memory limit (in bytes) + MemoryReservation int64 // Memory soft limit (in bytes) + MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap + MemorySwappiness *int64 // Tuning container memory swappiness behaviour + OomKillDisable *bool // Whether to disable OOM Killer or not + PidsLimit int64 // Setting pids limit for a container + Ulimits []*units.Ulimit // List of ulimits to be set in the container + + // Applicable to Windows + CPUCount int64 `json:"CpuCount"` // CPU count + CPUPercent int64 `json:"CpuPercent"` // CPU percent + IOMaximumIOps uint64 // Maximum IOps for the container system drive + IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive +} + +// UpdateConfig holds the mutable attributes of a Container. +// Those attributes can be updated at runtime. +type UpdateConfig struct { + // Contains container's resources (cgroups, ulimits) + Resources + RestartPolicy RestartPolicy +} + +// HostConfig the non-portable Config structure of a container. +// Here, "non-portable" means "dependent of the host we are running on". +// Portable information *should* appear in Config. +type HostConfig struct { + // Applicable to all platforms + Binds []string // List of volume bindings for this container + ContainerIDFile string // File (path) where the containerId is written + LogConfig LogConfig // Configuration of the logs for this container + NetworkMode NetworkMode // Network mode to use for the container + PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host + RestartPolicy RestartPolicy // Restart policy to be used for the container + AutoRemove bool // Automatically remove container when it exits + VolumeDriver string // Name of the volume driver used to mount volumes + VolumesFrom []string // List of volumes to take from other container + + // Applicable to UNIX platforms + CapAdd strslice.StrSlice // List of kernel capabilities to add to the container + CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container + DNS []string `json:"Dns"` // List of DNS server to lookup + DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for + DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for + ExtraHosts []string // List of extra hosts + GroupAdd []string // List of additional groups that the container process will run as + IpcMode IpcMode // IPC namespace to use for the container + Cgroup CgroupSpec // Cgroup to use for the container + Links []string // List of links (in the name:alias form) + OomScoreAdj int // Container preference for OOM-killing + PidMode PidMode // PID namespace to use for the container + Privileged bool // Is the container in privileged mode + PublishAllPorts bool // Should docker publish all exposed port for the container + ReadonlyRootfs bool // Is the container root filesystem in read-only + SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. + StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. + Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container + UTSMode UTSMode // UTS namespace to use for the container + UsernsMode UsernsMode // The user namespace to use for the container + ShmSize int64 // Total shm memory usage + Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container + Runtime string `json:",omitempty"` // Runtime to use with this container + + // Applicable to Windows + ConsoleSize [2]uint // Initial console size (height,width) + Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) + + // Contains container's resources (cgroups, ulimits) + Resources + + // Mounts specs used by the container + Mounts []mount.Mount `json:",omitempty"` + + // Run a custom init inside the container, if null, use the daemon's configured settings + Init *bool `json:",omitempty"` + + // Custom init path + InitPath string `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go new file mode 100644 index 000000000000..9fb79bed6f39 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go @@ -0,0 +1,81 @@ +// +build !windows + +package container + +import "strings" + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() +} + +// IsPrivate indicates whether container uses its private network stack. +func (n NetworkMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// IsDefault indicates whether container uses the default network stack. +func (n NetworkMode) IsDefault() bool { + return n == "default" +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsBridge() { + return "bridge" + } else if n.IsHost() { + return "host" + } else if n.IsContainer() { + return "container" + } else if n.IsNone() { + return "none" + } else if n.IsDefault() { + return "default" + } else if n.IsUserDefined() { + return n.UserDefined() + } + return "" +} + +// IsBridge indicates whether container uses the bridge network stack +func (n NetworkMode) IsBridge() bool { + return n == "bridge" +} + +// IsHost indicates whether container uses the host network stack. +func (n NetworkMode) IsHost() bool { + return n == "host" +} + +// IsContainer indicates whether container uses a container network stack. +func (n NetworkMode) IsContainer() bool { + parts := strings.SplitN(string(n), ":", 2) + return len(parts) > 1 && parts[0] == "container" +} + +// IsNone indicates whether container isn't using a network stack. +func (n NetworkMode) IsNone() bool { + return n == "none" +} + +// ConnectedContainer is the id of the container which network this container is connected to. +func (n NetworkMode) ConnectedContainer() string { + parts := strings.SplitN(string(n), ":", 2) + if len(parts) > 1 { + return parts[1] + } + return "" +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() +} + +//UserDefined indicates user-created network +func (n NetworkMode) UserDefined() string { + if n.IsUserDefined() { + return string(n) + } + return "" +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go new file mode 100644 index 000000000000..0ee332ba6899 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go @@ -0,0 +1,87 @@ +package container + +import ( + "strings" +) + +// IsDefault indicates whether container uses the default network stack. +func (n NetworkMode) IsDefault() bool { + return n == "default" +} + +// IsNone indicates whether container isn't using a network stack. +func (n NetworkMode) IsNone() bool { + return n == "none" +} + +// IsContainer indicates whether container uses a container network stack. +// Returns false as windows doesn't support this mode +func (n NetworkMode) IsContainer() bool { + return false +} + +// IsBridge indicates whether container uses the bridge network stack +// in windows it is given the name NAT +func (n NetworkMode) IsBridge() bool { + return n == "nat" +} + +// IsHost indicates whether container uses the host network stack. +// returns false as this is not supported by windows +func (n NetworkMode) IsHost() bool { + return false +} + +// IsPrivate indicates whether container uses its private network stack. +func (n NetworkMode) IsPrivate() bool { + return !(n.IsHost() || n.IsContainer()) +} + +// ConnectedContainer is the id of the container which network this container is connected to. +// Returns blank string on windows +func (n NetworkMode) ConnectedContainer() string { + return "" +} + +// IsUserDefined indicates user-created network +func (n NetworkMode) IsUserDefined() bool { + return !n.IsDefault() && !n.IsNone() && !n.IsBridge() +} + +// IsHyperV indicates the use of a Hyper-V partition for isolation +func (i Isolation) IsHyperV() bool { + return strings.ToLower(string(i)) == "hyperv" +} + +// IsProcess indicates the use of process isolation +func (i Isolation) IsProcess() bool { + return strings.ToLower(string(i)) == "process" +} + +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() || i.IsHyperV() || i.IsProcess() +} + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + if n.IsDefault() { + return "default" + } else if n.IsBridge() { + return "nat" + } else if n.IsNone() { + return "none" + } else if n.IsUserDefined() { + return n.UserDefined() + } + + return "" +} + +//UserDefined indicates user-created network +func (n NetworkMode) UserDefined() string { + if n.IsUserDefined() { + return string(n) + } + return "" +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go new file mode 100644 index 000000000000..31f2365b8ec0 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go @@ -0,0 +1,113 @@ +package mount + +import ( + "os" +) + +// Type represents the type of a mount. +type Type string + +// Type constants +const ( + // TypeBind is the type for mounting host dir + TypeBind Type = "bind" + // TypeVolume is the type for remote storage volumes + TypeVolume Type = "volume" + // TypeTmpfs is the type for mounting tmpfs + TypeTmpfs Type = "tmpfs" +) + +// Mount represents a mount (volume). +type Mount struct { + Type Type `json:",omitempty"` + // Source specifies the name of the mount. Depending on mount type, this + // may be a volume name or a host path, or even ignored. + // Source is not supported for tmpfs (must be an empty value) + Source string `json:",omitempty"` + Target string `json:",omitempty"` + ReadOnly bool `json:",omitempty"` + + BindOptions *BindOptions `json:",omitempty"` + VolumeOptions *VolumeOptions `json:",omitempty"` + TmpfsOptions *TmpfsOptions `json:",omitempty"` +} + +// Propagation represents the propagation of a mount. +type Propagation string + +const ( + // PropagationRPrivate RPRIVATE + PropagationRPrivate Propagation = "rprivate" + // PropagationPrivate PRIVATE + PropagationPrivate Propagation = "private" + // PropagationRShared RSHARED + PropagationRShared Propagation = "rshared" + // PropagationShared SHARED + PropagationShared Propagation = "shared" + // PropagationRSlave RSLAVE + PropagationRSlave Propagation = "rslave" + // PropagationSlave SLAVE + PropagationSlave Propagation = "slave" +) + +// Propagations is the list of all valid mount propagations +var Propagations = []Propagation{ + PropagationRPrivate, + PropagationPrivate, + PropagationRShared, + PropagationShared, + PropagationRSlave, + PropagationSlave, +} + +// BindOptions defines options specific to mounts of type "bind". +type BindOptions struct { + Propagation Propagation `json:",omitempty"` +} + +// VolumeOptions represents the options for a mount of type volume. +type VolumeOptions struct { + NoCopy bool `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + DriverConfig *Driver `json:",omitempty"` +} + +// Driver represents a volume driver. +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} + +// TmpfsOptions defines options specific to mounts of type "tmpfs". +type TmpfsOptions struct { + // Size sets the size of the tmpfs, in bytes. + // + // This will be converted to an operating system specific value + // depending on the host. For example, on linux, it will be convered to + // use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with + // docker, uses a straight byte value. + // + // Percentages are not supported. + SizeBytes int64 `json:",omitempty"` + // Mode of the tmpfs upon creation + Mode os.FileMode `json:",omitempty"` + + // TODO(stevvooe): There are several more tmpfs flags, specified in the + // daemon, that are accepted. Only the most basic are added for now. + // + // From docker/docker/pkg/mount/flags.go: + // + // var validFlags = map[string]bool{ + // "": true, + // "size": true, X + // "mode": true, X + // "uid": true, + // "gid": true, + // "nr_inodes": true, + // "nr_blocks": true, + // "mpol": true, + // } + // + // Some of these may be straightforward to add, but others, such as + // uid/gid have implications in a clustered system. +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go new file mode 100644 index 000000000000..64a648bad15a --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go @@ -0,0 +1,27 @@ +package swarm + +import "time" + +// Version represents the internal object version. +type Version struct { + Index uint64 `json:",omitempty"` +} + +// Meta is a base object inherited by most of the other once. +type Meta struct { + Version Version `json:",omitempty"` + CreatedAt time.Time `json:",omitempty"` + UpdatedAt time.Time `json:",omitempty"` +} + +// Annotations represents how to describe an object. +type Annotations struct { + Name string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` +} + +// Driver represents a driver (network, logging). +type Driver struct { + Name string `json:",omitempty"` + Options map[string]string `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go new file mode 100644 index 000000000000..4ab476ccc392 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go @@ -0,0 +1,46 @@ +package swarm + +import ( + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" +) + +// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) +// Detailed documentation is available in: +// http://man7.org/linux/man-pages/man5/resolv.conf.5.html +// `nameserver`, `search`, `options` have been supported. +// TODO: `domain` is not supported yet. +type DNSConfig struct { + // Nameservers specifies the IP addresses of the name servers + Nameservers []string `json:",omitempty"` + // Search specifies the search list for host-name lookup + Search []string `json:",omitempty"` + // Options allows certain internal resolver variables to be modified + Options []string `json:",omitempty"` +} + +// ContainerSpec represents the spec of a container. +type ContainerSpec struct { + Image string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Command []string `json:",omitempty"` + Args []string `json:",omitempty"` + Hostname string `json:",omitempty"` + Env []string `json:",omitempty"` + Dir string `json:",omitempty"` + User string `json:",omitempty"` + Groups []string `json:",omitempty"` + TTY bool `json:",omitempty"` + OpenStdin bool `json:",omitempty"` + Mounts []mount.Mount `json:",omitempty"` + StopGracePeriod *time.Duration `json:",omitempty"` + Healthcheck *container.HealthConfig `json:",omitempty"` + // The format of extra hosts on swarmkit is specified in: + // http://man7.org/linux/man-pages/man5/hosts.5.html + // IP_address canonical_hostname [aliases...] + Hosts []string `json:",omitempty"` + DNSConfig *DNSConfig `json:",omitempty"` + Secrets []*SecretReference `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go new file mode 100644 index 000000000000..5a5e11bdba59 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go @@ -0,0 +1,111 @@ +package swarm + +// Endpoint represents an endpoint. +type Endpoint struct { + Spec EndpointSpec `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` + VirtualIPs []EndpointVirtualIP `json:",omitempty"` +} + +// EndpointSpec represents the spec of an endpoint. +type EndpointSpec struct { + Mode ResolutionMode `json:",omitempty"` + Ports []PortConfig `json:",omitempty"` +} + +// ResolutionMode represents a resolution mode. +type ResolutionMode string + +const ( + // ResolutionModeVIP VIP + ResolutionModeVIP ResolutionMode = "vip" + // ResolutionModeDNSRR DNSRR + ResolutionModeDNSRR ResolutionMode = "dnsrr" +) + +// PortConfig represents the config of a port. +type PortConfig struct { + Name string `json:",omitempty"` + Protocol PortConfigProtocol `json:",omitempty"` + // TargetPort is the port inside the container + TargetPort uint32 `json:",omitempty"` + // PublishedPort is the port on the swarm hosts + PublishedPort uint32 `json:",omitempty"` + // PublishMode is the mode in which port is published + PublishMode PortConfigPublishMode `json:",omitempty"` +} + +// PortConfigPublishMode represents the mode in which the port is to +// be published. +type PortConfigPublishMode string + +const ( + // PortConfigPublishModeIngress is used for ports published + // for ingress load balancing using routing mesh. + PortConfigPublishModeIngress PortConfigPublishMode = "ingress" + // PortConfigPublishModeHost is used for ports published + // for direct host level access on the host where the task is running. + PortConfigPublishModeHost PortConfigPublishMode = "host" +) + +// PortConfigProtocol represents the protocol of a port. +type PortConfigProtocol string + +const ( + // TODO(stevvooe): These should be used generally, not just for PortConfig. + + // PortConfigProtocolTCP TCP + PortConfigProtocolTCP PortConfigProtocol = "tcp" + // PortConfigProtocolUDP UDP + PortConfigProtocolUDP PortConfigProtocol = "udp" +) + +// EndpointVirtualIP represents the virtual ip of a port. +type EndpointVirtualIP struct { + NetworkID string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Network represents a network. +type Network struct { + ID string + Meta + Spec NetworkSpec `json:",omitempty"` + DriverState Driver `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` +} + +// NetworkSpec represents the spec of a network. +type NetworkSpec struct { + Annotations + DriverConfiguration *Driver `json:",omitempty"` + IPv6Enabled bool `json:",omitempty"` + Internal bool `json:",omitempty"` + Attachable bool `json:",omitempty"` + IPAMOptions *IPAMOptions `json:",omitempty"` +} + +// NetworkAttachmentConfig represents the configuration of a network attachment. +type NetworkAttachmentConfig struct { + Target string `json:",omitempty"` + Aliases []string `json:",omitempty"` +} + +// NetworkAttachment represents a network attachment. +type NetworkAttachment struct { + Network Network `json:",omitempty"` + Addresses []string `json:",omitempty"` +} + +// IPAMOptions represents ipam options. +type IPAMOptions struct { + Driver Driver `json:",omitempty"` + Configs []IPAMConfig `json:",omitempty"` +} + +// IPAMConfig represents ipam configuration. +type IPAMConfig struct { + Subnet string `json:",omitempty"` + Range string `json:",omitempty"` + Gateway string `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go new file mode 100644 index 000000000000..379e17a779ac --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go @@ -0,0 +1,114 @@ +package swarm + +// Node represents a node. +type Node struct { + ID string + Meta + // Spec defines the desired state of the node as specified by the user. + // The system will honor this and will *never* modify it. + Spec NodeSpec `json:",omitempty"` + // Description encapsulates the properties of the Node as reported by the + // agent. + Description NodeDescription `json:",omitempty"` + // Status provides the current status of the node, as seen by the manager. + Status NodeStatus `json:",omitempty"` + // ManagerStatus provides the current status of the node's manager + // component, if the node is a manager. + ManagerStatus *ManagerStatus `json:",omitempty"` +} + +// NodeSpec represents the spec of a node. +type NodeSpec struct { + Annotations + Role NodeRole `json:",omitempty"` + Availability NodeAvailability `json:",omitempty"` +} + +// NodeRole represents the role of a node. +type NodeRole string + +const ( + // NodeRoleWorker WORKER + NodeRoleWorker NodeRole = "worker" + // NodeRoleManager MANAGER + NodeRoleManager NodeRole = "manager" +) + +// NodeAvailability represents the availability of a node. +type NodeAvailability string + +const ( + // NodeAvailabilityActive ACTIVE + NodeAvailabilityActive NodeAvailability = "active" + // NodeAvailabilityPause PAUSE + NodeAvailabilityPause NodeAvailability = "pause" + // NodeAvailabilityDrain DRAIN + NodeAvailabilityDrain NodeAvailability = "drain" +) + +// NodeDescription represents the description of a node. +type NodeDescription struct { + Hostname string `json:",omitempty"` + Platform Platform `json:",omitempty"` + Resources Resources `json:",omitempty"` + Engine EngineDescription `json:",omitempty"` +} + +// Platform represents the platform (Arch/OS). +type Platform struct { + Architecture string `json:",omitempty"` + OS string `json:",omitempty"` +} + +// EngineDescription represents the description of an engine. +type EngineDescription struct { + EngineVersion string `json:",omitempty"` + Labels map[string]string `json:",omitempty"` + Plugins []PluginDescription `json:",omitempty"` +} + +// PluginDescription represents the description of an engine plugin. +type PluginDescription struct { + Type string `json:",omitempty"` + Name string `json:",omitempty"` +} + +// NodeStatus represents the status of a node. +type NodeStatus struct { + State NodeState `json:",omitempty"` + Message string `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// Reachability represents the reachability of a node. +type Reachability string + +const ( + // ReachabilityUnknown UNKNOWN + ReachabilityUnknown Reachability = "unknown" + // ReachabilityUnreachable UNREACHABLE + ReachabilityUnreachable Reachability = "unreachable" + // ReachabilityReachable REACHABLE + ReachabilityReachable Reachability = "reachable" +) + +// ManagerStatus represents the status of a manager. +type ManagerStatus struct { + Leader bool `json:",omitempty"` + Reachability Reachability `json:",omitempty"` + Addr string `json:",omitempty"` +} + +// NodeState represents the state of a node. +type NodeState string + +const ( + // NodeStateUnknown UNKNOWN + NodeStateUnknown NodeState = "unknown" + // NodeStateDown DOWN + NodeStateDown NodeState = "down" + // NodeStateReady READY + NodeStateReady NodeState = "ready" + // NodeStateDisconnected DISCONNECTED + NodeStateDisconnected NodeState = "disconnected" +) diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go new file mode 100644 index 000000000000..fdb2388888d9 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go @@ -0,0 +1,31 @@ +package swarm + +import "os" + +// Secret represents a secret. +type Secret struct { + ID string + Meta + Spec SecretSpec +} + +// SecretSpec represents a secret specification from a secret in swarm +type SecretSpec struct { + Annotations + Data []byte `json:",omitempty"` +} + +// SecretReferenceFileTarget is a file target in a secret reference +type SecretReferenceFileTarget struct { + Name string + UID string + GID string + Mode os.FileMode +} + +// SecretReference is a reference to a secret in swarm +type SecretReference struct { + File *SecretReferenceFileTarget + SecretID string + SecretName string +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go new file mode 100644 index 000000000000..04f59de862e5 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go @@ -0,0 +1,105 @@ +package swarm + +import "time" + +// Service represents a service. +type Service struct { + ID string + Meta + Spec ServiceSpec `json:",omitempty"` + PreviousSpec *ServiceSpec `json:",omitempty"` + Endpoint Endpoint `json:",omitempty"` + UpdateStatus *UpdateStatus `json:",omitempty"` +} + +// ServiceSpec represents the spec of a service. +type ServiceSpec struct { + Annotations + + // TaskTemplate defines how the service should construct new tasks when + // orchestrating this service. + TaskTemplate TaskSpec `json:",omitempty"` + Mode ServiceMode `json:",omitempty"` + UpdateConfig *UpdateConfig `json:",omitempty"` + + // Networks field in ServiceSpec is deprecated. The + // same field in TaskSpec should be used instead. + // This field will be removed in a future release. + Networks []NetworkAttachmentConfig `json:",omitempty"` + EndpointSpec *EndpointSpec `json:",omitempty"` +} + +// ServiceMode represents the mode of a service. +type ServiceMode struct { + Replicated *ReplicatedService `json:",omitempty"` + Global *GlobalService `json:",omitempty"` +} + +// UpdateState is the state of a service update. +type UpdateState string + +const ( + // UpdateStateUpdating is the updating state. + UpdateStateUpdating UpdateState = "updating" + // UpdateStatePaused is the paused state. + UpdateStatePaused UpdateState = "paused" + // UpdateStateCompleted is the completed state. + UpdateStateCompleted UpdateState = "completed" +) + +// UpdateStatus reports the status of a service update. +type UpdateStatus struct { + State UpdateState `json:",omitempty"` + StartedAt *time.Time `json:",omitempty"` + CompletedAt *time.Time `json:",omitempty"` + Message string `json:",omitempty"` +} + +// ReplicatedService is a kind of ServiceMode. +type ReplicatedService struct { + Replicas *uint64 `json:",omitempty"` +} + +// GlobalService is a kind of ServiceMode. +type GlobalService struct{} + +const ( + // UpdateFailureActionPause PAUSE + UpdateFailureActionPause = "pause" + // UpdateFailureActionContinue CONTINUE + UpdateFailureActionContinue = "continue" +) + +// UpdateConfig represents the update configuration. +type UpdateConfig struct { + // Maximum number of tasks to be updated in one iteration. + // 0 means unlimited parallelism. + Parallelism uint64 + + // Amount of time between updates. + Delay time.Duration `json:",omitempty"` + + // FailureAction is the action to take when an update failures. + FailureAction string `json:",omitempty"` + + // Monitor indicates how long to monitor a task for failure after it is + // created. If the task fails by ending up in one of the states + // REJECTED, COMPLETED, or FAILED, within Monitor from its creation, + // this counts as a failure. If it fails after Monitor, it does not + // count as a failure. If Monitor is unspecified, a default value will + // be used. + Monitor time.Duration `json:",omitempty"` + + // MaxFailureRatio is the fraction of tasks that may fail during + // an update before the failure action is invoked. Any task created by + // the current update which ends up in one of the states REJECTED, + // COMPLETED or FAILED within Monitor from its creation counts as a + // failure. The number of failures is divided by the number of tasks + // being updated, and if this fraction is greater than + // MaxFailureRatio, the failure action is invoked. + // + // If the failure action is CONTINUE, there is no effect. + // If the failure action is PAUSE, no more tasks will be updated until + // another update is started. + MaxFailureRatio float32 +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go new file mode 100644 index 000000000000..0b4221969605 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go @@ -0,0 +1,197 @@ +package swarm + +import "time" + +// ClusterInfo represents info about the cluster for outputing in "info" +// it contains the same information as "Swarm", but without the JoinTokens +type ClusterInfo struct { + ID string + Meta + Spec Spec +} + +// Swarm represents a swarm. +type Swarm struct { + ClusterInfo + JoinTokens JoinTokens +} + +// JoinTokens contains the tokens workers and managers need to join the swarm. +type JoinTokens struct { + // Worker is the join token workers may use to join the swarm. + Worker string + // Manager is the join token managers may use to join the swarm. + Manager string +} + +// Spec represents the spec of a swarm. +type Spec struct { + Annotations + + Orchestration OrchestrationConfig `json:",omitempty"` + Raft RaftConfig `json:",omitempty"` + Dispatcher DispatcherConfig `json:",omitempty"` + CAConfig CAConfig `json:",omitempty"` + TaskDefaults TaskDefaults `json:",omitempty"` + EncryptionConfig EncryptionConfig `json:",omitempty"` +} + +// OrchestrationConfig represents orchestration configuration. +type OrchestrationConfig struct { + // TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or + // node. If negative, never remove completed or failed tasks. + TaskHistoryRetentionLimit *int64 `json:",omitempty"` +} + +// TaskDefaults parameterizes cluster-level task creation with default values. +type TaskDefaults struct { + // LogDriver selects the log driver to use for tasks created in the + // orchestrator if unspecified by a service. + // + // Updating this value will only have an affect on new tasks. Old tasks + // will continue use their previously configured log driver until + // recreated. + LogDriver *Driver `json:",omitempty"` +} + +// EncryptionConfig controls at-rest encryption of data and keys. +type EncryptionConfig struct { + // AutoLockManagers specifies whether or not managers TLS keys and raft data + // should be encrypted at rest in such a way that they must be unlocked + // before the manager node starts up again. + AutoLockManagers bool +} + +// RaftConfig represents raft configuration. +type RaftConfig struct { + // SnapshotInterval is the number of log entries between snapshots. + SnapshotInterval uint64 `json:",omitempty"` + + // KeepOldSnapshots is the number of snapshots to keep beyond the + // current snapshot. + KeepOldSnapshots *uint64 `json:",omitempty"` + + // LogEntriesForSlowFollowers is the number of log entries to keep + // around to sync up slow followers after a snapshot is created. + LogEntriesForSlowFollowers uint64 `json:",omitempty"` + + // ElectionTick is the number of ticks that a follower will wait for a message + // from the leader before becoming a candidate and starting an election. + // ElectionTick must be greater than HeartbeatTick. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + ElectionTick int + + // HeartbeatTick is the number of ticks between heartbeats. Every + // HeartbeatTick ticks, the leader will send a heartbeat to the + // followers. + // + // A tick currently defaults to one second, so these translate directly to + // seconds currently, but this is NOT guaranteed. + HeartbeatTick int +} + +// DispatcherConfig represents dispatcher configuration. +type DispatcherConfig struct { + // HeartbeatPeriod defines how often agent should send heartbeats to + // dispatcher. + HeartbeatPeriod time.Duration `json:",omitempty"` +} + +// CAConfig represents CA configuration. +type CAConfig struct { + // NodeCertExpiry is the duration certificates should be issued for + NodeCertExpiry time.Duration `json:",omitempty"` + + // ExternalCAs is a list of CAs to which a manager node will make + // certificate signing requests for node certificates. + ExternalCAs []*ExternalCA `json:",omitempty"` +} + +// ExternalCAProtocol represents type of external CA. +type ExternalCAProtocol string + +// ExternalCAProtocolCFSSL CFSSL +const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" + +// ExternalCA defines external CA to be used by the cluster. +type ExternalCA struct { + // Protocol is the protocol used by this external CA. + Protocol ExternalCAProtocol + + // URL is the URL where the external CA can be reached. + URL string + + // Options is a set of additional key/value pairs whose interpretation + // depends on the specified CA type. + Options map[string]string `json:",omitempty"` +} + +// InitRequest is the request used to init a swarm. +type InitRequest struct { + ListenAddr string + AdvertiseAddr string + ForceNewCluster bool + Spec Spec + AutoLockManagers bool +} + +// JoinRequest is the request used to join a swarm. +type JoinRequest struct { + ListenAddr string + AdvertiseAddr string + RemoteAddrs []string + JoinToken string // accept by secret +} + +// UnlockRequest is the request used to unlock a swarm. +type UnlockRequest struct { + // UnlockKey is the unlock key in ASCII-armored format. + UnlockKey string +} + +// LocalNodeState represents the state of the local node. +type LocalNodeState string + +const ( + // LocalNodeStateInactive INACTIVE + LocalNodeStateInactive LocalNodeState = "inactive" + // LocalNodeStatePending PENDING + LocalNodeStatePending LocalNodeState = "pending" + // LocalNodeStateActive ACTIVE + LocalNodeStateActive LocalNodeState = "active" + // LocalNodeStateError ERROR + LocalNodeStateError LocalNodeState = "error" + // LocalNodeStateLocked LOCKED + LocalNodeStateLocked LocalNodeState = "locked" +) + +// Info represents generic information about swarm. +type Info struct { + NodeID string + NodeAddr string + + LocalNodeState LocalNodeState + ControlAvailable bool + Error string + + RemoteManagers []Peer + Nodes int + Managers int + + Cluster ClusterInfo +} + +// Peer represents a peer. +type Peer struct { + NodeID string + Addr string +} + +// UpdateFlags contains flags for SwarmUpdate. +type UpdateFlags struct { + RotateWorkerToken bool + RotateManagerToken bool + RotateManagerUnlockKey bool +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go new file mode 100644 index 000000000000..ace12cc89fa3 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go @@ -0,0 +1,128 @@ +package swarm + +import "time" + +// TaskState represents the state of a task. +type TaskState string + +const ( + // TaskStateNew NEW + TaskStateNew TaskState = "new" + // TaskStateAllocated ALLOCATED + TaskStateAllocated TaskState = "allocated" + // TaskStatePending PENDING + TaskStatePending TaskState = "pending" + // TaskStateAssigned ASSIGNED + TaskStateAssigned TaskState = "assigned" + // TaskStateAccepted ACCEPTED + TaskStateAccepted TaskState = "accepted" + // TaskStatePreparing PREPARING + TaskStatePreparing TaskState = "preparing" + // TaskStateReady READY + TaskStateReady TaskState = "ready" + // TaskStateStarting STARTING + TaskStateStarting TaskState = "starting" + // TaskStateRunning RUNNING + TaskStateRunning TaskState = "running" + // TaskStateComplete COMPLETE + TaskStateComplete TaskState = "complete" + // TaskStateShutdown SHUTDOWN + TaskStateShutdown TaskState = "shutdown" + // TaskStateFailed FAILED + TaskStateFailed TaskState = "failed" + // TaskStateRejected REJECTED + TaskStateRejected TaskState = "rejected" +) + +// Task represents a task. +type Task struct { + ID string + Meta + Annotations + + Spec TaskSpec `json:",omitempty"` + ServiceID string `json:",omitempty"` + Slot int `json:",omitempty"` + NodeID string `json:",omitempty"` + Status TaskStatus `json:",omitempty"` + DesiredState TaskState `json:",omitempty"` + NetworksAttachments []NetworkAttachment `json:",omitempty"` +} + +// TaskSpec represents the spec of a task. +type TaskSpec struct { + ContainerSpec ContainerSpec `json:",omitempty"` + Resources *ResourceRequirements `json:",omitempty"` + RestartPolicy *RestartPolicy `json:",omitempty"` + Placement *Placement `json:",omitempty"` + Networks []NetworkAttachmentConfig `json:",omitempty"` + + // LogDriver specifies the LogDriver to use for tasks created from this + // spec. If not present, the one on cluster default on swarm.Spec will be + // used, finally falling back to the engine default if not specified. + LogDriver *Driver `json:",omitempty"` + + // ForceUpdate is a counter that triggers an update even if no relevant + // parameters have been changed. + ForceUpdate uint64 +} + +// Resources represents resources (CPU/Memory). +type Resources struct { + NanoCPUs int64 `json:",omitempty"` + MemoryBytes int64 `json:",omitempty"` +} + +// ResourceRequirements represents resources requirements. +type ResourceRequirements struct { + Limits *Resources `json:",omitempty"` + Reservations *Resources `json:",omitempty"` +} + +// Placement represents orchestration parameters. +type Placement struct { + Constraints []string `json:",omitempty"` +} + +// RestartPolicy represents the restart policy. +type RestartPolicy struct { + Condition RestartPolicyCondition `json:",omitempty"` + Delay *time.Duration `json:",omitempty"` + MaxAttempts *uint64 `json:",omitempty"` + Window *time.Duration `json:",omitempty"` +} + +// RestartPolicyCondition represents when to restart. +type RestartPolicyCondition string + +const ( + // RestartPolicyConditionNone NONE + RestartPolicyConditionNone RestartPolicyCondition = "none" + // RestartPolicyConditionOnFailure ON_FAILURE + RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure" + // RestartPolicyConditionAny ANY + RestartPolicyConditionAny RestartPolicyCondition = "any" +) + +// TaskStatus represents the status of a task. +type TaskStatus struct { + Timestamp time.Time `json:",omitempty"` + State TaskState `json:",omitempty"` + Message string `json:",omitempty"` + Err string `json:",omitempty"` + ContainerStatus ContainerStatus `json:",omitempty"` + PortStatus PortStatus `json:",omitempty"` +} + +// ContainerStatus represents the status of a container. +type ContainerStatus struct { + ContainerID string `json:",omitempty"` + PID int `json:",omitempty"` + ExitCode int `json:",omitempty"` +} + +// PortStatus represents the port status of a task's host ports whose +// service has published host ports +type PortStatus struct { + Ports []PortConfig `json:",omitempty"` +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go deleted file mode 100644 index 092fb6716a41..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "encoding/json" - "net/http" - "net/url" - "strconv" - - "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" -) - -// NoSuchNode is the error returned when a given node does not exist. -type NoSuchNode struct { - ID string - Err error -} - -func (err *NoSuchNode) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such node: " + err.ID -} - -// ListNodesOptions specify parameters to the ListNodes function. -// -// See http://goo.gl/3K4GwU for more details. -type ListNodesOptions struct { - Filters map[string][]string - Context context.Context -} - -// ListNodes returns a slice of nodes matching the given criteria. -// -// See http://goo.gl/3K4GwU for more details. -func (c *Client) ListNodes(opts ListNodesOptions) ([]swarm.Node, error) { - path := "/nodes?" + queryString(opts) - resp, err := c.do("GET", path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var nodes []swarm.Node - if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil { - return nil, err - } - return nodes, nil -} - -// InspectNode returns information about a node by its ID. -// -// See http://goo.gl/WjkTOk for more details. -func (c *Client) InspectNode(id string) (*swarm.Node, error) { - resp, err := c.do("GET", "/nodes/"+id, doOptions{}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return nil, &NoSuchNode{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var node swarm.Node - if err := json.NewDecoder(resp.Body).Decode(&node); err != nil { - return nil, err - } - return &node, nil -} - -// UpdateNodeOptions specify parameters to the NodeUpdate function. -// -// See http://goo.gl/VPBFgA for more details. -type UpdateNodeOptions struct { - swarm.NodeSpec - Version uint64 - Context context.Context -} - -// UpdateNode updates a node. -// -// See http://goo.gl/VPBFgA for more details. -func (c *Client) UpdateNode(id string, opts UpdateNodeOptions) error { - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - path := "/nodes/" + id + "/update?" + params.Encode() - _, err := c.do("POST", path, doOptions{ - context: opts.Context, - forceJSON: true, - data: opts.NodeSpec, - }) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchNode{ID: id} - } - return err - } - return nil -} - -// RemoveNodeOptions specify parameters to the RemoveNode function. -// -// See http://goo.gl/0SNvYg for more details. -type RemoveNodeOptions struct { - ID string - Force bool - Context context.Context -} - -// RemoveNode removes a node. -// -// See http://goo.gl/0SNvYg for more details. -func (c *Client) RemoveNode(opts RemoveNodeOptions) error { - params := make(url.Values) - params.Set("force", strconv.FormatBool(opts.Force)) - path := "/nodes/" + opts.ID + "?" + params.Encode() - _, err := c.do("DELETE", path, doOptions{context: opts.Context}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchNode{ID: opts.ID} - } - return err - } - return nil -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go deleted file mode 100644 index 3daf59c5d47b..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "encoding/json" - "net/http" - "net/url" - "strconv" - - "github.com/docker/docker/api/types/swarm" - "golang.org/x/net/context" -) - -// NoSuchService is the error returned when a given service does not exist. -type NoSuchService struct { - ID string - Err error -} - -func (err *NoSuchService) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such service: " + err.ID -} - -// CreateServiceOptions specify parameters to the CreateService function. -// -// See https://goo.gl/KrVjHz for more details. -type CreateServiceOptions struct { - swarm.ServiceSpec - Context context.Context -} - -// CreateService creates a new service, returning the service instance -// or an error in case of failure. -// -// See https://goo.gl/KrVjHz for more details. -func (c *Client) CreateService(opts CreateServiceOptions) (*swarm.Service, error) { - path := "/services/create?" + queryString(opts) - resp, err := c.do("POST", path, doOptions{ - data: opts.ServiceSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var service swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { - return nil, err - } - return &service, nil -} - -// RemoveServiceOptions encapsulates options to remove a service. -// -// See https://goo.gl/Tqrtya for more details. -type RemoveServiceOptions struct { - ID string `qs:"-"` - Context context.Context -} - -// RemoveService removes a service, returning an error in case of failure. -// -// See https://goo.gl/Tqrtya for more details. -func (c *Client) RemoveService(opts RemoveServiceOptions) error { - path := "/services/" + opts.ID - resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchService{ID: opts.ID} - } - return err - } - resp.Body.Close() - return nil -} - -// UpdateServiceOptions specify parameters to the UpdateService function. -// -// See https://goo.gl/wu3MmS for more details. -type UpdateServiceOptions struct { - swarm.ServiceSpec - Context context.Context - Version uint64 -} - -// UpdateService updates the service at ID with the options -// -// See https://goo.gl/wu3MmS for more details. -func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - resp, err := c.do("POST", "/services/"+id+"/update?"+params.Encode(), doOptions{ - data: opts.ServiceSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return &NoSuchService{ID: id} - } - return err - } - defer resp.Body.Close() - return nil -} - -// InspectService returns information about a service by its ID. -// -// See https://goo.gl/dHmr75 for more details. -func (c *Client) InspectService(id string) (*swarm.Service, error) { - path := "/services/" + id - resp, err := c.do("GET", path, doOptions{}) - if err != nil { - if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { - return nil, &NoSuchService{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var service swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { - return nil, err - } - return &service, nil -} - -// ListServicesOptions specify parameters to the ListServices function. -// -// See https://goo.gl/DwvNMd for more details. -type ListServicesOptions struct { - Filters map[string][]string - Context context.Context -} - -// ListServices returns a slice of services matching the given criteria. -// -// See https://goo.gl/DwvNMd for more details. -func (c *Client) ListServices(opts ListServicesOptions) ([]swarm.Service, error) { - path := "/services?" + queryString(opts) - resp, err := c.do("GET", path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var services []swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&services); err != nil { - return nil, err - } - return services, nil -} From 619b19fbdea6b56619f23dacdf5ec13b936fef56 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 22:27:57 +0100 Subject: [PATCH 16/27] Add node module for docker metricset --- metricbeat/docs/fields.asciidoc | 150 +++++++++++++----- metricbeat/metricbeat.template-es2x.json | 121 ++++++++++++++ metricbeat/metricbeat.template.json | 108 +++++++++++++ metricbeat/metricbeat.yml | 38 ++--- .../module/docker/container/_meta/fields.yml | 2 +- metricbeat/module/docker/container/data.go | 4 - metricbeat/module/docker/node/_meta/data.json | 54 +++++++ .../module/docker/node/_meta/docs.asciidoc | 4 + .../module/docker/node/_meta/fields.yml | 104 ++++++++++++ metricbeat/module/docker/node/data.go | 65 ++++++++ metricbeat/module/docker/node/node.go | 53 +++++++ .../docker/node/node_integration_test.go | 25 +++ 12 files changed, 657 insertions(+), 71 deletions(-) create mode 100644 metricbeat/module/docker/node/_meta/data.json create mode 100644 metricbeat/module/docker/node/_meta/docs.asciidoc create mode 100644 metricbeat/module/docker/node/_meta/fields.yml create mode 100644 metricbeat/module/docker/node/data.go create mode 100644 metricbeat/module/docker/node/node.go create mode 100644 metricbeat/module/docker/node/node_integration_test.go diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 40103b1cf38c..c9c3954a7d1b 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1077,8 +1077,9 @@ Size of the files that have been created or changed since creation. Container health metrics. + [float] -=== docker.container.event_end_date +=== docker.container.health.event_end_date type: date @@ -1086,7 +1087,7 @@ Healthcheck end date [float] -=== docker.container.event_start_date +=== docker.container.health.event_start_date type: date @@ -1094,15 +1095,15 @@ Healthcheck start date [float] -=== docker.container.event_output +=== docker.container.health.event_output -type: long +type: keyword Healthcheck output [float] -=== docker.container.event_exit_code +=== docker.container.health.event_exit_code type: integer @@ -1455,119 +1456,188 @@ Total number of outgoing packets. [float] -== container Fields +== node Fields -Docker container metrics. +Docker node metrics. [float] -=== docker.container.command +=== docker.node.createdat -type: keyword +type: date -Command that was executed in the Docker container. +date where the node has been added to the cluster [float] -=== docker.container.created +=== docker.node.updatedad type: date -Date when the container was created. +last gossip message [float] -=== docker.container.id +=== docker.node.id type: keyword -Unique container id. +Unique node id. [float] -=== docker.container.image +=== docker.node.hostname type: keyword -Name of the image the container was built on. +hostname of the node [float] -=== docker.container.name +== spec Fields + +Configured status + + + +[float] +=== docker.node.spec.role type: keyword -Container name. +Wanted role [float] -=== docker.container.status +=== docker.node.spec.avaiability type: keyword -Container status. +wanted status. [float] -== size Fields +== platform Fields -Container size metrics. +Node information hardware and system [float] -=== docker.container.size.root_fs +=== docker.node.platform.architecture + +type: keyword + +Cpu architecture of the node. + + +[float] +=== docker.node.platform.os + +type: keyword + +OS node. + + +[float] +== ressources Fields + +available ressources on the node + + + +[float] +=== docker.node.ressources.nanocpus type: long -Total size of all the files in the container. +available CPU ressources [float] -=== docker.container.size.rw +=== docker.node.ressources.memorybytes type: long -Size of the files that have been created or changed since creation. +available Memory ressources [float] -== health Fields +== engine Fields + +docker engine information -Container health metrics. [float] -=== docker.container.event_end_date +=== docker.node.engine.engine_version -type: date +type: keyword -Healthcheck end date +Docker engine version number [float] -=== docker.container.event_start_date +=== docker.node.engine.plugin -type: date +type: keyword -Healthcheck start date +Docker plugin installed on the node [float] -=== docker.container.event_output +== status Fields -type: long +docker swarm node status -Healthcheck output [float] -=== docker.container.event_exit_code +=== docker.node.status.state -type: integer +type: keyword -Healthcheck status code +Docker engine state + + +[float] +=== docker.node.status.addr + +type: keyword + +docker + + +[float] +== managerstatus Fields + +docker swarm manager status + + + +[float] +=== docker.node.managerstatus.leader + +type: boolean + +Docker engine manager state + + +[float] +=== docker.node.managerstatus.reachability + +type: keyword + +docker + + +[float] +=== docker.node.managerstatus.addr + +type: keyword + +docker manager listenning addr [[exported-fields-haproxy]] diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index f3d85fbb414d..1f7a23ce0410 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -582,6 +582,24 @@ "created": { "type": "date" }, + "health": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "event_start_date": { + "type": "date" + } + } + }, "id": { "ignore_above": 1024, "index": "not_analyzed", @@ -773,6 +791,109 @@ } } } + }, + "node": { + "properties": { + "createdat": { + "type": "date" + }, + "engine": { + "properties": { + "engine_version": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "plugin": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "hostname": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "id": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "managerstatus": { + "properties": { + "addr": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "leader": { + "type": "boolean" + }, + "reachability": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "platform": { + "properties": { + "architecture": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "os": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "ressources": { + "properties": { + "memorybytes": { + "type": "long" + }, + "nanocpus": { + "type": "long" + } + } + }, + "spec": { + "properties": { + "avaiability": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "role": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "status": { + "properties": { + "addr": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "state": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "updatedad": { + "type": "date" + } + } } } }, diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index d42d1cd726dd..2e5147988540 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -581,6 +581,23 @@ "created": { "type": "date" }, + "health": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "type": "keyword" + }, + "event_start_date": { + "type": "date" + } + } + }, "id": { "ignore_above": 1024, "type": "keyword" @@ -778,6 +795,97 @@ } } } + }, + "node": { + "properties": { + "createdat": { + "type": "date" + }, + "engine": { + "properties": { + "engine_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "plugin": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "managerstatus": { + "properties": { + "addr": { + "ignore_above": 1024, + "type": "keyword" + }, + "leader": { + "type": "boolean" + }, + "reachability": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "platform": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ressources": { + "properties": { + "memorybytes": { + "type": "long" + }, + "nanocpus": { + "type": "long" + } + } + }, + "spec": { + "properties": { + "avaiability": { + "ignore_above": 1024, + "type": "keyword" + }, + "role": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "status": { + "properties": { + "addr": { + "ignore_above": 1024, + "type": "keyword" + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "updatedad": { + "type": "date" + } + } } } }, diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index e024185f5ce6..657ea61828d2 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -10,28 +10,14 @@ #========================== Modules configuration ============================ metricbeat.modules: -#------------------------------- Docker Module ------------------------------- -- module: docker - metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] - hosts: ["unix:///var/run/docker.sock"] - enabled: true - period: 10s - - # To connect to Docker over TLS you must specify a client and CA certificate. - #ssl: - #certificate_authority: "/etc/pki/root/ca.pem" - #certificate: "/etc/pki/client/cert.pem" - #key: "/etc/pki/client/cert.key" - - #------------------------------- System Module ------------------------------- -#- module: system - #metricsets: +- module: system + metricsets: # CPU stats - #- cpu + - cpu # System Load stats - #- load + - load # Per CPU core stats #- core @@ -40,25 +26,25 @@ metricbeat.modules: #- diskio # Per filesystem stats - #- filesystem + - filesystem # File system summary stats - #- fsstat + - fsstat # Memory stats - #- memory + - memory # Network stats - #- network + - network # Per process stats - #- process + - process # Sockets (linux only) #- socket - #enabled: true - #period: 10s - #processes: ['.*'] + enabled: true + period: 10s + processes: ['.*'] diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index d6ad46412f4b..d70523ecea60 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -54,7 +54,7 @@ description: > Healthcheck start date - name: event_output - type: long + type: keyword description: > Healthcheck output - name: event_exit_code diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 783b8e6debf3..0ead59a039fa 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -8,7 +8,6 @@ import ( "strings" dc "github.com/fsouza/go-dockerclient" - "fmt" ) func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { @@ -34,7 +33,6 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { } if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - fmt.Println("HealthCheck !!\n") container, _ := m.dockerClient.InspectContainer(cont.ID) last_event := len(container.State.Health.Log)-1 @@ -47,8 +45,6 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "event_output": container.State.Health.Log[last_event].Output, } event["health"] = health - } else { - fmt.Println("No health check lets continue\n") } labels := docker.DeDotLabels(cont.Labels) diff --git a/metricbeat/module/docker/node/_meta/data.json b/metricbeat/module/docker/node/_meta/data.json new file mode 100644 index 000000000000..f03d1b95fb89 --- /dev/null +++ b/metricbeat/module/docker/node/_meta/data.json @@ -0,0 +1,54 @@ +{ + "@timestamp": "2016-05-23T08:05:34.853Z", + "beat": { + "hostname": "host.example.com", + "name": "host.example.com" + }, + "docker": { + "node": { + "createdat": "2017-01-10T05:37:07.548757912Z", + "updatedat": "2017-01-10T05:37:08.159552729Z", + "id": "4be260de8fc1213c9ff58789b8221e70c53f5af5d5a3915ff7de4b81b357d851", + "hostname": "thisisatest", + "labels": { + "swarm_labels_toto": "valueoftotolabel", + "swarm_number": "1" + }, + "spec": { + "role": "manager", + "avaiability": "active" + }, + "platform": { + "architecture": "x86_64", + "os": "Linux" + }, + "ressources": { + "nanocpus": 4000000000, + "memorybytes": 8115884032 + }, + "status": { + "state": "ready", + "addr": "127.0.0.1" + }, + "manager": { + "leader": true, + "reachability": "reachable", + "addr": "192.168.1.38:2377" + }, + "engine": { + "version": "1.13.0-rc5", + "labels": + { + "enginelabel1=enginelabel1value" + } + } + } + }, + "metricset": { + "host": "/var/run/docker.sock", + "module": "docker", + "name": "node", + "rtt": 115 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/docker/node/_meta/docs.asciidoc b/metricbeat/module/docker/node/_meta/docs.asciidoc new file mode 100644 index 000000000000..cf4f9f984d02 --- /dev/null +++ b/metricbeat/module/docker/node/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +=== Docker Node Metricset + +The Docker Swarm `node` metricset collects information and statistics about +running nodes in Docker cluster. diff --git a/metricbeat/module/docker/node/_meta/fields.yml b/metricbeat/module/docker/node/_meta/fields.yml new file mode 100644 index 000000000000..383f67c88bcc --- /dev/null +++ b/metricbeat/module/docker/node/_meta/fields.yml @@ -0,0 +1,104 @@ +- name: node + type: group + description: > + Docker node metrics. + fields: + + - name: createdat + type: date + description: > + date where the node has been added to the cluster + - name: updatedad + type: date + description: > + last gossip message + - name: id + type: keyword + description: > + Unique node id. + - name: hostname + type: keyword + description: > + hostname of the node + - name: spec + type: group + description: > + Configured status + fields: + - name: role + type: keyword + description: > + Wanted role + - name: avaiability + type: keyword + description: > + wanted status. + - name: platform + type: group + description: > + Node information hardware and system + fields: + - name: architecture + type: keyword + description: > + Cpu architecture of the node. + - name: os + type: keyword + description: > + OS node. + - name: ressources + type: group + description: > + available ressources on the node + fields: + - name: nanocpus + type: long + description: > + available CPU ressources + - name: memorybytes + type: long + description: > + available Memory ressources + - name: engine + type: group + description: > + docker engine information + fields: + - name: engine_version + type: keyword + description: > + Docker engine version number + - name: plugin + type: keyword + description: > + Docker plugin installed on the node + - name: status + type: group + description: > + docker swarm node status + fields: + - name: state + type: keyword + description: > + Docker engine state + - name: addr + type: keyword + description: > + docker + - name: managerstatus + type: group + description: > + docker swarm manager status + fields: + - name: leader + type: boolean + description: > + Docker engine manager state + - name: reachability + type: keyword + description: > + docker + - name: addr + type: keyword + description: > + docker manager listenning addr diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go new file mode 100644 index 000000000000..a6718242084d --- /dev/null +++ b/metricbeat/module/docker/node/data.go @@ -0,0 +1,65 @@ +package node + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/module/docker" + + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" +) + +func eventsMapping(nodesList []swarm.Node, m *MetricSet) []common.MapStr { + myEvents := []common.MapStr{} + + for _, node := range nodesList { + myEvents = append(myEvents, eventMapping(&node, m)) + } + + return myEvents +} + +func eventMapping(node *swarm.Node, m *MetricSet) common.MapStr { + event := common.MapStr{ + "createdat": node.Meta.CreatedAt, + "updatedat": node.Meta.UpdatedAt, + "id": node.ID, + "hostname": node.Description.Hostname, + "spec": common.MapStr{ + "role": node.Spec.Role, + "avaiability": node.Spec.Availability, + }, + "platform": common.MapStr{ + "architecture": node.Description.Platform.Architecture, + "os": node.Description.Platform.OS, + }, + "status": common.MapStr{ + "state": node.Status.State, + "addr": node.Status.Addr, + }, + "ressources": common.MapStr{ + "nanocpus": node.Description.Resources.NanoCPUs, + "memorybytes": node.Description.Resources.MemoryBytes, + }, + "engine.version": node.Description.Engine.EngineVersion, + } + + if node.Spec.Role == "manager" { + //fmt.Println("this is a manager ",node.ManagerStatus.Leader) + manager := common.MapStr{ + "leader": node.ManagerStatus.Leader, + "reachability": node.ManagerStatus.Reachability, + "addr": node.ManagerStatus.Addr, + } + event["manager"] = manager + } + + swarm_labels := docker.DeDotLabels(node.Spec.Annotations.Labels) + if len(swarm_labels) > 0 { + event["labels"] = swarm_labels + } + engine_labels := docker.DeDotLabels(node.Description.Engine.Labels) + if len(engine_labels) > 0 { + event["engine.labels"] = engine_labels + } + + return event +} diff --git a/metricbeat/module/docker/node/node.go b/metricbeat/module/docker/node/node.go new file mode 100644 index 000000000000..6381c53b6364 --- /dev/null +++ b/metricbeat/module/docker/node/node.go @@ -0,0 +1,53 @@ +package node + +import ( + dc "github.com/fsouza/go-dockerclient" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" +) + +func init() { + if err := mb.Registry.AddMetricSet("docker", "node", New, docker.HostParser); err != nil { + panic(err) + } +} + +type MetricSet struct { + mb.BaseMetricSet + dockerClient *dc.Client +} + +// New creates a new instance of the docker container MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("EXPERIMENTAL: The docker node metricset is experimental") + + config := docker.Config{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + client, err := docker.NewDockerClient(base.HostData().URI, config) + if err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + dockerClient: client, + }, nil +} + +// Fetch returns a list of all containers as events. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + // Fetch a list of all nodes. + nodes, err := m.dockerClient.ListNodes(dc.ListNodesOptions{}) + if err != nil { + return nil, err + } + + return eventsMapping(nodes, m), nil +} diff --git a/metricbeat/module/docker/node/node_integration_test.go b/metricbeat/module/docker/node/node_integration_test.go new file mode 100644 index 000000000000..5a35029ef229 --- /dev/null +++ b/metricbeat/module/docker/node/node_integration_test.go @@ -0,0 +1,25 @@ +// +build integration + +package node + +import ( + "testing" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "docker", + "metricsets": []string{"node"}, + "hosts": []string{"unix:///var/run/docker.sock"}, + } +} From 76bb65a4e8dee1004d91eecda0b1166c92d40bf4 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Tue, 10 Jan 2017 22:51:15 +0100 Subject: [PATCH 17/27] Fix docker dependency issue --- metricbeat/metricbeat.full.yml | 3 +- .../docker/api/types/blkiodev/blkio.go | 23 + .../docker/api/types/container/config.go | 6 +- .../docker/api/types/container/host_config.go | 15 +- .../docker/api/types/strslice/strslice.go | 30 + .../api/types/strslice/strslice_test.go | 86 +++ .../docker/api/types/swarm/container.go | 6 +- .../docker/go-connections/nat/nat.go | 242 ++++++++ .../docker/go-connections/nat/nat_test.go | 583 ++++++++++++++++++ .../docker/go-connections/nat/parse.go | 57 ++ .../docker/go-connections/nat/parse_test.go | 54 ++ .../docker/go-connections/nat/sort.go | 96 +++ .../docker/go-connections/nat/sort_test.go | 85 +++ 13 files changed, 1275 insertions(+), 11 deletions(-) create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 683008110ede..03467ccef23d 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -103,7 +103,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -865,4 +865,3 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 - diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go new file mode 100644 index 000000000000..931ae10ab1ef --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go @@ -0,0 +1,23 @@ +package blkiodev + +import "fmt" + +// WeightDevice is a structure that holds device:weight pair +type WeightDevice struct { + Path string + Weight uint16 +} + +func (w *WeightDevice) String() string { + return fmt.Sprintf("%s:%d", w.Path, w.Weight) +} + +// ThrottleDevice is a structure that holds device:rate_per_second pair +type ThrottleDevice struct { + Path string + Rate uint64 +} + +func (t *ThrottleDevice) String() string { + return fmt.Sprintf("%s:%d", t.Path, t.Rate) +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go index fc050e5dba9d..e5ddd70665de 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go @@ -3,8 +3,10 @@ package container import ( "time" - "github.com/docker/docker/api/types/strslice" - "github.com/docker/go-connections/nat" + //"github.com/docker/docker/api/types/strslice" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice" + "github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat" + //"github.com/docker/go-connections/nat" ) // HealthConfig holds configuration settings for the HEALTHCHECK feature. diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go index d34fa1405cf0..889fc9356edb 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go @@ -3,11 +3,16 @@ package container import ( "strings" - "github.com/docker/docker/api/types/blkiodev" - "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/api/types/strslice" - "github.com/docker/go-connections/nat" - "github.com/docker/go-units" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount" + "github.com/fsouza/go-dockerclient/external/github.com/docker/go-units" + "github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat" + //"github.com/docker/docker/api/types/blkiodev" + //"github.com/docker/docker/api/types/mount" + //"github.com/docker/docker/api/types/strslice" + //"github.com/docker/go-connections/nat" + //"github.com/docker/go-units" ) // NetworkMode represents the container network stack. diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go new file mode 100644 index 000000000000..bad493fb89fd --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go @@ -0,0 +1,30 @@ +package strslice + +import "encoding/json" + +// StrSlice represents a string or an array of strings. +// We need to override the json decoder to accept both options. +type StrSlice []string + +// UnmarshalJSON decodes the byte slice whether it's a string or an array of +// strings. This method is needed to implement json.Unmarshaler. +func (e *StrSlice) UnmarshalJSON(b []byte) error { + if len(b) == 0 { + // With no input, we preserve the existing value by returning nil and + // leaving the target alone. This allows defining default values for + // the type. + return nil + } + + p := make([]string, 0, 1) + if err := json.Unmarshal(b, &p); err != nil { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + p = append(p, s) + } + + *e = p + return nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go new file mode 100644 index 000000000000..1163b3652c98 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go @@ -0,0 +1,86 @@ +package strslice + +import ( + "encoding/json" + "reflect" + "testing" +) + +func TestStrSliceMarshalJSON(t *testing.T) { + for _, testcase := range []struct { + input StrSlice + expected string + }{ + // MADNESS(stevvooe): No clue why nil would be "" but empty would be + // "null". Had to make a change here that may affect compatibility. + {input: nil, expected: "null"}, + {StrSlice{}, "[]"}, + {StrSlice{"/bin/sh", "-c", "echo"}, `["/bin/sh","-c","echo"]`}, + } { + data, err := json.Marshal(testcase.input) + if err != nil { + t.Fatal(err) + } + if string(data) != testcase.expected { + t.Fatalf("%#v: expected %v, got %v", testcase.input, testcase.expected, string(data)) + } + } +} + +func TestStrSliceUnmarshalJSON(t *testing.T) { + parts := map[string][]string{ + "": {"default", "values"}, + "[]": {}, + `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"}, + } + for json, expectedParts := range parts { + strs := StrSlice{"default", "values"} + if err := strs.UnmarshalJSON([]byte(json)); err != nil { + t.Fatal(err) + } + + actualParts := []string(strs) + if !reflect.DeepEqual(actualParts, expectedParts) { + t.Fatalf("%#v: expected %v, got %v", json, expectedParts, actualParts) + } + + } +} + +func TestStrSliceUnmarshalString(t *testing.T) { + var e StrSlice + echo, err := json.Marshal("echo") + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(echo, &e); err != nil { + t.Fatal(err) + } + + if len(e) != 1 { + t.Fatalf("expected 1 element after unmarshal: %q", e) + } + + if e[0] != "echo" { + t.Fatalf("expected `echo`, got: %q", e[0]) + } +} + +func TestStrSliceUnmarshalSlice(t *testing.T) { + var e StrSlice + echo, err := json.Marshal([]string{"echo"}) + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(echo, &e); err != nil { + t.Fatal(err) + } + + if len(e) != 1 { + t.Fatalf("expected 1 element after unmarshal: %q", e) + } + + if e[0] != "echo" { + t.Fatalf("expected `echo`, got: %q", e[0]) + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go index 4ab476ccc392..0b823eb24772 100644 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go @@ -3,8 +3,10 @@ package swarm import ( "time" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/mount" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount" + //"github.com/docker/docker/api/types/container" + //"github.com/docker/docker/api/types/mount" ) // DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go new file mode 100644 index 000000000000..4d5f5ae63afd --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go @@ -0,0 +1,242 @@ +// Package nat is a convenience package for manipulation of strings describing network ports. +package nat + +import ( + "fmt" + "net" + "strconv" + "strings" +) + +const ( + // portSpecTemplate is the expected format for port specifications + portSpecTemplate = "ip:hostPort:containerPort" +) + +// PortBinding represents a binding between a Host IP address and a Host Port +type PortBinding struct { + // HostIP is the host IP Address + HostIP string `json:"HostIp"` + // HostPort is the host port number + HostPort string +} + +// PortMap is a collection of PortBinding indexed by Port +type PortMap map[Port][]PortBinding + +// PortSet is a collection of structs indexed by Port +type PortSet map[Port]struct{} + +// Port is a string containing port number and protocol in the format "80/tcp" +type Port string + +// NewPort creates a new instance of a Port given a protocol and port number or port range +func NewPort(proto, port string) (Port, error) { + // Check for parsing issues on "port" now so we can avoid having + // to check it later on. + + portStartInt, portEndInt, err := ParsePortRangeToInt(port) + if err != nil { + return "", err + } + + if portStartInt == portEndInt { + return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil + } + return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil +} + +// ParsePort parses the port number string and returns an int +func ParsePort(rawPort string) (int, error) { + if len(rawPort) == 0 { + return 0, nil + } + port, err := strconv.ParseUint(rawPort, 10, 16) + if err != nil { + return 0, err + } + return int(port), nil +} + +// ParsePortRangeToInt parses the port range string and returns start/end ints +func ParsePortRangeToInt(rawPort string) (int, int, error) { + if len(rawPort) == 0 { + return 0, 0, nil + } + start, end, err := ParsePortRange(rawPort) + if err != nil { + return 0, 0, err + } + return int(start), int(end), nil +} + +// Proto returns the protocol of a Port +func (p Port) Proto() string { + proto, _ := SplitProtoPort(string(p)) + return proto +} + +// Port returns the port number of a Port +func (p Port) Port() string { + _, port := SplitProtoPort(string(p)) + return port +} + +// Int returns the port number of a Port as an int +func (p Port) Int() int { + portStr := p.Port() + // We don't need to check for an error because we're going to + // assume that any error would have been found, and reported, in NewPort() + port, _ := ParsePort(portStr) + return port +} + +// Range returns the start/end port numbers of a Port range as ints +func (p Port) Range() (int, int, error) { + return ParsePortRangeToInt(p.Port()) +} + +// SplitProtoPort splits a port in the format of proto/port +func SplitProtoPort(rawPort string) (string, string) { + parts := strings.Split(rawPort, "/") + l := len(parts) + if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 { + return "", "" + } + if l == 1 { + return "tcp", rawPort + } + if len(parts[1]) == 0 { + return "tcp", parts[0] + } + return parts[1], parts[0] +} + +func validateProto(proto string) bool { + for _, availableProto := range []string{"tcp", "udp"} { + if availableProto == proto { + return true + } + } + return false +} + +// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses +// these in to the internal types +func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) { + var ( + exposedPorts = make(map[Port]struct{}, len(ports)) + bindings = make(map[Port][]PortBinding) + ) + for _, rawPort := range ports { + portMappings, err := ParsePortSpec(rawPort) + if err != nil { + return nil, nil, err + } + + for _, portMapping := range portMappings { + port := portMapping.Port + if _, exists := exposedPorts[port]; !exists { + exposedPorts[port] = struct{}{} + } + bslice, exists := bindings[port] + if !exists { + bslice = []PortBinding{} + } + bindings[port] = append(bslice, portMapping.Binding) + } + } + return exposedPorts, bindings, nil +} + +// PortMapping is a data object mapping a Port to a PortBinding +type PortMapping struct { + Port Port + Binding PortBinding +} + +func splitParts(rawport string) (string, string, string) { + parts := strings.Split(rawport, ":") + n := len(parts) + containerport := parts[n-1] + + switch n { + case 1: + return "", "", containerport + case 2: + return "", parts[0], containerport + case 3: + return parts[0], parts[1], containerport + default: + return strings.Join(parts[:n-2], ":"), parts[n-2], containerport + } +} + +// ParsePortSpec parses a port specification string into a slice of PortMappings +func ParsePortSpec(rawPort string) ([]PortMapping, error) { + var proto string + rawIP, hostPort, containerPort := splitParts(rawPort) + proto, containerPort = SplitProtoPort(containerPort) + + // Strip [] from IPV6 addresses + ip, _, err := net.SplitHostPort(rawIP + ":") + if err != nil { + return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err) + } + if ip != "" && net.ParseIP(ip) == nil { + return nil, fmt.Errorf("Invalid ip address: %s", ip) + } + if containerPort == "" { + return nil, fmt.Errorf("No port specified: %s", rawPort) + } + + startPort, endPort, err := ParsePortRange(containerPort) + if err != nil { + return nil, fmt.Errorf("Invalid containerPort: %s", containerPort) + } + + var startHostPort, endHostPort uint64 = 0, 0 + if len(hostPort) > 0 { + startHostPort, endHostPort, err = ParsePortRange(hostPort) + if err != nil { + return nil, fmt.Errorf("Invalid hostPort: %s", hostPort) + } + } + + if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) { + // Allow host port range iff containerPort is not a range. + // In this case, use the host port range as the dynamic + // host port range to allocate into. + if endPort != startPort { + return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort) + } + } + + if !validateProto(strings.ToLower(proto)) { + return nil, fmt.Errorf("Invalid proto: %s", proto) + } + + ports := []PortMapping{} + for i := uint64(0); i <= (endPort - startPort); i++ { + containerPort = strconv.FormatUint(startPort+i, 10) + if len(hostPort) > 0 { + hostPort = strconv.FormatUint(startHostPort+i, 10) + } + // Set hostPort to a range only if there is a single container port + // and a dynamic host port. + if startPort == endPort && startHostPort != endHostPort { + hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10)) + } + port, err := NewPort(strings.ToLower(proto), containerPort) + if err != nil { + return nil, err + } + + binding := PortBinding{ + HostIP: ip, + HostPort: hostPort, + } + ports = append(ports, PortMapping{Port: port, Binding: binding}) + } + return ports, nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go new file mode 100644 index 000000000000..787d5ac2338e --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go @@ -0,0 +1,583 @@ +package nat + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParsePort(t *testing.T) { + var ( + p int + err error + ) + + p, err = ParsePort("1234") + + if err != nil || p != 1234 { + t.Fatal("Parsing '1234' did not succeed") + } + + // FIXME currently this is a valid port. I don't think it should be. + // I'm leaving this test commented out until we make a decision. + // - erikh + + /* + p, err = ParsePort("0123") + + if err != nil { + t.Fatal("Successfully parsed port '0123' to '123'") + } + */ + + p, err = ParsePort("asdf") + + if err == nil || p != 0 { + t.Fatal("Parsing port 'asdf' succeeded") + } + + p, err = ParsePort("1asdf") + + if err == nil || p != 0 { + t.Fatal("Parsing port '1asdf' succeeded") + } +} + +func TestParsePortRangeToInt(t *testing.T) { + var ( + begin int + end int + err error + ) + + type TestRange struct { + Range string + Begin int + End int + } + validRanges := []TestRange{ + {"1234", 1234, 1234}, + {"1234-1234", 1234, 1234}, + {"1234-1235", 1234, 1235}, + {"8000-9000", 8000, 9000}, + {"0", 0, 0}, + {"0-0", 0, 0}, + } + + for _, r := range validRanges { + begin, end, err = ParsePortRangeToInt(r.Range) + + if err != nil || begin != r.Begin { + t.Fatalf("Parsing port range '%s' did not succeed. Expected begin %d, got %d", r.Range, r.Begin, begin) + } + if err != nil || end != r.End { + t.Fatalf("Parsing port range '%s' did not succeed. Expected end %d, got %d", r.Range, r.End, end) + } + } + + invalidRanges := []string{ + "asdf", + "1asdf", + "9000-8000", + "9000-", + "-8000", + "-8000-", + } + + for _, r := range invalidRanges { + begin, end, err = ParsePortRangeToInt(r) + + if err == nil || begin != 0 || end != 0 { + t.Fatalf("Parsing port range '%s' succeeded", r) + } + } +} + +func TestPort(t *testing.T) { + p, err := NewPort("tcp", "1234") + + if err != nil { + t.Fatalf("tcp, 1234 had a parsing issue: %v", err) + } + + if string(p) != "1234/tcp" { + t.Fatal("tcp, 1234 did not result in the string 1234/tcp") + } + + if p.Proto() != "tcp" { + t.Fatal("protocol was not tcp") + } + + if p.Port() != "1234" { + t.Fatal("port string value was not 1234") + } + + if p.Int() != 1234 { + t.Fatal("port int value was not 1234") + } + + p, err = NewPort("tcp", "asd1234") + if err == nil { + t.Fatal("tcp, asd1234 was supposed to fail") + } + + p, err = NewPort("tcp", "1234-1230") + if err == nil { + t.Fatal("tcp, 1234-1230 was supposed to fail") + } + + p, err = NewPort("tcp", "1234-1242") + if err != nil { + t.Fatalf("tcp, 1234-1242 had a parsing issue: %v", err) + } + + if string(p) != "1234-1242/tcp" { + t.Fatal("tcp, 1234-1242 did not result in the string 1234-1242/tcp") + } +} + +func TestSplitProtoPort(t *testing.T) { + var ( + proto string + port string + ) + + proto, port = SplitProtoPort("1234/tcp") + + if proto != "tcp" || port != "1234" { + t.Fatal("Could not split 1234/tcp properly") + } + + proto, port = SplitProtoPort("") + + if proto != "" || port != "" { + t.Fatal("parsing an empty string yielded surprising results", proto, port) + } + + proto, port = SplitProtoPort("1234") + + if proto != "tcp" || port != "1234" { + t.Fatal("tcp is not the default protocol for portspec '1234'", proto, port) + } + + proto, port = SplitProtoPort("1234/") + + if proto != "tcp" || port != "1234" { + t.Fatal("parsing '1234/' yielded:" + port + "/" + proto) + } + + proto, port = SplitProtoPort("/tcp") + + if proto != "" || port != "" { + t.Fatal("parsing '/tcp' yielded:" + port + "/" + proto) + } +} + +func TestParsePortSpecFull(t *testing.T) { + portMappings, err := ParsePortSpec("0.0.0.0:1234-1235:3333-3334/tcp") + assert.Nil(t, err) + + expected := []PortMapping{ + { + Port: "3333/tcp", + Binding: PortBinding{ + HostIP: "0.0.0.0", + HostPort: "1234", + }, + }, + { + Port: "3334/tcp", + Binding: PortBinding{ + HostIP: "0.0.0.0", + HostPort: "1235", + }, + }, + } + + assert.Equal(t, expected, portMappings) +} + +func TestPartPortSpecIPV6(t *testing.T) { + portMappings, err := ParsePortSpec("[2001:4860:0:2001::68]::333") + assert.Nil(t, err) + + expected := []PortMapping{ + { + Port: "333/tcp", + Binding: PortBinding{ + HostIP: "2001:4860:0:2001::68", + HostPort: "", + }, + }, + } + assert.Equal(t, expected, portMappings) +} + +func TestPartPortSpecIPV6WithHostPort(t *testing.T) { + portMappings, err := ParsePortSpec("[::1]:80:80") + assert.Nil(t, err) + + expected := []PortMapping{ + { + Port: "80/tcp", + Binding: PortBinding{ + HostIP: "::1", + HostPort: "80", + }, + }, + } + assert.Equal(t, expected, portMappings) +} + +func TestParsePortSpecs(t *testing.T) { + var ( + portMap map[Port]struct{} + bindingMap map[Port][]PortBinding + err error + ) + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234/tcp", "2345/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1234/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2345/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != "" { + t.Fatalf("HostPort should not be set for %s", portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234:1234/tcp", "2345:2345/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1234/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2345/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != port { + t.Fatalf("HostPort should be %s for %s", port, portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234:1234/tcp", "0.0.0.0:2345:2345/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1234/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2345/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "0.0.0.0" { + t.Fatalf("HostIP is not 0.0.0.0 for %s", portspec) + } + + if bindings[0].HostPort != port { + t.Fatalf("HostPort should be %s for %s", port, portspec) + } + } + + _, _, err = ParsePortSpecs([]string{"localhost:1234:1234/tcp"}) + + if err == nil { + t.Fatal("Received no error while trying to parse a hostname instead of ip") + } +} + +func TestParsePortSpecsWithRange(t *testing.T) { + var ( + portMap map[Port]struct{} + bindingMap map[Port][]PortBinding + err error + ) + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236/tcp", "2345-2347/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1235/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2346/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != "" { + t.Fatalf("HostPort should not be set for %s", portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236:1234-1236/tcp", "2345-2347:2345-2347/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1235/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2346/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + if len(bindings) != 1 { + t.Fatalf("%s should have exactly one binding", portspec) + } + + if bindings[0].HostIP != "" { + t.Fatalf("HostIP should not be set for %s", portspec) + } + + if bindings[0].HostPort != port { + t.Fatalf("HostPort should be %s for %s", port, portspec) + } + } + + portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234-1236:1234-1236/tcp", "0.0.0.0:2345-2347:2345-2347/udp"}) + + if err != nil { + t.Fatalf("Error while processing ParsePortSpecs: %s", err) + } + + if _, ok := portMap[Port("1235/tcp")]; !ok { + t.Fatal("1234/tcp was not parsed properly") + } + + if _, ok := portMap[Port("2346/udp")]; !ok { + t.Fatal("2345/udp was not parsed properly") + } + + for portspec, bindings := range bindingMap { + _, port := SplitProtoPort(string(portspec)) + if len(bindings) != 1 || bindings[0].HostIP != "0.0.0.0" || bindings[0].HostPort != port { + t.Fatalf("Expect single binding to port %s but found %s", port, bindings) + } + } + + _, _, err = ParsePortSpecs([]string{"localhost:1234-1236:1234-1236/tcp"}) + + if err == nil { + t.Fatal("Received no error while trying to parse a hostname instead of ip") + } +} + +func TestParseNetworkOptsPrivateOnly(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::80"}) + if err != nil { + t.Fatal(err) + } + if len(ports) != 1 { + t.Logf("Expected 1 got %d", len(ports)) + t.FailNow() + } + if len(bindings) != 1 { + t.Logf("Expected 1 got %d", len(bindings)) + t.FailNow() + } + for k := range ports { + if k.Proto() != "tcp" { + t.Logf("Expected tcp got %s", k.Proto()) + t.Fail() + } + if k.Port() != "80" { + t.Logf("Expected 80 got %s", k.Port()) + t.Fail() + } + b, exists := bindings[k] + if !exists { + t.Log("Binding does not exist") + t.FailNow() + } + if len(b) != 1 { + t.Logf("Expected 1 got %d", len(b)) + t.FailNow() + } + s := b[0] + if s.HostPort != "" { + t.Logf("Expected \"\" got %s", s.HostPort) + t.Fail() + } + if s.HostIP != "192.168.1.100" { + t.Fail() + } + } +} + +func TestParseNetworkOptsPublic(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:8080:80"}) + if err != nil { + t.Fatal(err) + } + if len(ports) != 1 { + t.Logf("Expected 1 got %d", len(ports)) + t.FailNow() + } + if len(bindings) != 1 { + t.Logf("Expected 1 got %d", len(bindings)) + t.FailNow() + } + for k := range ports { + if k.Proto() != "tcp" { + t.Logf("Expected tcp got %s", k.Proto()) + t.Fail() + } + if k.Port() != "80" { + t.Logf("Expected 80 got %s", k.Port()) + t.Fail() + } + b, exists := bindings[k] + if !exists { + t.Log("Binding does not exist") + t.FailNow() + } + if len(b) != 1 { + t.Logf("Expected 1 got %d", len(b)) + t.FailNow() + } + s := b[0] + if s.HostPort != "8080" { + t.Logf("Expected 8080 got %s", s.HostPort) + t.Fail() + } + if s.HostIP != "192.168.1.100" { + t.Fail() + } + } +} + +func TestParseNetworkOptsPublicNoPort(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100"}) + + if err == nil { + t.Logf("Expected error Invalid containerPort") + t.Fail() + } + if ports != nil { + t.Logf("Expected nil got %s", ports) + t.Fail() + } + if bindings != nil { + t.Logf("Expected nil got %s", bindings) + t.Fail() + } +} + +func TestParseNetworkOptsNegativePorts(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:-1:-1"}) + + if err == nil { + t.Fail() + } + if len(ports) != 0 { + t.Logf("Expected nil got %d", len(ports)) + t.Fail() + } + if len(bindings) != 0 { + t.Logf("Expected 0 got %d", len(bindings)) + t.Fail() + } +} + +func TestParseNetworkOptsUdp(t *testing.T) { + ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::6000/udp"}) + if err != nil { + t.Fatal(err) + } + if len(ports) != 1 { + t.Logf("Expected 1 got %d", len(ports)) + t.FailNow() + } + if len(bindings) != 1 { + t.Logf("Expected 1 got %d", len(bindings)) + t.FailNow() + } + for k := range ports { + if k.Proto() != "udp" { + t.Logf("Expected udp got %s", k.Proto()) + t.Fail() + } + if k.Port() != "6000" { + t.Logf("Expected 6000 got %s", k.Port()) + t.Fail() + } + b, exists := bindings[k] + if !exists { + t.Log("Binding does not exist") + t.FailNow() + } + if len(b) != 1 { + t.Logf("Expected 1 got %d", len(b)) + t.FailNow() + } + s := b[0] + if s.HostPort != "" { + t.Logf("Expected \"\" got %s", s.HostPort) + t.Fail() + } + if s.HostIP != "192.168.1.100" { + t.Fail() + } + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go new file mode 100644 index 000000000000..892adf8c6673 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go @@ -0,0 +1,57 @@ +package nat + +import ( + "fmt" + "strconv" + "strings" +) + +// PartParser parses and validates the specified string (data) using the specified template +// e.g. ip:public:private -> 192.168.0.1:80:8000 +// DEPRECATED: do not use, this function may be removed in a future version +func PartParser(template, data string) (map[string]string, error) { + // ip:public:private + var ( + templateParts = strings.Split(template, ":") + parts = strings.Split(data, ":") + out = make(map[string]string, len(templateParts)) + ) + if len(parts) != len(templateParts) { + return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template) + } + + for i, t := range templateParts { + value := "" + if len(parts) > i { + value = parts[i] + } + out[t] = value + } + return out, nil +} + +// ParsePortRange parses and validates the specified string as a port-range (8000-9000) +func ParsePortRange(ports string) (uint64, uint64, error) { + if ports == "" { + return 0, 0, fmt.Errorf("Empty string specified for ports.") + } + if !strings.Contains(ports, "-") { + start, err := strconv.ParseUint(ports, 10, 16) + end := start + return start, end, err + } + + parts := strings.Split(ports, "-") + start, err := strconv.ParseUint(parts[0], 10, 16) + if err != nil { + return 0, 0, err + } + end, err := strconv.ParseUint(parts[1], 10, 16) + if err != nil { + return 0, 0, err + } + if end < start { + return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports) + } + return start, end, nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go new file mode 100644 index 000000000000..2ac204a05bfd --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go @@ -0,0 +1,54 @@ +package nat + +import ( + "strings" + "testing" +) + +func TestParsePortRange(t *testing.T) { + if start, end, err := ParsePortRange("8000-8080"); err != nil || start != 8000 || end != 8080 { + t.Fatalf("Error: %s or Expecting {start,end} values {8000,8080} but found {%d,%d}.", err, start, end) + } +} + +func TestParsePortRangeEmpty(t *testing.T) { + if _, _, err := ParsePortRange(""); err == nil || err.Error() != "Empty string specified for ports." { + t.Fatalf("Expected error 'Empty string specified for ports.', got %v", err) + } +} + +func TestParsePortRangeWithNoRange(t *testing.T) { + start, end, err := ParsePortRange("8080") + if err != nil { + t.Fatal(err) + } + if start != 8080 || end != 8080 { + t.Fatalf("Expected start and end to be the same and equal to 8080, but were %v and %v", start, end) + } +} + +func TestParsePortRangeIncorrectRange(t *testing.T) { + if _, _, err := ParsePortRange("9000-8080"); err == nil || !strings.Contains(err.Error(), "Invalid range specified for the Port") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } +} + +func TestParsePortRangeIncorrectEndRange(t *testing.T) { + if _, _, err := ParsePortRange("8000-a"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } + + if _, _, err := ParsePortRange("8000-30a"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } +} + +func TestParsePortRangeIncorrectStartRange(t *testing.T) { + if _, _, err := ParsePortRange("a-8000"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } + + if _, _, err := ParsePortRange("30a-8000"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { + t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) + } +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go new file mode 100644 index 000000000000..ce950171e315 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go @@ -0,0 +1,96 @@ +package nat + +import ( + "sort" + "strings" +) + +type portSorter struct { + ports []Port + by func(i, j Port) bool +} + +func (s *portSorter) Len() int { + return len(s.ports) +} + +func (s *portSorter) Swap(i, j int) { + s.ports[i], s.ports[j] = s.ports[j], s.ports[i] +} + +func (s *portSorter) Less(i, j int) bool { + ip := s.ports[i] + jp := s.ports[j] + + return s.by(ip, jp) +} + +// Sort sorts a list of ports using the provided predicate +// This function should compare `i` and `j`, returning true if `i` is +// considered to be less than `j` +func Sort(ports []Port, predicate func(i, j Port) bool) { + s := &portSorter{ports, predicate} + sort.Sort(s) +} + +type portMapEntry struct { + port Port + binding PortBinding +} + +type portMapSorter []portMapEntry + +func (s portMapSorter) Len() int { return len(s) } +func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// sort the port so that the order is: +// 1. port with larger specified bindings +// 2. larger port +// 3. port with tcp protocol +func (s portMapSorter) Less(i, j int) bool { + pi, pj := s[i].port, s[j].port + hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort) + return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp") +} + +// SortPortMap sorts the list of ports and their respected mapping. The ports +// will explicit HostPort will be placed first. +func SortPortMap(ports []Port, bindings PortMap) { + s := portMapSorter{} + for _, p := range ports { + if binding, ok := bindings[p]; ok { + for _, b := range binding { + s = append(s, portMapEntry{port: p, binding: b}) + } + bindings[p] = []PortBinding{} + } else { + s = append(s, portMapEntry{port: p}) + } + } + + sort.Sort(s) + var ( + i int + pm = make(map[Port]struct{}) + ) + // reorder ports + for _, entry := range s { + if _, ok := pm[entry.port]; !ok { + ports[i] = entry.port + pm[entry.port] = struct{}{} + i++ + } + // reorder bindings for this port + if _, ok := bindings[entry.port]; ok { + bindings[entry.port] = append(bindings[entry.port], entry.binding) + } + } +} + +func toInt(s string) uint64 { + i, _, err := ParsePortRange(s) + if err != nil { + i = 0 + } + return i +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go new file mode 100644 index 000000000000..88ed911156a8 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go @@ -0,0 +1,85 @@ +package nat + +import ( + "fmt" + "reflect" + "testing" +) + +func TestSortUniquePorts(t *testing.T) { + ports := []Port{ + Port("6379/tcp"), + Port("22/tcp"), + } + + Sort(ports, func(ip, jp Port) bool { + return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp") + }) + + first := ports[0] + if fmt.Sprint(first) != "22/tcp" { + t.Log(fmt.Sprint(first)) + t.Fail() + } +} + +func TestSortSamePortWithDifferentProto(t *testing.T) { + ports := []Port{ + Port("8888/tcp"), + Port("8888/udp"), + Port("6379/tcp"), + Port("6379/udp"), + } + + Sort(ports, func(ip, jp Port) bool { + return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp") + }) + + first := ports[0] + if fmt.Sprint(first) != "6379/tcp" { + t.Fail() + } +} + +func TestSortPortMap(t *testing.T) { + ports := []Port{ + Port("22/tcp"), + Port("22/udp"), + Port("8000/tcp"), + Port("6379/tcp"), + Port("9999/tcp"), + } + + portMap := PortMap{ + Port("22/tcp"): []PortBinding{ + {}, + }, + Port("8000/tcp"): []PortBinding{ + {}, + }, + Port("6379/tcp"): []PortBinding{ + {}, + {HostIP: "0.0.0.0", HostPort: "32749"}, + }, + Port("9999/tcp"): []PortBinding{ + {HostIP: "0.0.0.0", HostPort: "40000"}, + }, + } + + SortPortMap(ports, portMap) + if !reflect.DeepEqual(ports, []Port{ + Port("9999/tcp"), + Port("6379/tcp"), + Port("8000/tcp"), + Port("22/tcp"), + Port("22/udp"), + }) { + t.Errorf("failed to prioritize port with explicit mappings, got %v", ports) + } + if pm := portMap[Port("6379/tcp")]; !reflect.DeepEqual(pm, []PortBinding{ + {HostIP: "0.0.0.0", HostPort: "32749"}, + {}, + }) { + t.Errorf("failed to prioritize bindings with explicit mappings, got %v", pm) + } +} From b604279c01a64488ae16f9b1a65ef366f12ebc86 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Wed, 11 Jan 2017 17:09:53 +0100 Subject: [PATCH 18/27] Add docker service metricset --- metricbeat/_meta/beat.full.yml | 2 +- metricbeat/docs/fields.asciidoc | 110 ++++++++++++++++++ metricbeat/docs/modules/docker.asciidoc | 6 +- .../docs/modules/docker/service.asciidoc | 19 +++ metricbeat/include/list.go | 1 + metricbeat/metricbeat.full.yml | 3 +- metricbeat/metricbeat.template-es2x.json | 56 +++++++++ metricbeat/metricbeat.template.json | 49 ++++++++ metricbeat/module/docker/_meta/config.yml | 2 +- metricbeat/module/docker/container/data.go | 8 +- metricbeat/module/docker/node/data.go | 6 +- metricbeat/module/docker/node/node.go | 4 +- .../module/docker/service/_meta/data.json | 30 +++++ .../module/docker/service/_meta/docs.asciidoc | 4 + .../module/docker/service/_meta/fields.yml | 59 ++++++++++ metricbeat/module/docker/service/data.go | 80 +++++++++++++ metricbeat/module/docker/service/service.go | 53 +++++++++ .../service/service_integration_test.go | 25 ++++ 18 files changed, 505 insertions(+), 12 deletions(-) create mode 100644 metricbeat/docs/modules/docker/service.asciidoc create mode 100644 metricbeat/module/docker/service/_meta/data.json create mode 100644 metricbeat/module/docker/service/_meta/docs.asciidoc create mode 100644 metricbeat/module/docker/service/_meta/fields.yml create mode 100644 metricbeat/module/docker/service/data.go create mode 100644 metricbeat/module/docker/service/service.go create mode 100644 metricbeat/module/docker/service/service_integration_test.go diff --git a/metricbeat/_meta/beat.full.yml b/metricbeat/_meta/beat.full.yml index f4065b153c0d..746bd5f65125 100644 --- a/metricbeat/_meta/beat.full.yml +++ b/metricbeat/_meta/beat.full.yml @@ -103,7 +103,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index c9c3954a7d1b..6f83e7151a55 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1640,6 +1640,116 @@ type: keyword docker manager listenning addr +[float] +== service Fields + +Docker service metrics. + + + +[float] +=== docker.service.id + +type: keyword + +service id + + +[float] +=== docker.service.createdat + +type: date + +date where the service has been created + + +[float] +=== docker.service.name + +type: keyword + +service name + + +[float] +=== docker.service.updatedad + +type: date + +last service specification change date + + +[float] +=== docker.service.mode + +type: keyword + +Service mode (replicated or global) + + +[float] +=== docker.service.replicas + +type: integer + +number of replicas if service mode is replicated + + +[float] +=== docker.service.healtcheck_enabled + +type: boolean + +check if healthcheck is activated in container specifications + + +[float] +=== docker.service.version + +type: integer + +service update versionning + + +[float] +== updatestatus Fields + +check update status + + + +[float] +=== docker.service.updatestatus.state + +type: keyword + +update state + + +[float] +=== docker.service.updatestatus.startedat + +type: date + +update started date + + +[float] +=== docker.service.updatestatus.completedat + +type: date + +update completed date + + +[float] +=== docker.service.updatestatus.message + +type: text + +update message + + [[exported-fields-haproxy]] == HAProxy Fields diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index a50007adc8b9..6a27ca8f4bdf 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -21,7 +21,7 @@ in <>. Here is an example configuration: ---- metricbeat.modules: #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -52,6 +52,8 @@ The following metricsets are available: * <> +* <> + include::docker/container.asciidoc[] include::docker/cpu.asciidoc[] @@ -66,3 +68,5 @@ include::docker/network.asciidoc[] include::docker/node.asciidoc[] +include::docker/service.asciidoc[] + diff --git a/metricbeat/docs/modules/docker/service.asciidoc b/metricbeat/docs/modules/docker/service.asciidoc new file mode 100644 index 000000000000..05af931e7b64 --- /dev/null +++ b/metricbeat/docs/modules/docker/service.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-docker-service]] +include::../../../module/docker/service/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/docker/service/_meta/data.json[] +---- diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 2c3111f6cc48..5161504ad015 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -22,6 +22,7 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" _ "github.com/elastic/beats/metricbeat/module/docker/node" + _ "github.com/elastic/beats/metricbeat/module/docker/service" _ "github.com/elastic/beats/metricbeat/module/haproxy" _ "github.com/elastic/beats/metricbeat/module/haproxy/info" _ "github.com/elastic/beats/metricbeat/module/haproxy/stat" diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 03467ccef23d..ae80e33985f0 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -103,7 +103,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -865,3 +865,4 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 + diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index 1f7a23ce0410..c5e67fdc1c93 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -894,6 +894,62 @@ "type": "date" } } + }, + "service": { + "properties": { + "createdat": { + "type": "date" + }, + "healtcheck_enabled": { + "type": "boolean" + }, + "id": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "mode": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "name": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "replicas": { + "type": "long" + }, + "updatedad": { + "type": "date" + }, + "updatestatus": { + "properties": { + "completedat": { + "type": "date" + }, + "message": { + "index": "analyzed", + "norms": { + "enabled": false + }, + "type": "string" + }, + "startedat": { + "type": "date" + }, + "state": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, + "version": { + "type": "long" + } + } } } }, diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index 2e5147988540..94872e23689f 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -886,6 +886,55 @@ "type": "date" } } + }, + "service": { + "properties": { + "createdat": { + "type": "date" + }, + "healtcheck_enabled": { + "type": "boolean" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "replicas": { + "type": "long" + }, + "updatedad": { + "type": "date" + }, + "updatestatus": { + "properties": { + "completedat": { + "type": "date" + }, + "message": { + "norms": false, + "type": "text" + }, + "startedat": { + "type": "date" + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "type": "long" + } + } } } }, diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index 745c6c91e590..ba7bc2f041e0 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -1,5 +1,5 @@ #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 0ead59a039fa..0a848ec55c93 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -32,10 +32,11 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "status": cont.Status, } - if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - container, _ := m.dockerClient.InspectContainer(cont.ID) - last_event := len(container.State.Health.Log)-1 +if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log)-1 + if last_event >= 0 { health := common.MapStr{ "status": container.State.Health.Status, "failingstreak": container.State.Health.FailingStreak, @@ -46,6 +47,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { } event["health"] = health } +} labels := docker.DeDotLabels(cont.Labels) diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go index a6718242084d..e1b5e9205186 100644 --- a/metricbeat/module/docker/node/data.go +++ b/metricbeat/module/docker/node/data.go @@ -7,17 +7,17 @@ import ( "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" ) -func eventsMapping(nodesList []swarm.Node, m *MetricSet) []common.MapStr { +func eventsMapping(nodesList []swarm.Node) []common.MapStr { myEvents := []common.MapStr{} for _, node := range nodesList { - myEvents = append(myEvents, eventMapping(&node, m)) + myEvents = append(myEvents, eventMapping(&node)) } return myEvents } -func eventMapping(node *swarm.Node, m *MetricSet) common.MapStr { +func eventMapping(node *swarm.Node) common.MapStr { event := common.MapStr{ "createdat": node.Meta.CreatedAt, "updatedat": node.Meta.UpdatedAt, diff --git a/metricbeat/module/docker/node/node.go b/metricbeat/module/docker/node/node.go index 6381c53b6364..40799a15ec0b 100644 --- a/metricbeat/module/docker/node/node.go +++ b/metricbeat/module/docker/node/node.go @@ -41,7 +41,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { } // Fetch returns a list of all containers as events. -// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-nodes. func (m *MetricSet) Fetch() ([]common.MapStr, error) { // Fetch a list of all nodes. nodes, err := m.dockerClient.ListNodes(dc.ListNodesOptions{}) @@ -49,5 +49,5 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { return nil, err } - return eventsMapping(nodes, m), nil + return eventsMapping(nodes), nil } diff --git a/metricbeat/module/docker/service/_meta/data.json b/metricbeat/module/docker/service/_meta/data.json new file mode 100644 index 000000000000..d7d27ffe8f88 --- /dev/null +++ b/metricbeat/module/docker/service/_meta/data.json @@ -0,0 +1,30 @@ +{ + "@timestamp": "2017-01-11T15:45:19.162Z", + "beat": { + "hostname": "smusso-ThinkPad", + "name": "smusso-ThinkPad", + "version": "6.0.0-alpha1" + }, + "docker": { + "service": { + "Replicas": 2, + "createdat": "2017-01-11T11:35:53.432238684Z", + "healtcheck_enabled": true, + "id": "1vyemp33ktfmk7xpfmlg29ns0", + "labels": { + "label1": "thisisatest" + }, + "mode": "Replicated", + "name": "elasticsearch", + "updatedat": "2017-01-11T15:45:03.726977327Z", + "version": 905 + } + }, + "metricset": { + "host": "/var/run/docker.sock", + "module": "docker", + "name": "service", + "rtt": 3967 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/docker/service/_meta/docs.asciidoc b/metricbeat/module/docker/service/_meta/docs.asciidoc new file mode 100644 index 000000000000..1d1858fabb24 --- /dev/null +++ b/metricbeat/module/docker/service/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +=== Docker Service Metricset + +The Docker Swarm `service` metricset collects information and statistics about +running services in Docker cluster. diff --git a/metricbeat/module/docker/service/_meta/fields.yml b/metricbeat/module/docker/service/_meta/fields.yml new file mode 100644 index 000000000000..4d16dcc426bc --- /dev/null +++ b/metricbeat/module/docker/service/_meta/fields.yml @@ -0,0 +1,59 @@ +- name: service + type: group + description: > + Docker service metrics. + fields: + + - name: id + type: keyword + description: > + service id + - name: createdat + type: date + description: > + date where the service has been created + - name: name + type: keyword + description: > + service name + - name: updatedad + type: date + description: > + last service specification change date + - name: mode + type: keyword + description: > + Service mode (replicated or global) + - name: replicas + type: integer + description: > + number of replicas if service mode is replicated + - name: healtcheck_enabled + type: boolean + description: > + check if healthcheck is activated in container specifications + - name: version + type: integer + description: > + service update versionning + - name: updatestatus + type: group + description: > + check update status + fields: + - name: "state" + type: keyword + description: > + update state + - name: "startedat" + type: date + description: > + update started date + - name: "completedat" + type: date + description: > + update completed date + - name: "message" + type: "text" + description: > + update message diff --git a/metricbeat/module/docker/service/data.go b/metricbeat/module/docker/service/data.go new file mode 100644 index 000000000000..3604fccdeeb5 --- /dev/null +++ b/metricbeat/module/docker/service/data.go @@ -0,0 +1,80 @@ +package service + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/module/docker" + "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" + "reflect" +) + +func eventsMapping(serviceList []swarm.Service) []common.MapStr { + myEvents := []common.MapStr{} + + for _, service := range serviceList { + myEvents = append(myEvents, eventMapping(&service)) + } + + return myEvents +} + +func eventMapping(service *swarm.Service) common.MapStr { + + event := common.MapStr{ + "id": service.ID, + "version": service.Meta.Version.Index, + "createdat": service.Meta.CreatedAt, + "updatedat": service.Meta.UpdatedAt, + "name": service.Spec.Annotations.Name, + } + + if service.UpdateStatus.Message != "" { + updatestatus := common.MapStr{ + "state": service.UpdateStatus.State, + "startedat": service.UpdateStatus.StartedAt, + "completedat": service.UpdateStatus.CompletedAt, + "message": service.UpdateStatus.Message, + } + event["updatestatus"] = updatestatus + } + + if service.Spec.Mode.Replicated != nil { + event["mode"] = "Replicated" + event["replicas"] = service.Spec.Mode.Replicated.Replicas + } else { + event["mode"] = "Global" + } + + previousspec_labels := common.MapStr{} + spec_labels := common.MapStr{} + + if service.PreviousSpec != nil && service.PreviousSpec.Annotations.Labels != nil { + previousspec_labels = docker.DeDotLabels(service.PreviousSpec.Annotations.Labels) + } + + if service.Spec.Annotations.Labels != nil { + spec_labels = docker.DeDotLabels(service.Spec.Annotations.Labels) + } + + if len(spec_labels) != 0 || len(previousspec_labels) != 0 { + if len(spec_labels) != 0 && len(previousspec_labels) != 0 { + if reflect.DeepEqual(spec_labels, previousspec_labels) { + event["labels"] = spec_labels + } else { + event["previousspec.labels"] = previousspec_labels + event["labels"] = spec_labels + } + } else if len(spec_labels) == 0 && len(previousspec_labels) != 0 { + event["previousspec.labels"] = previousspec_labels + } else { + event["labels"] = spec_labels + } + } + + if service.Spec.TaskTemplate.ContainerSpec.Healthcheck != nil { + event["healtcheck_enabled"] = true + } else { + event["healtcheck_enabled"] = false + } + + return event +} diff --git a/metricbeat/module/docker/service/service.go b/metricbeat/module/docker/service/service.go new file mode 100644 index 000000000000..f43389348bef --- /dev/null +++ b/metricbeat/module/docker/service/service.go @@ -0,0 +1,53 @@ +package service + +import ( + dc "github.com/fsouza/go-dockerclient" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" +) + +func init() { + if err := mb.Registry.AddMetricSet("docker", "service", New, docker.HostParser); err != nil { + panic(err) + } +} + +type MetricSet struct { + mb.BaseMetricSet + dockerClient *dc.Client +} + +// New creates a new instance of the docker services MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("EXPERIMENTAL: The docker service metricset is experimental") + + config := docker.Config{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + client, err := docker.NewDockerClient(base.HostData().URI, config) + if err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + dockerClient: client, + }, nil +} + +// Fetch returns a list of all services as events. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-services. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + // Fetch a list of all services. + services, err := m.dockerClient.ListServices(dc.ListServicesOptions{}) + if err != nil { + return nil, err + } + + return eventsMapping(services), nil +} diff --git a/metricbeat/module/docker/service/service_integration_test.go b/metricbeat/module/docker/service/service_integration_test.go new file mode 100644 index 000000000000..e3a5a5369a7e --- /dev/null +++ b/metricbeat/module/docker/service/service_integration_test.go @@ -0,0 +1,25 @@ +// +build integration + +package service + +import ( + "testing" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "docker", + "metricsets": []string{"service"}, + "hosts": []string{"unix:///var/run/docker.sock"}, + } +} From 4a8e71096f9bc1b8de5c32107590e87c16367cfe Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Wed, 11 Jan 2017 19:07:57 +0100 Subject: [PATCH 19/27] Fix service index mapping and add comment --- metricbeat/module/docker/container/data.go | 1 + metricbeat/module/docker/service/_meta/data.json | 2 +- metricbeat/module/docker/service/data.go | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index 0a848ec55c93..ea6dd77f6356 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -32,6 +32,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "status": cont.Status, } +// Check id container have health metrics configured if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { container, _ := m.dockerClient.InspectContainer(cont.ID) diff --git a/metricbeat/module/docker/service/_meta/data.json b/metricbeat/module/docker/service/_meta/data.json index d7d27ffe8f88..14dcbe4bc927 100644 --- a/metricbeat/module/docker/service/_meta/data.json +++ b/metricbeat/module/docker/service/_meta/data.json @@ -7,7 +7,7 @@ }, "docker": { "service": { - "Replicas": 2, + "replicas": 2, "createdat": "2017-01-11T11:35:53.432238684Z", "healtcheck_enabled": true, "id": "1vyemp33ktfmk7xpfmlg29ns0", diff --git a/metricbeat/module/docker/service/data.go b/metricbeat/module/docker/service/data.go index 3604fccdeeb5..fa2445ce2974 100644 --- a/metricbeat/module/docker/service/data.go +++ b/metricbeat/module/docker/service/data.go @@ -27,6 +27,7 @@ func eventMapping(service *swarm.Service) common.MapStr { "name": service.Spec.Annotations.Name, } + // Do not insert updatestatus map if no updatestatus is present if service.UpdateStatus.Message != "" { updatestatus := common.MapStr{ "state": service.UpdateStatus.State, @@ -37,6 +38,7 @@ func eventMapping(service *swarm.Service) common.MapStr { event["updatestatus"] = updatestatus } + // Check service mode if service.Spec.Mode.Replicated != nil { event["mode"] = "Replicated" event["replicas"] = service.Spec.Mode.Replicated.Replicas @@ -55,6 +57,7 @@ func eventMapping(service *swarm.Service) common.MapStr { spec_labels = docker.DeDotLabels(service.Spec.Annotations.Labels) } + // Print previous label only if they have been modify if len(spec_labels) != 0 || len(previousspec_labels) != 0 { if len(spec_labels) != 0 && len(previousspec_labels) != 0 { if reflect.DeepEqual(spec_labels, previousspec_labels) { From daeba370267f8c34e64dae9f123554c77a6f18a9 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:36:04 +0100 Subject: [PATCH 20/27] add healthcheck metricset in docker module --- metricbeat/_meta/beat.full.yml | 2 +- metricbeat/docs/fields.asciidoc | 389 +++--------------- metricbeat/docs/modules/docker.asciidoc | 14 +- metricbeat/docs/modules/docker/node.asciidoc | 19 - .../docs/modules/docker/service.asciidoc | 19 - metricbeat/include/list.go | 3 +- metricbeat/metricbeat.full.yml | 10 +- metricbeat/metricbeat.template-es2x.json | 203 ++------- metricbeat/metricbeat.template.json | 181 ++------ metricbeat/module/docker/_meta/config.yml | 2 +- .../module/docker/container/_meta/data.json | 8 - .../module/docker/container/_meta/fields.yml | 21 - .../module/docker/container/container.go | 2 +- metricbeat/module/docker/container/data.go | 25 +- metricbeat/module/docker/node/_meta/data.json | 54 --- .../module/docker/node/_meta/docs.asciidoc | 4 - .../module/docker/node/_meta/fields.yml | 104 ----- metricbeat/module/docker/node/data.go | 65 --- metricbeat/module/docker/node/node.go | 53 --- .../docker/node/node_integration_test.go | 25 -- .../module/docker/service/_meta/data.json | 30 -- .../module/docker/service/_meta/docs.asciidoc | 4 - .../module/docker/service/_meta/fields.yml | 59 --- metricbeat/module/docker/service/data.go | 83 ---- metricbeat/module/docker/service/service.go | 53 --- .../service/service_integration_test.go | 25 -- 26 files changed, 122 insertions(+), 1335 deletions(-) delete mode 100644 metricbeat/docs/modules/docker/node.asciidoc delete mode 100644 metricbeat/docs/modules/docker/service.asciidoc delete mode 100644 metricbeat/module/docker/node/_meta/data.json delete mode 100644 metricbeat/module/docker/node/_meta/docs.asciidoc delete mode 100644 metricbeat/module/docker/node/_meta/fields.yml delete mode 100644 metricbeat/module/docker/node/data.go delete mode 100644 metricbeat/module/docker/node/node.go delete mode 100644 metricbeat/module/docker/node/node_integration_test.go delete mode 100644 metricbeat/module/docker/service/_meta/data.json delete mode 100644 metricbeat/module/docker/service/_meta/docs.asciidoc delete mode 100644 metricbeat/module/docker/service/_meta/fields.yml delete mode 100644 metricbeat/module/docker/service/data.go delete mode 100644 metricbeat/module/docker/service/service.go delete mode 100644 metricbeat/module/docker/service/service_integration_test.go diff --git a/metricbeat/_meta/beat.full.yml b/metricbeat/_meta/beat.full.yml index 746bd5f65125..9ca948463296 100644 --- a/metricbeat/_meta/beat.full.yml +++ b/metricbeat/_meta/beat.full.yml @@ -103,7 +103,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 6f83e7151a55..a50f820cc883 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1071,45 +1071,6 @@ type: long Size of the files that have been created or changed since creation. -[float] -== health Fields - -Container health metrics. - - - -[float] -=== docker.container.health.event_end_date - -type: date - -Healthcheck end date - - -[float] -=== docker.container.health.event_start_date - -type: date - -Healthcheck start date - - -[float] -=== docker.container.health.event_output - -type: keyword - -Healthcheck output - - -[float] -=== docker.container.health.event_exit_code - -type: integer - -Healthcheck status code - - [float] == cpu Fields @@ -1210,6 +1171,61 @@ type: scaled_float Number of reads and writes combined. +[float] +== healthcheck Fields + +Docker container metrics. + + + +[float] +=== docker.healthcheck.event_end_date + +type: date + +Healthcheck end date + + +[float] +=== docker.healthcheck.event_start_date + +type: date + +Healthcheck start date + + +[float] +=== docker.healthcheck.event_output + +type: keyword + +Healthcheck output + + +[float] +=== docker.healthcheck.event_exit_code + +type: integer + +Healthcheck status code + + +[float] +=== docker.healthcheck.failingstreak + +type: integer + +concurent failed check + + +[float] +=== docker.healthcheck.status + +type: keyword + +Healthcheck status code + + [float] == info Fields @@ -1455,301 +1471,6 @@ type: long Total number of outgoing packets. -[float] -== node Fields - -Docker node metrics. - - - -[float] -=== docker.node.createdat - -type: date - -date where the node has been added to the cluster - - -[float] -=== docker.node.updatedad - -type: date - -last gossip message - - -[float] -=== docker.node.id - -type: keyword - -Unique node id. - - -[float] -=== docker.node.hostname - -type: keyword - -hostname of the node - - -[float] -== spec Fields - -Configured status - - - -[float] -=== docker.node.spec.role - -type: keyword - -Wanted role - - -[float] -=== docker.node.spec.avaiability - -type: keyword - -wanted status. - - -[float] -== platform Fields - -Node information hardware and system - - - -[float] -=== docker.node.platform.architecture - -type: keyword - -Cpu architecture of the node. - - -[float] -=== docker.node.platform.os - -type: keyword - -OS node. - - -[float] -== ressources Fields - -available ressources on the node - - - -[float] -=== docker.node.ressources.nanocpus - -type: long - -available CPU ressources - - -[float] -=== docker.node.ressources.memorybytes - -type: long - -available Memory ressources - - -[float] -== engine Fields - -docker engine information - - - -[float] -=== docker.node.engine.engine_version - -type: keyword - -Docker engine version number - - -[float] -=== docker.node.engine.plugin - -type: keyword - -Docker plugin installed on the node - - -[float] -== status Fields - -docker swarm node status - - - -[float] -=== docker.node.status.state - -type: keyword - -Docker engine state - - -[float] -=== docker.node.status.addr - -type: keyword - -docker - - -[float] -== managerstatus Fields - -docker swarm manager status - - - -[float] -=== docker.node.managerstatus.leader - -type: boolean - -Docker engine manager state - - -[float] -=== docker.node.managerstatus.reachability - -type: keyword - -docker - - -[float] -=== docker.node.managerstatus.addr - -type: keyword - -docker manager listenning addr - - -[float] -== service Fields - -Docker service metrics. - - - -[float] -=== docker.service.id - -type: keyword - -service id - - -[float] -=== docker.service.createdat - -type: date - -date where the service has been created - - -[float] -=== docker.service.name - -type: keyword - -service name - - -[float] -=== docker.service.updatedad - -type: date - -last service specification change date - - -[float] -=== docker.service.mode - -type: keyword - -Service mode (replicated or global) - - -[float] -=== docker.service.replicas - -type: integer - -number of replicas if service mode is replicated - - -[float] -=== docker.service.healtcheck_enabled - -type: boolean - -check if healthcheck is activated in container specifications - - -[float] -=== docker.service.version - -type: integer - -service update versionning - - -[float] -== updatestatus Fields - -check update status - - - -[float] -=== docker.service.updatestatus.state - -type: keyword - -update state - - -[float] -=== docker.service.updatestatus.startedat - -type: date - -update started date - - -[float] -=== docker.service.updatestatus.completedat - -type: date - -update completed date - - -[float] -=== docker.service.updatestatus.message - -type: text - -update message - - [[exported-fields-haproxy]] == HAProxy Fields diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index 6a27ca8f4bdf..44697ff78e57 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -21,7 +21,7 @@ in <>. Here is an example configuration: ---- metricbeat.modules: #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s @@ -44,29 +44,25 @@ The following metricsets are available: * <> +* <> + * <> * <> * <> -* <> - -* <> - include::docker/container.asciidoc[] include::docker/cpu.asciidoc[] include::docker/diskio.asciidoc[] +include::docker/healthcheck.asciidoc[] + include::docker/info.asciidoc[] include::docker/memory.asciidoc[] include::docker/network.asciidoc[] -include::docker/node.asciidoc[] - -include::docker/service.asciidoc[] - diff --git a/metricbeat/docs/modules/docker/node.asciidoc b/metricbeat/docs/modules/docker/node.asciidoc deleted file mode 100644 index e1d2341d0d22..000000000000 --- a/metricbeat/docs/modules/docker/node.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -//// -This file is generated! See scripts/docs_collector.py -//// - -[[metricbeat-metricset-docker-node]] -include::../../../module/docker/node/_meta/docs.asciidoc[] - - -==== Fields - -For a description of each field in the metricset, see the -<> section. - -Here is an example document generated by this metricset: - -[source,json] ----- -include::../../../module/docker/node/_meta/data.json[] ----- diff --git a/metricbeat/docs/modules/docker/service.asciidoc b/metricbeat/docs/modules/docker/service.asciidoc deleted file mode 100644 index 05af931e7b64..000000000000 --- a/metricbeat/docs/modules/docker/service.asciidoc +++ /dev/null @@ -1,19 +0,0 @@ -//// -This file is generated! See scripts/docs_collector.py -//// - -[[metricbeat-metricset-docker-service]] -include::../../../module/docker/service/_meta/docs.asciidoc[] - - -==== Fields - -For a description of each field in the metricset, see the -<> section. - -Here is an example document generated by this metricset: - -[source,json] ----- -include::../../../module/docker/service/_meta/data.json[] ----- diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 5161504ad015..948863c80dd8 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -18,11 +18,10 @@ import ( _ "github.com/elastic/beats/metricbeat/module/docker/container" _ "github.com/elastic/beats/metricbeat/module/docker/cpu" _ "github.com/elastic/beats/metricbeat/module/docker/diskio" + _ "github.com/elastic/beats/metricbeat/module/docker/healthcheck" _ "github.com/elastic/beats/metricbeat/module/docker/info" _ "github.com/elastic/beats/metricbeat/module/docker/memory" _ "github.com/elastic/beats/metricbeat/module/docker/network" - _ "github.com/elastic/beats/metricbeat/module/docker/node" - _ "github.com/elastic/beats/metricbeat/module/docker/service" _ "github.com/elastic/beats/metricbeat/module/haproxy" _ "github.com/elastic/beats/metricbeat/module/haproxy/info" _ "github.com/elastic/beats/metricbeat/module/haproxy/stat" diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index ae80e33985f0..cb0adf204242 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -102,11 +102,11 @@ metricbeat.modules: #hosts: ["localhost:8091"] #------------------------------- Docker Module ------------------------------- -#- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] - #hosts: ["unix:///var/run/docker.sock"] - #enabled: true - #period: 10s +- module: docker + metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + hosts: ["unix:///var/run/docker.sock"] + enabled: true + period: 10s # To connect to Docker over TLS you must specify a client and CA certificate. #ssl: diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index c5e67fdc1c93..53a17d824105 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -582,24 +582,6 @@ "created": { "type": "date" }, - "health": { - "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "event_start_date": { - "type": "date" - } - } - }, "id": { "ignore_above": 1024, "index": "not_analyzed", @@ -686,6 +668,32 @@ } } }, + "healthcheck": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "event_start_date": { + "type": "date" + }, + "failingstreak": { + "type": "long" + }, + "status": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + } + } + }, "info": { "properties": { "containers": { @@ -791,165 +799,6 @@ } } } - }, - "node": { - "properties": { - "createdat": { - "type": "date" - }, - "engine": { - "properties": { - "engine_version": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "plugin": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "hostname": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "id": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "managerstatus": { - "properties": { - "addr": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "leader": { - "type": "boolean" - }, - "reachability": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "platform": { - "properties": { - "architecture": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "os": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "ressources": { - "properties": { - "memorybytes": { - "type": "long" - }, - "nanocpus": { - "type": "long" - } - } - }, - "spec": { - "properties": { - "avaiability": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "role": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "status": { - "properties": { - "addr": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "state": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "updatedad": { - "type": "date" - } - } - }, - "service": { - "properties": { - "createdat": { - "type": "date" - }, - "healtcheck_enabled": { - "type": "boolean" - }, - "id": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "mode": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "name": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "replicas": { - "type": "long" - }, - "updatedad": { - "type": "date" - }, - "updatestatus": { - "properties": { - "completedat": { - "type": "date" - }, - "message": { - "index": "analyzed", - "norms": { - "enabled": false - }, - "type": "string" - }, - "startedat": { - "type": "date" - }, - "state": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - } - } - }, - "version": { - "type": "long" - } - } } } }, diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index 94872e23689f..1d7aca38f571 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -581,23 +581,6 @@ "created": { "type": "date" }, - "health": { - "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "type": "keyword" - }, - "event_start_date": { - "type": "date" - } - } - }, "id": { "ignore_above": 1024, "type": "keyword" @@ -687,6 +670,30 @@ } } }, + "healthcheck": { + "properties": { + "event_end_date": { + "type": "date" + }, + "event_exit_code": { + "type": "long" + }, + "event_output": { + "ignore_above": 1024, + "type": "keyword" + }, + "event_start_date": { + "type": "date" + }, + "failingstreak": { + "type": "long" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, "info": { "properties": { "containers": { @@ -795,146 +802,6 @@ } } } - }, - "node": { - "properties": { - "createdat": { - "type": "date" - }, - "engine": { - "properties": { - "engine_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "plugin": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "managerstatus": { - "properties": { - "addr": { - "ignore_above": 1024, - "type": "keyword" - }, - "leader": { - "type": "boolean" - }, - "reachability": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "platform": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ressources": { - "properties": { - "memorybytes": { - "type": "long" - }, - "nanocpus": { - "type": "long" - } - } - }, - "spec": { - "properties": { - "avaiability": { - "ignore_above": 1024, - "type": "keyword" - }, - "role": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "status": { - "properties": { - "addr": { - "ignore_above": 1024, - "type": "keyword" - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "updatedad": { - "type": "date" - } - } - }, - "service": { - "properties": { - "createdat": { - "type": "date" - }, - "healtcheck_enabled": { - "type": "boolean" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "replicas": { - "type": "long" - }, - "updatedad": { - "type": "date" - }, - "updatestatus": { - "properties": { - "completedat": { - "type": "date" - }, - "message": { - "norms": false, - "type": "text" - }, - "startedat": { - "type": "date" - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "type": "long" - } - } } } }, diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index ba7bc2f041e0..587a4c56f4f6 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -1,5 +1,5 @@ #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "node", "service"] + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/module/docker/container/_meta/data.json b/metricbeat/module/docker/container/_meta/data.json index 3e36df399d65..5fec882399e7 100644 --- a/metricbeat/module/docker/container/_meta/data.json +++ b/metricbeat/module/docker/container/_meta/data.json @@ -31,13 +31,5 @@ "name": "container", "rtt": 115 }, - "health": { - "event_end_date": "2017-01-09T20:38:13.080472813+01:00", - "event_exit_code": 0, - "event_output": "0.005", - "event_start_date": "2017-01-09T20:38:12.999970865+01:00", - "failingstreak": 0, - "status": "healthy" - }, "type": "metricsets" } diff --git a/metricbeat/module/docker/container/_meta/fields.yml b/metricbeat/module/docker/container/_meta/fields.yml index d70523ecea60..cf56b0a142f8 100644 --- a/metricbeat/module/docker/container/_meta/fields.yml +++ b/metricbeat/module/docker/container/_meta/fields.yml @@ -40,24 +40,3 @@ type: long description: > Size of the files that have been created or changed since creation. - - name: health - type: group - description: > - Container health metrics. - fields: - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: keyword - description: > - Healthcheck output - - name: event_exit_code - type: integer - description: > - Healthcheck status code diff --git a/metricbeat/module/docker/container/container.go b/metricbeat/module/docker/container/container.go index bfc0c32fa095..0606072cdfca 100644 --- a/metricbeat/module/docker/container/container.go +++ b/metricbeat/module/docker/container/container.go @@ -48,5 +48,5 @@ func (m *MetricSet) Fetch() ([]common.MapStr, error) { if err != nil { return nil, err } - return eventsMapping(containers, m), nil + return eventsMapping(containers), nil } diff --git a/metricbeat/module/docker/container/data.go b/metricbeat/module/docker/container/data.go index ea6dd77f6356..199cb4df2aef 100644 --- a/metricbeat/module/docker/container/data.go +++ b/metricbeat/module/docker/container/data.go @@ -6,19 +6,18 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/module/docker" - "strings" dc "github.com/fsouza/go-dockerclient" ) -func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { +func eventsMapping(containersList []dc.APIContainers) []common.MapStr { myEvents := []common.MapStr{} for _, container := range containersList { - myEvents = append(myEvents, eventMapping(&container, m)) + myEvents = append(myEvents, eventMapping(&container)) } return myEvents } -func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { +func eventMapping(cont *dc.APIContainers) common.MapStr { event := common.MapStr{ "created": common.Time(time.Unix(cont.Created, 0)), "id": cont.ID, @@ -32,24 +31,6 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "status": cont.Status, } -// Check id container have health metrics configured -if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { - container, _ := m.dockerClient.InspectContainer(cont.ID) - - last_event := len(container.State.Health.Log)-1 - if last_event >= 0 { - health := common.MapStr{ - "status": container.State.Health.Status, - "failingstreak": container.State.Health.FailingStreak, - "event_start_date": container.State.Health.Log[last_event].Start, - "event_end_date": container.State.Health.Log[last_event].End, - "event_exit_code": container.State.Health.Log[last_event].ExitCode, - "event_output": container.State.Health.Log[last_event].Output, - } - event["health"] = health - } -} - labels := docker.DeDotLabels(cont.Labels) if len(labels) > 0 { diff --git a/metricbeat/module/docker/node/_meta/data.json b/metricbeat/module/docker/node/_meta/data.json deleted file mode 100644 index f03d1b95fb89..000000000000 --- a/metricbeat/module/docker/node/_meta/data.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "@timestamp": "2016-05-23T08:05:34.853Z", - "beat": { - "hostname": "host.example.com", - "name": "host.example.com" - }, - "docker": { - "node": { - "createdat": "2017-01-10T05:37:07.548757912Z", - "updatedat": "2017-01-10T05:37:08.159552729Z", - "id": "4be260de8fc1213c9ff58789b8221e70c53f5af5d5a3915ff7de4b81b357d851", - "hostname": "thisisatest", - "labels": { - "swarm_labels_toto": "valueoftotolabel", - "swarm_number": "1" - }, - "spec": { - "role": "manager", - "avaiability": "active" - }, - "platform": { - "architecture": "x86_64", - "os": "Linux" - }, - "ressources": { - "nanocpus": 4000000000, - "memorybytes": 8115884032 - }, - "status": { - "state": "ready", - "addr": "127.0.0.1" - }, - "manager": { - "leader": true, - "reachability": "reachable", - "addr": "192.168.1.38:2377" - }, - "engine": { - "version": "1.13.0-rc5", - "labels": - { - "enginelabel1=enginelabel1value" - } - } - } - }, - "metricset": { - "host": "/var/run/docker.sock", - "module": "docker", - "name": "node", - "rtt": 115 - }, - "type": "metricsets" -} diff --git a/metricbeat/module/docker/node/_meta/docs.asciidoc b/metricbeat/module/docker/node/_meta/docs.asciidoc deleted file mode 100644 index cf4f9f984d02..000000000000 --- a/metricbeat/module/docker/node/_meta/docs.asciidoc +++ /dev/null @@ -1,4 +0,0 @@ -=== Docker Node Metricset - -The Docker Swarm `node` metricset collects information and statistics about -running nodes in Docker cluster. diff --git a/metricbeat/module/docker/node/_meta/fields.yml b/metricbeat/module/docker/node/_meta/fields.yml deleted file mode 100644 index 383f67c88bcc..000000000000 --- a/metricbeat/module/docker/node/_meta/fields.yml +++ /dev/null @@ -1,104 +0,0 @@ -- name: node - type: group - description: > - Docker node metrics. - fields: - - - name: createdat - type: date - description: > - date where the node has been added to the cluster - - name: updatedad - type: date - description: > - last gossip message - - name: id - type: keyword - description: > - Unique node id. - - name: hostname - type: keyword - description: > - hostname of the node - - name: spec - type: group - description: > - Configured status - fields: - - name: role - type: keyword - description: > - Wanted role - - name: avaiability - type: keyword - description: > - wanted status. - - name: platform - type: group - description: > - Node information hardware and system - fields: - - name: architecture - type: keyword - description: > - Cpu architecture of the node. - - name: os - type: keyword - description: > - OS node. - - name: ressources - type: group - description: > - available ressources on the node - fields: - - name: nanocpus - type: long - description: > - available CPU ressources - - name: memorybytes - type: long - description: > - available Memory ressources - - name: engine - type: group - description: > - docker engine information - fields: - - name: engine_version - type: keyword - description: > - Docker engine version number - - name: plugin - type: keyword - description: > - Docker plugin installed on the node - - name: status - type: group - description: > - docker swarm node status - fields: - - name: state - type: keyword - description: > - Docker engine state - - name: addr - type: keyword - description: > - docker - - name: managerstatus - type: group - description: > - docker swarm manager status - fields: - - name: leader - type: boolean - description: > - Docker engine manager state - - name: reachability - type: keyword - description: > - docker - - name: addr - type: keyword - description: > - docker manager listenning addr diff --git a/metricbeat/module/docker/node/data.go b/metricbeat/module/docker/node/data.go deleted file mode 100644 index e1b5e9205186..000000000000 --- a/metricbeat/module/docker/node/data.go +++ /dev/null @@ -1,65 +0,0 @@ -package node - -import ( - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/metricbeat/module/docker" - - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" -) - -func eventsMapping(nodesList []swarm.Node) []common.MapStr { - myEvents := []common.MapStr{} - - for _, node := range nodesList { - myEvents = append(myEvents, eventMapping(&node)) - } - - return myEvents -} - -func eventMapping(node *swarm.Node) common.MapStr { - event := common.MapStr{ - "createdat": node.Meta.CreatedAt, - "updatedat": node.Meta.UpdatedAt, - "id": node.ID, - "hostname": node.Description.Hostname, - "spec": common.MapStr{ - "role": node.Spec.Role, - "avaiability": node.Spec.Availability, - }, - "platform": common.MapStr{ - "architecture": node.Description.Platform.Architecture, - "os": node.Description.Platform.OS, - }, - "status": common.MapStr{ - "state": node.Status.State, - "addr": node.Status.Addr, - }, - "ressources": common.MapStr{ - "nanocpus": node.Description.Resources.NanoCPUs, - "memorybytes": node.Description.Resources.MemoryBytes, - }, - "engine.version": node.Description.Engine.EngineVersion, - } - - if node.Spec.Role == "manager" { - //fmt.Println("this is a manager ",node.ManagerStatus.Leader) - manager := common.MapStr{ - "leader": node.ManagerStatus.Leader, - "reachability": node.ManagerStatus.Reachability, - "addr": node.ManagerStatus.Addr, - } - event["manager"] = manager - } - - swarm_labels := docker.DeDotLabels(node.Spec.Annotations.Labels) - if len(swarm_labels) > 0 { - event["labels"] = swarm_labels - } - engine_labels := docker.DeDotLabels(node.Description.Engine.Labels) - if len(engine_labels) > 0 { - event["engine.labels"] = engine_labels - } - - return event -} diff --git a/metricbeat/module/docker/node/node.go b/metricbeat/module/docker/node/node.go deleted file mode 100644 index 40799a15ec0b..000000000000 --- a/metricbeat/module/docker/node/node.go +++ /dev/null @@ -1,53 +0,0 @@ -package node - -import ( - dc "github.com/fsouza/go-dockerclient" - - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/metricbeat/mb" - "github.com/elastic/beats/metricbeat/module/docker" -) - -func init() { - if err := mb.Registry.AddMetricSet("docker", "node", New, docker.HostParser); err != nil { - panic(err) - } -} - -type MetricSet struct { - mb.BaseMetricSet - dockerClient *dc.Client -} - -// New creates a new instance of the docker container MetricSet. -func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - logp.Warn("EXPERIMENTAL: The docker node metricset is experimental") - - config := docker.Config{} - if err := base.Module().UnpackConfig(&config); err != nil { - return nil, err - } - - client, err := docker.NewDockerClient(base.HostData().URI, config) - if err != nil { - return nil, err - } - - return &MetricSet{ - BaseMetricSet: base, - dockerClient: client, - }, nil -} - -// Fetch returns a list of all containers as events. -// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-nodes. -func (m *MetricSet) Fetch() ([]common.MapStr, error) { - // Fetch a list of all nodes. - nodes, err := m.dockerClient.ListNodes(dc.ListNodesOptions{}) - if err != nil { - return nil, err - } - - return eventsMapping(nodes), nil -} diff --git a/metricbeat/module/docker/node/node_integration_test.go b/metricbeat/module/docker/node/node_integration_test.go deleted file mode 100644 index 5a35029ef229..000000000000 --- a/metricbeat/module/docker/node/node_integration_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build integration - -package node - -import ( - "testing" - - mbtest "github.com/elastic/beats/metricbeat/mb/testing" -) - -func TestData(t *testing.T) { - f := mbtest.NewEventsFetcher(t, getConfig()) - err := mbtest.WriteEvents(f, t) - if err != nil { - t.Fatal("write", err) - } -} - -func getConfig() map[string]interface{} { - return map[string]interface{}{ - "module": "docker", - "metricsets": []string{"node"}, - "hosts": []string{"unix:///var/run/docker.sock"}, - } -} diff --git a/metricbeat/module/docker/service/_meta/data.json b/metricbeat/module/docker/service/_meta/data.json deleted file mode 100644 index 14dcbe4bc927..000000000000 --- a/metricbeat/module/docker/service/_meta/data.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "@timestamp": "2017-01-11T15:45:19.162Z", - "beat": { - "hostname": "smusso-ThinkPad", - "name": "smusso-ThinkPad", - "version": "6.0.0-alpha1" - }, - "docker": { - "service": { - "replicas": 2, - "createdat": "2017-01-11T11:35:53.432238684Z", - "healtcheck_enabled": true, - "id": "1vyemp33ktfmk7xpfmlg29ns0", - "labels": { - "label1": "thisisatest" - }, - "mode": "Replicated", - "name": "elasticsearch", - "updatedat": "2017-01-11T15:45:03.726977327Z", - "version": 905 - } - }, - "metricset": { - "host": "/var/run/docker.sock", - "module": "docker", - "name": "service", - "rtt": 3967 - }, - "type": "metricsets" -} diff --git a/metricbeat/module/docker/service/_meta/docs.asciidoc b/metricbeat/module/docker/service/_meta/docs.asciidoc deleted file mode 100644 index 1d1858fabb24..000000000000 --- a/metricbeat/module/docker/service/_meta/docs.asciidoc +++ /dev/null @@ -1,4 +0,0 @@ -=== Docker Service Metricset - -The Docker Swarm `service` metricset collects information and statistics about -running services in Docker cluster. diff --git a/metricbeat/module/docker/service/_meta/fields.yml b/metricbeat/module/docker/service/_meta/fields.yml deleted file mode 100644 index 4d16dcc426bc..000000000000 --- a/metricbeat/module/docker/service/_meta/fields.yml +++ /dev/null @@ -1,59 +0,0 @@ -- name: service - type: group - description: > - Docker service metrics. - fields: - - - name: id - type: keyword - description: > - service id - - name: createdat - type: date - description: > - date where the service has been created - - name: name - type: keyword - description: > - service name - - name: updatedad - type: date - description: > - last service specification change date - - name: mode - type: keyword - description: > - Service mode (replicated or global) - - name: replicas - type: integer - description: > - number of replicas if service mode is replicated - - name: healtcheck_enabled - type: boolean - description: > - check if healthcheck is activated in container specifications - - name: version - type: integer - description: > - service update versionning - - name: updatestatus - type: group - description: > - check update status - fields: - - name: "state" - type: keyword - description: > - update state - - name: "startedat" - type: date - description: > - update started date - - name: "completedat" - type: date - description: > - update completed date - - name: "message" - type: "text" - description: > - update message diff --git a/metricbeat/module/docker/service/data.go b/metricbeat/module/docker/service/data.go deleted file mode 100644 index fa2445ce2974..000000000000 --- a/metricbeat/module/docker/service/data.go +++ /dev/null @@ -1,83 +0,0 @@ -package service - -import ( - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/metricbeat/module/docker" - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm" - "reflect" -) - -func eventsMapping(serviceList []swarm.Service) []common.MapStr { - myEvents := []common.MapStr{} - - for _, service := range serviceList { - myEvents = append(myEvents, eventMapping(&service)) - } - - return myEvents -} - -func eventMapping(service *swarm.Service) common.MapStr { - - event := common.MapStr{ - "id": service.ID, - "version": service.Meta.Version.Index, - "createdat": service.Meta.CreatedAt, - "updatedat": service.Meta.UpdatedAt, - "name": service.Spec.Annotations.Name, - } - - // Do not insert updatestatus map if no updatestatus is present - if service.UpdateStatus.Message != "" { - updatestatus := common.MapStr{ - "state": service.UpdateStatus.State, - "startedat": service.UpdateStatus.StartedAt, - "completedat": service.UpdateStatus.CompletedAt, - "message": service.UpdateStatus.Message, - } - event["updatestatus"] = updatestatus - } - - // Check service mode - if service.Spec.Mode.Replicated != nil { - event["mode"] = "Replicated" - event["replicas"] = service.Spec.Mode.Replicated.Replicas - } else { - event["mode"] = "Global" - } - - previousspec_labels := common.MapStr{} - spec_labels := common.MapStr{} - - if service.PreviousSpec != nil && service.PreviousSpec.Annotations.Labels != nil { - previousspec_labels = docker.DeDotLabels(service.PreviousSpec.Annotations.Labels) - } - - if service.Spec.Annotations.Labels != nil { - spec_labels = docker.DeDotLabels(service.Spec.Annotations.Labels) - } - - // Print previous label only if they have been modify - if len(spec_labels) != 0 || len(previousspec_labels) != 0 { - if len(spec_labels) != 0 && len(previousspec_labels) != 0 { - if reflect.DeepEqual(spec_labels, previousspec_labels) { - event["labels"] = spec_labels - } else { - event["previousspec.labels"] = previousspec_labels - event["labels"] = spec_labels - } - } else if len(spec_labels) == 0 && len(previousspec_labels) != 0 { - event["previousspec.labels"] = previousspec_labels - } else { - event["labels"] = spec_labels - } - } - - if service.Spec.TaskTemplate.ContainerSpec.Healthcheck != nil { - event["healtcheck_enabled"] = true - } else { - event["healtcheck_enabled"] = false - } - - return event -} diff --git a/metricbeat/module/docker/service/service.go b/metricbeat/module/docker/service/service.go deleted file mode 100644 index f43389348bef..000000000000 --- a/metricbeat/module/docker/service/service.go +++ /dev/null @@ -1,53 +0,0 @@ -package service - -import ( - dc "github.com/fsouza/go-dockerclient" - - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/logp" - "github.com/elastic/beats/metricbeat/mb" - "github.com/elastic/beats/metricbeat/module/docker" -) - -func init() { - if err := mb.Registry.AddMetricSet("docker", "service", New, docker.HostParser); err != nil { - panic(err) - } -} - -type MetricSet struct { - mb.BaseMetricSet - dockerClient *dc.Client -} - -// New creates a new instance of the docker services MetricSet. -func New(base mb.BaseMetricSet) (mb.MetricSet, error) { - logp.Warn("EXPERIMENTAL: The docker service metricset is experimental") - - config := docker.Config{} - if err := base.Module().UnpackConfig(&config); err != nil { - return nil, err - } - - client, err := docker.NewDockerClient(base.HostData().URI, config) - if err != nil { - return nil, err - } - - return &MetricSet{ - BaseMetricSet: base, - dockerClient: client, - }, nil -} - -// Fetch returns a list of all services as events. -// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-services. -func (m *MetricSet) Fetch() ([]common.MapStr, error) { - // Fetch a list of all services. - services, err := m.dockerClient.ListServices(dc.ListServicesOptions{}) - if err != nil { - return nil, err - } - - return eventsMapping(services), nil -} diff --git a/metricbeat/module/docker/service/service_integration_test.go b/metricbeat/module/docker/service/service_integration_test.go deleted file mode 100644 index e3a5a5369a7e..000000000000 --- a/metricbeat/module/docker/service/service_integration_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build integration - -package service - -import ( - "testing" - - mbtest "github.com/elastic/beats/metricbeat/mb/testing" -) - -func TestData(t *testing.T) { - f := mbtest.NewEventsFetcher(t, getConfig()) - err := mbtest.WriteEvents(f, t) - if err != nil { - t.Fatal("write", err) - } -} - -func getConfig() map[string]interface{} { - return map[string]interface{}{ - "module": "docker", - "metricsets": []string{"service"}, - "hosts": []string{"unix:///var/run/docker.sock"}, - } -} From 61273fc14e9d28982fb27f1a0a474c01b0ab7ffe Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:36:27 +0100 Subject: [PATCH 21/27] add healthcheck metricset in docker module --- .../docs/modules/docker/healthcheck.asciidoc | 19 +++++++ .../module/docker/healthcheck/_meta/data.json | 24 +++++++++ .../docker/healthcheck/_meta/docs.asciidoc | 4 ++ .../docker/healthcheck/_meta/fields.yml | 29 +++++++++++ .../healthcheck/container_integration_test.go | 25 +++++++++ metricbeat/module/docker/healthcheck/data.go | 50 ++++++++++++++++++ .../module/docker/healthcheck/healthcheck.go | 52 +++++++++++++++++++ 7 files changed, 203 insertions(+) create mode 100644 metricbeat/docs/modules/docker/healthcheck.asciidoc create mode 100644 metricbeat/module/docker/healthcheck/_meta/data.json create mode 100644 metricbeat/module/docker/healthcheck/_meta/docs.asciidoc create mode 100644 metricbeat/module/docker/healthcheck/_meta/fields.yml create mode 100644 metricbeat/module/docker/healthcheck/container_integration_test.go create mode 100644 metricbeat/module/docker/healthcheck/data.go create mode 100644 metricbeat/module/docker/healthcheck/healthcheck.go diff --git a/metricbeat/docs/modules/docker/healthcheck.asciidoc b/metricbeat/docs/modules/docker/healthcheck.asciidoc new file mode 100644 index 000000000000..220ba07630d9 --- /dev/null +++ b/metricbeat/docs/modules/docker/healthcheck.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-docker-healthcheck]] +include::../../../module/docker/healthcheck/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/docker/healthcheck/_meta/data.json[] +---- diff --git a/metricbeat/module/docker/healthcheck/_meta/data.json b/metricbeat/module/docker/healthcheck/_meta/data.json new file mode 100644 index 000000000000..16e91a84feba --- /dev/null +++ b/metricbeat/module/docker/healthcheck/_meta/data.json @@ -0,0 +1,24 @@ +{ + "@timestamp": "2016-05-23T08:05:34.853Z", + "beat": { + "hostname": "host.example.com", + "name": "host.example.com" + }, + "docker": { + "healthcheck": { + "event_end_date": "2017-01-09T20:38:13.080472813+01:00", + "event_exit_code": 0, + "event_output": "this is an event output", + "event_start_date": "2017-01-09T20:38:12.999970865+01:00", + "failingstreak": 0, + "status": "healthy" + } + }, + "metricset": { + "host": "/var/run/docker.sock", + "module": "docker", + "name": "container", + "rtt": 115 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc new file mode 100644 index 000000000000..3c095e4e9c0e --- /dev/null +++ b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +=== Docker Container Metricset + +The Docker `container` metricset collects information and statistics about +running Docker containers. diff --git a/metricbeat/module/docker/healthcheck/_meta/fields.yml b/metricbeat/module/docker/healthcheck/_meta/fields.yml new file mode 100644 index 000000000000..4cd5c8dc5ba2 --- /dev/null +++ b/metricbeat/module/docker/healthcheck/_meta/fields.yml @@ -0,0 +1,29 @@ +- name: healthcheck + type: group + description: > + Docker container metrics. + fields: + - name: event_end_date + type: date + description: > + Healthcheck end date + - name: event_start_date + type: date + description: > + Healthcheck start date + - name: event_output + type: keyword + description: > + Healthcheck output + - name: event_exit_code + type: integer + description: > + Healthcheck status code + - name: failingstreak + type: integer + description: > + concurent failed check + - name: status + type: keyword + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/healthcheck/container_integration_test.go b/metricbeat/module/docker/healthcheck/container_integration_test.go new file mode 100644 index 000000000000..8c1356f7366c --- /dev/null +++ b/metricbeat/module/docker/healthcheck/container_integration_test.go @@ -0,0 +1,25 @@ +// +build integration + +package healthcheck + +import ( + "testing" + + mbtest "github.com/elastic/beats/metricbeat/mb/testing" +) + +func TestData(t *testing.T) { + f := mbtest.NewEventsFetcher(t, getConfig()) + err := mbtest.WriteEvents(f, t) + if err != nil { + t.Fatal("write", err) + } +} + +func getConfig() map[string]interface{} { + return map[string]interface{}{ + "module": "docker", + "metricsets": []string{"healthcheck"}, + "hosts": []string{"unix:///var/run/docker.sock"}, + } +} diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go new file mode 100644 index 000000000000..d436092c2cb8 --- /dev/null +++ b/metricbeat/module/docker/healthcheck/data.go @@ -0,0 +1,50 @@ +package healthcheck + +import ( + //"time" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" + + dc "github.com/fsouza/go-dockerclient" + "reflect" + "strings" +) + +func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { + myEvents := []common.MapStr{} + emptyEvent := common.MapStr{} + for _, container := range containersList { + returnevent := eventMapping(&container, m) + if !reflect.DeepEqual(emptyEvent, returnevent) { + myEvents = append(myEvents, eventMapping(&container, m)) + } + } + return myEvents +} + +func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { + event := common.MapStr{} + if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { + container, _ := m.dockerClient.InspectContainer(cont.ID) + last_event := len(container.State.Health.Log) - 1 + if last_event >= 0 { + event = common.MapStr{ + mb.ModuleData: common.MapStr{ + "container": common.MapStr{ + "name": docker.ExtractContainerName(cont.Names), + }, + }, + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event_start_date": common.Time(container.State.Health.Log[last_event].Start), + "event_end_date": common.Time(container.State.Health.Log[last_event].End), + "event_exit_code": container.State.Health.Log[last_event].ExitCode, + "event_output": container.State.Health.Log[last_event].Output, + } + } + } + + return event +} diff --git a/metricbeat/module/docker/healthcheck/healthcheck.go b/metricbeat/module/docker/healthcheck/healthcheck.go new file mode 100644 index 000000000000..0c775056e105 --- /dev/null +++ b/metricbeat/module/docker/healthcheck/healthcheck.go @@ -0,0 +1,52 @@ +package healthcheck + +import ( + dc "github.com/fsouza/go-dockerclient" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/docker" +) + +func init() { + if err := mb.Registry.AddMetricSet("docker", "healthcheck", New, docker.HostParser); err != nil { + panic(err) + } +} + +type MetricSet struct { + mb.BaseMetricSet + dockerClient *dc.Client +} + +// New creates a new instance of the docker container MetricSet. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("EXPERIMENTAL: The docker healthcheck metricset is experimental") + + config := docker.Config{} + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + client, err := docker.NewDockerClient(base.HostData().URI, config) + if err != nil { + return nil, err + } + + return &MetricSet{ + BaseMetricSet: base, + dockerClient: client, + }, nil +} + +// Fetch returns a list of all containers as events. +// This is based on https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/list-containers. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + // Fetch a list of all containers. + containers, err := m.dockerClient.ListContainers(dc.ListContainersOptions{}) + if err != nil { + return nil, err + } + return eventsMapping(containers, m), nil +} From 3391a69a47f48da418605bc1d8e6e08c2aad2a22 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 11:53:21 +0100 Subject: [PATCH 22/27] Set metricbeat.full.yml to default value --- metricbeat/metricbeat.full.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index cb0adf204242..b2fa770d21cb 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -102,11 +102,11 @@ metricbeat.modules: #hosts: ["localhost:8091"] #------------------------------- Docker Module ------------------------------- -- module: docker - metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] - hosts: ["unix:///var/run/docker.sock"] - enabled: true - period: 10s +#- module: docker + #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #hosts: ["unix:///var/run/docker.sock"] + #enabled: true + #period: 10s # To connect to Docker over TLS you must specify a client and CA certificate. #ssl: @@ -865,4 +865,3 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 - From 09aa8c8a9b6b4b2ee966d2405278c2a40edb1df2 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 12:00:03 +0100 Subject: [PATCH 23/27] Fix shell in metricbeat.full.yml --- metricbeat/metricbeat.full.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index b2fa770d21cb..98f2b892c7a0 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -865,3 +865,4 @@ logging.files: # Number of rotated log files to keep. Oldest files will be deleted first. #keepfiles: 7 + From b14b29055897af6b5b8388abde4582120adfb79b Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 13:28:35 +0100 Subject: [PATCH 24/27] Last commit, add comment --- metricbeat/module/docker/healthcheck/_meta/docs.asciidoc | 4 ++-- metricbeat/module/docker/healthcheck/data.go | 4 ++++ metricbeat/module/docker/healthcheck/healthcheck.go | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc index 3c095e4e9c0e..bfcf644a1069 100644 --- a/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc +++ b/metricbeat/module/docker/healthcheck/_meta/docs.asciidoc @@ -1,4 +1,4 @@ -=== Docker Container Metricset +=== Docker healthcheck Metricset -The Docker `container` metricset collects information and statistics about +The Docker `healthcheck` metricset collects information and statistics about running Docker containers. diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go index d436092c2cb8..4a8d630f2c5c 100644 --- a/metricbeat/module/docker/healthcheck/data.go +++ b/metricbeat/module/docker/healthcheck/data.go @@ -14,9 +14,11 @@ import ( func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} + // Set an empty map in order to detect empty healthcheck event emptyEvent := common.MapStr{} for _, container := range containersList { returnevent := eventMapping(&container, m) + // Compare event to empty event if !reflect.DeepEqual(emptyEvent, returnevent) { myEvents = append(myEvents, eventMapping(&container, m)) } @@ -26,9 +28,11 @@ func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.Map func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { event := common.MapStr{} + // Detect if healthcheck is available for container if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") { container, _ := m.dockerClient.InspectContainer(cont.ID) last_event := len(container.State.Health.Log) - 1 + // Detect if an healthcheck already occured if last_event >= 0 { event = common.MapStr{ mb.ModuleData: common.MapStr{ diff --git a/metricbeat/module/docker/healthcheck/healthcheck.go b/metricbeat/module/docker/healthcheck/healthcheck.go index 0c775056e105..f487e2708bbe 100644 --- a/metricbeat/module/docker/healthcheck/healthcheck.go +++ b/metricbeat/module/docker/healthcheck/healthcheck.go @@ -20,7 +20,7 @@ type MetricSet struct { dockerClient *dc.Client } -// New creates a new instance of the docker container MetricSet. +// New creates a new instance of the docker healthcheck MetricSet. func New(base mb.BaseMetricSet) (mb.MetricSet, error) { logp.Warn("EXPERIMENTAL: The docker healthcheck metricset is experimental") From fc031d8dfd290e0a32bf8e1f170205930d362960 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 15:34:08 +0100 Subject: [PATCH 25/27] set metricset list in alphabetical order, remap event healtcheck data, compare eventMapping to nil --- metricbeat/_meta/beat.full.yml | 2 +- metricbeat/docs/fields.asciidoc | 39 +++++++++++-------- metricbeat/docs/modules/docker.asciidoc | 2 +- metricbeat/metricbeat.full.yml | 2 +- metricbeat/metricbeat.template-es2x.json | 30 +++++++------- metricbeat/metricbeat.template.json | 28 +++++++------ metricbeat/module/docker/_meta/config.yml | 2 +- .../module/docker/healthcheck/_meta/data.json | 14 ++++--- .../docker/healthcheck/_meta/fields.yml | 37 ++++++++++-------- metricbeat/module/docker/healthcheck/data.go | 26 ++++++------- 10 files changed, 102 insertions(+), 80 deletions(-) diff --git a/metricbeat/_meta/beat.full.yml b/metricbeat/_meta/beat.full.yml index 9ca948463296..96967f3a20d7 100644 --- a/metricbeat/_meta/beat.full.yml +++ b/metricbeat/_meta/beat.full.yml @@ -103,7 +103,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index a50f820cc883..194c04690f7b 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -1179,50 +1179,57 @@ Docker container metrics. [float] -=== docker.healthcheck.event_end_date +=== docker.healthcheck.failingstreak -type: date +type: integer -Healthcheck end date +concurent failed check [float] -=== docker.healthcheck.event_start_date +=== docker.healthcheck.status -type: date +type: keyword -Healthcheck start date +Healthcheck status code [float] -=== docker.healthcheck.event_output +== event Fields -type: keyword +event fields. -Healthcheck output [float] -=== docker.healthcheck.event_exit_code +=== docker.healthcheck.event.end_date -type: integer +type: date -Healthcheck status code +Healthcheck end date [float] -=== docker.healthcheck.failingstreak +=== docker.healthcheck.event.start_date -type: integer +type: date -concurent failed check +Healthcheck start date [float] -=== docker.healthcheck.status +=== docker.healthcheck.event.output type: keyword +Healthcheck output + + +[float] +=== docker.healthcheck.event.exit_code + +type: integer + Healthcheck status code diff --git a/metricbeat/docs/modules/docker.asciidoc b/metricbeat/docs/modules/docker.asciidoc index 44697ff78e57..2388f6ea9e0b 100644 --- a/metricbeat/docs/modules/docker.asciidoc +++ b/metricbeat/docs/modules/docker.asciidoc @@ -21,7 +21,7 @@ in <>. Here is an example configuration: ---- metricbeat.modules: #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 98f2b892c7a0..f6bf6e4381f6 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -103,7 +103,7 @@ metricbeat.modules: #------------------------------- Docker Module ------------------------------- #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/metricbeat.template-es2x.json b/metricbeat/metricbeat.template-es2x.json index 53a17d824105..cf971336028a 100644 --- a/metricbeat/metricbeat.template-es2x.json +++ b/metricbeat/metricbeat.template-es2x.json @@ -670,19 +670,23 @@ }, "healthcheck": { "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "index": "not_analyzed", - "type": "string" - }, - "event_start_date": { - "type": "date" + "event": { + "properties": { + "end_date": { + "type": "date" + }, + "exit_code": { + "type": "long" + }, + "output": { + "ignore_above": 1024, + "index": "not_analyzed", + "type": "string" + }, + "start_date": { + "type": "date" + } + } }, "failingstreak": { "type": "long" diff --git a/metricbeat/metricbeat.template.json b/metricbeat/metricbeat.template.json index 1d7aca38f571..b270e0188c9f 100644 --- a/metricbeat/metricbeat.template.json +++ b/metricbeat/metricbeat.template.json @@ -672,18 +672,22 @@ }, "healthcheck": { "properties": { - "event_end_date": { - "type": "date" - }, - "event_exit_code": { - "type": "long" - }, - "event_output": { - "ignore_above": 1024, - "type": "keyword" - }, - "event_start_date": { - "type": "date" + "event": { + "properties": { + "end_date": { + "type": "date" + }, + "exit_code": { + "type": "long" + }, + "output": { + "ignore_above": 1024, + "type": "keyword" + }, + "start_date": { + "type": "date" + } + } }, "failingstreak": { "type": "long" diff --git a/metricbeat/module/docker/_meta/config.yml b/metricbeat/module/docker/_meta/config.yml index 587a4c56f4f6..f2440a78afdf 100644 --- a/metricbeat/module/docker/_meta/config.yml +++ b/metricbeat/module/docker/_meta/config.yml @@ -1,5 +1,5 @@ #- module: docker - #metricsets: ["cpu", "info", "memory", "network", "diskio", "container", "healthcheck"] + #metricsets: ["container", "cpu", "diskio", "healthcheck", "info", "memory", "network"] #hosts: ["unix:///var/run/docker.sock"] #enabled: true #period: 10s diff --git a/metricbeat/module/docker/healthcheck/_meta/data.json b/metricbeat/module/docker/healthcheck/_meta/data.json index 16e91a84feba..73978d883839 100644 --- a/metricbeat/module/docker/healthcheck/_meta/data.json +++ b/metricbeat/module/docker/healthcheck/_meta/data.json @@ -6,12 +6,16 @@ }, "docker": { "healthcheck": { - "event_end_date": "2017-01-09T20:38:13.080472813+01:00", - "event_exit_code": 0, - "event_output": "this is an event output", - "event_start_date": "2017-01-09T20:38:12.999970865+01:00", "failingstreak": 0, - "status": "healthy" + "status": "healthy", + "healthcheck": { + "event": { + "end_date": "2017-01-09T20:38:13.080472813+01:00", + "exit_code": 0, + "output": "this is an event output", + "start_date": "2017-01-09T20:38:12.999970865+01:00", + } + } } }, "metricset": { diff --git a/metricbeat/module/docker/healthcheck/_meta/fields.yml b/metricbeat/module/docker/healthcheck/_meta/fields.yml index 4cd5c8dc5ba2..0b37d42f13b8 100644 --- a/metricbeat/module/docker/healthcheck/_meta/fields.yml +++ b/metricbeat/module/docker/healthcheck/_meta/fields.yml @@ -3,22 +3,6 @@ description: > Docker container metrics. fields: - - name: event_end_date - type: date - description: > - Healthcheck end date - - name: event_start_date - type: date - description: > - Healthcheck start date - - name: event_output - type: keyword - description: > - Healthcheck output - - name: event_exit_code - type: integer - description: > - Healthcheck status code - name: failingstreak type: integer description: > @@ -27,3 +11,24 @@ type: keyword description: > Healthcheck status code + - name: event + type: group + description: > + event fields. + fields: + - name: end_date + type: date + description: > + Healthcheck end date + - name: start_date + type: date + description: > + Healthcheck start date + - name: output + type: keyword + description: > + Healthcheck output + - name: exit_code + type: integer + description: > + Healthcheck status code diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go index 4a8d630f2c5c..8fca6f4babe2 100644 --- a/metricbeat/module/docker/healthcheck/data.go +++ b/metricbeat/module/docker/healthcheck/data.go @@ -1,8 +1,6 @@ package healthcheck import ( - //"time" - "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/metricbeat/mb" "github.com/elastic/beats/metricbeat/module/docker" @@ -14,13 +12,11 @@ import ( func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr { myEvents := []common.MapStr{} - // Set an empty map in order to detect empty healthcheck event - emptyEvent := common.MapStr{} for _, container := range containersList { returnevent := eventMapping(&container, m) // Compare event to empty event - if !reflect.DeepEqual(emptyEvent, returnevent) { - myEvents = append(myEvents, eventMapping(&container, m)) + if !reflect.ValueOf(returnevent).IsNil() { + myEvents = append(myEvents, returnevent) } } return myEvents @@ -40,15 +36,17 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { "name": docker.ExtractContainerName(cont.Names), }, }, - "status": container.State.Health.Status, - "failingstreak": container.State.Health.FailingStreak, - "event_start_date": common.Time(container.State.Health.Log[last_event].Start), - "event_end_date": common.Time(container.State.Health.Log[last_event].End), - "event_exit_code": container.State.Health.Log[last_event].ExitCode, - "event_output": container.State.Health.Log[last_event].Output, + "status": container.State.Health.Status, + "failingstreak": container.State.Health.FailingStreak, + "event": common.MapStr{ + "start_date": common.Time(container.State.Health.Log[last_event].Start), + "end_date": common.Time(container.State.Health.Log[last_event].End), + "exit_code": container.State.Health.Log[last_event].ExitCode, + "output": container.State.Health.Log[last_event].Output, + }, } + return event } } - - return event + return nil } From 0be734073b8cbc5189181853d95ae486600d8ffc Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Fri, 20 Jan 2017 18:37:53 +0100 Subject: [PATCH 26/27] Delete external libs folder --- .../docker/api/types/blkiodev/blkio.go | 23 - .../docker/api/types/container/config.go | 64 -- .../api/types/container/container_create.go | 21 - .../api/types/container/container_update.go | 17 - .../api/types/container/container_wait.go | 17 - .../docker/api/types/container/host_config.go | 338 ---------- .../api/types/container/hostconfig_unix.go | 81 --- .../api/types/container/hostconfig_windows.go | 87 --- .../docker/api/types/mount/mount.go | 113 ---- .../docker/api/types/strslice/strslice.go | 30 - .../api/types/strslice/strslice_test.go | 86 --- .../docker/api/types/swarm/common.go | 27 - .../docker/api/types/swarm/container.go | 48 -- .../docker/api/types/swarm/network.go | 111 ---- .../github.com/docker/api/types/swarm/node.go | 114 ---- .../docker/api/types/swarm/secret.go | 31 - .../docker/api/types/swarm/service.go | 105 ---- .../docker/api/types/swarm/swarm.go | 197 ------ .../github.com/docker/api/types/swarm/task.go | 128 ---- .../docker/go-connections/nat/nat.go | 242 -------- .../docker/go-connections/nat/nat_test.go | 583 ------------------ .../docker/go-connections/nat/parse.go | 57 -- .../docker/go-connections/nat/parse_test.go | 54 -- .../docker/go-connections/nat/sort.go | 96 --- .../docker/go-connections/nat/sort_test.go | 85 --- 25 files changed, 2755 deletions(-) delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go delete mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go deleted file mode 100644 index 931ae10ab1ef..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev/blkio.go +++ /dev/null @@ -1,23 +0,0 @@ -package blkiodev - -import "fmt" - -// WeightDevice is a structure that holds device:weight pair -type WeightDevice struct { - Path string - Weight uint16 -} - -func (w *WeightDevice) String() string { - return fmt.Sprintf("%s:%d", w.Path, w.Weight) -} - -// ThrottleDevice is a structure that holds device:rate_per_second pair -type ThrottleDevice struct { - Path string - Rate uint64 -} - -func (t *ThrottleDevice) String() string { - return fmt.Sprintf("%s:%d", t.Path, t.Rate) -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go deleted file mode 100644 index e5ddd70665de..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/config.go +++ /dev/null @@ -1,64 +0,0 @@ -package container - -import ( - "time" - - //"github.com/docker/docker/api/types/strslice" - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice" - "github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat" - //"github.com/docker/go-connections/nat" -) - -// HealthConfig holds configuration settings for the HEALTHCHECK feature. -type HealthConfig struct { - // Test is the test to perform to check that the container is healthy. - // An empty slice means to inherit the default. - // The options are: - // {} : inherit healthcheck - // {"NONE"} : disable healthcheck - // {"CMD", args...} : exec arguments directly - // {"CMD-SHELL", command} : run command with system's default shell - Test []string `json:",omitempty"` - - // Zero means to inherit. Durations are expressed as integer nanoseconds. - Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks. - Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. - - // Retries is the number of consecutive failures needed to consider a container as unhealthy. - // Zero means inherit. - Retries int `json:",omitempty"` -} - -// Config contains the configuration data about a container. -// It should hold only portable information about the container. -// Here, "portable" means "independent from the host we are running on". -// Non-portable information *should* appear in HostConfig. -// All fields added to this struct must be marked `omitempty` to keep getting -// predictable hashes from the old `v1Compatibility` configuration. -type Config struct { - Hostname string // Hostname - Domainname string // Domainname - User string // User that will run the command(s) inside the container, also support user:group - AttachStdin bool // Attach the standard input, makes possible user interaction - AttachStdout bool // Attach the standard output - AttachStderr bool // Attach the standard error - ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports - Tty bool // Attach standard streams to a tty, including stdin if it is not closed. - OpenStdin bool // Open stdin - StdinOnce bool // If true, close stdin after the 1 attached client disconnects. - Env []string // List of environment variable to set in the container - Cmd strslice.StrSlice // Command to run when starting the container - Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy - ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific) - Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) - Volumes map[string]struct{} // List of volumes (mounts) used for the container - WorkingDir string // Current directory (PWD) in the command will be launched - Entrypoint strslice.StrSlice // Entrypoint to run when starting the container - NetworkDisabled bool `json:",omitempty"` // Is network disabled - MacAddress string `json:",omitempty"` // Mac Address of the container - OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile - Labels map[string]string // List of labels set to this container - StopSignal string `json:",omitempty"` // Signal to stop a container - StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container - Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go deleted file mode 100644 index c95023b814dc..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_create.go +++ /dev/null @@ -1,21 +0,0 @@ -package container - -// ---------------------------------------------------------------------------- -// DO NOT EDIT THIS FILE -// This file was generated by `swagger generate operation` -// -// See hack/generate-swagger-api.sh -// ---------------------------------------------------------------------------- - -// ContainerCreateCreatedBody container create created body -// swagger:model ContainerCreateCreatedBody -type ContainerCreateCreatedBody struct { - - // The ID of the created container - // Required: true - ID string `json:"Id"` - - // Warnings encountered when creating the container - // Required: true - Warnings []string `json:"Warnings"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go deleted file mode 100644 index 2339366fbd19..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_update.go +++ /dev/null @@ -1,17 +0,0 @@ -package container - -// ---------------------------------------------------------------------------- -// DO NOT EDIT THIS FILE -// This file was generated by `swagger generate operation` -// -// See hack/generate-swagger-api.sh -// ---------------------------------------------------------------------------- - -// ContainerUpdateOKBody container update o k body -// swagger:model ContainerUpdateOKBody -type ContainerUpdateOKBody struct { - - // warnings - // Required: true - Warnings []string `json:"Warnings"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go deleted file mode 100644 index 77ecdbaf7aed..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/container_wait.go +++ /dev/null @@ -1,17 +0,0 @@ -package container - -// ---------------------------------------------------------------------------- -// DO NOT EDIT THIS FILE -// This file was generated by `swagger generate operation` -// -// See hack/generate-swagger-api.sh -// ---------------------------------------------------------------------------- - -// ContainerWaitOKBody container wait o k body -// swagger:model ContainerWaitOKBody -type ContainerWaitOKBody struct { - - // Exit code of the container - // Required: true - StatusCode int64 `json:"StatusCode"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go deleted file mode 100644 index 889fc9356edb..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/host_config.go +++ /dev/null @@ -1,338 +0,0 @@ -package container - -import ( - "strings" - - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/blkiodev" - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice" - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount" - "github.com/fsouza/go-dockerclient/external/github.com/docker/go-units" - "github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat" - //"github.com/docker/docker/api/types/blkiodev" - //"github.com/docker/docker/api/types/mount" - //"github.com/docker/docker/api/types/strslice" - //"github.com/docker/go-connections/nat" - //"github.com/docker/go-units" -) - -// NetworkMode represents the container network stack. -type NetworkMode string - -// Isolation represents the isolation technology of a container. The supported -// values are platform specific -type Isolation string - -// IsDefault indicates the default isolation technology of a container. On Linux this -// is the native driver. On Windows, this is a Windows Server Container. -func (i Isolation) IsDefault() bool { - return strings.ToLower(string(i)) == "default" || string(i) == "" -} - -// IpcMode represents the container ipc stack. -type IpcMode string - -// IsPrivate indicates whether the container uses its private ipc stack. -func (n IpcMode) IsPrivate() bool { - return !(n.IsHost() || n.IsContainer()) -} - -// IsHost indicates whether the container uses the host's ipc stack. -func (n IpcMode) IsHost() bool { - return n == "host" -} - -// IsContainer indicates whether the container uses a container's ipc stack. -func (n IpcMode) IsContainer() bool { - parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" -} - -// Valid indicates whether the ipc stack is valid. -func (n IpcMode) Valid() bool { - parts := strings.Split(string(n), ":") - switch mode := parts[0]; mode { - case "", "host": - case "container": - if len(parts) != 2 || parts[1] == "" { - return false - } - default: - return false - } - return true -} - -// Container returns the name of the container ipc stack is going to be used. -func (n IpcMode) Container() string { - parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { - return parts[1] - } - return "" -} - -// UsernsMode represents userns mode in the container. -type UsernsMode string - -// IsHost indicates whether the container uses the host's userns. -func (n UsernsMode) IsHost() bool { - return n == "host" -} - -// IsPrivate indicates whether the container uses the a private userns. -func (n UsernsMode) IsPrivate() bool { - return !(n.IsHost()) -} - -// Valid indicates whether the userns is valid. -func (n UsernsMode) Valid() bool { - parts := strings.Split(string(n), ":") - switch mode := parts[0]; mode { - case "", "host": - default: - return false - } - return true -} - -// CgroupSpec represents the cgroup to use for the container. -type CgroupSpec string - -// IsContainer indicates whether the container is using another container cgroup -func (c CgroupSpec) IsContainer() bool { - parts := strings.SplitN(string(c), ":", 2) - return len(parts) > 1 && parts[0] == "container" -} - -// Valid indicates whether the cgroup spec is valid. -func (c CgroupSpec) Valid() bool { - return c.IsContainer() || c == "" -} - -// Container returns the name of the container whose cgroup will be used. -func (c CgroupSpec) Container() string { - parts := strings.SplitN(string(c), ":", 2) - if len(parts) > 1 { - return parts[1] - } - return "" -} - -// UTSMode represents the UTS namespace of the container. -type UTSMode string - -// IsPrivate indicates whether the container uses its private UTS namespace. -func (n UTSMode) IsPrivate() bool { - return !(n.IsHost()) -} - -// IsHost indicates whether the container uses the host's UTS namespace. -func (n UTSMode) IsHost() bool { - return n == "host" -} - -// Valid indicates whether the UTS namespace is valid. -func (n UTSMode) Valid() bool { - parts := strings.Split(string(n), ":") - switch mode := parts[0]; mode { - case "", "host": - default: - return false - } - return true -} - -// PidMode represents the pid namespace of the container. -type PidMode string - -// IsPrivate indicates whether the container uses its own new pid namespace. -func (n PidMode) IsPrivate() bool { - return !(n.IsHost() || n.IsContainer()) -} - -// IsHost indicates whether the container uses the host's pid namespace. -func (n PidMode) IsHost() bool { - return n == "host" -} - -// IsContainer indicates whether the container uses a container's pid namespace. -func (n PidMode) IsContainer() bool { - parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" -} - -// Valid indicates whether the pid namespace is valid. -func (n PidMode) Valid() bool { - parts := strings.Split(string(n), ":") - switch mode := parts[0]; mode { - case "", "host": - case "container": - if len(parts) != 2 || parts[1] == "" { - return false - } - default: - return false - } - return true -} - -// Container returns the name of the container whose pid namespace is going to be used. -func (n PidMode) Container() string { - parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { - return parts[1] - } - return "" -} - -// DeviceMapping represents the device mapping between the host and the container. -type DeviceMapping struct { - PathOnHost string - PathInContainer string - CgroupPermissions string -} - -// RestartPolicy represents the restart policies of the container. -type RestartPolicy struct { - Name string - MaximumRetryCount int -} - -// IsNone indicates whether the container has the "no" restart policy. -// This means the container will not automatically restart when exiting. -func (rp *RestartPolicy) IsNone() bool { - return rp.Name == "no" || rp.Name == "" -} - -// IsAlways indicates whether the container has the "always" restart policy. -// This means the container will automatically restart regardless of the exit status. -func (rp *RestartPolicy) IsAlways() bool { - return rp.Name == "always" -} - -// IsOnFailure indicates whether the container has the "on-failure" restart policy. -// This means the container will automatically restart of exiting with a non-zero exit status. -func (rp *RestartPolicy) IsOnFailure() bool { - return rp.Name == "on-failure" -} - -// IsUnlessStopped indicates whether the container has the -// "unless-stopped" restart policy. This means the container will -// automatically restart unless user has put it to stopped state. -func (rp *RestartPolicy) IsUnlessStopped() bool { - return rp.Name == "unless-stopped" -} - -// IsSame compares two RestartPolicy to see if they are the same -func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { - return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount -} - -// LogConfig represents the logging configuration of the container. -type LogConfig struct { - Type string - Config map[string]string -} - -// Resources contains container's resources (cgroups config, ulimits...) -type Resources struct { - // Applicable to all platforms - CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) - Memory int64 // Memory limit (in bytes) - NanoCPUs int64 `json:"NanoCpus"` // CPU quota in units of 10-9 CPUs. - - // Applicable to UNIX platforms - CgroupParent string // Parent cgroup. - BlkioWeight uint16 // Block IO weight (relative weight vs. other containers) - BlkioWeightDevice []*blkiodev.WeightDevice - BlkioDeviceReadBps []*blkiodev.ThrottleDevice - BlkioDeviceWriteBps []*blkiodev.ThrottleDevice - BlkioDeviceReadIOps []*blkiodev.ThrottleDevice - BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice - CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period - CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota - CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` // CPU real-time period - CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` // CPU real-time runtime - CpusetCpus string // CpusetCpus 0-2, 0,1 - CpusetMems string // CpusetMems 0-2, 0,1 - Devices []DeviceMapping // List of devices to map inside the container - DiskQuota int64 // Disk limit (in bytes) - KernelMemory int64 // Kernel memory limit (in bytes) - MemoryReservation int64 // Memory soft limit (in bytes) - MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap - MemorySwappiness *int64 // Tuning container memory swappiness behaviour - OomKillDisable *bool // Whether to disable OOM Killer or not - PidsLimit int64 // Setting pids limit for a container - Ulimits []*units.Ulimit // List of ulimits to be set in the container - - // Applicable to Windows - CPUCount int64 `json:"CpuCount"` // CPU count - CPUPercent int64 `json:"CpuPercent"` // CPU percent - IOMaximumIOps uint64 // Maximum IOps for the container system drive - IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive -} - -// UpdateConfig holds the mutable attributes of a Container. -// Those attributes can be updated at runtime. -type UpdateConfig struct { - // Contains container's resources (cgroups, ulimits) - Resources - RestartPolicy RestartPolicy -} - -// HostConfig the non-portable Config structure of a container. -// Here, "non-portable" means "dependent of the host we are running on". -// Portable information *should* appear in Config. -type HostConfig struct { - // Applicable to all platforms - Binds []string // List of volume bindings for this container - ContainerIDFile string // File (path) where the containerId is written - LogConfig LogConfig // Configuration of the logs for this container - NetworkMode NetworkMode // Network mode to use for the container - PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host - RestartPolicy RestartPolicy // Restart policy to be used for the container - AutoRemove bool // Automatically remove container when it exits - VolumeDriver string // Name of the volume driver used to mount volumes - VolumesFrom []string // List of volumes to take from other container - - // Applicable to UNIX platforms - CapAdd strslice.StrSlice // List of kernel capabilities to add to the container - CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container - DNS []string `json:"Dns"` // List of DNS server to lookup - DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for - DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for - ExtraHosts []string // List of extra hosts - GroupAdd []string // List of additional groups that the container process will run as - IpcMode IpcMode // IPC namespace to use for the container - Cgroup CgroupSpec // Cgroup to use for the container - Links []string // List of links (in the name:alias form) - OomScoreAdj int // Container preference for OOM-killing - PidMode PidMode // PID namespace to use for the container - Privileged bool // Is the container in privileged mode - PublishAllPorts bool // Should docker publish all exposed port for the container - ReadonlyRootfs bool // Is the container root filesystem in read-only - SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. - StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. - Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container - UTSMode UTSMode // UTS namespace to use for the container - UsernsMode UsernsMode // The user namespace to use for the container - ShmSize int64 // Total shm memory usage - Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container - Runtime string `json:",omitempty"` // Runtime to use with this container - - // Applicable to Windows - ConsoleSize [2]uint // Initial console size (height,width) - Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) - - // Contains container's resources (cgroups, ulimits) - Resources - - // Mounts specs used by the container - Mounts []mount.Mount `json:",omitempty"` - - // Run a custom init inside the container, if null, use the daemon's configured settings - Init *bool `json:",omitempty"` - - // Custom init path - InitPath string `json:",omitempty"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go deleted file mode 100644 index 9fb79bed6f39..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_unix.go +++ /dev/null @@ -1,81 +0,0 @@ -// +build !windows - -package container - -import "strings" - -// IsValid indicates if an isolation technology is valid -func (i Isolation) IsValid() bool { - return i.IsDefault() -} - -// IsPrivate indicates whether container uses its private network stack. -func (n NetworkMode) IsPrivate() bool { - return !(n.IsHost() || n.IsContainer()) -} - -// IsDefault indicates whether container uses the default network stack. -func (n NetworkMode) IsDefault() bool { - return n == "default" -} - -// NetworkName returns the name of the network stack. -func (n NetworkMode) NetworkName() string { - if n.IsBridge() { - return "bridge" - } else if n.IsHost() { - return "host" - } else if n.IsContainer() { - return "container" - } else if n.IsNone() { - return "none" - } else if n.IsDefault() { - return "default" - } else if n.IsUserDefined() { - return n.UserDefined() - } - return "" -} - -// IsBridge indicates whether container uses the bridge network stack -func (n NetworkMode) IsBridge() bool { - return n == "bridge" -} - -// IsHost indicates whether container uses the host network stack. -func (n NetworkMode) IsHost() bool { - return n == "host" -} - -// IsContainer indicates whether container uses a container network stack. -func (n NetworkMode) IsContainer() bool { - parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" -} - -// IsNone indicates whether container isn't using a network stack. -func (n NetworkMode) IsNone() bool { - return n == "none" -} - -// ConnectedContainer is the id of the container which network this container is connected to. -func (n NetworkMode) ConnectedContainer() string { - parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 { - return parts[1] - } - return "" -} - -// IsUserDefined indicates user-created network -func (n NetworkMode) IsUserDefined() bool { - return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() -} - -//UserDefined indicates user-created network -func (n NetworkMode) UserDefined() string { - if n.IsUserDefined() { - return string(n) - } - return "" -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go deleted file mode 100644 index 0ee332ba6899..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container/hostconfig_windows.go +++ /dev/null @@ -1,87 +0,0 @@ -package container - -import ( - "strings" -) - -// IsDefault indicates whether container uses the default network stack. -func (n NetworkMode) IsDefault() bool { - return n == "default" -} - -// IsNone indicates whether container isn't using a network stack. -func (n NetworkMode) IsNone() bool { - return n == "none" -} - -// IsContainer indicates whether container uses a container network stack. -// Returns false as windows doesn't support this mode -func (n NetworkMode) IsContainer() bool { - return false -} - -// IsBridge indicates whether container uses the bridge network stack -// in windows it is given the name NAT -func (n NetworkMode) IsBridge() bool { - return n == "nat" -} - -// IsHost indicates whether container uses the host network stack. -// returns false as this is not supported by windows -func (n NetworkMode) IsHost() bool { - return false -} - -// IsPrivate indicates whether container uses its private network stack. -func (n NetworkMode) IsPrivate() bool { - return !(n.IsHost() || n.IsContainer()) -} - -// ConnectedContainer is the id of the container which network this container is connected to. -// Returns blank string on windows -func (n NetworkMode) ConnectedContainer() string { - return "" -} - -// IsUserDefined indicates user-created network -func (n NetworkMode) IsUserDefined() bool { - return !n.IsDefault() && !n.IsNone() && !n.IsBridge() -} - -// IsHyperV indicates the use of a Hyper-V partition for isolation -func (i Isolation) IsHyperV() bool { - return strings.ToLower(string(i)) == "hyperv" -} - -// IsProcess indicates the use of process isolation -func (i Isolation) IsProcess() bool { - return strings.ToLower(string(i)) == "process" -} - -// IsValid indicates if an isolation technology is valid -func (i Isolation) IsValid() bool { - return i.IsDefault() || i.IsHyperV() || i.IsProcess() -} - -// NetworkName returns the name of the network stack. -func (n NetworkMode) NetworkName() string { - if n.IsDefault() { - return "default" - } else if n.IsBridge() { - return "nat" - } else if n.IsNone() { - return "none" - } else if n.IsUserDefined() { - return n.UserDefined() - } - - return "" -} - -//UserDefined indicates user-created network -func (n NetworkMode) UserDefined() string { - if n.IsUserDefined() { - return string(n) - } - return "" -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go deleted file mode 100644 index 31f2365b8ec0..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount/mount.go +++ /dev/null @@ -1,113 +0,0 @@ -package mount - -import ( - "os" -) - -// Type represents the type of a mount. -type Type string - -// Type constants -const ( - // TypeBind is the type for mounting host dir - TypeBind Type = "bind" - // TypeVolume is the type for remote storage volumes - TypeVolume Type = "volume" - // TypeTmpfs is the type for mounting tmpfs - TypeTmpfs Type = "tmpfs" -) - -// Mount represents a mount (volume). -type Mount struct { - Type Type `json:",omitempty"` - // Source specifies the name of the mount. Depending on mount type, this - // may be a volume name or a host path, or even ignored. - // Source is not supported for tmpfs (must be an empty value) - Source string `json:",omitempty"` - Target string `json:",omitempty"` - ReadOnly bool `json:",omitempty"` - - BindOptions *BindOptions `json:",omitempty"` - VolumeOptions *VolumeOptions `json:",omitempty"` - TmpfsOptions *TmpfsOptions `json:",omitempty"` -} - -// Propagation represents the propagation of a mount. -type Propagation string - -const ( - // PropagationRPrivate RPRIVATE - PropagationRPrivate Propagation = "rprivate" - // PropagationPrivate PRIVATE - PropagationPrivate Propagation = "private" - // PropagationRShared RSHARED - PropagationRShared Propagation = "rshared" - // PropagationShared SHARED - PropagationShared Propagation = "shared" - // PropagationRSlave RSLAVE - PropagationRSlave Propagation = "rslave" - // PropagationSlave SLAVE - PropagationSlave Propagation = "slave" -) - -// Propagations is the list of all valid mount propagations -var Propagations = []Propagation{ - PropagationRPrivate, - PropagationPrivate, - PropagationRShared, - PropagationShared, - PropagationRSlave, - PropagationSlave, -} - -// BindOptions defines options specific to mounts of type "bind". -type BindOptions struct { - Propagation Propagation `json:",omitempty"` -} - -// VolumeOptions represents the options for a mount of type volume. -type VolumeOptions struct { - NoCopy bool `json:",omitempty"` - Labels map[string]string `json:",omitempty"` - DriverConfig *Driver `json:",omitempty"` -} - -// Driver represents a volume driver. -type Driver struct { - Name string `json:",omitempty"` - Options map[string]string `json:",omitempty"` -} - -// TmpfsOptions defines options specific to mounts of type "tmpfs". -type TmpfsOptions struct { - // Size sets the size of the tmpfs, in bytes. - // - // This will be converted to an operating system specific value - // depending on the host. For example, on linux, it will be convered to - // use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with - // docker, uses a straight byte value. - // - // Percentages are not supported. - SizeBytes int64 `json:",omitempty"` - // Mode of the tmpfs upon creation - Mode os.FileMode `json:",omitempty"` - - // TODO(stevvooe): There are several more tmpfs flags, specified in the - // daemon, that are accepted. Only the most basic are added for now. - // - // From docker/docker/pkg/mount/flags.go: - // - // var validFlags = map[string]bool{ - // "": true, - // "size": true, X - // "mode": true, X - // "uid": true, - // "gid": true, - // "nr_inodes": true, - // "nr_blocks": true, - // "mpol": true, - // } - // - // Some of these may be straightforward to add, but others, such as - // uid/gid have implications in a clustered system. -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go deleted file mode 100644 index bad493fb89fd..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice.go +++ /dev/null @@ -1,30 +0,0 @@ -package strslice - -import "encoding/json" - -// StrSlice represents a string or an array of strings. -// We need to override the json decoder to accept both options. -type StrSlice []string - -// UnmarshalJSON decodes the byte slice whether it's a string or an array of -// strings. This method is needed to implement json.Unmarshaler. -func (e *StrSlice) UnmarshalJSON(b []byte) error { - if len(b) == 0 { - // With no input, we preserve the existing value by returning nil and - // leaving the target alone. This allows defining default values for - // the type. - return nil - } - - p := make([]string, 0, 1) - if err := json.Unmarshal(b, &p); err != nil { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - p = append(p, s) - } - - *e = p - return nil -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go deleted file mode 100644 index 1163b3652c98..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/strslice/strslice_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package strslice - -import ( - "encoding/json" - "reflect" - "testing" -) - -func TestStrSliceMarshalJSON(t *testing.T) { - for _, testcase := range []struct { - input StrSlice - expected string - }{ - // MADNESS(stevvooe): No clue why nil would be "" but empty would be - // "null". Had to make a change here that may affect compatibility. - {input: nil, expected: "null"}, - {StrSlice{}, "[]"}, - {StrSlice{"/bin/sh", "-c", "echo"}, `["/bin/sh","-c","echo"]`}, - } { - data, err := json.Marshal(testcase.input) - if err != nil { - t.Fatal(err) - } - if string(data) != testcase.expected { - t.Fatalf("%#v: expected %v, got %v", testcase.input, testcase.expected, string(data)) - } - } -} - -func TestStrSliceUnmarshalJSON(t *testing.T) { - parts := map[string][]string{ - "": {"default", "values"}, - "[]": {}, - `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"}, - } - for json, expectedParts := range parts { - strs := StrSlice{"default", "values"} - if err := strs.UnmarshalJSON([]byte(json)); err != nil { - t.Fatal(err) - } - - actualParts := []string(strs) - if !reflect.DeepEqual(actualParts, expectedParts) { - t.Fatalf("%#v: expected %v, got %v", json, expectedParts, actualParts) - } - - } -} - -func TestStrSliceUnmarshalString(t *testing.T) { - var e StrSlice - echo, err := json.Marshal("echo") - if err != nil { - t.Fatal(err) - } - if err := json.Unmarshal(echo, &e); err != nil { - t.Fatal(err) - } - - if len(e) != 1 { - t.Fatalf("expected 1 element after unmarshal: %q", e) - } - - if e[0] != "echo" { - t.Fatalf("expected `echo`, got: %q", e[0]) - } -} - -func TestStrSliceUnmarshalSlice(t *testing.T) { - var e StrSlice - echo, err := json.Marshal([]string{"echo"}) - if err != nil { - t.Fatal(err) - } - if err := json.Unmarshal(echo, &e); err != nil { - t.Fatal(err) - } - - if len(e) != 1 { - t.Fatalf("expected 1 element after unmarshal: %q", e) - } - - if e[0] != "echo" { - t.Fatalf("expected `echo`, got: %q", e[0]) - } -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go deleted file mode 100644 index 64a648bad15a..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/common.go +++ /dev/null @@ -1,27 +0,0 @@ -package swarm - -import "time" - -// Version represents the internal object version. -type Version struct { - Index uint64 `json:",omitempty"` -} - -// Meta is a base object inherited by most of the other once. -type Meta struct { - Version Version `json:",omitempty"` - CreatedAt time.Time `json:",omitempty"` - UpdatedAt time.Time `json:",omitempty"` -} - -// Annotations represents how to describe an object. -type Annotations struct { - Name string `json:",omitempty"` - Labels map[string]string `json:",omitempty"` -} - -// Driver represents a driver (network, logging). -type Driver struct { - Name string `json:",omitempty"` - Options map[string]string `json:",omitempty"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go deleted file mode 100644 index 0b823eb24772..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/container.go +++ /dev/null @@ -1,48 +0,0 @@ -package swarm - -import ( - "time" - - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/container" - "github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/mount" - //"github.com/docker/docker/api/types/container" - //"github.com/docker/docker/api/types/mount" -) - -// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) -// Detailed documentation is available in: -// http://man7.org/linux/man-pages/man5/resolv.conf.5.html -// `nameserver`, `search`, `options` have been supported. -// TODO: `domain` is not supported yet. -type DNSConfig struct { - // Nameservers specifies the IP addresses of the name servers - Nameservers []string `json:",omitempty"` - // Search specifies the search list for host-name lookup - Search []string `json:",omitempty"` - // Options allows certain internal resolver variables to be modified - Options []string `json:",omitempty"` -} - -// ContainerSpec represents the spec of a container. -type ContainerSpec struct { - Image string `json:",omitempty"` - Labels map[string]string `json:",omitempty"` - Command []string `json:",omitempty"` - Args []string `json:",omitempty"` - Hostname string `json:",omitempty"` - Env []string `json:",omitempty"` - Dir string `json:",omitempty"` - User string `json:",omitempty"` - Groups []string `json:",omitempty"` - TTY bool `json:",omitempty"` - OpenStdin bool `json:",omitempty"` - Mounts []mount.Mount `json:",omitempty"` - StopGracePeriod *time.Duration `json:",omitempty"` - Healthcheck *container.HealthConfig `json:",omitempty"` - // The format of extra hosts on swarmkit is specified in: - // http://man7.org/linux/man-pages/man5/hosts.5.html - // IP_address canonical_hostname [aliases...] - Hosts []string `json:",omitempty"` - DNSConfig *DNSConfig `json:",omitempty"` - Secrets []*SecretReference `json:",omitempty"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go deleted file mode 100644 index 5a5e11bdba59..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/network.go +++ /dev/null @@ -1,111 +0,0 @@ -package swarm - -// Endpoint represents an endpoint. -type Endpoint struct { - Spec EndpointSpec `json:",omitempty"` - Ports []PortConfig `json:",omitempty"` - VirtualIPs []EndpointVirtualIP `json:",omitempty"` -} - -// EndpointSpec represents the spec of an endpoint. -type EndpointSpec struct { - Mode ResolutionMode `json:",omitempty"` - Ports []PortConfig `json:",omitempty"` -} - -// ResolutionMode represents a resolution mode. -type ResolutionMode string - -const ( - // ResolutionModeVIP VIP - ResolutionModeVIP ResolutionMode = "vip" - // ResolutionModeDNSRR DNSRR - ResolutionModeDNSRR ResolutionMode = "dnsrr" -) - -// PortConfig represents the config of a port. -type PortConfig struct { - Name string `json:",omitempty"` - Protocol PortConfigProtocol `json:",omitempty"` - // TargetPort is the port inside the container - TargetPort uint32 `json:",omitempty"` - // PublishedPort is the port on the swarm hosts - PublishedPort uint32 `json:",omitempty"` - // PublishMode is the mode in which port is published - PublishMode PortConfigPublishMode `json:",omitempty"` -} - -// PortConfigPublishMode represents the mode in which the port is to -// be published. -type PortConfigPublishMode string - -const ( - // PortConfigPublishModeIngress is used for ports published - // for ingress load balancing using routing mesh. - PortConfigPublishModeIngress PortConfigPublishMode = "ingress" - // PortConfigPublishModeHost is used for ports published - // for direct host level access on the host where the task is running. - PortConfigPublishModeHost PortConfigPublishMode = "host" -) - -// PortConfigProtocol represents the protocol of a port. -type PortConfigProtocol string - -const ( - // TODO(stevvooe): These should be used generally, not just for PortConfig. - - // PortConfigProtocolTCP TCP - PortConfigProtocolTCP PortConfigProtocol = "tcp" - // PortConfigProtocolUDP UDP - PortConfigProtocolUDP PortConfigProtocol = "udp" -) - -// EndpointVirtualIP represents the virtual ip of a port. -type EndpointVirtualIP struct { - NetworkID string `json:",omitempty"` - Addr string `json:",omitempty"` -} - -// Network represents a network. -type Network struct { - ID string - Meta - Spec NetworkSpec `json:",omitempty"` - DriverState Driver `json:",omitempty"` - IPAMOptions *IPAMOptions `json:",omitempty"` -} - -// NetworkSpec represents the spec of a network. -type NetworkSpec struct { - Annotations - DriverConfiguration *Driver `json:",omitempty"` - IPv6Enabled bool `json:",omitempty"` - Internal bool `json:",omitempty"` - Attachable bool `json:",omitempty"` - IPAMOptions *IPAMOptions `json:",omitempty"` -} - -// NetworkAttachmentConfig represents the configuration of a network attachment. -type NetworkAttachmentConfig struct { - Target string `json:",omitempty"` - Aliases []string `json:",omitempty"` -} - -// NetworkAttachment represents a network attachment. -type NetworkAttachment struct { - Network Network `json:",omitempty"` - Addresses []string `json:",omitempty"` -} - -// IPAMOptions represents ipam options. -type IPAMOptions struct { - Driver Driver `json:",omitempty"` - Configs []IPAMConfig `json:",omitempty"` -} - -// IPAMConfig represents ipam configuration. -type IPAMConfig struct { - Subnet string `json:",omitempty"` - Range string `json:",omitempty"` - Gateway string `json:",omitempty"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go deleted file mode 100644 index 379e17a779ac..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/node.go +++ /dev/null @@ -1,114 +0,0 @@ -package swarm - -// Node represents a node. -type Node struct { - ID string - Meta - // Spec defines the desired state of the node as specified by the user. - // The system will honor this and will *never* modify it. - Spec NodeSpec `json:",omitempty"` - // Description encapsulates the properties of the Node as reported by the - // agent. - Description NodeDescription `json:",omitempty"` - // Status provides the current status of the node, as seen by the manager. - Status NodeStatus `json:",omitempty"` - // ManagerStatus provides the current status of the node's manager - // component, if the node is a manager. - ManagerStatus *ManagerStatus `json:",omitempty"` -} - -// NodeSpec represents the spec of a node. -type NodeSpec struct { - Annotations - Role NodeRole `json:",omitempty"` - Availability NodeAvailability `json:",omitempty"` -} - -// NodeRole represents the role of a node. -type NodeRole string - -const ( - // NodeRoleWorker WORKER - NodeRoleWorker NodeRole = "worker" - // NodeRoleManager MANAGER - NodeRoleManager NodeRole = "manager" -) - -// NodeAvailability represents the availability of a node. -type NodeAvailability string - -const ( - // NodeAvailabilityActive ACTIVE - NodeAvailabilityActive NodeAvailability = "active" - // NodeAvailabilityPause PAUSE - NodeAvailabilityPause NodeAvailability = "pause" - // NodeAvailabilityDrain DRAIN - NodeAvailabilityDrain NodeAvailability = "drain" -) - -// NodeDescription represents the description of a node. -type NodeDescription struct { - Hostname string `json:",omitempty"` - Platform Platform `json:",omitempty"` - Resources Resources `json:",omitempty"` - Engine EngineDescription `json:",omitempty"` -} - -// Platform represents the platform (Arch/OS). -type Platform struct { - Architecture string `json:",omitempty"` - OS string `json:",omitempty"` -} - -// EngineDescription represents the description of an engine. -type EngineDescription struct { - EngineVersion string `json:",omitempty"` - Labels map[string]string `json:",omitempty"` - Plugins []PluginDescription `json:",omitempty"` -} - -// PluginDescription represents the description of an engine plugin. -type PluginDescription struct { - Type string `json:",omitempty"` - Name string `json:",omitempty"` -} - -// NodeStatus represents the status of a node. -type NodeStatus struct { - State NodeState `json:",omitempty"` - Message string `json:",omitempty"` - Addr string `json:",omitempty"` -} - -// Reachability represents the reachability of a node. -type Reachability string - -const ( - // ReachabilityUnknown UNKNOWN - ReachabilityUnknown Reachability = "unknown" - // ReachabilityUnreachable UNREACHABLE - ReachabilityUnreachable Reachability = "unreachable" - // ReachabilityReachable REACHABLE - ReachabilityReachable Reachability = "reachable" -) - -// ManagerStatus represents the status of a manager. -type ManagerStatus struct { - Leader bool `json:",omitempty"` - Reachability Reachability `json:",omitempty"` - Addr string `json:",omitempty"` -} - -// NodeState represents the state of a node. -type NodeState string - -const ( - // NodeStateUnknown UNKNOWN - NodeStateUnknown NodeState = "unknown" - // NodeStateDown DOWN - NodeStateDown NodeState = "down" - // NodeStateReady READY - NodeStateReady NodeState = "ready" - // NodeStateDisconnected DISCONNECTED - NodeStateDisconnected NodeState = "disconnected" -) diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go deleted file mode 100644 index fdb2388888d9..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/secret.go +++ /dev/null @@ -1,31 +0,0 @@ -package swarm - -import "os" - -// Secret represents a secret. -type Secret struct { - ID string - Meta - Spec SecretSpec -} - -// SecretSpec represents a secret specification from a secret in swarm -type SecretSpec struct { - Annotations - Data []byte `json:",omitempty"` -} - -// SecretReferenceFileTarget is a file target in a secret reference -type SecretReferenceFileTarget struct { - Name string - UID string - GID string - Mode os.FileMode -} - -// SecretReference is a reference to a secret in swarm -type SecretReference struct { - File *SecretReferenceFileTarget - SecretID string - SecretName string -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go deleted file mode 100644 index 04f59de862e5..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/service.go +++ /dev/null @@ -1,105 +0,0 @@ -package swarm - -import "time" - -// Service represents a service. -type Service struct { - ID string - Meta - Spec ServiceSpec `json:",omitempty"` - PreviousSpec *ServiceSpec `json:",omitempty"` - Endpoint Endpoint `json:",omitempty"` - UpdateStatus *UpdateStatus `json:",omitempty"` -} - -// ServiceSpec represents the spec of a service. -type ServiceSpec struct { - Annotations - - // TaskTemplate defines how the service should construct new tasks when - // orchestrating this service. - TaskTemplate TaskSpec `json:",omitempty"` - Mode ServiceMode `json:",omitempty"` - UpdateConfig *UpdateConfig `json:",omitempty"` - - // Networks field in ServiceSpec is deprecated. The - // same field in TaskSpec should be used instead. - // This field will be removed in a future release. - Networks []NetworkAttachmentConfig `json:",omitempty"` - EndpointSpec *EndpointSpec `json:",omitempty"` -} - -// ServiceMode represents the mode of a service. -type ServiceMode struct { - Replicated *ReplicatedService `json:",omitempty"` - Global *GlobalService `json:",omitempty"` -} - -// UpdateState is the state of a service update. -type UpdateState string - -const ( - // UpdateStateUpdating is the updating state. - UpdateStateUpdating UpdateState = "updating" - // UpdateStatePaused is the paused state. - UpdateStatePaused UpdateState = "paused" - // UpdateStateCompleted is the completed state. - UpdateStateCompleted UpdateState = "completed" -) - -// UpdateStatus reports the status of a service update. -type UpdateStatus struct { - State UpdateState `json:",omitempty"` - StartedAt *time.Time `json:",omitempty"` - CompletedAt *time.Time `json:",omitempty"` - Message string `json:",omitempty"` -} - -// ReplicatedService is a kind of ServiceMode. -type ReplicatedService struct { - Replicas *uint64 `json:",omitempty"` -} - -// GlobalService is a kind of ServiceMode. -type GlobalService struct{} - -const ( - // UpdateFailureActionPause PAUSE - UpdateFailureActionPause = "pause" - // UpdateFailureActionContinue CONTINUE - UpdateFailureActionContinue = "continue" -) - -// UpdateConfig represents the update configuration. -type UpdateConfig struct { - // Maximum number of tasks to be updated in one iteration. - // 0 means unlimited parallelism. - Parallelism uint64 - - // Amount of time between updates. - Delay time.Duration `json:",omitempty"` - - // FailureAction is the action to take when an update failures. - FailureAction string `json:",omitempty"` - - // Monitor indicates how long to monitor a task for failure after it is - // created. If the task fails by ending up in one of the states - // REJECTED, COMPLETED, or FAILED, within Monitor from its creation, - // this counts as a failure. If it fails after Monitor, it does not - // count as a failure. If Monitor is unspecified, a default value will - // be used. - Monitor time.Duration `json:",omitempty"` - - // MaxFailureRatio is the fraction of tasks that may fail during - // an update before the failure action is invoked. Any task created by - // the current update which ends up in one of the states REJECTED, - // COMPLETED or FAILED within Monitor from its creation counts as a - // failure. The number of failures is divided by the number of tasks - // being updated, and if this fraction is greater than - // MaxFailureRatio, the failure action is invoked. - // - // If the failure action is CONTINUE, there is no effect. - // If the failure action is PAUSE, no more tasks will be updated until - // another update is started. - MaxFailureRatio float32 -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go deleted file mode 100644 index 0b4221969605..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/swarm.go +++ /dev/null @@ -1,197 +0,0 @@ -package swarm - -import "time" - -// ClusterInfo represents info about the cluster for outputing in "info" -// it contains the same information as "Swarm", but without the JoinTokens -type ClusterInfo struct { - ID string - Meta - Spec Spec -} - -// Swarm represents a swarm. -type Swarm struct { - ClusterInfo - JoinTokens JoinTokens -} - -// JoinTokens contains the tokens workers and managers need to join the swarm. -type JoinTokens struct { - // Worker is the join token workers may use to join the swarm. - Worker string - // Manager is the join token managers may use to join the swarm. - Manager string -} - -// Spec represents the spec of a swarm. -type Spec struct { - Annotations - - Orchestration OrchestrationConfig `json:",omitempty"` - Raft RaftConfig `json:",omitempty"` - Dispatcher DispatcherConfig `json:",omitempty"` - CAConfig CAConfig `json:",omitempty"` - TaskDefaults TaskDefaults `json:",omitempty"` - EncryptionConfig EncryptionConfig `json:",omitempty"` -} - -// OrchestrationConfig represents orchestration configuration. -type OrchestrationConfig struct { - // TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or - // node. If negative, never remove completed or failed tasks. - TaskHistoryRetentionLimit *int64 `json:",omitempty"` -} - -// TaskDefaults parameterizes cluster-level task creation with default values. -type TaskDefaults struct { - // LogDriver selects the log driver to use for tasks created in the - // orchestrator if unspecified by a service. - // - // Updating this value will only have an affect on new tasks. Old tasks - // will continue use their previously configured log driver until - // recreated. - LogDriver *Driver `json:",omitempty"` -} - -// EncryptionConfig controls at-rest encryption of data and keys. -type EncryptionConfig struct { - // AutoLockManagers specifies whether or not managers TLS keys and raft data - // should be encrypted at rest in such a way that they must be unlocked - // before the manager node starts up again. - AutoLockManagers bool -} - -// RaftConfig represents raft configuration. -type RaftConfig struct { - // SnapshotInterval is the number of log entries between snapshots. - SnapshotInterval uint64 `json:",omitempty"` - - // KeepOldSnapshots is the number of snapshots to keep beyond the - // current snapshot. - KeepOldSnapshots *uint64 `json:",omitempty"` - - // LogEntriesForSlowFollowers is the number of log entries to keep - // around to sync up slow followers after a snapshot is created. - LogEntriesForSlowFollowers uint64 `json:",omitempty"` - - // ElectionTick is the number of ticks that a follower will wait for a message - // from the leader before becoming a candidate and starting an election. - // ElectionTick must be greater than HeartbeatTick. - // - // A tick currently defaults to one second, so these translate directly to - // seconds currently, but this is NOT guaranteed. - ElectionTick int - - // HeartbeatTick is the number of ticks between heartbeats. Every - // HeartbeatTick ticks, the leader will send a heartbeat to the - // followers. - // - // A tick currently defaults to one second, so these translate directly to - // seconds currently, but this is NOT guaranteed. - HeartbeatTick int -} - -// DispatcherConfig represents dispatcher configuration. -type DispatcherConfig struct { - // HeartbeatPeriod defines how often agent should send heartbeats to - // dispatcher. - HeartbeatPeriod time.Duration `json:",omitempty"` -} - -// CAConfig represents CA configuration. -type CAConfig struct { - // NodeCertExpiry is the duration certificates should be issued for - NodeCertExpiry time.Duration `json:",omitempty"` - - // ExternalCAs is a list of CAs to which a manager node will make - // certificate signing requests for node certificates. - ExternalCAs []*ExternalCA `json:",omitempty"` -} - -// ExternalCAProtocol represents type of external CA. -type ExternalCAProtocol string - -// ExternalCAProtocolCFSSL CFSSL -const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" - -// ExternalCA defines external CA to be used by the cluster. -type ExternalCA struct { - // Protocol is the protocol used by this external CA. - Protocol ExternalCAProtocol - - // URL is the URL where the external CA can be reached. - URL string - - // Options is a set of additional key/value pairs whose interpretation - // depends on the specified CA type. - Options map[string]string `json:",omitempty"` -} - -// InitRequest is the request used to init a swarm. -type InitRequest struct { - ListenAddr string - AdvertiseAddr string - ForceNewCluster bool - Spec Spec - AutoLockManagers bool -} - -// JoinRequest is the request used to join a swarm. -type JoinRequest struct { - ListenAddr string - AdvertiseAddr string - RemoteAddrs []string - JoinToken string // accept by secret -} - -// UnlockRequest is the request used to unlock a swarm. -type UnlockRequest struct { - // UnlockKey is the unlock key in ASCII-armored format. - UnlockKey string -} - -// LocalNodeState represents the state of the local node. -type LocalNodeState string - -const ( - // LocalNodeStateInactive INACTIVE - LocalNodeStateInactive LocalNodeState = "inactive" - // LocalNodeStatePending PENDING - LocalNodeStatePending LocalNodeState = "pending" - // LocalNodeStateActive ACTIVE - LocalNodeStateActive LocalNodeState = "active" - // LocalNodeStateError ERROR - LocalNodeStateError LocalNodeState = "error" - // LocalNodeStateLocked LOCKED - LocalNodeStateLocked LocalNodeState = "locked" -) - -// Info represents generic information about swarm. -type Info struct { - NodeID string - NodeAddr string - - LocalNodeState LocalNodeState - ControlAvailable bool - Error string - - RemoteManagers []Peer - Nodes int - Managers int - - Cluster ClusterInfo -} - -// Peer represents a peer. -type Peer struct { - NodeID string - Addr string -} - -// UpdateFlags contains flags for SwarmUpdate. -type UpdateFlags struct { - RotateWorkerToken bool - RotateManagerToken bool - RotateManagerUnlockKey bool -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go deleted file mode 100644 index ace12cc89fa3..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/api/types/swarm/task.go +++ /dev/null @@ -1,128 +0,0 @@ -package swarm - -import "time" - -// TaskState represents the state of a task. -type TaskState string - -const ( - // TaskStateNew NEW - TaskStateNew TaskState = "new" - // TaskStateAllocated ALLOCATED - TaskStateAllocated TaskState = "allocated" - // TaskStatePending PENDING - TaskStatePending TaskState = "pending" - // TaskStateAssigned ASSIGNED - TaskStateAssigned TaskState = "assigned" - // TaskStateAccepted ACCEPTED - TaskStateAccepted TaskState = "accepted" - // TaskStatePreparing PREPARING - TaskStatePreparing TaskState = "preparing" - // TaskStateReady READY - TaskStateReady TaskState = "ready" - // TaskStateStarting STARTING - TaskStateStarting TaskState = "starting" - // TaskStateRunning RUNNING - TaskStateRunning TaskState = "running" - // TaskStateComplete COMPLETE - TaskStateComplete TaskState = "complete" - // TaskStateShutdown SHUTDOWN - TaskStateShutdown TaskState = "shutdown" - // TaskStateFailed FAILED - TaskStateFailed TaskState = "failed" - // TaskStateRejected REJECTED - TaskStateRejected TaskState = "rejected" -) - -// Task represents a task. -type Task struct { - ID string - Meta - Annotations - - Spec TaskSpec `json:",omitempty"` - ServiceID string `json:",omitempty"` - Slot int `json:",omitempty"` - NodeID string `json:",omitempty"` - Status TaskStatus `json:",omitempty"` - DesiredState TaskState `json:",omitempty"` - NetworksAttachments []NetworkAttachment `json:",omitempty"` -} - -// TaskSpec represents the spec of a task. -type TaskSpec struct { - ContainerSpec ContainerSpec `json:",omitempty"` - Resources *ResourceRequirements `json:",omitempty"` - RestartPolicy *RestartPolicy `json:",omitempty"` - Placement *Placement `json:",omitempty"` - Networks []NetworkAttachmentConfig `json:",omitempty"` - - // LogDriver specifies the LogDriver to use for tasks created from this - // spec. If not present, the one on cluster default on swarm.Spec will be - // used, finally falling back to the engine default if not specified. - LogDriver *Driver `json:",omitempty"` - - // ForceUpdate is a counter that triggers an update even if no relevant - // parameters have been changed. - ForceUpdate uint64 -} - -// Resources represents resources (CPU/Memory). -type Resources struct { - NanoCPUs int64 `json:",omitempty"` - MemoryBytes int64 `json:",omitempty"` -} - -// ResourceRequirements represents resources requirements. -type ResourceRequirements struct { - Limits *Resources `json:",omitempty"` - Reservations *Resources `json:",omitempty"` -} - -// Placement represents orchestration parameters. -type Placement struct { - Constraints []string `json:",omitempty"` -} - -// RestartPolicy represents the restart policy. -type RestartPolicy struct { - Condition RestartPolicyCondition `json:",omitempty"` - Delay *time.Duration `json:",omitempty"` - MaxAttempts *uint64 `json:",omitempty"` - Window *time.Duration `json:",omitempty"` -} - -// RestartPolicyCondition represents when to restart. -type RestartPolicyCondition string - -const ( - // RestartPolicyConditionNone NONE - RestartPolicyConditionNone RestartPolicyCondition = "none" - // RestartPolicyConditionOnFailure ON_FAILURE - RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure" - // RestartPolicyConditionAny ANY - RestartPolicyConditionAny RestartPolicyCondition = "any" -) - -// TaskStatus represents the status of a task. -type TaskStatus struct { - Timestamp time.Time `json:",omitempty"` - State TaskState `json:",omitempty"` - Message string `json:",omitempty"` - Err string `json:",omitempty"` - ContainerStatus ContainerStatus `json:",omitempty"` - PortStatus PortStatus `json:",omitempty"` -} - -// ContainerStatus represents the status of a container. -type ContainerStatus struct { - ContainerID string `json:",omitempty"` - PID int `json:",omitempty"` - ExitCode int `json:",omitempty"` -} - -// PortStatus represents the port status of a task's host ports whose -// service has published host ports -type PortStatus struct { - Ports []PortConfig `json:",omitempty"` -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go deleted file mode 100644 index 4d5f5ae63afd..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat.go +++ /dev/null @@ -1,242 +0,0 @@ -// Package nat is a convenience package for manipulation of strings describing network ports. -package nat - -import ( - "fmt" - "net" - "strconv" - "strings" -) - -const ( - // portSpecTemplate is the expected format for port specifications - portSpecTemplate = "ip:hostPort:containerPort" -) - -// PortBinding represents a binding between a Host IP address and a Host Port -type PortBinding struct { - // HostIP is the host IP Address - HostIP string `json:"HostIp"` - // HostPort is the host port number - HostPort string -} - -// PortMap is a collection of PortBinding indexed by Port -type PortMap map[Port][]PortBinding - -// PortSet is a collection of structs indexed by Port -type PortSet map[Port]struct{} - -// Port is a string containing port number and protocol in the format "80/tcp" -type Port string - -// NewPort creates a new instance of a Port given a protocol and port number or port range -func NewPort(proto, port string) (Port, error) { - // Check for parsing issues on "port" now so we can avoid having - // to check it later on. - - portStartInt, portEndInt, err := ParsePortRangeToInt(port) - if err != nil { - return "", err - } - - if portStartInt == portEndInt { - return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil - } - return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil -} - -// ParsePort parses the port number string and returns an int -func ParsePort(rawPort string) (int, error) { - if len(rawPort) == 0 { - return 0, nil - } - port, err := strconv.ParseUint(rawPort, 10, 16) - if err != nil { - return 0, err - } - return int(port), nil -} - -// ParsePortRangeToInt parses the port range string and returns start/end ints -func ParsePortRangeToInt(rawPort string) (int, int, error) { - if len(rawPort) == 0 { - return 0, 0, nil - } - start, end, err := ParsePortRange(rawPort) - if err != nil { - return 0, 0, err - } - return int(start), int(end), nil -} - -// Proto returns the protocol of a Port -func (p Port) Proto() string { - proto, _ := SplitProtoPort(string(p)) - return proto -} - -// Port returns the port number of a Port -func (p Port) Port() string { - _, port := SplitProtoPort(string(p)) - return port -} - -// Int returns the port number of a Port as an int -func (p Port) Int() int { - portStr := p.Port() - // We don't need to check for an error because we're going to - // assume that any error would have been found, and reported, in NewPort() - port, _ := ParsePort(portStr) - return port -} - -// Range returns the start/end port numbers of a Port range as ints -func (p Port) Range() (int, int, error) { - return ParsePortRangeToInt(p.Port()) -} - -// SplitProtoPort splits a port in the format of proto/port -func SplitProtoPort(rawPort string) (string, string) { - parts := strings.Split(rawPort, "/") - l := len(parts) - if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 { - return "", "" - } - if l == 1 { - return "tcp", rawPort - } - if len(parts[1]) == 0 { - return "tcp", parts[0] - } - return parts[1], parts[0] -} - -func validateProto(proto string) bool { - for _, availableProto := range []string{"tcp", "udp"} { - if availableProto == proto { - return true - } - } - return false -} - -// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses -// these in to the internal types -func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) { - var ( - exposedPorts = make(map[Port]struct{}, len(ports)) - bindings = make(map[Port][]PortBinding) - ) - for _, rawPort := range ports { - portMappings, err := ParsePortSpec(rawPort) - if err != nil { - return nil, nil, err - } - - for _, portMapping := range portMappings { - port := portMapping.Port - if _, exists := exposedPorts[port]; !exists { - exposedPorts[port] = struct{}{} - } - bslice, exists := bindings[port] - if !exists { - bslice = []PortBinding{} - } - bindings[port] = append(bslice, portMapping.Binding) - } - } - return exposedPorts, bindings, nil -} - -// PortMapping is a data object mapping a Port to a PortBinding -type PortMapping struct { - Port Port - Binding PortBinding -} - -func splitParts(rawport string) (string, string, string) { - parts := strings.Split(rawport, ":") - n := len(parts) - containerport := parts[n-1] - - switch n { - case 1: - return "", "", containerport - case 2: - return "", parts[0], containerport - case 3: - return parts[0], parts[1], containerport - default: - return strings.Join(parts[:n-2], ":"), parts[n-2], containerport - } -} - -// ParsePortSpec parses a port specification string into a slice of PortMappings -func ParsePortSpec(rawPort string) ([]PortMapping, error) { - var proto string - rawIP, hostPort, containerPort := splitParts(rawPort) - proto, containerPort = SplitProtoPort(containerPort) - - // Strip [] from IPV6 addresses - ip, _, err := net.SplitHostPort(rawIP + ":") - if err != nil { - return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err) - } - if ip != "" && net.ParseIP(ip) == nil { - return nil, fmt.Errorf("Invalid ip address: %s", ip) - } - if containerPort == "" { - return nil, fmt.Errorf("No port specified: %s", rawPort) - } - - startPort, endPort, err := ParsePortRange(containerPort) - if err != nil { - return nil, fmt.Errorf("Invalid containerPort: %s", containerPort) - } - - var startHostPort, endHostPort uint64 = 0, 0 - if len(hostPort) > 0 { - startHostPort, endHostPort, err = ParsePortRange(hostPort) - if err != nil { - return nil, fmt.Errorf("Invalid hostPort: %s", hostPort) - } - } - - if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) { - // Allow host port range iff containerPort is not a range. - // In this case, use the host port range as the dynamic - // host port range to allocate into. - if endPort != startPort { - return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort) - } - } - - if !validateProto(strings.ToLower(proto)) { - return nil, fmt.Errorf("Invalid proto: %s", proto) - } - - ports := []PortMapping{} - for i := uint64(0); i <= (endPort - startPort); i++ { - containerPort = strconv.FormatUint(startPort+i, 10) - if len(hostPort) > 0 { - hostPort = strconv.FormatUint(startHostPort+i, 10) - } - // Set hostPort to a range only if there is a single container port - // and a dynamic host port. - if startPort == endPort && startHostPort != endHostPort { - hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10)) - } - port, err := NewPort(strings.ToLower(proto), containerPort) - if err != nil { - return nil, err - } - - binding := PortBinding{ - HostIP: ip, - HostPort: hostPort, - } - ports = append(ports, PortMapping{Port: port, Binding: binding}) - } - return ports, nil -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go deleted file mode 100644 index 787d5ac2338e..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/nat_test.go +++ /dev/null @@ -1,583 +0,0 @@ -package nat - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParsePort(t *testing.T) { - var ( - p int - err error - ) - - p, err = ParsePort("1234") - - if err != nil || p != 1234 { - t.Fatal("Parsing '1234' did not succeed") - } - - // FIXME currently this is a valid port. I don't think it should be. - // I'm leaving this test commented out until we make a decision. - // - erikh - - /* - p, err = ParsePort("0123") - - if err != nil { - t.Fatal("Successfully parsed port '0123' to '123'") - } - */ - - p, err = ParsePort("asdf") - - if err == nil || p != 0 { - t.Fatal("Parsing port 'asdf' succeeded") - } - - p, err = ParsePort("1asdf") - - if err == nil || p != 0 { - t.Fatal("Parsing port '1asdf' succeeded") - } -} - -func TestParsePortRangeToInt(t *testing.T) { - var ( - begin int - end int - err error - ) - - type TestRange struct { - Range string - Begin int - End int - } - validRanges := []TestRange{ - {"1234", 1234, 1234}, - {"1234-1234", 1234, 1234}, - {"1234-1235", 1234, 1235}, - {"8000-9000", 8000, 9000}, - {"0", 0, 0}, - {"0-0", 0, 0}, - } - - for _, r := range validRanges { - begin, end, err = ParsePortRangeToInt(r.Range) - - if err != nil || begin != r.Begin { - t.Fatalf("Parsing port range '%s' did not succeed. Expected begin %d, got %d", r.Range, r.Begin, begin) - } - if err != nil || end != r.End { - t.Fatalf("Parsing port range '%s' did not succeed. Expected end %d, got %d", r.Range, r.End, end) - } - } - - invalidRanges := []string{ - "asdf", - "1asdf", - "9000-8000", - "9000-", - "-8000", - "-8000-", - } - - for _, r := range invalidRanges { - begin, end, err = ParsePortRangeToInt(r) - - if err == nil || begin != 0 || end != 0 { - t.Fatalf("Parsing port range '%s' succeeded", r) - } - } -} - -func TestPort(t *testing.T) { - p, err := NewPort("tcp", "1234") - - if err != nil { - t.Fatalf("tcp, 1234 had a parsing issue: %v", err) - } - - if string(p) != "1234/tcp" { - t.Fatal("tcp, 1234 did not result in the string 1234/tcp") - } - - if p.Proto() != "tcp" { - t.Fatal("protocol was not tcp") - } - - if p.Port() != "1234" { - t.Fatal("port string value was not 1234") - } - - if p.Int() != 1234 { - t.Fatal("port int value was not 1234") - } - - p, err = NewPort("tcp", "asd1234") - if err == nil { - t.Fatal("tcp, asd1234 was supposed to fail") - } - - p, err = NewPort("tcp", "1234-1230") - if err == nil { - t.Fatal("tcp, 1234-1230 was supposed to fail") - } - - p, err = NewPort("tcp", "1234-1242") - if err != nil { - t.Fatalf("tcp, 1234-1242 had a parsing issue: %v", err) - } - - if string(p) != "1234-1242/tcp" { - t.Fatal("tcp, 1234-1242 did not result in the string 1234-1242/tcp") - } -} - -func TestSplitProtoPort(t *testing.T) { - var ( - proto string - port string - ) - - proto, port = SplitProtoPort("1234/tcp") - - if proto != "tcp" || port != "1234" { - t.Fatal("Could not split 1234/tcp properly") - } - - proto, port = SplitProtoPort("") - - if proto != "" || port != "" { - t.Fatal("parsing an empty string yielded surprising results", proto, port) - } - - proto, port = SplitProtoPort("1234") - - if proto != "tcp" || port != "1234" { - t.Fatal("tcp is not the default protocol for portspec '1234'", proto, port) - } - - proto, port = SplitProtoPort("1234/") - - if proto != "tcp" || port != "1234" { - t.Fatal("parsing '1234/' yielded:" + port + "/" + proto) - } - - proto, port = SplitProtoPort("/tcp") - - if proto != "" || port != "" { - t.Fatal("parsing '/tcp' yielded:" + port + "/" + proto) - } -} - -func TestParsePortSpecFull(t *testing.T) { - portMappings, err := ParsePortSpec("0.0.0.0:1234-1235:3333-3334/tcp") - assert.Nil(t, err) - - expected := []PortMapping{ - { - Port: "3333/tcp", - Binding: PortBinding{ - HostIP: "0.0.0.0", - HostPort: "1234", - }, - }, - { - Port: "3334/tcp", - Binding: PortBinding{ - HostIP: "0.0.0.0", - HostPort: "1235", - }, - }, - } - - assert.Equal(t, expected, portMappings) -} - -func TestPartPortSpecIPV6(t *testing.T) { - portMappings, err := ParsePortSpec("[2001:4860:0:2001::68]::333") - assert.Nil(t, err) - - expected := []PortMapping{ - { - Port: "333/tcp", - Binding: PortBinding{ - HostIP: "2001:4860:0:2001::68", - HostPort: "", - }, - }, - } - assert.Equal(t, expected, portMappings) -} - -func TestPartPortSpecIPV6WithHostPort(t *testing.T) { - portMappings, err := ParsePortSpec("[::1]:80:80") - assert.Nil(t, err) - - expected := []PortMapping{ - { - Port: "80/tcp", - Binding: PortBinding{ - HostIP: "::1", - HostPort: "80", - }, - }, - } - assert.Equal(t, expected, portMappings) -} - -func TestParsePortSpecs(t *testing.T) { - var ( - portMap map[Port]struct{} - bindingMap map[Port][]PortBinding - err error - ) - - portMap, bindingMap, err = ParsePortSpecs([]string{"1234/tcp", "2345/udp"}) - - if err != nil { - t.Fatalf("Error while processing ParsePortSpecs: %s", err) - } - - if _, ok := portMap[Port("1234/tcp")]; !ok { - t.Fatal("1234/tcp was not parsed properly") - } - - if _, ok := portMap[Port("2345/udp")]; !ok { - t.Fatal("2345/udp was not parsed properly") - } - - for portspec, bindings := range bindingMap { - if len(bindings) != 1 { - t.Fatalf("%s should have exactly one binding", portspec) - } - - if bindings[0].HostIP != "" { - t.Fatalf("HostIP should not be set for %s", portspec) - } - - if bindings[0].HostPort != "" { - t.Fatalf("HostPort should not be set for %s", portspec) - } - } - - portMap, bindingMap, err = ParsePortSpecs([]string{"1234:1234/tcp", "2345:2345/udp"}) - - if err != nil { - t.Fatalf("Error while processing ParsePortSpecs: %s", err) - } - - if _, ok := portMap[Port("1234/tcp")]; !ok { - t.Fatal("1234/tcp was not parsed properly") - } - - if _, ok := portMap[Port("2345/udp")]; !ok { - t.Fatal("2345/udp was not parsed properly") - } - - for portspec, bindings := range bindingMap { - _, port := SplitProtoPort(string(portspec)) - - if len(bindings) != 1 { - t.Fatalf("%s should have exactly one binding", portspec) - } - - if bindings[0].HostIP != "" { - t.Fatalf("HostIP should not be set for %s", portspec) - } - - if bindings[0].HostPort != port { - t.Fatalf("HostPort should be %s for %s", port, portspec) - } - } - - portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234:1234/tcp", "0.0.0.0:2345:2345/udp"}) - - if err != nil { - t.Fatalf("Error while processing ParsePortSpecs: %s", err) - } - - if _, ok := portMap[Port("1234/tcp")]; !ok { - t.Fatal("1234/tcp was not parsed properly") - } - - if _, ok := portMap[Port("2345/udp")]; !ok { - t.Fatal("2345/udp was not parsed properly") - } - - for portspec, bindings := range bindingMap { - _, port := SplitProtoPort(string(portspec)) - - if len(bindings) != 1 { - t.Fatalf("%s should have exactly one binding", portspec) - } - - if bindings[0].HostIP != "0.0.0.0" { - t.Fatalf("HostIP is not 0.0.0.0 for %s", portspec) - } - - if bindings[0].HostPort != port { - t.Fatalf("HostPort should be %s for %s", port, portspec) - } - } - - _, _, err = ParsePortSpecs([]string{"localhost:1234:1234/tcp"}) - - if err == nil { - t.Fatal("Received no error while trying to parse a hostname instead of ip") - } -} - -func TestParsePortSpecsWithRange(t *testing.T) { - var ( - portMap map[Port]struct{} - bindingMap map[Port][]PortBinding - err error - ) - - portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236/tcp", "2345-2347/udp"}) - - if err != nil { - t.Fatalf("Error while processing ParsePortSpecs: %s", err) - } - - if _, ok := portMap[Port("1235/tcp")]; !ok { - t.Fatal("1234/tcp was not parsed properly") - } - - if _, ok := portMap[Port("2346/udp")]; !ok { - t.Fatal("2345/udp was not parsed properly") - } - - for portspec, bindings := range bindingMap { - if len(bindings) != 1 { - t.Fatalf("%s should have exactly one binding", portspec) - } - - if bindings[0].HostIP != "" { - t.Fatalf("HostIP should not be set for %s", portspec) - } - - if bindings[0].HostPort != "" { - t.Fatalf("HostPort should not be set for %s", portspec) - } - } - - portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236:1234-1236/tcp", "2345-2347:2345-2347/udp"}) - - if err != nil { - t.Fatalf("Error while processing ParsePortSpecs: %s", err) - } - - if _, ok := portMap[Port("1235/tcp")]; !ok { - t.Fatal("1234/tcp was not parsed properly") - } - - if _, ok := portMap[Port("2346/udp")]; !ok { - t.Fatal("2345/udp was not parsed properly") - } - - for portspec, bindings := range bindingMap { - _, port := SplitProtoPort(string(portspec)) - if len(bindings) != 1 { - t.Fatalf("%s should have exactly one binding", portspec) - } - - if bindings[0].HostIP != "" { - t.Fatalf("HostIP should not be set for %s", portspec) - } - - if bindings[0].HostPort != port { - t.Fatalf("HostPort should be %s for %s", port, portspec) - } - } - - portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234-1236:1234-1236/tcp", "0.0.0.0:2345-2347:2345-2347/udp"}) - - if err != nil { - t.Fatalf("Error while processing ParsePortSpecs: %s", err) - } - - if _, ok := portMap[Port("1235/tcp")]; !ok { - t.Fatal("1234/tcp was not parsed properly") - } - - if _, ok := portMap[Port("2346/udp")]; !ok { - t.Fatal("2345/udp was not parsed properly") - } - - for portspec, bindings := range bindingMap { - _, port := SplitProtoPort(string(portspec)) - if len(bindings) != 1 || bindings[0].HostIP != "0.0.0.0" || bindings[0].HostPort != port { - t.Fatalf("Expect single binding to port %s but found %s", port, bindings) - } - } - - _, _, err = ParsePortSpecs([]string{"localhost:1234-1236:1234-1236/tcp"}) - - if err == nil { - t.Fatal("Received no error while trying to parse a hostname instead of ip") - } -} - -func TestParseNetworkOptsPrivateOnly(t *testing.T) { - ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::80"}) - if err != nil { - t.Fatal(err) - } - if len(ports) != 1 { - t.Logf("Expected 1 got %d", len(ports)) - t.FailNow() - } - if len(bindings) != 1 { - t.Logf("Expected 1 got %d", len(bindings)) - t.FailNow() - } - for k := range ports { - if k.Proto() != "tcp" { - t.Logf("Expected tcp got %s", k.Proto()) - t.Fail() - } - if k.Port() != "80" { - t.Logf("Expected 80 got %s", k.Port()) - t.Fail() - } - b, exists := bindings[k] - if !exists { - t.Log("Binding does not exist") - t.FailNow() - } - if len(b) != 1 { - t.Logf("Expected 1 got %d", len(b)) - t.FailNow() - } - s := b[0] - if s.HostPort != "" { - t.Logf("Expected \"\" got %s", s.HostPort) - t.Fail() - } - if s.HostIP != "192.168.1.100" { - t.Fail() - } - } -} - -func TestParseNetworkOptsPublic(t *testing.T) { - ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:8080:80"}) - if err != nil { - t.Fatal(err) - } - if len(ports) != 1 { - t.Logf("Expected 1 got %d", len(ports)) - t.FailNow() - } - if len(bindings) != 1 { - t.Logf("Expected 1 got %d", len(bindings)) - t.FailNow() - } - for k := range ports { - if k.Proto() != "tcp" { - t.Logf("Expected tcp got %s", k.Proto()) - t.Fail() - } - if k.Port() != "80" { - t.Logf("Expected 80 got %s", k.Port()) - t.Fail() - } - b, exists := bindings[k] - if !exists { - t.Log("Binding does not exist") - t.FailNow() - } - if len(b) != 1 { - t.Logf("Expected 1 got %d", len(b)) - t.FailNow() - } - s := b[0] - if s.HostPort != "8080" { - t.Logf("Expected 8080 got %s", s.HostPort) - t.Fail() - } - if s.HostIP != "192.168.1.100" { - t.Fail() - } - } -} - -func TestParseNetworkOptsPublicNoPort(t *testing.T) { - ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100"}) - - if err == nil { - t.Logf("Expected error Invalid containerPort") - t.Fail() - } - if ports != nil { - t.Logf("Expected nil got %s", ports) - t.Fail() - } - if bindings != nil { - t.Logf("Expected nil got %s", bindings) - t.Fail() - } -} - -func TestParseNetworkOptsNegativePorts(t *testing.T) { - ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:-1:-1"}) - - if err == nil { - t.Fail() - } - if len(ports) != 0 { - t.Logf("Expected nil got %d", len(ports)) - t.Fail() - } - if len(bindings) != 0 { - t.Logf("Expected 0 got %d", len(bindings)) - t.Fail() - } -} - -func TestParseNetworkOptsUdp(t *testing.T) { - ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::6000/udp"}) - if err != nil { - t.Fatal(err) - } - if len(ports) != 1 { - t.Logf("Expected 1 got %d", len(ports)) - t.FailNow() - } - if len(bindings) != 1 { - t.Logf("Expected 1 got %d", len(bindings)) - t.FailNow() - } - for k := range ports { - if k.Proto() != "udp" { - t.Logf("Expected udp got %s", k.Proto()) - t.Fail() - } - if k.Port() != "6000" { - t.Logf("Expected 6000 got %s", k.Port()) - t.Fail() - } - b, exists := bindings[k] - if !exists { - t.Log("Binding does not exist") - t.FailNow() - } - if len(b) != 1 { - t.Logf("Expected 1 got %d", len(b)) - t.FailNow() - } - s := b[0] - if s.HostPort != "" { - t.Logf("Expected \"\" got %s", s.HostPort) - t.Fail() - } - if s.HostIP != "192.168.1.100" { - t.Fail() - } - } -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go deleted file mode 100644 index 892adf8c6673..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse.go +++ /dev/null @@ -1,57 +0,0 @@ -package nat - -import ( - "fmt" - "strconv" - "strings" -) - -// PartParser parses and validates the specified string (data) using the specified template -// e.g. ip:public:private -> 192.168.0.1:80:8000 -// DEPRECATED: do not use, this function may be removed in a future version -func PartParser(template, data string) (map[string]string, error) { - // ip:public:private - var ( - templateParts = strings.Split(template, ":") - parts = strings.Split(data, ":") - out = make(map[string]string, len(templateParts)) - ) - if len(parts) != len(templateParts) { - return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template) - } - - for i, t := range templateParts { - value := "" - if len(parts) > i { - value = parts[i] - } - out[t] = value - } - return out, nil -} - -// ParsePortRange parses and validates the specified string as a port-range (8000-9000) -func ParsePortRange(ports string) (uint64, uint64, error) { - if ports == "" { - return 0, 0, fmt.Errorf("Empty string specified for ports.") - } - if !strings.Contains(ports, "-") { - start, err := strconv.ParseUint(ports, 10, 16) - end := start - return start, end, err - } - - parts := strings.Split(ports, "-") - start, err := strconv.ParseUint(parts[0], 10, 16) - if err != nil { - return 0, 0, err - } - end, err := strconv.ParseUint(parts[1], 10, 16) - if err != nil { - return 0, 0, err - } - if end < start { - return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports) - } - return start, end, nil -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go deleted file mode 100644 index 2ac204a05bfd..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/parse_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package nat - -import ( - "strings" - "testing" -) - -func TestParsePortRange(t *testing.T) { - if start, end, err := ParsePortRange("8000-8080"); err != nil || start != 8000 || end != 8080 { - t.Fatalf("Error: %s or Expecting {start,end} values {8000,8080} but found {%d,%d}.", err, start, end) - } -} - -func TestParsePortRangeEmpty(t *testing.T) { - if _, _, err := ParsePortRange(""); err == nil || err.Error() != "Empty string specified for ports." { - t.Fatalf("Expected error 'Empty string specified for ports.', got %v", err) - } -} - -func TestParsePortRangeWithNoRange(t *testing.T) { - start, end, err := ParsePortRange("8080") - if err != nil { - t.Fatal(err) - } - if start != 8080 || end != 8080 { - t.Fatalf("Expected start and end to be the same and equal to 8080, but were %v and %v", start, end) - } -} - -func TestParsePortRangeIncorrectRange(t *testing.T) { - if _, _, err := ParsePortRange("9000-8080"); err == nil || !strings.Contains(err.Error(), "Invalid range specified for the Port") { - t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) - } -} - -func TestParsePortRangeIncorrectEndRange(t *testing.T) { - if _, _, err := ParsePortRange("8000-a"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { - t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) - } - - if _, _, err := ParsePortRange("8000-30a"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { - t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) - } -} - -func TestParsePortRangeIncorrectStartRange(t *testing.T) { - if _, _, err := ParsePortRange("a-8000"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { - t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) - } - - if _, _, err := ParsePortRange("30a-8000"); err == nil || !strings.Contains(err.Error(), "invalid syntax") { - t.Fatalf("Expecting error 'Invalid range specified for the Port' but received %s.", err) - } -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go deleted file mode 100644 index ce950171e315..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort.go +++ /dev/null @@ -1,96 +0,0 @@ -package nat - -import ( - "sort" - "strings" -) - -type portSorter struct { - ports []Port - by func(i, j Port) bool -} - -func (s *portSorter) Len() int { - return len(s.ports) -} - -func (s *portSorter) Swap(i, j int) { - s.ports[i], s.ports[j] = s.ports[j], s.ports[i] -} - -func (s *portSorter) Less(i, j int) bool { - ip := s.ports[i] - jp := s.ports[j] - - return s.by(ip, jp) -} - -// Sort sorts a list of ports using the provided predicate -// This function should compare `i` and `j`, returning true if `i` is -// considered to be less than `j` -func Sort(ports []Port, predicate func(i, j Port) bool) { - s := &portSorter{ports, predicate} - sort.Sort(s) -} - -type portMapEntry struct { - port Port - binding PortBinding -} - -type portMapSorter []portMapEntry - -func (s portMapSorter) Len() int { return len(s) } -func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -// sort the port so that the order is: -// 1. port with larger specified bindings -// 2. larger port -// 3. port with tcp protocol -func (s portMapSorter) Less(i, j int) bool { - pi, pj := s[i].port, s[j].port - hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort) - return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp") -} - -// SortPortMap sorts the list of ports and their respected mapping. The ports -// will explicit HostPort will be placed first. -func SortPortMap(ports []Port, bindings PortMap) { - s := portMapSorter{} - for _, p := range ports { - if binding, ok := bindings[p]; ok { - for _, b := range binding { - s = append(s, portMapEntry{port: p, binding: b}) - } - bindings[p] = []PortBinding{} - } else { - s = append(s, portMapEntry{port: p}) - } - } - - sort.Sort(s) - var ( - i int - pm = make(map[Port]struct{}) - ) - // reorder ports - for _, entry := range s { - if _, ok := pm[entry.port]; !ok { - ports[i] = entry.port - pm[entry.port] = struct{}{} - i++ - } - // reorder bindings for this port - if _, ok := bindings[entry.port]; ok { - bindings[entry.port] = append(bindings[entry.port], entry.binding) - } - } -} - -func toInt(s string) uint64 { - i, _, err := ParsePortRange(s) - if err != nil { - i = 0 - } - return i -} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go deleted file mode 100644 index 88ed911156a8..000000000000 --- a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/external/github.com/docker/go-connections/nat/sort_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package nat - -import ( - "fmt" - "reflect" - "testing" -) - -func TestSortUniquePorts(t *testing.T) { - ports := []Port{ - Port("6379/tcp"), - Port("22/tcp"), - } - - Sort(ports, func(ip, jp Port) bool { - return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp") - }) - - first := ports[0] - if fmt.Sprint(first) != "22/tcp" { - t.Log(fmt.Sprint(first)) - t.Fail() - } -} - -func TestSortSamePortWithDifferentProto(t *testing.T) { - ports := []Port{ - Port("8888/tcp"), - Port("8888/udp"), - Port("6379/tcp"), - Port("6379/udp"), - } - - Sort(ports, func(ip, jp Port) bool { - return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp") - }) - - first := ports[0] - if fmt.Sprint(first) != "6379/tcp" { - t.Fail() - } -} - -func TestSortPortMap(t *testing.T) { - ports := []Port{ - Port("22/tcp"), - Port("22/udp"), - Port("8000/tcp"), - Port("6379/tcp"), - Port("9999/tcp"), - } - - portMap := PortMap{ - Port("22/tcp"): []PortBinding{ - {}, - }, - Port("8000/tcp"): []PortBinding{ - {}, - }, - Port("6379/tcp"): []PortBinding{ - {}, - {HostIP: "0.0.0.0", HostPort: "32749"}, - }, - Port("9999/tcp"): []PortBinding{ - {HostIP: "0.0.0.0", HostPort: "40000"}, - }, - } - - SortPortMap(ports, portMap) - if !reflect.DeepEqual(ports, []Port{ - Port("9999/tcp"), - Port("6379/tcp"), - Port("8000/tcp"), - Port("22/tcp"), - Port("22/udp"), - }) { - t.Errorf("failed to prioritize port with explicit mappings, got %v", ports) - } - if pm := portMap[Port("6379/tcp")]; !reflect.DeepEqual(pm, []PortBinding{ - {HostIP: "0.0.0.0", HostPort: "32749"}, - {}, - }) { - t.Errorf("failed to prioritize bindings with explicit mappings, got %v", pm) - } -} From ffceff317edcdd8c7e8bd8fda2236fd327a27df1 Mon Sep 17 00:00:00 2001 From: sebastienmusso Date: Mon, 23 Jan 2017 19:09:56 +0100 Subject: [PATCH 27/27] fix healtheck layer, add node.go and service.go, compare event to nil --- .../module/docker/healthcheck/_meta/data.json | 12 +- metricbeat/module/docker/healthcheck/data.go | 4 +- .../github.com/fsouza/go-dockerclient/node.go | 128 ++++++++++++++ .../fsouza/go-dockerclient/service.go | 157 ++++++++++++++++++ 4 files changed, 292 insertions(+), 9 deletions(-) create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go create mode 100644 metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go diff --git a/metricbeat/module/docker/healthcheck/_meta/data.json b/metricbeat/module/docker/healthcheck/_meta/data.json index 73978d883839..2b33980faa22 100644 --- a/metricbeat/module/docker/healthcheck/_meta/data.json +++ b/metricbeat/module/docker/healthcheck/_meta/data.json @@ -8,13 +8,11 @@ "healthcheck": { "failingstreak": 0, "status": "healthy", - "healthcheck": { - "event": { - "end_date": "2017-01-09T20:38:13.080472813+01:00", - "exit_code": 0, - "output": "this is an event output", - "start_date": "2017-01-09T20:38:12.999970865+01:00", - } + "event": { + "end_date": "2017-01-09T20:38:13.080472813+01:00", + "exit_code": 0, + "output": "this is an event output", + "start_date": "2017-01-09T20:38:12.999970865+01:00", } } }, diff --git a/metricbeat/module/docker/healthcheck/data.go b/metricbeat/module/docker/healthcheck/data.go index 8fca6f4babe2..fedce1739c9d 100644 --- a/metricbeat/module/docker/healthcheck/data.go +++ b/metricbeat/module/docker/healthcheck/data.go @@ -6,7 +6,6 @@ import ( "github.com/elastic/beats/metricbeat/module/docker" dc "github.com/fsouza/go-dockerclient" - "reflect" "strings" ) @@ -15,7 +14,7 @@ func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.Map for _, container := range containersList { returnevent := eventMapping(&container, m) // Compare event to empty event - if !reflect.ValueOf(returnevent).IsNil() { + if returnevent != nil { myEvents = append(myEvents, returnevent) } } @@ -34,6 +33,7 @@ func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr { mb.ModuleData: common.MapStr{ "container": common.MapStr{ "name": docker.ExtractContainerName(cont.Names), + "id": cont.ID, }, }, "status": container.State.Health.Status, diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go new file mode 100644 index 000000000000..092fb6716a41 --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/node.go @@ -0,0 +1,128 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "encoding/json" + "net/http" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" + "golang.org/x/net/context" +) + +// NoSuchNode is the error returned when a given node does not exist. +type NoSuchNode struct { + ID string + Err error +} + +func (err *NoSuchNode) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such node: " + err.ID +} + +// ListNodesOptions specify parameters to the ListNodes function. +// +// See http://goo.gl/3K4GwU for more details. +type ListNodesOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListNodes returns a slice of nodes matching the given criteria. +// +// See http://goo.gl/3K4GwU for more details. +func (c *Client) ListNodes(opts ListNodesOptions) ([]swarm.Node, error) { + path := "/nodes?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var nodes []swarm.Node + if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil { + return nil, err + } + return nodes, nil +} + +// InspectNode returns information about a node by its ID. +// +// See http://goo.gl/WjkTOk for more details. +func (c *Client) InspectNode(id string) (*swarm.Node, error) { + resp, err := c.do("GET", "/nodes/"+id, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchNode{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var node swarm.Node + if err := json.NewDecoder(resp.Body).Decode(&node); err != nil { + return nil, err + } + return &node, nil +} + +// UpdateNodeOptions specify parameters to the NodeUpdate function. +// +// See http://goo.gl/VPBFgA for more details. +type UpdateNodeOptions struct { + swarm.NodeSpec + Version uint64 + Context context.Context +} + +// UpdateNode updates a node. +// +// See http://goo.gl/VPBFgA for more details. +func (c *Client) UpdateNode(id string, opts UpdateNodeOptions) error { + params := make(url.Values) + params.Set("version", strconv.FormatUint(opts.Version, 10)) + path := "/nodes/" + id + "/update?" + params.Encode() + _, err := c.do("POST", path, doOptions{ + context: opts.Context, + forceJSON: true, + data: opts.NodeSpec, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNode{ID: id} + } + return err + } + return nil +} + +// RemoveNodeOptions specify parameters to the RemoveNode function. +// +// See http://goo.gl/0SNvYg for more details. +type RemoveNodeOptions struct { + ID string + Force bool + Context context.Context +} + +// RemoveNode removes a node. +// +// See http://goo.gl/0SNvYg for more details. +func (c *Client) RemoveNode(opts RemoveNodeOptions) error { + params := make(url.Values) + params.Set("force", strconv.FormatBool(opts.Force)) + path := "/nodes/" + opts.ID + "?" + params.Encode() + _, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchNode{ID: opts.ID} + } + return err + } + return nil +} diff --git a/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go new file mode 100644 index 000000000000..3daf59c5d47b --- /dev/null +++ b/metricbeat/module/docker/vendor/github.com/fsouza/go-dockerclient/service.go @@ -0,0 +1,157 @@ +// Copyright 2016 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package docker + +import ( + "encoding/json" + "net/http" + "net/url" + "strconv" + + "github.com/docker/docker/api/types/swarm" + "golang.org/x/net/context" +) + +// NoSuchService is the error returned when a given service does not exist. +type NoSuchService struct { + ID string + Err error +} + +func (err *NoSuchService) Error() string { + if err.Err != nil { + return err.Err.Error() + } + return "No such service: " + err.ID +} + +// CreateServiceOptions specify parameters to the CreateService function. +// +// See https://goo.gl/KrVjHz for more details. +type CreateServiceOptions struct { + swarm.ServiceSpec + Context context.Context +} + +// CreateService creates a new service, returning the service instance +// or an error in case of failure. +// +// See https://goo.gl/KrVjHz for more details. +func (c *Client) CreateService(opts CreateServiceOptions) (*swarm.Service, error) { + path := "/services/create?" + queryString(opts) + resp, err := c.do("POST", path, doOptions{ + data: opts.ServiceSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var service swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { + return nil, err + } + return &service, nil +} + +// RemoveServiceOptions encapsulates options to remove a service. +// +// See https://goo.gl/Tqrtya for more details. +type RemoveServiceOptions struct { + ID string `qs:"-"` + Context context.Context +} + +// RemoveService removes a service, returning an error in case of failure. +// +// See https://goo.gl/Tqrtya for more details. +func (c *Client) RemoveService(opts RemoveServiceOptions) error { + path := "/services/" + opts.ID + resp, err := c.do("DELETE", path, doOptions{context: opts.Context}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchService{ID: opts.ID} + } + return err + } + resp.Body.Close() + return nil +} + +// UpdateServiceOptions specify parameters to the UpdateService function. +// +// See https://goo.gl/wu3MmS for more details. +type UpdateServiceOptions struct { + swarm.ServiceSpec + Context context.Context + Version uint64 +} + +// UpdateService updates the service at ID with the options +// +// See https://goo.gl/wu3MmS for more details. +func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { + params := make(url.Values) + params.Set("version", strconv.FormatUint(opts.Version, 10)) + resp, err := c.do("POST", "/services/"+id+"/update?"+params.Encode(), doOptions{ + data: opts.ServiceSpec, + forceJSON: true, + context: opts.Context, + }) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return &NoSuchService{ID: id} + } + return err + } + defer resp.Body.Close() + return nil +} + +// InspectService returns information about a service by its ID. +// +// See https://goo.gl/dHmr75 for more details. +func (c *Client) InspectService(id string) (*swarm.Service, error) { + path := "/services/" + id + resp, err := c.do("GET", path, doOptions{}) + if err != nil { + if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound { + return nil, &NoSuchService{ID: id} + } + return nil, err + } + defer resp.Body.Close() + var service swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { + return nil, err + } + return &service, nil +} + +// ListServicesOptions specify parameters to the ListServices function. +// +// See https://goo.gl/DwvNMd for more details. +type ListServicesOptions struct { + Filters map[string][]string + Context context.Context +} + +// ListServices returns a slice of services matching the given criteria. +// +// See https://goo.gl/DwvNMd for more details. +func (c *Client) ListServices(opts ListServicesOptions) ([]swarm.Service, error) { + path := "/services?" + queryString(opts) + resp, err := c.do("GET", path, doOptions{context: opts.Context}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var services []swarm.Service + if err := json.NewDecoder(resp.Body).Decode(&services); err != nil { + return nil, err + } + return services, nil +}