Skip to content
This repository was archived by the owner on Oct 10, 2023. It is now read-only.

Commit 48a065b

Browse files
author
Adolfo Duarte
committed
Graceful upgrade of addons-manager
- Pauses lifecycle management of addons-manager package - NoopDelete addons-manager packageinstall - Deletes adoons-manager addon secret
1 parent 0605dfc commit 48a065b

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

pkg/v1/tkg/managementcomponents/management_component_install.go

+160
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ package managementcomponents
55

66
import (
77
"context"
8+
"encoding/json"
9+
"fmt"
810
"os"
911
"time"
1012

1113
"github.com/pkg/errors"
1214
"golang.org/x/sync/errgroup"
15+
corev1 "k8s.io/api/core/v1"
16+
apierrors "k8s.io/apimachinery/pkg/api/errors"
1317
"k8s.io/apimachinery/pkg/labels"
1418
"k8s.io/apimachinery/pkg/selection"
19+
"k8s.io/apimachinery/pkg/types"
1520
crtclient "sigs.k8s.io/controller-runtime/pkg/client"
1621

1722
kappipkg "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/packaging/v1alpha1"
@@ -23,6 +28,8 @@ import (
2328
"github.com/vmware-tanzu/tanzu-framework/pkg/v1/tkg/tkgpackagedatamodel"
2429
)
2530

31+
const addonsManagerName = "addons-manager"
32+
2633
// ClusterOptions specifies cluster configuration
2734
type ClusterOptions struct {
2835
Kubeconfig string
@@ -49,6 +56,105 @@ type ManagementComponentsInstallOptions struct {
4956
ManagementPackageRepositoryOptions ManagementPackageRepositoryOptions
5057
}
5158

59+
func generateAddonSecretName(clusterName, addonName string) string {
60+
return fmt.Sprintf("%s-%s-addon", clusterName, addonName)
61+
}
62+
63+
func generateAddonsPkgiName(addonName string) string {
64+
return fmt.Sprintf("tanzu-%s", addonName)
65+
}
66+
func pauseAddonSecretReconciliation(ctx context.Context, clusterClient clusterclient.Client, clusterName, addonSecreteName, namespace string) error {
67+
secret := &corev1.Secret{}
68+
jsonPatch := []clusterclient.JSONPatch{
69+
{
70+
Op: "add",
71+
Path: fmt.Sprintf("/metadata/annotations/tkg.tanzu.vmware.com~1addon-paused"),
72+
Value: "",
73+
},
74+
}
75+
payloadBytes, err := json.Marshal(jsonPatch)
76+
if err != nil {
77+
return errors.Wrap(err, "unable to generate json patch")
78+
}
79+
80+
err = clusterClient.PatchResource(secret, addonSecreteName, namespace, string(payloadBytes), types.JSONPatchType, nil)
81+
if apierrors.IsNotFound(err) {
82+
return nil
83+
}
84+
if err != nil {
85+
return errors.Wrapf(err, "failed to pause %s secret reconciliation", addonSecreteName)
86+
}
87+
return nil
88+
}
89+
90+
func pausePackageInstallReconciliation(ctx context.Context, clusterClient clusterclient.Client, pkgiName, namespace string) error {
91+
pkgi := &kappipkg.PackageInstall{}
92+
jsonPatch := []map[string]interface{}{
93+
{
94+
"op": "add",
95+
"path": "/spec/paused",
96+
"value": true,
97+
},
98+
}
99+
payloadBytes, err := json.Marshal(jsonPatch)
100+
if err != nil {
101+
return errors.Wrap(err, "unable to generate json patch")
102+
}
103+
err = clusterClient.PatchResource(pkgi, pkgiName, namespace, string(payloadBytes), types.JSONPatchType, nil)
104+
if apierrors.IsNotFound(err) {
105+
return nil
106+
}
107+
if err != nil {
108+
return errors.Wrapf(err, "failed to pause %s packageinstall reconciliation", pkgiName)
109+
}
110+
return nil
111+
}
112+
113+
// PausedAdoonLifecycleManagement pauses/unpauses the lifecycle management of addon package with given name and namespace
114+
func PauseAddonLifecycleManagement(mcip *ManagementComponentsInstallOptions, addonName, namespace string) error {
115+
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
116+
if err != nil {
117+
return err
118+
}
119+
clusterName, err := clusterClient.GetCurrentClusterName(mcip.ClusterOptions.Kubecontext)
120+
if err != nil {
121+
return err
122+
}
123+
pkgiName := generateAddonsPkgiName(addonsManagerName)
124+
addonSecretName := generateAddonSecretName(clusterName, addonsManagerName)
125+
126+
err = pauseAddonSecretReconciliation(context.TODO(), clusterClient, clusterName, addonSecretName, namespace)
127+
if err != nil {
128+
return err
129+
}
130+
131+
err = pausePackageInstallReconciliation(context.TODO(), clusterClient, pkgiName, namespace)
132+
if err != nil {
133+
return err
134+
}
135+
136+
return nil
137+
}
138+
func DeleteAddonSecret(mcip *ManagementComponentsInstallOptions, addonName, namespace string) error {
139+
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
140+
if err != nil {
141+
return err
142+
}
143+
clusterName, err := clusterClient.GetCurrentClusterName(mcip.ClusterOptions.Kubecontext)
144+
if err != nil {
145+
return err
146+
}
147+
148+
secret := &corev1.Secret{}
149+
secret.Name = generateAddonSecretName(clusterName, addonName)
150+
secret.Namespace = constants.TkgNamespace
151+
err = clusterClient.DeleteResource(secret)
152+
if err != nil {
153+
return errors.Wrapf(err, "failed to delete addon secret %s", secret)
154+
}
155+
return nil
156+
}
157+
52158
// InstallManagementComponents installs the management component to cluster
53159
func InstallManagementComponents(mcip *ManagementComponentsInstallOptions) error {
54160
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
@@ -61,6 +167,22 @@ func InstallManagementComponents(mcip *ManagementComponentsInstallOptions) error
61167
if err != nil {
62168
return err
63169
}
170+
171+
err = PauseAddonLifecycleManagement(mcip, addonsManagerName, constants.TkgNamespace)
172+
if err != nil {
173+
panic(err)
174+
}
175+
176+
err = NoopDeletePackageInstall(mcip, addonsManagerName, constants.TkgNamespace)
177+
if err != nil {
178+
return nil
179+
}
180+
181+
err = DeleteAddonSecret(mcip, addonsManagerName, constants.TkgNamespace)
182+
if err != nil {
183+
return err
184+
}
185+
64186
if err = InstallManagementPackages(pkgClient, mcip.ManagementPackageRepositoryOptions); err != nil {
65187
// instead of throwing error here, wait for some additional time for packages to get reconciled successfully
66188
// error will be thrown at the next step if packages are not reconciled after timeout value
@@ -196,3 +318,41 @@ func WaitForManagementPackages(clusterClient clusterclient.Client, packageInstal
196318
}
197319
return nil
198320
}
321+
322+
// NoopDeletePackageInstall sets spec.noopdelete = true before deleting the package install
323+
func NoopDeletePackageInstall(mcip *ManagementComponentsInstallOptions, addonName, namespace string) error {
324+
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
325+
if err != nil {
326+
return err
327+
}
328+
pkgiName := fmt.Sprintf("tanzu-%s", addonName)
329+
330+
jsonPatch := []map[string]interface{}{
331+
{
332+
"op": "add",
333+
"path": "/spec/noopDelete",
334+
"value": true,
335+
},
336+
}
337+
payloadBytes, err := json.Marshal(jsonPatch)
338+
if err != nil {
339+
return errors.Wrap(err, "unable to generate json patch")
340+
}
341+
pkgi := &kappipkg.PackageInstall{}
342+
pkgi.Name = pkgiName
343+
pkgi.Namespace = namespace
344+
err = clusterClient.PatchResource(pkgi, pkgiName, namespace, string(payloadBytes), types.JSONPatchType, nil)
345+
if apierrors.IsNotFound(err) {
346+
return nil
347+
}
348+
if err != nil {
349+
return errors.Wrapf(err, "failed to patch %s packageinstall", pkgiName)
350+
}
351+
352+
// TODO (adduarter) should we check to make sure noopdelete is configured?
353+
err = clusterClient.DeleteResource(pkgi)
354+
if err != nil {
355+
return errors.Wrapf(err, "failed to delete PackageInstall resource %s", pkgiName)
356+
}
357+
return nil
358+
}

0 commit comments

Comments
 (0)