diff --git a/api/go.mod b/api/go.mod index d90ea3c..8c6dae2 100644 --- a/api/go.mod +++ b/api/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/openstack-k8s-operators/lib-common/modules/common v0.0.0-20230714104628-12cc1e43cccd + k8s.io/api v0.26.6 k8s.io/apimachinery v0.27.1 sigs.k8s.io/controller-runtime v0.14.6 ) @@ -55,7 +56,6 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.26.6 // indirect k8s.io/apiextensions-apiserver v0.26.6 // indirect k8s.io/client-go v0.26.6 // indirect k8s.io/component-base v0.26.6 // indirect diff --git a/api/v1beta1/barbicanapi_types.go b/api/v1beta1/barbicanapi_types.go index 9000c0c..10f9c39 100644 --- a/api/v1beta1/barbicanapi_types.go +++ b/api/v1beta1/barbicanapi_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1beta1 import ( + "github.com/openstack-k8s-operators/lib-common/modules/common/condition" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -35,12 +36,31 @@ type BarbicanAPISpec struct { BarbicanTemplate `json:",inline"` BarbicanAPITemplate `json:",inline"` + + // TransportURLSecret - Secret containing RabbitMQ transportURL + TransportURLSecret string `json:"transportURLSecret,omitempty"` } // BarbicanAPIStatus defines the observed state of BarbicanAPI type BarbicanAPIStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + + // ReadyCount of barbican API instances + ReadyCount int32 `json:"readyCount,omitempty"` + + // Map of hashes to track e.g. job status + Hash map[string]string `json:"hash,omitempty"` + + // API endpoint + APIEndpoints map[string]string `json:"apiEndpoint,omitempty"` + + // Conditions + Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"` + + // NetworkAttachments status of the deployment pods + NetworkAttachments map[string][]string `json:"networkAttachments,omitempty"` + + // Barbican Database Hostname + DatabaseHostname string `json:"databaseHostname,omitempty"` } //+kubebuilder:object:root=true diff --git a/api/v1beta1/barbicanworker_types.go b/api/v1beta1/barbicanworker_types.go index 02d8e17..c73ca07 100644 --- a/api/v1beta1/barbicanworker_types.go +++ b/api/v1beta1/barbicanworker_types.go @@ -33,6 +33,8 @@ type BarbicanWorkerSpec struct { BarbicanTemplate `json:",inline"` BarbicanWorkerTemplate `json:",inline"` + + TransportURLSecret string `json:"transportURLSecret,omitempty"` } // BarbicanWorkerStatus defines the observed state of BarbicanWorker diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 4fafc38..cee02b3 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -1,6 +1,9 @@ package v1beta1 -import "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" +import ( + "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" + corev1 "k8s.io/api/core/v1" +) // BarbicanTemplate defines common Spec elements for all Barbican components type BarbicanTemplate struct { @@ -32,6 +35,10 @@ type BarbicanTemplate struct { // Needed to request a transportURL that is created and used in Barbican RabbitMqClusterName string `json:"rabbitMqClusterName"` + // +kubebuilder:validation:Optional + // Secret containing SimpleCrypto KEK + SimpleCryptoBackendKEKSecret string `json:"simpleCryptoBackendKEKSecret,omitempty"` + // +kubebuilder:validation:Optional // Secret containing all passwords / keys needed Secret string `json:"secret"` @@ -91,6 +98,17 @@ type BarbicanComponentTemplate struct { // TODO: -> implement DefaultConfigOverwrite map[string]string `json:"defaultConfigOverwrite,omitempty"` + // +kubebuilder:validation:Optional + // CustomServiceConfigSecrets - customize the service config using this parameter to specify Secrets + // that contain sensitive service config data. The content of each Secret gets added to the + // /etc//.conf.d directory as a custom config file. + CustomServiceConfigSecrets []string `json:"customServiceConfigSecrets,omitempty"` + + // +kubebuilder:validation:Optional + // Resources - Compute Resources required by this service (Limits/Requests). + // https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // +kubebuilder:validation:Optional // NetworkAttachments is a list of NetworkAttachment resource names to expose the services to the given network NetworkAttachments []string `json:"networkAttachments,omitempty"` @@ -106,10 +124,6 @@ type PasswordSelector struct { // +kubebuilder:default="BarbicanPassword" // Service - Selector to get the barbican service user password from the Secret Service string `json:"service"` - - // +kubebuilder:validation:Optional - // SimpleCryptoKEK - base64 encoded KEK for SimpleCrypto backend - SimpleCryptoKEK string `json:"simpleCryptoKEK,omitempty"` } // BarbicanDebug indicates whether certain stages of deployment should be paused diff --git a/api/v1beta1/conditions.go b/api/v1beta1/conditions.go index e2e0f40..7ec075a 100644 --- a/api/v1beta1/conditions.go +++ b/api/v1beta1/conditions.go @@ -5,6 +5,7 @@ import "github.com/openstack-k8s-operators/lib-common/modules/common/condition" const ( // BarbicanAPIReadyCondition - BarbicanAPIReadyCondition condition.Type = "BarbicanAPIReady" + // BarbicanWorkerReadyCondition - BarbicanWorkerReadyCondition condition.Type = "BarbicanWorkerReady" // BarbicanRabbitMQTransportURLReadyCondition - @@ -14,6 +15,8 @@ const ( const ( // BarbicanAPIReadyInitMessage - BarbicanAPIReadyInitMessage = "BarbicanAPI not started" + // BarbicanAPIReadyErrorMessage - + BarbicanAPIReadyErrorMessage = "BarbicanAPI error occured %s" // BarbicanWorkerReadyInitMessage - BarbicanWorkerReadyInitMessage = "BarbicanWorker not started" diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index c4992bf..06917c2 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -59,7 +59,7 @@ func (in *BarbicanAPI) DeepCopyInto(out *BarbicanAPI) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanAPI. @@ -132,6 +132,42 @@ func (in *BarbicanAPISpec) DeepCopy() *BarbicanAPISpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BarbicanAPIStatus) DeepCopyInto(out *BarbicanAPIStatus) { *out = *in + if in.Hash != nil { + in, out := &in.Hash, &out.Hash + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.APIEndpoints != nil { + in, out := &in.APIEndpoints, &out.APIEndpoints + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(condition.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NetworkAttachments != nil { + in, out := &in.NetworkAttachments, &out.NetworkAttachments + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BarbicanAPIStatus. @@ -189,6 +225,12 @@ func (in *BarbicanComponentTemplate) DeepCopyInto(out *BarbicanComponentTemplate (*out)[key] = val } } + if in.CustomServiceConfigSecrets != nil { + in, out := &in.CustomServiceConfigSecrets, &out.CustomServiceConfigSecrets + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.Resources.DeepCopyInto(&out.Resources) if in.NetworkAttachments != nil { in, out := &in.NetworkAttachments, &out.NetworkAttachments *out = make([]string, len(*in)) diff --git a/config/crd/bases/barbican.openstack.org_barbicanapis.yaml b/config/crd/bases/barbican.openstack.org_barbicanapis.yaml index 0f525bc..663a815 100644 --- a/config/crd/bases/barbican.openstack.org_barbicanapis.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicanapis.yaml @@ -46,6 +46,14 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + customServiceConfigSecrets: + description: CustomServiceConfigSecrets - customize the service config + using this parameter to specify Secrets that contain sensitive service + config data. The content of each Secret gets added to the /etc//.conf.d + directory as a custom config file. + items: + type: string + type: array databaseInstance: description: 'MariaDB instance name TODO(dmendiza): Is this comment right? Right now required by the maridb-operator to get the credentials @@ -162,10 +170,6 @@ spec: description: Service - Selector to get the barbican service user password from the Secret type: string - simpleCryptoKEK: - description: SimpleCryptoKEK - base64 encoded KEK for SimpleCrypto - backend - type: string type: object rabbitMqClusterName: default: rabbitmq @@ -179,6 +183,54 @@ spec: maximum: 32 minimum: 0 type: integer + resources: + description: Resources - Compute Resources required by this service + (Limits/Requests). https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: "Claims lists the names of resources, defined in + spec.resourceClaims, that are used by this container. \n This + is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be set + for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims + of the Pod where this field is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object secret: description: Secret containing all passwords / keys needed type: string @@ -191,6 +243,12 @@ spec: description: ServiceUser - optional username used for this service to register in keystone type: string + simpleCryptoBackendKEKSecret: + description: Secret containing SimpleCrypto KEK + type: string + transportURLSecret: + description: TransportURLSecret - Secret containing RabbitMQ transportURL + type: string required: - containerImage - databaseInstance @@ -199,6 +257,74 @@ spec: type: object status: description: BarbicanAPIStatus defines the observed state of BarbicanAPI + properties: + apiEndpoint: + additionalProperties: + type: string + description: API endpoint + type: object + conditions: + description: Conditions + items: + description: Condition defines an observation of a API resource + operational state. + properties: + lastTransitionTime: + description: 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: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition + in CamelCase. + type: string + severity: + description: Severity provides a classification of Reason code, + so the current situation is immediately understandable and + could act accordingly. It is meant for situations where Status=False + and it should be indicated if it is just informational, warning + (next reconciliation might fix it) or an error (e.g. DB create + issue and no actions to automatically resolve the issue can/should + be done). For conditions where Status=Unknown or Status=True + the Severity should be SeverityNone. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition in CamelCase. + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + databaseHostname: + description: Barbican Database Hostname + type: string + hash: + additionalProperties: + type: string + description: Map of hashes to track e.g. job status + type: object + networkAttachments: + additionalProperties: + items: + type: string + type: array + description: NetworkAttachments status of the deployment pods + type: object + readyCount: + description: ReadyCount of barbican API instances + format: int32 + type: integer type: object type: object served: true diff --git a/config/crd/bases/barbican.openstack.org_barbicans.yaml b/config/crd/bases/barbican.openstack.org_barbicans.yaml index 2640da0..924fc23 100644 --- a/config/crd/bases/barbican.openstack.org_barbicans.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicans.yaml @@ -50,6 +50,15 @@ spec: content gets added to to /etc//.conf.d directory as a custom config file. type: string + customServiceConfigSecrets: + description: CustomServiceConfigSecrets - customize the service + config using this parameter to specify Secrets that contain + sensitive service config data. The content of each Secret gets + added to the /etc//.conf.d directory as a + custom config file. + items: + type: string + type: array defaultConfigOverwrite: additionalProperties: type: string @@ -122,6 +131,55 @@ spec: maximum: 32 minimum: 0 type: integer + resources: + description: Resources - Compute Resources required by this service + (Limits/Requests). https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object required: - containerImage type: object @@ -140,6 +198,15 @@ spec: content gets added to to /etc//.conf.d directory as a custom config file. type: string + customServiceConfigSecrets: + description: CustomServiceConfigSecrets - customize the service + config using this parameter to specify Secrets that contain + sensitive service config data. The content of each Secret gets + added to the /etc//.conf.d directory as a + custom config file. + items: + type: string + type: array defaultConfigOverwrite: additionalProperties: type: string @@ -168,6 +235,55 @@ spec: maximum: 32 minimum: 0 type: integer + resources: + description: Resources - Compute Resources required by this service + (Limits/Requests). https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object required: - containerImage type: object @@ -249,10 +365,6 @@ spec: description: Service - Selector to get the barbican service user password from the Secret type: string - simpleCryptoKEK: - description: SimpleCryptoKEK - base64 encoded KEK for SimpleCrypto - backend - type: string type: object preserveJobs: default: false @@ -276,6 +388,9 @@ spec: description: ServiceUser - optional username used for this service to register in keystone type: string + simpleCryptoBackendKEKSecret: + description: Secret containing SimpleCrypto KEK + type: string required: - barbicanAPI - barbicanWorker diff --git a/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml b/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml index 7fb65a9..a305a9d 100644 --- a/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml +++ b/config/crd/bases/barbican.openstack.org_barbicanworkers.yaml @@ -46,6 +46,14 @@ spec: added to to /etc//.conf.d directory as custom.conf file. type: string + customServiceConfigSecrets: + description: CustomServiceConfigSecrets - customize the service config + using this parameter to specify Secrets that contain sensitive service + config data. The content of each Secret gets added to the /etc//.conf.d + directory as a custom config file. + items: + type: string + type: array databaseInstance: description: 'MariaDB instance name TODO(dmendiza): Is this comment right? Right now required by the maridb-operator to get the credentials @@ -119,10 +127,6 @@ spec: description: Service - Selector to get the barbican service user password from the Secret type: string - simpleCryptoKEK: - description: SimpleCryptoKEK - base64 encoded KEK for SimpleCrypto - backend - type: string type: object rabbitMqClusterName: default: rabbitmq @@ -136,6 +140,54 @@ spec: maximum: 32 minimum: 0 type: integer + resources: + description: Resources - Compute Resources required by this service + (Limits/Requests). https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: "Claims lists the names of resources, defined in + spec.resourceClaims, that are used by this container. \n This + is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be set + for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims + of the Pod where this field is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object secret: description: Secret containing all passwords / keys needed type: string @@ -148,6 +200,11 @@ spec: description: ServiceUser - optional username used for this service to register in keystone type: string + simpleCryptoBackendKEKSecret: + description: Secret containing SimpleCrypto KEK + type: string + transportURLSecret: + type: string required: - containerImage - databaseInstance diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 5c5f0b8..ad13e96 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,2 +1,8 @@ resources: - manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: controller + newTag: latest diff --git a/config/samples/barbican_v1beta1_barbican.yaml b/config/samples/barbican_v1beta1_barbican.yaml index 57689ff..9914ea3 100644 --- a/config/samples/barbican_v1beta1_barbican.yaml +++ b/config/samples/barbican_v1beta1_barbican.yaml @@ -11,6 +11,7 @@ metadata: spec: serviceAccount: barbican serviceUser: barbican + containerImage: quay.io/podified-antelope-centos9/openstack-barbican-api:current-podified databaseInstance: openstack databaseUser: barbican rabbitMqCusterName: barbican_rabbit @@ -42,6 +43,9 @@ spec: defautlConfigOverwrite: optional_policy.json: | {"some": "custom policy"} + passwordSelectors: + database: BarbicanDatabasePassword + service: BarbicanPassword barbicanWorker: containerImage: quay.io/podified-antelope-centos9/openstack-barbican-worker:current-podified nodeSelector: diff --git a/config/samples/barbican_v1beta1_barbicanapi.yaml b/config/samples/barbican_v1beta1_barbicanapi.yaml deleted file mode 100644 index 01c0f82..0000000 --- a/config/samples/barbican_v1beta1_barbicanapi.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: barbican.openstack.org/v1beta1 -kind: BarbicanAPI -metadata: - labels: - name: barbicanapi -spec: - databaseInstance: openstack - containerImage: quay.io/podified-antelope-centos9/openstack-barbican-api:current-podified - keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing - secret: osp-secret - serviceAccount: barbican diff --git a/config/samples/barbican_v1beta1_barbicanworker.yaml b/config/samples/barbican_v1beta1_barbicanworker.yaml deleted file mode 100644 index ad95190..0000000 --- a/config/samples/barbican_v1beta1_barbicanworker.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: barbican.openstack.org/v1beta1 -kind: BarbicanWorker -metadata: - labels: - name: barbicanworker -spec: {} diff --git a/controllers/barbican_common.go b/controllers/barbican_common.go new file mode 100644 index 0000000..4f99f3d --- /dev/null +++ b/controllers/barbican_common.go @@ -0,0 +1,63 @@ +/* +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 ( + "context" + "fmt" + + "github.com/openstack-k8s-operators/lib-common/modules/common/env" + "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + "github.com/openstack-k8s-operators/lib-common/modules/common/secret" + "github.com/openstack-k8s-operators/lib-common/modules/common/util" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// GenerateConfigsGeneric - generates config files +func GenerateConfigsGeneric( + ctx context.Context, h *helper.Helper, + instance client.Object, + envVars *map[string]env.Setter, + templateParameters map[string]interface{}, + customData map[string]string, + cmLabels map[string]string, + scripts bool, +) error { + + cms := []util.Template{ + // Templates where the BarbicanAPI config is stored + { + Name: fmt.Sprintf("%s-config-data", instance.GetName()), + Namespace: instance.GetNamespace(), + Type: util.TemplateTypeConfig, + InstanceType: instance.GetObjectKind().GroupVersionKind().Kind, + ConfigOptions: templateParameters, + CustomData: customData, + Labels: cmLabels, + }, + } + if scripts { + cms = append(cms, util.Template{ + Name: fmt.Sprintf("%s-scripts", instance.GetName()), + Namespace: instance.GetNamespace(), + Type: util.TemplateTypeScripts, + InstanceType: instance.GetObjectKind().GroupVersionKind().Kind, + Labels: cmLabels, + }) + } + return secret.EnsureSecrets(ctx, h, instance, cms, envVars) +} diff --git a/controllers/barbican_controller.go b/controllers/barbican_controller.go index 400501b..a445039 100644 --- a/controllers/barbican_controller.go +++ b/controllers/barbican_controller.go @@ -32,9 +32,10 @@ import ( barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1" "github.com/openstack-k8s-operators/barbican-operator/pkg/barbican" rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1" + keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" - "github.com/openstack-k8s-operators/lib-common/modules/common/configmap" + "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" "github.com/openstack-k8s-operators/lib-common/modules/common/env" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" "github.com/openstack-k8s-operators/lib-common/modules/common/job" @@ -42,7 +43,6 @@ import ( nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment" common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" - "github.com/openstack-k8s-operators/lib-common/modules/common/util" "github.com/openstack-k8s-operators/lib-common/modules/database" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -163,8 +163,7 @@ func (r *BarbicanReconciler) reconcileNormal(ctx context.Context, instance *barb common.AppSelector: barbican.ServiceName, } - // ConfigMap - configMapVars := make(map[string]env.Setter) + configVars := make(map[string]env.Setter) // // create RabbitMQ transportURL CR and get the actual URL from the associated secret that is created @@ -196,6 +195,7 @@ func (r *BarbicanReconciler) reconcileNormal(ctx context.Context, instance *barb return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil } + r.Log.Info(fmt.Sprintf("TransportURL secret name %s", transportURL.Status.SecretName)) instance.Status.Conditions.MarkTrue(barbicanv1beta1.BarbicanRabbitMQTransportURLReadyCondition, barbicanv1beta1.BarbicanRabbitMQTransportURLReadyMessage) // @@ -220,12 +220,13 @@ func (r *BarbicanReconciler) reconcileNormal(ctx context.Context, instance *barb return ctrl.Result{}, err } // Add a prefix to the var name to avoid accidental collision with other non-secret vars. - configMapVars["secret-"+ospSecret.Name] = env.SetValue(hash) + configVars["secret-"+ospSecret.Name] = env.SetValue(hash) instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) + // Setting this here at the top level + instance.Spec.ServiceAccount = instance.RbacResourceName() - // create ConfigMap required for Barbican CR inputs - err = r.generateServiceConfigMaps(ctx, helper, instance, &configMapVars, serviceLabels) + err = r.generateServiceConfig(ctx, helper, instance, &configVars, serviceLabels) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.ServiceConfigReadyCondition, @@ -276,6 +277,29 @@ func (r *BarbicanReconciler) reconcileNormal(ctx context.Context, instance *barb return ctrlResult, nil } + // TODO(dmendiza): Handle service update + + // TODO(dmendiza): Handle service upgrade + + // create or update Barbican API deployment + _, op, err = r.apiDeploymentCreateOrUpdate(ctx, instance) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + barbicanv1beta1.BarbicanAPIReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + barbicanv1beta1.BarbicanAPIReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } + if op != controllerutil.OperationResultNone { + r.Log.Info(fmt.Sprintf("Deployment %s successfully reconciled - operation: %s", instance.Name, string(op))) + } + + // TODO(dmendiza): Handle API endpoints + + // TODO(dmendiza): Understand what Glance is doing with the API conditions and maybe do it here too + return ctrl.Result{}, nil } @@ -293,51 +317,58 @@ func (r *BarbicanReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } -func (r *BarbicanReconciler) generateServiceConfigMaps( +func (r *BarbicanReconciler) generateServiceConfig( ctx context.Context, h *helper.Helper, instance *barbicanv1beta1.Barbican, envVars *map[string]env.Setter, serviceLabels map[string]string, ) error { - // - // create Configmap/Secret required for barbican input + r.Log.Info("generateServiceConfigMaps - Barbican controller") + + // create Secret required for barbican input + labels := labels.GetLabels(instance, labels.GetGroupLabel(barbican.ServiceName), serviceLabels) + + ospSecret, _, err := secret.GetSecret(ctx, h, instance.Spec.Secret, instance.Namespace) + if err != nil { + return err + } - cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(barbican.ServiceName), serviceLabels) + transportURLSecret, _, err := secret.GetSecret(ctx, h, instance.Status.TransportURLSecret, instance.Namespace) + if err != nil { + return err + } - // customData hold any customization for the service. - // custom.conf is going to /etc//.conf.d - // all other files get placed into /etc/ to allow overwrite of e.g. policy.json - customData := map[string]string{common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig} + customData := map[string]string{barbican.CustomConfigFileName: instance.Spec.CustomServiceConfig} for key, data := range instance.Spec.DefaultConfigOverwrite { customData[key] = data } + keystoneAPI, err := keystonev1.GetKeystoneAPI(ctx, h, instance.Namespace, map[string]string{}) + // KeystoneAPI not available we should not aggregate the error and continue + if err != nil { + return err + } + keystoneInternalURL, err := keystoneAPI.GetEndpoint(endpoint.EndpointInternal) + if err != nil { + return err + } - templateParameters := make(map[string]interface{}) - - cms := []util.Template{ - // ScriptsConfigMap - { - Name: fmt.Sprintf("%s-scripts", instance.Name), - Namespace: instance.Namespace, - Type: util.TemplateTypeScripts, - InstanceType: instance.Kind, - Labels: cmLabels, - }, - // ConfigMap - { - Name: fmt.Sprintf("%s-config-data", instance.Name), - Namespace: instance.Namespace, - Type: util.TemplateTypeConfig, - InstanceType: instance.Kind, - CustomData: customData, - ConfigOptions: templateParameters, - Labels: cmLabels, - }, + templateParameters := map[string]interface{}{ + "DatabaseConnection": fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s", + instance.Spec.DatabaseUser, + string(ospSecret.Data[instance.Spec.PasswordSelectors.Database]), + instance.Status.DatabaseHostname, + barbican.DatabaseName, + ), + "KeystoneAuthURL": keystoneInternalURL, + "ServicePassword": string(ospSecret.Data[instance.Spec.PasswordSelectors.Service]), + "ServiceUser": instance.Spec.ServiceUser, + "ServiceURL": "TODO", + "TransportURL": string(transportURLSecret.Data["transport_url"]), } - return configmap.EnsureConfigMaps(ctx, h, instance, cms, envVars) + return GenerateConfigsGeneric(ctx, h, instance, envVars, templateParameters, customData, labels, false) } func (r *BarbicanReconciler) transportURLCreateOrUpdate( @@ -363,6 +394,38 @@ func (r *BarbicanReconciler) transportURLCreateOrUpdate( return transportURL, op, err } +func (r *BarbicanReconciler) apiDeploymentCreateOrUpdate(ctx context.Context, instance *barbicanv1beta1.Barbican) (*barbicanv1beta1.BarbicanAPI, controllerutil.OperationResult, error) { + + r.Log.Info(fmt.Sprintf("Creating barbican API spec. transporturlsecret: '%s'", instance.Status.TransportURLSecret)) + apiSpec := barbicanv1beta1.BarbicanAPISpec{ + BarbicanTemplate: instance.Spec.BarbicanTemplate, + BarbicanAPITemplate: instance.Spec.BarbicanAPI, + TransportURLSecret: instance.Status.TransportURLSecret, + } + + deployment := &barbicanv1beta1.BarbicanAPI{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-api", instance.Name), + Namespace: instance.Namespace, + }, + } + + op, err := controllerutil.CreateOrUpdate(ctx, r.Client, deployment, func() error { + r.Log.Info("Setting deployment spec to be apispec") + deployment.Spec = apiSpec + + err := controllerutil.SetControllerReference(instance, deployment, r.Scheme) + if err != nil { + return err + } + + // TODO(dmendiza): Do we want a finalizer here? Glance has one. + return nil + }) + + return deployment, op, err +} + func (r *BarbicanReconciler) reconcileInit( ctx context.Context, instance *barbicanv1beta1.Barbican, diff --git a/controllers/barbicanapi_controller.go b/controllers/barbicanapi_controller.go index e3c392d..b392915 100644 --- a/controllers/barbicanapi_controller.go +++ b/controllers/barbicanapi_controller.go @@ -18,17 +18,54 @@ package controllers import ( "context" + "fmt" + "time" + "github.com/go-logr/logr" + barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1" + "github.com/openstack-k8s-operators/barbican-operator/pkg/barbican" + "github.com/openstack-k8s-operators/barbican-operator/pkg/barbicanapi" + keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" + "github.com/openstack-k8s-operators/lib-common/modules/common" + "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/deployment" + "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" + "github.com/openstack-k8s-operators/lib-common/modules/common/env" + "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + "github.com/openstack-k8s-operators/lib-common/modules/common/labels" + nad "github.com/openstack-k8s-operators/lib-common/modules/common/networkattachment" + "github.com/openstack-k8s-operators/lib-common/modules/common/secret" + "github.com/openstack-k8s-operators/lib-common/modules/common/util" + corev1 "k8s.io/api/core/v1" + k8s_errors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" 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" - - "github.com/go-logr/logr" - barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1" ) +// GetClient - +func (r *BarbicanAPIReconciler) GetClient() client.Client { + return r.Client +} + +// GetKClient - +func (r *BarbicanAPIReconciler) GetKClient() kubernetes.Interface { + return r.Kclient +} + +// GetLogger - +func (r *BarbicanAPIReconciler) GetLogger() logr.Logger { + return r.Log +} + +// GetScheme - +func (r *BarbicanAPIReconciler) GetScheme() *runtime.Scheme { + return r.Scheme +} + // BarbicanAPIReconciler reconciles a BarbicanAPI object type BarbicanAPIReconciler struct { client.Client @@ -41,20 +78,366 @@ type BarbicanAPIReconciler struct { //+kubebuilder:rbac:groups=barbican.openstack.org,resources=barbicanapis/status,verbs=get;update;patch //+kubebuilder:rbac:groups=barbican.openstack.org,resources=barbicanapis/finalizers,verbs=update -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the BarbicanAPI object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile -func (r *BarbicanAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +// Reconcile BarbicanAPI +func (r *BarbicanAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, _err error) { _ = log.FromContext(ctx) - // TODO(user): your logic here + instance := &barbicanv1beta1.BarbicanAPI{} + err := r.Client.Get(ctx, req.NamespacedName, instance) + if err != nil { + if k8s_errors.IsNotFound(err) { + // Object not found + return ctrl.Result{}, err + } + } + r.Log.Info(fmt.Sprintf("Reconciling BarbicanAPI %s", instance.Name)) + + helper, err := helper.NewHelper( + instance, + r.Client, + r.Kclient, + r.Scheme, + r.Log, + ) + if err != nil { + return ctrl.Result{}, err + } + + // Always patch the instance when this function exits + defer func() { + if instance.Status.Conditions.AllSubConditionIsTrue() { + instance.Status.Conditions.MarkTrue(condition.ReadyCondition, condition.ReadyMessage) + } else { + instance.Status.Conditions.MarkUnknown( + condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage) + instance.Status.Conditions.Set( + instance.Status.Conditions.Mirror(condition.ReadyCondition)) + } + err := helper.PatchInstance(ctx, instance) + if err != nil { + _err = err + return + } + }() + + r.Log.Info(fmt.Sprintf("Add finalizer %s", instance.Name)) + // Add Finalizer + if instance.DeletionTimestamp.IsZero() && controllerutil.AddFinalizer(instance, helper.GetFinalizer()) { + return ctrl.Result{}, nil + } + + r.Log.Info(fmt.Sprintf("initilize %s", instance.Name)) + // Initialize Conditions + if instance.Status.Conditions == nil { + instance.Status.Conditions = condition.Conditions{} + cl := condition.CreateList( + condition.UnknownCondition(condition.ExposeServiceReadyCondition, condition.InitReason, condition.ExposeServiceReadyInitMessage), + condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage), + condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyInitMessage), + condition.UnknownCondition(condition.DeploymentReadyCondition, condition.InitReason, condition.DeploymentReadyInitMessage), + // right now we have no dedicated KeystoneServiceReadyInitMessage and KeystoneEndpointReadyInitMessage + condition.UnknownCondition(condition.KeystoneServiceReadyCondition, condition.InitReason, ""), + condition.UnknownCondition(condition.KeystoneEndpointReadyCondition, condition.InitReason, ""), + condition.UnknownCondition(condition.NetworkAttachmentsReadyCondition, condition.InitReason, condition.NetworkAttachmentsReadyInitMessage), + ) + r.Log.Info(fmt.Sprintf("calling init %s", instance.Name)) + instance.Status.Conditions.Init(&cl) + r.Log.Info(fmt.Sprintf("post init %s", instance.Name)) + + // TODO: (alee) this is ssupposed to exit here - but then it never comes back! + // Register overall status immediately to have an early feedback e.g. in the cli + return ctrl.Result{}, nil + } + r.Log.Info(fmt.Sprintf("post initiialize %s", instance.Name)) + + if instance.Status.Hash == nil { + instance.Status.Hash = map[string]string{} + } + if instance.Status.APIEndpoints == nil { + instance.Status.APIEndpoints = map[string]string{} + } + //if instance.Status.ServiceIDs == nil { + // instance.Status.ServiceIDs = map[string]string{} + //} + if instance.Status.NetworkAttachments == nil { + instance.Status.NetworkAttachments = map[string][]string{} + } + + // Handle service delete + if !instance.DeletionTimestamp.IsZero() { + return r.reconcileDelete(ctx, instance, helper) + } + + r.Log.Info(fmt.Sprintf("Calling reconcile normal %s", instance.Name)) + + // Handle non-deleted clusters + return r.reconcileNormal(ctx, instance, helper) +} + +func (r *BarbicanAPIReconciler) getSecret( + ctx context.Context, + h *helper.Helper, + instance *barbicanv1beta1.BarbicanAPI, + secretName string, + envVars *map[string]env.Setter, +) (ctrl.Result, error) { + secret, hash, err := secret.GetSecret(ctx, h, secretName, instance.Namespace) + if err != nil { + if k8s_errors.IsNotFound(err) { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.InputReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.InputReadyWaitingMessage)) + return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, fmt.Errorf("Secret %s not found", secretName) + } + instance.Status.Conditions.Set(condition.FalseCondition( + condition.InputReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.InputReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } + + // Add a prefix to the var name to avoid accidental collision with other non-secret + // vars. The secret names themselves will be unique. + (*envVars)["secret-"+secret.Name] = env.SetValue(hash) + // env[secret-osp-secret] = hash? + + return ctrl.Result{}, nil +} + +func (r *BarbicanAPIReconciler) createHashOfInputHashes( + ctx context.Context, + instance *barbicanv1beta1.BarbicanAPI, + envVars map[string]env.Setter, +) (string, bool, error) { + var hashMap map[string]string + changed := false + mergedMapVars := env.MergeEnvs([]corev1.EnvVar{}, envVars) + hash, err := util.ObjectHash(mergedMapVars) + if err != nil { + return hash, changed, err + } + if hashMap, changed = util.SetHash(instance.Status.Hash, common.InputHashName, hash); changed { + instance.Status.Hash = hashMap + r.Log.Info(fmt.Sprintf("Input maps hash %s - %s", common.InputHashName, hash)) + } + return hash, changed, nil +} + +// generateServiceConfigs - create Secret which holds the service configuration +// TODO add DefaultConfigOverwrite +func (r *BarbicanAPIReconciler) generateServiceConfigs( + ctx context.Context, + h *helper.Helper, + instance *barbicanv1beta1.BarbicanAPI, + envVars *map[string]env.Setter, +) error { + r.Log.Info("generateServiceConfigs - reconciling") + labels := labels.GetLabels(instance, labels.GetGroupLabel(barbican.ServiceName), map[string]string{}) + + // customData hold any customization for the service. + customData := map[string]string{common.CustomServiceConfigFileName: instance.Spec.CustomServiceConfig} + + for key, data := range instance.Spec.DefaultConfigOverwrite { + customData[key] = data + } + + keystoneAPI, err := keystonev1.GetKeystoneAPI(ctx, h, instance.Namespace, map[string]string{}) + // KeystoneAPI not available we should not aggregate the error and continue + if err != nil { + return err + } + keystoneInternalURL, err := keystoneAPI.GetEndpoint(endpoint.EndpointInternal) + if err != nil { + return err + } + + ospSecret, _, err := secret.GetSecret(ctx, h, instance.Spec.Secret, instance.Namespace) + if err != nil { + return err + } + + templateParameters := map[string]interface{}{ + "DatabaseConnection": fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s", + instance.Spec.DatabaseUser, + string(ospSecret.Data[instance.Spec.PasswordSelectors.Database]), + instance.Status.DatabaseHostname, + barbican.DatabaseName, + ), + "KeystoneAuthURL": keystoneInternalURL, + "ServicePassword": string(ospSecret.Data[instance.Spec.PasswordSelectors.Service]), + "ServiceUser": instance.Spec.ServiceUser, + "ServiceURL": "TODO", + "TransportURL": instance.Spec.TransportURLSecret, + } + + return GenerateConfigsGeneric(ctx, h, instance, envVars, templateParameters, customData, labels, false) +} + +func (r *BarbicanAPIReconciler) reconcileDelete(ctx context.Context, instance *barbicanv1beta1.BarbicanAPI, helper *helper.Helper) (ctrl.Result, error) { + r.Log.Info(fmt.Sprintf("Reconciling Service '%s' delete", instance.Name)) + return ctrl.Result{}, nil +} + +func (r *BarbicanAPIReconciler) reconcileNormal(ctx context.Context, instance *barbicanv1beta1.BarbicanAPI, helper *helper.Helper) (ctrl.Result, error) { + r.Log.Info(fmt.Sprintf("[API] Reconciling Service '%s'", instance.Name)) + + configVars := make(map[string]env.Setter) + + // + // check for required OpenStack secret holding passwords for service/admin user and add hash to the vars map + // + r.Log.Info(fmt.Sprintf("[API] Get secret 1 '%s'", instance.Name)) + ctrlResult, err := r.getSecret(ctx, helper, instance, instance.Spec.Secret, &configVars) + if err != nil { + return ctrlResult, err + } + + // + // check for required TransportURL secret holding transport URL string + // + r.Log.Info(fmt.Sprintf("[API] Get secret 2 '%s'", instance.Spec.TransportURLSecret)) + ctrlResult, err = r.getSecret(ctx, helper, instance, instance.Spec.TransportURLSecret, &configVars) + if err != nil { + return ctrlResult, err + } + + // TODO (alee) cinder has some code here to retrieve secrets from the parent CR + // Seems like we may want this instead + + // TODO (alee) cinder has some code to retrieve CustomServiceConfigSecrets + // This seems like a great place to store things like HSM passwords + + r.Log.Info(fmt.Sprintf("[API] Got secrets '%s'", instance.Name)) + // + // create custom config for this barbican service + // + err = r.generateServiceConfigs(ctx, helper, instance, &configVars) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.ServiceConfigReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.ServiceConfigReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } + + r.Log.Info(fmt.Sprintf("[API] Getting input hash '%s'", instance.Name)) + // + // create hash over all the different input resources to identify if any those changed + // and a restart/recreate is required. + // + inputHash, hashChanged, err := r.createHashOfInputHashes(ctx, instance, configVars) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.ServiceConfigReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.ServiceConfigReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } else if hashChanged { + // Hash changed and instance status should be updated (which will be done by main defer func), + // so we need to return and reconcile again + return ctrl.Result{}, nil + } + instance.Status.Conditions.MarkTrue(condition.ServiceConfigReadyCondition, condition.ServiceConfigReadyMessage) + + r.Log.Info(fmt.Sprintf("[API] Getting service labels '%s'", instance.Name)) + serviceLabels := map[string]string{ + common.AppSelector: fmt.Sprintf(barbican.ServiceName), + } + + r.Log.Info(fmt.Sprintf("[API] Getting networks '%s'", instance.Name)) + // networks to attach to + for _, netAtt := range instance.Spec.NetworkAttachments { + _, err := nad.GetNADWithName(ctx, helper, netAtt, instance.Namespace) + if err != nil { + if k8s_errors.IsNotFound(err) { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.NetworkAttachmentsReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.NetworkAttachmentsReadyWaitingMessage, + netAtt)) + return ctrl.Result{RequeueAfter: time.Second * 10}, fmt.Errorf("network-attachment-definition %s not found", netAtt) + } + instance.Status.Conditions.Set(condition.FalseCondition( + condition.NetworkAttachmentsReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.NetworkAttachmentsReadyErrorMessage, + err.Error())) + return ctrl.Result{}, err + } + } + + r.Log.Info(fmt.Sprintf("[API] Getting service annotations '%s'", instance.Name)) + serviceAnnotations, err := nad.CreateNetworksAnnotation(instance.Namespace, instance.Spec.NetworkAttachments) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed create network annotation from %s: %w", + instance.Spec.NetworkAttachments, err) + } + + r.Log.Info(fmt.Sprintf("[API] Defining deployment '%s'", instance.Name)) + // Define a new Deployment object + deplDef := barbicanapi.Deployment(instance, inputHash, serviceLabels, serviceAnnotations) + r.Log.Info(fmt.Sprintf("[API] Getting deployment '%s'", instance.Name)) + depl := deployment.NewDeployment( + deplDef, + time.Duration(5)*time.Second, + ) + r.Log.Info(fmt.Sprintf("[API] Got deployment '%s'", instance.Name)) + ctrlResult, err = depl.CreateOrPatch(ctx, helper) + if err != nil { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.DeploymentReadyErrorMessage, + err.Error())) + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + instance.Status.Conditions.Set(condition.FalseCondition( + condition.DeploymentReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + condition.DeploymentReadyRunningMessage)) + return ctrlResult, nil + } + instance.Status.ReadyCount = depl.GetDeployment().Status.ReadyReplicas + + // verify if network attachment matches expectations + networkReady, networkAttachmentStatus, err := nad.VerifyNetworkStatusFromAnnotation(ctx, helper, instance.Spec.NetworkAttachments, serviceLabels, instance.Status.ReadyCount) + if err != nil { + return ctrl.Result{}, err + } + + instance.Status.NetworkAttachments = networkAttachmentStatus + if networkReady { + instance.Status.Conditions.MarkTrue(condition.NetworkAttachmentsReadyCondition, condition.NetworkAttachmentsReadyMessage) + } else { + err := fmt.Errorf("not all pods have interfaces with ips as configured in NetworkAttachments: %s", instance.Spec.NetworkAttachments) + instance.Status.Conditions.Set(condition.FalseCondition( + condition.NetworkAttachmentsReadyCondition, + condition.ErrorReason, + condition.SeverityWarning, + condition.NetworkAttachmentsReadyErrorMessage, + err.Error())) + + return ctrl.Result{}, err + } + + if instance.Status.ReadyCount > 0 { + instance.Status.Conditions.MarkTrue(condition.DeploymentReadyCondition, condition.DeploymentReadyMessage) + } + // create Deployment - end + r.Log.Info(fmt.Sprintf("Reconciled Service '%s' in barbicanAPI successfully", instance.Name)) return ctrl.Result{}, nil } diff --git a/main.go b/main.go index 98b3491..01b9d70 100644 --- a/main.go +++ b/main.go @@ -113,22 +113,22 @@ func main() { os.Exit(1) } - if err = (&controllers.BarbicanAPIReconciler{ + if err = (&controllers.BarbicanReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), Kclient: kclient, - Log: ctrl.Log.WithName("controllers").WithName("BarbicanAPI"), + Log: ctrl.Log.WithName("controllers").WithName("Barbican"), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "BarbicanAPI") + setupLog.Error(err, "unable to create controller", "controller", "Barbican") os.Exit(1) } - if err = (&controllers.BarbicanReconciler{ + if err = (&controllers.BarbicanAPIReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), Kclient: kclient, - Log: ctrl.Log.WithName("controllers").WithName("Barbican"), + Log: ctrl.Log.WithName("controllers").WithName("BarbicanAPI"), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Barbican") + setupLog.Error(err, "unable to create controller", "controller", "BarbicanAPI") os.Exit(1) } if err = (&controllers.BarbicanWorkerReconciler{ diff --git a/pkg/barbican/const.go b/pkg/barbican/const.go index c82f3de..6548e98 100644 --- a/pkg/barbican/const.go +++ b/pkg/barbican/const.go @@ -1,10 +1,38 @@ package barbican +import "github.com/openstack-k8s-operators/lib-common/modules/storage" + const ( // ServiceName - ServiceName = "barbican" // DatabaseName - DatabaseName = "barbican" - // KollaConfigDbSync - - KollaConfigDbSync = "/var/lib/config-data/merged/barbican-config.json" + // BarbicanPublicPort - + BarbicanPublicPort int32 = 9311 + // DefaultsConfigFileName - + DefaultsConfigFileName = "00-default.conf" + // CustomConfigFileName - + CustomConfigFileName = "01-custom.conf" + // CustomServiceConfigFileName - + CustomServiceConfigFileName = "02-service.conf" + // CustomServiceConfigSecretsFileName - + CustomServiceConfigSecretsFileName = "03-secrets.conf" + // BarbicanAPI defines the barbican-api group + BarbicanAPI storage.PropagationType = "BarbicanAPI" + // Barbican is the global ServiceType that refers to all the components deployed + // by the barbican operator + Barbican storage.PropagationType = "Barbican" + // BarbicanLogPath is the path used by BarbicanAPI to stream/store its logs + BarbicanLogPath = "/var/log/barbican/" + // LogVolume is the default logVolume name used to mount logs on both + // BarbicanAPI and the sidecar container + LogVolume = "logs" ) + +// DbsyncPropagation keeps track of the DBSync Service Propagation Type +var DbsyncPropagation = []storage.PropagationType{storage.DBSync} + +// BarbicanAPIPropagation is the definition of the BarbicanAPI propagation group +// It allows the BarbicanAPI pod to mount volumes destined to Barbican related +// ServiceTypes +var BarbicanAPIPropagation = []storage.PropagationType{Barbican, BarbicanAPI} diff --git a/pkg/barbican/dbsync.go b/pkg/barbican/dbsync.go index 0de0ef2..0ecf75c 100644 --- a/pkg/barbican/dbsync.go +++ b/pkg/barbican/dbsync.go @@ -5,7 +5,6 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/env" - "github.com/openstack-k8s-operators/lib-common/modules/storage" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -13,16 +12,53 @@ import ( const ( // DBSyncCommand - - DBSyncCommand = "/usr/local/bin/kolla_set_configs && su -s /bin/sh -c \"barbican-manage db upgrade\"" + DBSyncCommand = "/usr/local/bin/kolla_set_configs && /usr/local/bin/kolla_start" ) -// DbsyncPropagation keeps track of the DBSync Service Propagation Type -var DbsyncPropagation = []storage.PropagationType{storage.DBSync} - // DbSyncJob func func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, annotations map[string]string) *batchv1.Job { secretNames := []string{} + var config0644AccessMode int32 = 0644 + + // Unlike the individual Barbican services, the DbSyncJob doesn't need a + // secret that contains all of the config snippets required by every + // service, The two snippet files that it does need (DefaultsConfigFileName + // and CustomConfigFileName) can be extracted from the top-level barbican + // config-data secret. + dbSyncVolume := corev1.Volume{ + Name: "db-sync-config-data", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: &config0644AccessMode, + SecretName: instance.Name + "-config-data", + Items: []corev1.KeyToPath{ + { + Key: DefaultsConfigFileName, + Path: DefaultsConfigFileName, + }, + { + Key: CustomConfigFileName, + Path: CustomConfigFileName, + }, + }, + }, + }, + } + + dbSyncMounts := []corev1.VolumeMount{ + { + Name: "db-sync-config-data", + MountPath: "/etc/barbican/barbican.conf.d", + ReadOnly: true, + }, + { + Name: "config-data", + MountPath: "/var/lib/kolla/config_files/config.json", + SubPath: "barbican-dbsync-config.json", + ReadOnly: true, + }, + } args := []string{"-c"} if instance.Spec.Debug.DBSync { args = append(args, common.DebugCommand) @@ -32,7 +68,6 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann runAsUser := int64(0) envVars := map[string]env.Setter{} - envVars["KOLLA_CONFIG_FILE"] = env.SetValue(KollaConfigDbSync) envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") envVars["KOLLA_BOOTSTRAP"] = env.SetValue("TRUE") @@ -61,8 +96,9 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann SecurityContext: &corev1.SecurityContext{ RunAsUser: &runAsUser, }, - Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - VolumeMounts: GetVolumeMounts(secretNames, DbsyncPropagation), + Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), + VolumeMounts: append(GetVolumeMounts(secretNames, DbsyncPropagation), + dbSyncMounts...), }, }, }, @@ -70,24 +106,13 @@ func DbSyncJob(instance *barbicanv1beta1.Barbican, labels map[string]string, ann }, } - job.Spec.Template.Spec.Volumes = GetVolumes( + job.Spec.Template.Spec.Volumes = append(GetVolumes( instance.Name, ServiceName, secretNames, - DbsyncPropagation, + DbsyncPropagation), + dbSyncVolume, ) - initContainerDetails := APIDetails{ - ContainerImage: instance.Spec.BarbicanAPI.ContainerImage, - DatabaseHost: instance.Status.DatabaseHostname, - DatabaseUser: instance.Spec.DatabaseUser, - DatabaseName: DatabaseName, - OSPSecret: instance.Spec.Secret, - DBPasswordSelector: instance.Spec.PasswordSelectors.Database, - UserPasswordSelector: instance.Spec.PasswordSelectors.Service, - VolumeMounts: GetInitVolumeMounts(secretNames, DbsyncPropagation), - } - job.Spec.Template.Spec.InitContainers = InitContainer(initContainerDetails) - return job } diff --git a/pkg/barbican/initcontainer.go b/pkg/barbican/initcontainer.go deleted file mode 100644 index 7fdb2f8..0000000 --- a/pkg/barbican/initcontainer.go +++ /dev/null @@ -1,92 +0,0 @@ -package barbican - -import ( - "github.com/openstack-k8s-operators/lib-common/modules/common/env" - corev1 "k8s.io/api/core/v1" -) - -// APIDetails information -type APIDetails struct { - ContainerImage string - DatabaseHost string - DatabaseUser string - DatabaseName string - TransportURL string - OSPSecret string - DBPasswordSelector string - UserPasswordSelector string - VolumeMounts []corev1.VolumeMount -} - -const ( - // InitContainerCommand - - InitContainerCommand = "/usr/local/bin/container-scripts/init.sh" -) - -// InitContainer - init container for barbican api pods -func InitContainer(init APIDetails) []corev1.Container { - runAsUser := int64(0) - - args := []string{ - "-c", - InitContainerCommand, - } - - envVars := map[string]env.Setter{} - envVars["DatabaseHost"] = env.SetValue(init.DatabaseHost) - envVars["DatabaseUser"] = env.SetValue(init.DatabaseUser) - envVars["DatabaseName"] = env.SetValue(init.DatabaseName) - - envs := []corev1.EnvVar{ - { - Name: "DatabasePassword", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: init.OSPSecret, - }, - Key: init.DBPasswordSelector, - }, - }, - }, - { - Name: "BarbicanPassword", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: init.OSPSecret, - }, - Key: init.UserPasswordSelector, - }, - }, - }, - // TODO - // { - // Name: "TransportUrl", - // ValueFrom: &corev1.EnvVarSource{ - // SecretKeyRef: &corev1.SecretKeySelector{ - // LocalObjectReference: corev1.LocalObjectReference{ - // Name: init.OSPSecret, - // }, - // Key: "TransportUrl", - // }, - // }, - // }, - } - envs = env.MergeEnvs(envs, envVars) - return []corev1.Container{ - { - Name: "init", - Image: init.ContainerImage, - SecurityContext: &corev1.SecurityContext{ - RunAsUser: &runAsUser, - }, - Command: []string{ - "/bin/bash", - }, - Args: args, - Env: envs, - VolumeMounts: init.VolumeMounts, - }, - } -} diff --git a/pkg/barbican/volumes.go b/pkg/barbican/volumes.go index bf5e060..a93141b 100644 --- a/pkg/barbican/volumes.go +++ b/pkg/barbican/volumes.go @@ -9,38 +9,18 @@ import ( // GetVolumes - service volumes func GetVolumes(name string, pvcName string, secretNames []string, svc []storage.PropagationType) []corev1.Volume { - var scriptsVolumeDefaultMode int32 = 0755 - var config0640AccessMode int32 = 0640 + var config0644AccessMode int32 = 0644 vm := []corev1.Volume{ - { - Name: "scripts", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - DefaultMode: &scriptsVolumeDefaultMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-scripts", - }, - }, - }, - }, { Name: "config-data", VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - DefaultMode: &config0640AccessMode, - LocalObjectReference: corev1.LocalObjectReference{ - Name: name + "-config-data", - }, + Secret: &corev1.SecretVolumeSource{ + DefaultMode: &config0644AccessMode, + SecretName: name + "-config-data", }, }, }, - { - Name: "config-data-merged", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{Medium: ""}, - }, - }, } secretConfig, _ := GetConfigSecretVolumes(secretNames) @@ -48,45 +28,15 @@ func GetVolumes(name string, pvcName string, secretNames []string, svc []storage return vm } -// GetInitVolumeMounts - general init task VolumeMounts -func GetInitVolumeMounts(secretNames []string, svc []storage.PropagationType) []corev1.VolumeMount { - vm := []corev1.VolumeMount{ - { - Name: "scripts", - MountPath: "/usr/local/bin/container-scripts", - ReadOnly: true, - }, - { - Name: "config-data", - MountPath: "/var/lib/config-data/default", - ReadOnly: true, - }, - { - Name: "config-data-merged", - MountPath: "/var/lib/config-data/merged", - ReadOnly: false, - }, - } - - _, secretConfig := GetConfigSecretVolumes(secretNames) - vm = append(vm, secretConfig...) - return vm -} - // GetVolumeMounts - general VolumeMounts func GetVolumeMounts(secretNames []string, svc []storage.PropagationType) []corev1.VolumeMount { vm := []corev1.VolumeMount{ { - Name: "scripts", - MountPath: "/usr/local/bin/container-scripts", + Name: "config-data", + MountPath: "/var/lib/config-data/default", ReadOnly: true, }, - { - Name: "config-data-merged", - MountPath: "/var/lib/config-data/merged", - ReadOnly: false, - }, } _, secretConfig := GetConfigSecretVolumes(secretNames) @@ -122,3 +72,26 @@ func GetConfigSecretVolumes(secretNames []string) ([]corev1.Volume, []corev1.Vol return secretVolumes, secretMounts } + +// GetLogVolumeMount - Returns the VolumeMount used for logging purposes +func GetLogVolumeMount() []corev1.VolumeMount { + return []corev1.VolumeMount{ + { + Name: LogVolume, + MountPath: "/var/log/barbican", + ReadOnly: false, + }, + } +} + +// GetLogVolume - Returns the Volume used for logging purposes +func GetLogVolume() []corev1.Volume { + return []corev1.Volume{ + { + Name: LogVolume, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{Medium: ""}, + }, + }, + } +} diff --git a/pkg/barbicanapi/deployment.go b/pkg/barbicanapi/deployment.go new file mode 100644 index 0000000..f3bfaa6 --- /dev/null +++ b/pkg/barbicanapi/deployment.go @@ -0,0 +1,160 @@ +package barbicanapi + +import ( + "fmt" + + "github.com/openstack-k8s-operators/lib-common/modules/common" + "github.com/openstack-k8s-operators/lib-common/modules/common/env" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + + barbicanv1beta1 "github.com/openstack-k8s-operators/barbican-operator/api/v1beta1" + barbican "github.com/openstack-k8s-operators/barbican-operator/pkg/barbican" +) + +const ( + // ServiceCommand - + ServiceCommand = "/usr/local/bin/kolla_set_configs && /usr/local/bin/kolla_start" +) + +// Deployment - returns a BarbicanAPI Deployment +func Deployment( + instance *barbicanv1beta1.BarbicanAPI, + configHash string, + labels map[string]string, + annotations map[string]string, +) *appsv1.Deployment { + runAsUser := int64(0) + var config0644AccessMode int32 = 0644 + envVars := map[string]env.Setter{} + envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") + envVars["CONFIG_HASH"] = env.SetValue(configHash) + livenessProbe := &corev1.Probe{ + // TODO might need tuning + TimeoutSeconds: 5, + PeriodSeconds: 3, + InitialDelaySeconds: 5, + } + readinessProbe := &corev1.Probe{ + // TODO might need tuning + TimeoutSeconds: 5, + PeriodSeconds: 5, + InitialDelaySeconds: 5, + } + args := []string{"-c"} + if instance.Spec.Debug.Service { + args = append(args, common.DebugCommand) + livenessProbe.Exec = &corev1.ExecAction{ + Command: []string{ + "/bin/true", + }, + } + readinessProbe.Exec = livenessProbe.Exec + } else { + args = append(args, ServiceCommand) + // + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ + // + livenessProbe.HTTPGet = &corev1.HTTPGetAction{ + Path: "/healthcheck", + Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(barbican.BarbicanPublicPort)}, + } + readinessProbe.HTTPGet = livenessProbe.HTTPGet + } + + apiVolumes := []corev1.Volume{ + { + Name: "config-data-custom", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: &config0644AccessMode, + SecretName: instance.Name + "-config-data", + }, + }, + }, + } + + apiVolumes = append(apiVolumes, barbican.GetLogVolume()...) + apiVolumeMounts := []corev1.VolumeMount{ + { + Name: "config-data", + MountPath: "/var/lib/kolla/config_files/config.json", + SubPath: "barbican-api-config.json", + ReadOnly: true, + }, + } + // Append LogVolume to the apiVolumes: this will be used to stream + // logging + apiVolumeMounts = append(apiVolumeMounts, barbican.GetLogVolumeMount()...) + + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-api", instance.Name), + Namespace: instance.Namespace, + Labels: labels, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Replicas: instance.Spec.Replicas, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: annotations, + Labels: labels, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: instance.Spec.ServiceAccount, + Containers: []corev1.Container{ + { + Name: instance.Name + "-log", + Command: []string{ + "/bin/bash", + }, + Args: []string{"-c", "tail -n+1 -F " + barbican.BarbicanLogPath + instance.Name + ".log"}, + Image: instance.Spec.ContainerImage, + SecurityContext: &corev1.SecurityContext{ + RunAsUser: &runAsUser, + }, + Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), + VolumeMounts: barbican.GetLogVolumeMount(), + Resources: instance.Spec.Resources, + ReadinessProbe: readinessProbe, + LivenessProbe: livenessProbe, + }, + { + Name: barbican.ServiceName + "-api", + Command: []string{ + "/bin/bash", + }, + Args: args, + Image: instance.Spec.ContainerImage, + SecurityContext: &corev1.SecurityContext{ + RunAsUser: &runAsUser, + }, + Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), + VolumeMounts: append(barbican.GetVolumeMounts( + instance.Spec.CustomServiceConfigSecrets, + barbican.BarbicanAPIPropagation), + apiVolumeMounts..., + ), + Resources: instance.Spec.Resources, + ReadinessProbe: readinessProbe, + LivenessProbe: livenessProbe, + }, + }, + }, + }, + }, + } + deployment.Spec.Template.Spec.Volumes = append(barbican.GetVolumes( + instance.Name, + barbican.ServiceName, + instance.Spec.CustomServiceConfigSecrets, + barbican.BarbicanAPIPropagation), + apiVolumes...) + + return deployment +} diff --git a/templates/barbican/bin/init.sh b/templates/barbican/bin/init.sh deleted file mode 100755 index 800d992..0000000 --- a/templates/barbican/bin/init.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin//bash -# -# Copyright 2020 Red Hat Inc. -# -# 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. -set -ex - -# This script generates the barbican.conf file and -# copies the result to the ephemeral /var/lib/config-data/merged volume. - -export PASSWORD=${BarbicanPassword:?"Please specify a BarbicanPassword variable."} -export DBHOST=${DatabaseHost:?"Please specify a DatabaseHost variable."} -export DBUSER=${DatabaseUser:-"barbican"} -export DB=${DatabaseName:-"barbican"} -export DBPASSWORD=${DatabasePassword:?"Please specify a DatabasePassword variable."} - - -DEFAULT_DIR=/var/lib/config-data/default -CUSTOM_DIR=/var/lib/config-data/custom -MERGED_DIR=/var/lib/config-data/merged -SVC_CFG=/etc/barbican/barbican.conf -SVC_CFG_MERGED=${MERGED_DIR}/barbican.conf -SVC_CFG_MERGED_DIR=${MERGED_DIR}/barbican.conf.d - -mkdir -p ${SVC_CFG_MERGED_DIR} - -cp ${DEFAULT_DIR}/* ${MERGED_DIR} - -# Save the default service config from container image as barbican.conf.sample, -# and create a small barbican.conf file that directs people to files in -# barbican.conf.d. - -cp -a ${SVC_CFG} ${SVC_CFG_MERGED}.sample -cat < ${SVC_CFG_MERGED} -# Service configuration snippets are stored in the barbican.conf.d subdirectory. -EOF - -cp ${DEFAULT_DIR}/barbican.conf ${SVC_CFG_MERGED_DIR}/00-default.conf - -# Generate 01-deployment-secrets.conf -DEPLOYMENT_SECRETS=${SVC_CFG_MERGED_DIR}/01-deployment-secrets.conf - -cat <> ${DEPLOYMENT_SECRETS} -[DEFAULT] -sql_connection = mysql+pymysql://${DBUSER}:${DBPASSWORD}@${DBHOST}/${DB} - -[keystone_authtoken] -password = ${PASSWORD} - -EOF - -if [ -f ${DEFAULT_DIR}/custom.conf ]; then - cp ${DEFAULT_DIR}/custom.conf ${SVC_CFG_MERGED_DIR}/80-custom.conf -fi - -SECRET_FILES="$(ls /var/lib/config-data/secret-*/* 2>/dev/null || true)" -if [ -n "${SECRET_FILES}" ]; then - cat ${SECRET_FILES} > ${SVC_CFG_MERGED_DIR}/90-secrets.conf -fi - -chown -R :barbican ${SVC_CFG_MERGED_DIR} diff --git a/templates/barbican/config/00-default.conf b/templates/barbican/config/00-default.conf new file mode 100644 index 0000000..4bcce2e --- /dev/null +++ b/templates/barbican/config/00-default.conf @@ -0,0 +1,45 @@ +[DEFAULT] +sql_connection = {{ .DatabaseConnection }} +host_href = {{ .ServiceURL }} +debug = true +transport_url = {{ .TransportURL }} + +[keystone_authtoken] +auth_version = v3 +auth_url={{ .KeystoneAuthURL }} +auth_type=password +username={{ .ServiceUser }} +user_domain_name=Default +password = {{ .ServicePassword }} +project_name=service +project_domain_name=Default +interface = internal + +[keystone_notifications] +enable = false +topic = notifications + +[oslo_messaging_notifications] +# TODO: update later once rabbit is working +#driver=messagingv2 +driver=noop + +[oslo_policy] +enforce_scope = true +enforce_new_defaults = true + +[queue] +enable = true + +[secretstore] +enable_multiple_secret_stores = true +stores_lookup_suffix = simple_crypto + +[secretstore:simple_crypto] +secret_store_plugin = store_crypto +crypto_plugin = simple_crypto +global_default = true + +[simple_crypto_plugin] +plugin_name = Software Only Crypto +kek = dGhpcnR5X3R3b19ieXRlX2tleWJsYWhibGFoYmxhaGg= diff --git a/templates/barbican/config/barbican-api-config.json b/templates/barbican/config/barbican-api-config.json new file mode 100644 index 0000000..60dad71 --- /dev/null +++ b/templates/barbican/config/barbican-api-config.json @@ -0,0 +1,32 @@ +{ + "command": "uwsgi --master --emperor /etc/barbican/vassals --logto /var/log/kolla/barbican/barbican_api_uwsgi_access.log --logfile-chmod 644", + "config_files": [ + { + "source": "/var/lib/config-data/default/00-default.conf", + "dest": "/etc/barbican/barbican.conf.d/00-default.conf", + "owner": "barbican", + "perm": "0600" + }, + { + "source": "/var/lib/config-data/default/02-service.conf", + "dest": "/etc/barbican/barbican.conf.d/02-service.conf", + "owner": "barbican", + "perm": "0600", + "optional": true + }, + { + "source": "/var/lib/config-data/default/03-secrets.conf", + "dest": "/etc/barbican/barbican.conf.d/03-secrets.conf", + "owner": "barbican", + "perm": "0640", + "optional": true + } + ], + "permissions": [ + { + "path": "/var/log/barbican", + "owner": "barbican:barbican", + "recurse": true + } + ] +} diff --git a/templates/barbican/config/barbican-config.json b/templates/barbican/config/barbican-config.json deleted file mode 100644 index 3995943..0000000 --- a/templates/barbican/config/barbican-config.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "command": "/usr/bin/barbican-api --config-dir /etc/barbican/barbican.conf.d", - "config_files": [ - { - "source": "/var/lib/config-data/merged/barbican.conf.d", - "dest": "/etc/barbican/barbican.conf.d", - "owner": "barbican", - "perm": "0750" - }, - { - "source": "/var/lib/config-data/merged/logging.conf", - "dest": "/etc/barbican/logging.conf", - "owner": "barbican", - "perm": "0600" - } - ] -} diff --git a/templates/barbican/config/barbican-dbsync-config.json b/templates/barbican/config/barbican-dbsync-config.json new file mode 100644 index 0000000..1282e1f --- /dev/null +++ b/templates/barbican/config/barbican-dbsync-config.json @@ -0,0 +1,3 @@ +{ + "command": "barbican-manage db upgrade" +} diff --git a/templates/barbican/config/barbican.conf b/templates/barbican/config/barbican.conf deleted file mode 100644 index 1200632..0000000 --- a/templates/barbican/config/barbican.conf +++ /dev/null @@ -1,20 +0,0 @@ -[DEFAULT] -log_config_append=/etc/barbican/logging.conf - -[keystone_authtoken] -{{ if (index . "KeystoneAuthURL") }} -auth_uri={{ .KeystoneAuthURL }} -auth_url={{ .KeystoneAuthURL }} -{{ end }} -auth_type=password -{{ if (index . "ServiceUser") }} -username={{ .ServiceUser }} -{{ end }} -project_domain_name=Default -user_domain_name=Default -project_name=service - -[oslo_messaging_notifications] -# TODO: update later once rabbit is working -#driver=messagingv2 -driver=noop diff --git a/templates/barbicanapi b/templates/barbicanapi new file mode 120000 index 0000000..cded8ff --- /dev/null +++ b/templates/barbicanapi @@ -0,0 +1 @@ +barbican \ No newline at end of file