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
18 changes: 18 additions & 0 deletions cmd/scw/testdata/test-all-usage-config-import-usage.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
🟥🟥🟥 STDERR️️ 🟥🟥🟥️
Import configurations from another file

USAGE:
scw config import <file ...> [arg=value ...]

ARGS:
file Path to the configuration file to import

FLAGS:
-h, --help help for import

GLOBAL FLAGS:
-c, --config string The path to the config file
-D, --debug Enable debug mode
-o, --output string Output format: json or human, see 'scw help output' for more info (default "human")
-p, --profile string The config profile to use
22 changes: 22 additions & 0 deletions docs/commands/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Read more about the config management engine at https://github.com/scaleway/scal
- [Destroy the config file](#destroy-the-config-file)
- [Dump the config file](#dump-the-config-file)
- [Get a value from the config file](#get-a-value-from-the-config-file)
- [Import configurations from another file](#import-configurations-from-another-file)
- [Get config values from the config file for the current profile](#get-config-values-from-the-config-file-for-the-current-profile)
- [Allows the deletion of a profile from the config file](#allows-the-deletion-of-a-profile-from-the-config-file)
- [Mark a profile as active in the config file](#mark-a-profile-as-active-in-the-config-file)
Expand Down Expand Up @@ -102,6 +103,27 @@ scw -p prod config get default_region



## Import configurations from another file





**Usage:**

```
scw config import <file ...> [arg=value ...]
```


**Args:**

| Name | | Description |
|------|---|-------------|
| file | Required | Path to the configuration file to import |



## Get config values from the config file for the current profile


Expand Down
67 changes: 67 additions & 0 deletions internal/namespaces/config/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func GetCommands() *core.Commands {
configResetCommand(),
configDestroyCommand(),
configInfoCommand(),
configImportCommand(),
)
}

Expand Down Expand Up @@ -628,6 +629,72 @@ func configInfoCommand() *core.Command {
}
}

// configImportCommand imports an external config
func configImportCommand() *core.Command {
type configImportArgs struct {
File string
}

return &core.Command{
Groups: []string{"config"},
Short: "Import configurations from another file",
Namespace: "config",
Resource: "import",
AllowAnonymousClient: true,
ArgsType: reflect.TypeOf(configImportArgs{}),
ArgSpecs: core.ArgSpecs{
{
Name: "file",
Short: "Path to the configuration file to import",
Required: true,
Positional: true,
},
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
args := argsI.(*configImportArgs)
configPath := core.ExtractConfigPath(ctx)

currentConfig, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
}
currentProfileName := core.ExtractProfileName(ctx)
currentProfile, err := currentConfig.GetProfile(currentProfileName)
if err != nil {
return nil, err
}

// Read the content of the file to import
importedConfig, err := scw.LoadConfigFromPath(args.File)
if err != nil {
return nil, err
}
importedProfile := importedConfig.Profile

// Merge the imported configurations into the existing configuration
currentConfig.Profile = *scw.MergeProfiles(currentProfile, &importedProfile)

for profileName, profile := range importedConfig.Profiles {
existingProfile, exists := currentConfig.Profiles[profileName]
if exists {
currentConfig.Profiles[profileName] = scw.MergeProfiles(existingProfile, profile)
} else {
currentConfig.Profiles[profileName] = profile
}
}

err = currentConfig.SaveTo(configPath)
if err != nil {
return nil, fmt.Errorf("failed to save updated configuration: %v", err)
}

return &core.SuccessResult{
Message: "successfully import config",
}, nil
},
}
}

// Helper functions
func getProfileValue(profile *scw.Profile, fieldName string) (interface{}, error) {
field, err := getProfileField(profile, fieldName)
Expand Down
80 changes: 80 additions & 0 deletions internal/namespaces/config/commands_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package config

import (
"fmt"
"io/ioutil"
"os"
"path"
"regexp"
Expand Down Expand Up @@ -303,6 +305,38 @@ func Test_ConfigInfoCommand(t *testing.T) {
}))
}

func Test_ConfigImportCommand(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
tmpFile, err := createTempConfigFile()
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpFile.Name())

core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: beforeFuncCreateFullConfig(),
Cmd: fmt.Sprintf("scw config import %s", tmpFile.Name()),
Check: core.TestCheckCombine(
core.TestCheckExitCode(0),
core.TestCheckGolden(),
checkConfig(func(t *testing.T, config *scw.Config) {
// config
assert.Equal(t, "22222222-2222-2222-2222-222222222222", *config.SecretKey)
assert.Equal(t, "nl-ams", *config.DefaultRegion)
// modified p1
assert.Equal(t, "99999999-9999-9999-9999-999999999999", *config.Profiles["p1"].SecretKey)
assert.Equal(t, "nl-ams", *config.Profiles["p1"].DefaultRegion)
// new p3
assert.Equal(t, "33333333-3333-3333-3333-333333333333", *config.Profiles["p3"].SecretKey)
assert.Equal(t, "fr-par", *config.Profiles["p3"].DefaultRegion)
}),
),
TmpHomeDir: true,
})(t)
})
}

func checkConfig(f func(t *testing.T, config *scw.Config)) core.TestCheck {
return func(t *testing.T, ctx *core.CheckFuncCtx) {
homeDir := ctx.OverrideEnv["HOME"]
Expand Down Expand Up @@ -361,3 +395,49 @@ func beforeFuncCreateFullConfig() core.BeforeFunc {
},
})
}

func createTempConfigFile() (*os.File, error) {
tmpFile, err := ioutil.TempFile("", "tmp.yaml")
if err != nil {
return nil, err
}

configContent := `
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 22222222-2222-2222-2222-222222222222
api_url: https://mock-api-url.com
insecure: true
default_organization_id: 22222222-2222-2222-2222-222222222222
default_region: nl-ams
default_zone: nl-ams-1
send_telemetry: true
profiles:
p1:
access_key: SCWP1XXXXXXXXXXXXXXX
secret_key: 99999999-9999-9999-9999-999999999999
api_url: https://p1-mock-api-url.com
insecure: true
default_organization_id: 99999999-9999-9999-9999-999999999999
default_region: nl-ams
default_zone: nl-ams-1
send_telemetry: true
p3:
access_key: SCWP3XXXXXXXXXXXXXXX
secret_key: 33333333-3333-3333-3333-333333333333
api_url: https://p3-mock-api-url.com
insecure: true
default_organization_id: 33333333-3333-3333-3333-333333333333
default_region: fr-par
default_zone: fr-par-1
send_telemetry: true
`

if _, err := tmpFile.Write([]byte(configContent)); err != nil {
return nil, err
}
if err := tmpFile.Close(); err != nil {
return nil, err
}

return tmpFile, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
🟩🟩🟩 STDOUT️ 🟩🟩🟩️
✅ Successfully import config.
🟩🟩🟩 JSON STDOUT 🟩🟩🟩
{
"message": "successfully import config",
"details": ""
}