Skip to content

Commit

Permalink
Add rm context command (#30)
Browse files Browse the repository at this point in the history
* Add rm context cmd

Signed-off-by: Jéssica Lins <[email protected]>

* Update cmd description

Signed-off-by: Jéssica Lins <[email protected]>

* Add TestRemoveContext

Signed-off-by: Jéssica Lins <[email protected]>

* Update documentation

Signed-off-by: Jéssica Lins <[email protected]>

* Update README.md

Co-authored-by: Matej Gera <[email protected]>

Co-authored-by: Matej Gera <[email protected]>
  • Loading branch information
jessicalins and matej-g committed Jun 3, 2022
1 parent 5f2523a commit 6ed7af6
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 3 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,10 @@ Usage:
obsctl context [command]

Available Commands:
api Add/edit API configuration.
api Add/edit/remove API configuration.
current View current context configuration.
list View all context configuration.
rm Remove context configuration.
switch Switch to another context.

Flags:
Expand All @@ -142,6 +143,8 @@ Global Flags:
Use "obsctl context [command] --help" for more information about a command.
```
You can also remove a context by using `obsctl context rm <API Name>/<Tenant Name>`. In case an API configuration does not have a tenant associated with it, the API configuration can be removed using `obsctl context api rm <API Name>`.
### Metrics
You can use `obsctl metrics` to get/set metrics-based resources.
Expand Down
25 changes: 23 additions & 2 deletions pkg/cmd/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ func NewContextCommand(ctx context.Context) *cobra.Command {

apiCmd := &cobra.Command{
Use: "api",
Short: "Add/edit API configuration.",
Long: "Add/edit API configuration.",
Short: "Add/edit/remove API configuration.",
Long: "Add/edit/remove API configuration.",
}

var addURL, addName string
Expand Down Expand Up @@ -136,10 +136,31 @@ func NewContextCommand(ctx context.Context) *cobra.Command {
},
}

rmCmd := &cobra.Command{
Use: "rm <api>/<tenant>",
Short: "Remove context configuration.",
Long: "Remove context configuration.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cntxt := strings.Split(args[0], "/")
if len(cntxt) != 2 {
return fmt.Errorf("invalid context name: use format <api>/<tenant>")
}

conf, err := config.Read(logger)
if err != nil {
return err
}

return conf.RemoveContext(logger, cntxt[0], cntxt[1])
},
}

cmd.AddCommand(apiCmd)
cmd.AddCommand(switchCmd)
cmd.AddCommand(currentCmd)
cmd.AddCommand(listCmd)
cmd.AddCommand(rmCmd)

apiCmd.AddCommand(apiAddCmd)
apiCmd.AddCommand(apiRmCmd)
Expand Down
13 changes: 13 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,16 @@ func (c *Config) SetCurrentContext(logger log.Logger, api string, tenant string)

return c.Save(logger)
}

// RemoveContext removes the specified context <api>/<tenant>. If the API configuration has only one tenant,
// the API configuration is removed.
func (c *Config) RemoveContext(logger log.Logger, api string, tenant string) error {
// If there is only one tenant per API configuration, remove the whole API configuration.
if _, ok := c.APIs[api].Contexts[tenant]; ok {
if len(c.APIs[api].Contexts) == 1 {
return c.RemoveAPI(logger, api)
}
}

return c.RemoveTenant(logger, tenant, api)
}
80 changes: 80 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,3 +920,83 @@ func TestSetCurrentContext(t *testing.T) {
})
})
}

func TestRemoveContext(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "test-save")
testutil.Ok(t, err)
t.Cleanup(func() { testutil.Ok(t, os.RemoveAll(tmpDir)) })
testutil.Ok(t, os.MkdirAll(filepath.Join(tmpDir, "obsctl", "test"), os.ModePerm))
testutil.Ok(t, ioutil.WriteFile(filepath.Join(tmpDir, "obsctl", "test", "config.json"), []byte(""), os.ModePerm))
testutil.Ok(t, os.Setenv("OBSCTL_CONFIG_PATH", filepath.Join(tmpDir, "obsctl", "test", "config.json")))

tlogger := level.NewFilter(log.NewJSONLogger(log.NewSyncWriter(os.Stderr)), level.AllowDebug())

t.Run("empty config", func(t *testing.T) {
cfg := Config{
pathOverride: filepath.Join(tmpDir, "obsctl", "test", "config.json"),
}

err := cfg.RemoveContext(tlogger, "stage", "first")
testutil.NotOk(t, err)
testutil.Equals(t, fmt.Errorf("api with name stage doesn't exist"), err)
})

t.Run("config with one API no tenant", func(t *testing.T) {
cfg := Config{
pathOverride: filepath.Join(tmpDir, "obsctl", "test", "config.json"),
APIs: map[string]APIConfig{
"stage": {URL: "https://stage.api:9090", Contexts: nil},
},
}

err := cfg.RemoveContext(tlogger, "stage", "first")

testutil.NotOk(t, err)
testutil.Equals(t, fmt.Errorf("tenant with name first doesn't exist in api stage"), err)
})

t.Run("config with one API and one tenant", func(t *testing.T) {
cfg := Config{
pathOverride: filepath.Join(tmpDir, "obsctl", "test", "config.json"),
APIs: map[string]APIConfig{
"stage": {URL: "https://stage.api:9090", Contexts: map[string]TenantConfig{
"first": {Tenant: "first", OIDC: &OIDCConfig{Audience: "obs", ClientID: "first", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
}},
},
}

testutil.Ok(t, cfg.RemoveContext(tlogger, "stage", "first"))

testutil.Equals(t, cfg.APIs, map[string]APIConfig{})
})

t.Run("config with multiple APIs and tenants", func(t *testing.T) {
cfg := Config{
pathOverride: filepath.Join(tmpDir, "obsctl", "test", "config.json"),
APIs: map[string]APIConfig{
"stage": {URL: "https://stage.api:9090", Contexts: map[string]TenantConfig{
"first": {Tenant: "first", OIDC: &OIDCConfig{Audience: "obs", ClientID: "first", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
"second": {Tenant: "second", OIDC: &OIDCConfig{Audience: "obs", ClientID: "second", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
}},
"prod": {URL: "https://prod.api:9090", Contexts: map[string]TenantConfig{
"first": {Tenant: "first", OIDC: &OIDCConfig{Audience: "obs", ClientID: "first", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
"second": {Tenant: "second", OIDC: &OIDCConfig{Audience: "obs", ClientID: "second", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
}},
},
}

testutil.Ok(t, cfg.RemoveContext(tlogger, "stage", "second"))
testutil.Ok(t, cfg.RemoveContext(tlogger, "prod", "first"))

exp := map[string]APIConfig{
"stage": {URL: "https://stage.api:9090", Contexts: map[string]TenantConfig{
"first": {Tenant: "first", OIDC: &OIDCConfig{Audience: "obs", ClientID: "first", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
}},
"prod": {URL: "https://prod.api:9090", Contexts: map[string]TenantConfig{
"second": {Tenant: "second", OIDC: &OIDCConfig{Audience: "obs", ClientID: "second", ClientSecret: "secret", IssuerURL: "sso.obs.com"}},
}},
}

testutil.Equals(t, cfg.APIs, exp)
})
}

0 comments on commit 6ed7af6

Please sign in to comment.