github.com/openshift/installer@v1.4.17/pkg/tfvars/ibmcloud/ibmcloud.go (about)

     1  package ibmcloud
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/sirupsen/logrus"
     9  
    10  	configv1 "github.com/openshift/api/config/v1"
    11  	"github.com/openshift/installer/pkg/rhcos/cache"
    12  	"github.com/openshift/installer/pkg/types"
    13  	ibmcloudtypes "github.com/openshift/installer/pkg/types/ibmcloud"
    14  	ibmcloudprovider "github.com/openshift/machine-api-provider-ibmcloud/pkg/apis/ibmcloudprovider/v1"
    15  )
    16  
    17  // IBMCloudEndpointJSONFileName is the file containing the IBM Cloud Terraform provider's endpoint override JSON.
    18  const IBMCloudEndpointJSONFileName = "ibmcloud_endpoints_override.json"
    19  
    20  // Auth is the collection of credentials that will be used by terrform.
    21  type Auth struct {
    22  	APIKey string `json:"ibmcloud_api_key,omitempty"`
    23  }
    24  
    25  // DedicatedHost is the format used by terraform.
    26  type DedicatedHost struct {
    27  	ID      string `json:"id,omitempty"`
    28  	Profile string `json:"profile,omitempty"`
    29  }
    30  
    31  type config struct {
    32  	Auth                       `json:",inline"`
    33  	BootstrapInstanceType      string          `json:"ibmcloud_bootstrap_instance_type,omitempty"`
    34  	CISInstanceCRN             string          `json:"ibmcloud_cis_crn,omitempty"`
    35  	ComputeSubnets             []string        `json:"ibmcloud_compute_subnets,omitempty"`
    36  	ControlPlaneBootVolumeKey  string          `json:"ibmcloud_control_plane_boot_volume_key"`
    37  	ControlPlaneSubnets        []string        `json:"ibmcloud_control_plane_subnets,omitempty"`
    38  	DNSInstanceID              string          `json:"ibmcloud_dns_id,omitempty"`
    39  	EndpointsJSONFile          string          `json:"ibmcloud_endpoints_json_file,omitempty"`
    40  	ExtraTags                  []string        `json:"ibmcloud_extra_tags,omitempty"`
    41  	ImageFilePath              string          `json:"ibmcloud_image_filepath,omitempty"`
    42  	MasterAvailabilityZones    []string        `json:"ibmcloud_master_availability_zones"`
    43  	MasterInstanceType         string          `json:"ibmcloud_master_instance_type,omitempty"`
    44  	MasterDedicatedHosts       []DedicatedHost `json:"ibmcloud_master_dedicated_hosts,omitempty"`
    45  	NetworkResourceGroupName   string          `json:"ibmcloud_network_resource_group_name,omitempty"`
    46  	PreexistingVPC             bool            `json:"ibmcloud_preexisting_vpc,omitempty"`
    47  	PublishStrategy            string          `json:"ibmcloud_publish_strategy,omitempty"`
    48  	Region                     string          `json:"ibmcloud_region,omitempty"`
    49  	ResourceGroupName          string          `json:"ibmcloud_resource_group_name,omitempty"`
    50  	TerraformPrivateVisibility bool            `json:"ibmcloud_terraform_private_visibility,omitempty"`
    51  	VPC                        string          `json:"ibmcloud_vpc,omitempty"`
    52  	VPCPermitted               bool            `json:"ibmcloud_vpc_permitted,omitempty"`
    53  	WorkerAvailabilityZones    []string        `json:"ibmcloud_worker_availability_zones"`
    54  	WorkerDedicatedHosts       []DedicatedHost `json:"ibmcloud_worker_dedicated_hosts,omitempty"`
    55  }
    56  
    57  // TFVarsSources contains the parameters to be converted into Terraform variables
    58  type TFVarsSources struct {
    59  	Auth                       Auth
    60  	CISInstanceCRN             string
    61  	DNSInstanceID              string
    62  	EndpointsJSONFile          string
    63  	ImageURL                   string
    64  	MasterConfigs              []*ibmcloudprovider.IBMCloudMachineProviderSpec
    65  	MasterDedicatedHosts       []DedicatedHost
    66  	NetworkResourceGroupName   string
    67  	PreexistingVPC             bool
    68  	PublishStrategy            types.PublishingStrategy
    69  	ResourceGroupName          string
    70  	TerraformPrivateVisibility bool
    71  	VPCPermitted               bool
    72  	WorkerConfigs              []*ibmcloudprovider.IBMCloudMachineProviderSpec
    73  	WorkerDedicatedHosts       []DedicatedHost
    74  }
    75  
    76  // TFVars generates ibmcloud-specific Terraform variables launching the cluster.
    77  func TFVars(sources TFVarsSources) ([]byte, error) {
    78  	cachedImage, err := cache.DownloadImageFile(sources.ImageURL, cache.InstallerApplicationName)
    79  	if err != nil {
    80  		return nil, errors.Wrap(err, "failed to use cached ibmcloud image")
    81  	}
    82  
    83  	masterConfig := sources.MasterConfigs[0]
    84  	masterAvailabilityZones := make([]string, len(sources.MasterConfigs))
    85  	for i, c := range sources.MasterConfigs {
    86  		masterAvailabilityZones[i] = c.Zone
    87  	}
    88  	workerAvailabilityZones := make([]string, len(sources.WorkerConfigs))
    89  	for i, c := range sources.WorkerConfigs {
    90  		workerAvailabilityZones[i] = c.Zone
    91  	}
    92  
    93  	// Set pre-existing network config
    94  	var vpc string
    95  	masterSubnets := make([]string, len(sources.MasterConfigs))
    96  	workerSubnets := make([]string, len(sources.WorkerConfigs))
    97  	if sources.PreexistingVPC {
    98  		vpc = sources.MasterConfigs[0].VPC
    99  		for index, config := range sources.MasterConfigs {
   100  			masterSubnets[index] = config.PrimaryNetworkInterface.Subnet
   101  		}
   102  		for index, config := range sources.WorkerConfigs {
   103  			workerSubnets[index] = config.PrimaryNetworkInterface.Subnet
   104  		}
   105  	}
   106  
   107  	cfg := &config{
   108  		Auth:                       sources.Auth,
   109  		BootstrapInstanceType:      masterConfig.Profile,
   110  		CISInstanceCRN:             sources.CISInstanceCRN,
   111  		ComputeSubnets:             workerSubnets,
   112  		ControlPlaneBootVolumeKey:  masterConfig.BootVolume.EncryptionKey,
   113  		ControlPlaneSubnets:        masterSubnets,
   114  		DNSInstanceID:              sources.DNSInstanceID,
   115  		EndpointsJSONFile:          sources.EndpointsJSONFile,
   116  		ImageFilePath:              cachedImage,
   117  		MasterAvailabilityZones:    masterAvailabilityZones,
   118  		MasterDedicatedHosts:       sources.MasterDedicatedHosts,
   119  		MasterInstanceType:         masterConfig.Profile,
   120  		NetworkResourceGroupName:   sources.NetworkResourceGroupName,
   121  		PreexistingVPC:             sources.PreexistingVPC,
   122  		PublishStrategy:            string(sources.PublishStrategy),
   123  		Region:                     masterConfig.Region,
   124  		ResourceGroupName:          sources.ResourceGroupName,
   125  		TerraformPrivateVisibility: sources.TerraformPrivateVisibility,
   126  		VPC:                        vpc,
   127  		VPCPermitted:               sources.VPCPermitted,
   128  		WorkerAvailabilityZones:    workerAvailabilityZones,
   129  		WorkerDedicatedHosts:       sources.WorkerDedicatedHosts,
   130  
   131  		// TODO: IBM: Future support
   132  		// ExtraTags:               masterConfig.Tags,
   133  	}
   134  
   135  	return json.MarshalIndent(cfg, "", "  ")
   136  }
   137  
   138  // CreateEndpointJSON creates JSON data containing IBM Cloud service endpoint override mappings.
   139  func CreateEndpointJSON(endpoints []configv1.IBMCloudServiceEndpoint, region string) ([]byte, error) {
   140  	// If no endpoint overrides, simply return
   141  	if len(endpoints) == 0 {
   142  		return nil, nil
   143  	}
   144  
   145  	endpointContents := ibmcloudtypes.EndpointsJSON{}
   146  	for _, endpoint := range endpoints {
   147  		switch endpoint.Name {
   148  		// COS endpoint is not used in Terraform
   149  		case configv1.IBMCloudServiceCOS:
   150  			continue
   151  		case configv1.IBMCloudServiceCIS:
   152  			endpointContents.IBMCloudEndpointCIS = &ibmcloudtypes.EndpointsVisibility{
   153  				Private: map[string]string{
   154  					region: endpoint.URL,
   155  				},
   156  				Public: map[string]string{
   157  					region: endpoint.URL,
   158  				},
   159  			}
   160  		case configv1.IBMCloudServiceDNSServices:
   161  			endpointContents.IBMCloudEndpointDNSServices = &ibmcloudtypes.EndpointsVisibility{
   162  				Private: map[string]string{
   163  					region: endpoint.URL,
   164  				},
   165  				Public: map[string]string{
   166  					region: endpoint.URL,
   167  				},
   168  			}
   169  		case configv1.IBMCloudServiceGlobalSearch:
   170  			endpointContents.IBMCloudEndpointGlobalSearch = &ibmcloudtypes.EndpointsVisibility{
   171  				Private: map[string]string{
   172  					region: endpoint.URL,
   173  				},
   174  				Public: map[string]string{
   175  					region: endpoint.URL,
   176  				},
   177  			}
   178  		case configv1.IBMCloudServiceGlobalTagging:
   179  			endpointContents.IBMCloudEndpointGlobalTagging = &ibmcloudtypes.EndpointsVisibility{
   180  				Private: map[string]string{
   181  					region: endpoint.URL,
   182  				},
   183  				Public: map[string]string{
   184  					region: endpoint.URL,
   185  				},
   186  			}
   187  		case configv1.IBMCloudServiceHyperProtect:
   188  			endpointContents.IBMCloudEndpointHyperProtect = &ibmcloudtypes.EndpointsVisibility{
   189  				Private: map[string]string{
   190  					region: endpoint.URL,
   191  				},
   192  				Public: map[string]string{
   193  					region: endpoint.URL,
   194  				},
   195  			}
   196  		case configv1.IBMCloudServiceIAM:
   197  			endpointContents.IBMCloudEndpointIAM = &ibmcloudtypes.EndpointsVisibility{
   198  				Private: map[string]string{
   199  					region: endpoint.URL,
   200  				},
   201  				Public: map[string]string{
   202  					region: endpoint.URL,
   203  				},
   204  			}
   205  		case configv1.IBMCloudServiceKeyProtect:
   206  			endpointContents.IBMCloudEndpointKeyProtect = &ibmcloudtypes.EndpointsVisibility{
   207  				Private: map[string]string{
   208  					region: endpoint.URL,
   209  				},
   210  				Public: map[string]string{
   211  					region: endpoint.URL,
   212  				},
   213  			}
   214  		case configv1.IBMCloudServiceResourceController:
   215  			endpointContents.IBMCloudEndpointResourceController = &ibmcloudtypes.EndpointsVisibility{
   216  				Private: map[string]string{
   217  					region: endpoint.URL,
   218  				},
   219  				Public: map[string]string{
   220  					region: endpoint.URL,
   221  				},
   222  			}
   223  		case configv1.IBMCloudServiceResourceManager:
   224  			endpointContents.IBMCloudEndpointResourceManager = &ibmcloudtypes.EndpointsVisibility{
   225  				Private: map[string]string{
   226  					region: endpoint.URL,
   227  				},
   228  				Public: map[string]string{
   229  					region: endpoint.URL,
   230  				},
   231  			}
   232  		case configv1.IBMCloudServiceVPC:
   233  			endpointContents.IBMCloudEndpointVPC = &ibmcloudtypes.EndpointsVisibility{
   234  				Private: map[string]string{
   235  					region: endpoint.URL,
   236  				},
   237  				Public: map[string]string{
   238  					region: endpoint.URL,
   239  				},
   240  			}
   241  		default:
   242  			return nil, fmt.Errorf("unable to build override values for unknown service: %s", endpoint.Name)
   243  		}
   244  	}
   245  	jsonData, err := json.Marshal(endpointContents)
   246  	if err != nil {
   247  		return nil, fmt.Errorf("failure building service endpoint override JSON data: %w", err)
   248  	}
   249  
   250  	// If the JSON contains no data, none was populated (jsonData == "{}"), but endpoints is not empty, we assume the Services are not required for Terraform (e.g., COS)
   251  	// Log this as a warning, but continue as if no service endpoints were provided
   252  	if len(jsonData) <= 2 {
   253  		logrus.Warnf("no terraform endpoint json was created for services: %s", endpoints)
   254  		return nil, nil
   255  	}
   256  	return jsonData, nil
   257  }