Skip to content

Commit df255e4

Browse files
committed
pkg/infrastructure: add capi provider
Implements the infrastructure provider interface with the CAPI system. This encapsulates the CAPI implementation similar to Terraform. It also maintains pkg/infrastructure/platform.go (and build variants) as the canonical source of truth for choosing an infrastructure provider. This also adds an interface that cloud platforms utilizing the CAPI provisioning should implement to provision additional resources.
1 parent d60ab7c commit df255e4

File tree

5 files changed

+444
-217
lines changed

5 files changed

+444
-217
lines changed

pkg/asset/cluster/cluster.go

Lines changed: 8 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,23 @@ import (
55
"fmt"
66
"path/filepath"
77
"strings"
8-
"time"
98

109
"github.com/pkg/errors"
1110
"github.com/sirupsen/logrus"
12-
"gopkg.in/yaml.v2"
13-
apierrors "k8s.io/apimachinery/pkg/api/errors"
14-
"k8s.io/apimachinery/pkg/util/wait"
15-
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
16-
utilkubeconfig "sigs.k8s.io/cluster-api/util/kubeconfig"
17-
"sigs.k8s.io/controller-runtime/pkg/client"
18-
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
1911

2012
"github.com/openshift/installer/pkg/asset"
2113
"github.com/openshift/installer/pkg/asset/cluster/aws"
2214
"github.com/openshift/installer/pkg/asset/cluster/azure"
2315
"github.com/openshift/installer/pkg/asset/cluster/openstack"
2416
"github.com/openshift/installer/pkg/asset/cluster/tfvars"
17+
"github.com/openshift/installer/pkg/asset/ignition/bootstrap"
18+
"github.com/openshift/installer/pkg/asset/ignition/machine"
2519
"github.com/openshift/installer/pkg/asset/installconfig"
26-
awsconfig "github.com/openshift/installer/pkg/asset/installconfig/aws"
2720
"github.com/openshift/installer/pkg/asset/kubeconfig"
28-
"github.com/openshift/installer/pkg/asset/manifests/capiutils"
21+
"github.com/openshift/installer/pkg/asset/machines"
2922
capimanifests "github.com/openshift/installer/pkg/asset/manifests/clusterapi"
3023
"github.com/openshift/installer/pkg/asset/password"
3124
"github.com/openshift/installer/pkg/asset/quota"
32-
"github.com/openshift/installer/pkg/clusterapi"
3325
infra "github.com/openshift/installer/pkg/infrastructure/platform"
3426
typesaws "github.com/openshift/installer/pkg/types/aws"
3527
typesazure "github.com/openshift/installer/pkg/types/azure"
@@ -72,6 +64,9 @@ func (c *Cluster) Dependencies() []asset.Asset {
7264
&password.KubeadminPassword{},
7365
&capimanifests.Cluster{},
7466
&kubeconfig.AdminClient{},
67+
&bootstrap.Bootstrap{},
68+
&machine.Master{},
69+
&machines.ClusterAPI{},
7570
}
7671
}
7772

@@ -98,31 +93,14 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) {
9893
return errors.New("cluster cannot be created with bootstrapInPlace set")
9994
}
10095

