Skip to content

Commit

Permalink
Create the Keystone service for Watcher service
Browse files Browse the repository at this point in the history
This patch is registrating the Keystone service for Watcher using the
KeystoneService CRD managed by keystone-operator. It also adds the
condition KeystoneServiceReadyCondition.

It adds functional envtests for the new feature.
  • Loading branch information
amoralej committed Dec 13, 2024
1 parent 214e8bd commit 759a7d3
Show file tree
Hide file tree
Showing 15 changed files with 388 additions and 21 deletions.
5 changes: 5 additions & 0 deletions api/bases/watcher.openstack.org_watcherapis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ spec:
default: osp-secret
description: Secret containing all passwords / keys needed
type: string
serviceUser:
default: watcher
description: ServiceUser - optional username used for this service
to register in keystone
type: string
required:
- databaseInstance
type: object
Expand Down
8 changes: 8 additions & 0 deletions api/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ spec:
default: osp-secret
description: Secret containing all passwords / keys needed
type: string
serviceUser:
default: watcher
description: ServiceUser - optional username used for this service
to register in keystone
type: string
required:
- databaseInstance
- rabbitMqClusterName
Expand Down Expand Up @@ -128,6 +133,9 @@ spec:
the opentack-operator in the top-level CR (e.g. the ContainerImage)
format: int64
type: integer
serviceID:
description: ServiceID
type: string
type: object
type: object
served: true
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ type WatcherCommon struct {
// Secret containing all passwords / keys needed
Secret string `json:"secret"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=watcher
// ServiceUser - optional username used for this service to register in keystone
ServiceUser string `json:"serviceUser"`

// +kubebuilder:validation:Optional
// +kubebuilder:default={service: WatcherPassword,}
// PasswordSelectors - Selectors to identify the ServiceUser password from the Secret
Expand Down
3 changes: 3 additions & 0 deletions api/v1beta1/watcher_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type WatcherStatus struct {
// Conditions
Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"`

// ServiceID
ServiceID string `json:"serviceID,omitempty"`

// ObservedGeneration - the most recent generation observed for this
// service. If the observed generation is less than the spec generation,
// then the controller has not processed the latest changes injected by
Expand Down
5 changes: 5 additions & 0 deletions config/crd/bases/watcher.openstack.org_watcherapis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ spec:
default: osp-secret
description: Secret containing all passwords / keys needed
type: string
serviceUser:
default: watcher
description: ServiceUser - optional username used for this service
to register in keystone
type: string
required:
- databaseInstance
type: object
Expand Down
8 changes: 8 additions & 0 deletions config/crd/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ spec:
default: osp-secret
description: Secret containing all passwords / keys needed
type: string
serviceUser:
default: watcher
description: ServiceUser - optional username used for this service
to register in keystone
type: string
required:
- databaseInstance
- rabbitMqClusterName
Expand Down Expand Up @@ -128,6 +133,9 @@ spec:
the opentack-operator in the top-level CR (e.g. the ContainerImage)
format: int64
type: integer
serviceID:
description: ServiceID
type: string
type: object
type: object
served: true
Expand Down
24 changes: 24 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ rules:
- patch
- update
- watch
- apiGroups:
- keystone.openstack.org
resources:
- keystoneendpoints
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- keystone.openstack.org
resources:
- keystoneservices
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- mariadb.openstack.org
resources:
Expand Down
101 changes: 101 additions & 0 deletions controllers/watcher_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package controllers

import (
"context"
"errors"
"fmt"
"time"

Expand All @@ -29,6 +30,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"

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/helper"
Expand Down Expand Up @@ -70,6 +72,8 @@ func (r *WatcherReconciler) GetLogger(ctx context.Context) logr.Logger {
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete;
//+kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete;
//+kubebuilder:rbac:groups=rabbitmq.openstack.org,resources=transporturls,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneservices,verbs=get;list;watch;create;update;patch;delete;
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneendpoints,verbs=get;list;watch;create;update;patch;delete;

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
Expand Down Expand Up @@ -189,6 +193,19 @@ func (r *WatcherReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re
_ = op
// end of TransportURL creation

// Create Keystone Service creation. The endpoint will be created by WatcherAPI
_, err = r.ensureKeystoneSvc(ctx, helper, instance, serviceLabels)

if err != nil {
return ctrl.Result{}, err
}

// End of Keystone service creation

// If ensureKeystoneSvc succeeds means that secrets are correct so let set InputReady to True
// We may need to move this to a more specific logic to check Inputs later.
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)

// remove finalizers from unused MariaDBAccount records
// this assumes all database-depedendent deployments are up and
// running with current database account info
Expand Down Expand Up @@ -240,6 +257,10 @@ func (r *WatcherReconciler) initConditions(instance *watcherv1beta1.Watcher) err
watcherv1beta1.WatcherRabbitMQTransportURLReadyCondition,
condition.InitReason,
condition.RabbitMqTransportURLReadyInitMessage),
condition.UnknownCondition(
condition.KeystoneServiceReadyCondition,
condition.InitReason,
"Service registration not started"),
)

instance.Status.Conditions.Init(&cl)
Expand Down Expand Up @@ -392,6 +413,69 @@ func (r *WatcherReconciler) ensureMQ(
return transportURL, op, nil
}

func (r *WatcherReconciler) ensureKeystoneSvc(
ctx context.Context,
h *helper.Helper,
instance *watcherv1beta1.Watcher,
serviceLabels map[string]string,
) (ctrl.Result, error) {
Log := r.GetLogger(ctx)
Log.Info(fmt.Sprintf("Reconciling the Keystone Service for '%s'", instance.Name))

//
// create Keystone service and user
//
hash, _, _, err := ensureSecret(
ctx,
types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret},
[]string{
instance.Spec.PasswordSelectors.Service,
},
h.GetClient(),
&instance.Status.Conditions,
r.RequeueTimeout,
)
if err != nil || hash == "" {
// Empty hash means that there is some problem retrieving the key from the secret
return ctrl.Result{}, errors.New("error retrieving required data from secret")
}

ksSvcSpec := keystonev1.KeystoneServiceSpec{
ServiceType: watcher.ServiceType,
ServiceName: watcher.ServiceName,
ServiceDescription: "Watcher Service",
Enabled: true,
ServiceUser: instance.Spec.ServiceUser,
Secret: instance.Spec.Secret,
PasswordSelector: instance.Spec.PasswordSelectors.Service,
}

ksSvc := keystonev1.NewKeystoneService(ksSvcSpec, instance.Namespace, serviceLabels, time.Duration(10)*time.Second)
ctrlResult, err := ksSvc.CreateOrPatch(ctx, h)
if err != nil {
return ctrlResult, err
}

// mirror the Status, Reason, Severity and Message of the latest keystoneservice condition
// into a local condition with the type condition.KeystoneServiceReadyCondition
c := ksSvc.GetConditions().Mirror(condition.KeystoneServiceReadyCondition)
if c != nil {
instance.Status.Conditions.Set(c)
}

if (ctrlResult != ctrl.Result{}) {
return ctrlResult, nil
}

instance.Status.ServiceID = ksSvc.GetServiceID()

//if instance.Status.Hash == nil {
// instance.Status.Hash = map[string]string{}
//}

return ctrlResult, nil
}

