Skip to content

Commit

Permalink
feat: Support running ext cmds as different users
Browse files Browse the repository at this point in the history
* Now ipmi can be run as root directly in the exporter

* Users can still use wrapper approach if they want

Signed-off-by: Mahendra Paipuri <[email protected]>
  • Loading branch information
mahendrapaipuri committed Dec 14, 2023
1 parent 667231a commit a41800d
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 7 deletions.
16 changes: 15 additions & 1 deletion internal/helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os/exec"
"strings"
"syscall"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
Expand All @@ -24,7 +25,20 @@ func Execute(cmd string, args []string, logger log.Logger) ([]byte, error) {
level.Debug(logger).Log("msg", "Executing", "command", cmd, "args", fmt.Sprintf("%+v", args))
out, err := exec.Command(cmd, args...).CombinedOutput()
if err != nil {
err = fmt.Errorf("error running %s: %s", cmd, err)
level.Error(logger).Log("msg", "Error executing command", "command", cmd, "args", fmt.Sprintf("%+v", args), "err", err)
}
return out, err
}

// Execute command as a given UID and GID and return stdout/stderr
func ExecuteAs(cmd string, args []string, uid int, gid int, logger log.Logger) ([]byte, error) {
level.Debug(logger).Log("msg", "Executing as user", "command", cmd, "args", fmt.Sprintf("%+v", args), "uid", uid, "gid", gid)
execCmd := exec.Command(cmd, args...)
execCmd.SysProcAttr = &syscall.SysProcAttr{}
execCmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
out, err := execCmd.CombinedOutput()
if err != nil {
level.Error(logger).Log("msg", "Error executing command as user", "command", cmd, "args", fmt.Sprintf("%+v", args), "uid", uid, "gid", gid, "err", err)
}
return out, err
}
26 changes: 21 additions & 5 deletions pkg/collector/ipmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ type impiCollector struct {
}

var (
ipmiDcmiWrapperExec = kingpin.Flag(
"collector.ipmi.dcmi.wrapper.path",
"Path to IPMI DCMI executable wrapper.",
ipmiDcmiExec = kingpin.Flag(
"collector.ipmi.dcmi.exec.path",
"Path to IPMI DCMI executable.",
).Default("ipmi-dcmi-wrapper").String()
ipmiDcmiExecAsRoot = kingpin.Flag(
"collector.ipmi.dcmi.exec.run.as.root",
"Execute IPMI DCMI command as root. This requires batchjob_exporter to run as root or to have appropriate capabilities (cap_setuid).",
).Default("false").Bool()
ipmiDCMIPowerMeasurementRegex = regexp.MustCompile(
`^Power Measurement\s*:\s*(?P<value>Active|Not\sAvailable).*`,
)
Expand Down Expand Up @@ -78,16 +82,27 @@ func getValue(ipmiOutput []byte, regex *regexp.Regexp) (string, error) {

// Update implements Collector and exposes IPMI DCMI power related metrics.
func (c *impiCollector) Update(ch chan<- prometheus.Metric) error {
args := []string{""}
stdOut, err := helpers.Execute(*ipmiDcmiWrapperExec, args, c.logger)
args := []string{"--get-system-power-statistics"}
var stdOut []byte
var err error

// Execute ipmi-dcmi command
if *ipmiDcmiExecAsRoot {
stdOut, err = helpers.ExecuteAs(*ipmiDcmiExec, args, 0, 0, c.logger)
} else {
stdOut, err = helpers.Execute(*ipmiDcmiExec, args, c.logger)
}
if err != nil {
return err
}

// Parse power consumption from output
currentPowerConsumption, err := c.getCurrentPowerConsumption(stdOut)
if err != nil {
level.Error(c.logger).Log("msg", "Failed to collect IPMI DCMI data", "error", err)
return err
}

// Returned value negative == Power Measurement is not avail
if currentPowerConsumption > -1 {
ch <- prometheus.MustNewConstMetric(c.wattsMetricDesc, prometheus.CounterValue, float64(currentPowerConsumption))
Expand All @@ -102,6 +117,7 @@ func (c *impiCollector) getCurrentPowerConsumption(ipmiOutput []byte) (float64,
if err != nil {
return -1, err
}

// When Power Measurement in 'Active' state - we can get watts
if value == "Active" {
value, err := getValue(ipmiOutput, ipmiDCMICurrentPowerRegex)
Expand Down
2 changes: 1 addition & 1 deletion scripts/e2e-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ then
--path.sysfs="pkg/collector/fixtures/sys" \
--path.cgroupfs="pkg/collector/fixtures/sys/fs/cgroup" \
--collector.slurm.job.stat.path="pkg/collector/fixtures/slurmjobstat" \
--collector.ipmi.dcmi.wrapper.path="pkg/collector/fixtures/ipmi-dcmi-wrapper.sh" \
--collector.ipmi.dcmi.exec.path="pkg/collector/fixtures/ipmi-dcmi-wrapper.sh" \
--collector.nvidia_gpu \
--collector.nvidia.gpu.stat.path="pkg/collector/fixtures/gpustat" \
--web.listen-address "127.0.0.1:${port}" \
Expand Down

0 comments on commit a41800d

Please sign in to comment.