From 57ba9b4ced0039e8d97653b5295abcd4a78434de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20D=C3=B6ll?= Date: Sun, 8 Dec 2024 20:03:32 +0000 Subject: [PATCH] wip: signing key controller --- api/v1alpha1/common_types.go | 3 +- api/v1alpha1/nats_operator_types.go | 2 +- api/v1alpha1/nats_signing_key_types.go | 60 +++++++ api/v1alpha1/zz_generated.deepcopy.go | 103 +++++++++++- controllers/natssigningkey_controller.go | 152 ++++++++++++++++++ .../templates/crds/natsoperators.yaml | 120 ++++++++++++-- .../bases/natz.zeiss.com_natsoperators.yaml | 120 ++++++++++++-- .../bases/natz.zeiss.com_natssigningkeys.yaml | 132 +++++++++++++++ pkg/status/status.go | 17 ++ 9 files changed, 685 insertions(+), 24 deletions(-) create mode 100644 api/v1alpha1/nats_signing_key_types.go create mode 100644 controllers/natssigningkey_controller.go create mode 100644 manifests/crd/bases/natz.zeiss.com_natssigningkeys.yaml diff --git a/api/v1alpha1/common_types.go b/api/v1alpha1/common_types.go index 6a986c6..b9fd247 100644 --- a/api/v1alpha1/common_types.go +++ b/api/v1alpha1/common_types.go @@ -17,7 +17,8 @@ const ( ) const ( - FinalizerName = "natz.zeiss.com/finalizer" + FinalizerName = "natz.zeiss.com/finalizer" + OwnerAnnotation = "natz.zeiss.com/owner" ) // SecretValueFromSource represents the source of a secret value diff --git a/api/v1alpha1/nats_operator_types.go b/api/v1alpha1/nats_operator_types.go index b85e3df..5fe1a68 100644 --- a/api/v1alpha1/nats_operator_types.go +++ b/api/v1alpha1/nats_operator_types.go @@ -23,7 +23,7 @@ type NatsOperatorSpec struct { // PublicKey is the public key that should be used to verify the JWT PublicKey corev1.SecretReference `json:"public_key,omitempty"` // SigningKeys is a list of references to secrets that contain the signing keys - SigningKeys []corev1.SecretReference `json:"signing_keys,omitempty"` + SigningKeys []NatsSigningKey `json:"signing_keys,omitempty"` } type NatsOperatorStatus struct { diff --git a/api/v1alpha1/nats_signing_key_types.go b/api/v1alpha1/nats_signing_key_types.go new file mode 100644 index 0000000..209be5c --- /dev/null +++ b/api/v1alpha1/nats_signing_key_types.go @@ -0,0 +1,60 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type SigningKeyPhase string + +const ( + SigningKeyPhaseNone SigningKeyPhase = "" + SigningKeyPhasePending SigningKeyPhase = "Pending" + SigningKeyPhaseCreating SigningKeyPhase = "Creating" + SigningKeyPhaseSynchronized SigningKeyPhase = "Synchronized" + SigningKeyPhaseFailed SigningKeyPhase = "Failed" +) + +// NatsSigningKeySpec defines the desired state of SigningKey +type NatsSigningKeySpec struct { + // DeleteSecret is a flag that indicates if the secret should be deleted. + DeleteSecret bool `json:"deleteSecret,omitempty"` +} + +// NatsSigningKeyStatus defines the observed state of SigningKey +type NatsSigningKeyStatus struct { + // Conditions is an array of conditions that the operator is currently in. + Conditions []metav1.Condition `json:"conditions,omitempty" optional:"true"` + // Phase is the current phase of the operator. + // + // +kubebuilder:validation:Enum={None,Pending,Creating,Synchronized,Failed} + Phase SigningKeyPhase `json:"phase"` + // ControlPaused is a flag that indicates if the operator is paused. + ControlPaused bool `json:"controlPaused,omitempty" optional:"true"` + // LastUpdate is the timestamp of the last update. + LastUpdate metav1.Time `json:"lastUpdate,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// NatsSigningKey is the Schema for the natssigningkeys API +type NatsSigningKey struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec NatsSigningKeySpec `json:"spec,omitempty"` + Status NatsSigningKeyStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// NatsSigningKeyList contains a list of NatsSigningKey +type NatsSigningKeyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []NatsSigningKey `json:"items"` +} + +func init() { + SchemeBuilder.Register(&NatsSigningKey{}, &NatsSigningKeyList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4f15377..b196149 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -348,8 +348,10 @@ func (in *NatsOperatorSpec) DeepCopyInto(out *NatsOperatorSpec) { out.PublicKey = in.PublicKey if in.SigningKeys != nil { in, out := &in.SigningKeys, &out.SigningKeys - *out = make([]v1.SecretReference, len(*in)) - copy(*out, *in) + *out = make([]NatsSigningKey, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -386,6 +388,103 @@ func (in *NatsOperatorStatus) DeepCopy() *NatsOperatorStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NatsSigningKey) DeepCopyInto(out *NatsSigningKey) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NatsSigningKey. +func (in *NatsSigningKey) DeepCopy() *NatsSigningKey { + if in == nil { + return nil + } + out := new(NatsSigningKey) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NatsSigningKey) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NatsSigningKeyList) DeepCopyInto(out *NatsSigningKeyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NatsSigningKey, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NatsSigningKeyList. +func (in *NatsSigningKeyList) DeepCopy() *NatsSigningKeyList { + if in == nil { + return nil + } + out := new(NatsSigningKeyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NatsSigningKeyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NatsSigningKeySpec) DeepCopyInto(out *NatsSigningKeySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NatsSigningKeySpec. +func (in *NatsSigningKeySpec) DeepCopy() *NatsSigningKeySpec { + if in == nil { + return nil + } + out := new(NatsSigningKeySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NatsSigningKeyStatus) DeepCopyInto(out *NatsSigningKeyStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LastUpdate.DeepCopyInto(&out.LastUpdate) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NatsSigningKeyStatus. +func (in *NatsSigningKeyStatus) DeepCopy() *NatsSigningKeyStatus { + if in == nil { + return nil + } + out := new(NatsSigningKeyStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NatsUser) DeepCopyInto(out *NatsUser) { *out = *in diff --git a/controllers/natssigningkey_controller.go b/controllers/natssigningkey_controller.go new file mode 100644 index 0000000..7814c2e --- /dev/null +++ b/controllers/natssigningkey_controller.go @@ -0,0 +1,152 @@ +package controllers + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + natsv1alpha1 "github.com/zeiss/natz-operator/api/v1alpha1" + "github.com/zeiss/natz-operator/pkg/status" + "github.com/zeiss/pkg/conv" + "github.com/zeiss/pkg/slices" + "github.com/zeiss/pkg/utilx" + corev1 "k8s.io/api/core/v1" +) + +// NatsSigningKeyReconciler ... +type NatsSigningKeyReconciler struct { + client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +// NewNatsSigningKeyReconciler ... +func NewNatsSigningKeyReconciler(mgr ctrl.Manager) *NatsSigningKeyReconciler { + return &NatsSigningKeyReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: mgr.GetEventRecorderFor(EventRecorderLabel), + } +} + +//+kubebuilder:rbac:groups=natz.zeiss.com,resources=natssigningkeys,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=natz.zeiss.com,resources=natssigningkeys/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=natz.zeiss.com,resources=natssigningkeys/finalizers,verbs=update +//+kubebuilder:rbac:groups=,resources=secrets,verbs=get;list;watch;create;update;patch;delete + +// Reconcile ... +// nolint:gocyclo +func (r *NatsSigningKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx) + + log.Info("reconcile signing key", "name", req.Name, "namespace", req.Namespace) + + sk := &natsv1alpha1.NatsSigningKey{} + if err := r.Get(ctx, req.NamespacedName, sk); err != nil { + // Request object not found, could have been deleted after reconcile request. + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + if !sk.ObjectMeta.DeletionTimestamp.IsZero() { + return r.reconcileDelete(ctx, sk) + } + + return r.reconcileResources(ctx, sk) +} + +func (r *NatsSigningKeyReconciler) reconcileResources(ctx context.Context, sk *natsv1alpha1.NatsSigningKey) (ctrl.Result, error) { + log := log.FromContext(ctx) + + err := r.reconcileStatus(ctx, sk) + if err != nil { + log.Error(err, "failed to reconcile status", "name", sk.Name, "namespace", sk.Namespace) + return ctrl.Result{}, err + } + + return r.ManageSuccess(ctx, sk) +} + +func (r *NatsSigningKeyReconciler) reconcileStatus(ctx context.Context, sk *natsv1alpha1.NatsSigningKey) error { + log := log.FromContext(ctx) + + log.Info("reconcile status", "name", sk.Name, "namespace", sk.Namespace) + + phase := natsv1alpha1.SigningKeyPhaseSynchronized + + if sk.Status.Phase != phase { + sk.Status.Phase = phase + + return r.Status().Update(ctx, sk) + } + + return nil +} + +func (r *NatsSigningKeyReconciler) reconcileDelete(ctx context.Context, sk *natsv1alpha1.NatsSigningKey) (ctrl.Result, error) { + // Remove our finalizer from the list. + controllerutil.RemoveFinalizer(sk, natsv1alpha1.FinalizerName) + + if !sk.DeletionTimestamp.IsZero() { + // Remove our finalizer from the list. + controllerutil.RemoveFinalizer(sk, natsv1alpha1.FinalizerName) + + // Stop reconciliation as the object is being deleted. + return ctrl.Result{}, r.Update(ctx, sk) + } + + return ctrl.Result{Requeue: true}, nil +} + +// IsCreating ... +func (r *NatsSigningKeyReconciler) IsCreating(obj *natsv1alpha1.NatsSigningKey) bool { + return utilx.Or(obj.Status.Conditions == nil, slices.Len(obj.Status.Conditions) == 0) +} + +// IsSynchronized ... +func (r *NatsSigningKeyReconciler) IsSynchronized(obj *natsv1alpha1.NatsSigningKey) bool { + return obj.Status.Phase == natsv1alpha1.SigningKeyPhaseSynchronized +} + +// ManageSuccess ... +func (r *NatsSigningKeyReconciler) ManageSuccess(ctx context.Context, obj *natsv1alpha1.NatsSigningKey) (ctrl.Result, error) { + if r.IsSynchronized(obj) { + return ctrl.Result{}, nil + } + + status.SetNatzSigningKeyCondition(obj, status.NewSigningKeySychronizedCondition(obj)) + + if r.IsCreating(obj) { + return ctrl.Result{Requeue: true}, nil + } + + if err := r.Client.Status().Update(ctx, obj); err != nil { + return ctrl.Result{}, err + } + + if !obj.ObjectMeta.DeletionTimestamp.IsZero() { + return ctrl.Result{Requeue: true}, nil + } + + if r.IsCreating(obj) { + return ctrl.Result{Requeue: true}, nil + } + + r.Recorder.Event(obj, corev1.EventTypeNormal, conv.String(EventReasonOperatorSynchronized), "operator synchronized") + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *NatsSigningKeyReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&natsv1alpha1.NatsSigningKey{}). + Owns(&corev1.Secret{}). + WithEventFilter(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{})). + Complete(r) +} diff --git a/helm/charts/natz-operator/templates/crds/natsoperators.yaml b/helm/charts/natz-operator/templates/crds/natsoperators.yaml index 77c2394..20737fb 100644 --- a/helm/charts/natz-operator/templates/crds/natsoperators.yaml +++ b/helm/charts/natz-operator/templates/crds/natsoperators.yaml @@ -55,20 +55,120 @@ spec: description: SigningKeys is a list of references to secrets that contain the signing keys items: - description: |- - SecretReference represents a Secret Reference. It has enough information to retrieve secret - in any namespace + description: NatsSigningKey is the Schema for the natssigningkeys + API properties: - name: - description: name is unique within a namespace to reference - a secret resource. + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string - namespace: - description: namespace defines the space within which the secret - name must be unique. + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string + metadata: + type: object + spec: + description: NatsSigningKeySpec defines the desired state of + SigningKey + properties: + deleteSecret: + description: DeleteSecret is a flag that indicates if the + secret should be deleted. + type: boolean + type: object + status: + description: NatsSigningKeyStatus defines the observed state + of SigningKey + properties: + conditions: + description: Conditions is an array of conditions that the + operator is currently in. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + 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. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + controlPaused: + description: ControlPaused is a flag that indicates if the + operator is paused. + type: boolean + lastUpdate: + description: LastUpdate is the timestamp of the last update. + format: date-time + type: string + phase: + description: Phase is the current phase of the operator. + enum: + - None + - Pending + - Creating + - Synchronized + - Failed + type: string + required: + - phase + type: object type: object - x-kubernetes-map-type: atomic type: array type: object status: diff --git a/manifests/crd/bases/natz.zeiss.com_natsoperators.yaml b/manifests/crd/bases/natz.zeiss.com_natsoperators.yaml index 77c2394..20737fb 100644 --- a/manifests/crd/bases/natz.zeiss.com_natsoperators.yaml +++ b/manifests/crd/bases/natz.zeiss.com_natsoperators.yaml @@ -55,20 +55,120 @@ spec: description: SigningKeys is a list of references to secrets that contain the signing keys items: - description: |- - SecretReference represents a Secret Reference. It has enough information to retrieve secret - in any namespace + description: NatsSigningKey is the Schema for the natssigningkeys + API properties: - name: - description: name is unique within a namespace to reference - a secret resource. + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string - namespace: - description: namespace defines the space within which the secret - name must be unique. + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string + metadata: + type: object + spec: + description: NatsSigningKeySpec defines the desired state of + SigningKey + properties: + deleteSecret: + description: DeleteSecret is a flag that indicates if the + secret should be deleted. + type: boolean + type: object + status: + description: NatsSigningKeyStatus defines the observed state + of SigningKey + properties: + conditions: + description: Conditions is an array of conditions that the + operator is currently in. + items: + description: Condition contains details for one aspect + of the current state of this API Resource. + 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. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, + False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in + foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + controlPaused: + description: ControlPaused is a flag that indicates if the + operator is paused. + type: boolean + lastUpdate: + description: LastUpdate is the timestamp of the last update. + format: date-time + type: string + phase: + description: Phase is the current phase of the operator. + enum: + - None + - Pending + - Creating + - Synchronized + - Failed + type: string + required: + - phase + type: object type: object - x-kubernetes-map-type: atomic type: array type: object status: diff --git a/manifests/crd/bases/natz.zeiss.com_natssigningkeys.yaml b/manifests/crd/bases/natz.zeiss.com_natssigningkeys.yaml new file mode 100644 index 0000000..da1da00 --- /dev/null +++ b/manifests/crd/bases/natz.zeiss.com_natssigningkeys.yaml @@ -0,0 +1,132 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.3 + name: natssigningkeys.natz.zeiss.com +spec: + group: natz.zeiss.com + names: + kind: NatsSigningKey + listKind: NatsSigningKeyList + plural: natssigningkeys + singular: natssigningkey + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NatsSigningKey is the Schema for the natssigningkeys API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NatsSigningKeySpec defines the desired state of SigningKey + properties: + deleteSecret: + description: DeleteSecret is a flag that indicates if the secret should + be deleted. + type: boolean + type: object + status: + description: NatsSigningKeyStatus defines the observed state of SigningKey + properties: + conditions: + description: Conditions is an array of conditions that the operator + is currently in. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + 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. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + controlPaused: + description: ControlPaused is a flag that indicates if the operator + is paused. + type: boolean + lastUpdate: + description: LastUpdate is the timestamp of the last update. + format: date-time + type: string + phase: + description: Phase is the current phase of the operator. + enum: + - None + - Pending + - Creating + - Synchronized + - Failed + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/status/status.go b/pkg/status/status.go index 0cc5dbc..5f7ac08 100644 --- a/pkg/status/status.go +++ b/pkg/status/status.go @@ -37,6 +37,11 @@ func SetNatzOperatorCondition(obj *natsv1alpha1.NatsOperator, condition metav1.C obj.Status.Conditions = SetCondition(condition, obj.Status.Conditions...) } +// SetNatzSigningKeyCondition ... +func SetNatzSigningKeyCondition(obj *natsv1alpha1.NatsSigningKey, condition metav1.Condition) { + obj.Status.Conditions = SetCondition(condition, obj.Status.Conditions...) +} + // SetNatzUserCondition ... func SetNatzUserCondition(obj *natsv1alpha1.NatsUser, condition metav1.Condition) { obj.Status.Conditions = SetCondition(condition, obj.Status.Conditions...) @@ -54,6 +59,18 @@ func NewOperatorSychronizedCondition(obj *natsv1alpha1.NatsOperator) metav1.Cond } } +// NewSigningKeySychronizedCondition creates the provisioning started condition in cluster conditions. +func NewSigningKeySychronizedCondition(obj *natsv1alpha1.NatsSigningKey) metav1.Condition { + return metav1.Condition{ + Type: natsv1alpha1.ConditionTypeSynchronized, + ObservedGeneration: obj.Generation, + Status: metav1.ConditionTrue, + LastTransitionTime: metav1.Now(), + Message: fmt.Sprintf("the signing key has successfully created: %s", obj.Name), + Reason: natsv1alpha1.ConditionReasonSynchronized, + } +} + // NewUserSychronizedCondition creates the provisioning started condition in cluster conditions. func NewUserSychronizedCondition(obj *natsv1alpha1.NatsUser) metav1.Condition { return metav1.Condition{