From 7dadfe73eb008c59462d17b306851582b791aca7 Mon Sep 17 00:00:00 2001 From: Vijay Samuel Date: Sun, 9 Apr 2017 23:26:08 -0700 Subject: [PATCH] Kubernetes module for metricbeat (#3916) * Kubernetes module for metricbeat * Changing nanoseconds in schema of kubelet module --- metricbeat/docs/fields.asciidoc | 90 +++++++++++++ metricbeat/docs/modules/kubelet.asciidoc | 53 ++++++++ .../docs/modules/kubelet/container.asciidoc | 19 +++ metricbeat/docs/modules/kubelet/node.asciidoc | 19 +++ metricbeat/docs/modules/kubelet/pod.asciidoc | 19 +++ .../docs/modules/kubelet/system.asciidoc | 19 +++ .../docs/modules/kubelet/volume.asciidoc | 19 +++ metricbeat/docs/modules_list.asciidoc | 2 + metricbeat/include/list.go | 6 + metricbeat/metricbeat.full.yml | 8 ++ metricbeat/module/kubelet/_meta/config.yml | 6 + metricbeat/module/kubelet/_meta/docs.asciidoc | 4 + metricbeat/module/kubelet/_meta/fields.yml | 12 ++ .../module/kubelet/container/_meta/data.json | 80 ++++++++++++ .../kubelet/container/_meta/docs.asciidoc | 3 + .../module/kubelet/container/_meta/fields.yml | 9 ++ .../module/kubelet/container/container.go | 67 ++++++++++ metricbeat/module/kubelet/container/data.go | 100 +++++++++++++++ metricbeat/module/kubelet/doc.go | 4 + .../module/kubelet/node/_meta/data.json | 84 +++++++++++++ .../module/kubelet/node/_meta/docs.asciidoc | 3 + .../module/kubelet/node/_meta/fields.yml | 9 ++ metricbeat/module/kubelet/node/data.go | 92 ++++++++++++++ metricbeat/module/kubelet/node/node.go | 67 ++++++++++ metricbeat/module/kubelet/pod/_meta/data.json | 33 +++++ .../module/kubelet/pod/_meta/docs.asciidoc | 3 + .../module/kubelet/pod/_meta/fields.yml | 9 ++ metricbeat/module/kubelet/pod/data.go | 44 +++++++ metricbeat/module/kubelet/pod/pod.go | 67 ++++++++++ .../module/kubelet/system/_meta/data.json | 45 +++++++ .../module/kubelet/system/_meta/docs.asciidoc | 3 + .../module/kubelet/system/_meta/fields.yml | 9 ++ metricbeat/module/kubelet/system/data.go | 58 +++++++++ metricbeat/module/kubelet/system/system.go | 67 ++++++++++ metricbeat/module/kubelet/types.go | 119 ++++++++++++++++++ .../module/kubelet/volume/_meta/data.json | 41 ++++++ .../module/kubelet/volume/_meta/docs.asciidoc | 3 + .../module/kubelet/volume/_meta/fields.yml | 9 ++ metricbeat/module/kubelet/volume/data.go | 56 +++++++++ metricbeat/module/kubelet/volume/volume.go | 67 ++++++++++ 40 files changed, 1427 insertions(+) create mode 100644 metricbeat/docs/modules/kubelet.asciidoc create mode 100644 metricbeat/docs/modules/kubelet/container.asciidoc create mode 100644 metricbeat/docs/modules/kubelet/node.asciidoc create mode 100644 metricbeat/docs/modules/kubelet/pod.asciidoc create mode 100644 metricbeat/docs/modules/kubelet/system.asciidoc create mode 100644 metricbeat/docs/modules/kubelet/volume.asciidoc create mode 100644 metricbeat/module/kubelet/_meta/config.yml create mode 100644 metricbeat/module/kubelet/_meta/docs.asciidoc create mode 100644 metricbeat/module/kubelet/_meta/fields.yml create mode 100644 metricbeat/module/kubelet/container/_meta/data.json create mode 100644 metricbeat/module/kubelet/container/_meta/docs.asciidoc create mode 100644 metricbeat/module/kubelet/container/_meta/fields.yml create mode 100644 metricbeat/module/kubelet/container/container.go create mode 100644 metricbeat/module/kubelet/container/data.go create mode 100644 metricbeat/module/kubelet/doc.go create mode 100644 metricbeat/module/kubelet/node/_meta/data.json create mode 100644 metricbeat/module/kubelet/node/_meta/docs.asciidoc create mode 100644 metricbeat/module/kubelet/node/_meta/fields.yml create mode 100644 metricbeat/module/kubelet/node/data.go create mode 100644 metricbeat/module/kubelet/node/node.go create mode 100644 metricbeat/module/kubelet/pod/_meta/data.json create mode 100644 metricbeat/module/kubelet/pod/_meta/docs.asciidoc create mode 100644 metricbeat/module/kubelet/pod/_meta/fields.yml create mode 100644 metricbeat/module/kubelet/pod/data.go create mode 100644 metricbeat/module/kubelet/pod/pod.go create mode 100644 metricbeat/module/kubelet/system/_meta/data.json create mode 100644 metricbeat/module/kubelet/system/_meta/docs.asciidoc create mode 100644 metricbeat/module/kubelet/system/_meta/fields.yml create mode 100644 metricbeat/module/kubelet/system/data.go create mode 100644 metricbeat/module/kubelet/system/system.go create mode 100644 metricbeat/module/kubelet/types.go create mode 100644 metricbeat/module/kubelet/volume/_meta/data.json create mode 100644 metricbeat/module/kubelet/volume/_meta/docs.asciidoc create mode 100644 metricbeat/module/kubelet/volume/_meta/fields.yml create mode 100644 metricbeat/module/kubelet/volume/data.go create mode 100644 metricbeat/module/kubelet/volume/volume.go diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index ab9856f8c72..2f8e117112f 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -23,6 +23,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> * <> * <> @@ -3329,6 +3330,95 @@ type: keyword Broker address +[[exported-fields-kubelet]] +== kubelet Fields + +beta[] +kubelet Module + + + +[float] +== kubelet Fields + + + + +[float] +== container Fields + +node + + + +[float] +=== kubelet.container.example + +type: keyword + +Example field + + +[float] +== node Fields + +node + + + +[float] +=== kubelet.node.example + +type: keyword + +Example field + + +[float] +== pod Fields + +node + + + +[float] +=== kubelet.pod.example + +type: keyword + +Example field + + +[float] +== system Fields + +node + + + +[float] +=== kubelet.system.example + +type: keyword + +Example field + + +[float] +== volume Fields + +node + + + +[float] +=== kubelet.volume.example + +type: keyword + +Example field + + [[exported-fields-memcached]] == memcached Fields diff --git a/metricbeat/docs/modules/kubelet.asciidoc b/metricbeat/docs/modules/kubelet.asciidoc new file mode 100644 index 00000000000..b2ca1a5699c --- /dev/null +++ b/metricbeat/docs/modules/kubelet.asciidoc @@ -0,0 +1,53 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-module-kubelet]] +== kubelet Module + +This is the kubelet Module. + + + +[float] +=== Example Configuration + +The kubelet module supports the standard configuration options that are described +in <>. Here is an example configuration: + +[source,yaml] +---- +metricbeat.modules: +#- module: kubelet +# metricsets: ["node","container","volume","pod","system"] +# enabled: true +# period: 10s +# hosts: ["localhost:10255"] + +---- + +[float] +=== Metricsets + +The following metricsets are available: + +* <> + +* <> + +* <> + +* <> + +* <> + +include::kubelet/container.asciidoc[] + +include::kubelet/node.asciidoc[] + +include::kubelet/pod.asciidoc[] + +include::kubelet/system.asciidoc[] + +include::kubelet/volume.asciidoc[] + diff --git a/metricbeat/docs/modules/kubelet/container.asciidoc b/metricbeat/docs/modules/kubelet/container.asciidoc new file mode 100644 index 00000000000..1b07114e155 --- /dev/null +++ b/metricbeat/docs/modules/kubelet/container.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-kubelet-container]] +include::../../../module/kubelet/container/_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/kubelet/container/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules/kubelet/node.asciidoc b/metricbeat/docs/modules/kubelet/node.asciidoc new file mode 100644 index 00000000000..0c263b376b6 --- /dev/null +++ b/metricbeat/docs/modules/kubelet/node.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-kubelet-node]] +include::../../../module/kubelet/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/kubelet/node/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules/kubelet/pod.asciidoc b/metricbeat/docs/modules/kubelet/pod.asciidoc new file mode 100644 index 00000000000..4de69b7b98b --- /dev/null +++ b/metricbeat/docs/modules/kubelet/pod.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-kubelet-pod]] +include::../../../module/kubelet/pod/_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/kubelet/pod/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules/kubelet/system.asciidoc b/metricbeat/docs/modules/kubelet/system.asciidoc new file mode 100644 index 00000000000..bc89fdaef2f --- /dev/null +++ b/metricbeat/docs/modules/kubelet/system.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-kubelet-system]] +include::../../../module/kubelet/system/_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/kubelet/system/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules/kubelet/volume.asciidoc b/metricbeat/docs/modules/kubelet/volume.asciidoc new file mode 100644 index 00000000000..59cc6cca253 --- /dev/null +++ b/metricbeat/docs/modules/kubelet/volume.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-kubelet-volume]] +include::../../../module/kubelet/volume/_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/kubelet/volume/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index fa3cc0b0186..505dd3e6341 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -10,6 +10,7 @@ This file is generated! See scripts/docs_collector.py * <> * <> * <> + * <> * <> * <> * <> @@ -33,6 +34,7 @@ include::modules/golang.asciidoc[] include::modules/haproxy.asciidoc[] include::modules/jolokia.asciidoc[] include::modules/kafka.asciidoc[] +include::modules/kubelet.asciidoc[] include::modules/memcached.asciidoc[] include::modules/mongodb.asciidoc[] include::modules/mysql.asciidoc[] diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 38558e0337c..93dd66bf6e7 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -39,6 +39,12 @@ import ( _ "github.com/elastic/beats/metricbeat/module/kafka" _ "github.com/elastic/beats/metricbeat/module/kafka/consumergroup" _ "github.com/elastic/beats/metricbeat/module/kafka/partition" + _ "github.com/elastic/beats/metricbeat/module/kubelet" + _ "github.com/elastic/beats/metricbeat/module/kubelet/container" + _ "github.com/elastic/beats/metricbeat/module/kubelet/node" + _ "github.com/elastic/beats/metricbeat/module/kubelet/pod" + _ "github.com/elastic/beats/metricbeat/module/kubelet/system" + _ "github.com/elastic/beats/metricbeat/module/kubelet/volume" _ "github.com/elastic/beats/metricbeat/module/memcached" _ "github.com/elastic/beats/metricbeat/module/memcached/stats" _ "github.com/elastic/beats/metricbeat/module/mongodb" diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 09ea01c96d3..8dac5646c54 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -182,6 +182,14 @@ metricbeat.modules: #username: "" #password: "" +#------------------------------- kubelet Module ------------------------------ +#- module: kubelet +# metricsets: ["node","container","volume","pod","system"] +# enabled: true +# period: 10s +# hosts: ["localhost:10255"] + + #------------------------------ memcached Module ----------------------------- - module: memcached metricsets: ["stats"] diff --git a/metricbeat/module/kubelet/_meta/config.yml b/metricbeat/module/kubelet/_meta/config.yml new file mode 100644 index 00000000000..17d7fb3c86d --- /dev/null +++ b/metricbeat/module/kubelet/_meta/config.yml @@ -0,0 +1,6 @@ +#- module: kubelet +# metricsets: ["node","container","volume","pod","system"] +# enabled: true +# period: 10s +# hosts: ["localhost:10255"] + diff --git a/metricbeat/module/kubelet/_meta/docs.asciidoc b/metricbeat/module/kubelet/_meta/docs.asciidoc new file mode 100644 index 00000000000..fb32f848f8b --- /dev/null +++ b/metricbeat/module/kubelet/_meta/docs.asciidoc @@ -0,0 +1,4 @@ +== kubelet Module + +This is the kubelet Module. + diff --git a/metricbeat/module/kubelet/_meta/fields.yml b/metricbeat/module/kubelet/_meta/fields.yml new file mode 100644 index 00000000000..d3b52350455 --- /dev/null +++ b/metricbeat/module/kubelet/_meta/fields.yml @@ -0,0 +1,12 @@ +- key: kubelet + title: "kubelet" + description: > + beta[] + + kubelet Module + short_config: false + fields: + - name: kubelet + type: group + description: > + fields: diff --git a/metricbeat/module/kubelet/container/_meta/data.json b/metricbeat/module/kubelet/container/_meta/data.json new file mode 100644 index 00000000000..d9e46b0f660 --- /dev/null +++ b/metricbeat/module/kubelet/container/_meta/data.json @@ -0,0 +1,80 @@ +{ + "@timestamp": "2017-04-06T15:29:27.150Z", + "beat": { + "hostname": "beathost", + "name": "beathost", + "version": "6.0.0-alpha1" + }, + "kubelet": { + "container": { + "cpu": { + "usage": { + "core": { + "ns": 3305756719 + }, + "nanocores": 5992 + } + }, + "logs": { + "available": { + "bytes": 1188063105024 + }, + "capacity": { + "bytes": 1197211648000 + }, + "inodes": { + "count": 584581120, + "free": 584447029, + "used": 134091 + }, + "used": { + "bytes": 0 + } + }, + "memory": { + "available": { + "bytes": 0 + }, + "majorpagefaults": 47, + "pagefaults": 2298, + "rss": { + "bytes": 1441792 + }, + "usage": { + "bytes": 7643136 + }, + "workingset": { + "bytes": 1466368 + } + }, + "name": "nginx", + "rootfs": { + "available": { + "bytes": 64694517760 + }, + "capacity": { + "bytes": 142782496768 + }, + "inodes": { + "used": 0 + }, + "used": { + "bytes": 16777216 + } + }, + "start_time": "2017-04-03T10:01:56Z" + }, + "pod": { + "name": "nginx-3137573019-pcfzh", + "namespace": "ns", + "node": "localhost" + } + }, + "metricset": { + "host": "localhost:10255", + "module": "kubelet", + "name": "container", + "rtt": 650739 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/kubelet/container/_meta/docs.asciidoc b/metricbeat/module/kubelet/container/_meta/docs.asciidoc new file mode 100644 index 00000000000..880c8fab2a3 --- /dev/null +++ b/metricbeat/module/kubelet/container/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +=== kubelet container MetricSet + +This is the container metricset of the module kubelet. diff --git a/metricbeat/module/kubelet/container/_meta/fields.yml b/metricbeat/module/kubelet/container/_meta/fields.yml new file mode 100644 index 00000000000..0a3cd7d8480 --- /dev/null +++ b/metricbeat/module/kubelet/container/_meta/fields.yml @@ -0,0 +1,9 @@ +- name: container + type: group + description: > + node + fields: + - name: example + type: keyword + description: > + Example field diff --git a/metricbeat/module/kubelet/container/container.go b/metricbeat/module/kubelet/container/container.go new file mode 100644 index 00000000000..2e360eb26cd --- /dev/null +++ b/metricbeat/module/kubelet/container/container.go @@ -0,0 +1,67 @@ +package container + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/helper" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" +) + +const ( + defaultScheme = "http" + defaultPath = "/stats/summary" +) + +var ( + hostParser = parse.URLHostParserBuilder{ + DefaultScheme: defaultScheme, + DefaultPath: defaultPath, + }.Build() +) + +// init registers the MetricSet with the central registry. +// The New method will be called after the setup of the module and before starting to fetch data +func init() { + if err := mb.Registry.AddMetricSet("kubelet", "container", New, hostParser); err != nil { + panic(err) + } +} + +// MetricSet type defines all fields of the MetricSet +// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with +// additional entries. These variables can be used to persist data or configuration between +// multiple fetch calls. +type MetricSet struct { + mb.BaseMetricSet + http *helper.HTTP +} + +// New create a new instance of the MetricSet +// Part of new is also setting up the configuration by processing additional +// configuration entries if needed. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("BETA: The kubelet container metricset is alpha") + return &MetricSet{ + BaseMetricSet: base, + http: helper.NewHTTP(base), + }, nil +} + +// Fetch methods implements the data gathering and data conversion to the right format +// It returns the event which is then forward to the output. In case of an error, a +// descriptive error must be returned. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + + body, err := m.http.FetchContent() + if err != nil { + return nil, err + } + + events, err := eventMapping(body) + if err != nil { + return nil, err + } + + return events, nil +} diff --git a/metricbeat/module/kubelet/container/data.go b/metricbeat/module/kubelet/container/data.go new file mode 100644 index 00000000000..9894ded37d3 --- /dev/null +++ b/metricbeat/module/kubelet/container/data.go @@ -0,0 +1,100 @@ +package container + +import ( + "encoding/json" + "fmt" + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/kubelet" +) + +func eventMapping(content []byte) ([]common.MapStr, error) { + events := []common.MapStr{} + var summary kubelet.Summary + + err := json.Unmarshal(content, &summary) + if err != nil { + return nil, fmt.Errorf("Cannot unmarshal json response: %s", err) + } + + node := summary.Node + for _, pod := range summary.Pods { + for _, container := range pod.Containers { + containerEvent := common.MapStr{ + mb.ModuleData: common.MapStr{ + "pod": common.MapStr{ + "name": pod.PodRef.Name, + "namespace": pod.PodRef.Namespace, + "node": node.NodeName, + }, + }, + + "name": container.Name, + "start_time": container.StartTime, + + "cpu": common.MapStr{ + "usage": common.MapStr{ + "nanocores": container.CPU.UsageNanoCores, + "core": common.MapStr{ + "ns": container.CPU.UsageCoreNanoSeconds, + }, + }, + }, + + "memory": common.MapStr{ + "available": common.MapStr{ + "bytes": container.Memory.AvailableBytes, + }, + "usage": common.MapStr{ + "bytes": container.Memory.UsageBytes, + }, + "workingset": common.MapStr{ + "bytes": container.Memory.WorkingSetBytes, + }, + "rss": common.MapStr{ + "bytes": container.Memory.RssBytes, + }, + "pagefaults": container.Memory.PageFaults, + "majorpagefaults": container.Memory.MajorPageFaults, + }, + + "rootfs": common.MapStr{ + "available": common.MapStr{ + "bytes": container.Rootfs.AvailableBytes, + }, + "capacity": common.MapStr{ + "bytes": container.Rootfs.CapacityBytes, + }, + "used": common.MapStr{ + "bytes": container.Rootfs.UsedBytes, + }, + "inodes": common.MapStr{ + "used": container.Rootfs.InodesUsed, + }, + }, + + "logs": common.MapStr{ + "available": common.MapStr{ + "bytes": container.Logs.AvailableBytes, + }, + "capacity": common.MapStr{ + "bytes": container.Logs.CapacityBytes, + }, + "used": common.MapStr{ + "bytes": container.Logs.UsedBytes, + }, + "inodes": common.MapStr{ + "used": container.Logs.InodesUsed, + "free": container.Logs.InodesFree, + "count": container.Logs.Inodes, + }, + }, + } + events = append(events, containerEvent) + } + + } + + return events, nil + +} diff --git a/metricbeat/module/kubelet/doc.go b/metricbeat/module/kubelet/doc.go new file mode 100644 index 00000000000..6925498b6ef --- /dev/null +++ b/metricbeat/module/kubelet/doc.go @@ -0,0 +1,4 @@ +/* +Package kubernetes is a Metricbeat module that contains MetricSets. +*/ +package kubelet diff --git a/metricbeat/module/kubelet/node/_meta/data.json b/metricbeat/module/kubelet/node/_meta/data.json new file mode 100644 index 00000000000..7b5469c2cbd --- /dev/null +++ b/metricbeat/module/kubelet/node/_meta/data.json @@ -0,0 +1,84 @@ +{ + "@timestamp": "2017-04-06T15:29:27.150Z", + "beat": { + "hostname": "beathost", + "name": "beathost", + "version": "6.0.0-alpha1" + }, + "kubelet": { + "node": { + "cpu": { + "usage": { + "core" : { + "ns": 7247863769557035 + }, + "nanocores": 1662117892 + } + }, + "fs": { + "available": { + "bytes": 1188063105024 + }, + "capacity": { + "bytes": 1197211648000 + }, + "inodes": { + "count": 584581120, + "free": 584447029, + "used": 134091 + }, + "used": { + "bytes": 9148542976 + } + }, + "memory": { + "available": { + "bytes": 134202847232 + }, + "majorpagefaults": 1044, + "pagefaults": 83482928, + "rss": { + "bytes": 178053120 + }, + "usage": { + "bytes": 67062091776 + }, + "workingset": { + "bytes": 51496206336 + } + }, + "name": "localhost", + "network": { + "rx": { + "bytes": 957942806894, + "errors": 0 + }, + "tx": { + "bytes": 461158498276, + "errors": 0 + } + }, + "runtime": { + "imagefs": { + "available": { + "bytes": 64694517760 + }, + "capacity": { + "bytes": 142782496768 + }, + "used": { + "bytes": 29570629855 + } + } + }, + "start_time": "2017-02-08T10:33:38Z" + } + }, + "metricset": { + "host": "localhost:10255", + "module": "kubelet", + "name": "node", + "rtt": 650741 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/kubelet/node/_meta/docs.asciidoc b/metricbeat/module/kubelet/node/_meta/docs.asciidoc new file mode 100644 index 00000000000..0b7b520120d --- /dev/null +++ b/metricbeat/module/kubelet/node/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +=== kubelet node MetricSet + +This is the node metricset of the module kubelet. diff --git a/metricbeat/module/kubelet/node/_meta/fields.yml b/metricbeat/module/kubelet/node/_meta/fields.yml new file mode 100644 index 00000000000..0afe51c83ca --- /dev/null +++ b/metricbeat/module/kubelet/node/_meta/fields.yml @@ -0,0 +1,9 @@ +- name: node + type: group + description: > + node + fields: + - name: example + type: keyword + description: > + Example field diff --git a/metricbeat/module/kubelet/node/data.go b/metricbeat/module/kubelet/node/data.go new file mode 100644 index 00000000000..1a5a28b63c3 --- /dev/null +++ b/metricbeat/module/kubelet/node/data.go @@ -0,0 +1,92 @@ +package node + +import ( + "encoding/json" + "fmt" + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/module/kubelet" +) + +func eventMapping(content []byte) (common.MapStr, error) { + var summary kubelet.Summary + err := json.Unmarshal(content, &summary) + if err != nil { + return nil, fmt.Errorf("Cannot unmarshal json response: %s", err) + } + + node := summary.Node + nodeEvent := common.MapStr{ + "name": node.NodeName, + "start_time": node.StartTime, + + "cpu": common.MapStr{ + "usage": common.MapStr{ + "nanocores": node.CPU.UsageNanoCores, + "core": common.MapStr{ + "ns": node.CPU.UsageCoreNanoSeconds, + }, + }, + }, + + "memory": common.MapStr{ + "available": common.MapStr{ + "bytes": node.Memory.AvailableBytes, + }, + "usage": common.MapStr{ + "bytes": node.Memory.UsageBytes, + }, + "workingset": common.MapStr{ + "bytes": node.Memory.WorkingSetBytes, + }, + "rss": common.MapStr{ + "bytes": node.Memory.RssBytes, + }, + "pagefaults": node.Memory.PageFaults, + "majorpagefaults": node.Memory.MajorPageFaults, + }, + + "network": common.MapStr{ + "rx": common.MapStr{ + "bytes": node.Network.RxBytes, + "errors": node.Network.RxErrors, + }, + "tx": common.MapStr{ + "bytes": node.Network.TxBytes, + "errors": node.Network.TxErrors, + }, + }, + + "fs": common.MapStr{ + "available": common.MapStr{ + "bytes": node.Fs.AvailableBytes, + }, + "capacity": common.MapStr{ + "bytes": node.Fs.CapacityBytes, + }, + "used": common.MapStr{ + "bytes": node.Fs.UsedBytes, + }, + "inodes": common.MapStr{ + "used": node.Fs.InodesUsed, + "free": node.Fs.InodesFree, + "count": node.Fs.Inodes, + }, + }, + + "runtime": common.MapStr{ + "imagefs": common.MapStr{ + "available": common.MapStr{ + "bytes": node.Runtime.ImageFs.AvailableBytes, + }, + "capacity": common.MapStr{ + "bytes": node.Runtime.ImageFs.CapacityBytes, + }, + "used": common.MapStr{ + "bytes": node.Runtime.ImageFs.UsedBytes, + }, + }, + }, + } + return nodeEvent, nil + +} diff --git a/metricbeat/module/kubelet/node/node.go b/metricbeat/module/kubelet/node/node.go new file mode 100644 index 00000000000..f74ee2af52d --- /dev/null +++ b/metricbeat/module/kubelet/node/node.go @@ -0,0 +1,67 @@ +package node + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/helper" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" +) + +const ( + defaultScheme = "http" + defaultPath = "/stats/summary" +) + +var ( + hostParser = parse.URLHostParserBuilder{ + DefaultScheme: defaultScheme, + DefaultPath: defaultPath, + }.Build() +) + +// init registers the MetricSet with the central registry. +// The New method will be called after the setup of the module and before starting to fetch data +func init() { + if err := mb.Registry.AddMetricSet("kubelet", "node", New, hostParser); err != nil { + panic(err) + } +} + +// MetricSet type defines all fields of the MetricSet +// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with +// additional entries. These variables can be used to persist data or configuration between +// multiple fetch calls. +type MetricSet struct { + mb.BaseMetricSet + http *helper.HTTP +} + +// New create a new instance of the MetricSet +// Part of new is also setting up the configuration by processing additional +// configuration entries if needed. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("BETA: The kubelet node metricset is alpha") + return &MetricSet{ + BaseMetricSet: base, + http: helper.NewHTTP(base), + }, nil +} + +// Fetch methods implements the data gathering and data conversion to the right format +// It returns the event which is then forward to the output. In case of an error, a +// descriptive error must be returned. +func (m *MetricSet) Fetch() (common.MapStr, error) { + + body, err := m.http.FetchContent() + if err != nil { + return nil, err + } + + event, err := eventMapping(body) + if err != nil { + return nil, err + } + + return event, nil +} diff --git a/metricbeat/module/kubelet/pod/_meta/data.json b/metricbeat/module/kubelet/pod/_meta/data.json new file mode 100644 index 00000000000..d822eaebb2f --- /dev/null +++ b/metricbeat/module/kubelet/pod/_meta/data.json @@ -0,0 +1,33 @@ +{ + "@timestamp": "2017-04-06T15:29:27.150Z", + "beat": { + "hostname": "beathost", + "name": "beathost", + "version": "6.0.0-alpha1" + }, + "kubelet": { + "pod": { + "name": "nginx-3137573019-pcfzh", + "namespace": "ns", + "network": { + "rx": { + "bytes": 18999261, + "errors": 0 + }, + "tx": { + "bytes": 28580621, + "errors": 0 + } + }, + "node": "localhost", + "start_time": "2017-04-06T12:09:05Z" + } + }, + "metricset": { + "host": "localhost:10255", + "module": "kubelet", + "name": "pod", + "rtt": 636230 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/kubelet/pod/_meta/docs.asciidoc b/metricbeat/module/kubelet/pod/_meta/docs.asciidoc new file mode 100644 index 00000000000..02711aa7bd8 --- /dev/null +++ b/metricbeat/module/kubelet/pod/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +=== kubelet pod MetricSet + +This is the pod metricset of the module kubelet. diff --git a/metricbeat/module/kubelet/pod/_meta/fields.yml b/metricbeat/module/kubelet/pod/_meta/fields.yml new file mode 100644 index 00000000000..a7fdcfe77bf --- /dev/null +++ b/metricbeat/module/kubelet/pod/_meta/fields.yml @@ -0,0 +1,9 @@ +- name: pod + type: group + description: > + node + fields: + - name: example + type: keyword + description: > + Example field diff --git a/metricbeat/module/kubelet/pod/data.go b/metricbeat/module/kubelet/pod/data.go new file mode 100644 index 00000000000..296f9ef9852 --- /dev/null +++ b/metricbeat/module/kubelet/pod/data.go @@ -0,0 +1,44 @@ +package node + +import ( + "encoding/json" + "fmt" + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/module/kubelet" +) + +func eventMapping(content []byte) ([]common.MapStr, error) { + events := []common.MapStr{} + + var summary kubelet.Summary + err := json.Unmarshal(content, &summary) + if err != nil { + return nil, fmt.Errorf("Cannot unmarshal json response: %s", err) + } + + node := summary.Node + + for _, pod := range summary.Pods { + podEvent := common.MapStr{ + "name": pod.PodRef.Name, + "namespace": pod.PodRef.Namespace, + "node": node.NodeName, + + "start_time": pod.StartTime, + + "network": common.MapStr{ + "rx": common.MapStr{ + "bytes": pod.Network.RxBytes, + "errors": pod.Network.RxErrors, + }, + "tx": common.MapStr{ + "bytes": pod.Network.TxBytes, + "errors": pod.Network.TxErrors, + }, + }, + } + events = append(events, podEvent) + } + return events, nil + +} diff --git a/metricbeat/module/kubelet/pod/pod.go b/metricbeat/module/kubelet/pod/pod.go new file mode 100644 index 00000000000..14798ac8028 --- /dev/null +++ b/metricbeat/module/kubelet/pod/pod.go @@ -0,0 +1,67 @@ +package node + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/helper" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" +) + +const ( + defaultScheme = "http" + defaultPath = "/stats/summary" +) + +var ( + hostParser = parse.URLHostParserBuilder{ + DefaultScheme: defaultScheme, + DefaultPath: defaultPath, + }.Build() +) + +// init registers the MetricSet with the central registry. +// The New method will be called after the setup of the module and before starting to fetch data +func init() { + if err := mb.Registry.AddMetricSet("kubelet", "pod", New, hostParser); err != nil { + panic(err) + } +} + +// MetricSet type defines all fields of the MetricSet +// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with +// additional entries. These variables can be used to persist data or configuration between +// multiple fetch calls. +type MetricSet struct { + mb.BaseMetricSet + http *helper.HTTP +} + +// New create a new instance of the MetricSet +// Part of new is also setting up the configuration by processing additional +// configuration entries if needed. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("BETA: The kubelet pod metricset is alpha") + return &MetricSet{ + BaseMetricSet: base, + http: helper.NewHTTP(base), + }, nil +} + +// Fetch methods implements the data gathering and data conversion to the right format +// It returns the event which is then forward to the output. In case of an error, a +// descriptive error must be returned. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + + body, err := m.http.FetchContent() + if err != nil { + return nil, err + } + + events, err := eventMapping(body) + if err != nil { + return nil, err + } + + return events, nil +} diff --git a/metricbeat/module/kubelet/system/_meta/data.json b/metricbeat/module/kubelet/system/_meta/data.json new file mode 100644 index 00000000000..5d046764068 --- /dev/null +++ b/metricbeat/module/kubelet/system/_meta/data.json @@ -0,0 +1,45 @@ +{ + "@timestamp": "2017-04-06T15:29:27.150Z", + "beat": { + "hostname": "beathost", + "name": "beathost", + "version": "6.0.0-alpha1" + }, + "kubelet": { + "node": { + "name": "localhost" + }, + "system": { + "container": "kubelet", + "cpu": { + "usage": { + "core": { + "ns": 1424273250468228 + }, + "nanocores": 382404825 + } + }, + "memory": { + "majorpagefaults": 49, + "pagefaults": 22921778663, + "rss": { + "bytes": 159412224 + }, + "usage": { + "bytes": 223035392 + }, + "workingset": { + "bytes": 169037824 + } + }, + "start_time": "2017-02-08T10:35:02Z" + } + }, + "metricset": { + "host": "localhost:10255", + "module": "kubelet", + "name": "system", + "rtt": 640649 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/kubelet/system/_meta/docs.asciidoc b/metricbeat/module/kubelet/system/_meta/docs.asciidoc new file mode 100644 index 00000000000..8137c694183 --- /dev/null +++ b/metricbeat/module/kubelet/system/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +=== kubelet system MetricSet + +This is the system metricset of the module kubelet. diff --git a/metricbeat/module/kubelet/system/_meta/fields.yml b/metricbeat/module/kubelet/system/_meta/fields.yml new file mode 100644 index 00000000000..81f6567c931 --- /dev/null +++ b/metricbeat/module/kubelet/system/_meta/fields.yml @@ -0,0 +1,9 @@ +- name: system + type: group + description: > + node + fields: + - name: example + type: keyword + description: > + Example field diff --git a/metricbeat/module/kubelet/system/data.go b/metricbeat/module/kubelet/system/data.go new file mode 100644 index 00000000000..1f942da3d03 --- /dev/null +++ b/metricbeat/module/kubelet/system/data.go @@ -0,0 +1,58 @@ +package node + +import ( + "encoding/json" + "fmt" + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/kubelet" +) + +func eventMapping(content []byte) ([]common.MapStr, error) { + events := []common.MapStr{} + + var summary kubelet.Summary + err := json.Unmarshal(content, &summary) + if err != nil { + return nil, fmt.Errorf("Cannot unmarshal json response: %s", err) + } + + node := summary.Node + + for _, syscontainer := range node.SystemContainers { + containerEvent := common.MapStr{ + mb.ModuleData: common.MapStr{ + "node": common.MapStr{ + "name": node.NodeName, + }, + }, + "container": syscontainer.Name, + "start_time": syscontainer.StartTime, + "cpu": common.MapStr{ + "usage": common.MapStr{ + "nanocores": syscontainer.CPU.UsageNanoCores, + "core": common.MapStr{ + "ns": syscontainer.CPU.UsageCoreNanoSeconds, + }, + }, + }, + "memory": common.MapStr{ + "usage": common.MapStr{ + "bytes": syscontainer.Memory.UsageBytes, + }, + "workingset": common.MapStr{ + "bytes": syscontainer.Memory.WorkingSetBytes, + }, + "rss": common.MapStr{ + "bytes": syscontainer.Memory.RssBytes, + }, + "pagefaults": syscontainer.Memory.PageFaults, + "majorpagefaults": syscontainer.Memory.MajorPageFaults, + }, + } + events = append(events, containerEvent) + } + + return events, nil + +} diff --git a/metricbeat/module/kubelet/system/system.go b/metricbeat/module/kubelet/system/system.go new file mode 100644 index 00000000000..e740e9f30c2 --- /dev/null +++ b/metricbeat/module/kubelet/system/system.go @@ -0,0 +1,67 @@ +package node + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/helper" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" +) + +const ( + defaultScheme = "http" + defaultPath = "/stats/summary" +) + +var ( + hostParser = parse.URLHostParserBuilder{ + DefaultScheme: defaultScheme, + DefaultPath: defaultPath, + }.Build() +) + +// init registers the MetricSet with the central registry. +// The New method will be called after the setup of the module and before starting to fetch data +func init() { + if err := mb.Registry.AddMetricSet("kubelet", "system", New, hostParser); err != nil { + panic(err) + } +} + +// MetricSet type defines all fields of the MetricSet +// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with +// additional entries. These variables can be used to persist data or configuration between +// multiple fetch calls. +type MetricSet struct { + mb.BaseMetricSet + http *helper.HTTP +} + +// New create a new instance of the MetricSet +// Part of new is also setting up the configuration by processing additional +// configuration entries if needed. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("BETA: The kubelet system metricset is alpha") + return &MetricSet{ + BaseMetricSet: base, + http: helper.NewHTTP(base), + }, nil +} + +// Fetch methods implements the data gathering and data conversion to the right format +// It returns the event which is then forward to the output. In case of an error, a +// descriptive error must be returned. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + + body, err := m.http.FetchContent() + if err != nil { + return nil, err + } + + events, err := eventMapping(body) + if err != nil { + return nil, err + } + + return events, nil +} diff --git a/metricbeat/module/kubelet/types.go b/metricbeat/module/kubelet/types.go new file mode 100644 index 00000000000..4de3eb18542 --- /dev/null +++ b/metricbeat/module/kubelet/types.go @@ -0,0 +1,119 @@ +package kubelet + +type Summary struct { + Node struct { + CPU struct { + Time string `json:"time"` + UsageCoreNanoSeconds int64 `json:"usageCoreNanoSeconds"` + UsageNanoCores int64 `json:"usageNanoCores"` + } `json:"cpu"` + Fs struct { + AvailableBytes int64 `json:"availableBytes"` + CapacityBytes int64 `json:"capacityBytes"` + Inodes int64 `json:"inodes"` + InodesFree int64 `json:"inodesFree"` + InodesUsed int64 `json:"inodesUsed"` + UsedBytes int64 `json:"usedBytes"` + } `json:"fs"` + Memory struct { + AvailableBytes int64 `json:"availableBytes"` + MajorPageFaults int64 `json:"majorPageFaults"` + PageFaults int64 `json:"pageFaults"` + RssBytes int64 `json:"rssBytes"` + Time string `json:"time"` + UsageBytes int64 `json:"usageBytes"` + WorkingSetBytes int64 `json:"workingSetBytes"` + } `json:"memory"` + Network struct { + RxBytes int64 `json:"rxBytes"` + RxErrors int64 `json:"rxErrors"` + Time string `json:"time"` + TxBytes int64 `json:"txBytes"` + TxErrors int64 `json:"txErrors"` + } `json:"network"` + NodeName string `json:"nodeName"` + Runtime struct { + ImageFs struct { + AvailableBytes int64 `json:"availableBytes"` + CapacityBytes int64 `json:"capacityBytes"` + UsedBytes int64 `json:"usedBytes"` + } `json:"imageFs"` + } `json:"runtime"` + StartTime string `json:"startTime"` + SystemContainers []struct { + CPU struct { + Time string `json:"time"` + UsageCoreNanoSeconds int64 `json:"usageCoreNanoSeconds"` + UsageNanoCores int64 `json:"usageNanoCores"` + } `json:"cpu"` + Memory struct { + MajorPageFaults int64 `json:"majorPageFaults"` + PageFaults int64 `json:"pageFaults"` + RssBytes int64 `json:"rssBytes"` + Time string `json:"time"` + UsageBytes int64 `json:"usageBytes"` + WorkingSetBytes int64 `json:"workingSetBytes"` + } `json:"memory"` + Name string `json:"name"` + StartTime string `json:"startTime"` + UserDefinedMetrics interface{} `json:"userDefinedMetrics"` + } `json:"systemContainers"` + } `json:"node"` + Pods []struct { + Containers []struct { + CPU struct { + Time string `json:"time"` + UsageCoreNanoSeconds int64 `json:"usageCoreNanoSeconds"` + UsageNanoCores int64 `json:"usageNanoCores"` + } `json:"cpu"` + Logs struct { + AvailableBytes int64 `json:"availableBytes"` + CapacityBytes int64 `json:"capacityBytes"` + Inodes int64 `json:"inodes"` + InodesFree int64 `json:"inodesFree"` + InodesUsed int64 `json:"inodesUsed"` + UsedBytes int64 `json:"usedBytes"` + } `json:"logs"` + Memory struct { + AvailableBytes int64 `json:"availableBytes"` + MajorPageFaults int64 `json:"majorPageFaults"` + PageFaults int64 `json:"pageFaults"` + RssBytes int64 `json:"rssBytes"` + Time string `json:"time"` + UsageBytes int64 `json:"usageBytes"` + WorkingSetBytes int64 `json:"workingSetBytes"` + } `json:"memory"` + Name string `json:"name"` + Rootfs struct { + AvailableBytes int64 `json:"availableBytes"` + CapacityBytes int64 `json:"capacityBytes"` + InodesUsed int64 `json:"inodesUsed"` + UsedBytes int64 `json:"usedBytes"` + } `json:"rootfs"` + StartTime string `json:"startTime"` + UserDefinedMetrics interface{} `json:"userDefinedMetrics"` + } `json:"containers"` + Network struct { + RxBytes int64 `json:"rxBytes"` + RxErrors int64 `json:"rxErrors"` + Time string `json:"time"` + TxBytes int64 `json:"txBytes"` + TxErrors int64 `json:"txErrors"` + } `json:"network"` + PodRef struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + UID string `json:"uid"` + } `json:"podRef"` + StartTime string `json:"startTime"` + Volume []struct { + AvailableBytes int64 `json:"availableBytes"` + CapacityBytes int64 `json:"capacityBytes"` + Inodes int64 `json:"inodes"` + InodesFree int64 `json:"inodesFree"` + InodesUsed int64 `json:"inodesUsed"` + Name string `json:"name"` + UsedBytes int64 `json:"usedBytes"` + } `json:"volume"` + } `json:"pods"` +} diff --git a/metricbeat/module/kubelet/volume/_meta/data.json b/metricbeat/module/kubelet/volume/_meta/data.json new file mode 100644 index 00000000000..20da195d3aa --- /dev/null +++ b/metricbeat/module/kubelet/volume/_meta/data.json @@ -0,0 +1,41 @@ +{ + "@timestamp": "2017-04-06T15:29:27.150Z", + "beat": { + "hostname": "beathost", + "name": "beathost", + "version": "6.0.0-alpha1" + }, + "kubelet": { + "pod": { + "name": "nginx-3137573019-pcfzh", + "namespace": "ns", + "node": "localhost" + }, + "volume": { + "fs": { + "available": { + "bytes": 92849512448 + }, + "capacity": { + "bytes": 92849524736 + }, + "inodes": { + "count": 22668341, + "free": 22668332, + "used": 9 + }, + "used": { + "bytes": 12288 + } + }, + "name": "default-token-4fkmg" + } + }, + "metricset": { + "host": "localhost:10255", + "module": "kubelet", + "name": "volume", + "rtt": 648606 + }, + "type": "metricsets" +} diff --git a/metricbeat/module/kubelet/volume/_meta/docs.asciidoc b/metricbeat/module/kubelet/volume/_meta/docs.asciidoc new file mode 100644 index 00000000000..3e2368cb148 --- /dev/null +++ b/metricbeat/module/kubelet/volume/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +=== kubelet volume MetricSet + +This is the volume metricset of the module kubelet. diff --git a/metricbeat/module/kubelet/volume/_meta/fields.yml b/metricbeat/module/kubelet/volume/_meta/fields.yml new file mode 100644 index 00000000000..fdcf9f25804 --- /dev/null +++ b/metricbeat/module/kubelet/volume/_meta/fields.yml @@ -0,0 +1,9 @@ +- name: volume + type: group + description: > + node + fields: + - name: example + type: keyword + description: > + Example field diff --git a/metricbeat/module/kubelet/volume/data.go b/metricbeat/module/kubelet/volume/data.go new file mode 100644 index 00000000000..02f6f2c902b --- /dev/null +++ b/metricbeat/module/kubelet/volume/data.go @@ -0,0 +1,56 @@ +package node + +import ( + "encoding/json" + "fmt" + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/module/kubelet" +) + +func eventMapping(content []byte) ([]common.MapStr, error) { + events := []common.MapStr{} + + var summary kubelet.Summary + err := json.Unmarshal(content, &summary) + if err != nil { + return nil, fmt.Errorf("Cannot unmarshal json response: %s", err) + } + + node := summary.Node + for _, pod := range summary.Pods { + for _, volume := range pod.Volume { + volumeEvent := common.MapStr{ + mb.ModuleData: common.MapStr{ + "pod": common.MapStr{ + "name": pod.PodRef.Name, + "namespace": pod.PodRef.Namespace, + "node": node.NodeName, + }, + }, + + "name": volume.Name, + "fs": common.MapStr{ + "available": common.MapStr{ + "bytes": volume.AvailableBytes, + }, + "capacity": common.MapStr{ + "bytes": volume.CapacityBytes, + }, + "used": common.MapStr{ + "bytes": volume.UsedBytes, + }, + "inodes": common.MapStr{ + "used": volume.InodesUsed, + "free": volume.InodesFree, + "count": volume.Inodes, + }, + }, + } + events = append(events, volumeEvent) + } + + } + return events, nil + +} diff --git a/metricbeat/module/kubelet/volume/volume.go b/metricbeat/module/kubelet/volume/volume.go new file mode 100644 index 00000000000..2c309c3fe26 --- /dev/null +++ b/metricbeat/module/kubelet/volume/volume.go @@ -0,0 +1,67 @@ +package node + +import ( + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/helper" + "github.com/elastic/beats/metricbeat/mb" + "github.com/elastic/beats/metricbeat/mb/parse" +) + +const ( + defaultScheme = "http" + defaultPath = "/stats/summary" +) + +var ( + hostParser = parse.URLHostParserBuilder{ + DefaultScheme: defaultScheme, + DefaultPath: defaultPath, + }.Build() +) + +// init registers the MetricSet with the central registry. +// The New method will be called after the setup of the module and before starting to fetch data +func init() { + if err := mb.Registry.AddMetricSet("kubelet", "volume", New, hostParser); err != nil { + panic(err) + } +} + +// MetricSet type defines all fields of the MetricSet +// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with +// additional entries. These variables can be used to persist data or configuration between +// multiple fetch calls. +type MetricSet struct { + mb.BaseMetricSet + http *helper.HTTP +} + +// New create a new instance of the MetricSet +// Part of new is also setting up the configuration by processing additional +// configuration entries if needed. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("BETA: The kubelet volume metricset is alpha") + return &MetricSet{ + BaseMetricSet: base, + http: helper.NewHTTP(base), + }, nil +} + +// Fetch methods implements the data gathering and data conversion to the right format +// It returns the event which is then forward to the output. In case of an error, a +// descriptive error must be returned. +func (m *MetricSet) Fetch() ([]common.MapStr, error) { + + body, err := m.http.FetchContent() + if err != nil { + return nil, err + } + + events, err := eventMapping(body) + if err != nil { + return nil, err + } + + return events, nil +}