Skip to content

Commit 67772a1

Browse files
clusterctl read templates from different sources
1 parent a552b9d commit 67772a1

18 files changed

+1082
-127
lines changed

cmd/clusterctl/cmd/config_cluster.go

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20+
"fmt"
2021
"os"
2122

2223
"github.com/pkg/errors"
@@ -33,6 +34,13 @@ type configClusterOptions struct {
3334
kubernetesVersion string
3435
controlPlaneMachineCount int
3536
workerMachineCount int
37+
38+
url string
39+
configMapNamespace string
40+
configMapName string
41+
configMapDataKey string
42+
43+
listVariables bool
3644
}
3745

3846
var cc = &configClusterOptions{}
@@ -65,50 +73,113 @@ var configClusterClusterCmd = &cobra.Command{
6573
6674
# Generates a yaml file for creating a Cluster API workload cluster with
6775
# custom number of nodes (if supported by provider's templates)
68-
clusterctl config cluster my-cluster --control-plane-machine-count=3 --worker-machine-count=10`),
76+
clusterctl config cluster my-cluster --control-plane-machine-count=3 --worker-machine-count=10
77+
78+
# Generates a yaml file for creating a Cluster API workload cluster using a template hosted on a ConfigMap
79+
# instead of using the cluster templates hosted in the provider's repository.
80+
clusterctl config cluster my-cluster --from-config-map MyTemplates
81+
82+
# Generates a yaml file for creating a Cluster API workload cluster using a template hosted on specific URL
83+
# instead of using the cluster templates hosted in the provider's repository.
84+
clusterctl config cluster my-cluster --from https://github.com/foo-org/foo-repository/blob/master/cluster-template.yaml
85+
86+
# Generates a yaml file for creating a Cluster API workload cluster using a template hosted on the local file system
87+
clusterctl config cluster my-cluster --from ~/workspace/cluster-template.yaml`),
6988

7089
Args: cobra.ExactArgs(1),
7190
RunE: func(cmd *cobra.Command, args []string) error {
72-
return runGenerateCluster(args[0])
91+
return runGetClusterTemplate(args[0])
7392
},
7493
}
7594

7695
func init() {
7796
configClusterClusterCmd.Flags().StringVarP(&cc.kubeconfig, "kubeconfig", "", "", "Path to the kubeconfig file to use for accessing the management cluster. If empty, default rules for kubeconfig discovery will be used")
7897

79-
configClusterClusterCmd.Flags().StringVarP(&cc.infrastructureProvider, "infrastructure", "i", "", "The infrastructure provider that should be used for creating the workload cluster")
80-
81-
configClusterClusterCmd.Flags().StringVarP(&cc.flavor, "flavor", "f", "", "The template variant to be used for creating the workload cluster")
98+
// flags for the template variables
8299
configClusterClusterCmd.Flags().StringVarP(&cc.targetNamespace, "target-namespace", "n", "", "The namespace where the objects describing the workload cluster should be deployed. If not specified, the current namespace will be used")
83100
configClusterClusterCmd.Flags().StringVarP(&cc.kubernetesVersion, "kubernetes-version", "", "", "The Kubernetes version to use for the workload cluster. By default (empty), the value from os env variables or the .cluster-api/clusterctl.yaml config file will be used")
84101
configClusterClusterCmd.Flags().IntVarP(&cc.controlPlaneMachineCount, "control-plane-machine-count", "", 1, "The number of control plane machines to be added to the workload cluster.")
85102
configClusterClusterCmd.Flags().IntVarP(&cc.workerMachineCount, "worker-machine-count", "", 0, "The number of worker machines to be added to the workload cluster.")
86103

104+
// flags for the repository source
105+
configClusterClusterCmd.Flags().StringVarP(&cc.infrastructureProvider, "infrastructure", "i", "", "The infrastructure provider to read the workload cluster template from. By default (empty), the default infrastructure provider will be used if no other source is specified")
106+
configClusterClusterCmd.Flags().StringVarP(&cc.flavor, "flavor", "f", "", "The workload cluster template variant to be used when reading from the infrastructure provider repository. By default (empty), the default cluster template will be used")
107+
108+
// flags for the url source
109+
configClusterClusterCmd.Flags().StringVarP(&cc.url, "from", "", "", "The URL to read the workload cluster template from. By default (empty), the infrastructure provider repository URL will be used")
110+
111+
// flags for the config map source
112+
configClusterClusterCmd.Flags().StringVarP(&cc.configMapName, "from-config-map", "", "", "The ConfigMap to read the workload cluster template from. This can be used as alternative to read from the provider repository or from an URL")
113+
configClusterClusterCmd.Flags().StringVarP(&cc.configMapNamespace, "from-config-map-namespace", "", "", "The namespace where the ConfigMap exists. By default (empty), the current namespace will be used")
114+
configClusterClusterCmd.Flags().StringVarP(&cc.configMapDataKey, "from-config-map-key", "", "", fmt.Sprintf("The ConfigMap.Data key where the workload cluster template is hosted. By default (empty), %q will be used", client.DefaultCustomTemplateConfigMapKey))
115+
116+
// other flags
117+
configClusterClusterCmd.Flags().BoolVarP(&cc.listVariables, "list-variables", "", false, "Returns the list of variables expected by the template instead of the template yaml")
118+
87119
configCmd.AddCommand(configClusterClusterCmd)
88120
}
89121

