Skip to content

Commit

Permalink
feat: Allow image to be specified in Internal API
Browse files Browse the repository at this point in the history
Signed-off-by: Sunil Thaha <[email protected]>
  • Loading branch information
sthaha committed Nov 17, 2023
1 parent be0ddb6 commit cee1bb3
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ spec:
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
- jsonPath: .spec.exporter.deployment.image
name: Image
type: string
- jsonPath: .spec.exporter.deployment.nodeSelector
name: Node-Selector
priority: 10
Expand Down Expand Up @@ -68,6 +71,8 @@ spec:
properties:
deployment:
properties:
image:
type: string
nodeSelector:
additionalProperties:
type: string
Expand Down
4 changes: 2 additions & 2 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ func main() {
// NOTE: RELATED_IMAGE_KEPLER can be set as env or flag, flag takes precedence over env
keplerImage := os.Getenv("RELATED_IMAGE_KEPLER")
keplerImageLibbpf := os.Getenv("RELATED_IMAGE_KEPLER_LIBBPF")
flag.StringVar(&exporter.Config.Image, "kepler.image", keplerImage, "kepler image")
flag.StringVar(&exporter.Config.ImageLibbpf, "kepler.image.libbpf", keplerImageLibbpf, "kepler libbpf image")
flag.StringVar(&controllers.Config.Image, "kepler.image", keplerImage, "kepler image")
flag.StringVar(&controllers.Config.ImageLibbpf, "kepler.image.libbpf", keplerImageLibbpf, "kepler libbpf image")

opts := zap.Options{
Development: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ spec:
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
- jsonPath: .spec.exporter.deployment.image
name: Image
type: string
- jsonPath: .spec.exporter.deployment.nodeSelector
name: Node-Selector
priority: 10
Expand Down Expand Up @@ -68,6 +71,8 @@ spec:
properties:
deployment:
properties:
image:
type: string
nodeSelector:
additionalProperties:
type: string
Expand Down
7 changes: 7 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ KeplerInternalSpec defines the desired state of Kepler
</tr>
</thead>
<tbody><tr>
<td><b>image</b></td>
<td>string</td>
<td>
<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>nodeSelector</b></td>
<td>map[string]string</td>
<td>
Expand Down
12 changes: 11 additions & 1 deletion pkg/api/v1alpha1/kepler_internal_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,18 @@ import (
// e.g. kepler-internal.spec.exporter can reuse ExporterSpec because the API is
// considered stable but not vice-versa.

type InternalExporterDeploymentSpec struct {
ExporterDeploymentSpec `json:",inline"`
Image string `json:"image,omitempty"`
}

type InternalExporterSpec struct {
Deployment InternalExporterDeploymentSpec `json:"deployment,omitempty"`
}

// KeplerInternalSpec defines the desired state of Kepler
type KeplerInternalSpec struct {
Exporter ExporterSpec `json:"exporter,omitempty"`
Exporter InternalExporterSpec `json:"exporter,omitempty"`
}

//+kubebuilder:object:root=true
Expand All @@ -40,6 +49,7 @@ type KeplerInternalSpec struct {
// +kubebuilder:printcolumn:name="Up-to-date",type=integer,JSONPath=`.status.updatedNumberScheduled`
// +kubebuilder:printcolumn:name="Available",type=integer,JSONPath=`.status.numberAvailable`
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:printcolumn:name="Image",type=string,JSONPath=`.spec.exporter.deployment.image`
// +kubebuilder:printcolumn:name="Node-Selector",type=string,JSONPath=`.spec.exporter.deployment.nodeSelector`,priority=10
// +kubebuilder:printcolumn:name="Tolerations",type=string,JSONPath=`.spec.exporter.deployment.tolerations`,priority=10
//
Expand Down
32 changes: 32 additions & 0 deletions pkg/api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 9 additions & 30 deletions pkg/components/exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package exporter
import (
_ "embed"
"strconv"
"strings"

"github.com/sustainable.computing.io/kepler-operator/pkg/api/v1alpha1"
"github.com/sustainable.computing.io/kepler-operator/pkg/components"
Expand Down Expand Up @@ -59,18 +58,6 @@ const (
DashboardNs = "openshift-config-managed"

PrometheusRuleName = prefix + "prom-rules"

KeplerBpfAttachMethodAnnotation = "kepler.sustainable.computing.io/bpf-attach-method"
KeplerBpfAttachMethodBCC = "bcc"
KeplerBpfAttachMethodLibbpf = "libbpf"
)

// Config that will be set from outside
var (
Config = struct {
Image string
ImageLibbpf string
}{}
)

var (
Expand Down Expand Up @@ -106,16 +93,13 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1.
}
}

deployment := k.Spec.Exporter.Deployment
deployment := k.Spec.Exporter.Deployment.ExporterDeploymentSpec
image := k.Spec.Exporter.Deployment.Image
nodeSelector := deployment.NodeSelector
tolerations := deployment.Tolerations
port := deployment.Port

bindAddress := "0.0.0.0:" + strconv.Itoa(int(deployment.Port))

keplerImage := Config.Image
if IsLibbpfAttachType(k) {
keplerImage = Config.ImageLibbpf
}
bindAddress := "0.0.0.0:" + strconv.Itoa(int(port))

return &appsv1.DaemonSet{
TypeMeta: metav1.TypeMeta{
Expand Down Expand Up @@ -144,7 +128,7 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1.
Containers: []corev1.Container{{
Name: "kepler-exporter",
SecurityContext: &corev1.SecurityContext{Privileged: pointer.Bool(true)},
Image: keplerImage,
Image: image,
Command: []string{
"/usr/bin/kepler",
"-address", bindAddress,
Expand All @@ -155,14 +139,14 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1.
"-redfish-cred-file-path=/etc/redfish/redfish.csv",
},
Ports: []corev1.ContainerPort{{
ContainerPort: int32(deployment.Port),
ContainerPort: int32(port),
Name: "http",
}},
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/healthz",
Port: intstr.IntOrString{Type: intstr.Int, IntVal: deployment.Port},
Port: intstr.IntOrString{Type: intstr.Int, IntVal: port},
Scheme: "HTTP",
},
},
Expand Down Expand Up @@ -279,7 +263,7 @@ func NewConfigMap(d components.Detail, k *v1alpha1.KeplerInternal) *corev1.Confi
}
}

deployment := k.Spec.Exporter.Deployment
deployment := k.Spec.Exporter.Deployment.ExporterDeploymentSpec
bindAddress := "0.0.0.0:" + strconv.Itoa(int(deployment.Port))

return &corev1.ConfigMap{
Expand Down Expand Up @@ -449,7 +433,7 @@ func NewServiceAccount() *corev1.ServiceAccount {
}

func NewService(k *v1alpha1.KeplerInternal) *corev1.Service {
deployment := k.Spec.Exporter.Deployment
deployment := k.Spec.Exporter.Deployment.ExporterDeploymentSpec

return &corev1.Service{
TypeMeta: metav1.TypeMeta{
Expand Down Expand Up @@ -602,8 +586,3 @@ func record(name, expr string) monv1.Rule {
Record: name,
}
}

func IsLibbpfAttachType(k *v1alpha1.KeplerInternal) bool {
bpftype, ok := k.Annotations[KeplerBpfAttachMethodAnnotation]
return ok && strings.ToLower(bpftype) == KeplerBpfAttachMethodLibbpf
}
91 changes: 21 additions & 70 deletions pkg/components/exporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,26 @@ import (
"github.com/sustainable.computing.io/kepler-operator/pkg/components"
"github.com/sustainable.computing.io/kepler-operator/pkg/utils/k8s"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestNodeSelection(t *testing.T) {

tt := []struct {
spec v1alpha1.ExporterSpec
spec v1alpha1.InternalExporterSpec
selector map[string]string
scenario string
}{
{
spec: v1alpha1.ExporterSpec{},
spec: v1alpha1.InternalExporterSpec{},
selector: map[string]string{"kubernetes.io/os": "linux"},
scenario: "default case",
},
{
spec: v1alpha1.ExporterSpec{
Deployment: v1alpha1.ExporterDeploymentSpec{
NodeSelector: map[string]string{"k1": "v1"},
spec: v1alpha1.InternalExporterSpec{
Deployment: v1alpha1.InternalExporterDeploymentSpec{
ExporterDeploymentSpec: v1alpha1.ExporterDeploymentSpec{
NodeSelector: map[string]string{"k1": "v1"},
},
},
},
selector: map[string]string{"k1": "v1", "kubernetes.io/os": "linux"},
Expand All @@ -52,20 +53,22 @@ func TestNodeSelection(t *testing.T) {
func TestTolerations(t *testing.T) {

tt := []struct {
spec v1alpha1.ExporterSpec
spec v1alpha1.InternalExporterSpec
tolerations []corev1.Toleration
scenario string
}{{
spec: v1alpha1.ExporterSpec{},
spec: v1alpha1.InternalExporterSpec{},
// NOTE: default toleration { "operator": "Exists" } is set by k8s API server (CRD default)
// see: Kepler_Reconciliation e2e test
tolerations: nil,
scenario: "default case",
}, {
spec: v1alpha1.ExporterSpec{
Deployment: v1alpha1.ExporterDeploymentSpec{
Tolerations: []corev1.Toleration{{
Effect: corev1.TaintEffectNoSchedule, Key: "key1"}},
spec: v1alpha1.InternalExporterSpec{
Deployment: v1alpha1.InternalExporterDeploymentSpec{
ExporterDeploymentSpec: v1alpha1.ExporterDeploymentSpec{
Tolerations: []corev1.Toleration{{
Effect: corev1.TaintEffectNoSchedule, Key: "key1"}},
},
},
},
tolerations: []corev1.Toleration{{
Expand All @@ -91,12 +94,12 @@ func TestTolerations(t *testing.T) {

func TestHostPID(t *testing.T) {
tt := []struct {
spec v1alpha1.ExporterSpec
spec v1alpha1.InternalExporterSpec
hostPID bool
scenario string
}{
{
spec: v1alpha1.ExporterSpec{},
spec: v1alpha1.InternalExporterSpec{},
hostPID: true,
scenario: "default case",
},
Expand All @@ -118,12 +121,12 @@ func TestHostPID(t *testing.T) {
}
func TestVolumeMounts(t *testing.T) {
tt := []struct {
spec v1alpha1.ExporterSpec
spec v1alpha1.InternalExporterSpec
volumeMounts []corev1.VolumeMount
scenario string
}{
{
spec: v1alpha1.ExporterSpec{},
spec: v1alpha1.InternalExporterSpec{},
volumeMounts: []corev1.VolumeMount{
{Name: "lib-modules", MountPath: "/lib/modules", ReadOnly: true},
{Name: "tracing", MountPath: "/sys", ReadOnly: true},
Expand Down Expand Up @@ -152,12 +155,12 @@ func TestVolumeMounts(t *testing.T) {
}
func TestVolumes(t *testing.T) {
tt := []struct {
spec v1alpha1.ExporterSpec
spec v1alpha1.InternalExporterSpec
volumes []corev1.Volume
scenario string
}{
{
spec: v1alpha1.ExporterSpec{},
spec: v1alpha1.InternalExporterSpec{},
volumes: []corev1.Volume{
k8s.VolumeFromHost("lib-modules", "/lib/modules"),
k8s.VolumeFromHost("tracing", "/sys"),
Expand Down Expand Up @@ -212,55 +215,3 @@ func TestSCCAllows(t *testing.T) {
})
}
}

func TestBpfAttachMethod(t *testing.T) {

tt := []struct {
annotations map[string]string
scenario string
IsLibbpf bool
}{
{
annotations: map[string]string{},
IsLibbpf: false,
scenario: "no annotation",
},
{
annotations: map[string]string{
KeplerBpfAttachMethodAnnotation: "junk",
},
IsLibbpf: false,
scenario: "annotation present but not libbpf",
},
{
annotations: map[string]string{
KeplerBpfAttachMethodAnnotation: "bcc",
},
IsLibbpf: false,
scenario: "annotation present with bcc",
},
{
annotations: map[string]string{
KeplerBpfAttachMethodAnnotation: "libbpf",
},
IsLibbpf: true,
scenario: "annotation present with libbpf",
},
}
for _, tc := range tt {
tc := tc
t.Run(tc.scenario, func(t *testing.T) {
t.Parallel()
k := v1alpha1.KeplerInternal{
ObjectMeta: metav1.ObjectMeta{
Annotations: tc.annotations,
},
Spec: v1alpha1.KeplerInternalSpec{
Exporter: v1alpha1.ExporterSpec{},
},
}
actual := IsLibbpfAttachType(&k)
assert.Equal(t, actual, tc.IsLibbpf)
})
}
}
Loading

0 comments on commit cee1bb3

Please sign in to comment.