github.com/openshift/installer@v1.4.17/pkg/asset/manifests/clusterapi/cluster.go (about)

     1  package clusterapi
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  	"github.com/sirupsen/logrus"
    11  	corev1 "k8s.io/api/core/v1"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    14  	"k8s.io/utils/ptr"
    15  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    16  	"sigs.k8s.io/controller-runtime/pkg/client"
    17  	"sigs.k8s.io/yaml"
    18  
    19  	"github.com/openshift/installer/pkg/asset"
    20  	"github.com/openshift/installer/pkg/asset/installconfig"
    21  	"github.com/openshift/installer/pkg/asset/manifests"
    22  	"github.com/openshift/installer/pkg/asset/manifests/aws"
    23  	"github.com/openshift/installer/pkg/asset/manifests/azure"
    24  	"github.com/openshift/installer/pkg/asset/manifests/capiutils"
    25  	"github.com/openshift/installer/pkg/asset/manifests/gcp"
    26  	"github.com/openshift/installer/pkg/asset/manifests/nutanix"
    27  	"github.com/openshift/installer/pkg/asset/manifests/openstack"
    28  	"github.com/openshift/installer/pkg/asset/manifests/powervs"
    29  	"github.com/openshift/installer/pkg/asset/manifests/vsphere"
    30  	"github.com/openshift/installer/pkg/asset/openshiftinstall"
    31  	"github.com/openshift/installer/pkg/asset/rhcos"
    32  	"github.com/openshift/installer/pkg/clusterapi"
    33  	awstypes "github.com/openshift/installer/pkg/types/aws"
    34  	azuretypes "github.com/openshift/installer/pkg/types/azure"
    35  	gcptypes "github.com/openshift/installer/pkg/types/gcp"
    36  	nutanixtypes "github.com/openshift/installer/pkg/types/nutanix"
    37  	openstacktypes "github.com/openshift/installer/pkg/types/openstack"
    38  	powervstypes "github.com/openshift/installer/pkg/types/powervs"
    39  	vsphereplatform "github.com/openshift/installer/pkg/types/vsphere"
    40  )
    41  
    42  var _ asset.WritableRuntimeAsset = (*Cluster)(nil)
    43  
    44  // Cluster generates manifests for target cluster
    45  // creation using CAPI.
    46  type Cluster struct {
    47  	FileList []*asset.RuntimeFile
    48  }
    49  
    50  // Name returns a human friendly name for the operator.
    51  func (c *Cluster) Name() string {
    52  	return "Cluster API Manifests"
    53  }
    54  
    55  // Dependencies returns all of the dependencies directly needed by the
    56  // ClusterAPI asset.
    57  func (c *Cluster) Dependencies() []asset.Asset {
    58  	return []asset.Asset{
    59  		&installconfig.InstallConfig{},
    60  		&installconfig.ClusterID{},
    61  		&openshiftinstall.Config{},
    62  		&manifests.FeatureGate{},
    63  		new(rhcos.Image),
    64  	}
    65  }
    66  
    67  // Generate generates the respective operator config.yml files.
    68  func (c *Cluster) Generate(_ context.Context, dependencies asset.Parents) error {
    69  	installConfig := &installconfig.InstallConfig{}
    70  	clusterID := &installconfig.ClusterID{}
    71  	openshiftInstall := &openshiftinstall.Config{}
    72  	featureGate := &manifests.FeatureGate{}
    73  	rhcosImage := new(rhcos.Image)
    74  	dependencies.Get(installConfig, clusterID, openshiftInstall, featureGate, rhcosImage)
    75  
    76  	// If the feature gate is not enabled, do not generate any manifests.
    77  	if !capiutils.IsEnabled(installConfig) {
    78  		return nil
    79  	}
    80  
    81  	c.FileList = []*asset.RuntimeFile{}
    82  
    83  	namespace := &corev1.Namespace{
    84  		ObjectMeta: metav1.ObjectMeta{
    85  			Name: capiutils.Namespace,
    86  		},
    87  	}
    88  	namespace.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Namespace"))
    89  	c.FileList = append(c.FileList, &asset.RuntimeFile{Object: namespace, File: asset.File{Filename: "000_capi-namespace.yaml"}})
    90  
    91  	var out *capiutils.GenerateClusterAssetsOutput
    92  	switch platform := installConfig.Config.Platform.Name(); platform {
    93  	case awstypes.Name:
    94  		var err error
    95  		out, err = aws.GenerateClusterAssets(installConfig, clusterID)
    96  		if err != nil {
    97  			return errors.Wrap(err, "failed to generate AWS manifests")
    98  		}
    99  	case azuretypes.Name:
   100  		var err error
   101  		out, err = azure.GenerateClusterAssets(installConfig, clusterID)
   102  		if err != nil {
   103  			return errors.Wrap(err, "failed to generate Azure manifests")
   104  		}
   105  	case gcptypes.Name:
   106  		var err error
   107  		out, err = gcp.GenerateClusterAssets(installConfig, clusterID)
   108  		if err != nil {
   109  			return fmt.Errorf("failed to generate GCP manifests: %w", err)
   110  		}
   111  	case vsphereplatform.Name:
   112  		var err error
   113  		out, err = vsphere.GenerateClusterAssets(installConfig, clusterID)
   114  		if err != nil {
   115  			return fmt.Errorf("failed to generate vSphere manifests %w", err)
   116  		}
   117  	case openstacktypes.Name:
   118  		var err error
   119  		out, err = openstack.GenerateClusterAssets(installConfig, clusterID)
   120  		if err != nil {
   121  			return errors.Wrap(err, "failed to generate OpenStack manifests")
   122  		}
   123  	case powervstypes.Name:
   124  		var err error
   125  		osImage := strings.SplitN(rhcosImage.ControlPlane, "/", 2)
   126  		out, err = powervs.GenerateClusterAssets(installConfig, clusterID, osImage[0], osImage[1])
   127  		if err != nil {
   128  			return fmt.Errorf("failed to generate PowerVS manifests %w", err)
   129  		}
   130  	case nutanixtypes.Name:
   131  		var err error
   132  		out, err = nutanix.GenerateClusterAssets(installConfig, clusterID)
   133  		if err != nil {
   134  			return errors.Wrap(err, "failed to generate Nutanix manifests")
   135  		}
   136  	default:
   137  		return fmt.Errorf("unsupported platform %q", platform)
   138  	}
   139  
   140  	if len(out.InfrastructureRefs) == 0 {
   141  		return fmt.Errorf("failed to generate manifests: cluster.Spec.InfrastructureRef was never set")
   142  	}
   143  
   144  	logrus.Infof("Adding clusters...")
   145  	for index, infra := range out.InfrastructureRefs {
   146  		cluster := &clusterv1.Cluster{
   147  			ObjectMeta: metav1.ObjectMeta{
   148  				Name:      infra.Name,
   149  				Namespace: capiutils.Namespace,
   150  			},
   151  			Spec: clusterv1.ClusterSpec{
   152  				ClusterNetwork: &clusterv1.ClusterNetwork{
   153  					APIServerPort: ptr.To[int32](6443),
   154  				},
   155  			},
   156  		}
   157  		cluster.Spec.InfrastructureRef = infra
   158  		cluster.SetGroupVersionKind(clusterv1.GroupVersion.WithKind("Cluster"))
   159  		c.FileList = append(c.FileList, &asset.RuntimeFile{Object: cluster, File: asset.File{Filename: fmt.Sprintf("01_capi-cluster-%d.yaml", index)}})
   160  	}
   161  
   162  	// Append the infrastructure manifests.
   163  	c.FileList = append(c.FileList, out.Manifests...)
   164  
   165  	// Create the infrastructure manifests.
   166  	for _, m := range c.FileList {
   167  		objData, err := yaml.Marshal(m.Object)
   168  		if err != nil {
   169  			return errors.Wrapf(err, "failed to marshal infrastructure manifest %s", m.Filename)
   170  		}
   171  		m.Data = objData
   172  
   173  		// If the filename is already a path, do not append the manifest dir.
   174  		if filepath.Dir(m.Filename) == capiutils.ManifestDir {
   175  			continue
   176  		}
   177  		m.Filename = filepath.Join(capiutils.ManifestDir, m.Filename)
   178  	}
   179  
   180  	asset.SortManifestFiles(c.FileList)
   181  	return nil
   182  }
   183  
   184  // Files returns the files generated by the asset.
   185  func (c *Cluster) Files() []*asset.File {
   186  	files := []*asset.File{}
   187  	for _, f := range c.FileList {
   188  		f := f // TODO: remove with golang 1.22
   189  		files = append(files, &f.File)
   190  	}
   191  	return files
   192  }
   193  
   194  // RuntimeFiles returns the files generated by the asset.
   195  func (c *Cluster) RuntimeFiles() []*asset.RuntimeFile {
   196  	return c.FileList
   197  }
   198  
   199  // Load returns the openshift asset from disk.
   200  func (c *Cluster) Load(f asset.FileFetcher) (bool, error) {
   201  	yamlFileList, err := f.FetchByPattern(filepath.Join(capiutils.ManifestDir, "*.yaml"))
   202  	if err != nil {
   203  		return false, errors.Wrap(err, "failed to load *.yaml files")
   204  	}
   205  	ymlFileList, err := f.FetchByPattern(filepath.Join(capiutils.ManifestDir, "*.yml"))
   206  	if err != nil {
   207  		return false, errors.Wrap(err, "failed to load *.yml files")
   208  	}
   209  	jsonFileList, err := f.FetchByPattern(filepath.Join(capiutils.ManifestDir, "*.json"))
   210  	if err != nil {
   211  		return false, errors.Wrap(err, "failed to load *.json files")
   212  	}
   213  	fileList := append(yamlFileList, ymlFileList...) //nolint:gocritic
   214  	fileList = append(fileList, jsonFileList...)
   215  
   216  	for _, file := range fileList {
   217  		u := &unstructured.Unstructured{}
   218  		if err := yaml.Unmarshal(file.Data, u); err != nil {
   219  			return false, errors.Wrap(err, "failed to unmarshal file")
   220  		}
   221  		obj, err := clusterapi.Scheme.New(u.GroupVersionKind())
   222  		if err != nil {
   223  			return false, errors.Wrap(err, "failed to create object")
   224  		}
   225  		if err := clusterapi.Scheme.Convert(u, obj, nil); err != nil {
   226  			return false, errors.Wrap(err, "failed to convert object")
   227  		}
   228  		c.FileList = append(c.FileList, &asset.RuntimeFile{
   229  			File: asset.File{
   230  				Filename: file.Filename,
   231  				Data:     file.Data,
   232  			},
   233  			Object: obj.(client.Object),
   234  		})
   235  	}
   236  
   237  	asset.SortManifestFiles(c.FileList)
   238  	return len(c.FileList) > 0, nil
   239  }