Skip to content

Commit

Permalink
GCLOUD2-13152: Profiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitrii Shelomentsev committed Mar 26, 2024
1 parent f870dbf commit 2c78fea
Show file tree
Hide file tree
Showing 22 changed files with 1,023 additions and 98 deletions.
3 changes: 2 additions & 1 deletion cmd/gcore-cli/main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package main

import (
"github.com/G-core/gcore-cli/internal/commands"
"github.com/G-core/gcore-cli/internal/core"
)

func main() {
core.Execute()
core.Execute(commands.Commands())
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module github.com/G-core/gcore-cli

go 1.21.5


require (
github.com/G-Core/FastEdge-client-sdk-go v0.0.0-20240304075046-db0c8c3d17e7
github.com/alecthomas/assert v1.0.0
Expand All @@ -18,6 +17,7 @@ require (
)

require (
github.com/AlekSi/pointer v1.2.0 // indirect
github.com/alecthomas/colour v0.1.0 // indirect
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
Expand All @@ -27,6 +27,7 @@ require (
github.com/go-openapi/swag v0.22.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
github.com/G-Core/FastEdge-client-sdk-go v0.0.0-20240214130448-d87df1e38764 h1:7CATrk7BJpU1t4wr2avczZaX1KrwsjhArBKBaiSQN2M=
github.com/G-Core/FastEdge-client-sdk-go v0.0.0-20240214130448-d87df1e38764/go.mod h1:ggyUVhy8/OCMBY4nbm7n9qDoPioROCk4vHhDJq9w7qE=
github.com/G-Core/FastEdge-client-sdk-go v0.0.0-20240304075046-db0c8c3d17e7 h1:99yyAfaF6OV2ghz75yE72LwdzxP6gUYa3hL7XkObb5s=
Expand Down Expand Up @@ -43,6 +45,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
Expand Down
17 changes: 17 additions & 0 deletions internal/commands/commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package commands

import (
"github.com/spf13/cobra"

"github.com/G-core/gcore-cli/internal/commands/config"
"github.com/G-core/gcore-cli/internal/commands/fastedge"
initCmd "github.com/G-core/gcore-cli/internal/commands/init"
)

func Commands() []*cobra.Command {
return []*cobra.Command{
fastedge.Commands(),
initCmd.Commands(),
config.Commands(),
}
}
149 changes: 149 additions & 0 deletions internal/commands/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package config

import (
"fmt"
"slices"

"github.com/spf13/cobra"

"github.com/G-core/gcore-cli/internal/config"
"github.com/G-core/gcore-cli/internal/core"
"github.com/G-core/gcore-cli/internal/output"
)

func Commands() *cobra.Command {
var cmd = &cobra.Command{
Use: "config",
Short: "Config file management",
GroupID: "configuration",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

cmd.AddCommand(info(), get(), set(), unset(), dump(), profileCmd())
return cmd
}

func profileCmd() *cobra.Command {
var cmd = &cobra.Command{
Use: "profile",
Short: "Commands to manage profiles from the config",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

cmd.AddCommand(listProfiles(), switchProfileCmd(), deleteProfileCmd())
return cmd
}

func deleteProfileCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "delete <profile>",
Aliases: []string{"d"},
ValidArgsFunction: core.ProfileCompletion,
Short: "Delete profile from the config",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
cmd.Help()

return nil
}

profileName := args[0]
ctx := cmd.Context()
cfg := core.ExtractConfig(ctx)
active := core.ExtractProfile(ctx)

_, exist := cfg.Profiles[profileName]
if exist {
delete(cfg.Profiles, profileName)
} else {
return fmt.Errorf("profile '%s' doesn't exist", profileName)
}

if active == profileName {
cfg.ActiveProfile = config.DefaultProfile
}

path, err := core.ExtractConfigPath(ctx)
if err != nil {
return err
}

return cfg.Save(path)
},
}

return cmd
}

func listProfiles() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "Display list of available profiles in the config",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
cfg := core.ExtractConfig(ctx)

profiles := append([]profileView{}, toProfileView(config.DefaultProfile, &cfg.Profile))

var names []string
for name, _ := range cfg.Profiles {
names = append(names, name)
}
slices.Sort(names)

for _, name := range names {
pv := toProfileView(name, cfg.Profiles[name])

profiles = append(profiles, pv)
}

output.Print(profiles)

return nil
},
}

return cmd
}

func switchProfileCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "switch <profile>",
ValidArgsFunction: core.ProfileCompletion,
Short: "Make selected profile active",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
cmd.Help()

return nil
}

profileName := args[0]
ctx := cmd.Context()
cfg := core.ExtractConfig(ctx)

_, exist := cfg.Profiles[profileName]
if exist {
cfg.ActiveProfile = profileName
} else if profileName != config.DefaultProfile {
return fmt.Errorf("profile '%s' doesn't exist", profileName)
} else {
cfg.ActiveProfile = config.DefaultProfile
}

path, err := core.ExtractConfigPath(ctx)
if err != nil {
return err
}

return cfg.Save(path)
},
}

return cmd
}
33 changes: 33 additions & 0 deletions internal/commands/config/dump.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package config

import (
"github.com/AlekSi/pointer"
"github.com/spf13/cobra"

"github.com/G-core/gcore-cli/internal/core"
"github.com/G-core/gcore-cli/internal/output"
)

func dump() *cobra.Command {
var cmd = &cobra.Command{
Use: "dump",
Short: "Dumps the config file",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context()
cfg := core.ExtractConfig(ctx)

// Secure keys
cfg.Profile.ApiKey = pointer.To(secureKey(cfg.Profile.ApiKey))
for _, profile := range cfg.Profiles {
profile.ApiKey = pointer.To(secureKey(profile.ApiKey))
}

output.Print(cfg)

return nil
},
}

return cmd
}
74 changes: 74 additions & 0 deletions internal/commands/config/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package config

import (
"fmt"
"reflect"

"github.com/iancoleman/strcase"
"github.com/spf13/cobra"

"github.com/G-core/gcore-cli/internal/config"
"github.com/G-core/gcore-cli/internal/core"
"github.com/G-core/gcore-cli/internal/output"
)

func getProfileField(profile *config.Profile, key string) (reflect.Value, error) {
field := reflect.ValueOf(profile).Elem().FieldByName(strcase.ToCamel(key))
reflect.ValueOf(profile).Elem().FieldByNameFunc(func(s string) bool {
return key == strcase.ToKebab(s)
})

if !field.IsValid() {
return reflect.ValueOf(nil), fmt.Errorf("invalid key: %s", key)
}

return field, nil
}

func getProfileValue(profile *config.Profile, fieldName string) (interface{}, error) {
field, err := getProfileField(profile, fieldName)
if err != nil {
return nil, err
}
return field.Interface(), nil
}

func get() *cobra.Command {
var cmd = &cobra.Command{
Use: "get <property>",
Short: "Get property value from the config file",
ValidArgs: []string{"api-url", "api-key"},
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
cmd.Help()
}

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return nil
}

ctx := cmd.Context()
profileName := core.ExtractProfile(ctx)
cfg := core.ExtractConfig(ctx)

profile, err := cfg.GetProfile(profileName)
if err != nil {
return err
}

value, err := getProfileValue(profile, args[0])
if err != nil {
return err
}

output.Print(value)

return nil
},
}

return cmd
}
69 changes: 69 additions & 0 deletions internal/commands/config/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package config

import (
"strings"

"github.com/AlekSi/pointer"
"github.com/spf13/cobra"

"github.com/G-core/gcore-cli/internal/config"
"github.com/G-core/gcore-cli/internal/core"
"github.com/G-core/gcore-cli/internal/output"
)

type profileView struct {
Name string
ApiUrl *string
ApiKey *string
}

func toProfileView(name string, profile *config.Profile) profileView {
var pv = profileView{
Name: name,
}

if profile.ApiUrl != nil {
pv.ApiUrl = profile.ApiUrl
}

if profile.ApiKey != nil {
pv.ApiKey = pointer.To(secureKey(profile.ApiKey))
}

return pv
}

func info() *cobra.Command {
var cmd = &cobra.Command{
Use: "info",
Short: "Get information about config profile",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
profile, err := core.GetClientProfile(ctx)
if err != nil {
return err
}

output.Print(toProfileView(core.ExtractProfile(ctx), profile))

return nil
},
}

return cmd
}

func secureKey(key *string) string {
if key == nil || *key == "" {
return ""
}

var p1 = 0 + 5
var p2 = len(*key) - 1 - 5
if p1 > p2 {
return "XXXXXX"
}

return strings.Join([]string{(*key)[0:p1], "XXXXXX", (*key)[p2 : len((*key))-1]}, "")
}
Loading

0 comments on commit 2c78fea

Please sign in to comment.