github.com/openshift/installer@v1.4.17/pkg/asset/manifests/openshift.go (about) 1 package manifests 2 3 import ( 4 "context" 5 "encoding/base64" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 11 "github.com/gophercloud/utils/v2/openstack/clientconfig" 12 "github.com/pkg/errors" 13 "github.com/sirupsen/logrus" 14 "k8s.io/apimachinery/pkg/util/sets" 15 "sigs.k8s.io/yaml" 16 17 "github.com/openshift/installer/pkg/asset" 18 "github.com/openshift/installer/pkg/asset/installconfig" 19 installconfigaws "github.com/openshift/installer/pkg/asset/installconfig/aws" 20 "github.com/openshift/installer/pkg/asset/installconfig/gcp" 21 "github.com/openshift/installer/pkg/asset/installconfig/ibmcloud" 22 "github.com/openshift/installer/pkg/asset/installconfig/ovirt" 23 "github.com/openshift/installer/pkg/asset/machines" 24 osmachine "github.com/openshift/installer/pkg/asset/machines/openstack" 25 openstackmanifests "github.com/openshift/installer/pkg/asset/manifests/openstack" 26 "github.com/openshift/installer/pkg/asset/openshiftinstall" 27 "github.com/openshift/installer/pkg/asset/password" 28 "github.com/openshift/installer/pkg/asset/rhcos" 29 "github.com/openshift/installer/pkg/asset/templates/content/openshift" 30 "github.com/openshift/installer/pkg/types" 31 awstypes "github.com/openshift/installer/pkg/types/aws" 32 azuretypes "github.com/openshift/installer/pkg/types/azure" 33 baremetaltypes "github.com/openshift/installer/pkg/types/baremetal" 34 gcptypes "github.com/openshift/installer/pkg/types/gcp" 35 ibmcloudtypes "github.com/openshift/installer/pkg/types/ibmcloud" 36 openstacktypes "github.com/openshift/installer/pkg/types/openstack" 37 ovirttypes "github.com/openshift/installer/pkg/types/ovirt" 38 vspheretypes "github.com/openshift/installer/pkg/types/vsphere" 39 ) 40 41 const ( 42 openshiftManifestDir = "openshift" 43 ) 44 45 var ( 46 _ asset.WritableAsset = (*Openshift)(nil) 47 ) 48 49 // Openshift generates the dependent resource manifests for openShift (as against bootkube) 50 type Openshift struct { 51 FileList []*asset.File 52 } 53 54 // Name returns a human friendly name for the operator 55 func (o *Openshift) Name() string { 56 return "Openshift Manifests" 57 } 58 59 // Dependencies returns all of the dependencies directly needed by the 60 // Openshift asset 61 func (o *Openshift) Dependencies() []asset.Asset { 62 return []asset.Asset{ 63 &installconfig.InstallConfig{}, 64 &installconfig.ClusterID{}, 65 &password.KubeadminPassword{}, 66 &openshiftinstall.Config{}, 67 &FeatureGate{}, 68 69 &openshift.CloudCredsSecret{}, 70 &openshift.KubeadminPasswordSecret{}, 71 &openshift.RoleCloudCredsSecretReader{}, 72 &openshift.BaremetalConfig{}, 73 new(rhcos.Image), 74 &openshift.AzureCloudProviderSecret{}, 75 } 76 } 77 78 // Generate generates the respective operator config.yml files 79 // 80 //nolint:gocyclo 81 func (o *Openshift) Generate(ctx context.Context, dependencies asset.Parents) error { 82 installConfig := &installconfig.InstallConfig{} 83 clusterID := &installconfig.ClusterID{} 84 kubeadminPassword := &password.KubeadminPassword{} 85 openshiftInstall := &openshiftinstall.Config{} 86 featureGate := &FeatureGate{} 87 dependencies.Get(installConfig, kubeadminPassword, clusterID, openshiftInstall, featureGate) 88 var cloudCreds cloudCredsSecretData 89 platform := installConfig.Config.Platform.Name() 90 switch platform { 91 case awstypes.Name: 92 ssn, err := installConfig.AWS.Session(ctx) 93 if err != nil { 94 return err 95 } 96 creds, err := ssn.Config.Credentials.Get() 97 if err != nil { 98 return err 99 } 100 if !installconfigaws.IsStaticCredentials(creds) { 101 switch { 102 case installConfig.Config.CredentialsMode == "": 103 return errors.Errorf("AWS credentials provided by %s are not valid for default credentials mode", creds.ProviderName) 104 case installConfig.Config.CredentialsMode != types.ManualCredentialsMode: 105 return errors.Errorf("AWS credentials provided by %s are not valid for %s credentials mode", creds.ProviderName, installConfig.Config.CredentialsMode) 106 } 107 } 108 cloudCreds = cloudCredsSecretData{ 109 AWS: &AwsCredsSecretData{ 110 Base64encodeAccessKeyID: base64.StdEncoding.EncodeToString([]byte(creds.AccessKeyID)), 111 Base64encodeSecretAccessKey: base64.StdEncoding.EncodeToString([]byte(creds.SecretAccessKey)), 112 }, 113 } 114 case azuretypes.Name: 115 resourceGroupName := installConfig.Config.Azure.ClusterResourceGroupName(clusterID.InfraID) 116 session, err := installConfig.Azure.Session() 117 if err != nil { 118 return err 119 } 120 creds := session.Credentials 121 cloudCreds = cloudCredsSecretData{ 122 Azure: &AzureCredsSecretData{ 123 Base64encodeSubscriptionID: base64.StdEncoding.EncodeToString([]byte(creds.SubscriptionID)), 124 Base64encodeClientID: base64.StdEncoding.EncodeToString([]byte(creds.ClientID)), 125 Base64encodeClientSecret: base64.StdEncoding.EncodeToString([]byte(creds.ClientSecret)), 126 Base64encodeTenantID: base64.StdEncoding.EncodeToString([]byte(creds.TenantID)), 127 Base64encodeResourcePrefix: base64.StdEncoding.EncodeToString([]byte(clusterID.InfraID)), 128 Base64encodeResourceGroup: base64.StdEncoding.EncodeToString([]byte(resourceGroupName)), 129 Base64encodeRegion: base64.StdEncoding.EncodeToString([]byte(installConfig.Config.Azure.Region)), 130 }, 131 } 132 case gcptypes.Name: 133 session, err := gcp.GetSession(ctx) 134 if err != nil { 135 return err 136 } 137 creds := session.Credentials.JSON 138 cloudCreds = cloudCredsSecretData{ 139 GCP: &GCPCredsSecretData{ 140 Base64encodeServiceAccount: base64.StdEncoding.EncodeToString(creds), 141 }, 142 } 143 case ibmcloudtypes.Name: 144 client, err := ibmcloud.NewClient(installConfig.Config.Platform.IBMCloud.ServiceEndpoints) 145 if err != nil { 146 return err 147 } 148 cloudCreds = cloudCredsSecretData{ 149 IBMCloud: &IBMCloudCredsSecretData{ 150 Base64encodeAPIKey: base64.StdEncoding.EncodeToString([]byte(client.GetAPIKey())), 151 }, 152 } 153 case openstacktypes.Name: 154 opts := new(clientconfig.ClientOpts) 155 opts.Cloud = installConfig.Config.Platform.OpenStack.Cloud 156 cloud, err := clientconfig.GetCloudFromYAML(opts) 157 if err != nil { 158 return err 159 } 160 161 // We need to replace the local cacert path with one that is used in OpenShift 162 if cloud.CACertFile != "" { 163 cloud.CACertFile = "/etc/kubernetes/static-pod-resources/configmaps/cloud-config/ca-bundle.pem" 164 } 165 166 // Application credentials are easily rotated in the event of a leak and should be preferred. Encourage their use. 167 authTypes := sets.New(clientconfig.AuthPassword, clientconfig.AuthV2Password, clientconfig.AuthV3Password) 168 if cloud.AuthInfo != nil && authTypes.Has(cloud.AuthType) { 169 logrus.Warnf( 170 "clouds.yaml file is using %q type auth. Consider using the %q auth type instead to rotate credentials more easily.", 171 cloud.AuthType, 172 clientconfig.AuthV3ApplicationCredential, 173 ) 174 } 175 176 clouds := make(map[string]map[string]*clientconfig.Cloud) 177 clouds["clouds"] = map[string]*clientconfig.Cloud{ 178 osmachine.CloudName: cloud, 179 } 180 181 marshalled, err := yaml.Marshal(clouds) 182 if err != nil { 183 return err 184 } 185 186 cloudProviderConf, err := openstackmanifests.CloudProviderConfigSecret(cloud) 187 if err != nil { 188 return err 189 } 190 191 credsEncoded := base64.StdEncoding.EncodeToString(marshalled) 192 credsINIEncoded := base64.StdEncoding.EncodeToString(cloudProviderConf) 193 cloudCreds = cloudCredsSecretData{ 194 OpenStack: &OpenStackCredsSecretData{ 195 Base64encodeCloudCreds: credsEncoded, 196 Base64encodeCloudCredsINI: credsINIEncoded, 197 }, 198 } 199 case vspheretypes.Name: 200 vsphereCredList := make([]*VSphereCredsSecretData, 0) 201 202 for _, vCenter := range installConfig.Config.VSphere.VCenters { 203 vsphereCred := VSphereCredsSecretData{ 204 VCenter: vCenter.Server, 205 Base64encodeUsername: base64.StdEncoding.EncodeToString([]byte(vCenter.Username)), 206 Base64encodePassword: base64.StdEncoding.EncodeToString([]byte(vCenter.Password)), 207 } 208 vsphereCredList = append(vsphereCredList, &vsphereCred) 209 } 210 211 cloudCreds = cloudCredsSecretData{ 212 VSphere: &vsphereCredList, 213 } 214 case ovirttypes.Name: 215 conf, err := ovirt.NewConfig() 216 if err != nil { 217 return err 218 } 219 220 if len(conf.CABundle) == 0 && len(conf.CAFile) > 0 { 221 content, err := os.ReadFile(conf.CAFile) 222 if err != nil { 223 return errors.Wrapf(err, "failed to read the cert file: %s", conf.CAFile) 224 } 225 conf.CABundle = strings.TrimSpace(string(content)) 226 } 227 228 cloudCreds = cloudCredsSecretData{ 229 Ovirt: &OvirtCredsSecretData{ 230 Base64encodeURL: base64.StdEncoding.EncodeToString([]byte(conf.URL)), 231 Base64encodeUsername: base64.StdEncoding.EncodeToString([]byte(conf.Username)), 232 Base64encodePassword: base64.StdEncoding.EncodeToString([]byte(conf.Password)), 233 Base64encodeInsecure: base64.StdEncoding.EncodeToString([]byte(strconv.FormatBool(conf.Insecure))), 234 Base64encodeCABundle: base64.StdEncoding.EncodeToString([]byte(conf.CABundle)), 235 }, 236 } 237 } 238 239 templateData := &openshiftTemplateData{ 240 CloudCreds: cloudCreds, 241 Base64EncodedKubeadminPwHash: base64.StdEncoding.EncodeToString(kubeadminPassword.PasswordHash), 242 } 243 244 cloudCredsSecret := &openshift.CloudCredsSecret{} 245 kubeadminPasswordSecret := &openshift.KubeadminPasswordSecret{} 246 roleCloudCredsSecretReader := &openshift.RoleCloudCredsSecretReader{} 247 baremetalConfig := &openshift.BaremetalConfig{} 248 rhcosImage := new(rhcos.Image) 249 250 dependencies.Get( 251 cloudCredsSecret, 252 kubeadminPasswordSecret, 253 roleCloudCredsSecretReader, 254 baremetalConfig, 255 rhcosImage) 256 257 assetData := map[string][]byte{ 258 "99_kubeadmin-password-secret.yaml": applyTemplateData(kubeadminPasswordSecret.Files()[0].Data, templateData), 259 } 260 261 switch platform { 262 case awstypes.Name, openstacktypes.Name, vspheretypes.Name, azuretypes.Name, gcptypes.Name, ibmcloudtypes.Name, ovirttypes.Name: 263 if installConfig.Config.CredentialsMode != types.ManualCredentialsMode { 264 assetData["99_cloud-creds-secret.yaml"] = applyTemplateData(cloudCredsSecret.Files()[0].Data, templateData) 265 } 266 assetData["99_role-cloud-creds-secret-reader.yaml"] = applyTemplateData(roleCloudCredsSecretReader.Files()[0].Data, templateData) 267 case baremetaltypes.Name: 268 bmTemplateData := baremetalTemplateData{ 269 Baremetal: installConfig.Config.Platform.BareMetal, 270 ProvisioningOSDownloadURL: rhcosImage.ControlPlane, 271 } 272 assetData["99_baremetal-provisioning-config.yaml"] = applyTemplateData(baremetalConfig.Files()[0].Data, bmTemplateData) 273 } 274 275 if platform == azuretypes.Name && installConfig.Config.Azure.IsARO() && installConfig.Config.CredentialsMode != types.ManualCredentialsMode { 276 // config is used to created compatible secret to trigger azure cloud 277 // controller config merge behaviour 278 // https://github.com/openshift/origin/blob/90c050f5afb4c52ace82b15e126efe98fa798d88/vendor/k8s.io/legacy-cloud-providers/azure/azure_config.go#L83 279 session, err := installConfig.Azure.Session() 280 if err != nil { 281 return err 282 } 283 config := struct { 284 AADClientID string `json:"aadClientId" yaml:"aadClientId"` 285 AADClientSecret string `json:"aadClientSecret" yaml:"aadClientSecret"` 286 }{ 287 AADClientID: session.Credentials.ClientID, 288 AADClientSecret: session.Credentials.ClientSecret, 289 } 290 291 b, err := yaml.Marshal(config) 292 if err != nil { 293 return err 294 } 295 296 azureCloudProviderSecret := &openshift.AzureCloudProviderSecret{} 297 dependencies.Get(azureCloudProviderSecret) 298 for _, f := range azureCloudProviderSecret.Files() { 299 name := strings.TrimSuffix(filepath.Base(f.Filename), ".template") 300 assetData[name] = applyTemplateData(f.Data, map[string]string{ 301 "CloudConfig": string(b), 302 }) 303 } 304 } 305 306 o.FileList = []*asset.File{} 307 for name, data := range assetData { 308 if len(data) == 0 { 309 continue 310 } 311 o.FileList = append(o.FileList, &asset.File{ 312 Filename: filepath.Join(openshiftManifestDir, name), 313 Data: data, 314 }) 315 } 316 317 o.FileList = append(o.FileList, openshiftInstall.Files()...) 318 o.FileList = append(o.FileList, featureGate.Files()...) 319 320 asset.SortFiles(o.FileList) 321 322 return nil 323 } 324 325 // Files returns the files generated by the asset. 326 func (o *Openshift) Files() []*asset.File { 327 return o.FileList 328 } 329 330 // Load returns the openshift asset from disk. 331 func (o *Openshift) Load(f asset.FileFetcher) (bool, error) { 332 yamlFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.yaml")) 333 if err != nil { 334 return false, errors.Wrap(err, "failed to load *.yaml files") 335 } 336 ymlFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.yml")) 337 if err != nil { 338 return false, errors.Wrap(err, "failed to load *.yml files") 339 } 340 jsonFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.json")) 341 if err != nil { 342 return false, errors.Wrap(err, "failed to load *.json files") 343 } 344 fileList := append(yamlFileList, ymlFileList...) 345 fileList = append(fileList, jsonFileList...) 346 347 for _, file := range fileList { 348 if machines.IsMachineManifest(file) { 349 continue 350 } 351 352 o.FileList = append(o.FileList, file) 353 } 354 355 asset.SortFiles(o.FileList) 356 return len(o.FileList) > 0, nil 357 }