github.com/openshift/installer@v1.4.17/pkg/clusterapi/providers.go (about) 1 package clusterapi 2 3 import ( 4 "archive/zip" 5 "bytes" 6 "embed" 7 "fmt" 8 "io" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 "k8s.io/apimachinery/pkg/util/sets" 16 ) 17 18 const ( 19 zipFile = "cluster-api.zip" 20 ) 21 22 var ( 23 // ClusterAPI is the core provider for cluster-api. 24 ClusterAPI = Provider{ 25 Name: "cluster-api", 26 Sources: sets.New("cluster-api"), 27 } 28 29 // EnvTest is the provider for the local control plane. 30 EnvTest = Provider{ 31 Name: "envtest", 32 Sources: sets.New("kube-apiserver", "etcd"), 33 } 34 35 // AWS is the provider for creating resources in AWS. 36 AWS = infrastructureProvider("aws") 37 // Azure is the provider for creating resources in Azure. 38 Azure = infrastructureProvider("azure") 39 // AzureASO is a companion component to Azure that is used to create resources declaratively. 40 AzureASO = infrastructureProvider("azureaso") 41 // GCP is the provider for creating resources in GCP. 42 GCP = infrastructureProvider("gcp") 43 // IBMCloud is the provider for creating resources in IBM Cloud and powervs. 44 IBMCloud = infrastructureProvider("ibmcloud") 45 // Nutanix is the provider for creating resources in Nutanix. 46 Nutanix = infrastructureProvider("nutanix") 47 // OpenStack is the provider for creating resources in OpenStack. 48 OpenStack = infrastructureProvider("openstack") 49 // VSphere is the provider for creating resources in vSphere. 50 VSphere = infrastructureProvider("vsphere") 51 ) 52 53 // Provider is a Cluster API provider. 54 type Provider struct { 55 // Name of the provider. 56 Name string 57 // Sources of the provider. 58 Sources sets.Set[string] 59 } 60 61 // infrastructureProvider configures a infrastructureProvider built locally. 62 func infrastructureProvider(name string) Provider { 63 return Provider{ 64 Name: name, 65 Sources: sets.New( 66 fmt.Sprintf("cluster-api-provider-%s", name), 67 ), 68 } 69 } 70 71 // Mirror is the embedded data for the providers. 72 // 73 //go:embed mirror/* 74 var Mirror embed.FS 75 76 // Extract extracts the provider from the embedded data into the specified directory. 77 func (p Provider) Extract(dir string) error { 78 f, err := Mirror.Open(filepath.Join("mirror", zipFile)) 79 if err != nil { 80 return errors.Wrap(err, "failed to open cluster api zip from mirror") 81 } 82 defer f.Close() 83 stat, err := f.Stat() 84 if err != nil { 85 return errors.Wrap(err, "failed to stat cluster api zip") 86 } 87 seek, ok := f.(io.ReaderAt) 88 if !ok { 89 // If the file does not support ReaderAt interface (<Go1.20) 90 // we need to read the whole file into memory. 91 b, err := io.ReadAll(f) 92 if err != nil { 93 return errors.Wrap(err, "failed to read cluster api zip") 94 } 95 seek = bytes.NewReader(b) 96 } 97 98 // Open a zip archive for reading. 99 r, err := zip.NewReader(seek, stat.Size()) 100 if err != nil { 101 return errors.Wrap(err, "failed to open cluster api zip") 102 } 103 104 // Ensure the directory exists. 105 logrus.Debugf("Creating %s directory", dir) 106 if err := os.MkdirAll(dir, 0o777); err != nil { 107 return errors.Wrapf(err, "could not make directory for the %s provider", p.Name) 108 } 109 110 // Extract the files. 111 for _, f := range r.File { 112 name := f.Name 113 if !p.Sources.Has(name) { 114 continue 115 } 116 path, err := sanitizeArchivePath(dir, name) 117 if err != nil { 118 return errors.Wrapf(err, "failed to sanitize archive file %q", name) 119 } 120 logrus.Debugf("Extracting %s file", path) 121 if err := unpackFile(f, path); err != nil { 122 return errors.Wrapf(err, "failed to extract %q", path) 123 } 124 } 125 return nil 126 } 127 128 func unpackFile(f *zip.File, destPath string) error { 129 src, err := f.Open() 130 if err != nil { 131 return errors.Wrapf(err, "failed to open file %s", f.Name) 132 } 133 defer src.Close() 134 destFile, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o777) 135 if err != nil { 136 return err 137 } 138 defer destFile.Close() 139 if _, err := io.CopyN(destFile, src, f.FileInfo().Size()); err != nil { 140 return err 141 } 142 return nil 143 } 144 145 func sanitizeArchivePath(d, t string) (v string, err error) { 146 v = filepath.Join(d, t) 147 if strings.HasPrefix(v, filepath.Clean(d)) { 148 return v, nil 149 } 150 151 return "", fmt.Errorf("%s: %s", "content filepath is tainted", t) 152 } 153 154 // UnpackClusterAPIBinary unpacks the cluster-api binary from the embedded data so that it can be run to create the 155 // infrastructure for the cluster. 156 func UnpackClusterAPIBinary(dir string) error { 157 return ClusterAPI.Extract(dir) 158 } 159 160 // UnpackEnvtestBinaries unpacks the envtest binaries from the embedded data so that it can be run to create the 161 // infrastructure for the cluster. 162 func UnpackEnvtestBinaries(dir string) error { 163 return EnvTest.Extract(dir) 164 }