Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial watcher api conf generation #27

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -49,6 +49,11 @@ spec:
MariaDB instance name
Required to use the mariadb-operator instance to create the DB and user
type: string
memcachedInstance:
default: memcached
description: MemcachedInstance is the name of the Memcached CR that
all watcher service will use.
type: string
passwordSelectors:
default:
service: WatcherPassword
Expand Down
5 changes: 5 additions & 0 deletions api/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ spec:
MariaDB instance name
Required to use the mariadb-operator instance to create the DB and user
type: string
memcachedInstance:
default: memcached
description: MemcachedInstance is the name of the Memcached CR that
all watcher service will use.
type: string
passwordSelectors:
default:
service: WatcherPassword
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 @@ -38,6 +38,11 @@ type WatcherCommon struct {
// +kubebuilder:default=watcher
// DatabaseAccount - MariaDBAccount CR name used for watcher DB, defaults to watcher
DatabaseAccount string `json:"databaseAccount"`

// +kubebuilder:validation:Optional
// +kubebuilder:default=memcached
// MemcachedInstance is the name of the Memcached CR that all watcher service will use.
MemcachedInstance string `json:"memcachedInstance"`
}

// WatcherTemplate defines the fields used in the top level CR
Expand Down
1 change: 1 addition & 0 deletions api/v1beta1/watcherapi_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type WatcherAPISpec struct {
// Important: Run "make" to regenerate code after modifying this file

WatcherCommon `json:",inline"`

// +kubebuilder:validation:Required
// Secret containing all passwords / keys needed
Secret string `json:"secret"`
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 @@ -49,6 +49,11 @@ spec:
MariaDB instance name
Required to use the mariadb-operator instance to create the DB and user
type: string
memcachedInstance:
default: memcached
description: MemcachedInstance is the name of the Memcached CR that
all watcher service will use.
type: string
passwordSelectors:
default:
service: WatcherPassword
Expand Down
5 changes: 5 additions & 0 deletions config/crd/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ spec:
MariaDB instance name
Required to use the mariadb-operator instance to create the DB and user
type: string
memcachedInstance:
default: memcached
description: MemcachedInstance is the name of the Memcached CR that
all watcher service will use.
type: string
passwordSelectors:
default:
service: WatcherPassword
Expand Down
25 changes: 25 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ rules:
- patch
- update
- watch
- apiGroups:
- keystone.openstack.org
resources:
- keystoneapis
verbs:
- get
- list
- watch
- apiGroups:
- keystone.openstack.org
resources:
Expand Down Expand Up @@ -82,6 +90,23 @@ rules:
- patch
- update
- watch
- apiGroups:
- memcached.openstack.org
resources:
- memcacheds
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- memcached.openstack.org
resources:
- memcacheds/finalizers
verbs:
- patch
- update
- apiGroups:
- rabbitmq.openstack.org
resources:
Expand Down
79 changes: 79 additions & 0 deletions controllers/watcher_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1"
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
"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"
)

Expand Down Expand Up @@ -188,3 +192,78 @@ func ensureSecret(

return hash, ctrl.Result{}, *secret, nil
}

func GenerateConfigsGeneric(
ctx context.Context, helper *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 watcher 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,
ConfigOptions: templateParameters,
Labels: cmLabels,
})
}
return secret.EnsureSecrets(ctx, helper, instance, cms, envVars)
}

// ensureMemcached - gets the Memcached instance used for watcher services cache backend
func ensureMemcached(
ctx context.Context,
helper *helper.Helper,
namespaceName string,
memcachedName string,
conditionUpdater conditionUpdater,
) (*memcachedv1.Memcached, error) {
memcached, err := memcachedv1.GetMemcachedByName(ctx, helper, memcachedName, namespaceName)
if err != nil {
if k8s_errors.IsNotFound(err) {
conditionUpdater.Set(condition.FalseCondition(
condition.MemcachedReadyCondition,
condition.RequestedReason,
condition.SeverityInfo,
condition.MemcachedReadyWaitingMessage))
return nil, fmt.Errorf("memcached %s not found", memcachedName)
}
conditionUpdater.Set(condition.FalseCondition(
condition.MemcachedReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.MemcachedReadyErrorMessage,
err.Error()))
return nil, err
}

if !memcached.IsReady() {
conditionUpdater.Set(condition.FalseCondition(
condition.MemcachedReadyCondition,
condition.RequestedReason,
condition.SeverityInfo,
condition.MemcachedReadyWaitingMessage))
return nil, fmt.Errorf("memcached %s is not ready", memcachedName)
}
conditionUpdater.MarkTrue(condition.MemcachedReadyCondition, condition.MemcachedReadyMessage)

return memcached, err
}
93 changes: 82 additions & 11 deletions controllers/watcherapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/go-logr/logr"
memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1"
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
"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"
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"

watcherv1beta1 "github.com/openstack-k8s-operators/watcher-operator/api/v1beta1"
Expand All @@ -59,6 +64,11 @@ func (r *WatcherAPIReconciler) GetLogger(ctx context.Context) logr.Logger {
//+kubebuilder:rbac:groups=watcher.openstack.org,resources=watcherapis/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=watcher.openstack.org,resources=watcherapis/finalizers,verbs=update
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update;patch;delete;
//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapis,verbs=get;list;watch;
//+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;
//+kubebuilder:rbac:groups=memcached.openstack.org,resources=memcacheds,verbs=get;list;watch;update;patch
//+kubebuilder:rbac:groups=memcached.openstack.org,resources=memcacheds/finalizers,verbs=update;patch

// 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 @@ -138,6 +148,7 @@ func (r *WatcherAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request)
types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Secret},
[]string{
instance.Spec.PasswordSelectors.Service,
TransportURLSelector,
},
helper.GetClient(),
&instance.Status.Conditions,
Expand All @@ -163,7 +174,26 @@ func (r *WatcherAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request)
// all our input checks out so report InputReady
instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage)

