From d1d9e4f182854eb19712bf0f6b83d159ddbc3b37 Mon Sep 17 00:00:00 2001 From: Sunil Thaha Date: Wed, 29 Nov 2023 15:49:40 +1000 Subject: [PATCH] fix: address review comments Signed-off-by: Sunil Thaha --- ...kepler-operator.clusterserviceversion.yaml | 17 +- ...tainable.computing.io_keplerinternals.yaml | 199 +++++++++--------- ...stem.sustainable.computing.io_keplers.yaml | 191 +++++++++-------- ...tainable.computing.io_keplerinternals.yaml | 199 +++++++++--------- ...stem.sustainable.computing.io_keplers.yaml | 191 +++++++++-------- ...kepler-operator.clusterserviceversion.yaml | 13 +- docs/api.md | 82 ++++++-- pkg/api/v1alpha1/kepler_internal_types.go | 29 ++- pkg/api/v1alpha1/kepler_types.go | 22 +- pkg/api/v1alpha1/zz_generated.deepcopy.go | 60 ++++-- pkg/components/components.go | 1 - pkg/components/exporter/exporter.go | 131 ++++++------ pkg/controllers/kepler.go | 41 ++-- pkg/controllers/kepler_internal.go | 49 ++--- pkg/controllers/kepler_test.go | 15 ++ pkg/utils/test/framework.go | 2 +- tests/e2e/kepler_test.go | 12 +- 17 files changed, 702 insertions(+), 552 deletions(-) diff --git a/bundle/manifests/kepler-operator.clusterserviceversion.yaml b/bundle/manifests/kepler-operator.clusterserviceversion.yaml index b6ddda1f..81c98722 100644 --- a/bundle/manifests/kepler-operator.clusterserviceversion.yaml +++ b/bundle/manifests/kepler-operator.clusterserviceversion.yaml @@ -27,7 +27,7 @@ metadata: capabilities: Basic Install categories: Monitoring containerImage: quay.io/sustainable_computing_io/kepler-operator:0.9.2 - createdAt: "2023-11-14T05:15:33Z" + createdAt: "2023-11-29T08:19:36Z" description: 'Deploys and Manages Kepler on Kubernetes ' operators.operatorframework.io/builder: operator-sdk-v1.27.0 operators.operatorframework.io/internal-objects: |- @@ -46,14 +46,23 @@ spec: displayName: KeplerInternal kind: KeplerInternal name: keplerinternals.kepler.system.sustainable.computing.io + statusDescriptors: + - description: conditions represent the latest available observations of the + kepler-exporter + displayName: Conditions + path: exporter.conditions + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:conditions version: v1alpha1 - description: Kepler is the Schema for the keplers API displayName: Kepler kind: Kepler name: keplers.kepler.system.sustainable.computing.io statusDescriptors: - - displayName: Conditions - path: conditions + - description: conditions represent the latest available observations of the + kepler-exporter + displayName: Conditions + path: exporter.conditions x-descriptors: - urn:alm:descriptor:com.tectonic.ui:conditions version: v1alpha1 @@ -349,5 +358,5 @@ spec: name: kepler - image: quay.io/sustainable_computing_io/kepler:release-0.6.1-libbpf name: kepler-libbpf - replaces: kepler-operator.v0.9.0 + replaces: kepler-operator.v0.0.0-dev version: 0.9.2 diff --git a/bundle/manifests/kepler.system.sustainable.computing.io_keplerinternals.yaml b/bundle/manifests/kepler.system.sustainable.computing.io_keplerinternals.yaml index 45164509..df938f9a 100644 --- a/bundle/manifests/kepler.system.sustainable.computing.io_keplerinternals.yaml +++ b/bundle/manifests/kepler.system.sustainable.computing.io_keplerinternals.yaml @@ -18,19 +18,19 @@ spec: - jsonPath: .spec.exporter.deployment.port name: Port type: integer - - jsonPath: .status.desiredNumberScheduled + - jsonPath: .status.exporter.desiredNumberScheduled name: Desired type: integer - - jsonPath: .status.currentNumberScheduled + - jsonPath: .status.exporter.currentNumberScheduled name: Current type: integer - - jsonPath: .status.numberReady - name: Ready - type: integer - jsonPath: .status.updatedNumberScheduled name: Up-to-date type: integer - - jsonPath: .status.numberAvailable + - jsonPath: .status.exporter.numberReady + name: Ready + type: integer + - jsonPath: .status.exporter.numberAvailable name: Available type: integer - jsonPath: .metadata.creationTimestamp @@ -65,15 +65,17 @@ spec: metadata: type: object spec: - description: KeplerInternalSpec defines the desired state of Kepler + description: KeplerInternalSpec defines the desired state of KeplerInternal properties: exporter: properties: deployment: properties: image: + description: Image of kepler-exporter to be deployed type: string namespace: + description: Namespace where kepler-exporter will be deployed type: string nodeSelector: additionalProperties: @@ -151,94 +153,103 @@ spec: type: object type: object status: - description: KeplerStatus defines the observed state of Kepler + description: KeplerInternalStatus represents status of KeplerInternal properties: - conditions: - items: - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. - type: string - status: - description: status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of Kepler Condition - Reconciled, Available - ... - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-type: atomic - currentNumberScheduled: - description: The number of nodes that are running at least 1 kepler - pod and are supposed to run the kepler pod. - format: int32 - type: integer - desiredNumberScheduled: - description: The total number of nodes that should be running the - kepler pod (including nodes correctly running the kepler pod). - format: int32 - type: integer - numberAvailable: - description: The number of nodes that should be running the kepler - pod and have one or more of the kepler pod running and available - format: int32 - type: integer - numberMisscheduled: - description: The number of nodes that are running the kepler pod, - but are not supposed to run the kepler pod. - format: int32 - type: integer - numberReady: - description: numberReady is the number of nodes that should be running - the kepler pod and have one or more of the kepler pod running with - a Ready Condition. - format: int32 - type: integer - numberUnavailable: - description: The number of nodes that should be running the kepler - pod and have none of the kepler pod running and available - format: int32 - type: integer - updatedNumberScheduled: - description: The total number of nodes that are running updated kepler - pod - format: int32 - type: integer - required: - - conditions - - currentNumberScheduled - - desiredNumberScheduled - - numberMisscheduled - - numberReady + exporter: + description: ExporterStatus defines the observed state of Kepler Exporter + properties: + conditions: + description: conditions represent the latest available observations + of the kepler-exporter + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be + when the underlying condition changed. If that is not + known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. + type: string + status: + description: status of the condition, one of True, False, + Unknown. + type: string + type: + description: Type of Kepler Condition - Reconciled, Available + ... + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + currentNumberScheduled: + description: The number of nodes that are running at least 1 kepler + pod and are supposed to run the kepler pod. + format: int32 + type: integer + desiredNumberScheduled: + description: The total number of nodes that should be running + the kepler pod (including nodes correctly running the kepler + pod). + format: int32 + type: integer + numberAvailable: + description: The number of nodes that should be running the kepler + pod and have one or more of the kepler pod running and available + format: int32 + type: integer + numberMisscheduled: + description: The number of nodes that are running the kepler pod, + but are not supposed to run the kepler pod. + format: int32 + type: integer + numberReady: + description: numberReady is the number of nodes that should be + running the kepler pod and have one or more of the kepler pod + running with a Ready Condition. + format: int32 + type: integer + numberUnavailable: + description: The number of nodes that should be running the kepler + pod and have none of the kepler pod running and available + format: int32 + type: integer + updatedNumberScheduled: + description: The total number of nodes that are running updated + kepler pod + format: int32 + type: integer + required: + - conditions + - currentNumberScheduled + - desiredNumberScheduled + - numberMisscheduled + - numberReady + type: object type: object type: object served: true diff --git a/bundle/manifests/kepler.system.sustainable.computing.io_keplers.yaml b/bundle/manifests/kepler.system.sustainable.computing.io_keplers.yaml index 72295f8d..b60f6bcf 100644 --- a/bundle/manifests/kepler.system.sustainable.computing.io_keplers.yaml +++ b/bundle/manifests/kepler.system.sustainable.computing.io_keplers.yaml @@ -18,19 +18,19 @@ spec: - jsonPath: .spec.exporter.deployment.port name: Port type: integer - - jsonPath: .status.desiredNumberScheduled + - jsonPath: .status.exporter.desiredNumberScheduled name: Desired type: integer - - jsonPath: .status.currentNumberScheduled + - jsonPath: .status.exporter.currentNumberScheduled name: Current type: integer - - jsonPath: .status.numberReady + - jsonPath: .status.exporter.numberReady name: Ready type: integer - - jsonPath: .status.updatedNumberScheduled + - jsonPath: .status.exporter.updatedNumberScheduled name: Up-to-date type: integer - - jsonPath: .status.numberAvailable + - jsonPath: .status.exporter.numberAvailable name: Available type: integer - jsonPath: .metadata.creationTimestamp @@ -134,92 +134,101 @@ spec: status: description: KeplerStatus defines the observed state of Kepler properties: - conditions: - items: - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. - type: string - status: - description: status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of Kepler Condition - Reconciled, Available - ... - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-type: atomic - currentNumberScheduled: - description: The number of nodes that are running at least 1 kepler - pod and are supposed to run the kepler pod. - format: int32 - type: integer - desiredNumberScheduled: - description: The total number of nodes that should be running the - kepler pod (including nodes correctly running the kepler pod). - format: int32 - type: integer - numberAvailable: - description: The number of nodes that should be running the kepler - pod and have one or more of the kepler pod running and available - format: int32 - type: integer - numberMisscheduled: - description: The number of nodes that are running the kepler pod, - but are not supposed to run the kepler pod. - format: int32 - type: integer - numberReady: - description: numberReady is the number of nodes that should be running - the kepler pod and have one or more of the kepler pod running with - a Ready Condition. - format: int32 - type: integer - numberUnavailable: - description: The number of nodes that should be running the kepler - pod and have none of the kepler pod running and available - format: int32 - type: integer - updatedNumberScheduled: - description: The total number of nodes that are running updated kepler - pod - format: int32 - type: integer - required: - - conditions - - currentNumberScheduled - - desiredNumberScheduled - - numberMisscheduled - - numberReady + exporter: + description: ExporterStatus defines the observed state of Kepler Exporter + properties: + conditions: + description: conditions represent the latest available observations + of the kepler-exporter + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be + when the underlying condition changed. If that is not + known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. + type: string + status: + description: status of the condition, one of True, False, + Unknown. + type: string + type: + description: Type of Kepler Condition - Reconciled, Available + ... + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + currentNumberScheduled: + description: The number of nodes that are running at least 1 kepler + pod and are supposed to run the kepler pod. + format: int32 + type: integer + desiredNumberScheduled: + description: The total number of nodes that should be running + the kepler pod (including nodes correctly running the kepler + pod). + format: int32 + type: integer + numberAvailable: + description: The number of nodes that should be running the kepler + pod and have one or more of the kepler pod running and available + format: int32 + type: integer + numberMisscheduled: + description: The number of nodes that are running the kepler pod, + but are not supposed to run the kepler pod. + format: int32 + type: integer + numberReady: + description: numberReady is the number of nodes that should be + running the kepler pod and have one or more of the kepler pod + running with a Ready Condition. + format: int32 + type: integer + numberUnavailable: + description: The number of nodes that should be running the kepler + pod and have none of the kepler pod running and available + format: int32 + type: integer + updatedNumberScheduled: + description: The total number of nodes that are running updated + kepler pod + format: int32 + type: integer + required: + - conditions + - currentNumberScheduled + - desiredNumberScheduled + - numberMisscheduled + - numberReady + type: object type: object type: object served: true diff --git a/config/crd/bases/kepler.system.sustainable.computing.io_keplerinternals.yaml b/config/crd/bases/kepler.system.sustainable.computing.io_keplerinternals.yaml index 48082b76..b1975c22 100644 --- a/config/crd/bases/kepler.system.sustainable.computing.io_keplerinternals.yaml +++ b/config/crd/bases/kepler.system.sustainable.computing.io_keplerinternals.yaml @@ -18,19 +18,19 @@ spec: - jsonPath: .spec.exporter.deployment.port name: Port type: integer - - jsonPath: .status.desiredNumberScheduled + - jsonPath: .status.exporter.desiredNumberScheduled name: Desired type: integer - - jsonPath: .status.currentNumberScheduled + - jsonPath: .status.exporter.currentNumberScheduled name: Current type: integer - - jsonPath: .status.numberReady - name: Ready - type: integer - jsonPath: .status.updatedNumberScheduled name: Up-to-date type: integer - - jsonPath: .status.numberAvailable + - jsonPath: .status.exporter.numberReady + name: Ready + type: integer + - jsonPath: .status.exporter.numberAvailable name: Available type: integer - jsonPath: .metadata.creationTimestamp @@ -65,15 +65,17 @@ spec: metadata: type: object spec: - description: KeplerInternalSpec defines the desired state of Kepler + description: KeplerInternalSpec defines the desired state of KeplerInternal properties: exporter: properties: deployment: properties: image: + description: Image of kepler-exporter to be deployed type: string namespace: + description: Namespace where kepler-exporter will be deployed type: string nodeSelector: additionalProperties: @@ -151,94 +153,103 @@ spec: type: object type: object status: - description: KeplerStatus defines the observed state of Kepler + description: KeplerInternalStatus represents status of KeplerInternal properties: - conditions: - items: - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. - type: string - status: - description: status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of Kepler Condition - Reconciled, Available - ... - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-type: atomic - currentNumberScheduled: - description: The number of nodes that are running at least 1 kepler - pod and are supposed to run the kepler pod. - format: int32 - type: integer - desiredNumberScheduled: - description: The total number of nodes that should be running the - kepler pod (including nodes correctly running the kepler pod). - format: int32 - type: integer - numberAvailable: - description: The number of nodes that should be running the kepler - pod and have one or more of the kepler pod running and available - format: int32 - type: integer - numberMisscheduled: - description: The number of nodes that are running the kepler pod, - but are not supposed to run the kepler pod. - format: int32 - type: integer - numberReady: - description: numberReady is the number of nodes that should be running - the kepler pod and have one or more of the kepler pod running with - a Ready Condition. - format: int32 - type: integer - numberUnavailable: - description: The number of nodes that should be running the kepler - pod and have none of the kepler pod running and available - format: int32 - type: integer - updatedNumberScheduled: - description: The total number of nodes that are running updated kepler - pod - format: int32 - type: integer - required: - - conditions - - currentNumberScheduled - - desiredNumberScheduled - - numberMisscheduled - - numberReady + exporter: + description: ExporterStatus defines the observed state of Kepler Exporter + properties: + conditions: + description: conditions represent the latest available observations + of the kepler-exporter + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be + when the underlying condition changed. If that is not + known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. + type: string + status: + description: status of the condition, one of True, False, + Unknown. + type: string + type: + description: Type of Kepler Condition - Reconciled, Available + ... + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + currentNumberScheduled: + description: The number of nodes that are running at least 1 kepler + pod and are supposed to run the kepler pod. + format: int32 + type: integer + desiredNumberScheduled: + description: The total number of nodes that should be running + the kepler pod (including nodes correctly running the kepler + pod). + format: int32 + type: integer + numberAvailable: + description: The number of nodes that should be running the kepler + pod and have one or more of the kepler pod running and available + format: int32 + type: integer + numberMisscheduled: + description: The number of nodes that are running the kepler pod, + but are not supposed to run the kepler pod. + format: int32 + type: integer + numberReady: + description: numberReady is the number of nodes that should be + running the kepler pod and have one or more of the kepler pod + running with a Ready Condition. + format: int32 + type: integer + numberUnavailable: + description: The number of nodes that should be running the kepler + pod and have none of the kepler pod running and available + format: int32 + type: integer + updatedNumberScheduled: + description: The total number of nodes that are running updated + kepler pod + format: int32 + type: integer + required: + - conditions + - currentNumberScheduled + - desiredNumberScheduled + - numberMisscheduled + - numberReady + type: object type: object type: object served: true diff --git a/config/crd/bases/kepler.system.sustainable.computing.io_keplers.yaml b/config/crd/bases/kepler.system.sustainable.computing.io_keplers.yaml index a53ac4de..7816020e 100644 --- a/config/crd/bases/kepler.system.sustainable.computing.io_keplers.yaml +++ b/config/crd/bases/kepler.system.sustainable.computing.io_keplers.yaml @@ -18,19 +18,19 @@ spec: - jsonPath: .spec.exporter.deployment.port name: Port type: integer - - jsonPath: .status.desiredNumberScheduled + - jsonPath: .status.exporter.desiredNumberScheduled name: Desired type: integer - - jsonPath: .status.currentNumberScheduled + - jsonPath: .status.exporter.currentNumberScheduled name: Current type: integer - - jsonPath: .status.numberReady + - jsonPath: .status.exporter.numberReady name: Ready type: integer - - jsonPath: .status.updatedNumberScheduled + - jsonPath: .status.exporter.updatedNumberScheduled name: Up-to-date type: integer - - jsonPath: .status.numberAvailable + - jsonPath: .status.exporter.numberAvailable name: Available type: integer - jsonPath: .metadata.creationTimestamp @@ -134,92 +134,101 @@ spec: status: description: KeplerStatus defines the observed state of Kepler properties: - conditions: - items: - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. - type: string - status: - description: status of the condition, one of True, False, Unknown. - type: string - type: - description: Type of Kepler Condition - Reconciled, Available - ... - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - x-kubernetes-list-type: atomic - currentNumberScheduled: - description: The number of nodes that are running at least 1 kepler - pod and are supposed to run the kepler pod. - format: int32 - type: integer - desiredNumberScheduled: - description: The total number of nodes that should be running the - kepler pod (including nodes correctly running the kepler pod). - format: int32 - type: integer - numberAvailable: - description: The number of nodes that should be running the kepler - pod and have one or more of the kepler pod running and available - format: int32 - type: integer - numberMisscheduled: - description: The number of nodes that are running the kepler pod, - but are not supposed to run the kepler pod. - format: int32 - type: integer - numberReady: - description: numberReady is the number of nodes that should be running - the kepler pod and have one or more of the kepler pod running with - a Ready Condition. - format: int32 - type: integer - numberUnavailable: - description: The number of nodes that should be running the kepler - pod and have none of the kepler pod running and available - format: int32 - type: integer - updatedNumberScheduled: - description: The total number of nodes that are running updated kepler - pod - format: int32 - type: integer - required: - - conditions - - currentNumberScheduled - - desiredNumberScheduled - - numberMisscheduled - - numberReady + exporter: + description: ExporterStatus defines the observed state of Kepler Exporter + properties: + conditions: + description: conditions represent the latest available observations + of the kepler-exporter + items: + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be + when the underlying condition changed. If that is not + known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if + .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. + type: string + status: + description: status of the condition, one of True, False, + Unknown. + type: string + type: + description: Type of Kepler Condition - Reconciled, Available + ... + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-type: atomic + currentNumberScheduled: + description: The number of nodes that are running at least 1 kepler + pod and are supposed to run the kepler pod. + format: int32 + type: integer + desiredNumberScheduled: + description: The total number of nodes that should be running + the kepler pod (including nodes correctly running the kepler + pod). + format: int32 + type: integer + numberAvailable: + description: The number of nodes that should be running the kepler + pod and have one or more of the kepler pod running and available + format: int32 + type: integer + numberMisscheduled: + description: The number of nodes that are running the kepler pod, + but are not supposed to run the kepler pod. + format: int32 + type: integer + numberReady: + description: numberReady is the number of nodes that should be + running the kepler pod and have one or more of the kepler pod + running with a Ready Condition. + format: int32 + type: integer + numberUnavailable: + description: The number of nodes that should be running the kepler + pod and have none of the kepler pod running and available + format: int32 + type: integer + updatedNumberScheduled: + description: The total number of nodes that are running updated + kepler pod + format: int32 + type: integer + required: + - conditions + - currentNumberScheduled + - desiredNumberScheduled + - numberMisscheduled + - numberReady + type: object type: object type: object served: true diff --git a/config/manifests/bases/kepler-operator.clusterserviceversion.yaml b/config/manifests/bases/kepler-operator.clusterserviceversion.yaml index 31e2af84..43898527 100644 --- a/config/manifests/bases/kepler-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/kepler-operator.clusterserviceversion.yaml @@ -24,14 +24,23 @@ spec: displayName: KeplerInternal kind: KeplerInternal name: keplerinternals.kepler.system.sustainable.computing.io + statusDescriptors: + - description: conditions represent the latest available observations of the + kepler-exporter + displayName: Conditions + path: exporter.conditions + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:conditions version: v1alpha1 - description: Kepler is the Schema for the keplers API displayName: Kepler kind: Kepler name: keplers.kepler.system.sustainable.computing.io statusDescriptors: - - displayName: Conditions - path: conditions + - description: conditions represent the latest available observations of the + kepler-exporter + displayName: Conditions + path: exporter.conditions x-descriptors: - urn:alm:descriptor:com.tectonic.ui:conditions version: v1alpha1 diff --git a/docs/api.md b/docs/api.md index 84c3e18c..da26e7ec 100644 --- a/docs/api.md +++ b/docs/api.md @@ -55,14 +55,14 @@ KeplerInternal is the Schema for the keplers internal API spec object - KeplerInternalSpec defines the desired state of Kepler
+ KeplerInternalSpec defines the desired state of KeplerInternal
false status object - KeplerStatus defines the observed state of Kepler
+ KeplerInternalStatus represents status of KeplerInternal
false @@ -74,7 +74,7 @@ KeplerInternal is the Schema for the keplers internal API -KeplerInternalSpec defines the desired state of Kepler +KeplerInternalSpec defines the desired state of KeplerInternal @@ -150,14 +150,14 @@ KeplerInternalSpec defines the desired state of Kepler @@ -321,7 +321,34 @@ The pod this Toleration is attached to tolerates any taint that matches the trip -KeplerStatus defines the observed state of Kepler +KeplerInternalStatus represents status of KeplerInternal + +
image string -
+ Image of kepler-exporter to be deployed
false
namespace string -
+ Namespace where kepler-exporter will be deployed
false
+ + + + + + + + + + + + + + +
NameTypeDescriptionRequired
exporterobject + ExporterStatus defines the observed state of Kepler Exporter
+
false
+ + +### KeplerInternal.status.exporter +[↩ Parent](#keplerinternalstatus) + + + +ExporterStatus defines the observed state of Kepler Exporter @@ -333,10 +360,10 @@ KeplerStatus defines the observed state of Kepler - + @@ -406,8 +433,8 @@ KeplerStatus defines the observed state of Kepler
conditionsconditions []object -
+ conditions represent the latest available observations of the kepler-exporter
true
-### KeplerInternal.status.conditions[index] -[↩ Parent](#keplerinternalstatus) +### KeplerInternal.status.exporter.conditions[index] +[↩ Parent](#keplerinternalstatusexporter) @@ -704,10 +731,37 @@ KeplerStatus defines the observed state of Kepler - conditions + exporter + object + + ExporterStatus defines the observed state of Kepler Exporter
+ + false + + + + +### Kepler.status.exporter +[↩ Parent](#keplerstatus) + + + +ExporterStatus defines the observed state of Kepler Exporter + + + + + + + + + + + + @@ -777,8 +831,8 @@ KeplerStatus defines the observed state of Kepler
NameTypeDescriptionRequired
conditions []object -
+ conditions represent the latest available observations of the kepler-exporter
true
-### Kepler.status.conditions[index] -[↩ Parent](#keplerstatus) +### Kepler.status.exporter.conditions[index] +[↩ Parent](#keplerstatusexporter) diff --git a/pkg/api/v1alpha1/kepler_internal_types.go b/pkg/api/v1alpha1/kepler_internal_types.go index 94b67f55..761a0117 100644 --- a/pkg/api/v1alpha1/kepler_internal_types.go +++ b/pkg/api/v1alpha1/kepler_internal_types.go @@ -26,8 +26,10 @@ import ( type InternalExporterDeploymentSpec struct { ExporterDeploymentSpec `json:",inline"` - Image string `json:"image,omitempty"` - Namespace string `json:"namespace,omitempty"` + // Image of kepler-exporter to be deployed + Image string `json:"image,omitempty"` + // Namespace where kepler-exporter will be deployed + Namespace string `json:"namespace,omitempty"` } type InternalExporterSpec struct { @@ -36,16 +38,16 @@ type InternalExporterSpec struct { type DashboardSpec struct { // +kubebuilder:default=false - Enabled *bool `json:"enabled,omitempty"` + Enabled bool `json:"enabled,omitempty"` } type OpenShiftSpec struct { // +kubebuilder:default=false - Enabled *bool `json:"enabled,omitempty"` + Enabled bool `json:"enabled,omitempty"` Dashboard DashboardSpec `json:"dashboard,omitempty"` } -// KeplerInternalSpec defines the desired state of Kepler +// KeplerInternalSpec defines the desired state of KeplerInternal type KeplerInternalSpec struct { Exporter InternalExporterSpec `json:"exporter,omitempty"` OpenShift OpenShiftSpec `json:"openshift,omitempty"` @@ -56,11 +58,11 @@ type KeplerInternalSpec struct { //+kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Port",type=integer,JSONPath=`.spec.exporter.deployment.port` -// +kubebuilder:printcolumn:name="Desired",type=integer,JSONPath=`.status.desiredNumberScheduled` -// +kubebuilder:printcolumn:name="Current",type=integer,JSONPath=`.status.currentNumberScheduled` -// +kubebuilder:printcolumn:name="Ready",type=integer,JSONPath=`.status.numberReady` +// +kubebuilder:printcolumn:name="Desired",type=integer,JSONPath=`.status.exporter.desiredNumberScheduled` +// +kubebuilder:printcolumn:name="Current",type=integer,JSONPath=`.status.exporter.currentNumberScheduled` // +kubebuilder:printcolumn:name="Up-to-date",type=integer,JSONPath=`.status.updatedNumberScheduled` -// +kubebuilder:printcolumn:name="Available",type=integer,JSONPath=`.status.numberAvailable` +// +kubebuilder:printcolumn:name="Ready",type=integer,JSONPath=`.status.exporter.numberReady` +// +kubebuilder:printcolumn:name="Available",type=integer,JSONPath=`.status.exporter.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 @@ -71,8 +73,13 @@ type KeplerInternal struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec KeplerInternalSpec `json:"spec,omitempty"` - Status KeplerStatus `json:"status,omitempty"` + Spec KeplerInternalSpec `json:"spec,omitempty"` + Status KeplerInternalStatus `json:"status,omitempty"` +} + +// KeplerInternalStatus represents status of KeplerInternal +type KeplerInternalStatus struct { + Exporter ExporterStatus `json:"exporter,omitempty"` } // returns namespace specified in the spec diff --git a/pkg/api/v1alpha1/kepler_types.go b/pkg/api/v1alpha1/kepler_types.go index e9259e1e..41ec8e3a 100644 --- a/pkg/api/v1alpha1/kepler_types.go +++ b/pkg/api/v1alpha1/kepler_types.go @@ -121,8 +121,8 @@ type Condition struct { Message string `json:"message"` } -// KeplerStatus defines the observed state of Kepler -type KeplerStatus struct { +// ExporterStatus defines the observed state of Kepler Exporter +type ExporterStatus struct { // The number of nodes that are running at least 1 kepler pod and are // supposed to run the kepler pod. CurrentNumberScheduled int32 `json:"currentNumberScheduled"` @@ -153,8 +153,7 @@ type KeplerStatus struct { // +optional NumberUnavailable int32 `json:"numberUnavailable,omitempty"` - // conditions represent the latest available observations of the kepler-system - + // conditions represent the latest available observations of the kepler-exporter // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:com.tectonic.ui:conditions" // +listType=atomic Conditions []Condition `json:"conditions"` @@ -165,11 +164,11 @@ type KeplerStatus struct { //+kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Port",type=integer,JSONPath=`.spec.exporter.deployment.port` -// +kubebuilder:printcolumn:name="Desired",type=integer,JSONPath=`.status.desiredNumberScheduled` -// +kubebuilder:printcolumn:name="Current",type=integer,JSONPath=`.status.currentNumberScheduled` -// +kubebuilder:printcolumn:name="Ready",type=integer,JSONPath=`.status.numberReady` -// +kubebuilder:printcolumn:name="Up-to-date",type=integer,JSONPath=`.status.updatedNumberScheduled` -// +kubebuilder:printcolumn:name="Available",type=integer,JSONPath=`.status.numberAvailable` +// +kubebuilder:printcolumn:name="Desired",type=integer,JSONPath=`.status.exporter.desiredNumberScheduled` +// +kubebuilder:printcolumn:name="Current",type=integer,JSONPath=`.status.exporter.currentNumberScheduled` +// +kubebuilder:printcolumn:name="Ready",type=integer,JSONPath=`.status.exporter.numberReady` +// +kubebuilder:printcolumn:name="Up-to-date",type=integer,JSONPath=`.status.exporter.updatedNumberScheduled` +// +kubebuilder:printcolumn:name="Available",type=integer,JSONPath=`.status.exporter.numberAvailable` // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // +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 @@ -183,6 +182,11 @@ type Kepler struct { Status KeplerStatus `json:"status,omitempty"` } +// KeplerStatus defines the observed state of Kepler +type KeplerStatus struct { + Exporter ExporterStatus `json:"exporter,omitempty"` +} + //+kubebuilder:object:root=true // KeplerList contains a list of Kepler diff --git a/pkg/api/v1alpha1/zz_generated.deepcopy.go b/pkg/api/v1alpha1/zz_generated.deepcopy.go index 4f0c8d1e..8fe6e8de 100644 --- a/pkg/api/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/v1alpha1/zz_generated.deepcopy.go @@ -45,11 +45,6 @@ func (in *Condition) DeepCopy() *Condition { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DashboardSpec) DeepCopyInto(out *DashboardSpec) { *out = *in - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled - *out = new(bool) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardSpec. @@ -107,6 +102,28 @@ func (in *ExporterSpec) DeepCopy() *ExporterSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExporterStatus) DeepCopyInto(out *ExporterStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExporterStatus. +func (in *ExporterStatus) DeepCopy() *ExporterStatus { + if in == nil { + return nil + } + out := new(ExporterStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InternalExporterDeploymentSpec) DeepCopyInto(out *InternalExporterDeploymentSpec) { *out = *in @@ -229,7 +246,7 @@ func (in *KeplerInternalList) DeepCopyObject() runtime.Object { func (in *KeplerInternalSpec) DeepCopyInto(out *KeplerInternalSpec) { *out = *in in.Exporter.DeepCopyInto(&out.Exporter) - in.OpenShift.DeepCopyInto(&out.OpenShift) + out.OpenShift = in.OpenShift } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeplerInternalSpec. @@ -242,6 +259,22 @@ func (in *KeplerInternalSpec) DeepCopy() *KeplerInternalSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeplerInternalStatus) DeepCopyInto(out *KeplerInternalStatus) { + *out = *in + in.Exporter.DeepCopyInto(&out.Exporter) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeplerInternalStatus. +func (in *KeplerInternalStatus) DeepCopy() *KeplerInternalStatus { + if in == nil { + return nil + } + out := new(KeplerInternalStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeplerList) DeepCopyInto(out *KeplerList) { *out = *in @@ -293,13 +326,7 @@ func (in *KeplerSpec) DeepCopy() *KeplerSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeplerStatus) DeepCopyInto(out *KeplerStatus) { *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + in.Exporter.DeepCopyInto(&out.Exporter) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeplerStatus. @@ -315,12 +342,7 @@ func (in *KeplerStatus) DeepCopy() *KeplerStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenShiftSpec) DeepCopyInto(out *OpenShiftSpec) { *out = *in - if in.Enabled != nil { - in, out := &in.Enabled, &out.Enabled - *out = new(bool) - **out = **in - } - in.Dashboard.DeepCopyInto(&out.Dashboard) + out.Dashboard = in.Dashboard } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenShiftSpec. diff --git a/pkg/components/components.go b/pkg/components/components.go index 2f0949cc..b4a34ffd 100644 --- a/pkg/components/components.go +++ b/pkg/components/components.go @@ -32,7 +32,6 @@ const ( var ( CommonLabels = k8s.StringMap{ "app.kubernetes.io/managed-by": "kepler-operator", - "app.kubernetes.io/part-of": "kepler", } ) diff --git a/pkg/components/exporter/exporter.go b/pkg/components/exporter/exporter.go index d883ce50..46d15668 100644 --- a/pkg/components/exporter/exporter.go +++ b/pkg/components/exporter/exporter.go @@ -18,6 +18,7 @@ package exporter import ( _ "embed" + "fmt" "strconv" "github.com/sustainable.computing.io/kepler-operator/pkg/api/v1alpha1" @@ -44,15 +45,6 @@ const ( ) var ( - labels = components.CommonLabels.Merge(k8s.StringMap{ - "app.kubernetes.io/component": "exporter", - "sustainable-computing.io/app": "kepler", - }) - - podSelector = labels.Merge(k8s.StringMap{ - "app.kubernetes.io/name": "kepler-exporter", - }) - linuxNodeSelector = k8s.StringMap{ "kubernetes.io/os": "linux", } @@ -64,6 +56,7 @@ var ( nsInfoDashboardJson string ) +// TODO: func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1.DaemonSet { if detail == components.Metadata { return &appsv1.DaemonSet{ @@ -74,7 +67,7 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1. ObjectMeta: metav1.ObjectMeta{ Name: k.DaemonsetName(), Namespace: k.Namespace(), - Labels: labels, + Labels: labels(k), }, } } @@ -84,6 +77,10 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1. nodeSelector := deployment.NodeSelector tolerations := deployment.Tolerations port := deployment.Port + // NOTE: since 2 or more KeplerInternals can be deployed to the same namespace, + // we need to make sure that the pod selector of each of the DaemonSet + // create of each kepler is unique. Thus the daemonset name is added as + // label to the pod bindAddress := "0.0.0.0:" + strconv.Itoa(int(port)) @@ -95,15 +92,15 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1. ObjectMeta: metav1.ObjectMeta{ Name: k.Name, Namespace: k.Namespace(), - Labels: labels, + Labels: labels(k), }, Spec: appsv1.DaemonSetSpec{ - Selector: &metav1.LabelSelector{MatchLabels: podSelector}, + Selector: &metav1.LabelSelector{MatchLabels: podSelector(k)}, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: k.DaemonsetName(), Namespace: k.Namespace(), - Labels: podSelector, + Labels: podSelector(k), }, Spec: corev1.PodSpec{ HostPID: true, @@ -167,14 +164,13 @@ func NewDaemonSet(detail components.Detail, k *v1alpha1.KeplerInternal) *appsv1. }, // PodTemplateSpec }, // Spec } - } func openshiftDashboardObjectMeta(name string) metav1.ObjectMeta { return metav1.ObjectMeta{ Name: name, Namespace: DashboardNs, - Labels: labels.Merge(k8s.StringMap{ + Labels: components.CommonLabels.Merge(k8s.StringMap{ "console.openshift.io/dashboard": "true", }), Annotations: k8s.StringMap{ @@ -244,7 +240,7 @@ func NewConfigMap(d components.Detail, k *v1alpha1.KeplerInternal) *corev1.Confi ObjectMeta: metav1.ObjectMeta{ Name: k.Name, Namespace: k.Namespace(), - Labels: labels, + Labels: labels(k).ToMap(), }, } } @@ -260,7 +256,7 @@ func NewConfigMap(d components.Detail, k *v1alpha1.KeplerInternal) *corev1.Confi ObjectMeta: metav1.ObjectMeta{ Name: k.Name, Namespace: k.Namespace(), - Labels: labels, + Labels: labels(k).ToMap(), }, Data: map[string]string{ "KEPLER_NAMESPACE": k.Namespace(), @@ -293,7 +289,7 @@ func NewClusterRole(c components.Detail, k *v1alpha1.KeplerInternal) *rbacv1.Clu }, ObjectMeta: metav1.ObjectMeta{ Name: k.Name, - Labels: labels, + Labels: labels(k), }, } } @@ -305,7 +301,7 @@ func NewClusterRole(c components.Detail, k *v1alpha1.KeplerInternal) *rbacv1.Clu }, ObjectMeta: metav1.ObjectMeta{ Name: k.Name, - Labels: labels, + Labels: labels(k), }, Rules: []rbacv1.PolicyRule{{ APIGroups: []string{""}, @@ -324,7 +320,7 @@ func NewClusterRoleBinding(c components.Detail, k *v1alpha1.KeplerInternal) *rba }, ObjectMeta: metav1.ObjectMeta{ Name: k.Name, - Labels: labels, + Labels: labels(k), }, } } @@ -336,7 +332,7 @@ func NewClusterRoleBinding(c components.Detail, k *v1alpha1.KeplerInternal) *rba }, ObjectMeta: metav1.ObjectMeta{ Name: k.Name, - Labels: labels, + Labels: labels(k), }, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", @@ -361,7 +357,7 @@ func NewSCC(d components.Detail, ki *v1alpha1.KeplerInternal) *secv1.SecurityCon ObjectMeta: metav1.ObjectMeta{ Name: ki.Name, - Labels: labels, + Labels: labels(ki), }, } } @@ -374,7 +370,7 @@ func NewSCC(d components.Detail, ki *v1alpha1.KeplerInternal) *secv1.SecurityCon ObjectMeta: metav1.ObjectMeta{ Name: ki.Name, - Labels: labels, + Labels: labels(ki), }, AllowPrivilegedContainer: true, @@ -413,7 +409,7 @@ func NewServiceAccount(ki *v1alpha1.KeplerInternal) *corev1.ServiceAccount { ObjectMeta: metav1.ObjectMeta{ Name: ki.Name, Namespace: ki.Namespace(), - Labels: labels, + Labels: labels(ki).ToMap(), }, } } @@ -429,12 +425,12 @@ func NewService(k *v1alpha1.KeplerInternal) *corev1.Service { ObjectMeta: metav1.ObjectMeta{ Name: k.Name, Namespace: k.Namespace(), - Labels: labels, + Labels: labels(k).ToMap(), }, Spec: corev1.ServiceSpec{ ClusterIP: "None", - Selector: podSelector, + Selector: podSelector(k), Ports: []corev1.ServicePort{{ Name: ServicePortName, Port: int32(deployment.Port), @@ -466,7 +462,7 @@ func NewServiceMonitor(k *v1alpha1.KeplerInternal) *monv1.ServiceMonitor { ObjectMeta: metav1.ObjectMeta{ Name: k.Name, Namespace: k.Namespace(), - Labels: labels, + Labels: labels(k).ToMap(), }, Spec: monv1.ServiceMonitorSpec{ Endpoints: []monv1.Endpoint{{ @@ -477,7 +473,7 @@ func NewServiceMonitor(k *v1alpha1.KeplerInternal) *monv1.ServiceMonitor { }}, JobLabel: "app.kubernetes.io/name", Selector: metav1.LabelSelector{ - MatchLabels: labels, + MatchLabels: labels(k), }, }, } @@ -485,6 +481,7 @@ func NewServiceMonitor(k *v1alpha1.KeplerInternal) *monv1.ServiceMonitor { func NewPrometheusRule(k *v1alpha1.KeplerInternal) *monv1.PrometheusRule { interval := monv1.Duration("15s") + ns := k.Namespace() return &monv1.PrometheusRule{ TypeMeta: metav1.TypeMeta{ @@ -493,8 +490,8 @@ func NewPrometheusRule(k *v1alpha1.KeplerInternal) *monv1.PrometheusRule { }, ObjectMeta: metav1.ObjectMeta{ Name: k.Name, - Namespace: k.Namespace(), - Labels: labels, + Namespace: ns, + Labels: labels(k).ToMap(), }, Spec: monv1.PrometheusRuleSpec{ Groups: []monv1.RuleGroup{{ @@ -502,63 +499,63 @@ func NewPrometheusRule(k *v1alpha1.KeplerInternal) *monv1.PrometheusRule { Interval: &interval, Rules: []monv1.Rule{ record("kepler:container_joules_total:consumed:24h:all", - `sum( - increase(kepler_container_joules_total[24h:1m]) - )`, + fmt.Sprintf(`sum( + increase(kepler_container_joules_total{namespace=%q}[24h:1m]) + )`, ns), ), record("kepler:container_joules_total:consumed:24h:by_ns", - `sum by (container_namespace) ( - increase(kepler_container_joules_total[24h:1m]) - )`, + fmt.Sprintf(`sum by (container_namespace) ( + increase(kepler_container_joules_total{namespace=%q}[24h:1m]) + )`, ns), ), record("kepler:container_gpu_joules_total:consumed:1h:by_ns", - `sum by (container_namespace) ( - increase(kepler_container_gpu_joules_total[1h:15s]) - )`, + fmt.Sprintf(`sum by (container_namespace) ( + increase(kepler_container_gpu_joules_total{namespace=%q}[1h:15s]) + )`, ns), ), record("kepler:container_dram_joules_total:consumed:1h:by_ns", - `sum by (container_namespace) ( - increase(kepler_container_dram_joules_total[1h:15s]) - )`, + fmt.Sprintf(`sum by (container_namespace) ( + increase(kepler_container_dram_joules_total{namespace=%q}[1h:15s]) + )`, ns), ), record("kepler:container_package_joules_total:consumed:1h:by_ns", - `sum by (container_namespace) ( - increase(kepler_container_package_joules_total[1h:15s]) - )`, + fmt.Sprintf(`sum by (container_namespace) ( + increase(kepler_container_package_joules_total{namespace=%q}[1h:15s]) + )`, ns), ), record("kepler:container_other_joules_total:consumed:1h:by_ns", - `sum by (container_namespace) ( - increase(kepler_container_other_joules_total[1h:15s]) - )`, + fmt.Sprintf(`sum by (container_namespace) ( + increase(kepler_container_other_joules_total{namespace=%q}[1h:15s]) + )`, ns), ), // irate of joules = joules per second -> watts record("kepler:container_gpu_watts:1m:by_ns_pod", - `sum by (container_namespace, pod_name) ( - irate(kepler_container_gpu_joules_total[1m]) - )`, + fmt.Sprintf(`sum by (container_namespace, pod_name) ( + irate(kepler_container_gpu_joules_total{namespace=%q}[1m]) + )`, ns), ), record("kepler:container_package_watts:1m:by_ns_pod", - `sum by (container_namespace, pod_name) ( - irate(kepler_container_package_joules_total[1m]) - )`, + fmt.Sprintf(`sum by (container_namespace, pod_name) ( + irate(kepler_container_package_joules_total{namespace=%q}[1m]) + )`, ns), ), record("kepler:container_other_watts:1m:by_ns_pod", - `sum by (container_namespace, pod_name) ( - irate(kepler_container_other_joules_total[1m]) - )`, + fmt.Sprintf(`sum by (container_namespace, pod_name) ( + irate(kepler_container_other_joules_total{namespace=%q}[1m]) + )`, ns), ), record("kepler:container_dram_watts:1m:by_ns_pod", - `sum by (container_namespace, pod_name) ( - irate(kepler_container_dram_joules_total[1m]) - )`, + fmt.Sprintf(`sum by (container_namespace, pod_name) ( + irate(kepler_container_dram_joules_total{namespace=%q}[1m]) + )`, ns), ), }, }}, @@ -572,3 +569,17 @@ func record(name, expr string) monv1.Rule { Record: name, } } + +func podSelector(ki *v1alpha1.KeplerInternal) k8s.StringMap { + return labels(ki).Merge(k8s.StringMap{ + "app.kubernetes.io/name": "kepler-exporter", + }) +} + +func labels(ki *v1alpha1.KeplerInternal) k8s.StringMap { + return components.CommonLabels.Merge(k8s.StringMap{ + "app.kubernetes.io/component": "exporter", + "operator.sustainable-computing.io/internal": ki.Name, + "app.kubernetes.io/part-of": ki.Name, + }) +} diff --git a/pkg/controllers/kepler.go b/pkg/controllers/kepler.go index ed653e60..0609321b 100644 --- a/pkg/controllers/kepler.go +++ b/pkg/controllers/kepler.go @@ -143,9 +143,11 @@ func (r KeplerReconciler) updateStatus(ctx context.Context, req ctrl.Request, re // NOTE: although, this copies the internal status, the observed generation // should be set to kepler's current generation to indicate that the // current generation has been "observed" - k.Status = internal.Status - for i := range k.Status.Conditions { - k.Status.Conditions[i].ObservedGeneration = k.Generation + k.Status = v1alpha1.KeplerStatus{ + Exporter: internal.Status.Exporter, + } + for i := range k.Status.Exporter.Conditions { + k.Status.Exporter.Conditions[i].ObservedGeneration = k.Generation } return r.Client.Status().Update(ctx, k) }) @@ -154,8 +156,8 @@ func (r KeplerReconciler) updateStatus(ctx context.Context, req ctrl.Request, re // returns true (i.e. status has changed ) if any of the Conditions' // ObservedGeneration is equal to the current generation func hasInternalStatusChanged(internal *v1alpha1.KeplerInternal) bool { - for i := range internal.Status.Conditions { - if internal.Status.Conditions[i].ObservedGeneration == internal.Generation { + for i := range internal.Status.Exporter.Conditions { + if internal.Status.Exporter.Conditions[i].ObservedGeneration == internal.Generation { return true } } @@ -221,7 +223,7 @@ func (r KeplerReconciler) setInvalidStatus(ctx context.Context, req ctrl.Request return nil } - invalidKepler.Status.Conditions = []v1alpha1.Condition{{ + invalidKepler.Status.Exporter.Conditions = []v1alpha1.Condition{{ Type: v1alpha1.Reconciled, Status: v1alpha1.ConditionFalse, ObservedGeneration: invalidKepler.Generation, @@ -266,29 +268,10 @@ func newKeplerInternal(d components.Detail, k *v1alpha1.Kepler) *v1alpha1.Kepler isOpenShift := Config.Cluster == k8s.OpenShift return &v1alpha1.KeplerInternal{ - TypeMeta: metav1.TypeMeta{ - Kind: "KeplerInternal", - APIVersion: v1alpha1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: k.Name, - Annotations: k.Annotations, - }, - Spec: v1alpha1.KeplerInternalSpec{ - Exporter: v1alpha1.InternalExporterSpec{ - Deployment: v1alpha1.InternalExporterDeploymentSpec{ - ExporterDeploymentSpec: k.Spec.Exporter.Deployment, - Image: keplerImage, - Namespace: KeplerDeploymentNS, - }, - }, - OpenShift: v1alpha1.OpenShiftSpec{ - Enabled: &isOpenShift, - Dashboard: v1alpha1.DashboardSpec{ - Enabled: &isOpenShift, - }, - }, - }, + TypeMeta: metav1.TypeMeta{Kind: "KeplerInternal", APIVersion: v1alpha1.GroupVersion.String()}, + ObjectMeta: metav1.ObjectMeta{Name: k.Name, Annotations: k.Annotations}, + Spec: v1alpha1.KeplerInternalSpec{Exporter: v1alpha1.InternalExporterSpec{Deployment: v1alpha1.InternalExporterDeploymentSpec{ExporterDeploymentSpec: k.Spec.Exporter.Deployment, Image: keplerImage, Namespace: KeplerDeploymentNS}}, OpenShift: v1alpha1.OpenShiftSpec{Enabled: isOpenShift, Dashboard: v1alpha1.DashboardSpec{Enabled: isOpenShift}}}, + Status: v1alpha1.KeplerInternalStatus{}, } } diff --git a/pkg/controllers/kepler_internal.go b/pkg/controllers/kepler_internal.go index e10c1ccb..fb09b0a4 100644 --- a/pkg/controllers/kepler_internal.go +++ b/pkg/controllers/kepler_internal.go @@ -89,32 +89,28 @@ func (r *KeplerInternalReconciler) SetupWithManager(mgr ctrl.Manager) error { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile func (r *KeplerInternalReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - // TODO: remove these keys from the log - // "controller": "kepler", "controllerGroup": "kepler.system.sustainable.computing.io", - // "controllerKind": "Kepler", "Kepler": {"name":"kepler"}, - logger := log.FromContext(ctx) r.logger = logger logger.Info("Start of reconcile") defer logger.Info("End of reconcile") - kepler, err := r.getInternal(ctx, req) + ki, err := r.getInternal(ctx, req) if err != nil { // retry since some error has occurred logger.V(6).Info("Get Error ", "error", err) return ctrl.Result{}, err } - if kepler == nil { - // no kepler found , so stop here + if ki == nil { + // no kepler-internal found , so stop here logger.V(6).Info("Kepler Nil") return ctrl.Result{}, nil } - logger.V(6).Info("Running sub reconcilers", "kepler", kepler.Spec) + logger.V(6).Info("Running sub reconcilers", "kepler-internal", ki.Spec) - result, recErr := r.runReconcilers(ctx, kepler) + result, recErr := r.runReconcilers(ctx, ki) updateErr := r.updateStatus(ctx, req, err) if recErr != nil { @@ -163,16 +159,17 @@ func (r KeplerInternalReconciler) updateStatus(ctx context.Context, req ctrl.Req return nil } - // TODO: move to using KeplerInternalStatus - ki.Status = v1alpha1.KeplerStatus{ - Conditions: []v1alpha1.Condition{}, + ki.Status = v1alpha1.KeplerInternalStatus{ + Exporter: v1alpha1.ExporterStatus{ + Conditions: []v1alpha1.Condition{}, + }, } r.updateReconciledStatus(ctx, ki, recErr) r.updateAvailableStatus(ctx, ki, recErr) now := metav1.Now() - for i := range ki.Status.Conditions { - ki.Status.Conditions[i].LastTransitionTime = now + for i := range ki.Status.Exporter.Conditions { + ki.Status.Exporter.Conditions[i].LastTransitionTime = now } return r.Client.Status().Update(ctx, ki) @@ -196,7 +193,7 @@ func (r KeplerInternalReconciler) updateReconciledStatus(ctx context.Context, ki reconciled.Message = recErr.Error() } - ki.Status.Conditions = append(ki.Status.Conditions, reconciled) + ki.Status.Exporter.Conditions = append(ki.Status.Exporter.Conditions, reconciled) } func (r KeplerInternalReconciler) updateAvailableStatus(ctx context.Context, ki *v1alpha1.KeplerInternal, recErr error) { @@ -204,24 +201,24 @@ func (r KeplerInternalReconciler) updateAvailableStatus(ctx context.Context, ki dset := appsv1.DaemonSet{} key := types.NamespacedName{Name: ki.DaemonsetName(), Namespace: ki.Namespace()} if err := r.Client.Get(ctx, key, &dset); err != nil { - ki.Status.Conditions = append(ki.Status.Conditions, availableConditionForGetError(err)) + ki.Status.Exporter.Conditions = append(ki.Status.Exporter.Conditions, availableConditionForGetError(err)) return } ds := dset.Status - ki.Status.NumberMisscheduled = ds.NumberMisscheduled - ki.Status.CurrentNumberScheduled = ds.CurrentNumberScheduled - ki.Status.DesiredNumberScheduled = ds.DesiredNumberScheduled - ki.Status.NumberReady = ds.NumberReady - ki.Status.UpdatedNumberScheduled = ds.UpdatedNumberScheduled - ki.Status.NumberAvailable = ds.NumberAvailable - ki.Status.NumberUnavailable = ds.NumberUnavailable + ki.Status.Exporter.NumberMisscheduled = ds.NumberMisscheduled + ki.Status.Exporter.CurrentNumberScheduled = ds.CurrentNumberScheduled + ki.Status.Exporter.DesiredNumberScheduled = ds.DesiredNumberScheduled + ki.Status.Exporter.NumberReady = ds.NumberReady + ki.Status.Exporter.UpdatedNumberScheduled = ds.UpdatedNumberScheduled + ki.Status.Exporter.NumberAvailable = ds.NumberAvailable + ki.Status.Exporter.NumberUnavailable = ds.NumberUnavailable c := availableCondition(&dset) if recErr == nil { c.ObservedGeneration = ki.Generation } - ki.Status.Conditions = append(ki.Status.Conditions, c) + ki.Status.Exporter.Conditions = append(ki.Status.Exporter.Conditions, c) } func availableConditionForGetError(err error) v1alpha1.Condition { @@ -386,14 +383,14 @@ func exporterReconcilers(ki *v1alpha1.KeplerInternal, cluster k8s.Cluster) []rec func openshiftResources(ki *v1alpha1.KeplerInternal, cluster k8s.Cluster) []client.Object { oshift := ki.Spec.OpenShift - if cluster != k8s.OpenShift || !*oshift.Enabled { + if cluster != k8s.OpenShift || !oshift.Enabled { return nil } // cluster-scoped resources first res := []client.Object{ exporter.NewSCC(components.Full, ki), } - if *oshift.Dashboard.Enabled { + if oshift.Dashboard.Enabled { res = append(res, exporter.NewOverviewDashboard(components.Full), exporter.NewNamespaceInfoDashboard(components.Full), diff --git a/pkg/controllers/kepler_test.go b/pkg/controllers/kepler_test.go index e0be0cbc..f98c48a0 100644 --- a/pkg/controllers/kepler_test.go +++ b/pkg/controllers/kepler_test.go @@ -1,3 +1,18 @@ +/* +Copyright 2023. + +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 controllers import ( diff --git a/pkg/utils/test/framework.go b/pkg/utils/test/framework.go index 5779a042..0f8b2504 100644 --- a/pkg/utils/test/framework.go +++ b/pkg/utils/test/framework.go @@ -189,7 +189,7 @@ func (f Framework) WaitUntilKeplerCondition(name string, t v1alpha1.ConditionTyp return true, fmt.Errorf("kepler %s is not found", name) } - condition, _ := k8s.FindCondition(k.Status.Conditions, t) + condition, _ := k8s.FindCondition(k.Status.Exporter.Conditions, t) return condition.Status == s, nil }) return &k diff --git a/tests/e2e/kepler_test.go b/tests/e2e/kepler_test.go index 2199ab54..d6e616af 100644 --- a/tests/e2e/kepler_test.go +++ b/tests/e2e/kepler_test.go @@ -56,13 +56,13 @@ func TestKepler_Reconciliation(t *testing.T) { // ensure the default toleration is set assert.Equal(t, []corev1.Toleration{{Operator: "Exists"}}, kepler.Spec.Exporter.Deployment.Tolerations) - reconciled, err := k8s.FindCondition(kepler.Status.Conditions, v1alpha1.Reconciled) + reconciled, err := k8s.FindCondition(kepler.Status.Exporter.Conditions, v1alpha1.Reconciled) assert.NoError(t, err, "unable to get reconciled condition") assert.Equal(t, reconciled.ObservedGeneration, kepler.Generation) assert.Equal(t, reconciled.Status, v1alpha1.ConditionTrue) kepler = f.WaitUntilKeplerCondition("kepler", v1alpha1.Available, v1alpha1.ConditionTrue) - available, err := k8s.FindCondition(kepler.Status.Conditions, v1alpha1.Available) + available, err := k8s.FindCondition(kepler.Status.Exporter.Conditions, v1alpha1.Available) assert.NoError(t, err, "unable to get available condition") assert.Equal(t, available.ObservedGeneration, kepler.Generation) assert.Equal(t, available.Status, v1alpha1.ConditionTrue) @@ -99,7 +99,7 @@ func TestNodeSelector(t *testing.T) { f.AssertResourceExists(k.Name, controllers.KeplerDeploymentNS, &ds) kepler := f.WaitUntilKeplerCondition("kepler", v1alpha1.Available, v1alpha1.ConditionTrue) - assert.EqualValues(t, 1, kepler.Status.NumberAvailable) + assert.EqualValues(t, 1, kepler.Status.Exporter.NumberAvailable) f.DeleteKepler("kepler") @@ -124,7 +124,7 @@ func TestNodeSelectorUnavailableLabel(t *testing.T) { f.AssertResourceExists(k.Name, controllers.KeplerDeploymentNS, &ds) kepler := f.WaitUntilKeplerCondition("kepler", v1alpha1.Available, v1alpha1.ConditionFalse) - assert.EqualValues(t, 0, kepler.Status.NumberAvailable) + assert.EqualValues(t, 0, kepler.Status.Exporter.NumberAvailable) f.DeleteKepler("kepler") @@ -158,7 +158,7 @@ func TestTaint_WithToleration(t *testing.T) { f.AssertResourceExists(k.Name, controllers.KeplerDeploymentNS, &ds) kepler := f.WaitUntilKeplerCondition("kepler", v1alpha1.Available, v1alpha1.ConditionTrue) - assert.EqualValues(t, len(nodes), kepler.Status.NumberAvailable) + assert.EqualValues(t, len(nodes), kepler.Status.Exporter.NumberAvailable) f.DeleteKepler("kepler") @@ -196,7 +196,7 @@ func TestBadTaint_WithToleration(t *testing.T) { f.AssertResourceExists(k.Name, controllers.KeplerDeploymentNS, &ds) kepler := f.WaitUntilKeplerCondition("kepler", v1alpha1.Available, v1alpha1.ConditionTrue) - assert.EqualValues(t, len(nodes)-1, kepler.Status.NumberAvailable) + assert.EqualValues(t, len(nodes)-1, kepler.Status.Exporter.NumberAvailable) f.DeleteKepler("kepler")