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

Commit 5416bd0

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 5416bd0

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed

pkg/v1/tkg/managementcomponents/management_component_install.go

+181
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ 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"
21+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1622

1723
kappipkg "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/packaging/v1alpha1"
1824

@@ -23,6 +29,11 @@ import (
2329
"github.com/vmware-tanzu/tanzu-framework/pkg/v1/tkg/tkgpackagedatamodel"
2430
)
2531

32+
const (
33+
addonsManagerName = "addons-manager"
34+
addonFinalizer = "tkg.tanzu.vmware.com/addon"
35+
)
36+
2637
// ClusterOptions specifies cluster configuration
2738
type ClusterOptions struct {
2839
Kubeconfig string
@@ -49,6 +60,160 @@ type ManagementComponentsInstallOptions struct {
4960
ManagementPackageRepositoryOptions ManagementPackageRepositoryOptions
5061
}
5162

63+
func generateAddonsPkgiName(addonName string) string {
64+
return fmt.Sprintf("tanzu-%s", addonName)
65+
}
66+
67+
func generateAddonSecretName(clusterName, addonName string) string {
68+
return fmt.Sprintf("%s-%s-addon", clusterName, generateAddonsPkgiName(addonName))
69+
}
70+
71+
func pauseAddonSecretReconciliation(ctx context.Context, clusterClient clusterclient.Client, clusterName, addonSecreteName, namespace string) error {
72+
secret := &corev1.Secret{}
73+
jsonPatch := []map[string]interface{}{
74+
{
75+
"op": "add",
76+
"path": fmt.Sprintf("/metadata/annotations/tkg.tanzu.vmware.com~1addon-paused"),
77+
"value": "",
78+
},
79+
}
80+
payloadBytes, err := json.Marshal(jsonPatch)
81+
if err != nil {
82+
return errors.Wrap(err, "unable to generate json patch")
83+
}
84+
85+
err = clusterClient.PatchResource(secret, addonSecreteName, namespace, string(payloadBytes), types.JSONPatchType, nil)
86+
if apierrors.IsNotFound(err) {
87+
return nil
88+
}
89+
if err != nil {
90+
return errors.Wrapf(err, "failed to pause %s secret reconciliation", addonSecreteName)
91+
}
92+
return nil
93+
}
94+
95+
func pausePackageInstallReconciliation(ctx context.Context, clusterClient clusterclient.Client, pkgiName, namespace string) error {
96+
pkgi := &kappipkg.PackageInstall{}
97+
jsonPatch := []map[string]interface{}{
98+
{
99+
"op": "add",
100+
"path": "/spec/paused",
101+
"value": true,
102+
},
103+
}
104+
payloadBytes, err := json.Marshal(jsonPatch)
105+
if err != nil {
106+
return errors.Wrap(err, "unable to generate json patch")
107+
}
108+
err = clusterClient.PatchResource(pkgi, pkgiName, namespace, string(payloadBytes), types.JSONPatchType, nil)
109+
if apierrors.IsNotFound(err) {
110+
return nil
111+
}
112+
if err != nil {
113+
return errors.Wrapf(err, "failed to pause %s packageinstall reconciliation", pkgiName)
114+
}
115+
return nil
116+
}
117+
118+
// PausedAdoonLifecycleManagement pauses/unpauses the lifecycle management of addon package with given name and namespace
119+
func PauseAddonLifecycleManagement(mcip *ManagementComponentsInstallOptions, addonName, namespace string) error {
120+
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
121+
if err != nil {
122+
return err
123+
}
124+
clusterName, err := clusterClient.GetCurrentClusterName(mcip.ClusterOptions.Kubecontext)
125+
if err != nil {
126+
return err
127+
}
128+
pkgiName := generateAddonsPkgiName(addonsManagerName)
129+
addonSecretName := generateAddonSecretName(clusterName, addonsManagerName)
130+
131+
err = pauseAddonSecretReconciliation(context.TODO(), clusterClient, clusterName, addonSecretName, namespace)
132+
if err != nil {
133+
return err
134+
}
135+
136+
err = pausePackageInstallReconciliation(context.TODO(), clusterClient, pkgiName, namespace)
137+
if err != nil {
138+
return err
139+
}
140+
141+
return nil
142+
}
143+
144+
// NoopDeletePackageInstall sets spec.noopdelete = true before deleting the package install
145+
func NoopDeletePackageInstall(mcip *ManagementComponentsInstallOptions, addonName, namespace string) error {
146+
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
147+
if err != nil {
148+
return err
149+
}
150+
pkgiName := fmt.Sprintf("tanzu-%s", addonName)
151+
152+
jsonPatch := []map[string]interface{}{
153+
{
154+
"op": "add",
155+
"path": "/spec/noopDelete",
156+
"value": true,
157+
},
158+
}
159+
payloadBytes, err := json.Marshal(jsonPatch)
160+
if err != nil {
161+
return errors.Wrap(err, "unable to generate json patch")
162+
}
163+
pkgi := &kappipkg.PackageInstall{}
164+
err = clusterClient.PatchResource(pkgi, pkgiName, namespace, string(payloadBytes), types.JSONPatchType, nil)
165+
if apierrors.IsNotFound(err) {
166+
return nil
167+
}
168+
if err != nil {
169+
return errors.Wrapf(err, "failed to patch %s packageinstall", pkgiName)
170+
}
171+
172+
pkgi.Name = pkgiName
173+
pkgi.Namespace = namespace
174+
err = clusterClient.DeleteResource(pkgi)
175+
if err != nil {
176+
return errors.Wrapf(err, "failed to delete PackageInstall resource %s", pkgiName)
177+
}
178+
return nil
179+
}
180+
181+
func DeleteAddonSecret(mcip *ManagementComponentsInstallOptions, addonName, namespace string) error {
182+
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
183+
if err != nil {
184+
return err
185+
}
186+
clusterName, err := clusterClient.GetCurrentClusterName(mcip.ClusterOptions.Kubecontext)
187+
if err != nil {
188+
return err
189+
}
190+
191+
addonSecret := &corev1.Secret{}
192+
addonSecret.Name = generateAddonSecretName(clusterName, addonName)
193+
addonSecret.Namespace = constants.TkgNamespace
194+
err = clusterClient.GetResource(addonSecret, addonSecret.Name, addonSecret.Namespace, nil, nil)
195+
if apierrors.IsNotFound(err) {
196+
return nil
197+
}
198+
if err != nil {
199+
return err
200+
}
201+
202+
if controllerutil.ContainsFinalizer(addonSecret, addonFinalizer) {
203+
controllerutil.RemoveFinalizer(addonSecret, addonFinalizer)
204+
}
205+
err = clusterClient.UpdateResource(addonSecret, addonSecret.Name, addonSecret.Namespace)
206+
if err != nil {
207+
return err
208+
}
209+
210+
err = clusterClient.DeleteResource(addonSecret)
211+
if err != nil && apierrors.IsNotFound(err) {
212+
return errors.Wrapf(err, "failed to delete addon addonSecret %s", addonSecret)
213+
}
214+
return nil
215+
}
216+
52217
// InstallManagementComponents installs the management component to cluster
53218
func InstallManagementComponents(mcip *ManagementComponentsInstallOptions) error {
54219
clusterClient, err := clusterclient.NewClient(mcip.ClusterOptions.Kubeconfig, mcip.ClusterOptions.Kubecontext, clusterclient.Options{})
@@ -61,6 +226,22 @@ func InstallManagementComponents(mcip *ManagementComponentsInstallOptions) error
61226
if err != nil {
62227
return err
63228
}
229+
230+
err = PauseAddonLifecycleManagement(mcip, addonsManagerName, constants.TkgNamespace)
231+
if err != nil {
232+
panic(err)
233+
}
234+
235+
err = NoopDeletePackageInstall(mcip, addonsManagerName, constants.TkgNamespace)
236+
if err != nil {
237+
return nil
238+
}
239+
240+
err = DeleteAddonSecret(mcip, addonsManagerName, constants.TkgNamespace)
241+
if err != nil {
242+
return err
243+
}
244+
64245
if err = InstallManagementPackages(pkgClient, mcip.ManagementPackageRepositoryOptions); err != nil {
65246
// instead of throwing error here, wait for some additional time for packages to get reconciled successfully
66247
// error will be thrown at the next step if packages are not reconciled after timeout value

0 commit comments

Comments
 (0)