Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config): add profile activate command #1206

Merged
merged 8 commits into from
Jul 13, 2020
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
🟥🟥🟥 STDERR️️ 🟥🟥🟥️
Mark a profile as active in the config file

USAGE:
scw config profile activate <profile-name ...> [arg=value ...]

ARGS:
profile-name

FLAGS:
-h, --help help for activate

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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ USAGE:
scw config profile <command>

AVAILABLE COMMANDS:
activate Mark a profile as active in the config file
delete Delete a profile from the config file

FLAGS:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/mattn/go-colorable v0.1.4
github.com/mattn/go-isatty v0.0.11
github.com/pkg/errors v0.9.1 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200707130522-abc4aeb2a4e6
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200710161155-10382899255f
github.com/sergi/go-diff v1.0.0 // indirect
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200624111939-0a4e128e532e
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200624111939-0a4e128e532e/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200707130522-abc4aeb2a4e6 h1:mCYMQVdy3ciDx7jtDnRuxTk9IUB525PhZYkCTjMWQUI=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200707130522-abc4aeb2a4e6/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200710161155-10382899255f h1:FHSh2peVlKEecLqHX/8uevrWqeua68LbVBOzIhC0HBw=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200710161155-10382899255f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
Expand Down
30 changes: 30 additions & 0 deletions internal/core/autocomplete_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package core

import (
"context"
"strings"

"github.com/scaleway/scaleway-sdk-go/scw"
)

func AutocompleteProfileName() AutoCompleteArgFunc {
return func(ctx context.Context, prefix string) AutocompleteSuggestions {
res := AutocompleteSuggestions(nil)
configPath := ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return res
}

for profileName := range config.Profiles {
if strings.HasPrefix(profileName, prefix) {
res = append(res, profileName)
}
}

if strings.HasPrefix(scw.DefaultProfileName, prefix) {
res = append(res, scw.DefaultProfileName)
}
return res
}
}
15 changes: 3 additions & 12 deletions internal/core/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,9 @@ func createClient(httpClient *http.Client, buildInfo *BuildInfo, profileName str
return nil, err
}

var activeProfile *scw.Profile

