Skip to content

Commit 538d015

Browse files
committed
ignition: add vpc ipv6 cidr to installconfig if needed
The installconfig in the cluster-config ConfigMap needs to have the Ipv6 CIDR of the VPC in the case of full IPI.
1 parent 819f665 commit 538d015

File tree

4 files changed

+173
-9
lines changed

4 files changed

+173
-9
lines changed

pkg/infrastructure/aws/clusterapi/ignition.go

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,53 @@ import (
1313
capa "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
1414
k8sClient "sigs.k8s.io/controller-runtime/pkg/client"
1515

16+
machinev1 "github.com/openshift/api/machineconfiguration/v1"
1617
"github.com/openshift/installer/pkg/asset/manifests/capiutils"
1718
"github.com/openshift/installer/pkg/infrastructure/clusterapi"
19+
"github.com/openshift/installer/pkg/ipnet"
20+
"github.com/openshift/installer/pkg/types"
1821
awstypes "github.com/openshift/installer/pkg/types/aws"
1922
"github.com/openshift/installer/pkg/types/dns"
2023
)
2124

2225
func editIgnition(ctx context.Context, in clusterapi.IgnitionInput) (*clusterapi.IgnitionOutput, error) {
23-
if in.InstallConfig.Config.AWS.UserProvisionedDNS != dns.UserProvisionedDNSEnabled {
24-
return &clusterapi.IgnitionOutput{
25-
UpdatedBootstrapIgn: in.BootstrapIgnData,
26-
UpdatedMasterIgn: in.MasterIgnData,
27-
UpdatedWorkerIgn: in.WorkerIgnData}, nil
26+
// To be revised: The IgnitionOutput and IgnitionInput can be chained in a series of editIgnition calls.
27+
// To update output with latest ignition output, use (*IgnitionOutput).Set(*IgnitionOutput).
28+
// To update input with latest ignition output (to use as input for another editIgnition call), use (*IgnitionInput).SetIgnFromOutput(*IgnitionOutput).
29+
ignOutput := &clusterapi.IgnitionOutput{
30+
UpdatedBootstrapIgn: in.BootstrapIgnData,
31+
UpdatedMasterIgn: in.MasterIgnData,
32+
UpdatedWorkerIgn: in.WorkerIgnData,
2833
}
2934

35+
// Dualstack mode
36+
if in.InstallConfig.Config.IsDualStackInfra() {
37+
// If there is no IPv6 machine network in the install-config, that means AWS will assign a IPv6 GUA range during
38+
// infrastructure provisioning. Thus, after VPC is ready, we need to populate the install config with the VPC IPv6 CIDR.
39+
if len(capiutils.MachineCIDRsFromInstallConfig(in.InstallConfig).IPv6Nets()) == 0 {
40+
dualStackIgnOut, err := editIgnitionForDualStack(ctx, in)
41+
if err != nil {
42+
return ignOutput, err
43+
}
44+
ignOutput.Set(dualStackIgnOut)
45+
in.SetIgnFromOutput(ignOutput)
46+
}
47+
}
48+
49+
// Custom DNS
50+
if in.InstallConfig.Config.AWS.UserProvisionedDNS == dns.UserProvisionedDNSEnabled {
51+
customDNSIgnOut, err := editIgnitionForCustomDNS(ctx, in)
52+
if err != nil {
53+
return ignOutput, err
54+
}
55+
ignOutput.Set(customDNSIgnOut)
56+
in.SetIgnFromOutput(ignOutput)
57+
}
58+
59+
return ignOutput, nil
60+
}
61+
62+
func editIgnitionForCustomDNS(ctx context.Context, in clusterapi.IgnitionInput) (*clusterapi.IgnitionOutput, error) {
3063
awsCluster := &capa.AWSCluster{}
3164
key := k8sClient.ObjectKey{
3265
Name: in.InfraID,
@@ -89,5 +122,36 @@ func editIgnition(ctx context.Context, in clusterapi.IgnitionInput) (*clusterapi
89122
publicIPAddresses = privateIPAddresses
90123
}
91124
logrus.Debugf("AWS: Editing Ignition files to start in-cluster DNS when UserProvisionedDNS is enabled")
92-
return clusterapi.EditIgnition(in, awstypes.Name, publicIPAddresses, privateIPAddresses)
125+
return clusterapi.EditIgnitionForCustomDNS(in, awstypes.Name, publicIPAddresses, privateIPAddresses)
126+
}
127+
128+
func editIgnitionForDualStack(ctx context.Context, in clusterapi.IgnitionInput) (*clusterapi.IgnitionOutput, error) {
129+
awsCluster := &capa.AWSCluster{}
130+
key := k8sClient.ObjectKey{
131+
Name: in.InfraID,
132+
Namespace: capiutils.Namespace,
133+
}
134+
if err := in.Client.Get(ctx, key, awsCluster); err != nil {
135+
return nil, fmt.Errorf("failed to get AWSCluster: %w", err)
136+
}
137+
138+
machineNetworks := in.InstallConfig.Config.MachineNetwork
139+
// Assumption: When IPv6 is enabled, the AWSCluster IPv6 block should be non-nil
140+
// And the VPC IPv6 CIDR is valid (i.e. set by CAPA)
141+
vpcIPv6CIDR := awsCluster.Spec.NetworkSpec.VPC.IPv6.CidrBlock
142+
143+
ic := in.InstallConfig.Config
144+
ipv6Entry := []types.MachineNetworkEntry{
145+
{
146+
CIDR: *ipnet.MustParseCIDR(vpcIPv6CIDR),
147+
},
148+
}
149+
if ic.InfraStack() == machinev1.IPFamiliesDualStackIPv6Primary {
150+
machineNetworks = append(ipv6Entry, machineNetworks...)
151+
} else {
152+
machineNetworks = append(machineNetworks, ipv6Entry...)
153+
}
154+
155+
logrus.Debugf("AWS: Editing Ignition files to add VPC IPv6 CIDR to the machine")
156+
return clusterapi.EditIgnitionForDualStack(in, awstypes.Name, machineNetworks)
93157
}

pkg/infrastructure/clusterapi/ignition.go

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/openshift/installer/pkg/asset/lbconfig"
2121
"github.com/openshift/installer/pkg/asset/machines"
2222
"github.com/openshift/installer/pkg/asset/tls"
23+
"github.com/openshift/installer/pkg/types"
2324
awstypes "github.com/openshift/installer/pkg/types/aws"
2425
gcptypes "github.com/openshift/installer/pkg/types/gcp"
2526
)
@@ -31,20 +32,24 @@ const (
3132
mcsCertFile = "/opt/openshift/tls/machine-config-server.crt"
3233
masterUserDataFile = "/opt/openshift/openshift/99_openshift-cluster-api_master-user-data-secret.yaml"
3334
workerUserDataFile = "/opt/openshift/openshift/99_openshift-cluster-api_worker-user-data-secret.yaml"
35+
clusterConfigDataFile = "/opt/openshift/manifests/cluster-config.yaml"
3436

3537
// header is the string that precedes the encoded data in the ignition data.
3638
// The data must be replaced before decoding the string, and the string must be
3739
// prepended to the encoded data.
3840
header = "data:text/plain;charset=utf-8;base64,"
3941

42+
// The key in the cluster-config-v1 ConfigMap to extract the install-config.
43+
clusterConfigCMKey = "install-config"
44+
4045
masterRole = "master"
4146
workerRole = "worker"
4247
)
4348

44-
// EditIgnition attempts to edit the contents of the bootstrap ignition when the user has selected
49+
// EditIgnitionForCustomDNS attempts to edit the contents of the bootstrap ignition when the user has selected
4550
// a custom DNS configuration. Find the public and private load balancer addresses and fill in the
4651
// infrastructure file within the ignition struct.
47-
func EditIgnition(in IgnitionInput, platform string, publicIPAddresses, privateIPAddresses []string) (*IgnitionOutput, error) {
52+
func EditIgnitionForCustomDNS(in IgnitionInput, platform string, publicIPAddresses, privateIPAddresses []string) (*IgnitionOutput, error) {
4853
ignData := &igntypes.Config{}
4954
err := json.Unmarshal(in.BootstrapIgnData, ignData)
5055
if err != nil {
@@ -287,3 +292,76 @@ func updateUserDataSecret(in IgnitionInput, role string, config *igntypes.Config
287292
}
288293
return nil
289294
}
295+
296+
// EditIgnitionForDualStack attempts to edit the contents of the bootstrap ignition when the cluster is in dualstack.
297+
// This addes the missing IPv6 manchine network for platform where IPv6 CIDRs are not known at install time, for example, AWS.
298+
func EditIgnitionForDualStack(in IgnitionInput, platform string, machineNetworks []types.MachineNetworkEntry) (*IgnitionOutput, error) {
299+
ignData := &igntypes.Config{}
300+
err := json.Unmarshal(in.BootstrapIgnData, ignData)
301+
if err != nil {
302+
return nil, fmt.Errorf("failed to unmarshal bootstrap ignition: %w", err)
303+
}
304+
305+
err = updateMachineNetworks(in, ignData, machineNetworks)
306+
if err != nil {
307+
return nil, fmt.Errorf("failed to add VPC IPv6 CIDR to ignition config: %w", err)
308+
}
309+
logrus.Debugf("Successfully added VPC IPv6 CIDR to the install-config machine networks")
310+
311+
editedIgnBytes, err := json.Marshal(ignData)
312+
if err != nil {
313+
return nil, fmt.Errorf("failed to convert ignition data to json: %w", err)
314+
}
315+
logrus.Debugf("Successfully updated bootstrap ignition with updated manifests")
316+
317+
return &IgnitionOutput{
318+
UpdatedBootstrapIgn: editedIgnBytes,
319+
UpdatedMasterIgn: in.MasterIgnData,
320+
UpdatedWorkerIgn: in.WorkerIgnData,
321+
}, nil
322+
}
323+
324+
func updateMachineNetworks(in IgnitionInput, config *igntypes.Config, machineNetworks []types.MachineNetworkEntry) error {
325+
for i, fileData := range config.Storage.Files {
326+
if fileData.Path == clusterConfigDataFile {
327+
contents := strings.Split(*config.Storage.Files[i].Contents.Source, ",")
328+
rawDecodedText, err := base64.StdEncoding.DecodeString(contents[1])
329+
if err != nil {
330+
return fmt.Errorf("failed to decode contents of ignition file: %w", err)
331+
}
332+
333+
configCM := &corev1.ConfigMap{}
334+
if err := yaml.Unmarshal(rawDecodedText, configCM); err != nil {
335+
return fmt.Errorf("failed to unmarshal cluster-config ConfigMap: %w", err)
336+
}
337+
338+
installConfig := &types.InstallConfig{}
339+
if err := yaml.Unmarshal([]byte(configCM.Data[clusterConfigCMKey]), installConfig); err != nil {
340+
return fmt.Errorf("failed to unmarshal install-config content: %w", err)
341+
}
342+
343+
// Update the machine network field
344+
installConfig.MachineNetwork = machineNetworks
345+
346+
// Convert the installconfig back to string and save it to the configmap
347+
icContents, err := yaml.Marshal(installConfig)
348+
if err != nil {
349+
return fmt.Errorf("failed to marshal install-config: %w", err)
350+
}
351+
configCM.Data[clusterConfigCMKey] = string(icContents)
352+
353+
// convert the infrastructure back to an encoded string
354+
configCMContents, err := yaml.Marshal(configCM)
355+
if err != nil {
356+
return fmt.Errorf("failed to marshal cluster-config ConfigMap: %w", err)
357+
}
358+
359+
encoded := fmt.Sprintf("%s%s", header, base64.StdEncoding.EncodeToString(configCMContents))
360+
// replace the contents with the edited information
361+
config.Storage.Files[i].Contents.Source = &encoded
362+
363+
break
364+
}
365+
}
366+
return nil
367+
}

pkg/infrastructure/clusterapi/types.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,35 @@ type IgnitionInput struct {
7272
RootCA *tls.RootCA
7373
}
7474

75+
// SetIgnFromOutput set the ignition data for input from an output.
76+
// This is used to chain multiple ignition editions.
77+
func (ignIn *IgnitionInput) SetIgnFromOutput(outIgn *IgnitionOutput) {
78+
if ignIn == nil || outIgn == nil {
79+
return
80+
}
81+
ignIn.BootstrapIgnData = outIgn.UpdatedBootstrapIgn
82+
ignIn.MasterIgnData = outIgn.UpdatedMasterIgn
83+
ignIn.WorkerIgnData = outIgn.UpdatedWorkerIgn
84+
}
85+
7586
// IgnitionOutput collects updated Ignition Data for Bootstrap, Master and Worker nodes.
7687
type IgnitionOutput struct {
7788
UpdatedBootstrapIgn []byte
7889
UpdatedMasterIgn []byte
7990
UpdatedWorkerIgn []byte
8091
}
8192

93+
// Set set the ignition data from another output.
94+
// This is used for chained multiple ignition editions.
95+
func (ignOut *IgnitionOutput) Set(other *IgnitionOutput) {
96+
if ignOut == nil || other == nil {
97+
return
98+
}
99+
ignOut.UpdatedBootstrapIgn = other.UpdatedBootstrapIgn
100+
ignOut.UpdatedMasterIgn = other.UpdatedMasterIgn
101+
ignOut.UpdatedWorkerIgn = other.UpdatedWorkerIgn
102+
}
103+
82104
// InfraReadyProvider defines the InfraReady hook, which is
83105
// called after the initial infrastructure manifests have been created
84106
// and InfrastructureReady == true on the cluster status, and before

pkg/infrastructure/gcp/clusterapi/ignition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,5 @@ func editIgnition(ctx context.Context, in clusterapi.IgnitionInput) (*clusterapi
7070
}
7171

7272
logrus.Debugf("GCP: Editing Ignition files to start in-cluster DNS when UserProvisionedDNS is enabled")
73-
return clusterapi.EditIgnition(in, gcp.Name, []string{computeAddress}, []string{computeIntAddress})
73+
return clusterapi.EditIgnitionForCustomDNS(in, gcp.Name, []string{computeAddress}, []string{computeIntAddress})
7474
}

0 commit comments

Comments
 (0)