101-
// Check if we're using Cluster API.
102-
if capiutils.IsEnabled(installConfig) {
103-
// TODO(vincepri): The context should be passed down from the caller,
104-
// although today the Asset interface doesn't allow it, refactor once it does.
105-
ctx, cancel := context.WithCancel(signals.SetupSignalHandler())
106-
go func() {
107-
<-ctx.Done()
108-
cancel()
109-
clusterapi.System().Teardown()
110-
}()
111-
112-
return c.provisionWithClusterAPI(ctx, parents, installConfig, clusterID)
113-
}
114-
115-
// Otherwise, use the normal path.
116-
return c.provision(installConfig, clusterID, terraformVariables, parents)
117-
}
118-
119-
func (c *Cluster) provision(installConfig *installconfig.InstallConfig, clusterID *installconfig.ClusterID, terraformVariables *tfvars.TerraformVariables, parents asset.Parents) error {
12096
platform := installConfig.Config.Platform.Name()
12197

12298
if azure := installConfig.Config.Platform.Azure; azure != nil && azure.CloudName == typesazure.StackCloud {
12399
platform = typesazure.StackTerraformName
124100
}
125101

102+
// TODO(padillon): determine whether CAPI handles tagging shared subnets, in which case we should be able
103+
// to encapsulate these into the terraform package.
126104
logrus.Infof("Creating infrastructure resources...")
127105
switch platform {
128106
case typesaws.Name:
@@ -154,137 +132,6 @@ func (c *Cluster) provision(installConfig *installconfig.InstallConfig, clusterI
154132
return nil
155133
}
156134

157-
func (c *Cluster) provisionWithClusterAPI(ctx context.Context, parents asset.Parents, installConfig *installconfig.InstallConfig, clusterID *installconfig.ClusterID) error {
158-
capiManifests := &capimanifests.Cluster{}
159-
clusterKubeconfigAsset := &kubeconfig.AdminClient{}
160-
parents.Get(
161-
capiManifests,
162-
clusterKubeconfigAsset,
163-
)
164-
165-
// Only need the objects--not the files.
166-
manifests := []client.Object{}
167-
for _, m := range capiManifests.RuntimeFiles() {
168-
manifests = append(manifests, m.Object)
169-
}
170-
171-
// Run the CAPI system.
172-
capiSystem := clusterapi.System()
173-
if err := capiSystem.Run(ctx, installConfig); err != nil {
174-
return fmt.Errorf("failed to run cluster api system: %w", err)
175-
}
176-
177-
// Grab the client.
178-
cl := capiSystem.Client()
179-
180-
// Create all the manifests and store them.
181-
for _, m := range manifests {
182-
m.SetNamespace(capiutils.Namespace)
183-
if err := cl.Create(context.Background(), m); err != nil {
184-
return fmt.Errorf("failed to create manifest: %w", err)
185-
}
186-
logrus.Infof("Created manifest %+T, namespace=%s name=%s", m, m.GetNamespace(), m.GetName())
187-
}
188-
189-
// Pass cluster kubeconfig and store it in; this is usually the role of a bootstrap provider.
190-
{
191-
key := client.ObjectKey{
192-
Name: clusterID.InfraID,
193-
Namespace: capiutils.Namespace,
194-
}
195-
cluster := &clusterv1.Cluster{}
196-
if err := cl.Get(context.Background(), key, cluster); err != nil {
197-
return err
198-
}
199-
// Create the secret.
200-
clusterKubeconfig := clusterKubeconfigAsset.Files()[0].Data
201-
secret := utilkubeconfig.GenerateSecret(cluster, clusterKubeconfig)
202-
if err := cl.Create(context.Background(), secret); err != nil {
203-
return err
204-
}
205-
}
206-
207-
// Wait for the load balancer to be ready by checking the control plane endpoint
208-
// on the cluster object.
209-
var cluster *clusterv1.Cluster
210-
{
211-
if err := wait.ExponentialBackoff(wait.Backoff{
212-
Duration: time.Second * 10,
213-
Factor: float64(1.5),
214-
Steps: 32,
215-
}, func() (bool, error) {
216-
c := &clusterv1.Cluster{}
217-
if err := cl.Get(context.Background(), client.ObjectKey{
218-
Name: clusterID.InfraID,
219-
Namespace: capiutils.Namespace,
220-
}, c); err != nil {
221-
if apierrors.IsNotFound(err) {
222-
return false, nil
223-
}
224-
return false, err
225-
}
226-
cluster = c
227-
return cluster.Spec.ControlPlaneEndpoint.IsValid(), nil
228-
}); err != nil {
229-
return err
230-
}
231-
if cluster == nil {
232-
return errors.New("error occurred during load balancer ready check")
233-
}
234-
if cluster.Spec.ControlPlaneEndpoint.Host == "" {
235-
return errors.New("control plane endpoint is not set")
236-
}
237-
}
238-
239-
// Run the post-provisioning steps for the platform we're on.
240-
// TODO(vincepri): The following should probably be in a separate package with a clear
241-
// interface and multiple hooks at different stages of the cluster lifecycle.
242-
switch installConfig.Config.Platform.Name() {
243-
case typesaws.Name:
244-
ssn, err := installConfig.AWS.Session(context.TODO())
245-
if err != nil {
246-
return fmt.Errorf("failed to create session: %w", err)
247-
}
248-
client := awsconfig.NewClient(ssn)
249-
r53cfg := awsconfig.GetR53ClientCfg(ssn, "")
250-
err = client.CreateOrUpdateRecord(installConfig.Config, cluster.Spec.ControlPlaneEndpoint.Host, r53cfg)
251-
if err != nil {
252-
return fmt.Errorf("failed to create route53 records: %w", err)
253-
}
254-
logrus.Infof("Created Route53 records to control plane load balancer.")
255-
default:
256-
}
257-
258-
// For each manifest we created, retrieve it and store it in the asset.
259-
for _, m := range manifests {
260-
key := client.ObjectKey{
261-
Name: m.GetName(),
262-
Namespace: m.GetNamespace(),
263-
}
264-
if err := cl.Get(context.Background(), key, m); err != nil {
265-
return fmt.Errorf("failed to get manifest: %w", err)
266-
}
267-
268-
gvk, err := cl.GroupVersionKindFor(m)
269-
if err != nil {
270-
return fmt.Errorf("failed to get GVK for manifest: %w", err)
271-
}
272-
fileName := fmt.Sprintf("%s-%s-%s.yaml", gvk.Kind, m.GetNamespace(), m.GetName())
273-
objData, err := yaml.Marshal(m)
274-
if err != nil {
275-
errMsg := fmt.Sprintf("failed to create infrastructure manifest %s from InstallConfig", fileName)
276-
return errors.Wrapf(err, errMsg)
277-
}
278-
c.FileList = append(c.FileList, &asset.File{
279-
Filename: fileName,
280-
Data: objData,
281-
})
282-
}
283-
284-
logrus.Infof("Cluster API resources have been created. Waiting for cluster to become ready...")
285-
return nil
286-
}
287-
288135
// Files returns the FileList generated by the asset.
289136
func (c *Cluster) Files() []*asset.File {
290137
return c.FileList

pkg/asset/manifests/clusterapi/cluster.go

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import (
1414
"sigs.k8s.io/yaml"
1515

1616
"github.com/openshift/installer/pkg/asset"
17-
"github.com/openshift/installer/pkg/asset/ignition/bootstrap"
18-
"github.com/openshift/installer/pkg/asset/ignition/machine"
1917
"github.com/openshift/installer/pkg/asset/installconfig"
2018
"github.com/openshift/installer/pkg/asset/manifests"
2119
"github.com/openshift/installer/pkg/asset/manifests/aws"
@@ -49,8 +47,6 @@ func (c *Cluster) Dependencies() []asset.Asset {
4947
&installconfig.ClusterID{},
5048
&openshiftinstall.Config{},
5149
&manifests.FeatureGate{},
52-
&bootstrap.Bootstrap{},
53-
&machine.Master{},
5450
new(rhcos.Image),
5551
}
5652
}
@@ -61,10 +57,8 @@ func (c *Cluster) Generate(dependencies asset.Parents) error {
6157
clusterID := &installconfig.ClusterID{}
6258
openshiftInstall := &openshiftinstall.Config{}
6359
featureGate := &manifests.FeatureGate{}
64-
bootstrapIgnAsset := &bootstrap.Bootstrap{}
65-
masterIgnAsset := &machine.Master{}
6660
rhcosImage := new(rhcos.Image)
67-
dependencies.Get(installConfig, clusterID, openshiftInstall, bootstrapIgnAsset, masterIgnAsset, featureGate, rhcosImage)
61+
dependencies.Get(installConfig, clusterID, openshiftInstall, featureGate, rhcosImage)
6862

6963
// If the feature gate is not enabled, do not generate any manifests.
7064
if !capiutils.IsEnabled(installConfig) {
@@ -93,49 +87,6 @@ func (c *Cluster) Generate(dependencies asset.Parents) error {
9387
}
9488
c.FileList = append(c.FileList, &asset.RuntimeFile{Object: cluster, File: asset.File{Filename: "01_capi-cluster.yaml"}})
9589

96-
// Gather the ignition files, and store them in a secret.
97-
{
98-
masterIgn := string(masterIgnAsset.Files()[0].Data)
99-
bootstrapIgn, err := injectInstallInfo(bootstrapIgnAsset.Files()[0].Data)
100-
if err != nil {
101-
return errors.Wrap(err, "unable to inject installation info")
102-
}
103-
c.FileList = append(c.FileList,
104-
&asset.RuntimeFile{
105-
File: asset.File{Filename: "01_ignition-secret-master.yaml"},
106-
Object: &corev1.Secret{
107-
ObjectMeta: metav1.ObjectMeta{
108-
Name: fmt.Sprintf("%s-%s", clusterID.InfraID, "master"),
109-
Namespace: capiutils.Namespace,
110-
Labels: map[string]string{
111-
"cluster.x-k8s.io/cluster-name": clusterID.InfraID,
112-
},
113-
},
114-
Data: map[string][]byte{
115-
"format": []byte("ignition"),
116-
"value": []byte(masterIgn),
117-
},
118-
},
119-
},
120-
&asset.RuntimeFile{
121-
File: asset.File{Filename: "01_ignition-secret-bootstrap.yaml"},
122-
Object: &corev1.Secret{
123-
ObjectMeta: metav1.ObjectMeta{
124-
Name: fmt.Sprintf("%s-%s", clusterID.InfraID, "bootstrap"),
125-
Namespace: capiutils.Namespace,
126-
Labels: map[string]string{
127-
"cluster.x-k8s.io/cluster-name": clusterID.InfraID,
128-
},
129-
},
130-
Data: map[string][]byte{
131-
"format": []byte("ignition"),
132-
"value": []byte(bootstrapIgn),
133-
},
134-
},
135-
},
136-
)
137-
}
138-
13990
var out *capiutils.GenerateClusterAssetsOutput
14091
switch platform := installConfig.Config.Platform.Name(); platform {
14192
case awstypes.Name:

0 commit comments

Comments
 (0)