Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var Cmd = &cobra.Command{ Use: "setup [additional-terraform-args...]", Short: "Initialize Terraform with GitLab backend using config file", Run: func(c *cobra.Command, args []string) { configDir := filepath.Join(".sikalabs", "terraform") yamlPath := filepath.Join(configDir, "terraform.yaml") jsonPath := filepath.Join(configDir, "terraform.json") var configPath string var data []byte var err error var config TerraformConfig if _, err = os.Stat(yamlPath); err == nil { configPath = yamlPath data, err = os.ReadFile(configPath) error_utils.HandleError(err, "Failed to read config file") err = yaml.Unmarshal(data, &config) error_utils.HandleError(err, "Failed to parse YAML config file") } else if _, err = os.Stat(jsonPath); err == nil { configPath = jsonPath data, err = os.ReadFile(configPath) error_utils.HandleError(err, "Failed to read config file") err = json.Unmarshal(data, &config) error_utils.HandleError(err, "Failed to parse JSON config file") } else { error_utils.HandleError(fmt.Errorf("config file not found"), "Neither terraform.yaml nor terraform.json found in .sikalabs/terraform/") } username := FlagUsername token := FlagToken if username == "" && token == "" { parsedURL, err := url.Parse(config.GitlabURL) if err == nil && parsedURL.Host != "" { gitlabDomain := parsedURL.Host itemName := fmt.Sprintf("GITLAB_TOKEN_TF_STATE_%s", gitlabDomain) fmt.Printf("Checking 1Password for token: %s\n", itemName) opToken, err := exec_utils.ExecStr("op", "item", "get", itemName, "--vault", "employee", "--fields", "password", "--reveal") if err == nil && opToken != "" { token = strings.TrimSpace(opToken) username = "token" fmt.Println("Using token from 1Password") } else { fmt.Println("Token not found in 1Password, will prompt for credentials") } } } if !FlagSkipFiles && len(config.FilesInVault) > 0 { if config.VaultAddr == "" { error_utils.HandleError(fmt.Errorf("vault address is required"), "VaultAddr must be configured in terraform config when FilesInVault is used") } fmt.Println("Logging in to Vault...") if !FlagDryRun { err = exec_utils.ExecOut("vault", "login", "-address", config.VaultAddr, "-method=oidc") error_utils.HandleError(err, "Failed to login to Vault") } fmt.Println("Downloading files from Vault...") for localPath, vaultPath := range config.FilesInVault { fmt.Printf(" Downloading %s from %s\n", localPath, vaultPath) if !FlagDryRun { err = exec_utils.ExecOut( "slu", "vault", "copy-file-from-vault", "--vault-address", config.VaultAddr, "--secret-path", vaultPath, "--file-path", localPath, ) error_utils.HandleError(err, fmt.Sprintf("Failed to download file %s from vault", localPath)) } } } if !FlagSkipFiles && len(config.FilesWithCustomTooling) > 0 { fmt.Println("Executing custom tooling commands...") for fileName, tooling := range config.FilesWithCustomTooling { fmt.Printf(" Executing command for %s\n", fileName) if tooling.Get == "" { error_utils.HandleError(fmt.Errorf("get command is empty"), fmt.Sprintf("Get command is required for file %s", fileName)) } if !FlagDryRun { err = exec_utils.ExecShOut(tooling.Get) error_utils.HandleError(err, fmt.Sprintf("Failed to execute custom tooling command for file %s", fileName)) } else { fmt.Printf(" Command: %s\n", tooling.Get) } } } fi, err := os.Stdin.Stat() isPipe := err == nil && fi.Mode()&os.ModeNamedPipe != 0 if isPipe { scanner := bufio.NewScanner(os.Stdin) if username == "" && scanner.Scan() { username = strings.TrimSpace(scanner.Text()) } if token == "" && scanner.Scan() { token = strings.TrimSpace(scanner.Text()) } if err := scanner.Err(); err != nil { error_utils.HandleError(err, "Failed to read from stdin") } } else { if username == "" { fmt.Print("GitLab Username: ") scanner := bufio.NewScanner(os.Stdin) if scanner.Scan() { username = strings.TrimSpace(scanner.Text()) } if err := scanner.Err(); err != nil { error_utils.HandleError(err, "Failed to read username") } } if token == "" { fmt.Print("GitLab Token: ") scanner := bufio.NewScanner(os.Stdin) if scanner.Scan() { token = strings.TrimSpace(scanner.Text()) } if err := scanner.Err(); err != nil { error_utils.HandleError(err, "Failed to read token") } } } if username == "" { error_utils.HandleError(fmt.Errorf("username is required"), "Username must be provided via --username flag or stdin") } if token == "" { error_utils.HandleError(fmt.Errorf("token is required"), "Token must be provided via --token flag or stdin") } backendAddress := fmt.Sprintf("address=%s/api/v4/projects/%s/terraform/state/%s", config.GitlabURL, config.ProjectID, config.StateName) lockAddress := fmt.Sprintf("lock_address=%s/api/v4/projects/%s/terraform/state/%s/lock", config.GitlabURL, config.ProjectID, config.StateName) unlockAddress := fmt.Sprintf("unlock_address=%s/api/v4/projects/%s/terraform/state/%s/lock", config.GitlabURL, config.ProjectID, config.StateName) usernameConfig := fmt.Sprintf("username=%s", username) password := fmt.Sprintf("password=%s", token) cmdArgs := []string{ "init", fmt.Sprintf("-backend-config=%s", backendAddress), fmt.Sprintf("-backend-config=%s", lockAddress), fmt.Sprintf("-backend-config=%s", unlockAddress), fmt.Sprintf("-backend-config=%s", usernameConfig), fmt.Sprintf("-backend-config=%s", password), "-backend-config=lock_method=POST", "-backend-config=unlock_method=DELETE", "-backend-config=retry_wait_min=5", } cmdArgs = append(cmdArgs, args...) if FlagDryRun { fmt.Printf("terraform %s\n", strings.Join(cmdArgs, " ")) os.Exit(0) } err = exec_utils.ExecInOut("terraform", cmdArgs...) error_utils.HandleError(err, "Failed to execute terraform init") }, }
View Source
var FlagDryRun bool
View Source
var FlagSkipFiles bool
View Source
var FlagToken string
View Source
var FlagUsername string
Functions ¶
This section is empty.
Types ¶
type CustomToolingConfig ¶ added in v0.94.0
type CustomToolingConfig struct {
Get string `json:"Get" yaml:"Get"`
}
type TerraformConfig ¶
type TerraformConfig struct {
Meta struct {
SchemaVersion string `json:"SchemaVersion" yaml:"SchemaVersion"`
} `json:"Meta" yaml:"Meta"`
GitlabURL string `json:"GitlabURL" yaml:"GitlabURL"`
ProjectID string `json:"ProjectID" yaml:"ProjectID"`
StateName string `json:"StateName" yaml:"StateName"`
VaultAddr string `json:"VaultAddr,omitempty" yaml:"VaultAddr,omitempty"`
FilesInVault map[string]string `json:"FilesInVault,omitempty" yaml:"FilesInVault,omitempty"`
FilesWithCustomTooling map[string]CustomToolingConfig `json:"FilesWithCustomTooling,omitempty" yaml:"FilesWithCustomTooling,omitempty"`
}
Click to show internal directories.
Click to hide internal directories.