Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions cmd/kepler/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/sustainable-computing-io/kepler/internal/device"
"github.com/sustainable-computing-io/kepler/internal/exporter/prometheus"
"github.com/sustainable-computing-io/kepler/internal/exporter/stdout"
"github.com/sustainable-computing-io/kepler/internal/k8s/pod"
"github.com/sustainable-computing-io/kepler/internal/logger"
"github.com/sustainable-computing-io/kepler/internal/monitor"
"github.com/sustainable-computing-io/kepler/internal/resource"
Expand Down Expand Up @@ -126,10 +127,22 @@ func createServices(logger *slog.Logger, cfg *config.Config) ([]service.Service,
if err != nil {
return nil, fmt.Errorf("failed to create CPU power meter: %w", err)
}
var services []service.Service

resouceInformer, err := resource.NewInformer(
var podInformer pod.Informer
if *cfg.Kube.Enabled {
podInformer = pod.NewInformer(
pod.WithLogger(logger),
pod.WithKubeEnabled(*cfg.Kube.Enabled),
pod.WithKubeConfig(cfg.Kube.Config),
pod.WithNodeName(cfg.Kube.Node),
)
services = append(services, podInformer)
}
resourceInformer, err := resource.NewInformer(
resource.WithLogger(logger),
resource.WithProcFSPath(cfg.Host.ProcFS),
resource.WithPodInformer(podInformer),
)
if err != nil {
return nil, fmt.Errorf("failed to create resource informer: %w", err)
Expand All @@ -138,7 +151,7 @@ func createServices(logger *slog.Logger, cfg *config.Config) ([]service.Service,
pm := monitor.NewPowerMonitor(
cpuPowerMeter,
monitor.WithLogger(logger),
monitor.WithResourceInformer(resouceInformer),
monitor.WithResourceInformer(resourceInformer),
monitor.WithInterval(cfg.Monitor.Interval),
monitor.WithMaxStaleness(cfg.Monitor.Staleness),
)
Expand All @@ -147,12 +160,12 @@ func createServices(logger *slog.Logger, cfg *config.Config) ([]service.Service,
server.WithLogger(logger),
)

services := []service.Service{
services = append(services,
resourceInformer,
cpuPowerMeter,
resouceInformer,
apiServer,
pm,
}
)

// Add Prometheus exporter if enabled
if *cfg.Exporter.Prometheus.Enabled {
Expand Down
48 changes: 48 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@
Pprof PprofDebug `yaml:"pprof"`
}

Kube struct {
Enabled *bool `yaml:"enabled"`
Config string `yaml:"config"`
Node string `yaml:"nodeName"`
}

Config struct {
Log Log `yaml:"log"`
Host Host `yaml:"host"`
Expand All @@ -80,13 +86,16 @@
Web Web `yaml:"web"`
Debug Debug `yaml:"debug"`
Dev Dev `yaml:"dev"` // WARN: do not expose dev settings as flags

Kube Kube `yaml:"kube"`
}
)

type SkipValidation int

const (
SkipHostValidation SkipValidation = 1
SkipKubeValidation SkipValidation = 2
)

const (
Expand Down Expand Up @@ -114,6 +123,11 @@
// NOTE: not a flag
ExporterPrometheusDebugCollectors = "exporter.prometheus.debug-collectors"

// kubernetes flags
KubernetesFlag = "kube.enable"
KubeConfigFlag = "kube.config"
KubeNodeNameFlag = "kube.node-name"

// WARN: dev settings shouldn't be exposed as flags as flags are intended for end users
)

Expand Down Expand Up @@ -149,6 +163,9 @@
Enabled: ptr.To(false),
},
},
Kube: Kube{
Enabled: ptr.To(false),
},
}

cfg.Dev.FakeCpuMeter.Enabled = ptr.To(false)
Expand Down Expand Up @@ -235,6 +252,10 @@

prometheusExporterEnabled := app.Flag(ExporterPrometheusEnabledFlag, "Enable Prometheus exporter").Default("true").Bool()

kubernetes := app.Flag(KubernetesFlag, "Monitor kubernetes").Default("false").Bool()
kubeconfig := app.Flag(KubeConfigFlag, "Path to a kubeconfig. Only required if out-of-cluster.").ExistingFile()
nodeName := app.Flag(KubeNodeNameFlag, "Name of kubernetes node on which kepler is running.").String()

