Skip to content

Commit

Permalink
Patch all apps with current app operator version (#1631)
Browse files Browse the repository at this point in the history
* Patch all apps with current app operator version

* Update CHANGELOG

* Use logger from parameters
  • Loading branch information
mnitchev committed Jul 18, 2023
1 parent 12d7434 commit b775795
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 67 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Patch app operator version on all apps instead of just optional ones.

## [5.7.0] - 2023-07-14

### Added
Expand Down
171 changes: 104 additions & 67 deletions service/controller/resource/appversionlabel/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,96 +8,133 @@ import (
"github.com/giantswarm/apiextensions-application/api/v1alpha1"
"github.com/giantswarm/apiextensions/v6/pkg/label"
"github.com/giantswarm/microerror"
"github.com/giantswarm/micrologger"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
apiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"

"github.com/giantswarm/cluster-operator/v5/pkg/project"
"github.com/giantswarm/cluster-operator/v5/service/controller/key"
"github.com/giantswarm/cluster-operator/v5/service/internal/releaseversion"

"sigs.k8s.io/controller-runtime/pkg/client"
)

func (r *Resource) EnsureCreated(ctx context.Context, obj interface{}) error {
cr, err := key.ToCluster(obj)
cluster, err := key.ToCluster(obj)
if err != nil {
return microerror.Mask(err)
}

var apps []*v1alpha1.App
{
r.logger.Debugf(ctx, "finding optional apps for tenant cluster %#q", key.ClusterID(&cr))
logger := r.logger.With("cluster", key.ClusterID(&cluster))

o := metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s!=%s", label.ManagedBy, project.Name()),
apps, err := r.getApps(ctx, logger, cluster)
if err != nil {
return microerror.Mask(err)
}

err = r.updateApps(ctx, logger, cluster, apps)
if err != nil {
return microerror.Mask(err)
}
return nil
}

func (r *Resource) getApps(ctx context.Context, logger micrologger.Logger, cluster apiv1beta1.Cluster) ([]*v1alpha1.App, error) {
logger.Debugf(ctx, "finding apps")

list := &v1alpha1.AppList{}
err := r.ctrlClient.List(ctx, list, &client.ListOptions{Namespace: key.ClusterID(&cluster), Raw: &metav1.ListOptions{}})
if err != nil {
return nil, microerror.Mask(err)
}

apps := []*v1alpha1.App{}
for _, item := range list.Items {
apps = append(apps, item.DeepCopy())
}

logger.Debugf(ctx, "found %d apps", len(apps))

return apps, nil
}

func (r *Resource) updateApps(ctx context.Context, logger micrologger.Logger, cluster apiv1beta1.Cluster, apps []*v1alpha1.App) error {
if len(apps) == 0 {
return nil
}

appOperatorVersion, err := r.getAppOperatorVersion(ctx, cluster)
if err != nil {
return err
}

logger.Debugf(ctx, "updating app version labels")

updatedAppCount := 0
for _, app := range apps {
currentVersion := app.Labels[label.AppOperatorVersion]

if !shouldUpdateAppOperatorVersionLabel(currentVersion, appOperatorVersion) {
continue
}

list := &v1alpha1.AppList{}
err = r.ctrlClient.List(ctx, list, &client.ListOptions{Namespace: key.ClusterID(&cr), Raw: &o})
err = r.patchAppOperatorVersion(ctx, app, appOperatorVersion)
if err != nil {
return microerror.Mask(err)
return err
}

for _, item := range list.Items {
apps = append(apps, item.DeepCopy())
}
updatedAppCount++
}

logger.Debugf(ctx, "updated version label for %d apps", updatedAppCount)

return nil
}

func (r *Resource) getAppOperatorVersion(ctx context.Context, cluster apiv1beta1.Cluster) (string, error) {
componentVersions, err := r.releaseVersion.ComponentVersion(ctx, &cluster)
if err != nil {
return "", microerror.Mask(err)
}

r.logger.Debugf(ctx, "found %d optional apps for tenant cluster %#q", len(apps), key.ClusterID(&cr))
appOperatorComponent := componentVersions[releaseversion.AppOperator]
appOperatorVersion := appOperatorComponent.Version
if appOperatorVersion == "" {
return "", microerror.Maskf(notFoundError, "app-operator component version not found")
}

{
var updatedAppCount int

if len(apps) > 0 {
componentVersions, err := r.releaseVersion.ComponentVersion(ctx, &cr)
if err != nil {
return microerror.Mask(err)
}

appOperatorComponent := componentVersions[releaseversion.AppOperator]
appOperatorVersion := appOperatorComponent.Version
if appOperatorVersion == "" {
return microerror.Maskf(notFoundError, "app-operator component version not found")
}

r.logger.Debugf(ctx, "updating version label for optional apps in tenant cluster %#q", key.ClusterID(&cr))

for _, app := range apps {
currentVersion := app.Labels[label.AppOperatorVersion]

if shouldUpdateAppOperatorVersionLabel(currentVersion, appOperatorVersion) {
var patches []patch

if len(app.Labels) == 0 {
patches = append(patches, patch{
Op: "add",
Path: "/metadata/labels",
Value: map[string]string{},
})
}

patches = append(patches, patch{
Op: "add",
Path: fmt.Sprintf("/metadata/labels/%s", replaceToEscape(label.AppOperatorVersion)),
Value: appOperatorVersion,
})

bytes, err := json.Marshal(patches)
if err != nil {
return microerror.Mask(err)
}

err = r.ctrlClient.Patch(ctx, app, client.RawPatch(types.JSONPatchType, bytes), &client.PatchOptions{Raw: &metav1.PatchOptions{}})
if err != nil {
return microerror.Mask(err)
}

updatedAppCount++
}
}

r.logger.Debugf(ctx, "updating version label for %d optional apps in tenant cluster %#q", updatedAppCount, key.ClusterID(&cr))
}
return appOperatorVersion, nil
}

func (r *Resource) patchAppOperatorVersion(ctx context.Context, app *v1alpha1.App, appOperatorVersion string) error {
var patches []patch

if len(app.Labels) == 0 {
patches = append(patches, patch{
Op: "add",
Path: "/metadata/labels",
Value: map[string]string{},
})
}

patches = append(patches, patch{
Op: "add",
Path: fmt.Sprintf("/metadata/labels/%s", replaceToEscape(label.AppOperatorVersion)),
Value: appOperatorVersion,
})

bytes, err := json.Marshal(patches)
if err != nil {
return microerror.Mask(err)
}

err = r.ctrlClient.Patch(ctx,
app,
client.RawPatch(types.JSONPatchType, bytes),
&client.PatchOptions{Raw: &metav1.PatchOptions{}},
)
if err != nil {
return microerror.Mask(err)
}

return nil
Expand Down

0 comments on commit b775795

Please sign in to comment.