diff --git a/pkg/asset/byo/byo.go b/pkg/asset/byo/byo.go new file mode 100644 index 00000000000..73b635f4f20 --- /dev/null +++ b/pkg/asset/byo/byo.go @@ -0,0 +1,68 @@ +package byo + +import ( + "github.com/openshift/installer/pkg/asset" + "path/filepath" +) + +const ( + PluginsDir = "plugins" +) + +type Deployment struct { + FileList []*asset.File +} + +var _ asset.Asset = (*Deployment)(nil) + +func (d *Deployment) Name() string { + return "BYO Deployment" +} + +func (d *Deployment) Dependencies() []asset.Asset { + return []asset.Asset{} +} + +func (d *Deployment) Generate(asset.Parents) error { + return nil +} + +func (d *Deployment) Files() []*asset.File { + return d.FileList +} + +// Load returns the deployment asset from disk. +func (d *Deployment) Load(f asset.FileFetcher) (bool, error) { + var fileList []*asset.File + + // get the main.tf + mainFile, err := f.FetchByName("main.tf") + if err != nil { + return false, err + } + fileList = append(fileList, mainFile) + + // get the variables-*.tf + variablesFile, err := f.FetchByPattern("variables-*.tf") + if err != nil { + return false, err + } + fileList = append(fileList, variablesFile...) + + // get all modules + modulesFileList, err := f.FetchByPattern(filepath.Join("**/*.tf")) + if err != nil { + return false, err + } + fileList = append(fileList, modulesFileList...) + + // get plugins + pluginsFileList, _ := f.FetchByPattern(filepath.Join(PluginsDir, "**/*")) + fileList = append(fileList, pluginsFileList...) + + d.FileList = fileList + + asset.SortFiles(d.FileList) + + return true, nil +} diff --git a/pkg/asset/cluster/cluster.go b/pkg/asset/cluster/cluster.go index 98a018a6e87..60ba605529d 100644 --- a/pkg/asset/cluster/cluster.go +++ b/pkg/asset/cluster/cluster.go @@ -2,17 +2,16 @@ package cluster import ( "fmt" - "io/ioutil" - "os" - "path/filepath" - - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/byo" "github.com/openshift/installer/pkg/asset/installconfig" "github.com/openshift/installer/pkg/asset/password" "github.com/openshift/installer/pkg/terraform" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "io/ioutil" + "os" + "path/filepath" ) var ( @@ -45,6 +44,7 @@ func (c *Cluster) Dependencies() []asset.Asset { &installconfig.PlatformCredsCheck{}, &TerraformVariables{}, &password.KubeadminPassword{}, + &byo.Deployment{}, } } @@ -54,7 +54,8 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { installConfig := &installconfig.InstallConfig{} terraformVariables := &TerraformVariables{} kubeadminPassword := &password.KubeadminPassword{} - parents.Get(clusterID, installConfig, terraformVariables, kubeadminPassword) + byoDeployment := &byo.Deployment{} + parents.Get(clusterID, installConfig, terraformVariables, kubeadminPassword, byoDeployment) if installConfig.Config.Platform.None != nil { return errors.New("cluster cannot be created with platform set to 'none'") @@ -82,8 +83,25 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { }, } + c.FileList = append(c.FileList, byoDeployment.Files()...) + for _, file := range byoDeployment.Files() { + // create path if not exists + path := filepath.Dir(filepath.Join(tmpDir, file.Filename)) + if _, err := os.Stat(path); os.IsNotExist(err) { + err = os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + } + + // write the file + if err := ioutil.WriteFile(filepath.Join(tmpDir, file.Filename), file.Data, 0700); err != nil { + return err + } + } + logrus.Infof("Creating cluster...") - stateFile, err := terraform.Apply(tmpDir, installConfig.Config.Platform.Name(), extraArgs...) + stateFile, err := terraform.Apply(tmpDir, installConfig.Config.Platform.Name(), installConfig.Config.BYO, extraArgs...) if err != nil { err = errors.Wrap(err, "failed to create cluster") if stateFile == "" { diff --git a/pkg/asset/cluster/metadata.go b/pkg/asset/cluster/metadata.go index b720da11538..4054077a2d5 100644 --- a/pkg/asset/cluster/metadata.go +++ b/pkg/asset/cluster/metadata.go @@ -53,6 +53,7 @@ func (m *Metadata) Generate(parents asset.Parents) (err error) { ClusterName: installConfig.Config.ObjectMeta.Name, ClusterID: clusterID.UUID, InfraID: clusterID.InfraID, + BYO: installConfig.Config.BYO, } switch { diff --git a/pkg/asset/targets/targets.go b/pkg/asset/targets/targets.go index f3cf542274d..3fa642732eb 100644 --- a/pkg/asset/targets/targets.go +++ b/pkg/asset/targets/targets.go @@ -2,6 +2,7 @@ package targets import ( "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/byo" "github.com/openshift/installer/pkg/asset/cluster" "github.com/openshift/installer/pkg/asset/ignition/bootstrap" "github.com/openshift/installer/pkg/asset/ignition/machine" @@ -63,6 +64,7 @@ var ( &kubeconfig.AdminClient{}, &tls.JournalCertKey{}, &cluster.Metadata{}, + &byo.Deployment{}, &cluster.Cluster{}, } ) diff --git a/pkg/destroy/bootstrap/bootstrap.go b/pkg/destroy/bootstrap/bootstrap.go index b11cf87d196..0286e58ff4f 100644 --- a/pkg/destroy/bootstrap/bootstrap.go +++ b/pkg/destroy/bootstrap/bootstrap.go @@ -3,6 +3,7 @@ package bootstrap import ( "fmt" + "github.com/openshift/installer/pkg/asset/byo" "io/ioutil" "os" "path/filepath" @@ -46,11 +47,46 @@ func Destroy(dir string) (err error) { } defer os.RemoveAll(tempDir) + if metadata.BYO { + copyNames = append(copyNames, "main.tf", fmt.Sprintf("variables-%s.tf", metadata.Platform())) + + var byoFiles []string + modules, err := filepath.Glob(filepath.Join(dir, "**/*.tf")) + if err != nil { + return err + } + byoFiles = append(byoFiles, modules...) + + plugins, err := filepath.Glob(filepath.Join(dir, byo.PluginsDir, "**/*")) + if err != nil { + return err + } + byoFiles = append(byoFiles, plugins...) + + for _, filename := range byoFiles { + copyNames = append(copyNames, strings.Replace(filename, filepath.ToSlash(dir), "", 1)) + } + } + extraArgs := []string{} for _, filename := range copyNames { sourcePath := filepath.Join(dir, filename) targetPath := filepath.Join(tempDir, filename) - err = copy(sourcePath, targetPath) + + path := filepath.Dir(targetPath) + if _, err := os.Stat(path); os.IsNotExist(err) { + err = os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + } + + perm := 0666 + if strings.HasPrefix(filename, filepath.FromSlash("/plugins/")) { + perm = 0755 + } + + err = copy(sourcePath, targetPath, perm) if err != nil { if os.IsNotExist(err) && err.(*os.PathError).Path == sourcePath && filename == tfPlatformVarsFileName { continue // platform may not need platform-specific Terraform variables @@ -63,31 +99,31 @@ func Destroy(dir string) (err error) { } if platform == libvirt.Name { - _, err = terraform.Apply(tempDir, platform, extraArgs...) + _, err = terraform.Apply(tempDir, platform, metadata.BYO, extraArgs...) if err != nil { return errors.Wrap(err, "Terraform apply") } } extraArgs = append(extraArgs, "-target=module.bootstrap") - err = terraform.Destroy(tempDir, platform, extraArgs...) + err = terraform.Destroy(tempDir, platform, metadata.BYO, extraArgs...) if err != nil { return errors.Wrap(err, "Terraform destroy") } tempStateFilePath := filepath.Join(dir, terraform.StateFileName+".new") - err = copy(filepath.Join(tempDir, terraform.StateFileName), tempStateFilePath) + err = copy(filepath.Join(tempDir, terraform.StateFileName), tempStateFilePath, 0666) if err != nil { return errors.Wrapf(err, "failed to copy %s from the temporary directory", terraform.StateFileName) } return os.Rename(tempStateFilePath, filepath.Join(dir, terraform.StateFileName)) } -func copy(from string, to string) error { +func copy(from string, to string, perm int) error { data, err := ioutil.ReadFile(from) if err != nil { return err } - return ioutil.WriteFile(to, data, 0666) + return ioutil.WriteFile(to, data, os.FileMode(perm)) } diff --git a/pkg/terraform/terraform.go b/pkg/terraform/terraform.go index 70ea3e8871f..3a60dcc9a44 100644 --- a/pkg/terraform/terraform.go +++ b/pkg/terraform/terraform.go @@ -27,8 +27,8 @@ const ( // given directory and then runs 'terraform init' and 'terraform // apply'. It returns the absolute path of the tfstate file, rooted // in the specified directory, along with any errors from Terraform. -func Apply(dir string, platform string, extraArgs ...string) (path string, err error) { - err = unpackAndInit(dir, platform) +func Apply(dir string, platform string, byo bool, extraArgs ...string) (path string, err error) { + err = unpackAndInit(dir, platform, byo) if err != nil { return "", err } @@ -59,8 +59,8 @@ func Apply(dir string, platform string, extraArgs ...string) (path string, err e // Destroy unpacks the platform-specific Terraform modules into the // given directory and then runs 'terraform init' and 'terraform // destroy'. -func Destroy(dir string, platform string, extraArgs ...string) (err error) { - err = unpackAndInit(dir, platform) +func Destroy(dir string, platform string, byo bool, extraArgs ...string) (err error) { + err = unpackAndInit(dir, platform, byo) if err != nil { return err } @@ -89,10 +89,13 @@ func Destroy(dir string, platform string, extraArgs ...string) (err error) { // unpack unpacks the platform-specific Terraform modules into the // given directory. -func unpack(dir string, platform string) (err error) { - err = data.Unpack(dir, platform) - if err != nil { - return err +func unpack(dir string, platform string, byo bool) (err error) { + + if !byo { + err = data.Unpack(dir, platform,) + if err != nil { + return err + } } err = data.Unpack(filepath.Join(dir, "config.tf"), "config.tf") @@ -105,8 +108,8 @@ func unpack(dir string, platform string) (err error) { // unpackAndInit unpacks the platform-specific Terraform modules into // the given directory and then runs 'terraform init'. -func unpackAndInit(dir string, platform string) (err error) { - err = unpack(dir, platform) +func unpackAndInit(dir string, platform string, byo bool) (err error) { + err = unpack(dir, platform, byo) if err != nil { return errors.Wrap(err, "failed to unpack Terraform modules") } diff --git a/pkg/types/clustermetadata.go b/pkg/types/clustermetadata.go index 4e2a9aae884..9fdeb5e434c 100644 --- a/pkg/types/clustermetadata.go +++ b/pkg/types/clustermetadata.go @@ -16,6 +16,8 @@ type ClusterMetadata struct { // infraID is an ID that is used to identify cloud resources created by the installer. InfraID string `json:"infraID"` ClusterPlatformMetadata `json:",inline"` + // Bring your own terraform platform deployment + BYO bool `json:"byo,omitempty"` } // ClusterPlatformMetadata contains metadata for platfrom. diff --git a/pkg/types/installconfig.go b/pkg/types/installconfig.go index 86c332f98d3..227f0990e44 100644 --- a/pkg/types/installconfig.go +++ b/pkg/types/installconfig.go @@ -62,6 +62,9 @@ type InstallConfig struct { // perform the installation. Platform `json:"platform"` + // Bring your own terraform platform deployment + BYO bool `json:"byo,omitempty"` + // PullSecret is the secret to use when pulling images. PullSecret string `json:"pullSecret"` }