// Copyright 2015 The Prometheus 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. // +build openbsd // +build !norcctl package collector import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" "os/exec" "strings" ) var ( specialSvcs = map[string]struct{}{ "accounting": struct{}{}, "check_quotas": struct{}{}, "ipsec": struct{}{}, "library_aslr": struct{}{}, "multicast": struct{}{}, "pf": struct{}{}, "spamd_black": struct{}{}, } ) const ( rcctl = "/usr/sbin/rcctl" rcdir = "/etc/rc.d" ) type rcctlCollector struct { state, stateDesired typedDesc logger log.Logger } func init() { registerCollector("rcctl", defaultDisabled, NewRcctlCollector) } // NewRunitCollector returns a new Collector exposing runit statistics. func NewRcctlCollector(logger log.Logger) (Collector, error) { var ( subsystem = "service" constLabels = prometheus.Labels{"supervisor": "rcctl"} labelNames = []string{"service"} ) return &rcctlCollector{ state: typedDesc{prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "state"), "State of rcctl service.", labelNames, constLabels, ), prometheus.GaugeValue}, stateDesired: typedDesc{prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "desired_state"), "Desired state of rcctl service.", labelNames, constLabels, ), prometheus.GaugeValue}, logger: logger, }, nil } func (rcctlCollector) check(service string) (status int) { cmd := exec.Command(rcdir+"/"+service, "check") err := cmd.Run() if err != nil { return } if cmd.ProcessState.ExitCode() == 0 { status = 1 } return } func (c *rcctlCollector) Update(ch chan<- prometheus.Metric) error { cmd := exec.Command(rcctl, "ls", "on") on, err := cmd.Output() if err != nil { return err } for _, s := range strings.Split(string(on), "\n") { if s == "" { continue } if _, ok := specialSvcs[s]; ok { continue } status := c.check(s) level.Debug(c.logger).Log("msg", "Current status", "Service", s, "Status", status) ch <- c.state.mustNewConstMetric(float64(status), s) ch <- c.stateDesired.mustNewConstMetric(float64(1), s) } return nil }