Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/cmd/ami.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func runAMIBuild(cmd *cobra.Command, args []string) error {
region: getFlagString(cmd, "region", cfg.Region, ""),
instanceType: getFlagStringOpt(cmd, "instance-type"),
profile: getFlagStringOpt(cmd, "profile"),
instanceProfile: getFlagStringOpt(cmd, "instance-profile"),
instanceProfile: getFlagString(cmd, "instance-profile", cfg.InstanceProfile, ""),
reuseResources: getFlagBool(cmd, "reuse-resources"),
}

Expand Down
67 changes: 67 additions & 0 deletions cli/cmd/ami_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cmd

import (
"testing"

"github.com/spf13/cobra"
)

func TestGetFlagString(t *testing.T) {
newCmd := func(flagVal string) *cobra.Command {
cmd := &cobra.Command{Use: "test"}
cmd.Flags().String("instance-profile", "", "")
if flagVal != "" {
if err := cmd.Flags().Set("instance-profile", flagVal); err != nil {
t.Fatalf("set flag: %v", err)
}
}
return cmd
}

tests := []struct {
name string
flagVal string
fallback1 string
fallback2 string
want string
}{
{
name: "flag wins over config fallback",
flagVal: "FlagProfile",
fallback1: "ConfigProfile",
fallback2: "default",
want: "FlagProfile",
},
{
name: "config fallback used when flag empty",
flagVal: "",
fallback1: "ConfigProfile",
fallback2: "default",
want: "ConfigProfile",
},
{
name: "second fallback when both flag and config empty",
flagVal: "",
fallback1: "",
fallback2: "default",
want: "default",
},
{
name: "empty when all sources empty",
flagVal: "",
fallback1: "",
fallback2: "",
want: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := newCmd(tt.flagVal)
got := getFlagString(cmd, "instance-profile", tt.fallback1, tt.fallback2)
if got != tt.want {
t.Errorf("getFlagString() = %q, want %q", got, tt.want)
}
})
}
}
31 changes: 16 additions & 15 deletions cli/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,22 @@ func (l LudusConfig) SSHTarget() string {

// Config holds all CLI configuration.
type Config struct {
Env string `mapstructure:"env"`
Provider string `mapstructure:"provider"`
Region string `mapstructure:"region"`
Debug bool `mapstructure:"debug"`
MaxRetries int `mapstructure:"max_retries"`
RetryDelay int `mapstructure:"retry_delay"`
IdleTimeout int `mapstructure:"idle_timeout"`
LogDir string `mapstructure:"log_dir"`
Playbooks []string `mapstructure:"playbooks"`
ProjectRoot string `mapstructure:"project_root"`
Environments map[string]EnvironmentConfig `mapstructure:"environments"`
Extensions map[string]ExtensionConfig `mapstructure:"extensions"`
Infra InfraConfig `mapstructure:"infra"`
Proxmox ProxmoxConfig `mapstructure:"proxmox"`
Ludus LudusConfig `mapstructure:"ludus"`
Env string `mapstructure:"env"`
Provider string `mapstructure:"provider"`
Region string `mapstructure:"region"`
InstanceProfile string `mapstructure:"instance_profile"`
Debug bool `mapstructure:"debug"`
MaxRetries int `mapstructure:"max_retries"`
RetryDelay int `mapstructure:"retry_delay"`
IdleTimeout int `mapstructure:"idle_timeout"`
LogDir string `mapstructure:"log_dir"`
Playbooks []string `mapstructure:"playbooks"`
ProjectRoot string `mapstructure:"project_root"`
Environments map[string]EnvironmentConfig `mapstructure:"environments"`
Extensions map[string]ExtensionConfig `mapstructure:"extensions"`
Infra InfraConfig `mapstructure:"infra"`
Proxmox ProxmoxConfig `mapstructure:"proxmox"`
Ludus LudusConfig `mapstructure:"ludus"`
}

var (
Expand Down
31 changes: 31 additions & 0 deletions cli/internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"

Expand Down Expand Up @@ -185,6 +186,36 @@ func TestLabConfigPath(t *testing.T) {
})
}

func TestConfigInstanceProfile(t *testing.T) {
t.Run("field accessible on struct", func(t *testing.T) {
c := &Config{InstanceProfile: "WarpgateImageBuilderInstanceProfile"}
if c.InstanceProfile != "WarpgateImageBuilderInstanceProfile" {
t.Errorf("InstanceProfile = %q, want %q", c.InstanceProfile, "WarpgateImageBuilderInstanceProfile")
}
})

t.Run("zero value is empty string", func(t *testing.T) {
c := &Config{}
if c.InstanceProfile != "" {
t.Errorf("InstanceProfile = %q, want empty", c.InstanceProfile)
}
})

t.Run("mapstructure tag is instance_profile", func(t *testing.T) {
// Verify the struct tag so viper unmarshals the YAML key correctly.
var c Config
typ := reflect.TypeOf(c)
f, ok := typ.FieldByName("InstanceProfile")
if !ok {
t.Fatal("Config struct missing InstanceProfile field")
}
tag := f.Tag.Get("mapstructure")
if tag != "instance_profile" {
t.Errorf("mapstructure tag = %q, want %q", tag, "instance_profile")
}
})
}

func TestConfigInventoryPathDifferentEnvs(t *testing.T) {
tests := []struct {
env string
Expand Down
1 change: 1 addition & 0 deletions cli/internal/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var RebootPlaybooks = []string{
func setDefaults() {
viper.SetDefault("env", "staging")
viper.SetDefault("region", "")
viper.SetDefault("instance_profile", "")
viper.SetDefault("debug", false)
viper.SetDefault("max_retries", 3)
viper.SetDefault("retry_delay", 30)
Expand Down
1 change: 1 addition & 0 deletions dreadgoad.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
env: staging
provider: aws # Provider: aws, proxmox, ludus
# region: us-west-2 # Override AWS region (default: from inventory)
instance_profile: WarpgateImageBuilderInstanceProfile # IAM instance profile for EC2 Image Builder
debug: false
max_retries: 3
retry_delay: 30
Expand Down
Loading