From 1dd01f975b9e1f5b6e0d88c6ca4aa022556f8212 Mon Sep 17 00:00:00 2001 From: Nathanael DEMACON Date: Fri, 24 Mar 2023 12:25:02 +0100 Subject: [PATCH 1/4] feat(container): add namespace waiters --- docs/commands/container.md | 21 ++++ internal/core/errors_cmp.go | 14 +++ .../namespaces/container/v1beta1/custom.go | 3 + .../container/v1beta1/custom_namespace.go | 104 ++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 internal/core/errors_cmp.go diff --git a/docs/commands/container.md b/docs/commands/container.md index a1adcb117b..f397806739 100644 --- a/docs/commands/container.md +++ b/docs/commands/container.md @@ -28,6 +28,7 @@ Containers API. - [Get a namespace](#get-a-namespace) - [List all your namespaces](#list-all-your-namespaces) - [Update an existing namespace](#update-an-existing-namespace) + - [Wait for a namespace to reach a stable state (installation)](#wait-for-a-namespace-to-reach-a-stable-state-(installation)) - [Token management commands](#token-management-commands) - [Create a new revocable token](#create-a-new-revocable-token) - [Delete a token](#delete-a-token) @@ -561,6 +562,26 @@ scw container namespace update [arg=value ...] +### Wait for a namespace to reach a stable state (installation) + +Wait for a namespace to reach a stable state. This is similar to using --wait flag on other action commands, but without requiring a new action on the namespace. + +**Usage:** + +``` +scw container namespace wait [arg=value ...] +``` + + +**Args:** + +| Name | | Description | +|------|---|-------------| +| namespace-id | Required | | +| region | Default: `fr-par`
One of: `fr-par`, `nl-ams`, `pl-waw` | Region to target. If none is passed will use default region from the config | + + + ## Token management commands Token management commands. diff --git a/internal/core/errors_cmp.go b/internal/core/errors_cmp.go new file mode 100644 index 0000000000..69d6ccff44 --- /dev/null +++ b/internal/core/errors_cmp.go @@ -0,0 +1,14 @@ +package core + +import ( + "errors" + "net/http" + + "github.com/scaleway/scaleway-sdk-go/scw" +) + +func IsNotFoundError(err error) bool { + notFoundError := &scw.ResourceNotFoundError{} + responseError := &scw.ResponseError{} + return errors.As(err, &responseError) && responseError.StatusCode == http.StatusNotFound || errors.As(err, ¬FoundError) +} diff --git a/internal/namespaces/container/v1beta1/custom.go b/internal/namespaces/container/v1beta1/custom.go index b420f01b37..8f6ff5c8a5 100644 --- a/internal/namespaces/container/v1beta1/custom.go +++ b/internal/namespaces/container/v1beta1/custom.go @@ -14,7 +14,10 @@ func GetCommands() *core.Commands { human.RegisterMarshalerFunc(container.CronStatus(""), human.EnumMarshalFunc(cronStatusMarshalSpecs)) cmds.MustFind("container", "container", "deploy").Override(containerContainerDeployBuilder) + cmds.MustFind("container", "namespace", "create").Override(containerNamespaceCreateBuilder) + cmds.MustFind("container", "namespace", "delete").Override(containerNamespaceDeleteBuilder) + cmds.Add(containerNamespaceWaitCommand()) cmds.Add(containerDeployCommand()) return cmds diff --git a/internal/namespaces/container/v1beta1/custom_namespace.go b/internal/namespaces/container/v1beta1/custom_namespace.go index 0fecb6fe8f..b01ce7446c 100644 --- a/internal/namespaces/container/v1beta1/custom_namespace.go +++ b/internal/namespaces/container/v1beta1/custom_namespace.go @@ -1,12 +1,22 @@ package container import ( + "context" + "fmt" + "reflect" + "time" + "github.com/fatih/color" + "github.com/scaleway/scaleway-cli/v2/internal/core" "github.com/scaleway/scaleway-cli/v2/internal/human" container "github.com/scaleway/scaleway-sdk-go/api/container/v1beta1" + "github.com/scaleway/scaleway-sdk-go/logger" + "github.com/scaleway/scaleway-sdk-go/scw" ) var ( + containerNamespaceActionTimeout = 5 * time.Minute + namespaceStatusMarshalSpecs = human.EnumMarshalSpecs{ container.NamespaceStatusCreating: &human.EnumMarshalSpec{Attribute: color.FgBlue}, container.NamespaceStatusDeleting: &human.EnumMarshalSpec{Attribute: color.FgBlue}, @@ -17,3 +27,97 @@ var ( container.NamespaceStatusUnknown: &human.EnumMarshalSpec{Attribute: color.Faint}, } ) + +func containerNamespaceWaitCommand() *core.Command { + type containerNamespaceWaitRequest struct { + Region scw.Region + + NamespaceID string + } + + return &core.Command{ + Short: `Wait for a namespace to reach a stable state (installation)`, + Long: `Wait for a namespace to reach a stable state. This is similar to using --wait flag on other action commands, but without requiring a new action on the namespace.`, + Namespace: "container", + Resource: "namespace", + Verb: "wait", + Groups: []string{"workflow"}, + ArgsType: reflect.TypeOf(containerNamespaceWaitRequest{}), + ArgSpecs: core.ArgSpecs{ + { + Name: "namespace-id", + Required: true, + Deprecated: false, + Positional: true, + }, + core.RegionArgSpec(scw.RegionFrPar, scw.RegionNlAms, scw.RegionPlWaw), + }, + Run: func(ctx context.Context, argsI interface{}) (i interface{}, err error) { + req := argsI.(*containerNamespaceWaitRequest) + api := container.NewAPI(core.ExtractClient(ctx)) + + logger.Debugf("starting to wait for the namespace to reach a stable delivery status") + namespace, err := api.WaitForNamespace(&container.WaitForNamespaceRequest{ + Region: req.Region, + NamespaceID: req.NamespaceID, + Timeout: scw.TimeDurationPtr(containerNamespaceActionTimeout), + RetryInterval: core.DefaultRetryInterval, + }) + if err != nil { + return nil, err + } + + if namespace.Status != container.NamespaceStatusReady { + return nil, &core.CliError{ + Err: fmt.Errorf("the namespace did not reach a stable delivery status"), + Details: fmt.Sprintf("the namespace %s is in %s status", namespace.RegistryNamespaceID, namespace.Status), + } + } + + return namespace, nil + }, + } +} + +func containerNamespaceCreateBuilder(c *core.Command) *core.Command { + c.WaitFunc = func(ctx context.Context, argsI, respI interface{}) (interface{}, error) { + res := respI.(*container.Namespace) + + client := core.ExtractClient(ctx) + api := container.NewAPI(client) + return api.WaitForNamespace(&container.WaitForNamespaceRequest{ + NamespaceID: res.ID, + Region: res.Region, + Timeout: scw.TimeDurationPtr(containerNamespaceActionTimeout), + RetryInterval: core.DefaultRetryInterval, + }) + } + + return c +} + +func containerNamespaceDeleteBuilder(c *core.Command) *core.Command { + c.WaitFunc = func(ctx context.Context, argsI, respI interface{}) (interface{}, error) { + req := argsI.(*container.DeleteNamespaceRequest) + + client := core.ExtractClient(ctx) + api := container.NewAPI(client) + _, err := api.WaitForNamespace(&container.WaitForNamespaceRequest{ + NamespaceID: req.NamespaceID, + Region: req.Region, + Timeout: scw.TimeDurationPtr(containerNamespaceActionTimeout), + RetryInterval: core.DefaultRetryInterval, + }) + if err != nil { + if core.IsNotFoundError(err) { + return nil, nil + } + + return nil, err + } + + return nil, nil + } + + return c +} From 5b4ba25627e500bab0a7521f72d55b4538288366 Mon Sep 17 00:00:00 2001 From: Nathanael DEMACON Date: Fri, 24 Mar 2023 14:52:38 +0100 Subject: [PATCH 2/4] remove wait command --- .../namespaces/container/v1beta1/custom.go | 1 - .../container/v1beta1/custom_namespace.go | 54 ------------------- 2 files changed, 55 deletions(-) diff --git a/internal/namespaces/container/v1beta1/custom.go b/internal/namespaces/container/v1beta1/custom.go index 8f6ff5c8a5..1381772125 100644 --- a/internal/namespaces/container/v1beta1/custom.go +++ b/internal/namespaces/container/v1beta1/custom.go @@ -17,7 +17,6 @@ func GetCommands() *core.Commands { cmds.MustFind("container", "namespace", "create").Override(containerNamespaceCreateBuilder) cmds.MustFind("container", "namespace", "delete").Override(containerNamespaceDeleteBuilder) - cmds.Add(containerNamespaceWaitCommand()) cmds.Add(containerDeployCommand()) return cmds diff --git a/internal/namespaces/container/v1beta1/custom_namespace.go b/internal/namespaces/container/v1beta1/custom_namespace.go index b01ce7446c..4f2b3653d9 100644 --- a/internal/namespaces/container/v1beta1/custom_namespace.go +++ b/internal/namespaces/container/v1beta1/custom_namespace.go @@ -2,15 +2,12 @@ package container import ( "context" - "fmt" - "reflect" "time" "github.com/fatih/color" "github.com/scaleway/scaleway-cli/v2/internal/core" "github.com/scaleway/scaleway-cli/v2/internal/human" container "github.com/scaleway/scaleway-sdk-go/api/container/v1beta1" - "github.com/scaleway/scaleway-sdk-go/logger" "github.com/scaleway/scaleway-sdk-go/scw" ) @@ -28,57 +25,6 @@ var ( } ) -func containerNamespaceWaitCommand() *core.Command { - type containerNamespaceWaitRequest struct { - Region scw.Region - - NamespaceID string - } - - return &core.Command{ - Short: `Wait for a namespace to reach a stable state (installation)`, - Long: `Wait for a namespace to reach a stable state. This is similar to using --wait flag on other action commands, but without requiring a new action on the namespace.`, - Namespace: "container", - Resource: "namespace", - Verb: "wait", - Groups: []string{"workflow"}, - ArgsType: reflect.TypeOf(containerNamespaceWaitRequest{}), - ArgSpecs: core.ArgSpecs{ - { - Name: "namespace-id", - Required: true, - Deprecated: false, - Positional: true, - }, - core.RegionArgSpec(scw.RegionFrPar, scw.RegionNlAms, scw.RegionPlWaw), - }, - Run: func(ctx context.Context, argsI interface{}) (i interface{}, err error) { - req := argsI.(*containerNamespaceWaitRequest) - api := container.NewAPI(core.ExtractClient(ctx)) - - logger.Debugf("starting to wait for the namespace to reach a stable delivery status") - namespace, err := api.WaitForNamespace(&container.WaitForNamespaceRequest{ - Region: req.Region, - NamespaceID: req.NamespaceID, - Timeout: scw.TimeDurationPtr(containerNamespaceActionTimeout), - RetryInterval: core.DefaultRetryInterval, - }) - if err != nil { - return nil, err - } - - if namespace.Status != container.NamespaceStatusReady { - return nil, &core.CliError{ - Err: fmt.Errorf("the namespace did not reach a stable delivery status"), - Details: fmt.Sprintf("the namespace %s is in %s status", namespace.RegistryNamespaceID, namespace.Status), - } - } - - return namespace, nil - }, - } -} - func containerNamespaceCreateBuilder(c *core.Command) *core.Command { c.WaitFunc = func(ctx context.Context, argsI, respI interface{}) (interface{}, error) { res := respI.(*container.Namespace) From 98436f1fea43a0251bef319bca9043d32cb89705 Mon Sep 17 00:00:00 2001 From: Nathanael DEMACON Date: Fri, 24 Mar 2023 14:53:50 +0100 Subject: [PATCH 3/4] update doc --- docs/commands/container.md | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/docs/commands/container.md b/docs/commands/container.md index f397806739..a1adcb117b 100644 --- a/docs/commands/container.md +++ b/docs/commands/container.md @@ -28,7 +28,6 @@ Containers API. - [Get a namespace](#get-a-namespace) - [List all your namespaces](#list-all-your-namespaces) - [Update an existing namespace](#update-an-existing-namespace) - - [Wait for a namespace to reach a stable state (installation)](#wait-for-a-namespace-to-reach-a-stable-state-(installation)) - [Token management commands](#token-management-commands) - [Create a new revocable token](#create-a-new-revocable-token) - [Delete a token](#delete-a-token) @@ -562,26 +561,6 @@ scw container namespace update [arg=value ...] -### Wait for a namespace to reach a stable state (installation) - -Wait for a namespace to reach a stable state. This is similar to using --wait flag on other action commands, but without requiring a new action on the namespace. - -**Usage:** - -``` -scw container namespace wait [arg=value ...] -``` - - -**Args:** - -| Name | | Description | -|------|---|-------------| -| namespace-id | Required | | -| region | Default: `fr-par`
One of: `fr-par`, `nl-ams`, `pl-waw` | Region to target. If none is passed will use default region from the config | - - - ## Token management commands Token management commands. From a7e3496badd18a971b46c848379d4db3f6684e3b Mon Sep 17 00:00:00 2001 From: Nathanael DEMACON Date: Fri, 24 Mar 2023 15:06:54 +0100 Subject: [PATCH 4/4] update goldens --- .../test-all-usage-container-namespace-create-usage.golden | 1 + .../test-all-usage-container-namespace-delete-usage.golden | 1 + 2 files changed, 2 insertions(+) diff --git a/cmd/scw/testdata/test-all-usage-container-namespace-create-usage.golden b/cmd/scw/testdata/test-all-usage-container-namespace-create-usage.golden index 552b6d8c4c..a60dc0f441 100644 --- a/cmd/scw/testdata/test-all-usage-container-namespace-create-usage.golden +++ b/cmd/scw/testdata/test-all-usage-container-namespace-create-usage.golden @@ -16,6 +16,7 @@ ARGS: FLAGS: -h, --help help for create + -w, --wait wait until the namespace is ready GLOBAL FLAGS: -c, --config string The path to the config file diff --git a/cmd/scw/testdata/test-all-usage-container-namespace-delete-usage.golden b/cmd/scw/testdata/test-all-usage-container-namespace-delete-usage.golden index e1624612fc..9502429299 100644 --- a/cmd/scw/testdata/test-all-usage-container-namespace-delete-usage.golden +++ b/cmd/scw/testdata/test-all-usage-container-namespace-delete-usage.golden @@ -11,6 +11,7 @@ ARGS: FLAGS: -h, --help help for delete + -w, --wait wait until the namespace is ready GLOBAL FLAGS: -c, --config string The path to the config file