/
command.go
185 lines (169 loc) · 6.4 KB
/
command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright © 2017-2019 The OpenEBS Authors
//
// 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
//
// 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.
// See the License for the specific language governing permissions and
// limitations under the License.
package command
import (
"errors"
goflag "flag"
"net/url"
"time"
"github.com/openebs/maya/cmd/maya-exporter/app/collector"
"github.com/openebs/maya/cmd/maya-exporter/app/collector/pool"
"github.com/openebs/maya/cmd/maya-exporter/app/collector/zvol"
types "github.com/openebs/maya/pkg/exec"
exec "github.com/openebs/maya/pkg/exec/v1alpha1"
"github.com/openebs/maya/pkg/util"
"github.com/prometheus/client_golang/prometheus"
"github.com/spf13/cobra"
"k8s.io/klog"
)
// Constants defined here are the default value of the flags. Which can be
// changed while running the binary.
const (
// listenAddress is the address where exporter listens for the rest api
// calls.
listenAddress = ":9500"
// metricsPath is the endpoint of exporter.
metricsPath = "/metrics"
// socketPath where istgt is listening
socketPath = "/var/run/istgt_ctl_sock"
// controllerAddress is the address where jiva controller listens.
controllerAddress = "http://localhost:9501"
// casType is the type of container attached storage (CAS) from which
// the metrics need to be exported. Default is Jiva"
casType = "jiva"
// timeout is the timeout for executing a command
timeout = 30 * time.Second
)
// VolumeExporterOptions is used to create flags for the monitoring command
type VolumeExporterOptions struct {
ListenAddress string
MetricsPath string
ControllerAddress string
CASType string
}
// AddListenAddressFlag is used to create flag to pass the listen address of exporter.
func AddListenAddressFlag(cmd *cobra.Command, value *string) {
cmd.Flags().StringVarP(value, "listen.addr", "a", *value,
"Address on which to expose metrics and web interface.)")
}
// AddMetricsPathFlag is used to create flag to pass the listen path where volume
// metrics are exposed.
func AddMetricsPathFlag(cmd *cobra.Command, value *string) {
cmd.Flags().StringVarP(value, "listen.path", "m", *value,
"Path under which to expose metrics.")
}
// AddControllerAddressFlag is used to create flag to pass the Jiva volume
// controllers IP.
func AddControllerAddressFlag(cmd *cobra.Command, value *string) {
cmd.Flags().StringVarP(value, "controller.addr", "c", *value,
"IP address from where metrics to be exported")
}
// AddCASTypeFlag is used to create flag to pass the storage engine name
func AddCASTypeFlag(cmd *cobra.Command, value *string) {
cmd.Flags().StringVarP(value, "cas.type", "e", *value,
"Type of container attached storage engine")
}
// NewCmdVolumeExporter is used to create command monitoring and it initialize
// monitoring flags also.
func NewCmdVolumeExporter() (*cobra.Command, error) {
// create an instance of VolumeExporterOptions to initialize with default
// values for the flags.
options := VolumeExporterOptions{}
options.ControllerAddress = controllerAddress
options.ListenAddress = listenAddress
options.MetricsPath = metricsPath
options.CASType = casType
cmd := &cobra.Command{
Short: "Collect metrics from OpenEBS volumes",
Long: `maya-exporter can be used to monitor openebs volumes and pools.
It can be deployed alongside the openebs volume or pool containers as sidecars.`,
Example: `maya-exporter -a=http://localhost:8001 -c=:9500 -m=/metrics`,
Run: func(cmd *cobra.Command, args []string) {
util.CheckErr(Run(cmd, &options), util.Fatal)
},
}
cmd.Flags().AddGoFlagSet(goflag.CommandLine)
goflag.CommandLine.Parse([]string{})
AddControllerAddressFlag(cmd, &options.ControllerAddress)
AddListenAddressFlag(cmd, &options.ListenAddress)
AddMetricsPathFlag(cmd, &options.MetricsPath)
AddCASTypeFlag(cmd, &options.CASType)
return cmd, nil
}
// Run used to process commands,args and call openebs exporter and it returns
// nil on successful execution.
func Run(cmd *cobra.Command, options *VolumeExporterOptions) error {
klog.Infof("Starting maya-exporter ...")
switch options.CASType {
case "cstor":
klog.Infof("Initialising maya-exporter for the cstor")
options.RegisterCstor()
case "jiva":
klog.Infof("Initialising maya-exporter for the jiva")
if err := options.RegisterJiva(); err != nil {
klog.Fatal(err)
return nil
}
case "pool":
klog.Infof("Initialising maya-exporter for the cstor pool")
options.RegisterPool()
default:
return errors.New("unsupported CAS")
}
options.StartMayaExporter()
return nil
}
// RegisterJiva parses the jiva controller URL and
// initialises an instance of Jiva.This returns err
// if the URL is not correct.
func (o *VolumeExporterOptions) RegisterJiva() error {
url, err := url.ParseRequestURI(o.ControllerAddress)
if err != nil {
klog.Error(err)
return errors.New("Error in parsing the URI")
}
jiva := collector.Jiva(url)
exporter := collector.New(jiva)
prometheus.MustRegister(exporter)
klog.Info("Registered maya exporter for jiva")
return nil
}
// RegisterCstor initiates the connection with the cstor and register
// the exporter with Prometheus for collecting the metrics.This doesn't returns
// error because that case is handled in InitiateConnection().
func (o *VolumeExporterOptions) RegisterCstor() {
cstor := collector.Cstor(socketPath)
exporter := collector.New(cstor)
prometheus.MustRegister(exporter)
klog.Info("Registered maya exporter for cstor")
return
}
// RegisterPool registers pool collector which collects
// pool level metrics
func (o *VolumeExporterOptions) RegisterPool() {
p := pool.New(buildRunner(timeout, "zpool", "list", "-Hp"))
z := zvol.New(buildRunner(timeout, "zfs", "stats"))
l := zvol.NewVolumeList(buildRunner(timeout, "zfs", "list", "-Hp"))
s := zvol.NewPoolSyncMetric(buildRunner(timeout, "zfs", "get", "io.openebs:livenesstimestamp", "-Hp"))
prometheus.MustRegister(p, z, l, s)
klog.Info("Registered maya exporter for cstor pool")
return
}
func buildRunner(timeout time.Duration, cmd string, args ...string) types.Runner {
return exec.StdoutBuilder().
WithTimeout(timeout).
WithCommand(cmd).
WithArgs(args...).
Build()
}