90-
func runGenerateCluster(name string) error {
122+
func runGetClusterTemplate(name string) error {
91123
c, err := client.New(cfgFile)
92124
if err != nil {
93125
return err
94126
}
95127

96-
options := client.GetClusterTemplateOptions{
128+
templateOptions := client.GetClusterTemplateOptions{
97129
Kubeconfig: cc.kubeconfig,
98-
InfrastructureProvider: cc.infrastructureProvider,
99-
Flavor: cc.flavor,
100130
ClusterName: name,
101131
TargetNamespace: cc.targetNamespace,
102132
KubernetesVersion: cc.kubernetesVersion,
103133
ControlPlaneMachineCount: cc.controlPlaneMachineCount,
104134
WorkerMachineCount: cc.workerMachineCount,
135+
ListVariablesOnly: cc.listVariables,
105136
}
106137

107-
template, err := c.GetClusterTemplate(options)
138+
if cc.url != "" {
139+
templateOptions.URLSource = &client.URLSourceOptions{
140+
URL: cc.url,
141+
}
142+
}
143+
144+
if cc.configMapNamespace != "" || cc.configMapName != "" || cc.configMapDataKey != "" {
145+
templateOptions.ConfigMapSource = &client.ConfigMapSourceOptions{
146+
Namespace: cc.configMapNamespace,
147+
Name: cc.configMapName,
148+
DataKey: cc.configMapDataKey,
149+
}
150+
}
151+
152+
if cc.infrastructureProvider != "" || cc.flavor != "" {
153+
templateOptions.ProviderRepositorySource = &client.ProviderRepositorySourceOptions{
154+
InfrastructureProvider: cc.infrastructureProvider,
155+
Flavor: cc.flavor,
156+
}
157+
}
158+
159+
template, err := c.GetClusterTemplate(templateOptions)
108160
if err != nil {
109161
return err
110162
}
111163

164+
if cc.listVariables {
165+
return templateListVariablesOutput(template)
166+
}
167+
168+
return templateYAMLOutput(template)
169+
}
170+
171+
func templateListVariablesOutput(template client.Template) error {
172+
if len(template.Variables()) > 0 {
173+
fmt.Println("Variables:")
174+
for _, v := range template.Variables() {
175+
fmt.Printf(" - %s\n", v)
176+
}
177+
}
178+
fmt.Println()
179+
return nil
180+
}
181+
182+
func templateYAMLOutput(template client.Template) error {
112183
yaml, err := template.Yaml()
113184
if err != nil {
114185
return err
@@ -118,6 +189,5 @@ func runGenerateCluster(name string) error {
118189
if _, err := os.Stdout.Write(yaml); err != nil {
119190
return errors.Wrap(err, "failed to write yaml to Stdout")
120191
}
121-
122192
return nil
123193
}

cmd/clusterctl/pkg/client/client.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,6 @@ type InitOptions struct {
5555
LogUsageInstructions bool
5656
}
5757

58-
// GetClusterTemplateOptions carries the options supported by GetClusterTemplate.
59-
type GetClusterTemplateOptions struct {
60-
// Kubeconfig file to use for accessing the management cluster. If empty, default rules for kubeconfig
61-
// discovery will be used.
62-
Kubeconfig string
63-
64-
// InfrastructureProvider that should be used for creating the workload cluster.
65-
InfrastructureProvider string
66-
67-
// Flavor defines the template variant to be used for creating the workload cluster.
68-
Flavor string
69-
70-
// TargetNamespace where the objects describing the workload cluster should be deployed. If not specified,
71-
// the current namespace will be used.
72-
TargetNamespace string
73-
74-
// ClusterName to be used for the workload cluster.
75-
ClusterName string
76-
77-
// KubernetesVersion to use for the workload cluster. By default (empty), the value from os env variables
78-
// or the .cluster-api/clusterctl.yaml config file will be used.
79-
KubernetesVersion string
80-
81-
// ControlPlaneMachineCount defines the number of control plane machines to be added to the workload cluster.
82-
ControlPlaneMachineCount int
83-
84-
// WorkerMachineCount defines number of worker machines to be added to the workload cluster.
85-
WorkerMachineCount int
86-
}
87-
8858
// DeleteOptions carries the options supported by Delete.
8959
type DeleteOptions struct {
9060
// Kubeconfig file to use for accessing the management cluster. If empty, default rules for kubeconfig

cmd/clusterctl/pkg/client/client_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestNewFakeClient(t *testing.T) {
4646
WithFile("v1.0", "components.yaml", []byte("content"))
4747

4848
// create a fake cluster, eventually adding some existing runtime objects to it
49-
cluster1 := newFakeCluster("cluster1").
49+
cluster1 := newFakeCluster("cluster1", config1).
5050
WithObjs()
5151

5252
// create a new fakeClient that allows to execute tests on the fake config, the fake repositories and the fake cluster.
@@ -143,8 +143,7 @@ func (f *fakeClient) WithRepository(repositoryClient repository.Client) *fakeCli
143143
// newFakeCluster returns a fakeClusterClient that
144144
// internally uses a FakeProxy (based on the controller-runtime FakeClient).
145145
// You can use WithObjs to pre-load a set of runtime objects in the cluster.
146-
func newFakeCluster(kubeconfig string) *fakeClusterClient {
147-
configClient := newFakeConfig()
146+
func newFakeCluster(kubeconfig string, configClient config.Client) *fakeClusterClient {
148147
fakeProxy := test.NewFakeProxy()
149148
pollImmediateWaiter := func(interval, timeout time.Duration, condition wait.ConditionFunc) error {
150149
return nil
@@ -209,6 +208,10 @@ func (f *fakeClusterClient) ProviderUpgrader() cluster.ProviderUpgrader {
209208
return f.internalclient.ProviderUpgrader()
210209
}
211210

211+
func (f *fakeClusterClient) Template() cluster.TemplateClient {
212+
return f.internalclient.Template()
213+
}
214+
212215
func (f *fakeClusterClient) WithObjs(objs ...runtime.Object) *fakeClusterClient {
213216
f.fakeProxy.WithObjs(objs...)
214217
return f

cmd/clusterctl/pkg/client/cluster/client.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,19 @@ type Client interface {
6666

6767
// ProviderUpgrader returns a ProviderUpgrader that supports upgrading Cluster API providers.
6868
ProviderUpgrader() ProviderUpgrader
69+
70+
// Template has methods to work with templates stored in the cluster.
71+
Template() TemplateClient
6972
}
7073

7174
// PollImmediateWaiter tries a condition func until it returns true, an error, or the timeout is reached.
7275
type PollImmediateWaiter func(interval, timeout time.Duration, condition wait.ConditionFunc) error
7376

7477
// clusterClient implements Client.
7578
type clusterClient struct {
79+
configClient config.Client
7680
kubeconfig string
7781
proxy Proxy
78-
configClient config.Client
7982
repositoryClientFactory RepositoryClientFactory
8083
pollImmediateWaiter PollImmediateWaiter
8184
}
@@ -117,6 +120,10 @@ func (c *clusterClient) ProviderUpgrader() ProviderUpgrader {
117120
return newProviderUpgrader(c.configClient, c.repositoryClientFactory, c.ProviderInventory())
118121
}
119122

123+
func (c *clusterClient) Template() TemplateClient {
124+
return newTemplateClient(c.proxy, c.configClient)
125+
}
126+
120127
// Option is a configuration option supplied to New
121128
type Option func(*clusterClient)
122129

0 commit comments

Comments
 (0)