@@ -5,14 +5,20 @@ package managementcomponents
5
5
6
6
import (
7
7
"context"
8
+ "encoding/json"
9
+ "fmt"
8
10
"os"
9
11
"time"
10
12
11
13
"github.com/pkg/errors"
12
14
"golang.org/x/sync/errgroup"
15
+ corev1 "k8s.io/api/core/v1"
16
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
13
17
"k8s.io/apimachinery/pkg/labels"
14
18
"k8s.io/apimachinery/pkg/selection"
19
+ "k8s.io/apimachinery/pkg/types"
15
20
crtclient "sigs.k8s.io/controller-runtime/pkg/client"
21
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
16
22
17
23
kappipkg "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/packaging/v1alpha1"
18
24
@@ -23,6 +29,11 @@ import (
23
29
"github.com/vmware-tanzu/tanzu-framework/pkg/v1/tkg/tkgpackagedatamodel"
24
30
)
25
31
32
+ const (
33
+ addonsManagerName = "addons-manager"
34
+ addonFinalizer = "tkg.tanzu.vmware.com/addon"
35
+ )
36
+
26
37
// ClusterOptions specifies cluster configuration
27
38
type ClusterOptions struct {
28
39
Kubeconfig string
@@ -49,6 +60,160 @@ type ManagementComponentsInstallOptions struct {
49
60
ManagementPackageRepositoryOptions ManagementPackageRepositoryOptions
50
61
}
51
62
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
+
52
217
// InstallManagementComponents installs the management component to cluster
53
218
func InstallManagementComponents (mcip * ManagementComponentsInstallOptions ) error {
54
219
clusterClient , err := clusterclient .NewClient (mcip .ClusterOptions .Kubeconfig , mcip .ClusterOptions .Kubecontext , clusterclient.Options {})
@@ -61,6 +226,22 @@ func InstallManagementComponents(mcip *ManagementComponentsInstallOptions) error
61
226
if err != nil {
62
227
return err
63
228
}
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
+
64
245
if err = InstallManagementPackages (pkgClient , mcip .ManagementPackageRepositoryOptions ); err != nil {
65
246
// instead of throwing error here, wait for some additional time for packages to get reconciled successfully
66
247
// error will be thrown at the next step if packages are not reconciled after timeout value
0 commit comments