if profileName != "" {
activeProfile, err = config.GetProfile(profileName)
if err != nil {
return nil, err
}
} else {
activeProfile, err = config.GetActiveProfile()
if err != nil {
return nil, err
}
activeProfile, err := config.GetProfile(profileName)
if err != nil {
return nil, err
}

envProfile := scw.LoadEnvProfile()
Expand Down
19 changes: 17 additions & 2 deletions internal/core/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,25 @@ func ExtractStdin(ctx context.Context) io.Reader {
}

func ExtractProfileName(ctx context.Context) string {
// Handle profile flag -p
if extractMeta(ctx).ProfileFlag != "" {
return extractMeta(ctx).ProfileFlag
}
return ExtractEnv(ctx, scw.ScwActiveProfileEnv)

// Handle SCW_PROFILE env variable
if env := ExtractEnv(ctx, scw.ScwActiveProfileEnv); env != "" {
return env
}

// Handle active_profile in config file
configPath := ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err == nil && config.ActiveProfile != nil {
return *config.ActiveProfile
}

// Return default profile name
return scw.DefaultProfileName
}

func ExtractHTTPClient(ctx context.Context) *http.Client {
Expand All @@ -139,7 +154,7 @@ func ReloadClient(ctx context.Context) error {
if meta.isClientFromBootstrapConfig {
return nil
}
meta.Client, err = createClient(meta.httpClient, meta.BuildInfo, "")
meta.Client, err = createClient(meta.httpClient, meta.BuildInfo, ExtractProfileName(ctx))
return err
}

Expand Down
75 changes: 61 additions & 14 deletions internal/namespaces/config/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
"fmt"
"path"
"reflect"

"github.com/scaleway/scaleway-sdk-go/validation"
Expand All @@ -27,6 +26,7 @@ func GetCommands() *core.Commands {
configDumpCommand(),
configProfileCommand(),
configDeleteProfileCommand(),
configActivateProfileCommand(),
configResetCommand(),
)
}
Expand Down Expand Up @@ -128,7 +128,7 @@ func configGetCommand() *core.Command {
},
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
config, err := scw.LoadConfigFromPath(extractConfigPath(ctx))
config, err := scw.LoadConfigFromPath(core.ExtractConfigPath(ctx))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -254,7 +254,7 @@ The only allowed attributes are access_key, secret_key, default_organization_id,
args := argsI.(*scw.Profile)

// Execute
configPath := extractConfigPath(ctx)
configPath := core.ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
Expand All @@ -263,7 +263,7 @@ The only allowed attributes are access_key, secret_key, default_organization_id,
// send_telemetry is the only key that is not in a profile but in the config object directly
profileName := core.ExtractProfileName(ctx)
profile := &config.Profile
if profileName != "" {
if profileName != scw.DefaultProfileName {
var exist bool
profile, exist = config.Profiles[profileName]
if !exist {
Expand Down Expand Up @@ -319,7 +319,7 @@ func configUnsetCommand() *core.Command {
},
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
configPath := extractConfigPath(ctx)
configPath := core.ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
Expand Down Expand Up @@ -365,7 +365,7 @@ func configDumpCommand() *core.Command {
},
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
configPath := extractConfigPath(ctx)
configPath := core.ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
Expand Down Expand Up @@ -406,7 +406,7 @@ func configDeleteProfileCommand() *core.Command {
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
profileName := argsI.(*configDeleteProfileArgs).Name
configPath := extractConfigPath(ctx)
configPath := core.ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
Expand All @@ -428,6 +428,56 @@ func configDeleteProfileCommand() *core.Command {
}
}

// configActivateProfileCommand mark a profile as active
func configActivateProfileCommand() *core.Command {
type configActiveProfileArgs struct {
ProfileName string
}

return &core.Command{
Short: `Mark a profile as active in the config file`,
Namespace: "config",
Resource: "profile",
Verb: "activate",
AllowAnonymousClient: true,
ArgsType: reflect.TypeOf(configActiveProfileArgs{}),
ArgSpecs: core.ArgSpecs{
{
Name: "profile-name",
Required: true,
Positional: true,
AutoCompleteFunc: core.AutocompleteProfileName(),
},
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
profileName := argsI.(*configActiveProfileArgs).ProfileName
configPath := core.ExtractConfigPath(ctx)
config, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
}

if profileName == scw.DefaultProfileName {
config.ActiveProfile = nil
} else {
if _, exists := config.Profiles[profileName]; !exists {
return nil, unknownProfileError(profileName)
}
config.ActiveProfile = &profileName
}

err = config.SaveTo(configPath)
if err != nil {
return nil, err
}

return &core.SuccessResult{
Message: fmt.Sprintf("successfully activate profile %s", profileName),
}, nil
},
}
}

// configResetCommand resets the config
func configResetCommand() *core.Command {
type configResetArgs struct{}
Expand Down Expand Up @@ -498,14 +548,11 @@ func getProfileKeys() []string {
return keys
}

// This func should be removes when core implement it
func extractConfigPath(ctx context.Context) string {
homeDir := core.ExtractUserHomeDir(ctx)
return path.Join(homeDir, ".config", "scw", "config.yaml")
}

// getProfile return a config profile by its name.
// Warning: This return the profile pointer directly so it can be modified by commands.
// For this reason we cannot rely on config.GetProfileByName method as it create a copy.
func getProfile(config *scw.Config, profileName string) (*scw.Profile, error) {
if profileName == "" {
if profileName == scw.DefaultProfileName {
return &config.Profile, nil
}
profile, exist := config.Profiles[profileName]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,31 @@ profiles:

🟩🟩🟩 JSON STDOUT 🟩🟩🟩
{
"AccessKey": "SCWXXXXXXXXXXXXXXXXX",
"SecretKey": "11111111-1111-1111-1111-111111111111",
"APIURL": null,
"Insecure": true,
"DefaultOrganizationID": "11111111-1111-1111-1111-111111111111",
"DefaultProjectID": null,
"DefaultRegion": "fr-par",
"DefaultZone": "fr-par-1",
"SendTelemetry": true,
"ActiveProfile": null,
"Profiles": {
"access_key": "SCWXXXXXXXXXXXXXXXXX",
"secret_key": "11111111-1111-1111-1111-111111111111",
"insecure": true,
"default_organization_id": "11111111-1111-1111-1111-111111111111",
"default_region": "fr-par",
"default_zone": "fr-par-1",
"send_telemetry": true,
"profiles": {
"p1": {
"AccessKey": "SCWP1XXXXXXXXXXXXXXX",
"SecretKey": "11111111-1111-1111-1111-111111111111",
"APIURL": "https://p1-mock-api-url.com",
"Insecure": true,
"DefaultOrganizationID": "11111111-1111-1111-1111-111111111111",
"DefaultProjectID": null,
"DefaultRegion": "fr-par",
"DefaultZone": "fr-par-1",
"SendTelemetry": null
"access_key": "SCWP1XXXXXXXXXXXXXXX",
"secret_key": "11111111-1111-1111-1111-111111111111",
"api_url": "https://p1-mock-api-url.com",
"insecure": true,
"default_organization_id": "11111111-1111-1111-1111-111111111111",
"default_region": "fr-par",
"default_zone": "fr-par-1"
},
"p2": {
"AccessKey": "SCWP2XXXXXXXXXXXXXXX",
"SecretKey": "11111111-1111-1111-1111-111111111111",
"APIURL": "https://p2-mock-api-url.com",
"Insecure": true,
"DefaultOrganizationID": "11111111-1111-1111-1111-111111111111",
"DefaultProjectID": null,
"DefaultRegion": "fr-par",
"DefaultZone": "fr-par-1",
"SendTelemetry": null
"access_key": "SCWP2XXXXXXXXXXXXXXX",
"secret_key": "11111111-1111-1111-1111-111111111111",
"api_url": "https://p2-mock-api-url.com",
"insecure": true,
"default_organization_id": "11111111-1111-1111-1111-111111111111",
"default_region": "fr-par",
"default_zone": "fr-par-1"
}
}
}
8 changes: 6 additions & 2 deletions internal/namespaces/info/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func infosRoot() *core.Command {
BuildInfo: core.ExtractBuildInfo(ctx),
Settings: []*setting{
configPath(ctx),
profile(ctx),
profile(ctx, config),
defaultRegion(ctx, config, profileName),
defaultZone(ctx, config, profileName),
defaultOrganizationID(ctx, config, profileName),
Expand Down Expand Up @@ -105,18 +105,22 @@ func configPath(ctx context.Context) *setting {
return setting
}

func profile(ctx context.Context) *setting {
func profile(ctx context.Context, config *scw.Config) *setting {
setting := &setting{
Key: "profile",
Value: core.ExtractProfileName(ctx),
}

switch {
case core.ExtractProfileFlag(ctx) != "":
setting.Origin = "flag --profile/-p"
setting.Value = core.ExtractProfileFlag(ctx)
case core.ExtractEnv(ctx, scw.ScwActiveProfileEnv) != "":
setting.Origin = fmt.Sprintf("env (%s)", scw.ScwActiveProfileEnv)
setting.Value = core.ExtractEnv(ctx, scw.ScwActiveProfileEnv)
case config != nil && config.ActiveProfile != nil:
setting.Origin = "active_profile in config file"
setting.Value = *config.ActiveProfile
default:
setting.Origin = ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GoOS runtime.GOOS
Settings:
KEY VALUE ORIGIN
config_path /tmp/.config/scw/config.yaml env (SCW_CONFIG_PATH)
profile - -
profile default -
default_region fr-par env (SCW_DEFAULT_REGION)
default_zone fr-par-1 env (SCW_DEFAULT_ZONE)
default_organization_id 22222222-2222-2222-2222-222222222222 env (SCW_DEFAULT_ORGANIZATION_ID)
Expand All @@ -37,7 +37,7 @@ secret_key 22222222-2222-2222-2222-222222222222 env (SCW_SECRET_K
},
{
"key": "profile",
"value": "",
"value": "default",
"origin": ""
},
{
Expand Down
Loading