Skip to content

Commit fc125b0

Browse files
committed
Support add-on providers in clusterctl
1 parent e774ad5 commit fc125b0

24 files changed

+162
-29
lines changed

cmd/clusterctl/api/v1alpha3/labels.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ func ManifestLabel(name string, providerType ProviderType) string {
5454
return fmt.Sprintf("ipam-%s", name)
5555
case RuntimeExtensionProviderType:
5656
return fmt.Sprintf("runtime-extension-%s", name)
57+
case AddonProviderType:
58+
return fmt.Sprintf("addon-%s", name)
5759
default:
5860
return name
5961
}

cmd/clusterctl/api/v1alpha3/provider_type.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ func (p *Provider) GetProviderType() ProviderType {
9595
InfrastructureProviderType,
9696
ControlPlaneProviderType,
9797
IPAMProviderType,
98-
RuntimeExtensionProviderType:
98+
RuntimeExtensionProviderType,
99+
AddonProviderType:
99100
return t
100101
default:
101102
return ProviderTypeUnknown
@@ -129,6 +130,10 @@ const (
129130
// runtime extensions.
130131
RuntimeExtensionProviderType = ProviderType("RuntimeExtensionProvider")
131132

133+
// AddonProviderType is the type associated with codebases that provide
134+
// add-on capabilities.
135+
AddonProviderType = ProviderType("AddonProvider")
136+
132137
// ProviderTypeUnknown is used when the type is unknown.
133138
ProviderTypeUnknown = ProviderType("")
134139
)
@@ -148,6 +153,8 @@ func (p ProviderType) Order() int {
148153
return 4
149154
case RuntimeExtensionProviderType:
150155
return 5
156+
case AddonProviderType:
157+
return 6
151158
default:
152159
return 99
153160
}

cmd/clusterctl/client/config/providers_client.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ const (
8181
KubeKeyK3sControlPlaneProviderName = "kubekey-k3s"
8282
)
8383

84+
// Add-on providers.
85+
const (
86+
HelmAddonProviderName = "helm"
87+
)
88+
8489
// Other.
8590
const (
8691
// ProvidersConfigKey is a constant for finding provider configurations with the ProvidersClient.
@@ -276,6 +281,7 @@ func (p *providersClient) defaults() []Provider {
276281
url: "https://github.com/canonical/cluster-api-bootstrap-provider-microk8s/releases/latest/bootstrap-components.yaml",
277282
providerType: clusterctlv1.BootstrapProviderType,
278283
},
284+
279285
// ControlPlane providers
280286
&provider{
281287
name: KubeadmControlPlaneProviderName,
@@ -302,6 +308,13 @@ func (p *providersClient) defaults() []Provider {
302308
url: "https://github.com/kubernetes-sigs/cluster-api-provider-nested/releases/latest/control-plane-components.yaml",
303309
providerType: clusterctlv1.ControlPlaneProviderType,
304310
},
311+
312+
// Add-on providers
313+
&provider{
314+
name: HelmAddonProviderName,
315+
url: "https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/releases/latest/addon-components.yaml",
316+
providerType: clusterctlv1.AddonProviderType,
317+
},
305318
}
306319

307320
return defaults
@@ -401,16 +414,18 @@ func validateProvider(r Provider) error {
401414
clusterctlv1.InfrastructureProviderType,
402415
clusterctlv1.ControlPlaneProviderType,
403416
clusterctlv1.IPAMProviderType,
404-
clusterctlv1.RuntimeExtensionProviderType:
417+
clusterctlv1.RuntimeExtensionProviderType,
418+
clusterctlv1.AddonProviderType:
405419
break
406420
default:
407-
return errors.Errorf("invalid provider type. Allowed values are [%s, %s, %s, %s, %s, %s]",
421+
return errors.Errorf("invalid provider type. Allowed values are [%s, %s, %s, %s, %s, %s, %s]",
408422
clusterctlv1.CoreProviderType,
409423
clusterctlv1.BootstrapProviderType,
410424
clusterctlv1.InfrastructureProviderType,
411425
clusterctlv1.ControlPlaneProviderType,
412426
clusterctlv1.IPAMProviderType,
413-
clusterctlv1.RuntimeExtensionProviderType)
427+
clusterctlv1.RuntimeExtensionProviderType,
428+
clusterctlv1.AddonProviderType)
414429
}
415430
return nil
416431
}

cmd/clusterctl/client/config/providers_client_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"testing"
2424

2525
. "github.com/onsi/gomega"
26+
"github.com/onsi/gomega/format"
2627

2728
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
2829
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
@@ -41,6 +42,10 @@ func Test_providers_List(t *testing.T) {
4142
})
4243

4344
defaultsAndZZZ := append(defaults, NewProvider("zzz", "https://zzz/infrastructure-components.yaml", "InfrastructureProvider"))
45+
// AddonProviders are at the end of the list so we want to make sure this InfrastructureProvider is before the AddonProviders.
46+
sort.Slice(defaultsAndZZZ, func(i, j int) bool {
47+
return defaultsAndZZZ[i].Less(defaultsAndZZZ[j])
48+
})
4449