func (r *WatcherReconciler) reconcileDelete(ctx context.Context, instance *watcherv1beta1.Watcher, helper *helper.Helper) (ctrl.Result, error) {
Log := r.GetLogger(ctx)
Log.Info(fmt.Sprintf("Reconcile Service '%s' delete started", instance.Name))
Expand All @@ -408,6 +492,22 @@ func (r *WatcherReconciler) reconcileDelete(ctx context.Context, instance *watch
}
}

// Remove the finalizer from our KeystoneService CR
keystoneService, err := keystonev1.GetKeystoneServiceWithName(ctx, helper, watcher.ServiceName, instance.Namespace)
if err != nil && !k8s_errors.IsNotFound(err) {
return ctrl.Result{}, err
}

if err == nil {
if controllerutil.RemoveFinalizer(keystoneService, helper.GetFinalizer()) {
err = helper.GetClient().Update(ctx, keystoneService)
if err != nil && !k8s_errors.IsNotFound(err) {
return ctrl.Result{}, err
}
util.LogForObject(helper, "Removed finalizer from our KeystoneService", instance)
}
}

controllerutil.RemoveFinalizer(instance, helper.GetFinalizer())
Log.Info(fmt.Sprintf("Reconciled Service '%s' delete successfully", instance.Name))
return ctrl.Result{}, nil
Expand All @@ -423,5 +523,6 @@ func (r *WatcherReconciler) SetupWithManager(mgr ctrl.Manager) error {
Owns(&mariadbv1.MariaDBDatabase{}).
Owns(&mariadbv1.MariaDBAccount{}).
Owns(&rabbitmqv1.TransportURL{}).
Owns(&keystonev1.KeystoneService{}).
Complete(r)
}
17 changes: 10 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ require (
github.com/onsi/ginkgo/v2 v2.20.1
github.com/onsi/gomega v1.34.1
github.com/openstack-k8s-operators/infra-operator/apis v0.5.0
github.com/openstack-k8s-operators/lib-common/modules/common v0.5.0
github.com/openstack-k8s-operators/lib-common/modules/test v0.5.0
github.com/openstack-k8s-operators/keystone-operator/api v0.5.1-0.20241023160107-bd8e671350e1
github.com/openstack-k8s-operators/lib-common/modules/common v0.5.1-0.20241029151503-4878b3fa3333
github.com/openstack-k8s-operators/lib-common/modules/test v0.5.1-0.20241029151503-4878b3fa3333
github.com/openstack-k8s-operators/mariadb-operator/api v0.5.0
go.uber.org/zap v1.27.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.29.9
k8s.io/apimachinery v0.29.9
k8s.io/client-go v0.29.9
k8s.io/api v0.29.10
k8s.io/apimachinery v0.29.10
k8s.io/client-go v0.29.10
sigs.k8s.io/controller-runtime v0.17.6
)

Expand All @@ -38,6 +39,7 @@ require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/gophercloud/gophercloud v1.14.1 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
Expand All @@ -47,6 +49,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openshift/api v3.9.0+incompatible // indirect
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.5.1-0.20241029151503-4878b3fa3333 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
Expand All @@ -68,8 +71,8 @@ require (
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiextensions-apiserver v0.29.9 // indirect
k8s.io/component-base v0.29.9 // indirect
k8s.io/apiextensions-apiserver v0.29.10 // indirect
k8s.io/component-base v0.29.10 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
Expand Down
Loading

0 comments on commit 759a7d3

Please sign in to comment.