-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #77 from StackVista/STAC-20950-commands-to-manage-…
…ingestion-api-keys STAC-20950 Commands to manage Ingestion Api Keys
- Loading branch information
Showing
9 changed files
with
370 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"github.com/stackvista/stackstate-cli/cmd/ingestionapikey" | ||
"github.com/stackvista/stackstate-cli/internal/di" | ||
) | ||
|
||
func IngestionApiKeyCommand(deps *di.Deps) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "ingestion-api-key", | ||
Short: "Manage Ingestion API Keys", | ||
Long: "Manage API Keys used by ingestion pipelines, means data (spans, metrics, logs an so on) send by STS Agent, OTel and so on.", | ||
} | ||
|
||
cmd.AddCommand(ingestionapikey.CreateCommand(deps)) | ||
cmd.AddCommand(ingestionapikey.ListCommand(deps)) | ||
cmd.AddCommand(ingestionapikey.DeleteCommand(deps)) | ||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package ingestionapikey | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/gookit/color" | ||
"github.com/spf13/cobra" | ||
"github.com/stackvista/stackstate-cli/generated/stackstate_api" | ||
"github.com/stackvista/stackstate-cli/internal/common" | ||
"github.com/stackvista/stackstate-cli/internal/di" | ||
) | ||
|
||
const ( | ||
DateFormat = "2006-01-02" | ||
) | ||
|
||
type CreateArgs struct { | ||
Name string | ||
Expiration time.Time | ||
Description string | ||
} | ||
|
||
func CreateCommand(deps *di.Deps) *cobra.Command { | ||
args := &CreateArgs{} | ||
cmd := &cobra.Command{ | ||
Use: "create", | ||
Short: "Create a new Ingestion Api Key", | ||
Long: "Creates a token and then returns it in the response, the token can't be obtained any more after that so store it in the safe space.", | ||
RunE: deps.CmdRunEWithApi(RunIngestionApiKeyGenerationCommand(args)), | ||
} | ||
|
||
common.AddRequiredNameFlagVar(cmd, &args.Name, "Name of the API Key") | ||
cmd.Flags().TimeVar(&args.Expiration, "expiration", time.Time{}, []string{DateFormat}, "Expiration date of the API Key") | ||
cmd.Flags().StringVar(&args.Description, "description", "", "Optional description of the API Key") | ||
return cmd | ||
} | ||
|
||
func RunIngestionApiKeyGenerationCommand(args *CreateArgs) di.CmdWithApiFn { | ||
return func(cmd *cobra.Command, cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo) common.CLIError { | ||
req := stackstate_api.GenerateIngestionApiKeyRequest{ | ||
Name: args.Name, | ||
} | ||
|
||
if len(args.Description) > 0 { | ||
req.Description = &args.Description | ||
} | ||
|
||
if !args.Expiration.IsZero() { | ||
m := args.Expiration.UnixMilli() | ||
req.Expiration = &m | ||
} | ||
|
||
ingestionApiKeyAPI := api.IngestionApiKeyApi.GenerateIngestionApiKey(cli.Context) | ||
|
||
serviceToken, resp, err := ingestionApiKeyAPI.GenerateIngestionApiKeyRequest(req).Execute() | ||
if err != nil { | ||
return common.NewResponseError(err, resp) | ||
} | ||
|
||
if cli.IsJson() { | ||
cli.Printer.PrintJson(map[string]interface{}{ | ||
"ingestion-api-key": serviceToken, | ||
}) | ||
} else { | ||
cli.Printer.Success(fmt.Sprintf("Ingestion API Key generated: %s\n", color.White.Render(serviceToken.ApiKey))) | ||
} | ||
|
||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package ingestionapikey | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stackvista/stackstate-cli/generated/stackstate_api" | ||
"github.com/stackvista/stackstate-cli/internal/di" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestIngestApiKeyGenerate(t *testing.T) { | ||
cli := di.NewMockDeps(t) | ||
cmd := CreateCommand(&cli.Deps) | ||
|
||
cli.MockClient.ApiMocks.IngestionApiKeyApi.GenerateIngestionApiKeyResponse.Result = stackstate_api.GeneratedIngestionApiKeyResponse{ | ||
Name: "test-token", | ||
ApiKey: "test-token-key", | ||
Expiration: int64p(1590105600000), | ||
Description: stringp("test-token-description"), | ||
} | ||
|
||
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "--name", "test-token", "--description", "test-token-description", "--expiration", "2020-05-22") | ||
|
||
checkCreateCall(t, cli.MockClient.ApiMocks.IngestionApiKeyApi.GenerateIngestionApiKeyCalls, "test-token", stringp("test-token-description"), int64p(1590105600000)) | ||
assert.Equal(t, []string{"Ingestion API Key generated: \x1b[37mtest-token-key\x1b[0m\n"}, *cli.MockPrinter.SuccessCalls) | ||
} | ||
|
||
func TestIngestApiKeyGenerateOnlyRequriedFlags(t *testing.T) { | ||
cli := di.NewMockDeps(t) | ||
cmd := CreateCommand(&cli.Deps) | ||
|
||
cli.MockClient.ApiMocks.IngestionApiKeyApi.GenerateIngestionApiKeyResponse.Result = stackstate_api.GeneratedIngestionApiKeyResponse{ | ||
Name: "test-token2", | ||
ApiKey: "test-token2-key", | ||
} | ||
|
||
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "--name", "test-token2") | ||
|
||
checkCreateCall(t, cli.MockClient.ApiMocks.IngestionApiKeyApi.GenerateIngestionApiKeyCalls, "test-token2", nil, nil) | ||
assert.Equal(t, []string{"Ingestion API Key generated: \x1b[37mtest-token2-key\x1b[0m\n"}, *cli.MockPrinter.SuccessCalls) | ||
} | ||
|
||
func TestIngestApiKeyGenerateJSON(t *testing.T) { | ||
cli := di.NewMockDeps(t) | ||
cmd := CreateCommand(&cli.Deps) | ||
|
||
r := &stackstate_api.GeneratedIngestionApiKeyResponse{ | ||
Name: "test-token", | ||
ApiKey: "test-token-key", | ||
Expiration: int64p(1590105600000), | ||
Description: stringp("test-token-description"), | ||
} | ||
|
||
cli.MockClient.ApiMocks.IngestionApiKeyApi.GenerateIngestionApiKeyResponse.Result = *r | ||
|
||
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "--name", "test-token", "--description", "test-token-description", "--expiration", "2020-05-22", "-o", "json") | ||
|
||
checkCreateCall(t, cli.MockClient.ApiMocks.IngestionApiKeyApi.GenerateIngestionApiKeyCalls, "test-token", stringp("test-token-description"), int64p(1590105600000)) | ||
assert.Equal(t, | ||
[]map[string]interface{}{{ | ||
"ingestion-api-key": r, | ||
}}, | ||
*cli.MockPrinter.PrintJsonCalls, | ||
) | ||
assert.False(t, cli.MockPrinter.HasNonJsonCalls) | ||
} | ||
|
||
func int64p(i int64) *int64 { | ||
return &i | ||
} | ||
|
||
func stringp(i string) *string { | ||
return &i | ||
} | ||
|
||
func checkCreateCall(t *testing.T, calls *[]stackstate_api.GenerateIngestionApiKeyCall, name string, description *string, expiration *int64) { | ||
assert.Len(t, *calls, 1) | ||
|
||
call := (*calls)[0] | ||
assert.Equal(t, name, call.PgenerateIngestionApiKeyRequest.Name) | ||
|
||
if description != nil { | ||
assert.Equal(t, *description, *call.PgenerateIngestionApiKeyRequest.Description) | ||
} else { | ||
assert.Nil(t, call.PgenerateIngestionApiKeyRequest.Description) | ||
} | ||
|
||
if expiration != nil { | ||
assert.Equal(t, *expiration, *call.PgenerateIngestionApiKeyRequest.Expiration) | ||
} else { | ||
assert.Nil(t, call.PgenerateIngestionApiKeyRequest.Expiration) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package ingestionapikey | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/stackvista/stackstate-cli/generated/stackstate_api" | ||
"github.com/stackvista/stackstate-cli/internal/common" | ||
"github.com/stackvista/stackstate-cli/internal/di" | ||
) | ||
|
||
type DeleteArgs struct { | ||
ID int64 | ||
} | ||
|
||
func DeleteCommand(deps *di.Deps) *cobra.Command { | ||
args := &DeleteArgs{} | ||
cmd := &cobra.Command{ | ||
Use: "delete", | ||
Short: "Delete an Ingestion Api Key", | ||
Long: "Deleted key can't be used by sources, so all ingestion pipelines for that key will fail.", | ||
RunE: deps.CmdRunEWithApi(RunIngestionApiKeyDeleteCommand(args)), | ||
} | ||
|
||
common.AddRequiredIDFlagVar(cmd, &args.ID, "ID of the Ingestion Api Key to delete") | ||
|
||
return cmd | ||
} | ||
|
||
func RunIngestionApiKeyDeleteCommand(args *DeleteArgs) di.CmdWithApiFn { | ||
return func(cmd *cobra.Command, cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo) common.CLIError { | ||
resp, err := api.IngestionApiKeyApi.DeleteIngestionApiKey(cli.Context, args.ID).Execute() | ||
if err != nil { | ||
return common.NewResponseError(err, resp) | ||
} | ||
|
||
if cli.IsJson() { | ||
cli.Printer.PrintJson(map[string]interface{}{ | ||
"deleted-ingestion-api-key": args.ID, | ||
}) | ||
} else { | ||
cli.Printer.Success(fmt.Sprintf("Ingestion Api Key deleted: %d", args.ID)) | ||
} | ||
|
||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package ingestionapikey | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stackvista/stackstate-cli/internal/di" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestDeleteShouldFailOnNonIntID(t *testing.T) { | ||
cli := di.NewMockDeps(t) | ||
cmd := DeleteCommand(&cli.Deps) | ||
|
||
_, err := di.ExecuteCommandWithContext(&cli.Deps, cmd, "--id", "foo") | ||
|
||
assert.NotNil(t, err) | ||
assert.Contains(t, err.Error(), "invalid argument \"foo\" for \"-i, --id\"") | ||
} | ||
|
||
func TestDelete(t *testing.T) { | ||
cli := di.NewMockDeps(t) | ||
cmd := DeleteCommand(&cli.Deps) | ||
|
||
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "--id", "1") | ||
|
||
assert.Len(t, *cli.MockClient.ApiMocks.IngestionApiKeyApi.DeleteIngestionApiKeyCalls, 1) | ||
assert.Equal(t, int64(1), (*cli.MockClient.ApiMocks.IngestionApiKeyApi.DeleteIngestionApiKeyCalls)[0].PingestionApiKeyId) | ||
|
||
assert.Equal(t, []string{"Ingestion Api Key deleted: 1"}, *cli.MockPrinter.SuccessCalls) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package ingestionapikey | ||
|
||
import ( | ||
"sort" | ||
"time" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/stackvista/stackstate-cli/generated/stackstate_api" | ||
"github.com/stackvista/stackstate-cli/internal/common" | ||
"github.com/stackvista/stackstate-cli/internal/di" | ||
"github.com/stackvista/stackstate-cli/internal/printer" | ||
) | ||
|
||
func ListCommand(deps *di.Deps) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "list", | ||
Short: "List Ingestion Api Keys", | ||
Long: "Returns only metadata without a key itself.", | ||
RunE: deps.CmdRunEWithApi(RunIngestionApiKeyListCommand), | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
func RunIngestionApiKeyListCommand(cmd *cobra.Command, cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo) common.CLIError { | ||
ingestionApiKeys, resp, err := api.IngestionApiKeyApi.GetIngestionApiKeys(cli.Context).Execute() | ||
if err != nil { | ||
return common.NewResponseError(err, resp) | ||
} | ||
|
||
sort.SliceStable(ingestionApiKeys, func(i, j int) bool { | ||
return ingestionApiKeys[i].Name < ingestionApiKeys[j].Name | ||
}) | ||
|
||
if cli.IsJson() { | ||
cli.Printer.PrintJson(map[string]interface{}{ | ||
"ingestion-api-keys": ingestionApiKeys, | ||
}) | ||
} else { | ||
data := make([][]interface{}, 0) | ||
for _, ingestionApiKey := range ingestionApiKeys { | ||
sid := ingestionApiKey.Id | ||
exp := "" | ||
if ingestionApiKey.Expiration != nil { | ||
exp = time.UnixMilli(*ingestionApiKey.Expiration).Format(DateFormat) | ||
} | ||
data = append(data, []interface{}{sid, ingestionApiKey.Name, exp, ingestionApiKey.Description}) | ||
} | ||
|
||
cli.Printer.Table(printer.TableData{ | ||
Header: []string{"id", "name", "expiration", "description"}, | ||
Data: data, | ||
MissingTableDataMsg: printer.NotFoundMsg{Types: "ingestion api keys"}, | ||
}) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package ingestionapikey | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stackvista/stackstate-cli/generated/stackstate_api" | ||
"github.com/stackvista/stackstate-cli/internal/di" | ||
"github.com/stackvista/stackstate-cli/internal/printer" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestIngestionApiKeyList(t *testing.T) { | ||
cli := di.NewMockDeps(t) | ||
cmd := ListCommand(&cli.Deps) | ||
key1desc := "main key" | ||
|
||
cli.MockClient.ApiMocks.IngestionApiKeyApi.GetIngestionApiKeysResponse.Result = []stackstate_api.IngestionApiKey{ | ||
{ | ||
Id: 1, | ||
Name: "key1", | ||
Description: &key1desc, | ||
Expiration: int64p(1590105600000), | ||
}, | ||
{ | ||
Id: 2, | ||
Name: "key2", | ||
Description: nil, | ||
Expiration: nil, | ||
}, | ||
} | ||
|
||
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd) | ||
|
||
tableData := []printer.TableData{ | ||
{ | ||
Header: []string{"id", "name", "expiration", "description"}, | ||
Data: [][]interface{}{ | ||
{int64(1), "key1", "2020-05-22", &key1desc}, | ||
{int64(2), "key2", "", (*string)(nil)}, | ||
}, | ||
MissingTableDataMsg: printer.NotFoundMsg{Types: "ingestion api keys"}, | ||
}, | ||
} | ||
|
||
assert.Equal(t, tableData, *cli.MockPrinter.TableCalls) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.