4550
defaultsWithOverride := append([]Provider{}, defaults...)
4651
defaultsWithOverride[0] = NewProvider(defaults[0].Name(), "https://zzz/infrastructure-components.yaml", defaults[0].Type())
@@ -135,6 +140,9 @@ func Test_providers_List(t *testing.T) {
135140
wantErr: true,
136141
},
137142
}
143+
144+
format.MaxLength = 15000 // This way it doesn't truncate the output on test failure
145+
138146
for _, tt := range tests {
139147
t.Run(tt.name, func(t *testing.T) {
140148
g := NewWithT(t)

cmd/clusterctl/client/config_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func Test_clusterctlClient_GetProvidersConfig(t *testing.T) {
9090
config.VclusterProviderName,
9191
config.VirtinkProviderName,
9292
config.VSphereProviderName,
93+
config.HelmAddonProviderName,
9394
},
9495
wantErr: false,
9596
},
@@ -136,6 +137,7 @@ func Test_clusterctlClient_GetProvidersConfig(t *testing.T) {
136137
config.VclusterProviderName,
137138
config.VirtinkProviderName,
138139
config.VSphereProviderName,
140+
config.HelmAddonProviderName,
139141
},
140142
wantErr: false,
141143
},

cmd/clusterctl/client/delete.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ type DeleteOptions struct {
4848
// RuntimeExtensionProviders and versions (e.g. test:v0.0.1) to delete from the management cluster.
4949
RuntimeExtensionProviders []string
5050

51+
// AddonProviders and versions (e.g. helm:v0.1.0) to delete from the management cluster.
52+
AddonProviders []string
53+
5154
// DeleteAll set for deletion of all the providers.
5255
DeleteAll bool
5356

@@ -122,6 +125,11 @@ func (c *clusterctlClient) Delete(options DeleteOptions) error {
122125
return err
123126
}
124127

128+
providers, err = appendProviders(providers, clusterctlv1.AddonProviderType, options.AddonProviders...)
129+
if err != nil {
130+
return err
131+
}
132+
125133
for _, provider := range providers {
126134
// Try to detect the namespace where the provider lives
127135
provider.Namespace, err = clusterClient.ProviderInventory().GetProviderNamespace(provider.ProviderName, provider.GetProviderType())

cmd/clusterctl/client/init.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ type InitOptions struct {
5959
// RuntimeExtensionProviders and versions (e.g. test:v0.0.1) to add to the management cluster.
6060
RuntimeExtensionProviders []string
6161

62+
// AddonProviders and versions (e.g. helm:v0.1.0) to add to the management cluster.
63+
AddonProviders []string
64+
6265
// TargetNamespace defines the namespace where the providers should be deployed. If unspecified, each provider
6366
// will be installed in a provider's default namespace.
6467
TargetNamespace string
@@ -255,6 +258,10 @@ func (c *clusterctlClient) setupInstaller(cluster cluster.Client, options InitOp
255258
return nil, err
256259
}
257260

261+
if err := c.addToInstaller(addOptions, clusterctlv1.AddonProviderType, options.AddonProviders...); err != nil {
262+
return nil, err
263+
}
264+
258265
return installer, nil
259266
}
260267

cmd/clusterctl/client/upgrade.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ type ApplyUpgradeOptions struct {
121121
// RuntimeExtensionProviders instance and versions (e.g. runtime-extension-system/test:v0.0.1) to upgrade to. This field can be used as alternative to Contract.
122122
RuntimeExtensionProviders []string
123123

124+
// AddonProviders instance and versions (e.g. caaph-system/helm:v0.1.0) to upgrade to. This field can be used as alternative to Contract.
125+
AddonProviders []string
126+
124127
// WaitProviders instructs the upgrade apply command to wait till the providers are successfully upgraded.
125128
WaitProviders bool
126129

@@ -169,7 +172,8 @@ func (c *clusterctlClient) ApplyUpgrade(options ApplyUpgradeOptions) error {
169172
len(options.ControlPlaneProviders) > 0 ||
170173
len(options.InfrastructureProviders) > 0 ||
171174
len(options.IPAMProviders) > 0 ||
172-
len(options.RuntimeExtensionProviders) > 0
175+
len(options.RuntimeExtensionProviders) > 0 ||
176+
len(options.AddonProviders) > 0
173177

174178
opts := cluster.UpgradeOptions{
175179
WaitProviders: options.WaitProviders,
@@ -207,6 +211,10 @@ func (c *clusterctlClient) ApplyUpgrade(options ApplyUpgradeOptions) error {
207211
if err != nil {
208212
return err
209213
}
214+
upgradeItems, err = addUpgradeItems(clusterClient, upgradeItems, clusterctlv1.AddonProviderType, options.AddonProviders...)
215+
if err != nil {
216+
return err
217+
}
210218

211219
// Execute the upgrade using the custom upgrade items
212220
return clusterClient.ProviderUpgrader().ApplyCustomPlan(opts, upgradeItems...)

cmd/clusterctl/cmd/config_repositories_test.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"path/filepath"
2424
"testing"
2525

26+
"github.com/google/go-cmp/cmp"
2627
. "github.com/onsi/gomega"
2728
)
2829

@@ -45,11 +46,13 @@ func Test_runGetRepositories(t *testing.T) {
4546
out, err := io.ReadAll(buf)
4647
g.Expect(err).ToNot(HaveOccurred())
4748

49+
var diff string
4850
if val == RepositoriesOutputText {
49-
g.Expect(string(out)).To(Equal(expectedOutputText))
51+
diff = cmp.Diff(expectedOutputText, string(out))
5052
} else if val == RepositoriesOutputYaml {
51-
g.Expect(string(out)).To(Equal(expectedOutputYaml))
53+
diff = cmp.Diff(expectedOutputYaml, string(out))
5254
}
55+
g.Expect(diff).To(BeEmpty()) // Use diff to compare as Gomega output does not actually print the string values on failure
5356
}
5457
})
5558

@@ -137,6 +140,7 @@ vcd InfrastructureProvider https://github.com/vmware/cluster-a
137140
vcluster InfrastructureProvider https://github.com/loft-sh/cluster-api-provider-vcluster/releases/latest/ infrastructure-components.yaml
138141
virtink InfrastructureProvider https://github.com/smartxworks/cluster-api-provider-virtink/releases/latest/ infrastructure-components.yaml
139142
vsphere InfrastructureProvider https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/latest/ infrastructure-components.yaml
143+
helm AddonProvider https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/releases/latest/ addon-components.yaml
140144
`
141145

142146
var expectedOutputYaml = `- File: core_components.yaml
@@ -287,4 +291,8 @@ var expectedOutputYaml = `- File: core_components.yaml
287291
Name: vsphere
288292
ProviderType: InfrastructureProvider
289293
URL: https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/latest/
294+
- File: addon-components.yaml
295+
Name: helm
296+
ProviderType: AddonProvider
297+
URL: https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/releases/latest/
290298
`

cmd/clusterctl/cmd/delete.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type deleteOptions struct {
3232
infrastructureProviders []string
3333
ipamProviders []string
3434
runtimeExtensionProviders []string
35+
addonProviders []string
3536
includeNamespace bool
3637
includeCRDs bool
3738
deleteAll bool
@@ -109,6 +110,8 @@ func init() {
109110
"IPAM providers and versions (e.g. infoblox:v0.0.1) to delete from the management cluster")
110111
deleteCmd.Flags().StringSliceVar(&dd.runtimeExtensionProviders, "runtime-extension", nil,
111112
"Runtime extension providers and versions (e.g. test:v0.0.1) to delete from the management cluster")
113+
deleteCmd.Flags().StringSliceVar(&dd.addonProviders, "addon", nil,
114+
"Add-on providers and versions (e.g. helm:v0.1.0) to delete from the management cluster")
112115

113116
deleteCmd.Flags().BoolVar(&dd.deleteAll, "all", false,
114117
"Force deletion of all the providers")
@@ -127,14 +130,15 @@ func runDelete() error {
127130
(len(dd.controlPlaneProviders) > 0) ||
128131
(len(dd.infrastructureProviders) > 0) ||
129132
(len(dd.ipamProviders) > 0) ||
130-
(len(dd.runtimeExtensionProviders) > 0)
133+
(len(dd.runtimeExtensionProviders) > 0) ||
134+
(len(dd.addonProviders) > 0)
131135

132136
if dd.deleteAll && hasProviderNames {
133-
return errors.New("The --all flag can't be used in combination with --core, --bootstrap, --control-plane, --infrastructure, --ipam, --extension")
137+
return errors.New("The --all flag can't be used in combination with --core, --bootstrap, --control-plane, --infrastructure, --ipam, --extension, --addon")
134138
}
135139

136140
if !dd.deleteAll && !hasProviderNames {
137-
return errors.New("At least one of --core, --bootstrap, --control-plane, --infrastructure, --ipam, --extension should be specified or the --all flag should be set")
141+
return errors.New("At least one of --core, --bootstrap, --control-plane, --infrastructure, --ipam, --extension, --addon should be specified or the --all flag should be set")
138142
}
139143

140144
return c.Delete(client.DeleteOptions{
@@ -147,6 +151,7 @@ func runDelete() error {
147151
ControlPlaneProviders: dd.controlPlaneProviders,
148152
IPAMProviders: dd.ipamProviders,
149153
RuntimeExtensionProviders: dd.runtimeExtensionProviders,
154+
AddonProviders: dd.addonProviders,
150155
DeleteAll: dd.deleteAll,
151156
})
152157
}

0 commit comments

Comments
 (0)