From df1e3a4ed44631ed5ff42264d5707c4bbf7f3f5e Mon Sep 17 00:00:00 2001 From: Marcin Olszewski Date: Fri, 4 Aug 2017 13:05:49 +0200 Subject: [PATCH] Promote plugin to supported level - switch to plugin-lib-go - refactor metric-key processing (use array instead of concatenated strings) --- disk/disk.go | 141 +++++++++++++++++++++------------------------- disk/disk_test.go | 81 ++++++++++++++++---------- glide.lock | 92 ++++++++++++++++++++---------- glide.yaml | 55 +++--------------- main.go | 25 ++++---- 5 files changed, 196 insertions(+), 198 deletions(-) diff --git a/disk/disk.go b/disk/disk.go index ff850dc..3857aa0 100644 --- a/disk/disk.go +++ b/disk/disk.go @@ -1,10 +1,15 @@ /* http://www.apache.org/licenses/LICENSE-2.0.txt + + Copyright 2016 Intel Corporation + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,20 +31,14 @@ import ( log "github.com/Sirupsen/logrus" - "github.com/intelsdi-x/snap/control/plugin" - "github.com/intelsdi-x/snap/control/plugin/cpolicy" - "github.com/intelsdi-x/snap/core" - - "github.com/intelsdi-x/snap-plugin-utilities/config" + "github.com/intelsdi-x/snap-plugin-lib-go/v1/plugin" ) const ( // Name of plugin - pluginName = "disk" + PluginName = "disk" // Version of plugin - pluginVersion = 4 - // Type of plugin - pluginType = plugin.CollectorPluginType + PluginVersion = 5 nsVendor = "intel" nsClass = "procfs" @@ -73,14 +72,14 @@ var ( // DiskCollector holds disk statistics type DiskCollector struct { - data diskStats // holds current raw data - dataPrev diskStats // previous data, to calculate derivatives - output map[string]float64 // contains exposed metrics and their value (calculated based on data & dataPrev) - first bool // is true for first collecting (do not calculate derivatives), after that set false + data diskStats // holds current raw data + dataPrev diskStats // previous data, to calculate derivatives + output map[metricKey]float64 // contains exposed metrics and their value (calculated based on data & dataPrev) + first bool // is true for first collecting (do not calculate derivatives), after that set false } type diskStats struct { - stats map[string]uint64 + stats map[metricKey]uint64 timestamp time.Time } @@ -91,43 +90,37 @@ type diffStats struct { diffReadOps uint64 } +type metricKey [2]string + // prefix in metric namespace var prefix = []string{nsVendor, nsClass, nsType} // New returns snap-plugin-collector-disk instance func New() (*DiskCollector, error) { - dc := &DiskCollector{data: diskStats{stats: map[string]uint64{}, timestamp: time.Now()}, - dataPrev: diskStats{stats: map[string]uint64{}, timestamp: time.Now()}, - output: map[string]float64{}, + dc := &DiskCollector{data: diskStats{stats: map[metricKey]uint64{}, timestamp: time.Now()}, + dataPrev: diskStats{stats: map[metricKey]uint64{}, timestamp: time.Now()}, + output: map[metricKey]float64{}, first: true} return dc, nil } // Meta returns plugin meta data -func Meta() *plugin.PluginMeta { - return plugin.NewPluginMeta( - pluginName, - pluginVersion, - pluginType, - []string{}, - []string{plugin.SnapGOBContentType}, +func Meta() []plugin.MetaOpt { + return []plugin.MetaOpt{ plugin.ConcurrencyCount(1), - ) + } } // GetConfigPolicy returns a ConfigPolicy -func (dc *DiskCollector) GetConfigPolicy() (*cpolicy.ConfigPolicy, error) { - cp := cpolicy.New() - rule, _ := cpolicy.NewStringRule("proc_path", false, "/proc") - node := cpolicy.NewPolicyNode() - node.Add(rule) - cp.Add([]string{nsVendor, nsClass, pluginName}, node) - return cp, nil +func (dc *DiskCollector) GetConfigPolicy() (plugin.ConfigPolicy, error) { + policy := plugin.NewConfigPolicy() + policy.AddNewStringRule(prefix, "proc_path", false, plugin.SetDefaultString("/proc")) + return *policy, nil } // GetMetricTypes returns list of exposed disk stats metrics -func (dc *DiskCollector) GetMetricTypes(cfg plugin.ConfigType) ([]plugin.MetricType, error) { - mts := []plugin.MetricType{} +func (dc *DiskCollector) GetMetricTypes(cfg plugin.Config) ([]plugin.Metric, error) { + mts := []plugin.Metric{} procFilePath, err := resolveSrcFile(cfg) if err != nil { @@ -145,11 +138,11 @@ func (dc *DiskCollector) GetMetricTypes(cfg plugin.ConfigType) ([]plugin.MetricT // Keep it if not already seen before if !mList[metricName] { mList[metricName] = true - mts = append(mts, plugin.MetricType{ - Namespace_: core.NewNamespace(prefix...). + mts = append(mts, plugin.Metric{ + Namespace: plugin.NewNamespace(prefix...). AddDynamicElement("disk", "name of disk"). AddStaticElement(metricName), - Description_: "dynamic disk metric: " + metricName, + Description: "dynamic disk metric: " + metricName, }) } } @@ -157,10 +150,10 @@ func (dc *DiskCollector) GetMetricTypes(cfg plugin.ConfigType) ([]plugin.MetricT } // CollectMetrics retrieves disk stats values for given metrics -func (dc *DiskCollector) CollectMetrics(mts []plugin.MetricType) ([]plugin.MetricType, error) { - metrics := []plugin.MetricType{} +func (dc *DiskCollector) CollectMetrics(mts []plugin.Metric) ([]plugin.Metric, error) { + metrics := []plugin.Metric{} - procFilePath, err := resolveSrcFile(mts[0]) + procFilePath, err := resolveSrcFile(mts[0].Config) if err != nil { return nil, err } @@ -195,7 +188,7 @@ func (dc *DiskCollector) CollectMetrics(mts []plugin.MetricType) ([]plugin.Metri for _, m := range mts { - requestedDiskID, requestedMetric, err := parseNamespace(m.Namespace()) + requestedDiskID, requestedMetric, err := parseNamespace(m.Namespace) if err != nil { return nil, err } @@ -206,16 +199,15 @@ func (dc *DiskCollector) CollectMetrics(mts []plugin.MetricType) ([]plugin.Metri if metricName == requestedMetric { // create a copy of incoming namespace and specify disk name - ns := make([]core.NamespaceElement, len(m.Namespace())) - copy(ns, m.Namespace()) + ns := plugin.CopyNamespace(m.Namespace) ns[len(prefix)].Value = diskID - metric := plugin.MetricType{ - Namespace_: ns, - Data_: value, - Timestamp_: dc.data.timestamp, - Version_: pluginVersion, - Tags_: m.Tags(), + metric := plugin.Metric{ + Namespace: ns, + Data: value, + Timestamp: dc.data.timestamp, + Version: PluginVersion, + Tags: m.Tags, } metrics = append(metrics, metric) } @@ -225,17 +217,17 @@ func (dc *DiskCollector) CollectMetrics(mts []plugin.MetricType) ([]plugin.Metri // get this metric for specified disk (given explicitly) metricKey := createMetricKey(requestedDiskID, requestedMetric) if value, ok := dc.output[metricKey]; ok { - metric := plugin.MetricType{ - Namespace_: m.Namespace(), - Data_: value, - Timestamp_: dc.data.timestamp, - Version_: pluginVersion, - Tags_: m.Tags(), + metric := plugin.Metric{ + Namespace: m.Namespace, + Data: value, + Timestamp: dc.data.timestamp, + Version: PluginVersion, + Tags: m.Tags, } metrics = append(metrics, metric) } else { - log.Warning(fmt.Sprintf("Can not find metric value for %s", m.Namespace().Strings())) + log.Warning(fmt.Sprintf("Can not find metric value for %s", m.Namespace.Strings())) } } } @@ -326,7 +318,7 @@ func (dc *DiskCollector) getDiskStats(srcFile string) error { func (dc *DiskCollector) calcGauge() { for key, val := range dc.data.stats { - if strings.HasSuffix(key, nPendingOps) { + if _, metric := parseMetricKey(key); strings.HasSuffix(metric, nPendingOps) { // for 'pending_ops' output value is simply stored as-is dc.output[key] = float64(val) } @@ -403,8 +395,8 @@ func (dc *DiskCollector) calcDerivatives() error { // calculate disk time for disk, values := range avgDiskTime { - dc.output[disk+"/"+nTimeRead] = calcTimeIncrement(values.diffReadTime, values.diffReadOps, interval) - dc.output[disk+"/"+nTimeWrite] = calcTimeIncrement(values.diffWriteTime, values.diffWriteOps, interval) + dc.output[createMetricKey(disk, nTimeRead)] = calcTimeIncrement(values.diffReadTime, values.diffReadOps, interval) + dc.output[createMetricKey(disk, nTimeWrite)] = calcTimeIncrement(values.diffWriteTime, values.diffWriteOps, interval) } return nil @@ -434,7 +426,7 @@ func stashData(dst *diskStats, src *diskStats) { } // parseNamespace returns extracted disk ID and metric key from a given namespace and true if raw metric is requested -func parseNamespace(ns core.Namespace) (string, string, error) { +func parseNamespace(ns plugin.Namespace) (string, string, error) { if len(ns.Strings()) <= len(prefix)+1 { return "", "", fmt.Errorf("Cannot parse a given namespace %s, it's too short (expected length > %d)", ns.Strings(), len(prefix)) } @@ -448,7 +440,7 @@ func parseNamespace(ns core.Namespace) (string, string, error) { return diskID, metricName, nil } -func isRawMetrics(ns core.Namespace) bool { +func isRawMetrics(ns plugin.Namespace) bool { if ns.Strings()[len(prefix)+1] == "raw" { return true } @@ -456,27 +448,20 @@ func isRawMetrics(ns core.Namespace) bool { } // parseMetricKey extracts information about disk and metric name from metric key (exemplary metric key is `sda/time_write`) -func parseMetricKey(k string) (disk, metric string) { - result := strings.Split(k, core.Separator) - - if len(result) < 2 { - // invalid key format, return empty strings - return - } - - return result[0], result[1] +func parseMetricKey(k metricKey) (disk, metric string) { + return k[0], k[1] } // createMetricKey returns metric key which includes disk name and name of metric, exemplary metric key is `sda/time_write` -func createMetricKey(diskName string, metricName string) string { - return diskName + core.Separator + metricName +func createMetricKey(diskName string, metricName string) metricKey { + return metricKey{diskName, metricName} } -func resolveSrcFile(cfg interface{}) (string, error) { +func resolveSrcFile(config plugin.Config) (string, error) { // first configuration - if srcFile, err := config.GetConfigItem(cfg, "proc_path"); err == nil { + if srcFile, err := config.GetString("proc_path"); err == nil { // diskstats - diskstats := path.Join(srcFile.(string), "diskstats") + diskstats := path.Join(srcFile, "diskstats") fh, err := os.Open(diskstats) if err == nil { fh.Close() @@ -484,13 +469,13 @@ func resolveSrcFile(cfg interface{}) (string, error) { } // partitions old kernel - partitions := path.Join(srcFile.(string), "partitions") + partitions := path.Join(srcFile, "partitions") fh, err = os.Open(partitions) if err == nil { fh.Close() return partitions, nil } else { - return "", fmt.Errorf("Provided path to procfs diskstats/partitions is not correct {%s}", srcFile.(string)) + return "", fmt.Errorf("Provided path to procfs diskstats/partitions is not correct {%s}", srcFile) } } diff --git a/disk/disk_test.go b/disk/disk_test.go index 81d9636..0f03cea 100644 --- a/disk/disk_test.go +++ b/disk/disk_test.go @@ -1,12 +1,17 @@ -// +build linux +// +build small /* http://www.apache.org/licenses/LICENSE-2.0.txt + + Copyright 2016 Intel Corporation + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,10 +25,9 @@ import ( "os" "testing" - "github.com/intelsdi-x/snap/control/plugin" - "github.com/intelsdi-x/snap/core" - . "github.com/smartystreets/goconvey/convey" + + "github.com/intelsdi-x/snap-plugin-lib-go/v1/plugin" ) const ( @@ -33,42 +37,61 @@ const ( ) var ( - mockMts = []plugin.MetricType{ - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda", "ops_read"), + mockMts = []plugin.Metric{ + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda", "ops_read"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda", "ops_write"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda", "ops_write"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda", "octets_read"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda", "octets_read"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda", "octets_write"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda", "octets_write"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda1", "ops_read"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda1", "ops_read"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda1", "ops_write"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda1", "ops_write"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda1", "octets_read"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda1", "octets_read"), }, - plugin.MetricType{ - Namespace_: core.NewNamespace("intel", "procfs", "disk", "test_sda1", "octets_write"), + plugin.Metric{ + Namespace: plugin.NewNamespace("intel", "procfs", "disk", "test_sda1", "octets_write"), }, } - srcMockFile = "/tmp/diskstats_mock" - srcMockFileNext = "/tmp/diskstats_mock_next" - srcMockFileOldVer = "/tmp/partitions_mock" - srcMockFileInv = "/tmp/invalid_mock" + srcMockFile = "/tmp/diskstats_mock" + srcMockFileNext = "/tmp/diskstats_mock_next" + srcMockFileOldVer = "/tmp/partitions_mock" + srcMockFileInv = "/tmp/invalid_mock" + bkupDefaultSrcFile string + bkupDefaultSrcFileOld string ) +func TestMain(m *testing.M) { + PrepareTests() + ret := m.Run() + TeardownTests() + os.Exit(ret) +} + +func PrepareTests() { + bkupDefaultSrcFile = defaultSrcFile + bkupDefaultSrcFileOld = defaultSrcFileOld +} + +func TeardownTests() { + defaultSrcFile = bkupDefaultSrcFile + defaultSrcFileOld = bkupDefaultSrcFileOld +} + func TestGetConfigPolicy(t *testing.T) { Convey("normal case", t, func() { diskPlugin, err := New() @@ -84,7 +107,7 @@ func TestGetConfigPolicy(t *testing.T) { func TestGetMetricTypes(t *testing.T) { defaultSrcFile = srcMockFile defaultSrcFileOld = srcMockFileOldVer - var cfg plugin.ConfigType + var cfg plugin.Config createMockFiles() @@ -190,7 +213,7 @@ func TestCollectMetrics(t *testing.T) { So(results, ShouldNotBeEmpty) So(len(results), ShouldEqual, len(mockMts)) for _, r := range results { - So(r.Data(), ShouldEqual, 0) + So(r.Data, ShouldEqual, 0) } }) @@ -202,7 +225,7 @@ func TestCollectMetrics(t *testing.T) { So(len(results), ShouldEqual, len(mockMts)) for _, r := range results { - So(r.Data(), ShouldNotEqual, 0) + So(r.Data, ShouldNotEqual, 0) } }) }) diff --git a/glide.lock b/glide.lock index f3290b1..a07c1e6 100644 --- a/glide.lock +++ b/glide.lock @@ -1,50 +1,80 @@ -hash: 577285134234fb7d485bf38cc91e6a3fe9efaa3030f79c1442189417c3a51a5a -updated: 2016-11-02T20:04:18.415316327+01:00 +hash: f17aab7dd2b2060a146cb31d29f20837cceab3d4fec54ceb84529847979eee30 +updated: 2017-08-04T15:51:35.997524835+02:00 imports: -- name: github.com/intelsdi-x/snap - version: c14d5c2330ec39da8d502da1856bef6acd4c6b30 - subpackages: - - control/plugin - - control/plugin/cpolicy - - control/plugin/encoding - - control/plugin/encrypter - - core - - core/cdata - - core/ctypes - - core/serror - - pkg/ctree - - pkg/schedule - - pkg/stringutils - - scheduler/wmap -- name: github.com/intelsdi-x/snap-plugin-utilities - version: 925bafffac36edcfaf4aff937dcb7d3d5659782d - subpackages: - - config -- name: github.com/robfig/cron - version: 32d9c273155a0506d27cf73dd1246e86a470997e +- name: github.com/golang/protobuf + version: 748d386b5c1ea99658fd69fe9f03991ce86a90c1 + subpackages: + - proto + - ptypes/any +- name: github.com/intelsdi-x/snap-plugin-lib-go + version: f9ce43c629c97377e2ff2c53699aa785c0251c46 + subpackages: + - v1/plugin + - v1/plugin/rpc +- name: github.com/julienschmidt/httprouter + version: 8c199fb6259ffc1af525cc3ad52ee60ba8359669 - name: github.com/Sirupsen/logrus - version: be52937128b38f1d99787bb476c789e2af1147f1 + version: a3f95b5c423586578a4e099b11a46c2479628cac +- name: github.com/urfave/cli + version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6 +- name: golang.org/x/net + version: f5079bd7f6f74e23c4d65efa0f4ce14cbd6a3c0f + subpackages: + - context + - http2 + - http2/hpack + - idna + - internal/timeseries + - lex/httplex + - trace - name: golang.org/x/sys - version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 + version: d8f5ea21b9295e315e612b4bcf4bedea93454d4d subpackages: - unix -- name: gopkg.in/yaml.v2 - version: c1cd2254a6dd314c9d73c338c12688c9325d85c6 +- name: golang.org/x/text + version: 3bd178b88a8180be2df394a1fbb81313916f0e7b + subpackages: + - secure/bidirule + - transform + - unicode/bidi + - unicode/norm +- name: google.golang.org/genproto + version: 09f6ed296fc66555a25fe4ce95173148778dfa85 + subpackages: + - googleapis/rpc/status +- name: google.golang.org/grpc + version: b8669c35455183da6d5c474ea6e72fbf55183274 + subpackages: + - codes + - credentials + - grpclb/grpc_lb_v1 + - grpclog + - internal + - keepalive + - metadata + - naming + - peer + - stats + - status + - tap + - transport testImports: - name: github.com/gopherjs/gopherjs - version: 4b53e1bddba0e2f734514aeb6c02db652f4c6fe8 + version: 2b1d432c8a82c9bff0b0baffaeb3ec6e92974112 subpackages: - js - name: github.com/jtolds/gls - version: 8ddce2a84170772b95dd5d576c48d517b22cac63 + version: 77f18212c9c7edc9bd6a33d383a7b545ce62f064 - name: github.com/smartystreets/assertions - version: 443d812296a84445c202c085f19e18fc238f8250 + version: 3c7b29c4776a870a5983b38635e241a40a7e5422 subpackages: - internal/go-render/render - internal/oglematchers - name: github.com/smartystreets/goconvey - version: 995f5b2e021c69b8b028ba6d0b05c1dd500783db + version: d4c757aa9afd1e2fc1832aaab209b5794eb336e1 subpackages: - convey - convey/gotest - convey/reporting +- name: github.com/smartystreets/logging + version: ac3a674540761aa0b4382094ba4795f917e85c7f diff --git a/glide.yaml b/glide.yaml index a870490..4f1f6ce 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,49 +1,12 @@ -hash: dca2cf749a7496a7fc9b476a5e8fe75a6b74ef65c7b2b6e880f31ec9a1d8a428 -updated: 2016-10-27T14:11:10.759279255-07:00 -imports: -- name: github.com/intelsdi-x/snap - version: 891c09fd7e93aaf7cc0fb976fb91407901fd3843 +package: github.com/intelsdi-x/snap-plugin-collector-disk +import: +- package: github.com/Sirupsen/logrus + version: ^1.0.2 +- package: github.com/intelsdi-x/snap-plugin-lib-go subpackages: - - control/plugin - - control/plugin/cpolicy - - control/plugin/encoding - - control/plugin/encrypter - - core - - core/cdata - - core/ctypes - - core/serror - - pkg/ctree - - pkg/schedule - - scheduler/wmap -- name: github.com/intelsdi-x/snap-plugin-utilities - version: f907c27a012b4e57329799c1f00fb22241243f2d - subpackages: - - config -- name: github.com/robfig/cron - version: 0f39cf7ebc65a602f45692f9894bd6a193faf8fa -- name: github.com/Sirupsen/logrus - version: cd7d1bbe41066b6c1f19780f895901052150a575 -- name: golang.org/x/sys - version: c8bc69bc2db9c57ccf979550bc69655df5039a8a - subpackages: - - unix -- name: gopkg.in/yaml.v2 - version: c1cd2254a6dd314c9d73c338c12688c9325d85c6 -testImports: -- name: github.com/gopherjs/gopherjs - version: 4b53e1bddba0e2f734514aeb6c02db652f4c6fe8 - subpackages: - - js -- name: github.com/jtolds/gls - version: 8ddce2a84170772b95dd5d576c48d517b22cac63 -- name: github.com/smartystreets/assertions - version: 443d812296a84445c202c085f19e18fc238f8250 - subpackages: - - internal/go-render/render - - internal/oglematchers -- name: github.com/smartystreets/goconvey - version: d4c757aa9afd1e2fc1832aaab209b5794eb336e1 + - v1/plugin +testImport: +- package: github.com/smartystreets/goconvey + version: ^1.6.2 subpackages: - convey - - convey/gotest - - convey/reporting diff --git a/main.go b/main.go index fa971b5..06fb890 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,15 @@ -// +build linux - /* http://www.apache.org/licenses/LICENSE-2.0.txt + + Copyright 2016 Intel Corporation + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,25 +20,19 @@ limitations under the License. package main import ( - "os" - - // Import the snap plugin library - "github.com/intelsdi-x/snap/control/plugin" - - // Import our collector plugin implementation "github.com/intelsdi-x/snap-plugin-collector-disk/disk" + "github.com/intelsdi-x/snap-plugin-lib-go/v1/plugin" ) func main() { - p, err := disk.New() if err != nil { panic(err) } - - plugin.Start( - disk.Meta(), + plugin.StartCollector( p, - os.Args[1], + disk.PluginName, + disk.PluginVersion, + disk.Meta()..., ) }