github.com/openshift/installer@v1.4.17/pkg/asset/machines/gcp/machines.go (about)

     1  // Package gcp generates Machine objects for gcp.
     2  package gcp
     3  
     4  import (
     5  	"fmt"
     6  	"sort"
     7  
     8  	"github.com/pkg/errors"
     9  	corev1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/runtime"
    12  
    13  	v1 "github.com/openshift/api/config/v1"
    14  	machinev1 "github.com/openshift/api/machine/v1"
    15  	machineapi "github.com/openshift/api/machine/v1beta1"
    16  	"github.com/openshift/installer/pkg/types"
    17  	"github.com/openshift/installer/pkg/types/gcp"
    18  )
    19  
    20  // Machines returns a list of machines for a machinepool.
    21  func Machines(clusterID string, config *types.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string) ([]machineapi.Machine, *machinev1.ControlPlaneMachineSet, error) {
    22  	if configPlatform := config.Platform.Name(); configPlatform != gcp.Name {
    23  		return nil, nil, fmt.Errorf("non-GCP configuration: %q", configPlatform)
    24  	}
    25  	if poolPlatform := pool.Platform.Name(); poolPlatform != gcp.Name {
    26  		return nil, nil, fmt.Errorf("non-GCP machine-pool: %q", poolPlatform)
    27  	}
    28  	platform := config.Platform.GCP
    29  	mpool := pool.Platform.GCP
    30  	azs := mpool.Zones
    31  
    32  	credentialsMode := config.CredentialsMode
    33  
    34  	total := int64(1)
    35  	if pool.Replicas != nil {
    36  		total = *pool.Replicas
    37  	}
    38  
    39  	var machines []machineapi.Machine
    40  	machineSetProvider := &machineapi.GCPMachineProviderSpec{}
    41  	for idx := int64(0); idx < total; idx++ {
    42  		azIndex := int(idx) % len(azs)
    43  		provider, err := provider(clusterID, platform, mpool, osImage, azIndex, role, userDataSecret, credentialsMode)
    44  		if err != nil {
    45  			return nil, nil, errors.Wrap(err, "failed to create provider")
    46  		}
    47  		machine := machineapi.Machine{
    48  			TypeMeta: metav1.TypeMeta{
    49  				APIVersion: "machine.openshift.io/v1beta1",
    50  				Kind:       "Machine",
    51  			},
    52  			ObjectMeta: metav1.ObjectMeta{
    53  				Namespace: "openshift-machine-api",
    54  				Name:      fmt.Sprintf("%s-%s-%d", clusterID, pool.Name, idx),
    55  				Labels: map[string]string{
    56  					"machine.openshift.io/cluster-api-cluster":      clusterID,
    57  					"machine.openshift.io/cluster-api-machine-role": role,
    58  					"machine.openshift.io/cluster-api-machine-type": role,
    59  				},
    60  			},
    61  			Spec: machineapi.MachineSpec{
    62  				ProviderSpec: machineapi.ProviderSpec{
    63  					Value: &runtime.RawExtension{Object: provider},
    64  				},
    65  				// we don't need to set Versions, because we control those via operators.
    66  			},
    67  		}
    68  		*machineSetProvider = *provider
    69  		machines = append(machines, machine)
    70  	}
    71  	replicas := int32(total)
    72  	failureDomains := []machinev1.GCPFailureDomain{}
    73  	sort.Strings(mpool.Zones)
    74  	for _, zone := range mpool.Zones {
    75  		domain := machinev1.GCPFailureDomain{
    76  			Zone: zone,
    77  		}
    78  		failureDomains = append(failureDomains, domain)
    79  	}
    80  	machineSetProvider.Zone = ""
    81  	controlPlaneMachineSet := &machinev1.ControlPlaneMachineSet{
    82  		TypeMeta: metav1.TypeMeta{
    83  			APIVersion: "machine.openshift.io/v1",
    84  			Kind:       "ControlPlaneMachineSet",
    85  		},
    86  		ObjectMeta: metav1.ObjectMeta{
    87  			Namespace: "openshift-machine-api",
    88  			Name:      "cluster",
    89  			Labels: map[string]string{
    90  				"machine.openshift.io/cluster-api-cluster": clusterID,
    91  			},
    92  		},
    93  		Spec: machinev1.ControlPlaneMachineSetSpec{
    94  			Replicas: &replicas,
    95  			State:    machinev1.ControlPlaneMachineSetStateActive,
    96  			Selector: metav1.LabelSelector{
    97  				MatchLabels: map[string]string{
    98  					"machine.openshift.io/cluster-api-machine-role": role,
    99  					"machine.openshift.io/cluster-api-machine-type": role,
   100  					"machine.openshift.io/cluster-api-cluster":      clusterID,
   101  				},
   102  			},
   103  			Template: machinev1.ControlPlaneMachineSetTemplate{
   104  				MachineType: machinev1.OpenShiftMachineV1Beta1MachineType,
   105  				OpenShiftMachineV1Beta1Machine: &machinev1.OpenShiftMachineV1Beta1MachineTemplate{
   106  					FailureDomains: &machinev1.FailureDomains{
   107  						Platform: v1.GCPPlatformType,
   108  						GCP:      &failureDomains,
   109  					},
   110  					ObjectMeta: machinev1.ControlPlaneMachineSetTemplateObjectMeta{
   111  						Labels: map[string]string{
   112  							"machine.openshift.io/cluster-api-cluster":      clusterID,
   113  							"machine.openshift.io/cluster-api-machine-role": role,
   114  							"machine.openshift.io/cluster-api-machine-type": role,
   115  						},
   116  					},
   117  					Spec: machineapi.MachineSpec{
   118  						ProviderSpec: machineapi.ProviderSpec{
   119  							Value: &runtime.RawExtension{Object: machineSetProvider},
   120  						},
   121  					},
   122  				},
   123  			},
   124  		},
   125  	}
   126  
   127  	return machines, controlPlaneMachineSet, nil
   128  }
   129  
   130  func provider(clusterID string, platform *gcp.Platform, mpool *gcp.MachinePool, osImage string, azIdx int, role, userDataSecret string, credentialsMode types.CredentialsMode) (*machineapi.GCPMachineProviderSpec, error) {
   131  	az := mpool.Zones[azIdx]
   132  	if mpool.OSImage != nil {
   133  		osImage = fmt.Sprintf("projects/%s/global/images/%s", mpool.OSImage.Project, mpool.OSImage.Name)
   134  	}
   135  	network, subnetwork, err := getNetworks(platform, clusterID, role)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	var encryptionKey *machineapi.GCPEncryptionKeyReference
   141  
   142  	if mpool.OSDisk.EncryptionKey != nil {
   143  		encryptionKey = &machineapi.GCPEncryptionKeyReference{
   144  			KMSKey: &machineapi.GCPKMSKeyReference{
   145  				Name:      mpool.OSDisk.EncryptionKey.KMSKey.Name,
   146  				KeyRing:   mpool.OSDisk.EncryptionKey.KMSKey.KeyRing,
   147  				ProjectID: mpool.OSDisk.EncryptionKey.KMSKey.ProjectID,
   148  				Location:  mpool.OSDisk.EncryptionKey.KMSKey.Location,
   149  			},
   150  			KMSKeyServiceAccount: mpool.OSDisk.EncryptionKey.KMSKeyServiceAccount,
   151  		}
   152  	}
   153  
   154  	serviceAccountEmail := gcp.GetConfiguredServiceAccount(platform, mpool)
   155  	if serviceAccountEmail == "" {
   156  		serviceAccountEmail = gcp.GetDefaultServiceAccount(platform, clusterID, role[0:1])
   157  	}
   158  
   159  	shieldedInstanceConfig := machineapi.GCPShieldedInstanceConfig{}
   160  	if mpool.SecureBoot == string(machineapi.SecureBootPolicyEnabled) {
   161  		shieldedInstanceConfig.SecureBoot = machineapi.SecureBootPolicyEnabled
   162  	}
   163  	labels := make(map[string]string, len(platform.UserLabels))
   164  	for _, label := range platform.UserLabels {
   165  		labels[label.Key] = label.Value
   166  	}
   167  	tags := make([]machineapi.ResourceManagerTag, len(platform.UserTags))
   168  	for i, tag := range platform.UserTags {
   169  		tags[i] = machineapi.ResourceManagerTag{
   170  			ParentID: tag.ParentID,
   171  			Key:      tag.Key,
   172  			Value:    tag.Value,
   173  		}
   174  	}
   175  	return &machineapi.GCPMachineProviderSpec{
   176  		TypeMeta: metav1.TypeMeta{
   177  			APIVersion: "machine.openshift.io/v1beta1",
   178  			Kind:       "GCPMachineProviderSpec",
   179  		},
   180  		UserDataSecret:    &corev1.LocalObjectReference{Name: userDataSecret},
   181  		CredentialsSecret: &corev1.LocalObjectReference{Name: "gcp-cloud-credentials"},
   182  		Disks: []*machineapi.GCPDisk{{
   183  			AutoDelete:    true,
   184  			Boot:          true,
   185  			SizeGB:        mpool.OSDisk.DiskSizeGB,
   186  			Type:          mpool.OSDisk.DiskType,
   187  			Image:         osImage,
   188  			Labels:        labels,
   189  			EncryptionKey: encryptionKey,
   190  		}},
   191  		NetworkInterfaces: []*machineapi.GCPNetworkInterface{{
   192  			Network:    network,
   193  			ProjectID:  platform.NetworkProjectID,
   194  			Subnetwork: subnetwork,
   195  		}},
   196  		ServiceAccounts: []machineapi.GCPServiceAccount{{
   197  			Email:  serviceAccountEmail,
   198  			Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
   199  		}},
   200  		Tags:                   append(mpool.Tags, []string{fmt.Sprintf("%s-%s", clusterID, role)}...),
   201  		MachineType:            mpool.InstanceType,
   202  		Region:                 platform.Region,
   203  		Zone:                   az,
   204  		ProjectID:              platform.ProjectID,
   205  		ShieldedInstanceConfig: shieldedInstanceConfig,
   206  		ConfidentialCompute:    machineapi.ConfidentialComputePolicy(mpool.ConfidentialCompute),
   207  		OnHostMaintenance:      machineapi.GCPHostMaintenanceType(mpool.OnHostMaintenance),
   208  		Labels:                 labels,
   209  		ResourceManagerTags:    tags,
   210  	}, nil
   211  }
   212  
   213  // ConfigMasters assigns a set of load balancers to the given machines
   214  func ConfigMasters(machines []machineapi.Machine, controlPlane *machinev1.ControlPlaneMachineSet, clusterID string, publish types.PublishingStrategy) error {
   215  	var targetPools []string
   216  	if publish == types.ExternalPublishingStrategy {
   217  		targetPools = append(targetPools, fmt.Sprintf("%s-api", clusterID))
   218  	}
   219  
   220  	for _, machine := range machines {
   221  		providerSpec := machine.Spec.ProviderSpec.Value.Object.(*machineapi.GCPMachineProviderSpec)
   222  		providerSpec.TargetPools = targetPools
   223  	}
   224  
   225  	providerSpec, ok := controlPlane.Spec.Template.OpenShiftMachineV1Beta1Machine.Spec.ProviderSpec.Value.Object.(*machineapi.GCPMachineProviderSpec)
   226  	if !ok {
   227  		return errors.New("Unable to set target pools to control plane machine set")
   228  	}
   229  	providerSpec.TargetPools = targetPools
   230  	return nil
   231  }
   232  func getNetworks(platform *gcp.Platform, clusterID, role string) (string, string, error) {
   233  	if platform.Network == "" {
   234  		return fmt.Sprintf("%s-network", clusterID), fmt.Sprintf("%s-%s-subnet", clusterID, role), nil
   235  	}
   236  
   237  	switch role {
   238  	case "worker":
   239  		return platform.Network, platform.ComputeSubnet, nil
   240  	case "master":
   241  		return platform.Network, platform.ControlPlaneSubnet, nil
   242  	default:
   243  		return "", "", fmt.Errorf("unrecognized machine role %s", role)
   244  	}
   245  }