diff --git a/Makefile b/Makefile index b00c4d5d..80909bb3 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ undeploy: # Generate manifests e.g. CRD, RBAC etc. manifests: controller-gen - $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=controller-role webhook paths=./pkg/apis/v2beta1 paths=./pkg/apis/v2beta2 output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=controller-role webhook paths=./pkg/apis/v2beta1 paths=./pkg/apis/v2beta2 paths=./controllers output:crd:artifacts:config=config/crd/bases cd config/manager && kustomize edit set image controller=${IMG} && cd ../../ kustomize build config/default | sed -e '/creationTimestamp/d' > config/bundle.yaml kustomize build config/samples | sed -e '/creationTimestamp/d' > config/samples/bundle.yaml diff --git a/adapter/deploy/yaml/adapter.yaml b/adapter/deploy/yaml/adapter.yaml index a56c5407..dc63214f 100644 --- a/adapter/deploy/yaml/adapter.yaml +++ b/adapter/deploy/yaml/adapter.yaml @@ -19,10 +19,9 @@ spec: args: - --with-stdout=true imagePullPolicy: Always - volumeMounts: - - mountPath: /etc/localtime - name: host-time - readOnly: true + env: + - name: TZ + value: GMT lifecycle: preStop: httpGet: @@ -48,12 +47,6 @@ spec: requests: cpu: 20m memory: 50Mi - volumes: - - hostPath: - path: /etc/localtime - type: "" - name: host-time - --- apiVersion: v1 kind: Service diff --git a/adapter/test/samples/socket.yaml b/adapter/test/samples/socket.yaml index c61bc85f..cb799d9b 100644 --- a/adapter/test/samples/socket.yaml +++ b/adapter/test/samples/socket.yaml @@ -19,16 +19,12 @@ spec: command: - socket-server imagePullPolicy: Always - volumeMounts: - - mountPath: /etc/localtime - name: host-time - readOnly: true - volumes: - - hostPath: - path: /etc/localtime - type: "" - name: host-time - + env: + - name: NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace --- apiVersion: v1 kind: Service diff --git a/config/bundle.yaml b/config/bundle.yaml index 5a62ec98..be5dd074 100644 --- a/config/bundle.yaml +++ b/config/bundle.yaml @@ -4808,6 +4808,109 @@ spec: description: The default namespace to which notification manager secrets belong. type: string + env: + description: List of environment variable + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using + the previous defined environment variables in the container + and any service environment variables. If a variable cannot + be resolved, the reference in the input string will be unchanged. + The $(VAR_NAME) syntax can be escaped with a double $$, ie: + $$(VAR_NAME). Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, + status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array groupLabels: description: Labels for grouping notifiations. items: @@ -10924,12 +11027,19 @@ rules: - apiGroups: - "" resources: - - secrets - configmaps verbs: - get - list - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -10958,6 +11068,12 @@ rules: - patch - update - watch +- apiGroups: + - notification.kubesphere.io + resources: + - notificationmanagers/finalizers + verbs: + - update - apiGroups: - notification.kubesphere.io resources: @@ -11127,9 +11243,6 @@ spec: - mountPath: /tmp/k8s-webhook-server/serving-certs name: cert readOnly: true - - mountPath: /etc/localtime - name: host-time - readOnly: true - args: - --secure-listen-address=0.0.0.0:8443 - --upstream=http://127.0.0.1:8080/ @@ -11147,10 +11260,6 @@ spec: secret: defaultMode: 420 secretName: notification-manager-webhook-server-cert - - hostPath: - path: /etc/localtime - type: "" - name: host-time --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration diff --git a/config/crd/bases/notification.kubesphere.io_notificationmanagers.yaml b/config/crd/bases/notification.kubesphere.io_notificationmanagers.yaml index f3166130..8d19b11d 100644 --- a/config/crd/bases/notification.kubesphere.io_notificationmanagers.yaml +++ b/config/crd/bases/notification.kubesphere.io_notificationmanagers.yaml @@ -3668,6 +3668,109 @@ spec: description: The default namespace to which notification manager secrets belong. type: string + env: + description: List of environment variable + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using + the previous defined environment variables in the container + and any service environment variables. If a variable cannot + be resolved, the reference in the input string will be unchanged. + The $(VAR_NAME) syntax can be escaped with a double $$, ie: + $$(VAR_NAME). Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, + status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array groupLabels: description: Labels for grouping notifiations. items: diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 37e582f9..cb435174 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -31,19 +31,10 @@ spec: requests: cpu: 100m memory: 20Mi - volumeMounts: - - mountPath: /etc/localtime - name: host-time - readOnly: true env: - - name: NAMESPACE - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - volumes: - - hostPath: - path: /etc/localtime - type: "" - name: host-time + - name: NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace terminationGracePeriodSeconds: 10 diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index b16a626e..4c5b82bb 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -21,12 +21,19 @@ rules: - apiGroups: - "" resources: - - secrets - configmaps verbs: - get - list - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -55,6 +62,12 @@ rules: - patch - update - watch +- apiGroups: + - notification.kubesphere.io + resources: + - notificationmanagers/finalizers + verbs: + - update - apiGroups: - notification.kubesphere.io resources: @@ -63,4 +76,3 @@ rules: - get - patch - update - diff --git a/controllers/notificationmanager_controller.go b/controllers/notificationmanager_controller.go index c0226bee..6161fbf3 100644 --- a/controllers/notificationmanager_controller.go +++ b/controllers/notificationmanager_controller.go @@ -60,12 +60,13 @@ type NotificationManagerReconciler struct { // Reconcile reads that state of NotificationManager objects and makes changes based on the state read // and what is in the NotificationManagerSpec -// +kubebuilder:rbac:groups=notification.kubesphere.io,resources=notificationmanagers;receivers;configs,routers,silences,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=notification.kubesphere.io,resources=notificationmanagers;receivers;configs;routers;silences,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=notification.kubesphere.io,resources=notificationmanagers/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=notification.kubesphere.io,resources=notificationmanagers/finalizers,verbs=update // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch -// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch; +// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch func (r *NotificationManagerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { @@ -188,13 +189,6 @@ func (r *NotificationManagerReconciler) mutateDeployment(deploy *appsv1.Deployme Protocol: corev1.ProtocolTCP, }, }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "host-time", - MountPath: "/etc/localtime", - ReadOnly: true, - }, - }, } if utils.StringIsNil(nm.Spec.DefaultSecretNamespace) { @@ -217,8 +211,12 @@ func (r *NotificationManagerReconciler) mutateDeployment(deploy *appsv1.Deployme } } + if nm.Spec.Env != nil { + newC.Env = append(newC.Env, nm.Spec.Env...) + } + if nm.Spec.VolumeMounts != nil { - newC.VolumeMounts = append(newC.VolumeMounts, nm.Spec.VolumeMounts...) + newC.VolumeMounts = nm.Spec.VolumeMounts } if nm.Spec.Args != nil { @@ -231,17 +229,7 @@ func (r *NotificationManagerReconciler) mutateDeployment(deploy *appsv1.Deployme deploy.Spec.Template.Spec.Containers = append(deploy.Spec.Template.Spec.Containers, *sidecar) } - deploy.Spec.Template.Spec.Volumes = []corev1.Volume{ - { - Name: "host-time", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{ - Path: "/etc/localtime", - }, - }, - }, - } - deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes, nm.Spec.Volumes...) + deploy.Spec.Template.Spec.Volumes = nm.Spec.Volumes deploy.SetOwnerReferences(nil) return ctrl.SetControllerReference(nm, deploy, r.Scheme) @@ -260,13 +248,13 @@ func (r *NotificationManagerReconciler) mutateTenantSidecar(nm *v2beta2.Notifica } if sidecar.Type == kubesphereSidecar { - return r.generateKubesphereSidecar(sidecar) + return r.generateKubesphereSidecar(sidecar, nm) } return sidecar.Container } -func (r *NotificationManagerReconciler) generateKubesphereSidecar(sidecar *v2beta2.Sidecar) *corev1.Container { +func (r *NotificationManagerReconciler) generateKubesphereSidecar(sidecar *v2beta2.Sidecar, nm *v2beta2.NotificationManager) *corev1.Container { container := sidecar.Container if container == nil { @@ -290,11 +278,10 @@ func (r *NotificationManagerReconciler) generateKubesphereSidecar(sidecar *v2bet } } - container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{ - Name: "host-time", - MountPath: "/etc/localtime", - ReadOnly: true, - }) + if nm.Spec.Env != nil { + container.Env = append(container.Env, nm.Spec.Env...) + } + return container } diff --git a/docs/crds/notification-manager.md b/docs/crds/notification-manager.md index 9c378c23..83bc9204 100644 --- a/docs/crds/notification-manager.md +++ b/docs/crds/notification-manager.md @@ -68,6 +68,7 @@ A NotificationManager resource allows the user to define: Properties of Notification Manager webhook deployment. - `resources` +- `env` - `image` - `imagePullPolicy` - `replicas` diff --git a/helm/crds/bundle.yaml b/helm/crds/bundle.yaml index e5d9cd0c..07cb9510 100644 --- a/helm/crds/bundle.yaml +++ b/helm/crds/bundle.yaml @@ -4808,6 +4808,109 @@ spec: description: The default namespace to which notification manager secrets belong. type: string + env: + description: List of environment variable + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using + the previous defined environment variables in the container + and any service environment variables. If a variable cannot + be resolved, the reference in the input string will be unchanged. + The $(VAR_NAME) syntax can be escaped with a double $$, ie: + $$(VAR_NAME). Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, + status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array groupLabels: description: Labels for grouping notifiations. items: diff --git a/helm/templates/clusterroles.yaml b/helm/templates/clusterroles.yaml index 48ec8697..2cb5a8bd 100644 --- a/helm/templates/clusterroles.yaml +++ b/helm/templates/clusterroles.yaml @@ -55,19 +55,17 @@ rules: - apiGroups: - notification.kubesphere.io resources: - - notificationmanagers/status + - notificationmanagers/finalizers verbs: - - get - - patch - update - apiGroups: - - rbac.authorization.k8s.io + - notification.kubesphere.io resources: - - rolebindings + - notificationmanagers/status verbs: - get - - list - - watch + - patch + - update --- apiVersion: rbac.authorization.k8s.io/v1 diff --git a/helm/templates/notificationmanagers.yaml b/helm/templates/notificationmanagers.yaml index ef847820..2a20fcec 100644 --- a/helm/templates/notificationmanagers.yaml +++ b/helm/templates/notificationmanagers.yaml @@ -24,6 +24,11 @@ spec: {{- toYaml .Values.notificationmanager.receivers | nindent 4 }} defaultConfigSelector: {{- toYaml .Values.notificationmanager.defaultConfigSelector | nindent 4 }} + {{- if .Values.timezone }} + env: + - name: TZ + value: {{ .Values.timezone }} + {{- end }} volumeMounts: {{- toYaml .Values.notificationmanager.volumeMounts | nindent 4 }} volumes: diff --git a/helm/templates/operator.yaml b/helm/templates/operator.yaml index b868b966..d66955b9 100644 --- a/helm/templates/operator.yaml +++ b/helm/templates/operator.yaml @@ -42,6 +42,10 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.namespace + {{- if .Values.timezone }} + - name: TZ + value: {{ .Values.timezone }} + {{- end }} image: {{ .Values.operator.containers.operator.image.repo }}:{{ .Values.operator.containers.operator.image.tag }} imagePullPolicy: {{ .Values.operator.containers.operator.image.pullPolicy }} name: notification-manager-operator @@ -55,18 +59,11 @@ spec: - mountPath: /tmp/k8s-webhook-server/serving-certs name: cert readOnly: true - - mountPath: /etc/localtime - name: host-time - readOnly: true volumes: - name: cert secret: defaultMode: 420 secretName: notification-manager-webhook-server-cert - - hostPath: - path: /etc/localtime - type: "" - name: host-time serviceAccount: notification-manager-sa serviceAccountName: notification-manager-sa nodeSelector: diff --git a/helm/values.yaml b/helm/values.yaml index a7650d76..7246e565 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -5,6 +5,9 @@ hook: postInstall: backoffLimit: 1 +# Set timezone to be injected into containers +# timezone: "America/Toronto" + # value of notification-manager-operator operator: containers: diff --git a/pkg/apis/v2beta2/notificationmanager_types.go b/pkg/apis/v2beta2/notificationmanager_types.go index 61de7b08..f76a0a96 100644 --- a/pkg/apis/v2beta2/notificationmanager_types.go +++ b/pkg/apis/v2beta2/notificationmanager_types.go @@ -123,6 +123,8 @@ type NotificationManagerSpec struct { Receivers *ReceiversSpec `json:"receivers"` // The default namespace to which notification manager secrets belong. DefaultSecretNamespace string `json:"defaultSecretNamespace,omitempty"` + // List of environment variable + Env []v1.EnvVar `json:"env,omitempty"` // List of volumes that can be mounted by containers belonging to the pod. Volumes []v1.Volume `json:"volumes,omitempty"` // Pod volumes to mount into the container's filesystem. diff --git a/pkg/apis/v2beta2/zz_generated.deepcopy.go b/pkg/apis/v2beta2/zz_generated.deepcopy.go index fdd751c9..c2fe9b7b 100644 --- a/pkg/apis/v2beta2/zz_generated.deepcopy.go +++ b/pkg/apis/v2beta2/zz_generated.deepcopy.go @@ -973,6 +973,13 @@ func (in *NotificationManagerSpec) DeepCopyInto(out *NotificationManagerSpec) { *out = new(ReceiversSpec) (*in).DeepCopyInto(*out) } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]v1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Volumes != nil { in, out := &in.Volumes, &out.Volumes *out = make([]v1.Volume, len(*in))