diff --git a/pkg/infra/cluster.go b/pkg/infra/assets/cluster/cluster.go similarity index 47% rename from pkg/infra/cluster.go rename to pkg/infra/assets/cluster/cluster.go index 09b6274907be6a4c9b97536fab2d25c0dbf89eab..c22963e1a130ff73b3a1c79c97a18bd318de9798 100644 --- a/pkg/infra/cluster.go +++ b/pkg/infra/assets/cluster/cluster.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package infra +package cluster import ( "os" @@ -22,6 +22,7 @@ import ( "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/assets" "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform" + platformStages "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform/stages/platform" "github.com/hashicorp/terraform-exec/tfexec" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -31,6 +32,61 @@ type Cluster struct { FileList []*assets.File } +func (c *Cluster) Create(platform string, node string, installDir string) (err error) { + if installDir == "" { + logrus.Fatal("InstallDir has not been set") + } + + terraformVariables := &TerraformVariables{} + stages, err := platformStages.StagesForPlatform(platform, node) + + terraformBinary := filepath.Join(installDir, "terraform") + _, err = os.Stat(terraformBinary) + if os.IsNotExist(err) { + if err := os.Mkdir(terraformBinary, 0777); err != nil { + return errors.Wrap(err, "could not create the terraform directory") + } + } + + // TODO 将所需二进制文件保存到terraformBinary目录 + + terraformBinaryPath, err := filepath.Abs(terraformBinary) + if err != nil { + return errors.Wrap(err, "cannot get absolute path of terraform directory") + } + + tfvarsFiles := make([]*assets.File, 0, len(terraformVariables.Files())+len(stages)) + tfvarsFiles = append(tfvarsFiles, terraformVariables.Files()...) + + for _, stage := range stages { + outputs, err := c.applyStage(platform, stage, terraformBinaryPath, tfvarsFiles) + if err != nil { + return errors.Wrapf(err, "failure applying terraform for %q stage", stage.Name()) + } + tfvarsFiles = append(tfvarsFiles, outputs) + c.FileList = append(c.FileList, outputs) + } + + return nil +} + +func (c *Cluster) applyStage(platform string, stage terraform.Stage, terraformBinary string, tfvarsFiles []*assets.File) (*assets.File, error) { + tmpDir := filepath.Join(terraformBinary, platform, stage.Name()) + if err := os.MkdirAll(tmpDir, 0777); err != nil { + return nil, errors.Wrapf(err, "cannot create the directory for %s", stage.Name()) + } + + var applyOpts []tfexec.ApplyOption + for _, file := range tfvarsFiles { + if err := os.WriteFile(filepath.Join(tmpDir, file.Filename), file.Data, 0o600); err != nil { + return nil, err + } + applyOpts = append(applyOpts, tfexec.VarFile(filepath.Join(tmpDir, file.Filename))) + } + + return c.applyTerraform(tmpDir, platform, stage, terraformBinary, applyOpts...) +} + func (c *Cluster) applyTerraform(tmpDir string, platform string, stage terraform.Stage, terraformBinary string, applyOpts ...tfexec.ApplyOption) (*assets.File, error) { applyErr := terraform.TFApply(tmpDir, platform, stage, terraformBinary, applyOpts...) diff --git a/pkg/infra/assets/cluster/tfvars.go b/pkg/infra/assets/cluster/tfvars.go new file mode 100644 index 0000000000000000000000000000000000000000..6d5729f14b2fe274239311daf851c839690b4e58 --- /dev/null +++ b/pkg/infra/assets/cluster/tfvars.go @@ -0,0 +1,27 @@ +/* +Copyright 2023 KylinSoft Co., Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cluster + +import "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/assets" + +type TerraformVariables struct { + FileList []*assets.File +} + +func (t *TerraformVariables) Files() []*assets.File { + return t.FileList +} diff --git a/pkg/infra/terraform/stages/openstack/stages.go b/pkg/infra/terraform/stages/openstack/stages.go new file mode 100644 index 0000000000000000000000000000000000000000..93ad003b2e8aec72c61c5efdc14d016827db6c7e --- /dev/null +++ b/pkg/infra/terraform/stages/openstack/stages.go @@ -0,0 +1,19 @@ +package openstack + +import ( + "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform" + "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform/providers" + "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform/stages" +) + +var PlatformStages = []terraform.Stage{} + +func AddPlatformStage(stage string) { + newStage := stages.NewStage( + "openstack", + stage, + []providers.Provider{providers.OpenStack}, + ) + + PlatformStages = append(PlatformStages, newStage) +} diff --git a/pkg/infra/terraform/stages/platform/stages.go b/pkg/infra/terraform/stages/platform/stages.go new file mode 100644 index 0000000000000000000000000000000000000000..7a99cad051b99d1645a50c8fd0a89232b5fe5421 --- /dev/null +++ b/pkg/infra/terraform/stages/platform/stages.go @@ -0,0 +1,19 @@ +package platform + +import ( + "errors" + "fmt" + + "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform" + "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform/stages/openstack" +) + +func StagesForPlatform(platform string, stage string) ([]terraform.Stage, error) { + switch platform { + case "openstack": + openstack.AddPlatformStage(stage) + return openstack.PlatformStages, nil + default: + return nil, errors.New(fmt.Sprintf("unsupported platform %q", platform)) + } +} diff --git a/pkg/infra/terraform/stages/split.go b/pkg/infra/terraform/stages/split.go new file mode 100644 index 0000000000000000000000000000000000000000..caf0de7e1889f51cdc6f176149899e5f6e6e47f1 --- /dev/null +++ b/pkg/infra/terraform/stages/split.go @@ -0,0 +1,43 @@ +package stages + +import ( + "fmt" + + "gitee.com/openeuler/nestos-kubernetes-deployer/pkg/infra/terraform/providers" +) + +type StageOption func(*SplitStage) + +func NewStage(platform, name string, providers []providers.Provider, opts ...StageOption) SplitStage { + s := SplitStage{ + platform: platform, + name: name, + providers: providers, + } + for _, opt := range opts { + opt(&s) + } + return s +} + +type SplitStage struct { + platform string + name string + providers []providers.Provider +} + +func (s SplitStage) Name() string { + return s.name +} + +func (s SplitStage) Providers() []providers.Provider { + return s.providers +} + +func (s SplitStage) StateFilename() string { + return fmt.Sprintf("terraform.%s.tfstate", s.name) +} + +func (s SplitStage) OutputsFilename() string { + return fmt.Sprintf("%s.tfvars.json", s.name) +} diff --git a/pkg/infra/terraform/terraform.go b/pkg/infra/terraform/terraform.go index e961f8d351fc436fed86f6f220ee7eed330c356d..ba540da1334bf40a00082b30aa5b6a718d3d656f 100644 --- a/pkg/infra/terraform/terraform.go +++ b/pkg/infra/terraform/terraform.go @@ -35,13 +35,13 @@ func newTFExec(workingDir string, terraformBinary string) (*tfexec.Terraform, er } // If the log path is not set, terraform will not receive debug logs. - if path, ok := os.LookupEnv("TEREFORM_LOG_PATH"); ok { + if logPath, ok := os.LookupEnv("TEREFORM_LOG_PATH"); ok { if err := tf.SetLog(os.Getenv("TEREFORM_LOG")); err != nil { logrus.Infof("Skipping setting terraform log levels: %v", err) } else { tf.SetLogCore(os.Getenv("TEREFORM_LOG_CORE")) //nolint:errcheck tf.SetLogProvider(os.Getenv("TEREFORM_LOG_PROVIDER")) //nolint:errcheck - tf.SetLogPath(path) //nolint:errcheck + tf.SetLogPath(logPath) //nolint:errcheck } }