err = r.generateServiceConfigs(ctx, instance, secret, db, helper, &configVars)
memcached, err := ensureMemcached(ctx, helper, instance.Namespace, instance.Spec.MemcachedInstance, &instance.Status.Conditions)

if err != nil {
return ctrl.Result{}, err
}
// Add finalizer to Memcached to prevent it from being deleted now that we're using it
if controllerutil.AddFinalizer(memcached, helper.GetFinalizer()) {
err := helper.GetClient().Update(ctx, memcached)
if err != nil {
instance.Status.Conditions.Set(condition.FalseCondition(
condition.MemcachedReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.MemcachedReadyErrorMessage,
err.Error()))
return ctrl.Result{}, err
}
}

err = r.generateServiceConfigs(ctx, instance, secret, db, memcached, helper, &configVars)
if err != nil {
return ctrl.Result{}, err
}
Expand All @@ -181,25 +211,65 @@ func (r *WatcherAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}

// generateServiceConfigs - create Secret which holds the service configuration
// NOTE - jgilaber this function is WIP, currently implements a fraction of its
// functionality and will be expanded of further iteration to actually generate
// the service configs
func (r *WatcherAPIReconciler) generateServiceConfigs(
ctx context.Context, instance *watcherv1beta1.WatcherAPI,
secret corev1.Secret, db *mariadbv1.Database,
memcachedInstance *memcachedv1.Memcached,
helper *helper.Helper, envVars *map[string]env.Setter,
) error {
Log := r.GetLogger(ctx)
Log.Info("generateServiceConfigs - reconciling")

// replace by actual usage in future iterations
_ = db
_ = helper
_ = instance
_ = secret
_ = envVars
labels := labels.GetLabels(instance, labels.GetGroupLabel(watcher.ServiceName), map[string]string{})
// jgilaber this might be wrong? we should probably get keystonapi in the
// watcher controller and set the url in the spec eventually?
keystoneAPI, err := keystonev1.GetKeystoneAPI(ctx, helper, instance.Namespace, map[string]string{})
// KeystoneAPI not available we should not aggregate the error and continue
if err != nil {
instance.Status.Conditions.Set(condition.FalseCondition(
condition.ServiceConfigReadyCondition,
condition.ErrorReason,
condition.SeverityWarning,
condition.ServiceConfigReadyErrorMessage,
"keystoneAPI not found"))
return err
}
keystoneInternalURL, err := keystoneAPI.GetEndpoint(endpoint.EndpointInternal)
if err != nil {
return err
}
// customData hold any customization for the service.
// NOTE jgilaber making an empty map for now, we'll probably want to
// implement CustomServiceConfig later
customData := map[string]string{}

databaseAccount := db.GetAccount()
databaseSecret := db.GetSecret()
templateParameters := map[string]interface{}{
"DatabaseConnection": fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s?charset=utf8",
databaseAccount.Spec.UserName,
string(databaseSecret.Data[mariadbv1.DatabasePasswordSelector]),
db.GetDatabaseHostname(),
watcher.DatabaseName,
),
"KeystoneAuthURL": keystoneInternalURL,
"ServicePassword": string(secret.Data[instance.Spec.PasswordSelectors.Service]),
"ServiceUser": instance.Spec.ServiceUser,
"TransportURL": string(secret.Data[TransportURLSelector]),
"MemcachedServers": memcachedInstance.GetMemcachedServerListString(),
}

return nil
// create httpd vhost template parameters
httpdVhostConfig := map[string]interface{}{}
cescgina marked this conversation as resolved.
Show resolved Hide resolved
for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} {
endptConfig := map[string]interface{}{}
endptConfig["ServerName"] = fmt.Sprintf("%s-%s.%s.svc", watcher.ServiceName, endpt.String(), instance.Namespace)
endptConfig["TLS"] = false // default TLS to false, and set it below when implemented
httpdVhostConfig[endpt.String()] = endptConfig
}
templateParameters["VHosts"] = httpdVhostConfig

return GenerateConfigsGeneric(ctx, helper, instance, envVars, templateParameters, customData, labels, false)
}

func (r *WatcherAPIReconciler) reconcileDelete(ctx context.Context, instance *watcherv1beta1.WatcherAPI, helper *helper.Helper) (ctrl.Result, error) {
Expand All @@ -221,6 +291,7 @@ func (r *WatcherAPIReconciler) initStatus(instance *watcherv1beta1.WatcherAPI) e
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
condition.UnknownCondition(condition.InputReadyCondition, condition.InitReason, condition.InputReadyInitMessage),
condition.UnknownCondition(condition.ServiceConfigReadyCondition, condition.InitReason, condition.ServiceConfigReadyMessage),
condition.UnknownCondition(condition.MemcachedReadyCondition, condition.InitReason, condition.MemcachedReadyInitMessage),
)

instance.Status.Conditions.Init(&cl)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
k8s.io/api v0.29.10
k8s.io/apimachinery v0.29.10
k8s.io/client-go v0.29.10
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
sigs.k8s.io/controller-runtime v0.17.6
)

Expand Down Expand Up @@ -75,7 +76,6 @@ require (
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
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"

memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1"
rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
Expand All @@ -58,6 +59,7 @@ func init() {
utilruntime.Must(mariadbv1.AddToScheme(scheme))
utilruntime.Must(rabbitmqv1.AddToScheme(scheme))
utilruntime.Must(keystonev1.AddToScheme(scheme))
utilruntime.Must(memcachedv1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}

Expand Down
Loading
Loading