mirror of
https://github.com/digitalocean/ceph_exporter
synced 2025-02-15 10:56:55 +00:00
Added the expansion factor metric which will compute the multiplier for data expansion for EC clusters. Will return the pool size if it is not an EC pool
183 lines
5.2 KiB
Go
183 lines
5.2 KiB
Go
// Copyright 2016 DigitalOcean
|
|
//
|
|
// 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 collectors
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/ceph/go-ceph/rados"
|
|
)
|
|
|
|
// Conn interface implements only necessary methods that are used
|
|
// in this repository of *rados.Conn. This keeps rest of the implementation
|
|
// clean and *rados.Conn doesn't need to show up everywhere (it being
|
|
// more of an implementation detail in reality). Also it makes mocking
|
|
// easier for unit-testing the collectors.
|
|
type Conn interface {
|
|
ReadDefaultConfigFile() error
|
|
Connect() error
|
|
Shutdown()
|
|
MonCommand([]byte) ([]byte, string, error)
|
|
PGCommand([]byte, []byte) ([]byte, string, error)
|
|
}
|
|
|
|
// Verify that *rados.Conn implements Conn correctly.
|
|
var _ Conn = &rados.Conn{}
|
|
|
|
// NoopConn is the stub we use for mocking rados Conn. Unit testing
|
|
// each individual collectors becomes a lot easier after that.
|
|
// TODO: both output and cmdOut provide the command outputs for "go test", but
|
|
// we can deprecate output, because cmdOut is able to hold the outputs we desire
|
|
// for multiple commands for "go test".
|
|
type NoopConn struct {
|
|
output string // deprecated
|
|
cmdOut []map[string]string
|
|
iteration int
|
|
}
|
|
|
|
// The stub we use for testing should also satisfy the interface properties.
|
|
var _ Conn = &NoopConn{}
|
|
|
|
// NewNoopConn returns an instance of *NoopConn. The string that we want output
|
|
// at the end of the command we issue to Ceph is fixed and should be specified
|
|
// in the only input parameter.
|
|
func NewNoopConn(output string) *NoopConn {
|
|
return &NoopConn{output: output}
|
|
}
|
|
|
|
// NewNoopConnWithCmdOut returns an instance of *NoopConn. The string that we
|
|
// want output at the end of the command we issue to Ceph can be various and
|
|
// should be specified by the map in the only input parameter.
|
|
func NewNoopConnWithCmdOut(cmdOut []map[string]string) *NoopConn {
|
|
return &NoopConn{
|
|
cmdOut: cmdOut,
|
|
iteration: 0,
|
|
}
|
|
}
|
|
|
|
// IncIteration increments iteration by 1.
|
|
func (n *NoopConn) IncIteration() {
|
|
n.iteration++
|
|
}
|
|
|
|
// ReadDefaultConfigFile does not need to return an error. It satisfies
|
|
// rados.Conn's function with the same prototype.
|
|
func (n *NoopConn) ReadDefaultConfigFile() error {
|
|
return nil
|
|
}
|
|
|
|
// Connect does not need to return an error. It satisfies
|
|
// rados.Conn's function with the same prototype.
|
|
func (n *NoopConn) Connect() error {
|
|
return nil
|
|
}
|
|
|
|
// Shutdown satisfies rados.Conn's function prototype.
|
|
func (n *NoopConn) Shutdown() {}
|
|
|
|
// MonCommand returns the provided output string to NoopConn as is, making
|
|
// it seem like it actually ran something and produced that string as a result.
|
|
func (n *NoopConn) MonCommand(args []byte) ([]byte, string, error) {
|
|
// Unmarshal the input command and see if we need to intercept
|
|
cmd := map[string]interface{}{}
|
|
err := json.Unmarshal(args, &cmd)
|
|
if err != nil {
|
|
return []byte(n.output), "", err
|
|
}
|
|
|
|
// Intercept and mock the output
|
|
switch prefix := cmd["prefix"]; prefix {
|
|
case "pg dump":
|
|
val, ok := cmd["dumpcontents"]
|
|
if !ok {
|
|
break
|
|
}
|
|
|
|
dc, ok := val.([]interface{})
|
|
if !ok || len(dc) == 0 {
|
|
break
|
|
}
|
|
|
|
switch dc[0] {
|
|
case "pgs_brief":
|
|
return []byte(n.cmdOut[n.iteration]["ceph pg dump pgs_brief"]), "", nil
|
|
}
|
|
|
|
case "osd tree":
|
|
val, ok := cmd["states"]
|
|
if !ok {
|
|
break
|
|
}
|
|
|
|
st, ok := val.([]interface{})
|
|
if !ok || len(st) == 0 {
|
|
break
|
|
}
|
|
|
|
switch st[0] {
|
|
case "down":
|
|
return []byte(n.cmdOut[n.iteration]["ceph osd tree down"]), "", nil
|
|
}
|
|
|
|
case "osd df":
|
|
return []byte(n.cmdOut[n.iteration]["ceph osd df"]), "", nil
|
|
|
|
case "osd perf":
|
|
return []byte(n.cmdOut[n.iteration]["ceph osd perf"]), "", nil
|
|
|
|
case "osd dump":
|
|
return []byte(n.cmdOut[n.iteration]["ceph osd dump"]), "", nil
|
|
|
|
case "osd erasure-code-profile get ec-4-2":
|
|
ec42Return :=
|
|
`{
|
|
"crush-device-class": "",
|
|
"crush-failure-domain": "host",
|
|
"crush-root": "objectdata",
|
|
"jerasure-per-chunk-alignment": "false",
|
|
"k": "4",
|
|
"m": "2",
|
|
"plugin": "jerasure",
|
|
"technique": "reed_sol_van",
|
|
"w": "8"
|
|
}`
|
|
return []byte(ec42Return), "", nil
|
|
|
|
case "osd erasure-code-profile get replicated-ruleset":
|
|
return []byte("{}"), "", nil
|
|
}
|
|
return []byte(n.output), "", nil
|
|
}
|
|
|
|
// PGCommand returns the provided output string to NoopConn as is, making
|
|
// it seem like it actually ran something and produced that string as a result.
|
|
func (n *NoopConn) PGCommand(pgid, args []byte) ([]byte, string, error) {
|
|
// Unmarshal the input command and see if we need to intercept
|
|
cmd := map[string]interface{}{}
|
|
err := json.Unmarshal(args, &cmd)
|
|
if err != nil {
|
|
return []byte(n.output), "", err
|
|
}
|
|
|
|
// Intercept and mock the output
|
|
switch prefix := cmd["prefix"]; prefix {
|
|
case "query":
|
|
return []byte(n.cmdOut[n.iteration][fmt.Sprintf("ceph tell %s query", string(pgid))]), "", nil
|
|
}
|
|
|
|
return []byte(n.output), "", nil
|
|
}
|