github.com/openshift/installer@v1.4.17/pkg/clusterapi/localcontrolplane.go (about)

     1  package clusterapi
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	capnv1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
    11  	"github.com/sirupsen/logrus"
    12  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    13  	"k8s.io/client-go/kubernetes/scheme"
    14  	"k8s.io/client-go/rest"
    15  	"k8s.io/client-go/tools/clientcmd"
    16  	"k8s.io/client-go/tools/clientcmd/api"
    17  	"k8s.io/klog/v2"
    18  	capav1beta1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1"
    19  	capav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
    20  	capzv1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    21  	capgv1 "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1"
    22  	capiv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
    23  	capov1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
    24  	capvv1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
    25  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    26  	"sigs.k8s.io/controller-runtime/pkg/client"
    27  	"sigs.k8s.io/controller-runtime/pkg/envtest"
    28  	"sigs.k8s.io/controller-runtime/pkg/log"
    29  
    30  	"github.com/openshift/installer/cmd/openshift-install/command"
    31  )
    32  
    33  var (
    34  	// Scheme is the scheme used by the local control plane.
    35  	Scheme = scheme.Scheme
    36  )
    37  
    38  func init() {
    39  	utilruntime.Must(clusterv1.AddToScheme(Scheme))
    40  	utilruntime.Must(capav1beta1.AddToScheme(Scheme))
    41  	utilruntime.Must(capav1.AddToScheme(Scheme))
    42  	utilruntime.Must(capzv1.AddToScheme(Scheme))
    43  	utilruntime.Must(capgv1.AddToScheme(Scheme))
    44  	utilruntime.Must(capvv1.AddToScheme(Scheme))
    45  	utilruntime.Must(capov1.AddToScheme(Scheme))
    46  	utilruntime.Must(capiv1.AddToScheme(Scheme))
    47  	utilruntime.Must(capnv1.AddToScheme(Scheme))
    48  }
    49  
    50  // localControlPlane creates a local capi control plane
    51  // to use as a management cluster.
    52  type localControlPlane struct {
    53  	Env            *envtest.Environment
    54  	Client         client.Client
    55  	Cfg            *rest.Config
    56  	BinDir         string
    57  	EtcdDataDir    string
    58  	KubeconfigPath string
    59  	EtcdLog        *os.File
    60  	APIServerLog   *os.File
    61  }
    62  
    63  // Run launches the local control plane.
    64  func (c *localControlPlane) Run(ctx context.Context) error {
    65  	// Create a temporary directory to unpack the cluster-api binaries.
    66  	c.BinDir = filepath.Join(command.RootOpts.Dir, "cluster-api")
    67  	if err := UnpackClusterAPIBinary(c.BinDir); err != nil {
    68  		return fmt.Errorf("failed to unpack cluster-api binary: %w", err)
    69  	}
    70  	if err := UnpackEnvtestBinaries(c.BinDir); err != nil {
    71  		return fmt.Errorf("failed to unpack envtest binaries: %w", err)
    72  	}
    73  	c.EtcdDataDir = filepath.Join(command.RootOpts.Dir, ArtifactsDir, "etcd")
    74  
    75  	// Write etcd & kube-apiserver output to log files.
    76  	var err error
    77  	if err := os.MkdirAll(filepath.Join(command.RootOpts.Dir, ArtifactsDir), 0750); err != nil {
    78  		return fmt.Errorf("error creating artifacts dir: %w", err)
    79  	}
    80  	if c.EtcdLog, err = os.Create(filepath.Join(command.RootOpts.Dir, ArtifactsDir, "etcd.log")); err != nil {
    81  		return fmt.Errorf("failed to create etcd log file: %w", err)
    82  	}
    83  	if c.APIServerLog, err = os.Create(filepath.Join(command.RootOpts.Dir, ArtifactsDir, "kube-apiserver.log")); err != nil {
    84  		return fmt.Errorf("failed to create kube-apiserver log file: %w", err)
    85  	}
    86  
    87  	log.SetLogger(klog.NewKlogr())
    88  	logrus.Info("Started local control plane with envtest")
    89  	c.Env = &envtest.Environment{
    90  		Scheme:                   Scheme,
    91  		AttachControlPlaneOutput: true,
    92  		BinaryAssetsDirectory:    c.BinDir,
    93  		ControlPlaneStartTimeout: 10 * time.Second,
    94  		ControlPlaneStopTimeout:  10 * time.Second,
    95  		ControlPlane: envtest.ControlPlane{
    96  			Etcd: &envtest.Etcd{
    97  				DataDir: c.EtcdDataDir,
    98  				Out:     c.EtcdLog,
    99  				Err:     c.EtcdLog,
   100  			},
   101  			APIServer: &envtest.APIServer{
   102  				Out: c.APIServerLog,
   103  				Err: c.APIServerLog,
   104  			},
   105  		},
   106  	}
   107  	c.Cfg, err = c.Env.Start()
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	artifactsDirPath := filepath.Join(command.RootOpts.Dir, ArtifactsDir)
   113  	err = os.MkdirAll(artifactsDirPath, 0750)
   114  	if err != nil {
   115  		return fmt.Errorf("error creating cluster-api artifacts directory: %w", err)
   116  	}
   117  
   118  	kc := fromEnvTestConfig(c.Cfg)
   119  	{
   120  		kf, err := os.Create(filepath.Join(artifactsDirPath, "envtest.kubeconfig"))
   121  		if err != nil {
   122  			return err
   123  		}
   124  		if _, err := kf.Write(kc); err != nil {
   125  			return err
   126  		}
   127  		if err := kf.Close(); err != nil {
   128  			return err
   129  		}
   130  		c.KubeconfigPath, err = filepath.Abs(kf.Name())
   131  		if err != nil {
   132  			return err
   133  		}
   134  	}
   135  
   136  	// Create a new client to interact with the cluster.
   137  	cl, err := client.New(c.Cfg, client.Options{
   138  		Scheme: c.Env.Scheme,
   139  	})
   140  	if err != nil {
   141  		return err
   142  	}
   143  	c.Client = cl
   144  
   145  	logrus.Infof("Stored kubeconfig for envtest in: %v", c.KubeconfigPath)
   146  	return nil
   147  }
   148  
   149  func (c *localControlPlane) Stop() error {
   150  	return c.Env.Stop()
   151  }
   152  
   153  // fromEnvTestConfig returns a new Kubeconfig in byte form when running in envtest.
   154  func fromEnvTestConfig(cfg *rest.Config) []byte {
   155  	clusterName := "envtest"
   156  	contextName := fmt.Sprintf("%s@%s", cfg.Username, clusterName)
   157  	c := api.Config{
   158  		Clusters: map[string]*api.Cluster{
   159  			clusterName: {
   160  				Server:                   cfg.Host,
   161  				CertificateAuthorityData: cfg.CAData,
   162  			},
   163  		},
   164  		Contexts: map[string]*api.Context{
   165  			contextName: {
   166  				Cluster:  clusterName,
   167  				AuthInfo: cfg.Username,
   168  			},
   169  		},
   170  		AuthInfos: map[string]*api.AuthInfo{
   171  			cfg.Username: {
   172  				ClientKeyData:         cfg.KeyData,
   173  				ClientCertificateData: cfg.CertData,
   174  			},
   175  		},
   176  		CurrentContext: contextName,
   177  	}
   178  	data, err := clientcmd.Write(c)
   179  	if err != nil {
   180  		logrus.Fatalf("failed to write kubeconfig: %v", err)
   181  	}
   182  	return data
   183  }