return func(cfg *Config) error {
// Logging settings
if flagsSet[LogLevelFlag] {
Expand Down Expand Up @@ -274,6 +295,18 @@
cfg.Exporter.Prometheus.Enabled = prometheusExporterEnabled
}

if flagsSet[KubernetesFlag] {
cfg.Kube.Enabled = kubernetes
}

Check warning on line 300 in config/config.go

View check run for this annotation

Codecov / codecov/patch

config/config.go#L299-L300

Added lines #L299 - L300 were not covered by tests

if flagsSet[KubeConfigFlag] {
cfg.Kube.Config = *kubeconfig
}

Check warning on line 304 in config/config.go

View check run for this annotation

Codecov / codecov/patch

config/config.go#L303-L304

Added lines #L303 - L304 were not covered by tests

if flagsSet[KubeNodeNameFlag] {
cfg.Kube.Node = *nodeName
}

Check warning on line 308 in config/config.go

View check run for this annotation

Codecov / codecov/patch

config/config.go#L307-L308

Added lines #L307 - L308 were not covered by tests

cfg.sanitize()
return cfg.Validate()
}
Expand All @@ -293,6 +326,7 @@
for i := range c.Exporter.Prometheus.DebugCollectors {
c.Exporter.Prometheus.DebugCollectors[i] = strings.TrimSpace(c.Exporter.Prometheus.DebugCollectors[i])
}
c.Kube.Config = strings.TrimSpace(c.Kube.Config)
}

// Validate checks for configuration errors
Expand Down Expand Up @@ -351,6 +385,19 @@
errs = append(errs, fmt.Sprintf("invalid monitor staleness: %s can't be negative", c.Monitor.Staleness))
}
}
{ // Kubernetes
if c.Kube.Config != "" && !ptr.Deref(c.Kube.Enabled, false) {
errs = append(errs, fmt.Sprintf("%s supplied but %s set to false", KubeConfigFlag, KubernetesFlag))
}
if c.Kube.Node != "" && !ptr.Deref(c.Kube.Enabled, false) {
errs = append(errs, fmt.Sprintf("%s supplied but %s set to false", KubeNodeNameFlag, KubernetesFlag))
}
if ptr.Deref(c.Kube.Enabled, false) && c.Kube.Config != "" {
if err := canReadFile(c.Kube.Config); err != nil {
errs = append(errs, fmt.Sprintf("unreadable kubeconfig: %s", c.Kube.Config))
}
}
}

if len(errs) > 0 {
return fmt.Errorf("invalid configuration: %s", strings.Join(errs, ", "))
Expand Down Expand Up @@ -423,6 +470,7 @@
{ExporterPrometheusEnabledFlag, fmt.Sprintf("%v", c.Exporter.Prometheus.Enabled)},
{ExporterPrometheusDebugCollectors, strings.Join(c.Exporter.Prometheus.DebugCollectors, ", ")},
{pprofEnabledFlag, fmt.Sprintf("%v", c.Debug.Pprof.Enabled)},
{KubeConfigFlag, fmt.Sprintf("%v", c.Kube.Config)},
}
sb := strings.Builder{}

Expand Down
25 changes: 25 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,31 @@ func TestInvalidConfigurationValues(t *testing.T) {
},
},
error: "invalid web config file",
}, {
name: "unreadable kubeconfig",
config: &Config{
Kube: Kube{
Config: "/non/existent/file",
Enabled: ptr.To(true),
},
},
error: "unreadable kubeconfig",
}, {
name: "kube not enabled, kubeconfig supplied",
config: &Config{
Kube: Kube{
Config: "/some/existing/file",
},
},
error: "kube.config supplied but kube.enable set to false",
}, {
name: "kube not enabled, nodeName supplied",
config: &Config{
Kube: Kube{
Node: "dummyNode",
},
},
error: "kube.node-name supplied but kube.enable set to false",
}}

// test yaml marshall
Expand Down
51 changes: 47 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,51 +1,94 @@
module github.com/sustainable-computing-io/kepler

go 1.23
go 1.23.0

toolchain go1.23.3

require (
dario.cat/mergo v1.0.2
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/go-logr/logr v1.4.2
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v1.0.5
github.com/prometheus/client_golang v1.22.0
github.com/prometheus/client_model v0.6.1
github.com/prometheus/exporter-toolkit v0.14.0
github.com/prometheus/procfs v0.15.1
github.com/stretchr/testify v1.10.0
golang.org/x/sync v0.10.0
go.uber.org/zap v1.26.0
golang.org/x/sync v0.12.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.31.0
k8s.io/apimachinery v0.31.0
k8s.io/client-go v0.31.0
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
sigs.k8s.io/controller-runtime v0.19.0
)

require (
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/olekukonko/errors v0.0.0-20250405072817-4e6d85265da6 // indirect
github.com/olekukonko/ll v0.0.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.3.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiextensions-apiserver v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
Loading
Loading