Skip to content

Commit

Permalink
Handle glanceAPI cleanup
Browse files Browse the repository at this point in the history
We have the ability to grow the deployment and add more glanceAPI
instance as needed, as well as select which one should be used as
the main instance registered to keystone catalog. With this patch
we have now the ability to cleanup an instance thar no longer
belongs to the main CR. The endpoints registered in the Status are
removed as well.

Signed-off-by: Francesco Pantano <[email protected]>
  • Loading branch information
fmount committed Dec 5, 2023
1 parent f8e0eb1 commit 6386e06
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 2 deletions.
5 changes: 5 additions & 0 deletions api/bases/glance.openstack.org_glances.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,11 @@ spec:
type: array
databaseHostname:
type: string
glanceAPIReadyCounts:
additionalProperties:
format: int32
type: integer
type: object
hash:
additionalProperties:
type: string
Expand Down
3 changes: 3 additions & 0 deletions api/v1beta1/glance_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ type GlanceStatus struct {

// Glance Database Hostname
DatabaseHostname string `json:"databaseHostname,omitempty"`

// GlanceAPIReadyCounts -
GlanceAPIReadyCounts map[string]int32 `json:"glanceAPIReadyCounts,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
7 changes: 7 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions config/crd/bases/glance.openstack.org_glances.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,11 @@ spec:
type: array
databaseHostname:
type: string
glanceAPIReadyCounts:
additionalProperties:
format: int32
type: integer
type: object
hash:
additionalProperties:
type: string
Expand Down
61 changes: 59 additions & 2 deletions controllers/glance_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func (r *GlanceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
instance.Status.Conditions.Init(&cl)

// Register overall status immediately to have an early feedback e.g. in the cli
return ctrl.Result{}, nil
return ctrl.Result{}, err
}
if instance.Status.Hash == nil {
instance.Status.Hash = map[string]string{}
Expand All @@ -174,6 +174,10 @@ func (r *GlanceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res
instance.Status.APIEndpoints = map[string]string{}
}

if instance.Status.GlanceAPIReadyCounts == nil {
instance.Status.GlanceAPIReadyCounts = map[string]int32{}
}

// Handle service delete
if !instance.DeletionTimestamp.IsZero() {
return r.reconcileDelete(ctx, instance, helper)
Expand Down Expand Up @@ -231,7 +235,7 @@ func (r *GlanceReconciler) reconcileDelete(ctx context.Context, instance *glance
}
}

// Remove the finalizer on rach GlanceAPI CR
// Remove the finalizer on each GlanceAPI CR
for name := range instance.Spec.GlanceAPIs {
err = r.removeAPIFinalizer(ctx, instance, helper, name)
if err != nil {
Expand Down Expand Up @@ -591,6 +595,10 @@ func (r *GlanceReconciler) reconcileNormal(ctx context.Context, instance *glance
if err != nil {
return ctrl.Result{}, err
}
err = r.glanceAPICleanup(ctx, instance)
if err != nil {
return ctrl.Result{}, err
}
}
// create CronJobs: DBPurge (always), CacheCleaner and CachePruner if image-cache
// is enabled
Expand Down Expand Up @@ -686,6 +694,11 @@ func (r *GlanceReconciler) ensureAPIDeployment(
r.Log.Info(fmt.Sprintf("StatefulSet %s successfully reconciled - operation: %s", instance.Name, string(op)))
}

if instance.Status.GlanceAPIReadyCounts == nil {
instance.Status.GlanceAPIReadyCounts = map[string]int32{}
}
instance.Status.GlanceAPIReadyCounts[apiName] = glanceAPI.Status.ReadyCount

apiPubEndpoint := fmt.Sprintf("%s-%s", apiName, string(endpoint.EndpointPublic))
apiIntEndpoint := fmt.Sprintf("%s-%s", apiName, string(endpoint.EndpointInternal))

Expand Down Expand Up @@ -956,3 +969,47 @@ func (r *GlanceReconciler) registeredLimitsDelete(
}
return nil
}

// GlanceAPICleanup - Delete the glanceAPI instance if it no longer appears
// in the spec.
func (r *GlanceReconciler) glanceAPICleanup(ctx context.Context, instance *glancev1.Glance) error {
// Generate a list of GlanceAPI CRs
apis := &glancev1.GlanceAPIList{}
listOpts := []client.ListOption{
client.InNamespace(instance.Namespace),
}
if err := r.Client.List(ctx, apis, listOpts...); err != nil {
r.Log.Error(err, "Unable to retrieve GlanceAPI CRs %v")
return nil
}

for _, glanceAPI := range apis.Items {
// Skip any GlanceAPI that we don't own
if glance.GetOwningGlanceName(&glanceAPI) != instance.Name {
continue
}
apiName := glance.GetGlanceAPIName(glanceAPI.Name)
// Simply return if the apiName doesn't match the existing pattern, log but do not
// raise an error
if apiName == "" {
r.Log.Info(fmt.Sprintf("GlanceAPI %s does not match the pattern", glanceAPI.Name))
return nil
}
// Delete the api if it's no longer in the spec
_, exists := instance.Spec.GlanceAPIs[apiName]
if !exists && glanceAPI.DeletionTimestamp.IsZero() {
err := r.Client.Delete(ctx, &glanceAPI)
if err != nil && !k8s_errors.IsNotFound(err) {
err = fmt.Errorf("Error cleaning up %s: %w", glanceAPI.Name, err)
return err
}
// Update the APIEndpoints in the top-level CR
endpoints := []endpoint.Endpoint{endpoint.EndpointPublic, endpoint.EndpointInternal}
for _, ep := range endpoints {
endpointKey := fmt.Sprintf("%s-%s", apiName, ep)
delete(instance.Status.APIEndpoints, endpointKey)
}
}
}
return nil
}
36 changes: 36 additions & 0 deletions pkg/glance/funcs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package glance

import (
glancev1 "github.com/openstack-k8s-operators/glance-operator/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
)
Expand Down Expand Up @@ -40,3 +41,38 @@ func GetEnabledBackends(customServiceConfig string) []string {
}
return availableBackends
}

// GetGlanceAPIName - For a given full glanceAPIName passed as input, this utility
// resolves the name used in the glance CR to identify the API.
func GetGlanceAPIName(name string) string {

/***
A given GlanceAPI name can be found in the form:
+--------------------------------------------------------+
| "glance.ServiceName + instance.Name + instance.Type" |
+--------------------------------------------------------+
but only "instance.Name" is used to identify the glanceAPI instance in
the main CR. For this reason we cut the string passed as input and we
trim both prefix and suffix.
Example:
input = "glance-api1-internal"
output = "api1"
***/
var api = ""
prefix := ServiceName + "-"
suffixes := []string{
glancev1.APIInternal,
glancev1.APIExternal,
glancev1.APISingle,
}
for _, suffix := range suffixes {
if strings.Contains(name, suffix) {
apiName := strings.TrimSuffix(name, "-"+suffix)
api = apiName[len(prefix):]
}
}
return api
}

0 comments on commit 6386e06

Please sign in to comment.