github.com/openshift/installer@v1.4.17/pkg/infrastructure/gcp/clusterapi/ignition.go (about) 1 package clusterapi 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "strings" 9 "time" 10 11 igntypes "github.com/coreos/ignition/v2/config/v3_2/types" 12 capg "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1" 13 "sigs.k8s.io/controller-runtime/pkg/client" 14 "sigs.k8s.io/yaml" 15 16 configv1 "github.com/openshift/api/config/v1" 17 "github.com/openshift/installer/pkg/asset/manifests/capiutils" 18 "github.com/openshift/installer/pkg/infrastructure/clusterapi" 19 "github.com/openshift/installer/pkg/types/gcp" 20 ) 21 22 const ( 23 infrastructureFilepath = "/opt/openshift/manifests/cluster-infrastructure-02-config.yml" 24 25 // replaceable is the string that precedes the encoded data in the ignition data. 26 // The data must be replaced before decoding the string, and the string must be 27 // prepended to the encoded data. 28 replaceable = "data:text/plain;charset=utf-8;base64," 29 ) 30 31 // EditIgnition attempts to edit the contents of the bootstrap ignition when the user has selected 32 // a custom DNS configuration. Find the public and private load balancer addresses and fill in the 33 // infrastructure file within the ignition struct. 34 func EditIgnition(ctx context.Context, in clusterapi.IgnitionInput) ([]byte, error) { 35 ctx, cancel := context.WithTimeout(ctx, time.Minute*2) 36 defer cancel() 37 38 if in.InstallConfig.Config.GCP.UserProvisionedDNS == gcp.UserProvisionedDNSEnabled { 39 gcpCluster := &capg.GCPCluster{} 40 key := client.ObjectKey{ 41 Name: in.InfraID, 42 Namespace: capiutils.Namespace, 43 } 44 if err := in.Client.Get(ctx, key, gcpCluster); err != nil { 45 return nil, fmt.Errorf("failed to get GCP cluster: %w", err) 46 } 47 48 // public load balancer and health check are created by capi gcp provider. 49 // TODO: this is currently a global address 50 apiIPAddress := *gcpCluster.Status.Network.APIServerAddress 51 52 ignData := &igntypes.Config{} 53 err := json.Unmarshal(in.BootstrapIgnData, ignData) 54 if err != nil { 55 return nil, fmt.Errorf("failed to unmarshal bootstrap ignition: %w", err) 56 } 57 58 apiIntIPAddress, err := getInternalLBAddress(ctx, in.InstallConfig.Config.GCP.ProjectID, in.InstallConfig.Config.GCP.Region, getAPIAddressName(in.InfraID)) 59 if err != nil { 60 return nil, fmt.Errorf("failed to create the internal load balancer address: %w", err) 61 } 62 63 err = addLoadBalancersToInfra(gcp.Name, ignData, []string{apiIPAddress}, []string{apiIntIPAddress}) 64 if err != nil { 65 return nil, fmt.Errorf("failed to add load balancers to ignition config: %w", err) 66 } 67 68 editedIgnBytes, err := json.Marshal(ignData) 69 if err != nil { 70 return nil, fmt.Errorf("failed to convert ignition data to json: %w", err) 71 } 72 73 return editedIgnBytes, nil 74 } 75 76 return nil, nil 77 } 78 79 // addLoadBalancersToInfra will load the public and private load balancer information into 80 // the infrastructure CR. This will occur after the data has already been inserted into the 81 // ignition file. 82 func addLoadBalancersToInfra(platform string, config *igntypes.Config, publicLBs []string, privateLBs []string) error { 83 for i, fileData := range config.Storage.Files { 84 // update the contents of this file 85 if fileData.Path == infrastructureFilepath { 86 contents := config.Storage.Files[i].Contents.Source 87 replaced := strings.Replace(*contents, replaceable, "", 1) 88 89 rawDecodedText, err := base64.StdEncoding.DecodeString(replaced) 90 if err != nil { 91 return fmt.Errorf("failed to decode contents of ignition file: %w", err) 92 } 93 94 infra := &configv1.Infrastructure{} 95 if err := yaml.Unmarshal(rawDecodedText, infra); err != nil { 96 return fmt.Errorf("failed to unmarshal infrastructure: %w", err) 97 } 98 99 // convert the list of strings to a list of IPs 100 apiIntLbs := []configv1.IP{} 101 for _, ip := range privateLBs { 102 apiIntLbs = append(apiIntLbs, configv1.IP(ip)) 103 } 104 apiLbs := []configv1.IP{} 105 for _, ip := range publicLBs { 106 apiLbs = append(apiLbs, configv1.IP(ip)) 107 } 108 cloudLBInfo := configv1.CloudLoadBalancerIPs{ 109 APIIntLoadBalancerIPs: apiIntLbs, 110 APILoadBalancerIPs: apiLbs, 111 } 112 113 if infra.Status.PlatformStatus.GCP.CloudLoadBalancerConfig.DNSType == configv1.ClusterHostedDNSType { 114 infra.Status.PlatformStatus.GCP.CloudLoadBalancerConfig.ClusterHosted = &cloudLBInfo 115 } 116 117 // convert the infrastructure back to an encoded string 118 infraContents, err := yaml.Marshal(infra) 119 if err != nil { 120 return fmt.Errorf("failed to marshal infrastructure: %w", err) 121 } 122 123 encoded := fmt.Sprintf("%s%s", replaceable, base64.StdEncoding.EncodeToString(infraContents)) 124 // replace the contents with the edited information 125 config.Storage.Files[i].Contents.Source = &encoded 126 127 break 128 } 129 } 130 131 return nil 132 }