diff --git a/docs/stackit_network-area.md b/docs/stackit_network-area.md index d9ba1ecda..6f2d751f8 100644 --- a/docs/stackit_network-area.md +++ b/docs/stackit_network-area.md @@ -35,6 +35,7 @@ stackit network-area [flags] * [stackit network-area describe](./stackit_network-area_describe.md) - Shows details of a STACKIT Network Area * [stackit network-area list](./stackit_network-area_list.md) - Lists all STACKIT Network Areas (SNA) of an organization * [stackit network-area network-range](./stackit_network-area_network-range.md) - Provides functionality for network ranges in STACKIT Network Areas +* [stackit network-area region](./stackit_network-area_region.md) - Provides functionality for regional configuration of STACKIT Network Area (SNA) * [stackit network-area route](./stackit_network-area_route.md) - Provides functionality for static routes in STACKIT Network Areas * [stackit network-area update](./stackit_network-area_update.md) - Updates a STACKIT Network Area (SNA) diff --git a/docs/stackit_network-area_create.md b/docs/stackit_network-area_create.md index 7dc278927..e9a28231d 100644 --- a/docs/stackit_network-area_create.md +++ b/docs/stackit_network-area_create.md @@ -13,32 +13,20 @@ stackit network-area create [flags] ### Examples ``` - Create a network area with name "network-area-1" in organization with ID "xxx" with network ranges and a transfer network - $ stackit network-area create --name network-area-1 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" + Create a network area with name "network-area-1" in organization with ID "xxx" + $ stackit network-area create --name network-area-1 --organization-id xxx" - Create a network area with name "network-area-2" in organization with ID "xxx" with network ranges, transfer network and DNS name server - $ stackit network-area create --name network-area-2 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" --dns-name-servers "1.1.1.1" - - Create a network area with name "network-area-3" in organization with ID "xxx" with network ranges, transfer network and additional options - $ stackit network-area create --name network-area-3 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" --default-prefix-length 25 --max-prefix-length 29 --min-prefix-length 24 - - Create a network area with name "network-area-1" in organization with ID "xxx" with network ranges and a transfer network and labels "key=value,key1=value1" - $ stackit network-area create --name network-area-1 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" --labels key=value,key1=value1 + Create a network area with name "network-area-1" in organization with ID "xxx" with labels "key=value,key1=value1" + $ stackit network-area create --name network-area-1 --organization-id xxx --labels key=value,key1=value1 ``` ### Options ``` - --default-prefix-length int The default prefix length for networks in the network area - --dns-name-servers strings List of DNS name server IPs - -h, --help Help for "stackit network-area create" - --labels stringToString Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...' (default []) - --max-prefix-length int The maximum prefix length for networks in the network area - --min-prefix-length int The minimum prefix length for networks in the network area - -n, --name string Network area name - --network-ranges strings List of network ranges (default []) - --organization-id string Organization ID - --transfer-network string Transfer network in CIDR notation + -h, --help Help for "stackit network-area create" + --labels stringToString Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...' (default []) + -n, --name string Network area name + --organization-id string Organization ID ``` ### Options inherited from parent commands diff --git a/docs/stackit_network-area_region.md b/docs/stackit_network-area_region.md new file mode 100644 index 000000000..07fd820eb --- /dev/null +++ b/docs/stackit_network-area_region.md @@ -0,0 +1,38 @@ +## stackit network-area region + +Provides functionality for regional configuration of STACKIT Network Area (SNA) + +### Synopsis + +Provides functionality for regional configuration of STACKIT Network Area (SNA). + +``` +stackit network-area region [flags] +``` + +### Options + +``` + -h, --help Help for "stackit network-area region" +``` + +### Options inherited from parent commands + +``` + -y, --assume-yes If set, skips all confirmation prompts + --async If set, runs the command asynchronously + -o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"] + -p, --project-id string Project ID + --region string Target region for region-specific requests + --verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info") +``` + +### SEE ALSO + +* [stackit network-area](./stackit_network-area.md) - Provides functionality for STACKIT Network Area (SNA) +* [stackit network-area region create](./stackit_network-area_region_create.md) - Creates a new regional configuration for a STACKIT Network Area (SNA) +* [stackit network-area region delete](./stackit_network-area_region_delete.md) - Deletes a regional configuration for a STACKIT Network Area (SNA) +* [stackit network-area region describe](./stackit_network-area_region_describe.md) - Describes a regional configuration for a STACKIT Network Area (SNA) +* [stackit network-area region list](./stackit_network-area_region_list.md) - Lists all configured regions for a STACKIT Network Area (SNA) +* [stackit network-area region update](./stackit_network-area_region_update.md) - Updates a existing regional configuration for a STACKIT Network Area (SNA) + diff --git a/docs/stackit_network-area_region_create.md b/docs/stackit_network-area_region_create.md new file mode 100644 index 000000000..55632632f --- /dev/null +++ b/docs/stackit_network-area_region_create.md @@ -0,0 +1,58 @@ +## stackit network-area region create + +Creates a new regional configuration for a STACKIT Network Area (SNA) + +### Synopsis + +Creates a new regional configuration for a STACKIT Network Area (SNA). + +``` +stackit network-area region create [flags] +``` + +### Examples + +``` + Create a new regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24" and ipv4 transfer network "192.168.1.0/24" + $ stackit network-area region create --network-area-id xxx --region eu02 --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 + + Create a new regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", using the set region config + $ stackit config set --region eu02 + $ stackit network-area region create --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 + + Create a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20" + $ stackit network-area region create --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20 + + Create a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20" + $ stackit network-area region create --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20 +``` + +### Options + +``` + -h, --help Help for "stackit network-area region create" + --ipv4-default-nameservers strings List of default DNS name server IPs + --ipv4-default-prefix-length int The default prefix length for networks in the network area + --ipv4-max-prefix-length int The maximum prefix length for networks in the network area + --ipv4-min-prefix-length int The minimum prefix length for networks in the network area + --ipv4-network-ranges strings Network range to create in CIDR notation (default []) + --ipv4-transfer-network string Transfer network in CIDR notation + --network-area-id string STACKIT Network Area (SNA) ID + --organization-id string Organization ID +``` + +### Options inherited from parent commands + +``` + -y, --assume-yes If set, skips all confirmation prompts + --async If set, runs the command asynchronously + -o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"] + -p, --project-id string Project ID + --region string Target region for region-specific requests + --verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info") +``` + +### SEE ALSO + +* [stackit network-area region](./stackit_network-area_region.md) - Provides functionality for regional configuration of STACKIT Network Area (SNA) + diff --git a/docs/stackit_network-area_region_delete.md b/docs/stackit_network-area_region_delete.md new file mode 100644 index 000000000..6f2193e5e --- /dev/null +++ b/docs/stackit_network-area_region_delete.md @@ -0,0 +1,46 @@ +## stackit network-area region delete + +Deletes a regional configuration for a STACKIT Network Area (SNA) + +### Synopsis + +Deletes a regional configuration for a STACKIT Network Area (SNA). + +``` +stackit network-area region delete [flags] +``` + +### Examples + +``` + Delete a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" + $ stackit network-area region delete --network-area-id xxx --region eu02 --organization-id yyy + + Delete a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", using the set region config + $ stackit config set --region eu02 + $ stackit network-area region delete --network-area-id xxx --organization-id yyy +``` + +### Options + +``` + -h, --help Help for "stackit network-area region delete" + --network-area-id string STACKIT Network Area (SNA) ID + --organization-id string Organization ID +``` + +### Options inherited from parent commands + +``` + -y, --assume-yes If set, skips all confirmation prompts + --async If set, runs the command asynchronously + -o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"] + -p, --project-id string Project ID + --region string Target region for region-specific requests + --verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info") +``` + +### SEE ALSO + +* [stackit network-area region](./stackit_network-area_region.md) - Provides functionality for regional configuration of STACKIT Network Area (SNA) + diff --git a/docs/stackit_network-area_region_describe.md b/docs/stackit_network-area_region_describe.md new file mode 100644 index 000000000..e97ee813a --- /dev/null +++ b/docs/stackit_network-area_region_describe.md @@ -0,0 +1,46 @@ +## stackit network-area region describe + +Describes a regional configuration for a STACKIT Network Area (SNA) + +### Synopsis + +Describes a regional configuration for a STACKIT Network Area (SNA). + +``` +stackit network-area region describe [flags] +``` + +### Examples + +``` + Describe a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" + $ stackit network-area region describe --network-area-id xxx --region eu02 --organization-id yyy + + Describe a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", using the set region config + $ stackit config set --region eu02 + $ stackit network-area region describe --network-area-id xxx --organization-id yyy +``` + +### Options + +``` + -h, --help Help for "stackit network-area region describe" + --network-area-id string STACKIT Network Area (SNA) ID + --organization-id string Organization ID +``` + +### Options inherited from parent commands + +``` + -y, --assume-yes If set, skips all confirmation prompts + --async If set, runs the command asynchronously + -o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"] + -p, --project-id string Project ID + --region string Target region for region-specific requests + --verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info") +``` + +### SEE ALSO + +* [stackit network-area region](./stackit_network-area_region.md) - Provides functionality for regional configuration of STACKIT Network Area (SNA) + diff --git a/docs/stackit_network-area_region_list.md b/docs/stackit_network-area_region_list.md new file mode 100644 index 000000000..2b6eaf673 --- /dev/null +++ b/docs/stackit_network-area_region_list.md @@ -0,0 +1,42 @@ +## stackit network-area region list + +Lists all configured regions for a STACKIT Network Area (SNA) + +### Synopsis + +Lists all configured regions for a STACKIT Network Area (SNA). + +``` +stackit network-area region list [flags] +``` + +### Examples + +``` + List all configured region for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" + $ stackit network-area region list --network-area-id xxx --organization-id yyy +``` + +### Options + +``` + -h, --help Help for "stackit network-area region list" + --network-area-id string STACKIT Network Area (SNA) ID + --organization-id string Organization ID +``` + +### Options inherited from parent commands + +``` + -y, --assume-yes If set, skips all confirmation prompts + --async If set, runs the command asynchronously + -o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"] + -p, --project-id string Project ID + --region string Target region for region-specific requests + --verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info") +``` + +### SEE ALSO + +* [stackit network-area region](./stackit_network-area_region.md) - Provides functionality for regional configuration of STACKIT Network Area (SNA) + diff --git a/docs/stackit_network-area_region_update.md b/docs/stackit_network-area_region_update.md new file mode 100644 index 000000000..400d85bc7 --- /dev/null +++ b/docs/stackit_network-area_region_update.md @@ -0,0 +1,56 @@ +## stackit network-area region update + +Updates a existing regional configuration for a STACKIT Network Area (SNA) + +### Synopsis + +Updates a existing regional configuration for a STACKIT Network Area (SNA). + +``` +stackit network-area region update [flags] +``` + +### Examples + +``` + Update a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" with new ipv4-default-nameservers "8.8.8.8" + $ stackit network-area region update --network-area-id xxx --region eu02 --organization-id yyy --ipv4-default-nameservers 8.8.8.8 + + Update a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" with new ipv4-default-nameservers "8.8.8.8", using the set region config + $ stackit config set --region eu02 + $ stackit network-area region update --network-area-id xxx --organization-id yyy --ipv4-default-nameservers 8.8.8.8 + + Update a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20" + $ stackit network-area region update --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20 + + Update a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20" + $ stackit network-area region update --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20 +``` + +### Options + +``` + -h, --help Help for "stackit network-area region update" + --ipv4-default-nameservers strings List of default DNS name server IPs + --ipv4-default-prefix-length int The default prefix length for networks in the network area + --ipv4-max-prefix-length int The maximum prefix length for networks in the network area + --ipv4-min-prefix-length int The minimum prefix length for networks in the network area + --network-area-id string STACKIT Network Area (SNA) ID + --organization-id string Organization ID +``` + +### Options inherited from parent commands + +``` + -y, --assume-yes If set, skips all confirmation prompts + --async If set, runs the command asynchronously + -o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"] + -p, --project-id string Project ID + --region string Target region for region-specific requests + --verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info") +``` + +### SEE ALSO + +* [stackit network-area region](./stackit_network-area_region.md) - Provides functionality for regional configuration of STACKIT Network Area (SNA) + diff --git a/docs/stackit_network-area_route_create.md b/docs/stackit_network-area_route_create.md index 79d239fee..ff697f896 100644 --- a/docs/stackit_network-area_route_create.md +++ b/docs/stackit_network-area_route_create.md @@ -15,22 +15,25 @@ stackit network-area route create [flags] ### Examples ``` - Create a static route with prefix "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy" - $ stackit network-area route create --organization-id yyy --network-area-id xxx --prefix 1.1.1.0/24 --next-hop 1.1.1.1 + Create a static route with destination "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy" + $ stackit network-area route create --organization-id yyy --network-area-id xxx --destination 1.1.1.0/24 --next-hop 1.1.1.1 - Create a static route with labels "key:value" and "foo:bar" with prefix "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy" - $ stackit network-area route create --labels key=value,foo=bar --organization-id yyy --network-area-id xxx --prefix 1.1.1.0/24 --next-hop 1.1.1.1 + Create a static route with labels "key:value" and "foo:bar" with destination "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy" + $ stackit network-area route create --labels key=value,foo=bar --organization-id yyy --network-area-id xxx --destination 1.1.1.0/24 --next-hop 1.1.1.1 ``` ### Options ``` + --destination string Destination route. Must be a valid IPv4 or IPv6 CIDR -h, --help Help for "stackit network-area route create" --labels stringToString Labels are key-value string pairs which can be attached to a route. A label can be provided with the format key=value and the flag can be used multiple times to provide a list of labels (default []) --network-area-id string STACKIT Network Area ID - --next-hop string Next hop IP address. Must be a valid IPv4 + --next-hop-ipv4 string Next hop IPv4 address + --next-hop-ipv6 string Next hop IPv6 address + --nexthop-blackhole Sets next hop to black hole + --nexthop-internet Sets next hop to internet --organization-id string Organization ID - --prefix string Static route prefix ``` ### Options inherited from parent commands diff --git a/docs/stackit_network-area_update.md b/docs/stackit_network-area_update.md index 57b32a662..77665f0e8 100644 --- a/docs/stackit_network-area_update.md +++ b/docs/stackit_network-area_update.md @@ -20,14 +20,10 @@ stackit network-area update AREA_ID [flags] ### Options ``` - --default-prefix-length int The default prefix length for networks in the network area - --dns-name-servers strings List of DNS name server IPs - -h, --help Help for "stackit network-area update" - --labels stringToString Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...' (default []) - --max-prefix-length int The maximum prefix length for networks in the network area - --min-prefix-length int The minimum prefix length for networks in the network area - -n, --name string Network area name - --organization-id string Organization ID + -h, --help Help for "stackit network-area update" + --labels stringToString Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...' (default []) + -n, --name string Network area name + --organization-id string Organization ID ``` ### Options inherited from parent commands diff --git a/docs/stackit_network_create.md b/docs/stackit_network_create.md index 21d9e863c..146264977 100644 --- a/docs/stackit_network_create.md +++ b/docs/stackit_network_create.md @@ -26,7 +26,7 @@ stackit network create [flags] $ stackit network create --name network-1 --labels key=value,key1=value1 Create an IPv4 network with name "network-1" with DNS name servers, a prefix and a gateway - $ stackit network create --name network-1 --ipv4-dns-name-servers "1.1.1.1,8.8.8.8,9.9.9.9" --ipv4-prefix "10.1.2.0/24" --ipv4-gateway "10.1.2.3" + $ stackit network create --name network-1 --non-routed --ipv4-dns-name-servers "1.1.1.1,8.8.8.8,9.9.9.9" --ipv4-prefix "10.1.2.0/24" --ipv4-gateway "10.1.2.3" Create an IPv6 network with name "network-1" with DNS name servers, a prefix and a gateway $ stackit network create --name network-1 --ipv6-dns-name-servers "2001:4860:4860::8888,2001:4860:4860::8844" --ipv6-prefix "2001:4860:4860::8888" --ipv6-gateway "2001:4860:4860::8888" diff --git a/go.mod b/go.mod index 6eff66cae..1d4e8ac4f 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/stackitcloud/stackit-sdk-go/services/authorization v0.9.0 github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1 github.com/stackitcloud/stackit-sdk-go/services/git v0.9.0 - github.com/stackitcloud/stackit-sdk-go/services/iaas v0.31.0 + github.com/stackitcloud/stackit-sdk-go/services/iaas v1.0.0 github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v1.5.2 github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.24.1 github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.2.1 diff --git a/go.sum b/go.sum index b9e0a5002..850d60dfe 100644 --- a/go.sum +++ b/go.sum @@ -571,8 +571,8 @@ github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1 h1:CnhAMLql0MNmAeq4r github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1/go.mod h1:7Bx85knfNSBxulPdJUFuBePXNee3cO+sOTYnUG6M+iQ= github.com/stackitcloud/stackit-sdk-go/services/git v0.9.0 h1:zuoJnsLnjxdQcQbs7gUXYzrN0Ip5NXj+6LFBp1EO6cg= github.com/stackitcloud/stackit-sdk-go/services/git v0.9.0/go.mod h1:AXFfYBJZIW1o0W0zZEb/proQMhMsb3Nn5E1htS8NDPE= -github.com/stackitcloud/stackit-sdk-go/services/iaas v0.31.0 h1:dnEjyapuv8WwRN5vE2z6+4/+ZqQTBx+bX27x2nOF7Jw= -github.com/stackitcloud/stackit-sdk-go/services/iaas v0.31.0/go.mod h1:854gnLR92NvAbJAA1xZEumrtNh1DoBP1FXTMvhwYA6w= +github.com/stackitcloud/stackit-sdk-go/services/iaas v1.0.0 h1:qLMpd5whPMLnaLEdFQjK51q/o9V6eMFMORBDSsyGyNI= +github.com/stackitcloud/stackit-sdk-go/services/iaas v1.0.0/go.mod h1:854gnLR92NvAbJAA1xZEumrtNh1DoBP1FXTMvhwYA6w= github.com/stackitcloud/stackit-sdk-go/services/kms v1.0.0 h1:zxoOv7Fu+FmdsvTKiKkbmLItrMKfL+QoVtz9ReEF30E= github.com/stackitcloud/stackit-sdk-go/services/kms v1.0.0/go.mod h1:KEPVoO21pC4bjy5l0nyhjUJ0+uVwVWb+k2TYrzJ8xYw= github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.6.0 h1:q33ZaCBVEBUsnMDxYyuJKtJvGcE5nKgvuPed3s8zXNI= diff --git a/internal/cmd/affinity-groups/create/create.go b/internal/cmd/affinity-groups/create/create.go index 89e7659bb..311115644 100644 --- a/internal/cmd/affinity-groups/create/create.go +++ b/internal/cmd/affinity-groups/create/create.go @@ -88,7 +88,7 @@ func configureFlags(cmd *cobra.Command) { } func buildRequest(ctx context.Context, model inputModel, apiClient *iaas.APIClient) iaas.ApiCreateAffinityGroupRequest { - req := apiClient.CreateAffinityGroup(ctx, model.ProjectId) + req := apiClient.CreateAffinityGroup(ctx, model.ProjectId, model.Region) req = req.CreateAffinityGroupPayload( iaas.CreateAffinityGroupPayload{ Name: utils.Ptr(model.Name), diff --git a/internal/cmd/affinity-groups/create/create_test.go b/internal/cmd/affinity-groups/create/create_test.go index ba70232d0..6876da538 100644 --- a/internal/cmd/affinity-groups/create/create_test.go +++ b/internal/cmd/affinity-groups/create/create_test.go @@ -15,7 +15,11 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -const projectIdFlag = globalflags.ProjectIdFlag +const ( + testName = "test-name" + testPolicy = "test-policy" + testRegion = "eu01" +) type testCtxKey struct{} @@ -25,14 +29,10 @@ var ( testProjectId = uuid.NewString() ) -const ( - testName = "test-name" - testPolicy = "test-policy" -) - func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, nameFlag: testName, policyFlag: testPolicy, @@ -48,6 +48,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Name: testName, Policy: testPolicy, @@ -59,7 +60,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateAffinityGroupRequest)) iaas.ApiCreateAffinityGroupRequest { - request := testClient.CreateAffinityGroup(testCtx, testProjectId) + request := testClient.CreateAffinityGroup(testCtx, testProjectId, testRegion) request = request.CreateAffinityGroupPayload(fixturePayload()) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/affinity-groups/delete/delete.go b/internal/cmd/affinity-groups/delete/delete.go index 59532f96d..fdfb68c1a 100644 --- a/internal/cmd/affinity-groups/delete/delete.go +++ b/internal/cmd/affinity-groups/delete/delete.go @@ -58,7 +58,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - affinityGroupLabel, err := iaasUtils.GetAffinityGroupName(ctx, apiClient, model.ProjectId, model.AffinityGroupId) + affinityGroupLabel, err := iaasUtils.GetAffinityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.AffinityGroupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get affinity group name: %v", err) affinityGroupLabel = model.AffinityGroupId @@ -87,7 +87,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } func buildRequest(ctx context.Context, model inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteAffinityGroupRequest { - return apiClient.DeleteAffinityGroup(ctx, model.ProjectId, model.AffinityGroupId) + return apiClient.DeleteAffinityGroup(ctx, model.ProjectId, model.Region, model.AffinityGroupId) } func parseInput(p *print.Printer, cmd *cobra.Command, cliArgs []string) (*inputModel, error) { diff --git a/internal/cmd/affinity-groups/delete/delete_test.go b/internal/cmd/affinity-groups/delete/delete_test.go index e3df49cbb..d66437d2f 100644 --- a/internal/cmd/affinity-groups/delete/delete_test.go +++ b/internal/cmd/affinity-groups/delete/delete_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -const projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +39,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -50,6 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, AffinityGroupId: testAffinityGroupId, } @@ -60,7 +64,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteAffinityGroupRequest)) iaas.ApiDeleteAffinityGroupRequest { - request := testClient.DeleteAffinityGroup(testCtx, testProjectId, testAffinityGroupId) + request := testClient.DeleteAffinityGroup(testCtx, testProjectId, testRegion, testAffinityGroupId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/affinity-groups/describe/describe.go b/internal/cmd/affinity-groups/describe/describe.go index 7af292d74..5510a439d 100644 --- a/internal/cmd/affinity-groups/describe/describe.go +++ b/internal/cmd/affinity-groups/describe/describe.go @@ -68,7 +68,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } func buildRequest(ctx context.Context, model inputModel, apiClient *iaas.APIClient) iaas.ApiGetAffinityGroupRequest { - return apiClient.GetAffinityGroup(ctx, model.ProjectId, model.AffinityGroupId) + return apiClient.GetAffinityGroup(ctx, model.ProjectId, model.Region, model.AffinityGroupId) } func parseInput(p *print.Printer, cmd *cobra.Command, cliArgs []string) (*inputModel, error) { diff --git a/internal/cmd/affinity-groups/describe/describe_test.go b/internal/cmd/affinity-groups/describe/describe_test.go index 530319c96..01c0d3eac 100644 --- a/internal/cmd/affinity-groups/describe/describe_test.go +++ b/internal/cmd/affinity-groups/describe/describe_test.go @@ -13,12 +13,14 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -const projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} var ( - testCtx = context.WithValue(context.Background(), &testCtxKey{}, projectIdFlag) + testCtx = context.WithValue(context.Background(), &testCtxKey{}, "test") testClient = &iaas.APIClient{} testProjectId = uuid.NewString() @@ -37,7 +39,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -50,6 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, AffinityGroupId: testAffinityGroupId, } @@ -60,7 +64,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetAffinityGroupRequest)) iaas.ApiGetAffinityGroupRequest { - request := testClient.GetAffinityGroup(testCtx, testProjectId, testAffinityGroupId) + request := testClient.GetAffinityGroup(testCtx, testProjectId, testRegion, testAffinityGroupId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/affinity-groups/list/list.go b/internal/cmd/affinity-groups/list/list.go index 75d0e667e..3752106e0 100644 --- a/internal/cmd/affinity-groups/list/list.go +++ b/internal/cmd/affinity-groups/list/list.go @@ -82,7 +82,7 @@ func configureFlags(cmd *cobra.Command) { } func buildRequest(ctx context.Context, model inputModel, apiClient *iaas.APIClient) iaas.ApiListAffinityGroupsRequest { - return apiClient.ListAffinityGroups(ctx, model.ProjectId) + return apiClient.ListAffinityGroups(ctx, model.ProjectId, model.Region) } func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { diff --git a/internal/cmd/affinity-groups/list/list_test.go b/internal/cmd/affinity-groups/list/list_test.go index 23c643f1b..5c792a299 100644 --- a/internal/cmd/affinity-groups/list/list_test.go +++ b/internal/cmd/affinity-groups/list/list_test.go @@ -16,7 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -const projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" + testLimit = 10 +) type testCtxKey struct{} @@ -26,13 +29,10 @@ var ( testProjectId = uuid.NewString() ) -const ( - testLimit = 10 -) - func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -45,6 +45,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, } for _, mod := range mods { @@ -54,7 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListAffinityGroupsRequest)) iaas.ApiListAffinityGroupsRequest { - request := testClient.ListAffinityGroups(testCtx, testProjectId) + request := testClient.ListAffinityGroups(testCtx, testProjectId, testRegion) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/image/create/create.go b/internal/cmd/image/create/create.go index 9ad653d18..06a270b11 100644 --- a/internal/cmd/image/create/create.go +++ b/internal/cmd/image/create/create.go @@ -332,7 +332,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateImageRequest { - request := apiClient.CreateImage(ctx, model.ProjectId). + request := apiClient.CreateImage(ctx, model.ProjectId, model.Region). CreateImagePayload(createPayload(ctx, model)) return request } diff --git a/internal/cmd/image/create/create_test.go b/internal/cmd/image/create/create_test.go index 545586502..2b28c7676 100644 --- a/internal/cmd/image/create/create_test.go +++ b/internal/cmd/image/create/create_test.go @@ -17,15 +17,8 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag - -type testCtxKey struct{} - -var ( - testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") - testClient = &iaas.APIClient{} - testProjectId = uuid.NewString() - +const ( + testRegion = "eu01" testLocalImagePath = "/does/not/exist" testDiskFormat = "raw" testDiskSize int64 = 16 * 1024 * 1024 * 1024 @@ -49,9 +42,18 @@ var ( testLabels = "foo=FOO,bar=BAR,baz=BAZ" ) +type testCtxKey struct{} + +var ( + testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") + testClient = &iaas.APIClient{} + testProjectId = uuid.NewString() +) + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, nameFlag: testName, diskFormatFlag: testDiskFormat, @@ -93,30 +95,34 @@ func parseLabels(labelstring string) map[string]string { func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - Name: testName, - DiskFormat: testDiskFormat, - LocalFilePath: testLocalImagePath, - Labels: utils.Ptr(parseLabels(testLabels)), + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Verbosity: globalflags.VerbosityDefault, + Region: testRegion, + }, + Name: testName, + DiskFormat: testDiskFormat, + LocalFilePath: testLocalImagePath, + Labels: utils.Ptr(parseLabels(testLabels)), Config: &imageConfig{ - Architecture: &testArchitecture, - BootMenu: &testBootmenu, - CdromBus: &testCdRomBus, - DiskBus: &testDiskBus, - NicModel: &testNicModel, - OperatingSystem: &testOperatingSystem, - OperatingSystemDistro: &testOperatingSystemDistro, - OperatingSystemVersion: &testOperatingSystemVersion, - RescueBus: &testRescueBus, - RescueDevice: &testRescueDevice, - SecureBoot: &testSecureBoot, + Architecture: utils.Ptr(testArchitecture), + BootMenu: utils.Ptr(testBootmenu), + CdromBus: utils.Ptr(testCdRomBus), + DiskBus: utils.Ptr(testDiskBus), + NicModel: utils.Ptr(testNicModel), + OperatingSystem: utils.Ptr(testOperatingSystem), + OperatingSystemDistro: utils.Ptr(testOperatingSystemDistro), + OperatingSystemVersion: utils.Ptr(testOperatingSystemVersion), + RescueBus: utils.Ptr(testRescueBus), + RescueDevice: utils.Ptr(testRescueDevice), + SecureBoot: utils.Ptr(testSecureBoot), Uefi: testUefi, - VideoModel: &testVideoModel, - VirtioScsi: &testVirtioScsi, + VideoModel: utils.Ptr(testVideoModel), + VirtioScsi: utils.Ptr(testVirtioScsi), }, - MinDiskSize: &testDiskSize, - MinRam: &testRamSize, - Protected: &testProtected, + MinDiskSize: utils.Ptr(testDiskSize), + MinRam: utils.Ptr(testRamSize), + Protected: utils.Ptr(testProtected), } for _, mod := range mods { mod(model) @@ -127,31 +133,31 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { func fixtureCreatePayload(mods ...func(payload *iaas.CreateImagePayload)) (payload iaas.CreateImagePayload) { payload = iaas.CreateImagePayload{ Config: &iaas.ImageConfig{ - Architecture: &testArchitecture, - BootMenu: &testBootmenu, - CdromBus: iaas.NewNullableString(&testCdRomBus), - DiskBus: iaas.NewNullableString(&testDiskBus), - NicModel: iaas.NewNullableString(&testNicModel), - OperatingSystem: &testOperatingSystem, - OperatingSystemDistro: iaas.NewNullableString(&testOperatingSystemDistro), - OperatingSystemVersion: iaas.NewNullableString(&testOperatingSystemVersion), - RescueBus: iaas.NewNullableString(&testRescueBus), - RescueDevice: iaas.NewNullableString(&testRescueDevice), - SecureBoot: &testSecureBoot, - Uefi: &testUefi, - VideoModel: iaas.NewNullableString(&testVideoModel), - VirtioScsi: &testVirtioScsi, + Architecture: utils.Ptr(testArchitecture), + BootMenu: utils.Ptr(testBootmenu), + CdromBus: iaas.NewNullableString(utils.Ptr(testCdRomBus)), + DiskBus: iaas.NewNullableString(utils.Ptr(testDiskBus)), + NicModel: iaas.NewNullableString(utils.Ptr(testNicModel)), + OperatingSystem: utils.Ptr(testOperatingSystem), + OperatingSystemDistro: iaas.NewNullableString(utils.Ptr(testOperatingSystemDistro)), + OperatingSystemVersion: iaas.NewNullableString(utils.Ptr(testOperatingSystemVersion)), + RescueBus: iaas.NewNullableString(utils.Ptr(testRescueBus)), + RescueDevice: iaas.NewNullableString(utils.Ptr(testRescueDevice)), + SecureBoot: utils.Ptr(testSecureBoot), + Uefi: utils.Ptr(testUefi), + VideoModel: iaas.NewNullableString(utils.Ptr(testVideoModel)), + VirtioScsi: utils.Ptr(testVirtioScsi), }, - DiskFormat: &testDiskFormat, + DiskFormat: utils.Ptr(testDiskFormat), Labels: &map[string]interface{}{ "foo": "FOO", "bar": "BAR", "baz": "BAZ", }, - MinDiskSize: &testDiskSize, - MinRam: &testRamSize, - Name: &testName, - Protected: &testProtected, + MinDiskSize: utils.Ptr(testDiskSize), + MinRam: utils.Ptr(testRamSize), + Name: utils.Ptr(testName), + Protected: utils.Ptr(testProtected), } for _, mod := range mods { mod(&payload) @@ -160,7 +166,7 @@ func fixtureCreatePayload(mods ...func(payload *iaas.CreateImagePayload)) (paylo } func fixtureRequest(mods ...func(request *iaas.ApiCreateImageRequest)) iaas.ApiCreateImageRequest { - request := testClient.CreateImage(testCtx, testProjectId) + request := testClient.CreateImage(testCtx, testProjectId, testRegion) request = request.CreateImagePayload(fixtureCreatePayload()) @@ -192,21 +198,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/image/delete/delete.go b/internal/cmd/image/delete/delete.go index 80f7f2dc8..d394c0bfd 100644 --- a/internal/cmd/image/delete/delete.go +++ b/internal/cmd/image/delete/delete.go @@ -53,7 +53,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - imageName, err := iaasUtils.GetImageName(ctx, apiClient, model.ProjectId, model.ImageId) + imageName, err := iaasUtils.GetImageName(ctx, apiClient, model.ProjectId, model.Region, model.ImageId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get image name: %v", err) imageName = model.ImageId @@ -98,6 +98,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, cliArgs []string) (*inputM } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteImageRequest { - request := apiClient.DeleteImage(ctx, model.ProjectId, model.ImageId) + request := apiClient.DeleteImage(ctx, model.ProjectId, model.Region, model.ImageId) return request } diff --git a/internal/cmd/image/delete/delete_test.go b/internal/cmd/image/delete/delete_test.go index 2b4f74c1e..cd1179f41 100644 --- a/internal/cmd/image/delete/delete_test.go +++ b/internal/cmd/image/delete/delete_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,8 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -37,8 +40,12 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - ImageId: testImageId, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Verbosity: globalflags.VerbosityDefault, + Region: testRegion, + }, + ImageId: testImageId, } for _, mod := range mods { mod(model) @@ -47,7 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteImageRequest)) iaas.ApiDeleteImageRequest { - request := testClient.DeleteImage(testCtx, testProjectId, testImageId) + request := testClient.DeleteImage(testCtx, testProjectId, testRegion, testImageId) for _, mod := range mods { mod(&request) } @@ -73,14 +80,14 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/image/describe/describe.go b/internal/cmd/image/describe/describe.go index b6d81e06d..516fa9c99 100644 --- a/internal/cmd/image/describe/describe.go +++ b/internal/cmd/image/describe/describe.go @@ -67,7 +67,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetImageRequest { - request := apiClient.GetImage(ctx, model.ProjectId, model.ImageId) + request := apiClient.GetImage(ctx, model.ProjectId, model.Region, model.ImageId) return request } diff --git a/internal/cmd/image/describe/describe_test.go b/internal/cmd/image/describe/describe_test.go index 076010d69..6a76a3200 100644 --- a/internal/cmd/image/describe/describe_test.go +++ b/internal/cmd/image/describe/describe_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,8 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -37,8 +40,12 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - ImageId: testImageId[0], + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Verbosity: globalflags.VerbosityDefault, + Region: testRegion, + }, + ImageId: testImageId[0], } for _, mod := range mods { mod(model) @@ -47,7 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetImageRequest)) iaas.ApiGetImageRequest { - request := testClient.GetImage(testCtx, testProjectId, testImageId[0]) + request := testClient.GetImage(testCtx, testProjectId, testRegion, testImageId[0]) for _, mod := range mods { mod(&request) } @@ -79,7 +86,7 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), args: testImageId, isValid: false, @@ -87,7 +94,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), args: testImageId, isValid: false, @@ -95,7 +102,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), args: testImageId, isValid: false, diff --git a/internal/cmd/image/list/list.go b/internal/cmd/image/list/list.go index a0949187f..0ebdf9e95 100644 --- a/internal/cmd/image/list/list.go +++ b/internal/cmd/image/list/list.go @@ -128,7 +128,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListImagesRequest { - request := apiClient.ListImages(ctx, model.ProjectId) + request := apiClient.ListImages(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { request = request.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/image/list/list_test.go b/internal/cmd/image/list/list_test.go index bdfc4c6ed..6dbdb119f 100644 --- a/internal/cmd/image/list/list_test.go +++ b/internal/cmd/image/list/list_test.go @@ -17,7 +17,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -31,7 +33,9 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + labelSelectorFlag: testLabels, limitFlag: strconv.Itoa(int(testLimit)), } @@ -43,9 +47,13 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - LabelSelector: utils.Ptr(testLabels), - Limit: &testLimit, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Verbosity: globalflags.VerbosityDefault, + Region: testRegion, + }, + LabelSelector: utils.Ptr(testLabels), + Limit: &testLimit, } for _, mod := range mods { mod(model) @@ -54,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListImagesRequest)) iaas.ApiListImagesRequest { - request := testClient.ListImages(testCtx, testProjectId) + request := testClient.ListImages(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabels) for _, mod := range mods { mod(&request) @@ -84,21 +92,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/image/update/update.go b/internal/cmd/image/update/update.go index 434fc0ea8..799b594b6 100644 --- a/internal/cmd/image/update/update.go +++ b/internal/cmd/image/update/update.go @@ -132,7 +132,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - imageLabel, err := iaasUtils.GetImageName(ctx, apiClient, model.ProjectId, model.Id) + imageLabel, err := iaasUtils.GetImageName(ctx, apiClient, model.ProjectId, model.Region, model.Id) if err != nil { params.Printer.Debug(print.WarningLevel, "cannot retrieve image name: %v", err) imageLabel = model.Id @@ -238,7 +238,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, cliArgs []string) (*inputM } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateImageRequest { - request := apiClient.UpdateImage(ctx, model.ProjectId, model.Id) + request := apiClient.UpdateImage(ctx, model.ProjectId, model.Region, model.Id) payload := iaas.NewUpdateImagePayload() // Config *ImageConfig `json:"config,omitempty"` diff --git a/internal/cmd/image/update/update_test.go b/internal/cmd/image/update/update_test.go index a40748f3b..9df1cf99e 100644 --- a/internal/cmd/image/update/update_test.go +++ b/internal/cmd/image/update/update_test.go @@ -17,7 +17,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -50,7 +52,8 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, nameFlag: testName, diskFormatFlag: testDiskFormat, @@ -90,11 +93,15 @@ func parseLabels(labelstring string) map[string]string { func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - Id: testImageId[0], - Name: &testName, - DiskFormat: &testDiskFormat, - Labels: utils.Ptr(parseLabels(testLabels)), + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Verbosity: globalflags.VerbosityDefault, + Region: testRegion, + }, + Id: testImageId[0], + Name: &testName, + DiskFormat: &testDiskFormat, + Labels: utils.Ptr(parseLabels(testLabels)), Config: &imageConfig{ BootMenu: &testBootmenu, CdromBus: &testCdRomBus, @@ -155,7 +162,7 @@ func fixtureCreatePayload(mods ...func(payload *iaas.UpdateImagePayload)) (paylo } func fixtureRequest(mods ...func(*iaas.ApiUpdateImageRequest)) iaas.ApiUpdateImageRequest { - request := testClient.UpdateImage(testCtx, testProjectId, testImageId[0]) + request := testClient.UpdateImage(testCtx, testProjectId, testRegion, testImageId[0]) request = request.UpdateImagePayload(fixtureCreatePayload()) @@ -184,7 +191,7 @@ func TestParseInput(t *testing.T) { { description: "no values but valid image id", flagValues: map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, }, args: testImageId, isValid: false, @@ -196,7 +203,7 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), args: testImageId, isValid: false, @@ -204,7 +211,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), args: testImageId, isValid: false, @@ -212,7 +219,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), args: testImageId, isValid: false, @@ -302,8 +309,8 @@ func TestParseInput(t *testing.T) { { description: "update only name", flagValues: map[string]string{ - projectIdFlag: testProjectId, - nameFlag: "foo", + globalflags.ProjectIdFlag: testProjectId, + nameFlag: "foo", }, args: testImageId, isValid: true, diff --git a/internal/cmd/network-area/create/create.go b/internal/cmd/network-area/create/create.go index fa97908d9..7268d0a2d 100644 --- a/internal/cmd/network-area/create/create.go +++ b/internal/cmd/network-area/create/create.go @@ -3,9 +3,12 @@ package create import ( "context" "fmt" + "os" + "strings" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" + cliErr "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" @@ -13,35 +16,58 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" rmClient "github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/client" rmUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" + "github.com/stackitcloud/stackit-sdk-go/services/iaas/wait" "github.com/spf13/cobra" ) const ( - nameFlag = "name" - organizationIdFlag = "organization-id" - dnsNameServersFlag = "dns-name-servers" - networkRangesFlag = "network-ranges" - transferNetworkFlag = "transfer-network" + nameFlag = "name" + organizationIdFlag = "organization-id" + // Deprecated: dnsNameServersFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + dnsNameServersFlag = "dns-name-servers" + // Deprecated: networkRangesFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + networkRangesFlag = "network-ranges" + // Deprecated: transferNetworkFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + transferNetworkFlag = "transfer-network" + // Deprecated: defaultPrefixLengthFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. defaultPrefixLengthFlag = "default-prefix-length" - maxPrefixLengthFlag = "max-prefix-length" - minPrefixLengthFlag = "min-prefix-length" - labelFlag = "labels" + // Deprecated: maxPrefixLengthFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + maxPrefixLengthFlag = "max-prefix-length" + // Deprecated: minPrefixLengthFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + minPrefixLengthFlag = "min-prefix-length" + labelFlag = "labels" + + deprecationMessage = "Deprecated and will be removed after April 2026. Use instead the new command `$ stackit network-area region` to configure these options for a network area." ) type inputModel struct { *globalflags.GlobalFlagModel - Name *string - OrganizationId *string - DnsNameServers *[]string - NetworkRanges *[]string - TransferNetwork *string + Name *string + OrganizationId string + // Deprecated: DnsNameServers is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + DnsNameServers *[]string + // Deprecated: NetworkRanges is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + NetworkRanges *[]string + // Deprecated: TransferNetwork is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + TransferNetwork *string + // Deprecated: DefaultPrefixLength is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. DefaultPrefixLength *int64 - MaxPrefixLength *int64 - MinPrefixLength *int64 - Labels *map[string]string + // Deprecated: MaxPrefixLength is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + MaxPrefixLength *int64 + // Deprecated: MinPrefixLength is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + MinPrefixLength *int64 + Labels *map[string]string +} + +// NetworkAreaResponses is a workaround, to keep the two responses of the iaas v2 api together for the json and yaml output +// Should be removed when the deprecated flags are removed +type NetworkAreaResponses struct { + NetworkArea iaas.NetworkArea `json:"network_area"` + RegionalArea *iaas.RegionalArea `json:"regional_area"` } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -52,20 +78,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { Args: args.NoArgs, Example: examples.Build( examples.NewExample( - `Create a network area with name "network-area-1" in organization with ID "xxx" with network ranges and a transfer network`, - `$ stackit network-area create --name network-area-1 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24"`, - ), - examples.NewExample( - `Create a network area with name "network-area-2" in organization with ID "xxx" with network ranges, transfer network and DNS name server`, - `$ stackit network-area create --name network-area-2 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" --dns-name-servers "1.1.1.1"`, - ), - examples.NewExample( - `Create a network area with name "network-area-3" in organization with ID "xxx" with network ranges, transfer network and additional options`, - `$ stackit network-area create --name network-area-3 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" --default-prefix-length 25 --max-prefix-length 29 --min-prefix-length 24`, + `Create a network area with name "network-area-1" in organization with ID "xxx"`, + `$ stackit network-area create --name network-area-1 --organization-id xxx"`, ), examples.NewExample( - `Create a network area with name "network-area-1" in organization with ID "xxx" with network ranges and a transfer network and labels "key=value,key1=value1"`, - `$ stackit network-area create --name network-area-1 --organization-id xxx --network-ranges "1.1.1.0/24,192.123.1.0/24" --transfer-network "192.160.0.0/24" --labels key=value,key1=value1`, + `Create a network area with name "network-area-1" in organization with ID "xxx" with labels "key=value,key1=value1"`, + `$ stackit network-area create --name network-area-1 --organization-id xxx --labels key=value,key1=value1`, ), ), RunE: func(cmd *cobra.Command, args []string) error { @@ -84,12 +102,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { var orgLabel string rmApiClient, err := rmClient.ConfigureClient(params.Printer, params.CliVersion) if err == nil { - orgLabel, err = rmUtils.GetOrganizationName(ctx, rmApiClient, *model.OrganizationId) + orgLabel, err = rmUtils.GetOrganizationName(ctx, rmApiClient, model.OrganizationId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) - orgLabel = *model.OrganizationId + orgLabel = model.OrganizationId } else if orgLabel == "" { - orgLabel = *model.OrganizationId + orgLabel = model.OrganizationId } } else { params.Printer.Debug(print.ErrorLevel, "configure resource manager client: %v", err) @@ -109,8 +127,38 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("create network area: %w", err) } + if resp == nil || resp.Id == nil { + return fmt.Errorf("create network area: empty response") + } + + responses := &NetworkAreaResponses{ + NetworkArea: *resp, + } - return outputResult(params.Printer, model.OutputFormat, orgLabel, resp) + if hasDeprecatedFlagsSet(model) { + deprecatedFlags := getConfiguredDeprecatedFlags(model) + params.Printer.Warn("the flags %q are deprecated and will be removed after April 2026. Use `$ stackit network-area region` to configure these options for a network area.\n", strings.Join(deprecatedFlags, ",")) + if resp == nil || resp.Id == nil { + return fmt.Errorf("create network area: empty response") + } + reqNetworkArea := buildRequestNetworkAreaRegion(ctx, model, *resp.Id, apiClient) + respNetworkArea, err := reqNetworkArea.Execute() + if err != nil { + return fmt.Errorf("create network area region: %w", err) + } + if !model.AssumeYes { + s := spinner.New(params.Printer) + s.Start("Create network area region") + _, err = wait.CreateNetworkAreaRegionWaitHandler(ctx, apiClient, model.OrganizationId, *resp.Id, model.Region).WaitWithContext(ctx) + if err != nil { + return fmt.Errorf("wait for creating network area region %w", err) + } + s.Stop() + } + responses.RegionalArea = respNetworkArea + } + + return outputResult(params.Printer, model.OutputFormat, orgLabel, responses) }, } configureFlags(cmd) @@ -120,25 +168,64 @@ func NewCmd(params *params.CmdParams) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().StringP(nameFlag, "n", "", "Network area name") cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") + cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...'") cmd.Flags().StringSlice(dnsNameServersFlag, nil, "List of DNS name server IPs") cmd.Flags().Var(flags.CIDRSliceFlag(), networkRangesFlag, "List of network ranges") cmd.Flags().Var(flags.CIDRFlag(), transferNetworkFlag, "Transfer network in CIDR notation") cmd.Flags().Int64(defaultPrefixLengthFlag, 0, "The default prefix length for networks in the network area") cmd.Flags().Int64(maxPrefixLengthFlag, 0, "The maximum prefix length for networks in the network area") cmd.Flags().Int64(minPrefixLengthFlag, 0, "The minimum prefix length for networks in the network area") - cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...'") - err := flags.MarkFlagsRequired(cmd, nameFlag, organizationIdFlag, networkRangesFlag, transferNetworkFlag) + cobra.CheckErr(cmd.Flags().MarkDeprecated(dnsNameServersFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(networkRangesFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(transferNetworkFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(defaultPrefixLengthFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(maxPrefixLengthFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(minPrefixLengthFlag, deprecationMessage)) + // Set the output for deprecation warnings to stderr + cmd.Flags().SetOutput(os.Stderr) + + cmd.MarkFlagsRequiredTogether(networkRangesFlag, transferNetworkFlag) + + err := flags.MarkFlagsRequired(cmd, nameFlag, organizationIdFlag) cobra.CheckErr(err) } +func hasDeprecatedFlagsSet(model *inputModel) bool { + deprecatedFlags := getConfiguredDeprecatedFlags(model) + return len(deprecatedFlags) > 0 +} + +func getConfiguredDeprecatedFlags(model *inputModel) []string { + var result []string + if model.DnsNameServers != nil { + result = append(result, dnsNameServersFlag) + } + if model.NetworkRanges != nil { + result = append(result, networkRangesFlag) + } + if model.TransferNetwork != nil { + result = append(result, transferNetworkFlag) + } + if model.DefaultPrefixLength != nil { + result = append(result, defaultPrefixLengthFlag) + } + if model.MaxPrefixLength != nil { + result = append(result, maxPrefixLengthFlag) + } + if model.MinPrefixLength != nil { + result = append(result, minPrefixLengthFlag) + } + return result +} + func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) model := inputModel{ GlobalFlagModel: globalFlags, Name: flags.FlagToStringPointer(p, cmd, nameFlag), - OrganizationId: flags.FlagToStringPointer(p, cmd, organizationIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), DnsNameServers: flags.FlagToStringSlicePointer(p, cmd, dnsNameServersFlag), NetworkRanges: flags.FlagToStringSlicePointer(p, cmd, networkRangesFlag), TransferNetwork: flags.FlagToStringPointer(p, cmd, transferNetworkFlag), @@ -148,44 +235,71 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag), } + // Check if any of the deprecated **optional** fields are set and if no of the associated deprecated **required** fields is set. + hasAllRequiredRegionalAreaFieldsSet := model.NetworkRanges != nil && model.TransferNetwork != nil + hasOptionalRegionalAreaFieldsSet := model.DnsNameServers != nil || model.DefaultPrefixLength != nil || model.MaxPrefixLength != nil || model.MinPrefixLength != nil + if hasOptionalRegionalAreaFieldsSet && !hasAllRequiredRegionalAreaFieldsSet { + return nil, &cliErr.MultipleFlagsAreMissing{ + MissingFlags: []string{networkRangesFlag, transferNetworkFlag}, + SetFlags: []string{dnsNameServersFlag, defaultPrefixLengthFlag, minPrefixLengthFlag, maxPrefixLengthFlag}, + } + } + p.DebugInputModel(model) return &model, nil } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateNetworkAreaRequest { - req := apiClient.CreateNetworkArea(ctx, *model.OrganizationId) - - networkRanges := make([]iaas.NetworkRange, len(*model.NetworkRanges)) - for i, networkRange := range *model.NetworkRanges { - networkRanges[i] = iaas.NetworkRange{ - Prefix: utils.Ptr(networkRange), - } - } + req := apiClient.CreateNetworkArea(ctx, model.OrganizationId) payload := iaas.CreateNetworkAreaPayload{ Name: model.Name, Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), - AddressFamily: &iaas.CreateAreaAddressFamily{ - Ipv4: &iaas.CreateAreaIPv4{ - DefaultNameservers: model.DnsNameServers, - NetworkRanges: utils.Ptr(networkRanges), - TransferNetwork: model.TransferNetwork, - DefaultPrefixLen: model.DefaultPrefixLength, - MaxPrefixLen: model.MaxPrefixLength, - MinPrefixLen: model.MinPrefixLength, - }, - }, } return req.CreateNetworkAreaPayload(payload) } -func outputResult(p *print.Printer, outputFormat, orgLabel string, networkArea *iaas.NetworkArea) error { - if networkArea == nil { +func buildRequestNetworkAreaRegion(ctx context.Context, model *inputModel, networkAreaId string, apiClient *iaas.APIClient) iaas.ApiCreateNetworkAreaRegionRequest { + req := apiClient.CreateNetworkAreaRegion(ctx, model.OrganizationId, networkAreaId, model.Region) + + var networkRanges []iaas.NetworkRange + if model.NetworkRanges != nil { + networkRanges = make([]iaas.NetworkRange, len(*model.NetworkRanges)) + for i, networkRange := range *model.NetworkRanges { + networkRanges[i] = iaas.NetworkRange{ + Prefix: utils.Ptr(networkRange), + } + } + } + + payload := iaas.CreateNetworkAreaRegionPayload{ + Ipv4: &iaas.RegionalAreaIPv4{ + DefaultNameservers: model.DnsNameServers, + NetworkRanges: utils.Ptr(networkRanges), + TransferNetwork: model.TransferNetwork, + DefaultPrefixLen: model.DefaultPrefixLength, + MaxPrefixLen: model.MaxPrefixLength, + MinPrefixLen: model.MinPrefixLength, + }, + } + + return req.CreateNetworkAreaRegionPayload(payload) +} + +func outputResult(p *print.Printer, outputFormat, orgLabel string, responses *NetworkAreaResponses) error { + if responses == nil { return fmt.Errorf("network area is nil") } - return p.OutputResult(outputFormat, networkArea, func() error { - p.Outputf("Created STACKIT Network Area for organization %q.\nNetwork area ID: %s\n", orgLabel, utils.PtrString(networkArea.AreaId)) + + prettyOutputFunc := func() error { + p.Outputf("Created STACKIT Network Area for organization %q.\nNetwork area ID: %s\n", orgLabel, utils.PtrString(responses.NetworkArea.Id)) return nil - }) + } + // If RegionalArea is NOT set in the response, then no deprecated Flags were set. + // In this case, only the response of NetworkArea should be printed in JSON and yaml output, to avoid breaking changes after the deprecated fields are removed + if responses.RegionalArea == nil { + return p.OutputResult(outputFormat, responses.NetworkArea, prettyOutputFunc) + } + return p.OutputResult(outputFormat, responses, prettyOutputFunc) } diff --git a/internal/cmd/network-area/create/create_test.go b/internal/cmd/network-area/create/create_test.go index a731541fd..9bfadd260 100644 --- a/internal/cmd/network-area/create/create_test.go +++ b/internal/cmd/network-area/create/create_test.go @@ -2,6 +2,8 @@ package create import ( "context" + "strconv" + "strings" "testing" "github.com/stackitcloud/stackit-cli/internal/cmd/params" @@ -16,24 +18,34 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" + testName = "example-network-area-name" + testTransferNetwork = "100.0.0.0/24" + testDefaultPrefixLength int64 = 25 + testMaxPrefixLength int64 = 26 + testMinPrefixLength int64 = 24 +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &iaas.APIClient{} -var testOrgId = uuid.NewString() +var ( + testOrgId = uuid.NewString() + testAreaId = uuid.NewString() + testDnsNameservers = []string{"1.1.1.0", "1.1.2.0"} + testNetworkRanges = []string{"192.0.0.0/24", "102.0.0.0/24"} +) func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - nameFlag: "example-network-area-name", - organizationIdFlag: testOrgId, - dnsNameServersFlag: "1.1.1.0,1.1.2.0", - networkRangesFlag: "192.0.0.0/24,102.0.0.0/24", - transferNetworkFlag: "100.0.0.0/24", - defaultPrefixLengthFlag: "24", - maxPrefixLengthFlag: "24", - minPrefixLengthFlag: "24", - labelFlag: "key=value", + globalflags.RegionFlag: testRegion, + + nameFlag: testName, + organizationIdFlag: testOrgId, + labelFlag: "key=value", } for _, mod := range mods { mod(flagValues) @@ -45,15 +57,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - Name: utils.Ptr("example-network-area-name"), - OrganizationId: utils.Ptr(testOrgId), - DnsNameServers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - NetworkRanges: utils.Ptr([]string{"192.0.0.0/24", "102.0.0.0/24"}), - TransferNetwork: utils.Ptr("100.0.0.0/24"), - DefaultPrefixLength: utils.Ptr(int64(24)), - MaxPrefixLength: utils.Ptr(int64(24)), - MinPrefixLength: utils.Ptr(int64(24)), + Name: utils.Ptr("example-network-area-name"), + OrganizationId: testOrgId, Labels: utils.Ptr(map[string]string{ "key": "value", }), @@ -79,23 +86,40 @@ func fixturePayload(mods ...func(payload *iaas.CreateNetworkAreaPayload)) iaas.C Labels: utils.Ptr(map[string]interface{}{ "key": "value", }), - AddressFamily: &iaas.CreateAreaAddressFamily{ - Ipv4: &iaas.CreateAreaIPv4{ - DefaultNameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - NetworkRanges: &[]iaas.NetworkRange{ - { - Prefix: utils.Ptr("192.0.0.0/24"), - }, - { - Prefix: utils.Ptr("102.0.0.0/24"), - }, - }, - TransferNetwork: utils.Ptr("100.0.0.0/24"), - DefaultPrefixLen: utils.Ptr(int64(24)), - MaxPrefixLen: utils.Ptr(int64(24)), - MinPrefixLen: utils.Ptr(int64(24)), - }, + } + for _, mod := range mods { + mod(&payload) + } + return payload +} + +func fixtureRequestRegionalArea(mods ...func(request *iaas.ApiCreateNetworkAreaRegionRequest)) iaas.ApiCreateNetworkAreaRegionRequest { + req := testClient.CreateNetworkAreaRegion(testCtx, testOrgId, testAreaId, testRegion) + req = req.CreateNetworkAreaRegionPayload(fixtureRegionalAreaPayload()) + for _, mod := range mods { + mod(&req) + } + return req +} + +func fixtureRegionalAreaPayload(mods ...func(request *iaas.CreateNetworkAreaRegionPayload)) iaas.CreateNetworkAreaRegionPayload { + var networkRanges []iaas.NetworkRange + for _, networkRange := range testNetworkRanges { + networkRanges = append(networkRanges, iaas.NetworkRange{ + Prefix: utils.Ptr(networkRange), + }) + } + + payload := iaas.CreateNetworkAreaRegionPayload{ + Ipv4: &iaas.RegionalAreaIPv4{ + DefaultNameservers: utils.Ptr(testDnsNameservers), + DefaultPrefixLen: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLen: utils.Ptr(testMaxPrefixLength), + MinPrefixLen: utils.Ptr(testMinPrefixLength), + NetworkRanges: utils.Ptr(networkRanges), + TransferNetwork: utils.Ptr(testTransferNetwork), }, + Status: nil, } for _, mod := range mods { mod(&payload) @@ -119,20 +143,35 @@ func TestParseInput(t *testing.T) { expectedModel: fixtureInputModel(), }, { - description: "required only", - flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, dnsNameServersFlag) - delete(flagValues, defaultPrefixLengthFlag) - delete(flagValues, maxPrefixLengthFlag) - delete(flagValues, minPrefixLengthFlag) - }), + description: "with deprecated flags", + flagValues: map[string]string{ + nameFlag: testName, + organizationIdFlag: testOrgId, + + // Deprecated flags + dnsNameServersFlag: strings.Join(testDnsNameservers, ","), + networkRangesFlag: strings.Join(testNetworkRanges, ","), + transferNetworkFlag: testTransferNetwork, + defaultPrefixLengthFlag: strconv.FormatInt(testDefaultPrefixLength, 10), + maxPrefixLengthFlag: strconv.FormatInt(testMaxPrefixLength, 10), + minPrefixLengthFlag: strconv.FormatInt(testMinPrefixLength, 10), + }, isValid: true, - expectedModel: fixtureInputModel(func(model *inputModel) { - model.DnsNameServers = nil - model.DefaultPrefixLength = nil - model.MaxPrefixLength = nil - model.MinPrefixLength = nil - }), + expectedModel: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: testOrgId, + + // Deprecated fields + DnsNameServers: utils.Ptr(testDnsNameservers), + NetworkRanges: utils.Ptr(testNetworkRanges), + TransferNetwork: utils.Ptr(testTransferNetwork), + DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + MinPrefixLength: utils.Ptr(testMinPrefixLength), + }, }, { description: "name missing", @@ -142,16 +181,38 @@ func TestParseInput(t *testing.T) { isValid: false, }, { - description: "network ranges missing", + description: "set deprecated network ranges - missing transfer network", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, networkRangesFlag) + flagValues[networkRangesFlag] = strings.Join(testNetworkRanges, ",") }), isValid: false, }, { - description: "transfer network missing", + description: "set deprecated transfer network - missing network ranges", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, transferNetworkFlag) + flagValues[transferNetworkFlag] = testTransferNetwork + }), + isValid: false, + }, + { + description: "set deprecated transfer network and network ranges", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkRangesFlag] = strings.Join(testNetworkRanges, ",") + flagValues[transferNetworkFlag] = testTransferNetwork + }), + isValid: true, + expectedModel: fixtureInputModel(func(model *inputModel) { + model.NetworkRanges = utils.Ptr(testNetworkRanges) + model.TransferNetwork = utils.Ptr(testTransferNetwork) + }), + }, + { + description: "set deprecated optional flags", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[dnsNameServersFlag] = strings.Join(testDnsNameservers, ",") + flagValues[defaultPrefixLengthFlag] = strconv.FormatInt(testDefaultPrefixLength, 10) + flagValues[maxPrefixLengthFlag] = strconv.FormatInt(testMaxPrefixLength, 10) + flagValues[minPrefixLengthFlag] = strconv.FormatInt(testMinPrefixLength, 10) }), isValid: false, }, @@ -228,11 +289,63 @@ func TestBuildRequest(t *testing.T) { } } +func TestBuildRequestNetworkAreaRegion(t *testing.T) { + tests := []struct { + description string + model *inputModel + areaId string + expectedRequest iaas.ApiCreateNetworkAreaRegionRequest + }{ + { + description: "base", + model: fixtureInputModel(func(model *inputModel) { + // Deprecated fields + model.DnsNameServers = utils.Ptr(testDnsNameservers) + model.NetworkRanges = utils.Ptr(testNetworkRanges) + model.TransferNetwork = utils.Ptr(testTransferNetwork) + model.DefaultPrefixLength = utils.Ptr(testDefaultPrefixLength) + model.MaxPrefixLength = utils.Ptr(testMaxPrefixLength) + model.MinPrefixLength = utils.Ptr(testMinPrefixLength) + }), + areaId: testAreaId, + expectedRequest: fixtureRequestRegionalArea(), + }, + { + description: "base without network ranges", + model: fixtureInputModel(func(model *inputModel) { + // Deprecated fields + model.DnsNameServers = utils.Ptr(testDnsNameservers) + model.NetworkRanges = utils.Ptr(testNetworkRanges) + model.TransferNetwork = utils.Ptr(testTransferNetwork) + model.DefaultPrefixLength = utils.Ptr(testDefaultPrefixLength) + model.MaxPrefixLength = utils.Ptr(testMaxPrefixLength) + model.MinPrefixLength = utils.Ptr(testMinPrefixLength) + }), + areaId: testAreaId, + expectedRequest: fixtureRequestRegionalArea(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequestNetworkAreaRegion(testCtx, tt.model, testAreaId, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + func Test_outputResult(t *testing.T) { type args struct { outputFormat string orgLabel string - networkArea *iaas.NetworkArea + responses *NetworkAreaResponses } tests := []struct { name string @@ -244,10 +357,19 @@ func Test_outputResult(t *testing.T) { args: args{}, wantErr: true, }, + { + name: "set empty response", + args: args{ + responses: &NetworkAreaResponses{}, + }, + wantErr: false, + }, { name: "set empty network area", args: args{ - networkArea: &iaas.NetworkArea{}, + responses: &NetworkAreaResponses{ + NetworkArea: iaas.NetworkArea{}, + }, }, wantErr: false, }, @@ -256,9 +378,140 @@ func Test_outputResult(t *testing.T) { p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.orgLabel, tt.args.networkArea); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.orgLabel, tt.args.responses); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) } } + +func TestGetConfiguredDeprecatedFlags(t *testing.T) { + type args struct { + model *inputModel + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "no deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: testOrgId, + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: nil, + NetworkRanges: nil, + TransferNetwork: nil, + DefaultPrefixLength: nil, + MaxPrefixLength: nil, + MinPrefixLength: nil, + }, + }, + want: nil, + }, + { + name: "deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: testOrgId, + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: utils.Ptr(testDnsNameservers), + NetworkRanges: utils.Ptr(testNetworkRanges), + TransferNetwork: utils.Ptr(testTransferNetwork), + DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + MinPrefixLength: utils.Ptr(testMinPrefixLength), + }, + }, + want: []string{dnsNameServersFlag, networkRangesFlag, transferNetworkFlag, defaultPrefixLengthFlag, minPrefixLengthFlag, maxPrefixLengthFlag}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := getConfiguredDeprecatedFlags(tt.args.model) + + less := func(a, b string) bool { + return a < b + } + if diff := cmp.Diff(tt.want, got, cmpopts.SortSlices(less)); diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + +func TestHasDeprecatedFlagsSet(t *testing.T) { + type args struct { + model *inputModel + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "no deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: testOrgId, + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: nil, + NetworkRanges: nil, + TransferNetwork: nil, + DefaultPrefixLength: nil, + MaxPrefixLength: nil, + MinPrefixLength: nil, + }, + }, + want: false, + }, + { + name: "deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: testOrgId, + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: utils.Ptr(testDnsNameservers), + NetworkRanges: utils.Ptr(testNetworkRanges), + TransferNetwork: utils.Ptr(testTransferNetwork), + DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + MinPrefixLength: utils.Ptr(testMinPrefixLength), + }, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := hasDeprecatedFlagsSet(tt.args.model); got != tt.want { + t.Errorf("hasDeprecatedFlagsSet() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/cmd/network-area/delete/delete.go b/internal/cmd/network-area/delete/delete.go index d16a9e656..0e42d5883 100644 --- a/internal/cmd/network-area/delete/delete.go +++ b/internal/cmd/network-area/delete/delete.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/spf13/cobra" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" @@ -12,17 +13,19 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils" - "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/stackitcloud/stackit-sdk-go/services/iaas/wait" - - "github.com/spf13/cobra" ) const ( areaIdArg = "AREA_ID" organizationIdFlag = "organization-id" + + deprecationMessage = "The regional network area configuration %q for the area %q still exists.\n" + + "The regional configuration of the network area was moved to the new command group `$ stackit network-area region`.\n" + + "The regional area will be automatically deleted. This behavior is deprecated and will be removed after April 2026.\n" + + "Use in the future the command `$ stackit network-area region delete` to delete the regional network area and afterwards delete the network-area with the command `$ stackit network-area delete`.\n" ) type inputModel struct { @@ -73,29 +76,31 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } } - // Call API - req := buildRequest(ctx, model, apiClient) - err = req.Execute() + // Check if the network area has a regional configuration + regionalArea, err := apiClient.GetNetworkAreaRegion(ctx, *model.OrganizationId, model.AreaId, model.Region).Execute() if err != nil { - return fmt.Errorf("delete network area: %w", err) + params.Printer.Debug(print.ErrorLevel, "get regional area: %v", err) } - - // Wait for async operation, if async mode not enabled - if !model.Async { - s := spinner.New(params.Printer) - s.Start("Deleting network area") - _, err = wait.DeleteNetworkAreaWaitHandler(ctx, apiClient, *model.OrganizationId, model.AreaId).WaitWithContext(ctx) + if regionalArea != nil { + params.Printer.Warn(deprecationMessage, model.Region, networkAreaLabel) + err = apiClient.DeleteNetworkAreaRegion(ctx, *model.OrganizationId, model.AreaId, model.Region).Execute() if err != nil { - return fmt.Errorf("wait for network area deletion: %w", err) + return fmt.Errorf("delete network area region: %w", err) + } + _, err := wait.DeleteNetworkAreaRegionWaitHandler(ctx, apiClient, *model.OrganizationId, model.AreaId, model.Region).WaitWithContext(ctx) + if err != nil { + return fmt.Errorf("wait delete network area region: %w", err) } - s.Stop() } - operationState := "Deleted" - if model.Async { - operationState = "Triggered deletion of" + // Call API + req := buildRequest(ctx, model, apiClient) + err = req.Execute() + if err != nil { + return fmt.Errorf("delete network area: %w", err) } - params.Printer.Info("%s STACKIT Network Area %q\n", operationState, networkAreaLabel) + + params.Printer.Outputf("Deleted STACKIT Network Area %q\n", networkAreaLabel) return nil }, } diff --git a/internal/cmd/network-area/describe/describe.go b/internal/cmd/network-area/describe/describe.go index b6c086a4b..4fdf257c5 100644 --- a/internal/cmd/network-area/describe/describe.go +++ b/internal/cmd/network-area/describe/describe.go @@ -126,60 +126,11 @@ func outputResult(p *print.Printer, outputFormat string, networkArea *iaas.Netwo } return p.OutputResult(outputFormat, networkArea, func() error { - var routes []string - var networkRanges []string - - if networkArea.Ipv4 != nil { - if networkArea.Ipv4.Routes != nil { - for _, route := range *networkArea.Ipv4.Routes { - routes = append(routes, fmt.Sprintf("next hop: %s\nprefix: %s", *route.Nexthop, *route.Prefix)) - } - } - - if networkArea.Ipv4.NetworkRanges != nil { - for _, networkRange := range *networkArea.Ipv4.NetworkRanges { - networkRanges = append(networkRanges, *networkRange.Prefix) - } - } - } - table := tables.NewTable() - table.AddRow("ID", utils.PtrString(networkArea.AreaId)) + table.AddRow("ID", utils.PtrString(networkArea.Id)) table.AddSeparator() table.AddRow("NAME", utils.PtrString(networkArea.Name)) table.AddSeparator() - table.AddRow("STATE", utils.PtrString(networkArea.State)) - table.AddSeparator() - if len(networkRanges) > 0 { - table.AddRow("NETWORK RANGES", strings.Join(networkRanges, ",")) - } - table.AddSeparator() - for i, route := range routes { - table.AddRow(fmt.Sprintf("STATIC ROUTE %d", i+1), route) - table.AddSeparator() - } - if networkArea.Ipv4 != nil { - if networkArea.Ipv4.TransferNetwork != nil { - table.AddRow("TRANSFER RANGE", *networkArea.Ipv4.TransferNetwork) - table.AddSeparator() - } - if networkArea.Ipv4.DefaultNameservers != nil && len(*networkArea.Ipv4.DefaultNameservers) > 0 { - table.AddRow("DNS NAME SERVERS", strings.Join(*networkArea.Ipv4.DefaultNameservers, ",")) - table.AddSeparator() - } - if networkArea.Ipv4.DefaultPrefixLen != nil { - table.AddRow("DEFAULT PREFIX LENGTH", *networkArea.Ipv4.DefaultPrefixLen) - table.AddSeparator() - } - if networkArea.Ipv4.MaxPrefixLen != nil { - table.AddRow("MAX PREFIX LENGTH", *networkArea.Ipv4.MaxPrefixLen) - table.AddSeparator() - } - if networkArea.Ipv4.MinPrefixLen != nil { - table.AddRow("MIN PREFIX LENGTH", *networkArea.Ipv4.MinPrefixLen) - table.AddSeparator() - } - } if networkArea.Labels != nil && len(*networkArea.Labels) > 0 { var labels []string for key, value := range *networkArea.Labels { @@ -195,6 +146,10 @@ func outputResult(p *print.Printer, outputFormat string, networkArea *iaas.Netwo table.AddRow("# ATTACHED PROJECTS", utils.PtrString(networkArea.ProjectCount)) table.AddSeparator() } + table.AddRow("CREATED AT", utils.PtrString(networkArea.CreatedAt)) + table.AddSeparator() + table.AddRow("UPDATED AT", utils.PtrString(networkArea.UpdatedAt)) + table.AddSeparator() err := table.Display(p) if err != nil { diff --git a/internal/cmd/network-area/list/list.go b/internal/cmd/network-area/list/list.go index 6184148aa..e37822602 100644 --- a/internal/cmd/network-area/list/list.go +++ b/internal/cmd/network-area/list/list.go @@ -150,21 +150,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat string, networkAreas []iaas.NetworkArea) error { return p.OutputResult(outputFormat, networkAreas, func() error { table := tables.NewTable() - table.SetHeader("ID", "Name", "Status", "Network Ranges", "# Attached Projects") + table.SetHeader("ID", "Name", "# Attached Projects") for _, networkArea := range networkAreas { - networkRanges := "n/a" - if ipv4 := networkArea.Ipv4; ipv4 != nil { - if netRange := ipv4.NetworkRanges; netRange != nil { - networkRanges = fmt.Sprint(len(*netRange)) - } - } - table.AddRow( - utils.PtrString(networkArea.AreaId), + utils.PtrString(networkArea.Id), utils.PtrString(networkArea.Name), - utils.PtrString(networkArea.State), - networkRanges, utils.PtrString(networkArea.ProjectCount), ) table.AddSeparator() diff --git a/internal/cmd/network-area/network-range/create/create.go b/internal/cmd/network-area/network-range/create/create.go index ec7f1dbcf..33610c045 100644 --- a/internal/cmd/network-area/network-range/create/create.go +++ b/internal/cmd/network-area/network-range/create/create.go @@ -118,7 +118,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateNetworkAreaRangeRequest { - req := apiClient.CreateNetworkAreaRange(ctx, *model.OrganizationId, *model.NetworkAreaId) + req := apiClient.CreateNetworkAreaRange(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) payload := iaas.CreateNetworkAreaRangePayload{ Ipv4: &[]iaas.NetworkRange{ { @@ -131,7 +131,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, networkRange iaas.NetworkRange) error { return p.OutputResult(outputFormat, networkRange, func() error { - p.Outputf("Created network range for SNA %q.\nNetwork range ID: %s\n", networkAreaLabel, utils.PtrString(networkRange.NetworkRangeId)) + p.Outputf("Created network range for SNA %q.\nNetwork range ID: %s\n", networkAreaLabel, utils.PtrString(networkRange.Id)) return nil }) } diff --git a/internal/cmd/network-area/network-range/create/create_test.go b/internal/cmd/network-area/network-range/create/create_test.go index 6edc6b23b..e5b01e224 100644 --- a/internal/cmd/network-area/network-range/create/create_test.go +++ b/internal/cmd/network-area/network-range/create/create_test.go @@ -16,6 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -26,6 +30,8 @@ var testNetworkAreaId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, networkRangeFlag: "1.1.1.0/24", @@ -40,6 +46,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: utils.Ptr(testOrgId), NetworkAreaId: utils.Ptr(testNetworkAreaId), @@ -52,7 +59,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateNetworkAreaRangeRequest)) iaas.ApiCreateNetworkAreaRangeRequest { - request := testClient.CreateNetworkAreaRange(testCtx, testOrgId, testNetworkAreaId) + request := testClient.CreateNetworkAreaRange(testCtx, testOrgId, testNetworkAreaId, testRegion) request = request.CreateNetworkAreaRangePayload(fixturePayload()) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/network-area/network-range/delete/delete.go b/internal/cmd/network-area/network-range/delete/delete.go index 12126917e..4d3a94c5d 100644 --- a/internal/cmd/network-area/network-range/delete/delete.go +++ b/internal/cmd/network-area/network-range/delete/delete.go @@ -62,7 +62,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) networkAreaLabel = *model.NetworkAreaId } - networkRangeLabel, err := iaasUtils.GetNetworkRangePrefix(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId, model.NetworkRangeId) + networkRangeLabel, err := iaasUtils.GetNetworkRangePrefix(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId, model.Region, model.NetworkRangeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network range prefix: %v", err) networkRangeLabel = model.NetworkRangeId @@ -118,6 +118,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteNetworkAreaRangeRequest { - req := apiClient.DeleteNetworkAreaRange(ctx, *model.OrganizationId, *model.NetworkAreaId, model.NetworkRangeId) + req := apiClient.DeleteNetworkAreaRange(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region, model.NetworkRangeId) return req } diff --git a/internal/cmd/network-area/network-range/delete/delete_test.go b/internal/cmd/network-area/network-range/delete/delete_test.go index 5fb112ef6..79c1ad52c 100644 --- a/internal/cmd/network-area/network-range/delete/delete_test.go +++ b/internal/cmd/network-area/network-range/delete/delete_test.go @@ -15,6 +15,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -36,6 +40,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, } @@ -49,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: utils.Ptr(testOrgId), NetworkAreaId: utils.Ptr(testNetworkAreaId), @@ -61,7 +68,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteNetworkAreaRangeRequest)) iaas.ApiDeleteNetworkAreaRangeRequest { - request := testClient.DeleteNetworkAreaRange(testCtx, testOrgId, testNetworkAreaId, testNetworkRangeId) + request := testClient.DeleteNetworkAreaRange(testCtx, testOrgId, testNetworkAreaId, testRegion, testNetworkRangeId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-area/network-range/describe/describe.go b/internal/cmd/network-area/network-range/describe/describe.go index dcc695246..ee13560b9 100644 --- a/internal/cmd/network-area/network-range/describe/describe.go +++ b/internal/cmd/network-area/network-range/describe/describe.go @@ -95,7 +95,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetNetworkAreaRangeRequest { - req := apiClient.GetNetworkAreaRange(ctx, *model.OrganizationId, *model.NetworkAreaId, model.NetworkRangeId) + req := apiClient.GetNetworkAreaRange(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region, model.NetworkRangeId) return req } @@ -106,7 +106,7 @@ func outputResult(p *print.Printer, outputFormat string, networkRange *iaas.Netw return p.OutputResult(outputFormat, networkRange, func() error { table := tables.NewTable() - table.AddRow("ID", utils.PtrString(networkRange.NetworkRangeId)) + table.AddRow("ID", utils.PtrString(networkRange.Id)) table.AddSeparator() table.AddRow("Network range", utils.PtrString(networkRange.Prefix)) diff --git a/internal/cmd/network-area/network-range/describe/describe_test.go b/internal/cmd/network-area/network-range/describe/describe_test.go index a314d11ee..6e519fef8 100644 --- a/internal/cmd/network-area/network-range/describe/describe_test.go +++ b/internal/cmd/network-area/network-range/describe/describe_test.go @@ -15,6 +15,11 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + projectIdFlag = globalflags.ProjectIdFlag + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -36,6 +41,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, } @@ -48,6 +55,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, OrganizationId: utils.Ptr(testOrgId), @@ -61,7 +69,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetNetworkAreaRangeRequest)) iaas.ApiGetNetworkAreaRangeRequest { - request := testClient.GetNetworkAreaRange(testCtx, testOrgId, testNetworkAreaId, testNetworkRangeId) + request := testClient.GetNetworkAreaRange(testCtx, testOrgId, testNetworkAreaId, testRegion, testNetworkRangeId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-area/network-range/list/list.go b/internal/cmd/network-area/network-range/list/list.go index 967ffbb9c..2fec7b330 100644 --- a/internal/cmd/network-area/network-range/list/list.go +++ b/internal/cmd/network-area/network-range/list/list.go @@ -128,7 +128,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworkAreaRangesRequest { - return apiClient.ListNetworkAreaRanges(ctx, *model.OrganizationId, *model.NetworkAreaId) + return apiClient.ListNetworkAreaRanges(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) } func outputResult(p *print.Printer, outputFormat string, networkRanges []iaas.NetworkRange) error { @@ -137,7 +137,7 @@ func outputResult(p *print.Printer, outputFormat string, networkRanges []iaas.Ne table.SetHeader("ID", "Network Range") for _, networkRange := range networkRanges { - table.AddRow(utils.PtrString(networkRange.NetworkRangeId), utils.PtrString(networkRange.Prefix)) + table.AddRow(utils.PtrString(networkRange.Id), utils.PtrString(networkRange.Prefix)) } p.Outputln(table.Render()) diff --git a/internal/cmd/network-area/network-range/list/list_test.go b/internal/cmd/network-area/network-range/list/list_test.go index f8525e39b..67044ee06 100644 --- a/internal/cmd/network-area/network-range/list/list_test.go +++ b/internal/cmd/network-area/network-range/list/list_test.go @@ -16,6 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -25,6 +29,8 @@ var testNetworkAreaId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrganizationId, networkAreaIdFlag: testNetworkAreaId, limitFlag: "10", @@ -38,6 +44,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, OrganizationId: &testOrganizationId, @@ -51,7 +58,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListNetworkAreaRangesRequest)) iaas.ApiListNetworkAreaRangesRequest { - request := testClient.ListNetworkAreaRanges(testCtx, testOrganizationId, testNetworkAreaId) + request := testClient.ListNetworkAreaRanges(testCtx, testOrganizationId, testNetworkAreaId, testRegion) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-area/network_area.go b/internal/cmd/network-area/network_area.go index 0b67ea3ea..637a7af0e 100644 --- a/internal/cmd/network-area/network_area.go +++ b/internal/cmd/network-area/network_area.go @@ -6,6 +6,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/describe" "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/list" networkrange "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/network-range" + "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/region" "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/route" "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/update" "github.com/stackitcloud/stackit-cli/internal/cmd/params" @@ -33,6 +34,7 @@ func addSubcommands(cmd *cobra.Command, params *params.CmdParams) { cmd.AddCommand(describe.NewCmd(params)) cmd.AddCommand(list.NewCmd(params)) cmd.AddCommand(networkrange.NewCmd(params)) + cmd.AddCommand(region.NewCmd(params)) cmd.AddCommand(route.NewCmd(params)) cmd.AddCommand(update.NewCmd(params)) } diff --git a/internal/cmd/network-area/region/create/create.go b/internal/cmd/network-area/region/create/create.go new file mode 100644 index 000000000..a4cda53d6 --- /dev/null +++ b/internal/cmd/network-area/region/create/create.go @@ -0,0 +1,195 @@ +package create + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" + "github.com/stackitcloud/stackit-cli/internal/pkg/errors" + "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/flags" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" + iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" + "github.com/stackitcloud/stackit-sdk-go/services/iaas/wait" +) + +const ( + networkAreaIdFlag = "network-area-id" + organizationIdFlag = "organization-id" + ipv4DefaultNameservers = "ipv4-default-nameservers" + ipv4DefaultPrefixLengthFlag = "ipv4-default-prefix-length" + ipv4MaxPrefixLengthFlag = "ipv4-max-prefix-length" + ipv4MinPrefixLengthFlag = "ipv4-min-prefix-length" + ipv4NetworkRangesFlag = "ipv4-network-ranges" + ipv4TransferNetworkFlag = "ipv4-transfer-network" +) + +type inputModel struct { + *globalflags.GlobalFlagModel + OrganizationId string + NetworkAreaId string + + IPv4DefaultNameservers *[]string + IPv4DefaultPrefixLength *int64 + IPv4MaxPrefixLength *int64 + IPv4MinPrefixLength *int64 + IPv4NetworkRanges []string + IPv4TransferNetwork string +} + +func NewCmd(params *params.CmdParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Short: "Creates a new regional configuration for a STACKIT Network Area (SNA)", + Long: "Creates a new regional configuration for a STACKIT Network Area (SNA).", + Args: args.NoArgs, + Example: examples.Build( + examples.NewExample( + `Create a new regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24" and ipv4 transfer network "192.168.1.0/24"`, + `$ stackit network-area region create --network-area-id xxx --region eu02 --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24`, + ), + examples.NewExample( + `Create a new regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", using the set region config`, + `$ stackit config set --region eu02`, + `$ stackit network-area region create --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24`, + ), + examples.NewExample( + `Create a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20"`, + `$ stackit network-area region create --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20`, + ), + examples.NewExample( + `Create a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20"`, + `$ stackit network-area region create --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20`, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + model, err := parseInput(params.Printer, cmd, args) + if err != nil { + return err + } + + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + if err != nil { + return err + } + + // Get network area label + networkAreaLabel, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) + networkAreaLabel = model.NetworkAreaId + } + + if !model.AssumeYes { + prompt := fmt.Sprintf("Are you sure you want to create the regional configuration %q for STACKIT Network Area (SNA) %q?", model.Region, networkAreaLabel) + err = params.Printer.PromptForConfirmation(prompt) + if err != nil { + return err + } + } + + // Call API + req := buildRequest(ctx, model, apiClient) + resp, err := req.Execute() + if err != nil { + return fmt.Errorf("create network area region: %w", err) + } + + if resp == nil || resp.Ipv4 == nil { + return fmt.Errorf("empty response from API") + } + + if !model.Async { + s := spinner.New(params.Printer) + s.Start("Create network area region") + _, err = wait.CreateNetworkAreaRegionWaitHandler(ctx, apiClient, model.OrganizationId, model.NetworkAreaId, model.Region).WaitWithContext(ctx) + if err != nil { + return fmt.Errorf("wait for network area region creation: %w", err) + } + s.Stop() + } + + return outputResult(params.Printer, model.OutputFormat, model.Region, networkAreaLabel, *resp) + }, + } + configureFlags(cmd) + return cmd +} + +func configureFlags(cmd *cobra.Command) { + cmd.Flags().Var(flags.UUIDFlag(), networkAreaIdFlag, "STACKIT Network Area (SNA) ID") + cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") + cmd.Flags().Var(flags.CIDRSliceFlag(), ipv4NetworkRangesFlag, "Network range to create in CIDR notation") + cmd.Flags().Var(flags.CIDRFlag(), ipv4TransferNetworkFlag, "Transfer network in CIDR notation") + cmd.Flags().StringSlice(ipv4DefaultNameservers, nil, "List of default DNS name server IPs") + cmd.Flags().Int64(ipv4DefaultPrefixLengthFlag, 0, "The default prefix length for networks in the network area") + cmd.Flags().Int64(ipv4MaxPrefixLengthFlag, 0, "The maximum prefix length for networks in the network area") + cmd.Flags().Int64(ipv4MinPrefixLengthFlag, 0, "The minimum prefix length for networks in the network area") + + err := flags.MarkFlagsRequired(cmd, networkAreaIdFlag, organizationIdFlag, ipv4NetworkRangesFlag, ipv4TransferNetworkFlag) + cobra.CheckErr(err) +} + +func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { + globalFlags := globalflags.Parse(p, cmd) + if globalFlags.Region == "" { + return nil, &errors.RegionError{} + } + + model := inputModel{ + GlobalFlagModel: globalFlags, + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + IPv4DefaultNameservers: flags.FlagToStringSlicePointer(p, cmd, ipv4DefaultNameservers), + IPv4DefaultPrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4DefaultPrefixLengthFlag), + IPv4MaxPrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4MaxPrefixLengthFlag), + IPv4MinPrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4MinPrefixLengthFlag), + IPv4NetworkRanges: flags.FlagToStringSliceValue(p, cmd, ipv4NetworkRangesFlag), + IPv4TransferNetwork: flags.FlagToStringValue(p, cmd, ipv4TransferNetworkFlag), + } + + p.DebugInputModel(model) + return &model, nil +} + +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateNetworkAreaRegionRequest { + req := apiClient.CreateNetworkAreaRegion(ctx, model.OrganizationId, model.NetworkAreaId, model.Region) + + var networkRange []iaas.NetworkRange + if len(model.IPv4NetworkRanges) > 0 { + networkRange = make([]iaas.NetworkRange, len(model.IPv4NetworkRanges)) + for i := range model.IPv4NetworkRanges { + networkRange[i] = iaas.NetworkRange{ + Prefix: utils.Ptr(model.IPv4NetworkRanges[i]), + } + } + } + + payload := iaas.CreateNetworkAreaRegionPayload{ + Ipv4: &iaas.RegionalAreaIPv4{ + DefaultNameservers: model.IPv4DefaultNameservers, + DefaultPrefixLen: model.IPv4DefaultPrefixLength, + MaxPrefixLen: model.IPv4MaxPrefixLength, + MinPrefixLen: model.IPv4MinPrefixLength, + NetworkRanges: utils.Ptr(networkRange), + TransferNetwork: utils.Ptr(model.IPv4TransferNetwork), + }, + } + return req.CreateNetworkAreaRegionPayload(payload) +} + +func outputResult(p *print.Printer, outputFormat, region, networkAreaLabel string, regionalArea iaas.RegionalArea) error { + return p.OutputResult(outputFormat, regionalArea, func() error { + p.Outputf("Create region configuration for SNA %q.\nRegion: %s\n", networkAreaLabel, region) + return nil + }) +} diff --git a/internal/cmd/network-area/region/create/create_test.go b/internal/cmd/network-area/region/create/create_test.go new file mode 100644 index 000000000..1f8cacef2 --- /dev/null +++ b/internal/cmd/network-area/region/create/create_test.go @@ -0,0 +1,307 @@ +package create + +import ( + "context" + "strconv" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + testRegion = "eu01" + testDefaultPrefixLength int64 = 25 + testMaxPrefixLength int64 = 29 + testMinPrefixLength int64 = 24 + testTransferNetwork = "192.168.2.0/24" +) + +type testCtxKey struct{} + +var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") +var testClient = &iaas.APIClient{} + +var ( + testAreaId = uuid.NewString() + testOrgId = uuid.NewString() + testDefaultNameservers = []string{"8.8.8.8", "8.8.4.4"} + testNetworkRanges = []string{"192.168.0.0/24", "10.0.0.0/24"} +) + +func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + + networkAreaIdFlag: testAreaId, + organizationIdFlag: testOrgId, + ipv4DefaultNameservers: strings.Join(testDefaultNameservers, ","), + ipv4DefaultPrefixLengthFlag: strconv.FormatInt(testDefaultPrefixLength, 10), + ipv4MaxPrefixLengthFlag: strconv.FormatInt(testMaxPrefixLength, 10), + ipv4MinPrefixLengthFlag: strconv.FormatInt(testMinPrefixLength, 10), + ipv4NetworkRangesFlag: strings.Join(testNetworkRanges, ","), + ipv4TransferNetworkFlag: testTransferNetwork, + } + for _, mod := range mods { + mod(flagValues) + } + return flagValues +} + +func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { + model := &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, + OrganizationId: testOrgId, + NetworkAreaId: testAreaId, + IPv4DefaultNameservers: utils.Ptr(testDefaultNameservers), + IPv4DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + IPv4MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + IPv4MinPrefixLength: utils.Ptr(testMinPrefixLength), + IPv4NetworkRanges: testNetworkRanges, + IPv4TransferNetwork: testTransferNetwork, + } + for _, mod := range mods { + mod(model) + } + return model +} + +func fixtureRequest(mods ...func(request *iaas.ApiCreateNetworkAreaRegionRequest)) iaas.ApiCreateNetworkAreaRegionRequest { + request := testClient.CreateNetworkAreaRegion(testCtx, testOrgId, testAreaId, testRegion) + request = request.CreateNetworkAreaRegionPayload(fixturePayload()) + for _, mod := range mods { + mod(&request) + } + return request +} + +func fixturePayload(mods ...func(payload *iaas.CreateNetworkAreaRegionPayload)) iaas.CreateNetworkAreaRegionPayload { + var networkRange []iaas.NetworkRange + if len(testNetworkRanges) > 0 { + networkRange = make([]iaas.NetworkRange, len(testNetworkRanges)) + for i := range testNetworkRanges { + networkRange[i] = iaas.NetworkRange{ + Prefix: utils.Ptr(testNetworkRanges[i]), + } + } + } + + payload := iaas.CreateNetworkAreaRegionPayload{ + Ipv4: &iaas.RegionalAreaIPv4{ + DefaultNameservers: utils.Ptr(testDefaultNameservers), + DefaultPrefixLen: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLen: utils.Ptr(testMaxPrefixLength), + MinPrefixLen: utils.Ptr(testMinPrefixLength), + NetworkRanges: utils.Ptr(networkRange), + TransferNetwork: utils.Ptr(testTransferNetwork), + }, + } + for _, mod := range mods { + mod(&payload) + } + return payload +} + +func TestParseInput(t *testing.T) { + tests := []struct { + description string + argValues []string + flagValues map[string]string + isValid bool + expectedModel *inputModel + }{ + { + description: "base", + flagValues: fixtureFlagValues(), + isValid: true, + expectedModel: fixtureInputModel(), + }, + { + description: "no values", + flagValues: map[string]string{}, + isValid: false, + }, + { + description: "area id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, networkAreaIdFlag) + }), + isValid: false, + }, + { + description: "area id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "" + }), + isValid: false, + }, + { + description: "area id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "org id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, organizationIdFlag) + }), + isValid: false, + }, + { + description: "org id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "" + }), + isValid: false, + }, + { + description: "org id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "network range missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, ipv4NetworkRangesFlag) + }), + isValid: false, + }, + { + description: "multiple network ranges", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4NetworkRangesFlag] = "192.168.2.0/24,10.0.0.0/24" + }), + expectedModel: fixtureInputModel(func(model *inputModel) { + model.IPv4NetworkRanges = []string{"192.168.2.0/24", "10.0.0.0/24"} + }), + isValid: true, + }, + { + description: "network range invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4NetworkRangesFlag] = "invalid-cidr" + }), + isValid: false, + }, + { + description: "transfer network missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, ipv4TransferNetworkFlag) + }), + isValid: false, + }, + { + description: "transfer network invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4TransferNetworkFlag] = "" + }), + isValid: false, + }, + { + description: "transfer network invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4TransferNetworkFlag] = "invalid-cidr" + }), + isValid: false, + }, + { + description: "region empty", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[globalflags.RegionFlag] = "" + }), + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + testutils.TestParseInput(t, NewCmd, parseInput, tt.expectedModel, tt.argValues, tt.flagValues, tt.isValid) + }) + } +} + +func TestBuildRequest(t *testing.T) { + tests := []struct { + description string + model *inputModel + expectedRequest iaas.ApiCreateNetworkAreaRegionRequest + }{ + { + description: "base", + model: fixtureInputModel(), + expectedRequest: fixtureRequest(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequest(testCtx, tt.model, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + region string + networkAreaLabel string + regionalArea iaas.RegionalArea + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "set empty regional area", + args: args{ + regionalArea: iaas.RegionalArea{}, + }, + wantErr: false, + }, + { + name: "output json", + args: args{ + outputFormat: print.JSONOutputFormat, + regionalArea: iaas.RegionalArea{}, + }, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.region, tt.args.networkAreaLabel, tt.args.regionalArea); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/network-area/region/delete/delete.go b/internal/cmd/network-area/region/delete/delete.go new file mode 100644 index 000000000..37f1f8bb0 --- /dev/null +++ b/internal/cmd/network-area/region/delete/delete.go @@ -0,0 +1,129 @@ +package delete + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" + "github.com/stackitcloud/stackit-cli/internal/pkg/errors" + "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/flags" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" + iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" + "github.com/stackitcloud/stackit-sdk-go/services/iaas/wait" +) + +const ( + networkAreaIdFlag = "network-area-id" + organizationIdFlag = "organization-id" +) + +type inputModel struct { + *globalflags.GlobalFlagModel + OrganizationId string + NetworkAreaId string +} + +func NewCmd(params *params.CmdParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "delete", + Short: "Deletes a regional configuration for a STACKIT Network Area (SNA)", + Long: "Deletes a regional configuration for a STACKIT Network Area (SNA).", + Args: args.NoArgs, + Example: examples.Build( + examples.NewExample( + `Delete a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, + `$ stackit network-area region delete --network-area-id xxx --region eu02 --organization-id yyy`, + ), + examples.NewExample( + `Delete a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", using the set region config`, + `$ stackit config set --region eu02`, + `$ stackit network-area region delete --network-area-id xxx --organization-id yyy`, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + model, err := parseInput(params.Printer, cmd, args) + if err != nil { + return err + } + + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + if err != nil { + return err + } + + // Get network area label + networkAreaName, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) + networkAreaName = model.NetworkAreaId + } + + if !model.AssumeYes { + prompt := fmt.Sprintf("Are you sure you want to delete the regional configuration %q for STACKIT Network Area (SNA) %q?", model.Region, networkAreaName) + err = params.Printer.PromptForConfirmation(prompt) + if err != nil { + return err + } + } + + // Call API + req := buildRequest(ctx, model, apiClient) + err = req.Execute() + if err != nil { + return fmt.Errorf("delete network area region: %w", err) + } + + if !model.Async { + s := spinner.New(params.Printer) + s.Start("Delete network area region") + _, err = wait.DeleteNetworkAreaRegionWaitHandler(ctx, apiClient, model.OrganizationId, model.NetworkAreaId, model.Region).WaitWithContext(ctx) + if err != nil { + return fmt.Errorf("wait for network area region deletion: %w", err) + } + s.Stop() + } + + params.Printer.Outputf("Delete regional network area %q for %q\n", model.Region, networkAreaName) + return nil + }, + } + configureFlags(cmd) + return cmd +} + +func configureFlags(cmd *cobra.Command) { + cmd.Flags().Var(flags.UUIDFlag(), networkAreaIdFlag, "STACKIT Network Area (SNA) ID") + cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") + + err := flags.MarkFlagsRequired(cmd, networkAreaIdFlag, organizationIdFlag) + cobra.CheckErr(err) +} + +func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { + globalFlags := globalflags.Parse(p, cmd) + if globalFlags.Region == "" { + return nil, &errors.RegionError{} + } + + model := inputModel{ + GlobalFlagModel: globalFlags, + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + } + + p.DebugInputModel(model) + return &model, nil +} + +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteNetworkAreaRegionRequest { + return apiClient.DeleteNetworkAreaRegion(ctx, model.OrganizationId, model.NetworkAreaId, model.Region) +} diff --git a/internal/cmd/network-area/region/delete/delete_test.go b/internal/cmd/network-area/region/delete/delete_test.go new file mode 100644 index 000000000..919e86cb8 --- /dev/null +++ b/internal/cmd/network-area/region/delete/delete_test.go @@ -0,0 +1,168 @@ +package delete + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + testRegion = "eu01" +) + +type testCtxKey struct{} + +var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") +var testClient = &iaas.APIClient{} + +var ( + testAreaId = uuid.NewString() + testOrgId = uuid.NewString() +) + +func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + + networkAreaIdFlag: testAreaId, + organizationIdFlag: testOrgId, + } + for _, mod := range mods { + mod(flagValues) + } + return flagValues +} + +func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { + model := &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, + OrganizationId: testOrgId, + NetworkAreaId: testAreaId, + } + for _, mod := range mods { + mod(model) + } + return model +} + +func fixtureRequest(mods ...func(request *iaas.ApiDeleteNetworkAreaRegionRequest)) iaas.ApiDeleteNetworkAreaRegionRequest { + request := testClient.DeleteNetworkAreaRegion(testCtx, testOrgId, testAreaId, testRegion) + for _, mod := range mods { + mod(&request) + } + return request +} + +func TestParseInput(t *testing.T) { + tests := []struct { + description string + argValues []string + flagValues map[string]string + isValid bool + expectedModel *inputModel + }{ + { + description: "base", + flagValues: fixtureFlagValues(), + isValid: true, + expectedModel: fixtureInputModel(), + }, + { + description: "no values", + flagValues: map[string]string{}, + isValid: false, + }, + { + description: "area id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, networkAreaIdFlag) + }), + isValid: false, + }, + { + description: "area id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "" + }), + isValid: false, + }, + { + description: "area id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "org id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, organizationIdFlag) + }), + isValid: false, + }, + { + description: "org id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "" + }), + isValid: false, + }, + { + description: "org id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "region empty", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[globalflags.RegionFlag] = "" + }), + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + testutils.TestParseInput(t, NewCmd, parseInput, tt.expectedModel, tt.argValues, tt.flagValues, tt.isValid) + }) + } +} + +func TestBuildRequest(t *testing.T) { + tests := []struct { + description string + model *inputModel + expectedRequest iaas.ApiDeleteNetworkAreaRegionRequest + }{ + { + description: "base", + model: fixtureInputModel(), + expectedRequest: fixtureRequest(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequest(testCtx, tt.model, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} diff --git a/internal/cmd/network-area/region/describe/describe.go b/internal/cmd/network-area/region/describe/describe.go new file mode 100644 index 000000000..71e4f5c31 --- /dev/null +++ b/internal/cmd/network-area/region/describe/describe.go @@ -0,0 +1,169 @@ +package describe + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" + "github.com/stackitcloud/stackit-cli/internal/pkg/errors" + "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/flags" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" + iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/tables" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + networkAreaIdFlag = "network-area-id" + organizationIdFlag = "organization-id" +) + +type inputModel struct { + *globalflags.GlobalFlagModel + OrganizationId string + NetworkAreaId string +} + +func NewCmd(params *params.CmdParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "describe", + Short: "Describes a regional configuration for a STACKIT Network Area (SNA)", + Long: "Describes a regional configuration for a STACKIT Network Area (SNA).", + Args: args.NoArgs, + Example: examples.Build( + examples.NewExample( + `Describe a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, + `$ stackit network-area region describe --network-area-id xxx --region eu02 --organization-id yyy`, + ), + examples.NewExample( + `Describe a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", using the set region config`, + `$ stackit config set --region eu02`, + `$ stackit network-area region describe --network-area-id xxx --organization-id yyy`, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + model, err := parseInput(params.Printer, cmd, args) + if err != nil { + return err + } + + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + if err != nil { + return err + } + + // Get network area label + networkAreaName, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) + // Set explicit the networkAreaName to empty string and not to the ID, because this is used for the table output + networkAreaName = "" + } + + // Call API + req := buildRequest(ctx, model, apiClient) + resp, err := req.Execute() + if err != nil { + return fmt.Errorf("describe network area region: %w", err) + } + + if resp == nil || resp.Ipv4 == nil { + return fmt.Errorf("empty response from API") + } + + return outputResult(params.Printer, model.OutputFormat, model.Region, model.NetworkAreaId, networkAreaName, *resp) + }, + } + configureFlags(cmd) + return cmd +} + +func configureFlags(cmd *cobra.Command) { + cmd.Flags().Var(flags.UUIDFlag(), networkAreaIdFlag, "STACKIT Network Area (SNA) ID") + cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") + + err := flags.MarkFlagsRequired(cmd, networkAreaIdFlag, organizationIdFlag) + cobra.CheckErr(err) +} + +func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { + globalFlags := globalflags.Parse(p, cmd) + if globalFlags.Region == "" { + return nil, &errors.RegionError{} + } + + model := inputModel{ + GlobalFlagModel: globalFlags, + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + } + + p.DebugInputModel(model) + return &model, nil +} + +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetNetworkAreaRegionRequest { + return apiClient.GetNetworkAreaRegion(ctx, model.OrganizationId, model.NetworkAreaId, model.Region) +} + +func outputResult(p *print.Printer, outputFormat, region, areaId, areaName string, regionalArea iaas.RegionalArea) error { + return p.OutputResult(outputFormat, regionalArea, func() error { + table := tables.NewTable() + table.AddRow("ID", areaId) + table.AddSeparator() + if areaName != "" { + table.AddRow("NAME", areaName) + table.AddSeparator() + } + table.AddRow("REGION", region) + table.AddSeparator() + table.AddRow("STATUS", utils.PtrString(regionalArea.Status)) + table.AddSeparator() + if ipv4 := regionalArea.Ipv4; ipv4 != nil { + if ipv4.NetworkRanges != nil { + var networkRanges []string + for _, networkRange := range *ipv4.NetworkRanges { + if networkRange.Prefix != nil { + networkRanges = append(networkRanges, *networkRange.Prefix) + } + } + table.AddRow("NETWORK RANGES", strings.Join(networkRanges, ",")) + table.AddSeparator() + } + if transferNetwork := ipv4.TransferNetwork; transferNetwork != nil { + table.AddRow("TRANSFER RANGE", utils.PtrString(transferNetwork)) + table.AddSeparator() + } + if defaultNameserver := ipv4.DefaultNameservers; defaultNameserver != nil && len(*defaultNameserver) > 0 { + table.AddRow("DNS NAME SERVERS", strings.Join(*defaultNameserver, ",")) + table.AddSeparator() + } + if defaultPrefixLength := ipv4.DefaultPrefixLen; defaultPrefixLength != nil { + table.AddRow("DEFAULT PREFIX LENGTH", utils.PtrString(defaultPrefixLength)) + table.AddSeparator() + } + if maxPrefixLength := ipv4.MaxPrefixLen; maxPrefixLength != nil { + table.AddRow("MAX PREFIX LENGTH", utils.PtrString(maxPrefixLength)) + table.AddSeparator() + } + if minPrefixLen := ipv4.MinPrefixLen; minPrefixLen != nil { + table.AddRow("MIN PREFIX LENGTH", utils.PtrString(minPrefixLen)) + table.AddSeparator() + } + } + + if err := table.Display(p); err != nil { + return fmt.Errorf("render table: %w", err) + } + return nil + }) +} diff --git a/internal/cmd/network-area/region/describe/describe_test.go b/internal/cmd/network-area/region/describe/describe_test.go new file mode 100644 index 000000000..7d06c1794 --- /dev/null +++ b/internal/cmd/network-area/region/describe/describe_test.go @@ -0,0 +1,214 @@ +package describe + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + testRegion = "eu01" +) + +type testCtxKey struct{} + +var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") +var testClient = &iaas.APIClient{} + +var ( + testAreaId = uuid.NewString() + testOrgId = uuid.NewString() +) + +func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + + networkAreaIdFlag: testAreaId, + organizationIdFlag: testOrgId, + } + for _, mod := range mods { + mod(flagValues) + } + return flagValues +} + +func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { + model := &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, + OrganizationId: testOrgId, + NetworkAreaId: testAreaId, + } + for _, mod := range mods { + mod(model) + } + return model +} + +func fixtureRequest(mods ...func(request *iaas.ApiGetNetworkAreaRegionRequest)) iaas.ApiGetNetworkAreaRegionRequest { + request := testClient.GetNetworkAreaRegion(testCtx, testOrgId, testAreaId, testRegion) + for _, mod := range mods { + mod(&request) + } + return request +} + +func TestParseInput(t *testing.T) { + tests := []struct { + description string + argValues []string + flagValues map[string]string + isValid bool + expectedModel *inputModel + }{ + { + description: "base", + flagValues: fixtureFlagValues(), + isValid: true, + expectedModel: fixtureInputModel(), + }, + { + description: "no values", + flagValues: map[string]string{}, + isValid: false, + }, + { + description: "org id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, organizationIdFlag) + }), + isValid: false, + }, + { + description: "org id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "" + }), + isValid: false, + }, + { + description: "org id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "area id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, networkAreaIdFlag) + }), + isValid: false, + }, + { + description: "area id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "" + }), + isValid: false, + }, + { + description: "area id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "region empty", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[globalflags.RegionFlag] = "" + }), + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + testutils.TestParseInput(t, NewCmd, parseInput, tt.expectedModel, tt.argValues, tt.flagValues, tt.isValid) + }) + } +} + +func TestBuildRequest(t *testing.T) { + tests := []struct { + description string + model *inputModel + expectedRequest iaas.ApiGetNetworkAreaRegionRequest + }{ + { + description: "base", + model: fixtureInputModel(), + expectedRequest: fixtureRequest(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequest(testCtx, tt.model, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + areaId string + region string + networkAreaLabel string + regionalArea iaas.RegionalArea + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "set empty regional area", + args: args{ + regionalArea: iaas.RegionalArea{}, + }, + wantErr: false, + }, + { + name: "output json", + args: args{ + outputFormat: print.JSONOutputFormat, + regionalArea: iaas.RegionalArea{}, + }, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.region, tt.args.areaId, tt.args.networkAreaLabel, tt.args.regionalArea); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/network-area/region/list/list.go b/internal/cmd/network-area/region/list/list.go new file mode 100644 index 000000000..44149c9af --- /dev/null +++ b/internal/cmd/network-area/region/list/list.go @@ -0,0 +1,153 @@ +package list + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" + "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/flags" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" + iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/tables" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + networkAreaIdFlag = "network-area-id" + organizationIdFlag = "organization-id" +) + +type inputModel struct { + *globalflags.GlobalFlagModel + OrganizationId string + NetworkAreaId string +} + +func NewCmd(params *params.CmdParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "Lists all configured regions for a STACKIT Network Area (SNA)", + Long: "Lists all configured regions for a STACKIT Network Area (SNA).", + Args: args.NoArgs, + Example: examples.Build( + examples.NewExample( + `List all configured region for a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, + `$ stackit network-area region list --network-area-id xxx --organization-id yyy`, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + model, err := parseInput(params.Printer, cmd, args) + if err != nil { + return err + } + + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + if err != nil { + return err + } + + // Get network area label + networkAreaLabel, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) + networkAreaLabel = model.NetworkAreaId + } + + // Call API + req := buildRequest(ctx, model, apiClient) + resp, err := req.Execute() + if err != nil { + return fmt.Errorf("list network area region: %w", err) + } + + if resp == nil { + return fmt.Errorf("empty response from API") + } + + return outputResult(params.Printer, model.OutputFormat, networkAreaLabel, *resp) + }, + } + configureFlags(cmd) + return cmd +} + +func configureFlags(cmd *cobra.Command) { + cmd.Flags().Var(flags.UUIDFlag(), networkAreaIdFlag, "STACKIT Network Area (SNA) ID") + cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") + + err := flags.MarkFlagsRequired(cmd, networkAreaIdFlag, organizationIdFlag) + cobra.CheckErr(err) +} + +func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { + globalFlags := globalflags.Parse(p, cmd) + + model := inputModel{ + GlobalFlagModel: globalFlags, + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + } + + p.DebugInputModel(model) + return &model, nil +} + +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworkAreaRegionsRequest { + return apiClient.ListNetworkAreaRegions(ctx, model.OrganizationId, model.NetworkAreaId) +} + +func outputResult(p *print.Printer, outputFormat, areaLabel string, regionalArea iaas.RegionalAreaListResponse) error { + return p.OutputResult(outputFormat, regionalArea, func() error { + if regionalArea.Regions == nil || len(*regionalArea.Regions) == 0 { + p.Outputf("No regions found for network area %q\n", areaLabel) + return nil + } + + table := tables.NewTable() + table.SetHeader("REGION", "STATUS", "DNS NAME SERVERS", "NETWORK RANGES", "TRANSFER NETWORK") + for region, regionConfig := range *regionalArea.Regions { + var dnsNames string + var networkRanges []string + var transferNetwork string + + if ipv4 := regionConfig.Ipv4; ipv4 != nil { + // Set dnsNames + dnsNames = utils.JoinStringPtr(ipv4.DefaultNameservers, ",") + + // Set networkRanges + if ipv4.NetworkRanges != nil && len(*ipv4.NetworkRanges) > 0 { + for _, networkRange := range *ipv4.NetworkRanges { + if networkRange.Prefix != nil { + networkRanges = append(networkRanges, *networkRange.Prefix) + } + } + } + + // Set transferNetwork + transferNetwork = utils.PtrString(ipv4.TransferNetwork) + } + + table.AddRow( + region, + utils.PtrString(regionConfig.Status), + dnsNames, + strings.Join(networkRanges, ","), + transferNetwork, + ) + } + + if err := table.Display(p); err != nil { + return fmt.Errorf("render table: %w", err) + } + return nil + }) +} diff --git a/internal/cmd/network-area/region/list/list_test.go b/internal/cmd/network-area/region/list/list_test.go new file mode 100644 index 000000000..bb7b3f15b --- /dev/null +++ b/internal/cmd/network-area/region/list/list_test.go @@ -0,0 +1,221 @@ +package list + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +type testCtxKey struct{} + +var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") +var testClient = &iaas.APIClient{} + +var ( + testAreaId = uuid.NewString() + testOrgId = uuid.NewString() +) + +func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := map[string]string{ + networkAreaIdFlag: testAreaId, + organizationIdFlag: testOrgId, + } + for _, mod := range mods { + mod(flagValues) + } + return flagValues +} + +func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { + model := &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + OrganizationId: testOrgId, + NetworkAreaId: testAreaId, + } + for _, mod := range mods { + mod(model) + } + return model +} + +func fixtureRequest(mods ...func(request *iaas.ApiListNetworkAreaRegionsRequest)) iaas.ApiListNetworkAreaRegionsRequest { + request := testClient.ListNetworkAreaRegions(testCtx, testOrgId, testAreaId) + for _, mod := range mods { + mod(&request) + } + return request +} + +func TestParseInput(t *testing.T) { + tests := []struct { + description string + argValues []string + flagValues map[string]string + isValid bool + expectedModel *inputModel + }{ + { + description: "base", + flagValues: fixtureFlagValues(), + isValid: true, + expectedModel: fixtureInputModel(), + }, + { + description: "no values", + flagValues: map[string]string{}, + isValid: false, + }, + { + description: "org id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, organizationIdFlag) + }), + isValid: false, + }, + { + description: "org id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "" + }), + isValid: false, + }, + { + description: "org id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "area id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, networkAreaIdFlag) + }), + isValid: false, + }, + { + description: "area id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "" + }), + isValid: false, + }, + { + description: "area id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + testutils.TestParseInput(t, NewCmd, parseInput, tt.expectedModel, tt.argValues, tt.flagValues, tt.isValid) + }) + } +} + +func TestBuildRequest(t *testing.T) { + tests := []struct { + description string + model *inputModel + expectedRequest iaas.ApiListNetworkAreaRegionsRequest + }{ + { + description: "base", + model: fixtureInputModel(), + expectedRequest: fixtureRequest(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequest(testCtx, tt.model, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + networkAreaLabel string + regionalArea iaas.RegionalAreaListResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "set empty response", + args: args{ + regionalArea: iaas.RegionalAreaListResponse{}, + }, + wantErr: false, + }, + { + name: "set nil for regions map in response", + args: args{ + regionalArea: iaas.RegionalAreaListResponse{ + Regions: nil, + }, + }, + wantErr: false, + }, + { + name: "set empty map for regions map in response", + args: args{ + regionalArea: iaas.RegionalAreaListResponse{ + Regions: utils.Ptr(map[string]iaas.RegionalArea{}), + }, + }, + wantErr: false, + }, + { + name: "set empty region in response", + args: args{ + regionalArea: iaas.RegionalAreaListResponse{ + Regions: utils.Ptr(map[string]iaas.RegionalArea{ + "eu01": {}, + }), + }, + }, + wantErr: false, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.networkAreaLabel, tt.args.regionalArea); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/network-area/region/region.go b/internal/cmd/network-area/region/region.go new file mode 100644 index 000000000..99edcace2 --- /dev/null +++ b/internal/cmd/network-area/region/region.go @@ -0,0 +1,34 @@ +package region + +import ( + "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/region/create" + "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/region/delete" + "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/region/describe" + "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/region/list" + "github.com/stackitcloud/stackit-cli/internal/cmd/network-area/region/update" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + + "github.com/spf13/cobra" +) + +func NewCmd(params *params.CmdParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "region", + Short: "Provides functionality for regional configuration of STACKIT Network Area (SNA)", + Long: "Provides functionality for regional configuration of STACKIT Network Area (SNA).", + Args: args.NoArgs, + Run: utils.CmdHelp, + } + addSubcommands(cmd, params) + return cmd +} + +func addSubcommands(cmd *cobra.Command, params *params.CmdParams) { + cmd.AddCommand(create.NewCmd(params)) + cmd.AddCommand(describe.NewCmd(params)) + cmd.AddCommand(delete.NewCmd(params)) + cmd.AddCommand(update.NewCmd(params)) + cmd.AddCommand(list.NewCmd(params)) +} diff --git a/internal/cmd/network-area/region/update/update.go b/internal/cmd/network-area/region/update/update.go new file mode 100644 index 000000000..9018cb175 --- /dev/null +++ b/internal/cmd/network-area/region/update/update.go @@ -0,0 +1,165 @@ +package update + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" + "github.com/stackitcloud/stackit-cli/internal/pkg/errors" + "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/flags" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" + iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + networkAreaIdFlag = "network-area-id" + organizationIdFlag = "organization-id" + ipv4DefaultNameservers = "ipv4-default-nameservers" + ipv4DefaultPrefixLengthFlag = "ipv4-default-prefix-length" + ipv4MaxPrefixLengthFlag = "ipv4-max-prefix-length" + ipv4MinPrefixLengthFlag = "ipv4-min-prefix-length" +) + +type inputModel struct { + *globalflags.GlobalFlagModel + OrganizationId string + NetworkAreaId string + + IPv4DefaultNameservers *[]string + IPv4DefaultPrefixLength *int64 + IPv4MaxPrefixLength *int64 + IPv4MinPrefixLength *int64 +} + +func NewCmd(params *params.CmdParams) *cobra.Command { + cmd := &cobra.Command{ + Use: "update", + Short: "Updates a existing regional configuration for a STACKIT Network Area (SNA)", + Long: "Updates a existing regional configuration for a STACKIT Network Area (SNA).", + Args: args.NoArgs, + Example: examples.Build( + examples.NewExample( + `Update a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" with new ipv4-default-nameservers "8.8.8.8"`, + `$ stackit network-area region update --network-area-id xxx --region eu02 --organization-id yyy --ipv4-default-nameservers 8.8.8.8`, + ), + examples.NewExample( + `Update a regional configuration "eu02" for a STACKIT Network Area with ID "xxx" in organization with ID "yyy" with new ipv4-default-nameservers "8.8.8.8", using the set region config`, + `$ stackit config set --region eu02`, + `$ stackit network-area region update --network-area-id xxx --organization-id yyy --ipv4-default-nameservers 8.8.8.8`, + ), + examples.NewExample( + `Update a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20"`, + `$ stackit network-area region update --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20`, + ), + examples.NewExample( + `Update a new regional configuration for a STACKIT Network Area with ID "xxx" in organization with ID "yyy", ipv4 network range "192.168.0.0/24", ipv4 transfer network "192.168.1.0/24", default prefix length "24", max prefix length "25" and min prefix length "20"`, + `$ stackit network-area region update --network-area-id xxx --organization-id yyy --ipv4-network-ranges 192.168.0.0/24 --ipv4-transfer-network 192.168.1.0/24 --region "eu02" --ipv4-default-prefix-length 24 --ipv4-max-prefix-length 25 --ipv4-min-prefix-length 20`, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + model, err := parseInput(params.Printer, cmd, args) + if err != nil { + return err + } + + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + if err != nil { + return err + } + + // Get network area label + networkAreaLabel, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) + networkAreaLabel = model.NetworkAreaId + } + + if !model.AssumeYes { + prompt := fmt.Sprintf("Are you sure you want to update the regional configuration %q for STACKIT Network Area (SNA) %q?", model.Region, networkAreaLabel) + err = params.Printer.PromptForConfirmation(prompt) + if err != nil { + return err + } + } + + // Call API + req := buildRequest(ctx, model, apiClient) + resp, err := req.Execute() + if err != nil { + return fmt.Errorf("update network area region: %w", err) + } + + if resp == nil || resp.Ipv4 == nil { + return fmt.Errorf("empty response from API") + } + + return outputResult(params.Printer, model.OutputFormat, model.Region, networkAreaLabel, *resp) + }, + } + configureFlags(cmd) + return cmd +} + +func configureFlags(cmd *cobra.Command) { + cmd.Flags().Var(flags.UUIDFlag(), networkAreaIdFlag, "STACKIT Network Area (SNA) ID") + cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") + cmd.Flags().StringSlice(ipv4DefaultNameservers, nil, "List of default DNS name server IPs") + cmd.Flags().Int64(ipv4DefaultPrefixLengthFlag, 0, "The default prefix length for networks in the network area") + cmd.Flags().Int64(ipv4MaxPrefixLengthFlag, 0, "The maximum prefix length for networks in the network area") + cmd.Flags().Int64(ipv4MinPrefixLengthFlag, 0, "The minimum prefix length for networks in the network area") + + // At least one of the flags is required, otherwise there is nothing to update + cmd.MarkFlagsOneRequired(ipv4DefaultNameservers, ipv4MaxPrefixLengthFlag, ipv4MinPrefixLengthFlag, ipv4DefaultPrefixLengthFlag) + + err := flags.MarkFlagsRequired(cmd, networkAreaIdFlag, organizationIdFlag) + cobra.CheckErr(err) +} + +func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { + globalFlags := globalflags.Parse(p, cmd) + if globalFlags.Region == "" { + return nil, &errors.RegionError{} + } + + model := inputModel{ + GlobalFlagModel: globalFlags, + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + IPv4DefaultNameservers: flags.FlagToStringSlicePointer(p, cmd, ipv4DefaultNameservers), + IPv4DefaultPrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4DefaultPrefixLengthFlag), + IPv4MaxPrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4MaxPrefixLengthFlag), + IPv4MinPrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4MinPrefixLengthFlag), + } + + p.DebugInputModel(model) + return &model, nil +} + +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateNetworkAreaRegionRequest { + req := apiClient.UpdateNetworkAreaRegion(ctx, model.OrganizationId, model.NetworkAreaId, model.Region) + + payload := iaas.UpdateNetworkAreaRegionPayload{ + Ipv4: &iaas.UpdateRegionalAreaIPv4{ + DefaultNameservers: model.IPv4DefaultNameservers, + DefaultPrefixLen: model.IPv4DefaultPrefixLength, + MaxPrefixLen: model.IPv4MaxPrefixLength, + MinPrefixLen: model.IPv4MinPrefixLength, + }, + } + return req.UpdateNetworkAreaRegionPayload(payload) +} + +func outputResult(p *print.Printer, outputFormat, region, networkAreaLabel string, regionalArea iaas.RegionalArea) error { + return p.OutputResult(outputFormat, regionalArea, func() error { + p.Outputf("Updated region configuration for SNA %q.\nRegion: %s\n", networkAreaLabel, region) + return nil + }) +} diff --git a/internal/cmd/network-area/region/update/update_test.go b/internal/cmd/network-area/region/update/update_test.go new file mode 100644 index 000000000..73482555d --- /dev/null +++ b/internal/cmd/network-area/region/update/update_test.go @@ -0,0 +1,265 @@ +package update + +import ( + "context" + "strconv" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +const ( + testRegion = "eu01" + testDefaultPrefixLength int64 = 25 + testMaxPrefixLength int64 = 29 + testMinPrefixLength int64 = 24 +) + +type testCtxKey struct{} + +var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") +var testClient = &iaas.APIClient{} + +var ( + testAreaId = uuid.NewString() + testOrgId = uuid.NewString() + testDefaultNameservers = []string{"8.8.8.8", "8.8.4.4"} + testNetworkRanges = []string{"192.168.0.0/24", "10.0.0.0/24"} +) + +func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + + networkAreaIdFlag: testAreaId, + organizationIdFlag: testOrgId, + ipv4DefaultNameservers: strings.Join(testDefaultNameservers, ","), + ipv4DefaultPrefixLengthFlag: strconv.FormatInt(testDefaultPrefixLength, 10), + ipv4MaxPrefixLengthFlag: strconv.FormatInt(testMaxPrefixLength, 10), + ipv4MinPrefixLengthFlag: strconv.FormatInt(testMinPrefixLength, 10), + } + for _, mod := range mods { + mod(flagValues) + } + return flagValues +} + +func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { + model := &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, + OrganizationId: testOrgId, + NetworkAreaId: testAreaId, + IPv4DefaultNameservers: utils.Ptr(testDefaultNameservers), + IPv4DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + IPv4MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + IPv4MinPrefixLength: utils.Ptr(testMinPrefixLength), + } + for _, mod := range mods { + mod(model) + } + return model +} + +func fixtureRequest(mods ...func(request *iaas.ApiUpdateNetworkAreaRegionRequest)) iaas.ApiUpdateNetworkAreaRegionRequest { + request := testClient.UpdateNetworkAreaRegion(testCtx, testOrgId, testAreaId, testRegion) + request = request.UpdateNetworkAreaRegionPayload(fixturePayload()) + for _, mod := range mods { + mod(&request) + } + return request +} + +func fixturePayload(mods ...func(payload *iaas.UpdateNetworkAreaRegionPayload)) iaas.UpdateNetworkAreaRegionPayload { + var networkRange []iaas.NetworkRange + if len(testNetworkRanges) > 0 { + networkRange = make([]iaas.NetworkRange, len(testNetworkRanges)) + for i := range testNetworkRanges { + networkRange[i] = iaas.NetworkRange{ + Prefix: utils.Ptr(testNetworkRanges[i]), + } + } + } + + payload := iaas.UpdateNetworkAreaRegionPayload{ + Ipv4: &iaas.UpdateRegionalAreaIPv4{ + DefaultNameservers: utils.Ptr(testDefaultNameservers), + DefaultPrefixLen: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLen: utils.Ptr(testMaxPrefixLength), + MinPrefixLen: utils.Ptr(testMinPrefixLength), + }, + } + for _, mod := range mods { + mod(&payload) + } + return payload +} + +func TestParseInput(t *testing.T) { + tests := []struct { + description string + argValues []string + flagValues map[string]string + isValid bool + expectedModel *inputModel + }{ + { + description: "base", + flagValues: fixtureFlagValues(), + isValid: true, + expectedModel: fixtureInputModel(), + }, + { + description: "no values", + flagValues: map[string]string{}, + isValid: false, + }, + { + description: "org id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, organizationIdFlag) + }), + isValid: false, + }, + { + description: "org id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "" + }), + isValid: false, + }, + { + description: "org id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[organizationIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "area id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, networkAreaIdFlag) + }), + isValid: false, + }, + { + description: "area id invalid 1", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "" + }), + isValid: false, + }, + { + description: "area id invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[networkAreaIdFlag] = "invalid-uuid" + }), + isValid: false, + }, + { + description: "no update data is set", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, ipv4DefaultPrefixLengthFlag) + delete(flagValues, ipv4MaxPrefixLengthFlag) + delete(flagValues, ipv4MinPrefixLengthFlag) + delete(flagValues, ipv4DefaultNameservers) + }), + isValid: false, + }, + { + description: "region empty", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[globalflags.RegionFlag] = "" + }), + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + testutils.TestParseInput(t, NewCmd, parseInput, tt.expectedModel, tt.argValues, tt.flagValues, tt.isValid) + }) + } +} + +func TestBuildRequest(t *testing.T) { + tests := []struct { + description string + model *inputModel + expectedRequest iaas.ApiUpdateNetworkAreaRegionRequest + }{ + { + description: "base", + model: fixtureInputModel(), + expectedRequest: fixtureRequest(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequest(testCtx, tt.model, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + region string + networkAreaLabel string + regionalArea iaas.RegionalArea + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "set empty regional area", + args: args{ + regionalArea: iaas.RegionalArea{}, + }, + wantErr: false, + }, + { + name: "output json", + args: args{ + outputFormat: print.JSONOutputFormat, + regionalArea: iaas.RegionalArea{}, + }, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.region, tt.args.networkAreaLabel, tt.args.regionalArea); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/network-area/route/create/create.go b/internal/cmd/network-area/route/create/create.go index f8548316c..c8950144e 100644 --- a/internal/cmd/network-area/route/create/create.go +++ b/internal/cmd/network-area/route/create/create.go @@ -3,6 +3,8 @@ package create import ( "context" "fmt" + "net" + "os" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" @@ -21,18 +23,39 @@ import ( const ( organizationIdFlag = "organization-id" networkAreaIdFlag = "network-area-id" - prefixFlag = "prefix" - nexthopFlag = "next-hop" - labelFlag = "labels" + // Deprecated: prefixFlag is deprecated and will be removed after April 2026. Use instead destinationFlag + prefixFlag = "prefix" + destinationFlag = "destination" + // Deprecated: nexthopFlag is deprecated and will be removed after April 2026. Use instead nexthopIPv4Flag or nexthopIPv6Flag + nexthopFlag = "next-hop" + nexthopIPv4Flag = "next-hop-ipv4" + nexthopIPv6Flag = "next-hop-ipv6" + nexthopBlackholeFlag = "nexthop-blackhole" + nexthopInternetFlag = "nexthop-internet" + labelFlag = "labels" +) + +const ( + destinationCIDRv4Type = "cidrv4" + destinationCIDRv6Type = "cidrv6" + + nexthopBlackholeType = "blackhole" + nexthopInternetType = "internet" + nexthopIPv4Type = "ipv4" + nexthopIPv6Type = "ipv6" ) type inputModel struct { *globalflags.GlobalFlagModel - OrganizationId *string - NetworkAreaId *string - Prefix *string - Nexthop *string - Labels *map[string]string + OrganizationId *string + NetworkAreaId *string + DestinationV4 *string + DestinationV6 *string + NexthopV4 *string + NexthopV6 *string + NexthopBlackhole *bool + NexthopInternet *bool + Labels *map[string]string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -46,12 +69,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { Args: args.NoArgs, Example: examples.Build( examples.NewExample( - `Create a static route with prefix "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, - "$ stackit network-area route create --organization-id yyy --network-area-id xxx --prefix 1.1.1.0/24 --next-hop 1.1.1.1", + `Create a static route with destination "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, + "$ stackit network-area route create --organization-id yyy --network-area-id xxx --destination 1.1.1.0/24 --next-hop 1.1.1.1", ), examples.NewExample( - `Create a static route with labels "key:value" and "foo:bar" with prefix "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, - "$ stackit network-area route create --labels key=value,foo=bar --organization-id yyy --network-area-id xxx --prefix 1.1.1.0/24 --next-hop 1.1.1.1", + `Create a static route with labels "key:value" and "foo:bar" with destination "1.1.1.0/24" and next hop "1.1.1.1" in a STACKIT Network Area with ID "xxx" in organization with ID "yyy"`, + "$ stackit network-area route create --labels key=value,foo=bar --organization-id yyy --network-area-id xxx --destination 1.1.1.0/24 --next-hop 1.1.1.1", ), ), RunE: func(cmd *cobra.Command, args []string) error { @@ -93,7 +116,27 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return fmt.Errorf("empty response from API") } - route, err := iaasUtils.GetRouteFromAPIResponse(*model.Prefix, *model.Nexthop, resp.Items) + var destination string + var nexthop string + if model.DestinationV4 != nil { + destination = *model.DestinationV4 + } else if model.DestinationV6 != nil { + destination = *model.DestinationV6 + } + + if model.NexthopV4 != nil { + nexthop = *model.NexthopV4 + } else if model.NexthopV6 != nil { + nexthop = *model.NexthopV6 + } else if model.NexthopBlackhole != nil { + // For nexthopBlackhole the type is assigned to nexthop, because it doesn't have any value + nexthop = nexthopBlackholeType + } else if model.NexthopInternet != nil { + // For nexthopInternet the type is assigned to nexthop, because it doesn't have any value + nexthop = nexthopInternetType + } + + route, err := iaasUtils.GetRouteFromAPIResponse(destination, nexthop, resp.Items) if err != nil { return err } @@ -109,23 +152,83 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Var(flags.UUIDFlag(), organizationIdFlag, "Organization ID") cmd.Flags().Var(flags.UUIDFlag(), networkAreaIdFlag, "STACKIT Network Area ID") cmd.Flags().Var(flags.CIDRFlag(), prefixFlag, "Static route prefix") - cmd.Flags().String(nexthopFlag, "", "Next hop IP address. Must be a valid IPv4") + cmd.Flags().Var(flags.CIDRFlag(), destinationFlag, "Destination route. Must be a valid IPv4 or IPv6 CIDR") + cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a route. A label can be provided with the format key=value and the flag can be used multiple times to provide a list of labels") + cmd.Flags().String(nexthopFlag, "", "Next hop IP address. Must be a valid IPv4") + cmd.Flags().String(nexthopIPv4Flag, "", "Next hop IPv4 address") + cmd.Flags().String(nexthopIPv6Flag, "", "Next hop IPv6 address") + cmd.Flags().Bool(nexthopBlackholeFlag, false, "Sets next hop to black hole") + cmd.Flags().Bool(nexthopInternetFlag, false, "Sets next hop to internet") - err := flags.MarkFlagsRequired(cmd, organizationIdFlag, networkAreaIdFlag, prefixFlag, nexthopFlag) + cobra.CheckErr(cmd.Flags().MarkDeprecated(nexthopFlag, fmt.Sprintf("The flag %q is deprecated and will be removed after April 2026. Use instead %q to configure a IPv4 next hop.", nexthopFlag, nexthopBlackholeFlag))) + cobra.CheckErr(cmd.Flags().MarkDeprecated(prefixFlag, fmt.Sprintf("The flag %q is deprecated and will be removed after April 2026. Use instead %q to configure a destination.", prefixFlag, destinationFlag))) + // Set the output for deprecation warnings to stderr + cmd.Flags().SetOutput(os.Stderr) + + destinationFlags := []string{prefixFlag, destinationFlag} + nexthopFlags := []string{nexthopFlag, nexthopIPv4Flag, nexthopIPv6Flag, nexthopBlackholeFlag, nexthopInternetFlag} + cmd.MarkFlagsMutuallyExclusive(destinationFlags...) + cmd.MarkFlagsMutuallyExclusive(nexthopFlags...) + + cmd.MarkFlagsOneRequired(destinationFlags...) + cmd.MarkFlagsOneRequired(nexthopFlags...) + err := flags.MarkFlagsRequired(cmd, organizationIdFlag, networkAreaIdFlag) cobra.CheckErr(err) } +func parseDestination(input string) (destinationV4, destinationV6 *string, err error) { + ip, _, err := net.ParseCIDR(input) + if err != nil { + return nil, nil, fmt.Errorf("parse CIDR: %w", err) + } + if ip.To4() != nil { // CIDR is IPv4 + destinationV4 = utils.Ptr(input) + return destinationV4, nil, nil + } + // CIDR is IPv6 + destinationV6 = utils.Ptr(input) + return nil, destinationV6, nil +} + func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) + var destinationV4, destinationV6 *string + if destination := flags.FlagToStringPointer(p, cmd, destinationFlag); destination != nil { + var err error + destinationV4, destinationV6, err = parseDestination(*destination) + if err != nil { + return nil, err + } + } + if prefix := flags.FlagToStringPointer(p, cmd, prefixFlag); prefix != nil { + var err error + destinationV4, destinationV6, err = parseDestination(*prefix) + if err != nil { + return nil, err + } + } + + nexthopIPv4 := flags.FlagToStringPointer(p, cmd, nexthopIPv4Flag) + nexthopIPv6 := flags.FlagToStringPointer(p, cmd, nexthopIPv6Flag) + nexthopInternet := flags.FlagToBoolPointer(p, cmd, nexthopInternetFlag) + nexthopBlackhole := flags.FlagToBoolPointer(p, cmd, nexthopBlackholeFlag) + if nexthop := flags.FlagToStringPointer(p, cmd, nexthopFlag); nexthop != nil { + nexthopIPv4 = nexthop + } + model := inputModel{ - GlobalFlagModel: globalFlags, - OrganizationId: flags.FlagToStringPointer(p, cmd, organizationIdFlag), - NetworkAreaId: flags.FlagToStringPointer(p, cmd, networkAreaIdFlag), - Prefix: flags.FlagToStringPointer(p, cmd, prefixFlag), - Nexthop: flags.FlagToStringPointer(p, cmd, nexthopFlag), - Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag), + GlobalFlagModel: globalFlags, + OrganizationId: flags.FlagToStringPointer(p, cmd, organizationIdFlag), + NetworkAreaId: flags.FlagToStringPointer(p, cmd, networkAreaIdFlag), + DestinationV4: destinationV4, + DestinationV6: destinationV6, + NexthopV4: nexthopIPv4, + NexthopV6: nexthopIPv6, + NexthopBlackhole: nexthopBlackhole, + NexthopInternet: nexthopInternet, + Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag), } p.DebugInputModel(model) @@ -133,14 +236,62 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateNetworkAreaRouteRequest { - req := apiClient.CreateNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId) + req := apiClient.CreateNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) + + var destinationV4 *iaas.DestinationCIDRv4 + var destinationV6 *iaas.DestinationCIDRv6 + if model.DestinationV4 != nil { + destinationV4 = &iaas.DestinationCIDRv4{ + Type: utils.Ptr(destinationCIDRv4Type), + Value: model.DestinationV4, + } + } + if model.DestinationV6 != nil { + destinationV6 = &iaas.DestinationCIDRv6{ + Type: utils.Ptr(destinationCIDRv6Type), + Value: model.DestinationV6, + } + } + + var nexthopIPv4 *iaas.NexthopIPv4 + var nexthopIPv6 *iaas.NexthopIPv6 + var nexthopBlackhole *iaas.NexthopBlackhole + var nexthopInternet *iaas.NexthopInternet + + if model.NexthopV4 != nil { + nexthopIPv4 = &iaas.NexthopIPv4{ + Type: utils.Ptr(nexthopIPv4Type), + Value: model.NexthopV4, + } + } else if model.NexthopV6 != nil { + nexthopIPv6 = &iaas.NexthopIPv6{ + Type: utils.Ptr(nexthopIPv6Type), + Value: model.NexthopV6, + } + } else if model.NexthopBlackhole != nil { + nexthopBlackhole = &iaas.NexthopBlackhole{ + Type: utils.Ptr(nexthopBlackholeType), + } + } else if model.NexthopInternet != nil { + nexthopInternet = &iaas.NexthopInternet{ + Type: utils.Ptr(nexthopInternetType), + } + } payload := iaas.CreateNetworkAreaRoutePayload{ - Ipv4: &[]iaas.Route{ + Items: &[]iaas.Route{ { - Prefix: model.Prefix, - Nexthop: model.Nexthop, - Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: destinationV4, + DestinationCIDRv6: destinationV6, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: nexthopIPv4, + NexthopIPv6: nexthopIPv6, + NexthopBlackhole: nexthopBlackhole, + NexthopInternet: nexthopInternet, + }, + Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), }, }, } @@ -149,7 +300,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, route iaas.Route) error { return p.OutputResult(outputFormat, route, func() error { - p.Outputf("Created static route for SNA %q.\nStatic route ID: %s\n", networkAreaLabel, utils.PtrString(route.RouteId)) + p.Outputf("Created static route for SNA %q.\nStatic route ID: %s\n", networkAreaLabel, utils.PtrString(route.Id)) return nil }) } diff --git a/internal/cmd/network-area/route/create/create_test.go b/internal/cmd/network-area/route/create/create_test.go index 1bc7cb161..b3d577b80 100644 --- a/internal/cmd/network-area/route/create/create_test.go +++ b/internal/cmd/network-area/route/create/create_test.go @@ -16,6 +16,12 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" + testDestinationCIDRv4 = "1.1.1.0/24" + testNexthopIPv4 = "1.1.1.1" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -26,10 +32,12 @@ var testNetworkAreaId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, - prefixFlag: "1.1.1.0/24", - nexthopFlag: "1.1.1.1", + destinationFlag: testDestinationCIDRv4, + nexthopIPv4Flag: testNexthopIPv4, } for _, mod := range mods { mod(flagValues) @@ -41,11 +49,12 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: utils.Ptr(testOrgId), NetworkAreaId: utils.Ptr(testNetworkAreaId), - Prefix: utils.Ptr("1.1.1.0/24"), - Nexthop: utils.Ptr("1.1.1.1"), + DestinationV4: utils.Ptr(testDestinationCIDRv4), + NexthopV4: utils.Ptr(testNexthopIPv4), } for _, mod := range mods { mod(model) @@ -54,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateNetworkAreaRouteRequest)) iaas.ApiCreateNetworkAreaRouteRequest { - request := testClient.CreateNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId) + request := testClient.CreateNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRegion) request = request.CreateNetworkAreaRoutePayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -64,10 +73,20 @@ func fixtureRequest(mods ...func(request *iaas.ApiCreateNetworkAreaRouteRequest) func fixturePayload(mods ...func(payload *iaas.CreateNetworkAreaRoutePayload)) iaas.CreateNetworkAreaRoutePayload { payload := iaas.CreateNetworkAreaRoutePayload{ - Ipv4: &[]iaas.Route{ + Items: &[]iaas.Route{ { - Prefix: utils.Ptr("1.1.1.0/24"), - Nexthop: utils.Ptr("1.1.1.1"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Type: utils.Ptr(destinationCIDRv4Type), + Value: utils.Ptr(testDestinationCIDRv4), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Type: utils.Ptr(nexthopIPv4Type), + Value: utils.Ptr(testNexthopIPv4), + }, + }, }, }, } @@ -96,7 +115,7 @@ func TestParseInput(t *testing.T) { { description: "next hop missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, nexthopFlag) + delete(flagValues, nexthopIPv4Flag) }), isValid: false, }, @@ -148,23 +167,23 @@ func TestParseInput(t *testing.T) { isValid: false, }, { - description: "prefix missing", + description: "destination missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, prefixFlag) + delete(flagValues, destinationFlag) }), isValid: false, }, { - description: "prefix invalid 1", + description: "destinationFlag invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[prefixFlag] = "" + flagValues[destinationFlag] = "" }), isValid: false, }, { - description: "prefix invalid 2", + description: "destinationFlag invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[prefixFlag] = "invalid-prefix" + flagValues[destinationFlag] = "invalid-destinationFlag" }), isValid: false, }, @@ -178,6 +197,23 @@ func TestParseInput(t *testing.T) { }), isValid: true, }, + { + description: "conflicting destination and prefix set", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[prefixFlag] = testDestinationCIDRv4 + }), + isValid: false, + }, + { + description: "conflicting nexthop and nexthop-ipv4 set", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[nexthopFlag] = testNexthopIPv4 + }), + isValid: false, + }, + { + description: "conflicting nexthop and nexthop-ipv4 set", + }, } for _, tt := range tests { @@ -205,7 +241,7 @@ func TestBuildRequest(t *testing.T) { }), expectedRequest: fixtureRequest(func(request *iaas.ApiCreateNetworkAreaRouteRequest) { *request = (*request).CreateNetworkAreaRoutePayload(fixturePayload(func(payload *iaas.CreateNetworkAreaRoutePayload) { - (*payload.Ipv4)[0].Labels = utils.Ptr(map[string]interface{}{"key": "value"}) + (*payload.Items)[0].Labels = utils.Ptr(map[string]interface{}{"key": "value"}) })) }), }, diff --git a/internal/cmd/network-area/route/delete/delete.go b/internal/cmd/network-area/route/delete/delete.go index 254e7fb7a..b888fb6d5 100644 --- a/internal/cmd/network-area/route/delete/delete.go +++ b/internal/cmd/network-area/route/delete/delete.go @@ -110,6 +110,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteNetworkAreaRouteRequest { - req := apiClient.DeleteNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.RouteId) + req := apiClient.DeleteNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region, model.RouteId) return req } diff --git a/internal/cmd/network-area/route/delete/delete_test.go b/internal/cmd/network-area/route/delete/delete_test.go index 0358eba8c..d34c268a7 100644 --- a/internal/cmd/network-area/route/delete/delete_test.go +++ b/internal/cmd/network-area/route/delete/delete_test.go @@ -15,6 +15,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -36,6 +40,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, } @@ -49,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: utils.Ptr(testOrgId), NetworkAreaId: utils.Ptr(testNetworkAreaId), @@ -61,7 +68,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteNetworkAreaRouteRequest)) iaas.ApiDeleteNetworkAreaRouteRequest { - request := testClient.DeleteNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRouteId) + request := testClient.DeleteNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRegion, testRouteId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-area/route/describe/describe.go b/internal/cmd/network-area/route/describe/describe.go index 2e54ac4c8..b650e5964 100644 --- a/internal/cmd/network-area/route/describe/describe.go +++ b/internal/cmd/network-area/route/describe/describe.go @@ -100,18 +100,47 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetNetworkAreaRouteRequest { - req := apiClient.GetNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.RouteId) + req := apiClient.GetNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region, model.RouteId) return req } func outputResult(p *print.Printer, outputFormat string, route iaas.Route) error { return p.OutputResult(outputFormat, route, func() error { table := tables.NewTable() - table.AddRow("ID", utils.PtrString(route.RouteId)) + table.AddRow("ID", utils.PtrString(route.Id)) table.AddSeparator() - table.AddRow("PREFIX", utils.PtrString(route.Prefix)) - table.AddSeparator() - table.AddRow("NEXTHOP", utils.PtrString(route.Nexthop)) + if destination := route.Destination; destination != nil { + if destination.DestinationCIDRv4 != nil { + table.AddRow("DESTINATION TYPE", utils.PtrString(destination.DestinationCIDRv4.Type)) + table.AddSeparator() + table.AddRow("DESTINATION", utils.PtrString(destination.DestinationCIDRv4.Value)) + table.AddSeparator() + } else if destination.DestinationCIDRv6 != nil { + table.AddRow("DESTINATION TYPE", utils.PtrString(destination.DestinationCIDRv6.Type)) + table.AddSeparator() + table.AddRow("DESTINATION", utils.PtrString(destination.DestinationCIDRv6.Value)) + table.AddSeparator() + } + } + if nexthop := route.Nexthop; nexthop != nil { + if nexthop.NexthopIPv4 != nil { + table.AddRow("NEXTHOP", utils.PtrString(nexthop.NexthopIPv4.Value)) + table.AddSeparator() + table.AddRow("NEXTHOP TYPE", utils.PtrString(nexthop.NexthopIPv4.Type)) + table.AddSeparator() + } else if nexthop.NexthopIPv6 != nil { + table.AddRow("NEXTHOP", utils.PtrString(nexthop.NexthopIPv6.Value)) + table.AddSeparator() + table.AddRow("NEXTHOP TYPE", utils.PtrString(nexthop.NexthopIPv6.Type)) + table.AddSeparator() + } else if nexthop.NexthopBlackhole != nil { + table.AddRow("NEXTHOP TYPE", utils.PtrString(nexthop.NexthopBlackhole.Type)) + table.AddSeparator() + } else if nexthop.NexthopInternet != nil { + table.AddRow("NEXTHOP TYPE", utils.PtrString(nexthop.NexthopInternet.Type)) + table.AddSeparator() + } + } if route.Labels != nil && len(*route.Labels) > 0 { labels := []string{} for key, value := range *route.Labels { diff --git a/internal/cmd/network-area/route/describe/describe_test.go b/internal/cmd/network-area/route/describe/describe_test.go index 0c674de81..67345ccae 100644 --- a/internal/cmd/network-area/route/describe/describe_test.go +++ b/internal/cmd/network-area/route/describe/describe_test.go @@ -15,6 +15,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -36,6 +40,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, } @@ -49,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: utils.Ptr(testOrgId), NetworkAreaId: utils.Ptr(testNetworkAreaId), @@ -61,7 +68,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetNetworkAreaRouteRequest)) iaas.ApiGetNetworkAreaRouteRequest { - request := testClient.GetNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRouteId) + request := testClient.GetNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRegion, testRouteId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-area/route/list/list.go b/internal/cmd/network-area/route/list/list.go index 2af24763a..9ea4f6159 100644 --- a/internal/cmd/network-area/route/list/list.go +++ b/internal/cmd/network-area/route/list/list.go @@ -127,19 +127,45 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworkAreaRoutesRequest { - return apiClient.ListNetworkAreaRoutes(ctx, *model.OrganizationId, *model.NetworkAreaId) + return apiClient.ListNetworkAreaRoutes(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) } func outputResult(p *print.Printer, outputFormat string, routes []iaas.Route) error { return p.OutputResult(outputFormat, routes, func() error { table := tables.NewTable() - table.SetHeader("Static Route ID", "Next Hop", "Prefix") + table.SetHeader("Static Route ID", "Next Hop", "Next Hop Type", "Destination") for _, route := range routes { + var nextHop string + var nextHopType string + var destination string + if routeDest := route.Destination; routeDest != nil { + if routeDest.DestinationCIDRv4 != nil { + destination = *routeDest.DestinationCIDRv4.Value + } + if routeDest.DestinationCIDRv6 != nil { + destination = *routeDest.DestinationCIDRv6.Value + } + } + if routeNexthop := route.Nexthop; routeNexthop != nil { + if routeNexthop.NexthopIPv4 != nil { + nextHop = *routeNexthop.NexthopIPv4.Value + nextHopType = *routeNexthop.NexthopIPv4.Type + } else if routeNexthop.NexthopIPv6 != nil { + nextHop = *routeNexthop.NexthopIPv6.Value + nextHopType = *routeNexthop.NexthopIPv6.Type + } else if routeNexthop.NexthopBlackhole != nil { + nextHopType = *routeNexthop.NexthopBlackhole.Type + } else if routeNexthop.NexthopInternet != nil { + nextHopType = *routeNexthop.NexthopInternet.Type + } + } + table.AddRow( - utils.PtrString(route.RouteId), - utils.PtrString(route.Nexthop), - utils.PtrString(route.Prefix), + utils.PtrString(route.Id), + nextHop, + nextHopType, + destination, ) } diff --git a/internal/cmd/network-area/route/list/list_test.go b/internal/cmd/network-area/route/list/list_test.go index 8681aa87d..365249370 100644 --- a/internal/cmd/network-area/route/list/list_test.go +++ b/internal/cmd/network-area/route/list/list_test.go @@ -16,6 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -25,6 +29,8 @@ var testNetworkAreaId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrganizationId, networkAreaIdFlag: testNetworkAreaId, limitFlag: "10", @@ -39,6 +45,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: &testOrganizationId, NetworkAreaId: &testNetworkAreaId, @@ -51,7 +58,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListNetworkAreaRoutesRequest)) iaas.ApiListNetworkAreaRoutesRequest { - request := testClient.ListNetworkAreaRoutes(testCtx, testOrganizationId, testNetworkAreaId) + request := testClient.ListNetworkAreaRoutes(testCtx, testOrganizationId, testNetworkAreaId, testRegion) for _, mod := range mods { mod(&request) } @@ -204,6 +211,24 @@ func TestOutputResult(t *testing.T) { }, wantErr: false, }, + { + name: "empty destination in route", + args: args{ + routes: []iaas.Route{{ + Destination: &iaas.RouteDestination{}, + }}, + }, + wantErr: false, + }, + { + name: "empty nexthop in route", + args: args{ + routes: []iaas.Route{{ + Nexthop: &iaas.RouteNexthop{}, + }}, + }, + wantErr: false, + }, } p := print.NewPrinter() p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) diff --git a/internal/cmd/network-area/route/update/update.go b/internal/cmd/network-area/route/update/update.go index 23e6391ff..92ca244a9 100644 --- a/internal/cmd/network-area/route/update/update.go +++ b/internal/cmd/network-area/route/update/update.go @@ -116,7 +116,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateNetworkAreaRouteRequest { - req := apiClient.UpdateNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.RouteId) + req := apiClient.UpdateNetworkAreaRoute(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region, model.RouteId) payload := iaas.UpdateNetworkAreaRoutePayload{ Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), @@ -128,7 +128,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, route iaas.Route) error { return p.OutputResult(outputFormat, route, func() error { - p.Outputf("Updated static route for SNA %q.\nStatic route ID: %s\n", networkAreaLabel, utils.PtrString(route.RouteId)) + p.Outputf("Updated static route for SNA %q.\nStatic route ID: %s\n", networkAreaLabel, utils.PtrString(route.Id)) return nil }) } diff --git a/internal/cmd/network-area/route/update/update_test.go b/internal/cmd/network-area/route/update/update_test.go index 03bdf6da2..da6c6e03a 100644 --- a/internal/cmd/network-area/route/update/update_test.go +++ b/internal/cmd/network-area/route/update/update_test.go @@ -14,6 +14,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") @@ -35,6 +39,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.RegionFlag: testRegion, + organizationIdFlag: testOrgId, networkAreaIdFlag: testNetworkAreaId, labelFlag: "value=key", @@ -74,6 +80,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, OrganizationId: utils.Ptr(testOrgId), NetworkAreaId: utils.Ptr(testNetworkAreaId), @@ -87,7 +94,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateNetworkAreaRouteRequest)) iaas.ApiUpdateNetworkAreaRouteRequest { - request := testClient.UpdateNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRouteId) + request := testClient.UpdateNetworkAreaRoute(testCtx, testOrgId, testNetworkAreaId, testRegion, testRouteId) request = request.UpdateNetworkAreaRoutePayload(fixturePayload()) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/network-area/update/update.go b/internal/cmd/network-area/update/update.go index 855da9f10..20f426d89 100644 --- a/internal/cmd/network-area/update/update.go +++ b/internal/cmd/network-area/update/update.go @@ -3,8 +3,8 @@ package update import ( "context" "fmt" - - rmClient "github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/client" + "os" + "strings" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" @@ -13,6 +13,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" + rmClient "github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/client" rmUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" @@ -23,26 +24,43 @@ import ( const ( areaIdArg = "AREA_ID" - nameFlag = "name" - organizationIdFlag = "organization-id" - areaIdFlag = "area-id" - dnsNameServersFlag = "dns-name-servers" + nameFlag = "name" + organizationIdFlag = "organization-id" + areaIdFlag = "area-id" + // Deprecated: dnsNameServersFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + dnsNameServersFlag = "dns-name-servers" + // Deprecated: defaultPrefixLengthFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. defaultPrefixLengthFlag = "default-prefix-length" - maxPrefixLengthFlag = "max-prefix-length" - minPrefixLengthFlag = "min-prefix-length" - labelFlag = "labels" + // Deprecated: maxPrefixLengthFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + maxPrefixLengthFlag = "max-prefix-length" + // Deprecated: minPrefixLengthFlag is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + minPrefixLengthFlag = "min-prefix-length" + labelFlag = "labels" + + deprecationMessage = "Deprecated and will be removed after April 2026. Use instead the new command `$ stackit network-area region` to configure these options for a network area." ) +// NetworkAreaResponses is a workaround, to keep the two responses of the iaas v2 api together for the json and yaml output +// Should be removed when the deprecated flags are removed +type NetworkAreaResponses struct { + NetworkArea iaas.NetworkArea `json:"network_area"` + RegionalArea *iaas.RegionalArea `json:"regional_area"` +} + type inputModel struct { *globalflags.GlobalFlagModel - AreaId string - Name *string - OrganizationId *string - DnsNameServers *[]string + AreaId string + Name *string + OrganizationId *string + // Deprecated: DnsNameServers is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + DnsNameServers *[]string + // Deprecated: DefaultPrefixLength is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. DefaultPrefixLength *int64 - MaxPrefixLength *int64 - MinPrefixLength *int64 - Labels *map[string]string + // Deprecated: MaxPrefixLength is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + MaxPrefixLength *int64 + // Deprecated: MinPrefixLength is deprecated, because with iaas v2 the create endpoint for network area was separated, remove this after April 2026. + MinPrefixLength *int64 + Labels *map[string]string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -99,7 +117,26 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return fmt.Errorf("update network area: %w", err) } - return outputResult(params.Printer, model.OutputFormat, orgLabel, *resp) + if resp == nil || resp.Id == nil { + return fmt.Errorf("update network area: empty response") + } + + responses := NetworkAreaResponses{ + NetworkArea: *resp, + } + + if hasDeprecatedFlagsSet(model) { + deprecatedFlags := getConfiguredDeprecatedFlags(model) + params.Printer.Warn("the flags %q are deprecated and will be removed after April 2026. Use `$ stackit network-area region` to configure these options for a network area.\n", strings.Join(deprecatedFlags, ",")) + reqNetworkArea := buildRequestNetworkAreaRegion(ctx, model, apiClient) + respNetworkArea, err := reqNetworkArea.Execute() + if err != nil { + return fmt.Errorf("create network area region: %w", err) + } + responses.RegionalArea = respNetworkArea + } + + return outputResult(params.Printer, model.OutputFormat, orgLabel, responses) }, } configureFlags(cmd) @@ -115,6 +152,13 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Int64(minPrefixLengthFlag, 0, "The minimum prefix length for networks in the network area") cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a network-area. E.g. '--labels key1=value1,key2=value2,...'") + cobra.CheckErr(cmd.Flags().MarkDeprecated(dnsNameServersFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(defaultPrefixLengthFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(maxPrefixLengthFlag, deprecationMessage)) + cobra.CheckErr(cmd.Flags().MarkDeprecated(minPrefixLengthFlag, deprecationMessage)) + // Set the output for deprecation warnings to stderr + cmd.Flags().SetOutput(os.Stderr) + err := flags.MarkFlagsRequired(cmd, organizationIdFlag) cobra.CheckErr(err) } @@ -140,27 +184,67 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu return &model, nil } +func hasDeprecatedFlagsSet(model *inputModel) bool { + deprecatedFlags := getConfiguredDeprecatedFlags(model) + return len(deprecatedFlags) > 0 +} + +func getConfiguredDeprecatedFlags(model *inputModel) []string { + var result []string + if model.DnsNameServers != nil { + result = append(result, dnsNameServersFlag) + } + if model.DefaultPrefixLength != nil { + result = append(result, defaultPrefixLengthFlag) + } + if model.MaxPrefixLength != nil { + result = append(result, maxPrefixLengthFlag) + } + if model.MinPrefixLength != nil { + result = append(result, minPrefixLengthFlag) + } + return result +} + func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiPartialUpdateNetworkAreaRequest { req := apiClient.PartialUpdateNetworkArea(ctx, *model.OrganizationId, model.AreaId) payload := iaas.PartialUpdateNetworkAreaPayload{ Name: model.Name, Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), - AddressFamily: &iaas.UpdateAreaAddressFamily{ - Ipv4: &iaas.UpdateAreaIPv4{ - DefaultNameservers: model.DnsNameServers, - DefaultPrefixLen: model.DefaultPrefixLength, - MaxPrefixLen: model.MaxPrefixLength, - MinPrefixLen: model.MinPrefixLength, - }, - }, } return req.PartialUpdateNetworkAreaPayload(payload) } -func outputResult(p *print.Printer, outputFormat, projectLabel string, networkArea iaas.NetworkArea) error { - return p.OutputResult(outputFormat, networkArea, func() error { +func buildRequestNetworkAreaRegion(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateNetworkAreaRegionRequest { + req := apiClient.UpdateNetworkAreaRegion(ctx, *model.OrganizationId, model.AreaId, model.Region) + + payload := iaas.UpdateNetworkAreaRegionPayload{ + Ipv4: &iaas.UpdateRegionalAreaIPv4{ + DefaultNameservers: model.DnsNameServers, + DefaultPrefixLen: model.DefaultPrefixLength, + MaxPrefixLen: model.MaxPrefixLength, + MinPrefixLen: model.MinPrefixLength, + }, + } + + return req.UpdateNetworkAreaRegionPayload(payload) +} + +func outputResult(p *print.Printer, outputFormat, projectLabel string, responses NetworkAreaResponses) error { + prettyOutputFunc := func() error { + p.Outputf("Updated STACKIT Network Area for project %q.\n", projectLabel) + return nil + } + + // If RegionalArea is NOT set in the reponses, then no deprecated Flags were set. + // In this case, only the response of NetworkArea should be printed in JSON and yaml output, to avoid breaking changes after the deprecated fields are removed + if responses.RegionalArea == nil { + return p.OutputResult(outputFormat, responses.NetworkArea, prettyOutputFunc) + } + + return p.OutputResult(outputFormat, responses, func() error { p.Outputf("Updated STACKIT Network Area for project %q.\n", projectLabel) return nil }) diff --git a/internal/cmd/network-area/update/update_test.go b/internal/cmd/network-area/update/update_test.go index f25018286..b46b66aab 100644 --- a/internal/cmd/network-area/update/update_test.go +++ b/internal/cmd/network-area/update/update_test.go @@ -2,6 +2,8 @@ package update import ( "context" + "strconv" + "strings" "testing" "github.com/stackitcloud/stackit-cli/internal/cmd/params" @@ -15,13 +17,25 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" + testName = "example-network-area-name" + testDefaultPrefixLength int64 = 25 + testMinPrefixLength int64 = 24 + testMaxPrefixLength int64 = 26 +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &iaas.APIClient{} -var testOrgId = uuid.NewString() -var testAreaId = uuid.NewString() +var ( + testOrgId = uuid.NewString() + testAreaId = uuid.NewString() + + testDnsNameservers = []string{"1.1.1.0", "1.1.2.0"} +) func fixtureArgValues(mods ...func(argValues []string)) []string { argValues := []string{ @@ -35,13 +49,11 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - nameFlag: "example-network-area-name", - organizationIdFlag: testOrgId, - dnsNameServersFlag: "1.1.1.0,1.1.2.0", - defaultPrefixLengthFlag: "24", - maxPrefixLengthFlag: "24", - minPrefixLengthFlag: "24", - labelFlag: "key=value", + globalflags.RegionFlag: testRegion, + + nameFlag: testName, + organizationIdFlag: testOrgId, + labelFlag: "key=value", } for _, mod := range mods { mod(flagValues) @@ -53,14 +65,11 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - Name: utils.Ptr("example-network-area-name"), - OrganizationId: utils.Ptr(testOrgId), - AreaId: testAreaId, - DnsNameServers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - DefaultPrefixLength: utils.Ptr(int64(24)), - MaxPrefixLength: utils.Ptr(int64(24)), - MinPrefixLength: utils.Ptr(int64(24)), + Name: utils.Ptr(testName), + OrganizationId: utils.Ptr(testOrgId), + AreaId: testAreaId, Labels: utils.Ptr(map[string]string{ "key": "value", }), @@ -82,17 +91,33 @@ func fixtureRequest(mods ...func(request *iaas.ApiPartialUpdateNetworkAreaReques func fixturePayload(mods ...func(payload *iaas.PartialUpdateNetworkAreaPayload)) iaas.PartialUpdateNetworkAreaPayload { payload := iaas.PartialUpdateNetworkAreaPayload{ - Name: utils.Ptr("example-network-area-name"), + Name: utils.Ptr(testName), Labels: utils.Ptr(map[string]interface{}{ "key": "value", }), - AddressFamily: &iaas.UpdateAreaAddressFamily{ - Ipv4: &iaas.UpdateAreaIPv4{ - DefaultNameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - DefaultPrefixLen: utils.Ptr(int64(24)), - MaxPrefixLen: utils.Ptr(int64(24)), - MinPrefixLen: utils.Ptr(int64(24)), - }, + } + for _, mod := range mods { + mod(&payload) + } + return payload +} + +func fixtureRequestRegionalArea(mods ...func(request *iaas.ApiUpdateNetworkAreaRegionRequest)) iaas.ApiUpdateNetworkAreaRegionRequest { + request := testClient.UpdateNetworkAreaRegion(testCtx, testOrgId, testAreaId, testRegion) + request = request.UpdateNetworkAreaRegionPayload(fixturePayloadRegionalArea()) + for _, mod := range mods { + mod(&request) + } + return request +} + +func fixturePayloadRegionalArea(mods ...func(payload *iaas.UpdateNetworkAreaRegionPayload)) iaas.UpdateNetworkAreaRegionPayload { + payload := iaas.UpdateNetworkAreaRegionPayload{ + Ipv4: &iaas.UpdateRegionalAreaIPv4{ + DefaultNameservers: utils.Ptr(testDnsNameservers), + DefaultPrefixLen: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLen: utils.Ptr(testMaxPrefixLength), + MinPrefixLen: utils.Ptr(testMinPrefixLength), }, } for _, mod := range mods { @@ -118,20 +143,20 @@ func TestParseInput(t *testing.T) { expectedModel: fixtureInputModel(), }, { - description: "required only", + description: "with deprecated flags", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, dnsNameServersFlag) - delete(flagValues, defaultPrefixLengthFlag) - delete(flagValues, maxPrefixLengthFlag) - delete(flagValues, minPrefixLengthFlag) + flagValues[dnsNameServersFlag] = strings.Join(testDnsNameservers, ",") + flagValues[defaultPrefixLengthFlag] = strconv.FormatInt(testDefaultPrefixLength, 10) + flagValues[maxPrefixLengthFlag] = strconv.FormatInt(testMaxPrefixLength, 10) + flagValues[minPrefixLengthFlag] = strconv.FormatInt(testMinPrefixLength, 10) }), isValid: true, expectedModel: fixtureInputModel(func(model *inputModel) { - model.DnsNameServers = nil - model.DefaultPrefixLength = nil - model.MaxPrefixLength = nil - model.MinPrefixLength = nil + model.DnsNameServers = utils.Ptr(testDnsNameservers) + model.DefaultPrefixLength = utils.Ptr(testDefaultPrefixLength) + model.MaxPrefixLength = utils.Ptr(testMaxPrefixLength) + model.MinPrefixLength = utils.Ptr(testMinPrefixLength) }), }, @@ -286,11 +311,44 @@ func TestBuildRequest(t *testing.T) { } } +func TestBuildRequestNetworkAreaRegion(t *testing.T) { + tests := []struct { + description string + model *inputModel + expectedRequest iaas.ApiUpdateNetworkAreaRegionRequest + }{ + { + description: "base", + model: fixtureInputModel(func(model *inputModel) { + model.DnsNameServers = utils.Ptr(testDnsNameservers) + model.DefaultPrefixLength = utils.Ptr(testDefaultPrefixLength) + model.MaxPrefixLength = utils.Ptr(testMaxPrefixLength) + model.MinPrefixLength = utils.Ptr(testMinPrefixLength) + }), + expectedRequest: fixtureRequestRegionalArea(), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + request := buildRequestNetworkAreaRegion(testCtx, tt.model, testClient) + + diff := cmp.Diff(request, tt.expectedRequest, + cmp.AllowUnexported(tt.expectedRequest), + cmpopts.EquateComparable(testCtx), + ) + if diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + func TestOutputResult(t *testing.T) { type args struct { outputFormat string projectLabel string - networkArea iaas.NetworkArea + responses NetworkAreaResponses } tests := []struct { name string @@ -305,7 +363,10 @@ func TestOutputResult(t *testing.T) { { name: "empty network area", args: args{ - networkArea: iaas.NetworkArea{}, + responses: NetworkAreaResponses{ + NetworkArea: iaas.NetworkArea{}, + RegionalArea: nil, + }, }, wantErr: false, }, @@ -314,9 +375,132 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.networkArea); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.responses); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) } } + +func TestGetConfiguredDeprecatedFlags(t *testing.T) { + type args struct { + model *inputModel + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "no deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: utils.Ptr(testOrgId), + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: nil, + DefaultPrefixLength: nil, + MaxPrefixLength: nil, + MinPrefixLength: nil, + }, + }, + want: nil, + }, + { + name: "deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: utils.Ptr(testOrgId), + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: utils.Ptr(testDnsNameservers), + DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + MinPrefixLength: utils.Ptr(testMinPrefixLength), + }, + }, + want: []string{dnsNameServersFlag, defaultPrefixLengthFlag, minPrefixLengthFlag, maxPrefixLengthFlag}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := getConfiguredDeprecatedFlags(tt.args.model) + + less := func(a, b string) bool { + return a < b + } + if diff := cmp.Diff(tt.want, got, cmpopts.SortSlices(less)); diff != "" { + t.Fatalf("Data does not match: %s", diff) + } + }) + } +} + +func TestHasDeprecatedFlagsSet(t *testing.T) { + type args struct { + model *inputModel + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "no deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: utils.Ptr(testOrgId), + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: nil, + DefaultPrefixLength: nil, + MaxPrefixLength: nil, + MinPrefixLength: nil, + }, + }, + want: false, + }, + { + name: "deprecated flags", + args: args{ + model: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + Verbosity: globalflags.VerbosityDefault, + }, + Name: utils.Ptr(testName), + OrganizationId: utils.Ptr(testOrgId), + Labels: utils.Ptr(map[string]string{ + "key": "value", + }), + DnsNameServers: utils.Ptr(testDnsNameservers), + DefaultPrefixLength: utils.Ptr(testDefaultPrefixLength), + MaxPrefixLength: utils.Ptr(testMaxPrefixLength), + MinPrefixLength: utils.Ptr(testMinPrefixLength), + }, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := hasDeprecatedFlagsSet(tt.args.model); got != tt.want { + t.Errorf("hasDeprecatedFlagsSet() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/cmd/network-interface/create/create.go b/internal/cmd/network-interface/create/create.go index 1fc368ffa..ad945e81d 100644 --- a/internal/cmd/network-interface/create/create.go +++ b/internal/cmd/network-interface/create/create.go @@ -38,7 +38,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - NetworkId *string + NetworkId string AllowedAddresses *[]iaas.AllowedAddressesInner Ipv4 *string Ipv6 *string @@ -177,7 +177,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, - NetworkId: flags.FlagToStringPointer(p, cmd, networkIdFlag), + NetworkId: flags.FlagToStringValue(p, cmd, networkIdFlag), Ipv4: flags.FlagToStringPointer(p, cmd, ipv4Flag), Ipv6: flags.FlagToStringPointer(p, cmd, ipv6Flag), Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag), @@ -195,7 +195,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateNicRequest { - req := apiClient.CreateNic(ctx, model.ProjectId, *model.NetworkId) + req := apiClient.CreateNic(ctx, model.ProjectId, model.Region, model.NetworkId) payload := iaas.CreateNicPayload{ AllowedAddresses: model.AllowedAddresses, diff --git a/internal/cmd/network-interface/create/create_test.go b/internal/cmd/network-interface/create/create_test.go index 82e5b628a..fd584b84e 100644 --- a/internal/cmd/network-interface/create/create_test.go +++ b/internal/cmd/network-interface/create/create_test.go @@ -15,19 +15,24 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &iaas.APIClient{} -var projectIdFlag = globalflags.ProjectIdFlag var testProjectId = uuid.NewString() var testNetworkId = uuid.NewString() var testSecurityGroup = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + networkIdFlag: testNetworkId, allowedAddressesFlag: "1.1.1.1,8.8.8.8,9.9.9.9", ipv4Flag: "1.2.3.4", @@ -52,9 +57,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, - NetworkId: utils.Ptr(testNetworkId), + NetworkId: testNetworkId, AllowedAddresses: utils.Ptr(allowedAddresses), Ipv4: utils.Ptr("1.2.3.4"), Ipv6: utils.Ptr("2001:0db8:85a3:08d3::0370:7344"), @@ -72,7 +78,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateNicRequest)) iaas.ApiCreateNicRequest { - request := testClient.CreateNic(testCtx, testProjectId, testNetworkId) + request := testClient.CreateNic(testCtx, testProjectId, testRegion, testNetworkId) request = request.CreateNicPayload(fixturePayload()) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/network-interface/delete/delete.go b/internal/cmd/network-interface/delete/delete.go index 043e41217..c5d9d61e0 100644 --- a/internal/cmd/network-interface/delete/delete.go +++ b/internal/cmd/network-interface/delete/delete.go @@ -24,7 +24,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - NetworkId *string + NetworkId string NicId string } @@ -90,7 +90,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - NetworkId: flags.FlagToStringPointer(p, cmd, networkIdFlag), + NetworkId: flags.FlagToStringValue(p, cmd, networkIdFlag), NicId: nicId, } @@ -99,6 +99,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteNicRequest { - req := apiClient.DeleteNic(ctx, model.ProjectId, *model.NetworkId, model.NicId) + req := apiClient.DeleteNic(ctx, model.ProjectId, model.Region, model.NetworkId, model.NicId) return req } diff --git a/internal/cmd/network-interface/delete/delete_test.go b/internal/cmd/network-interface/delete/delete_test.go index ac03d45f6..c0170eab1 100644 --- a/internal/cmd/network-interface/delete/delete_test.go +++ b/internal/cmd/network-interface/delete/delete_test.go @@ -10,16 +10,18 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &iaas.APIClient{} -var projectIdFlag = globalflags.ProjectIdFlag var testProjectId = uuid.NewString() var testNetworkId = uuid.NewString() var testNicId = uuid.NewString() @@ -36,8 +38,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - networkIdFlag: testNetworkId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + networkIdFlag: testNetworkId, } for _, mod := range mods { mod(flagValues) @@ -50,8 +53,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - NetworkId: utils.Ptr(testNetworkId), + NetworkId: testNetworkId, NicId: testNicId, } for _, mod := range mods { @@ -61,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteNicRequest)) iaas.ApiDeleteNicRequest { - request := testClient.DeleteNic(testCtx, testProjectId, testNetworkId, testNicId) + request := testClient.DeleteNic(testCtx, testProjectId, testRegion, testNetworkId, testNicId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-interface/describe/describe.go b/internal/cmd/network-interface/describe/describe.go index 4c1fc6d7d..128c333fa 100644 --- a/internal/cmd/network-interface/describe/describe.go +++ b/internal/cmd/network-interface/describe/describe.go @@ -27,7 +27,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - NetworkId *string + NetworkId string NicId string } @@ -94,7 +94,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - NetworkId: flags.FlagToStringPointer(p, cmd, networkIdFlag), + NetworkId: flags.FlagToStringValue(p, cmd, networkIdFlag), NicId: nicId, } @@ -103,7 +103,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetNicRequest { - req := apiClient.GetNic(ctx, model.ProjectId, *model.NetworkId, model.NicId) + req := apiClient.GetNic(ctx, model.ProjectId, model.Region, model.NetworkId, model.NicId) return req } diff --git a/internal/cmd/network-interface/describe/describe_test.go b/internal/cmd/network-interface/describe/describe_test.go index 24163ac87..2f802bf0e 100644 --- a/internal/cmd/network-interface/describe/describe_test.go +++ b/internal/cmd/network-interface/describe/describe_test.go @@ -10,16 +10,18 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &iaas.APIClient{} -var projectIdFlag = globalflags.ProjectIdFlag var testProjectId = uuid.NewString() var testNetworkId = uuid.NewString() var testNicId = uuid.NewString() @@ -36,8 +38,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - networkIdFlag: testNetworkId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + networkIdFlag: testNetworkId, } for _, mod := range mods { mod(flagValues) @@ -50,8 +53,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - NetworkId: utils.Ptr(testNetworkId), + NetworkId: testNetworkId, NicId: testNicId, } for _, mod := range mods { @@ -61,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetNicRequest)) iaas.ApiGetNicRequest { - request := testClient.GetNic(testCtx, testProjectId, testNetworkId, testNicId) + request := testClient.GetNic(testCtx, testProjectId, testRegion, testNetworkId, testNicId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/network-interface/list/list.go b/internal/cmd/network-interface/list/list.go index cd683883a..23fe3aa4d 100644 --- a/internal/cmd/network-interface/list/list.go +++ b/internal/cmd/network-interface/list/list.go @@ -29,7 +29,7 @@ type inputModel struct { *globalflags.GlobalFlagModel Limit *int64 LabelSelector *string - NetworkId *string + NetworkId string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -77,12 +77,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } if resp.Items == nil || len(*resp.Items) == 0 { - networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, *model.NetworkId) + networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.Region, model.NetworkId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network name: %v", err) - networkLabel = *model.NetworkId + networkLabel = model.NetworkId } else if networkLabel == "" { - networkLabel = *model.NetworkId + networkLabel = model.NetworkId } params.Printer.Info("No network interfaces found for network %q\n", networkLabel) return nil @@ -128,7 +128,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, GlobalFlagModel: globalFlags, Limit: limit, LabelSelector: flags.FlagToStringPointer(p, cmd, labelSelectorFlag), - NetworkId: flags.FlagToStringPointer(p, cmd, networkIdFlag), + NetworkId: flags.FlagToStringValue(p, cmd, networkIdFlag), } p.DebugInputModel(model) @@ -136,7 +136,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNicsRequest { - req := apiClient.ListNics(ctx, model.ProjectId, *model.NetworkId) + req := apiClient.ListNics(ctx, model.ProjectId, model.Region, model.NetworkId) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/network-interface/list/list_test.go b/internal/cmd/network-interface/list/list_test.go index 68df78a25..56eb5435d 100644 --- a/internal/cmd/network-interface/list/list_test.go +++ b/internal/cmd/network-interface/list/list_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -28,7 +30,9 @@ var testLabelSelector = "label" func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + networkIdFlag: testNetworkId, limitFlag: "10", labelSelectorFlag: testLabelSelector, @@ -44,10 +48,11 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), - NetworkId: utils.Ptr(testNetworkId), + NetworkId: testNetworkId, } for _, mod := range mods { mod(model) @@ -56,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListNicsRequest)) iaas.ApiListNicsRequest { - request := testClient.ListNics(testCtx, testProjectId, testNetworkId) + request := testClient.ListNics(testCtx, testProjectId, testRegion, testNetworkId) request = request.LabelSelector(testLabelSelector) for _, mod := range mods { mod(&request) @@ -91,21 +96,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/network-interface/update/update.go b/internal/cmd/network-interface/update/update.go index 190946bd7..3b1902bb4 100644 --- a/internal/cmd/network-interface/update/update.go +++ b/internal/cmd/network-interface/update/update.go @@ -38,7 +38,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel NicId string - NetworkId *string + NetworkId string AllowedAddresses *[]iaas.AllowedAddressesInner Labels *map[string]string Name *string // <= 63 characters + regex ^[A-Za-z0-9]+((-|_|\s|\.)[A-Za-z0-9]+)*$ @@ -171,7 +171,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, NicId: nicId, - NetworkId: flags.FlagToStringPointer(p, cmd, networkIdFlag), + NetworkId: flags.FlagToStringValue(p, cmd, networkIdFlag), Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag), Name: name, NicSecurity: flags.FlagToBoolPointer(p, cmd, nicSecurityFlag), @@ -187,7 +187,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateNicRequest { - req := apiClient.UpdateNic(ctx, model.ProjectId, *model.NetworkId, model.NicId) + req := apiClient.UpdateNic(ctx, model.ProjectId, model.Region, model.NetworkId, model.NicId) payload := iaas.UpdateNicPayload{ AllowedAddresses: model.AllowedAddresses, diff --git a/internal/cmd/network-interface/update/update_test.go b/internal/cmd/network-interface/update/update_test.go index 03faa73ad..3f1382dab 100644 --- a/internal/cmd/network-interface/update/update_test.go +++ b/internal/cmd/network-interface/update/update_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -38,7 +40,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + networkIdFlag: testNetworkId, allowedAddressesFlag: "1.1.1.1,8.8.8.8,9.9.9.9", labelFlag: "key=value", @@ -62,8 +66,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - NetworkId: utils.Ptr(testNetworkId), + NetworkId: testNetworkId, AllowedAddresses: utils.Ptr(allowedAddresses), Labels: utils.Ptr(map[string]string{ "key": "value", @@ -80,7 +85,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateNicRequest)) iaas.ApiUpdateNicRequest { - request := testClient.UpdateNic(testCtx, testProjectId, testNetworkId, testNicId) + request := testClient.UpdateNic(testCtx, testProjectId, testRegion, testNetworkId, testNicId) request = request.UpdateNicPayload(fixturePayload()) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/network/create/create.go b/internal/cmd/network/create/create.go index acb1bc7e1..9877e4477 100644 --- a/internal/cmd/network/create/create.go +++ b/internal/cmd/network/create/create.go @@ -79,7 +79,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { ), examples.NewExample( `Create an IPv4 network with name "network-1" with DNS name servers, a prefix and a gateway`, - `$ stackit network create --name network-1 --ipv4-dns-name-servers "1.1.1.1,8.8.8.8,9.9.9.9" --ipv4-prefix "10.1.2.0/24" --ipv4-gateway "10.1.2.3"`, + `$ stackit network create --name network-1 --non-routed --ipv4-dns-name-servers "1.1.1.1,8.8.8.8,9.9.9.9" --ipv4-prefix "10.1.2.0/24" --ipv4-gateway "10.1.2.3"`, ), examples.NewExample( `Create an IPv6 network with name "network-1" with DNS name servers, a prefix and a gateway`, @@ -121,13 +121,17 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("create network : %w", err) } - networkId := *resp.NetworkId + + if resp == nil || resp.Id == nil { + return fmt.Errorf("create network : empty response") + } + networkId := *resp.Id // Wait for async operation, if async mode not enabled if !model.Async { s := spinner.New(params.Printer) s.Start("Creating network") - _, err = wait.CreateNetworkWaitHandler(ctx, apiClient, model.ProjectId, networkId).WaitWithContext(ctx) + _, err = wait.CreateNetworkWaitHandler(ctx, apiClient, model.ProjectId, model.Region, networkId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for network creation: %w", err) } @@ -156,6 +160,17 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Bool(noIpv6GatewayFlag, false, "If set to true, the network doesn't have an IPv6 gateway") cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a network. E.g. '--labels key1=value1,key2=value2,...'") + // IPv4 checks + cmd.MarkFlagsMutuallyExclusive(ipv4PrefixFlag, ipv4PrefixLengthFlag) + cmd.MarkFlagsMutuallyExclusive(ipv4GatewayFlag, ipv4PrefixLengthFlag) + cmd.MarkFlagsMutuallyExclusive(ipv4GatewayFlag, noIpv4GatewayFlag) + cmd.MarkFlagsMutuallyExclusive(noIpv4GatewayFlag, ipv4PrefixLengthFlag) + + // IPv6 checks + cmd.MarkFlagsMutuallyExclusive(ipv6PrefixFlag, ipv6PrefixLengthFlag) + cmd.MarkFlagsMutuallyExclusive(ipv6GatewayFlag, ipv6PrefixLengthFlag) + cmd.MarkFlagsMutuallyExclusive(ipv6GatewayFlag, noIpv6GatewayFlag) + err := flags.MarkFlagsRequired(cmd, nameFlag) cobra.CheckErr(err) } @@ -173,6 +188,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, IPv4PrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv4PrefixLengthFlag), IPv4Prefix: flags.FlagToStringPointer(p, cmd, ipv4PrefixFlag), IPv4Gateway: flags.FlagToStringPointer(p, cmd, ipv4GatewayFlag), + IPv6DnsNameServers: flags.FlagToStringSlicePointer(p, cmd, ipv6DnsNameServersFlag), IPv6PrefixLength: flags.FlagToInt64Pointer(p, cmd, ipv6PrefixLengthFlag), IPv6Prefix: flags.FlagToStringPointer(p, cmd, ipv6PrefixFlag), @@ -183,39 +199,92 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag), } + // IPv4 nameserver can not be set alone. IPv4 Prefix || IPv4 Prefix length must be set as well + isIPv4NameserverSet := model.IPv4DnsNameServers != nil && len(*model.IPv4DnsNameServers) > 0 + isIPv4PrefixOrPrefixLengthSet := model.IPv4Prefix != nil || model.IPv4PrefixLength != nil + if isIPv4NameserverSet && !isIPv4PrefixOrPrefixLengthSet { + return nil, &cliErr.OneOfFlagsIsMissing{ + MissingFlags: []string{ipv4PrefixLengthFlag, ipv4PrefixFlag}, + SetFlag: ipv4DnsNameServersFlag, + } + } + isIPv4GatewaySet := model.IPv4Gateway != nil + isIPv4PrefixSet := model.IPv4Prefix != nil + if isIPv4GatewaySet && !isIPv4PrefixSet { + return nil, &cliErr.DependingFlagIsMissing{ + MissingFlag: ipv4PrefixFlag, + SetFlag: ipv4GatewayFlag, + } + } + + // IPv6 nameserver can not be set alone. IPv6 Prefix || IPv6 Prefix length must be set as well + isIPv6NameserverSet := model.IPv6DnsNameServers != nil && len(*model.IPv6DnsNameServers) > 0 + isIPv6PrefixOrPrefixLengthSet := model.IPv6Prefix != nil || model.IPv6PrefixLength != nil + if isIPv6NameserverSet && !isIPv6PrefixOrPrefixLengthSet { + return nil, &cliErr.OneOfFlagsIsMissing{ + MissingFlags: []string{ipv6PrefixLengthFlag, ipv6PrefixFlag}, + SetFlag: ipv6DnsNameServersFlag, + } + } + isIPv6GatewaySet := model.IPv6Gateway != nil + isIPv6PrefixSet := model.IPv6Prefix != nil + if isIPv6GatewaySet && !isIPv6PrefixSet { + return nil, &cliErr.DependingFlagIsMissing{ + MissingFlag: ipv6PrefixFlag, + SetFlag: ipv6GatewayFlag, + } + } + p.DebugInputModel(model) return &model, nil } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateNetworkRequest { - req := apiClient.CreateNetwork(ctx, model.ProjectId) - addressFamily := &iaas.CreateNetworkAddressFamily{} - - if model.IPv6DnsNameServers != nil || model.IPv6PrefixLength != nil || model.IPv6Prefix != nil || model.NoIPv6Gateway || model.IPv6Gateway != nil { - addressFamily.Ipv6 = &iaas.CreateNetworkIPv6Body{ - Nameservers: model.IPv6DnsNameServers, - PrefixLength: model.IPv6PrefixLength, - Prefix: model.IPv6Prefix, + req := apiClient.CreateNetwork(ctx, model.ProjectId, model.Region) + var ipv4Network *iaas.CreateNetworkIPv4 + var ipv6Network *iaas.CreateNetworkIPv6 + + if model.IPv6Prefix != nil { + ipv6Network = &iaas.CreateNetworkIPv6{ + CreateNetworkIPv6WithPrefix: &iaas.CreateNetworkIPv6WithPrefix{ + Prefix: model.IPv6Prefix, + Nameservers: model.IPv6DnsNameServers, + }, } if model.NoIPv6Gateway { - addressFamily.Ipv6.Gateway = iaas.NewNullableString(nil) + ipv6Network.CreateNetworkIPv6WithPrefix.Gateway = iaas.NewNullableString(nil) } else if model.IPv6Gateway != nil { - addressFamily.Ipv6.Gateway = iaas.NewNullableString(model.IPv6Gateway) + ipv6Network.CreateNetworkIPv6WithPrefix.Gateway = iaas.NewNullableString(model.IPv6Gateway) + } + } else if model.IPv6PrefixLength != nil { + ipv6Network = &iaas.CreateNetworkIPv6{ + CreateNetworkIPv6WithPrefixLength: &iaas.CreateNetworkIPv6WithPrefixLength{ + PrefixLength: model.IPv6PrefixLength, + Nameservers: model.IPv6DnsNameServers, + }, } } - if model.IPv4DnsNameServers != nil || model.IPv4PrefixLength != nil || model.IPv4Prefix != nil || model.NoIPv4Gateway || model.IPv4Gateway != nil { - addressFamily.Ipv4 = &iaas.CreateNetworkIPv4Body{ - Nameservers: model.IPv4DnsNameServers, - PrefixLength: model.IPv4PrefixLength, - Prefix: model.IPv4Prefix, + if model.IPv4Prefix != nil { + ipv4Network = &iaas.CreateNetworkIPv4{ + CreateNetworkIPv4WithPrefix: &iaas.CreateNetworkIPv4WithPrefix{ + Prefix: model.IPv4Prefix, + Nameservers: model.IPv4DnsNameServers, + }, } if model.NoIPv4Gateway { - addressFamily.Ipv4.Gateway = iaas.NewNullableString(nil) + ipv4Network.CreateNetworkIPv4WithPrefix.Gateway = iaas.NewNullableString(nil) } else if model.IPv4Gateway != nil { - addressFamily.Ipv4.Gateway = iaas.NewNullableString(model.IPv4Gateway) + ipv4Network.CreateNetworkIPv4WithPrefix.Gateway = iaas.NewNullableString(model.IPv4Gateway) + } + } else if model.IPv4PrefixLength != nil { + ipv4Network = &iaas.CreateNetworkIPv4{ + CreateNetworkIPv4WithPrefixLength: &iaas.CreateNetworkIPv4WithPrefixLength{ + PrefixLength: model.IPv4PrefixLength, + Nameservers: model.IPv4DnsNameServers, + }, } } @@ -228,10 +297,8 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli Name: model.Name, Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), Routed: &routed, - } - - if addressFamily.Ipv4 != nil || addressFamily.Ipv6 != nil { - payload.AddressFamily = addressFamily + Ipv4: ipv4Network, + Ipv6: ipv6Network, } return req.CreateNetworkPayload(payload) @@ -246,7 +313,7 @@ func outputResult(p *print.Printer, outputFormat string, async bool, projectLabe if async { operationState = "Triggered creation of" } - p.Outputf("%s network for project %q.\nNetwork ID: %s\n", operationState, projectLabel, utils.PtrString(network.NetworkId)) + p.Outputf("%s network for project %q.\nNetwork ID: %s\n", operationState, projectLabel, utils.PtrString(network.Id)) return nil }) } diff --git a/internal/cmd/network/create/create_test.go b/internal/cmd/network/create/create_test.go index 6fd5c6a9a..a73f7d07a 100644 --- a/internal/cmd/network/create/create_test.go +++ b/internal/cmd/network/create/create_test.go @@ -2,6 +2,8 @@ package create import ( "context" + "strconv" + "strings" "testing" "github.com/stackitcloud/stackit-cli/internal/cmd/params" @@ -16,30 +18,71 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" -type testCtxKey struct{} + testNetworkName = "example-network-name" + testIPv4PrefixLength int64 = 24 + testIPv4Prefix = "10.1.2.0/24" + testIPv4Gateway = "10.1.2.3" + testIPv6PrefixLength int64 = 24 + testIPv6Prefix = "2001:4860:4860::/64" + testIPv6Gateway = "2001:db8:0:8d3:0:8a2e:70:1" + testNonRouted = false +) + +var ( + testIPv4NameServers = []string{"1.1.1.0", "1.1.2.0"} + testIPv6NameServers = []string{"2001:4860:4860::8888", "2001:4860:4860::8844"} +) -var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") -var testClient = &iaas.APIClient{} +type testCtxKey struct{} -var testProjectId = uuid.NewString() +var ( + testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") + testClient = &iaas.APIClient{} + testProjectId = uuid.NewString() +) func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - nameFlag: "example-network-name", - ipv4DnsNameServersFlag: "1.1.1.0,1.1.2.0", - ipv4PrefixLengthFlag: "24", - ipv4PrefixFlag: "10.1.2.0/24", - ipv4GatewayFlag: "10.1.2.3", - ipv6DnsNameServersFlag: "2001:4860:4860::8888,2001:4860:4860::8844", - ipv6PrefixLengthFlag: "24", - ipv6PrefixFlag: "2001:4860:4860::8888", - ipv6GatewayFlag: "2001:4860:4860::8888", - nonRoutedFlag: "false", - labelFlag: "key=value", + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + nameFlag: testNetworkName, + nonRoutedFlag: strconv.FormatBool(testNonRouted), + labelFlag: "key=value", + } + for _, mod := range mods { + mod(flagValues) + } + return flagValues +} + +func fixtureFlagValuesWithPrefix(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4DnsNameServersFlag] = strings.Join(testIPv4NameServers, ",") + flagValues[ipv4PrefixFlag] = testIPv4Prefix + flagValues[ipv4GatewayFlag] = testIPv4Gateway + + flagValues[ipv6DnsNameServersFlag] = strings.Join(testIPv6NameServers, ",") + flagValues[ipv6PrefixFlag] = testIPv6Prefix + flagValues[ipv6GatewayFlag] = testIPv6Gateway + }) + for _, mod := range mods { + mod(flagValues) } + return flagValues +} + +func fixtureFlagValuesWithPrefixLength(mods ...func(flagValues map[string]string)) map[string]string { + flagValues := fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4PrefixLengthFlag] = strconv.FormatInt(testIPv4PrefixLength, 10) + flagValues[ipv4DnsNameServersFlag] = strings.Join(testIPv4NameServers, ",") + + flagValues[ipv6PrefixLengthFlag] = strconv.FormatInt(testIPv6PrefixLength, 10) + flagValues[ipv6DnsNameServersFlag] = strings.Join(testIPv6NameServers, ",") + }) for _, mod := range mods { mod(flagValues) } @@ -51,17 +94,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - Name: utils.Ptr("example-network-name"), - IPv4DnsNameServers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - IPv4PrefixLength: utils.Ptr(int64(24)), - IPv4Prefix: utils.Ptr("10.1.2.0/24"), - IPv4Gateway: utils.Ptr("10.1.2.3"), - IPv6DnsNameServers: utils.Ptr([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"}), - IPv6PrefixLength: utils.Ptr(int64(24)), - IPv6Prefix: utils.Ptr("2001:4860:4860::8888"), - IPv6Gateway: utils.Ptr("2001:4860:4860::8888"), - NonRouted: false, + Name: utils.Ptr(testNetworkName), + NonRouted: testNonRouted, Labels: utils.Ptr(map[string]string{ "key": "value", }), @@ -72,8 +108,40 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { return model } +func fixtureInputModelWithPrefix(mods ...func(model *inputModel)) *inputModel { + model := fixtureInputModel() + + model.IPv4DnsNameServers = utils.Ptr(testIPv4NameServers) + model.IPv4Prefix = utils.Ptr(testIPv4Prefix) + model.IPv4Gateway = utils.Ptr(testIPv4Gateway) + + model.IPv6DnsNameServers = utils.Ptr(testIPv6NameServers) + model.IPv6Prefix = utils.Ptr(testIPv6Prefix) + model.IPv6Gateway = utils.Ptr(testIPv6Gateway) + + for _, mod := range mods { + mod(model) + } + return model +} + +func fixtureInputModelWithPrefixLength(mods ...func(model *inputModel)) *inputModel { + model := fixtureInputModel() + + model.IPv4DnsNameServers = utils.Ptr(testIPv4NameServers) + model.IPv4PrefixLength = utils.Ptr(testIPv4PrefixLength) + + model.IPv6DnsNameServers = utils.Ptr(testIPv6NameServers) + model.IPv6PrefixLength = utils.Ptr(testIPv6PrefixLength) + + for _, mod := range mods { + mod(model) + } + return model +} + func fixtureRequest(mods ...func(request *iaas.ApiCreateNetworkRequest)) iaas.ApiCreateNetworkRequest { - request := testClient.CreateNetwork(testCtx, testProjectId) + request := testClient.CreateNetwork(testCtx, testProjectId, testRegion) request = request.CreateNetworkPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -82,9 +150,9 @@ func fixtureRequest(mods ...func(request *iaas.ApiCreateNetworkRequest)) iaas.Ap } func fixtureRequiredRequest(mods ...func(request *iaas.ApiCreateNetworkRequest)) iaas.ApiCreateNetworkRequest { - request := testClient.CreateNetwork(testCtx, testProjectId) + request := testClient.CreateNetwork(testCtx, testProjectId, testRegion) request = request.CreateNetworkPayload(iaas.CreateNetworkPayload{ - Name: utils.Ptr("example-network-name"), + Name: utils.Ptr(testNetworkName), Routed: utils.Ptr(true), }) for _, mod := range mods { @@ -100,19 +168,47 @@ func fixturePayload(mods ...func(payload *iaas.CreateNetworkPayload)) iaas.Creat Labels: utils.Ptr(map[string]interface{}{ "key": "value", }), - AddressFamily: &iaas.CreateNetworkAddressFamily{ - Ipv4: &iaas.CreateNetworkIPv4Body{ - Nameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - PrefixLength: utils.Ptr(int64(24)), - Prefix: utils.Ptr("10.1.2.0/24"), - Gateway: iaas.NewNullableString(utils.Ptr("10.1.2.3")), - }, - Ipv6: &iaas.CreateNetworkIPv6Body{ - Nameservers: utils.Ptr([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"}), - PrefixLength: utils.Ptr(int64(24)), - Prefix: utils.Ptr("2001:4860:4860::8888"), - Gateway: iaas.NewNullableString(utils.Ptr("2001:4860:4860::8888")), - }, + } + for _, mod := range mods { + mod(&payload) + } + return payload +} + +func fixturePayloadWithPrefix(mods ...func(payload *iaas.CreateNetworkPayload)) iaas.CreateNetworkPayload { + payload := fixturePayload() + payload.Ipv4 = &iaas.CreateNetworkIPv4{ + CreateNetworkIPv4WithPrefix: &iaas.CreateNetworkIPv4WithPrefix{ + Gateway: iaas.NewNullableString(utils.Ptr(testIPv4Gateway)), + Nameservers: utils.Ptr(testIPv4NameServers), + Prefix: utils.Ptr(testIPv4Prefix), + }, + } + payload.Ipv6 = &iaas.CreateNetworkIPv6{ + CreateNetworkIPv6WithPrefix: &iaas.CreateNetworkIPv6WithPrefix{ + Nameservers: utils.Ptr(testIPv6NameServers), + Prefix: utils.Ptr(testIPv6Prefix), + Gateway: iaas.NewNullableString(utils.Ptr(testIPv6Gateway)), + }, + } + for _, mod := range mods { + mod(&payload) + } + return payload +} + +func fixturePayloadWithPrefixLength(mods ...func(payload *iaas.CreateNetworkPayload)) iaas.CreateNetworkPayload { + payload := fixturePayload() + payload.Ipv4 = &iaas.CreateNetworkIPv4{ + CreateNetworkIPv4WithPrefixLength: &iaas.CreateNetworkIPv4WithPrefixLength{ + PrefixLength: utils.Ptr(testIPv4PrefixLength), + Nameservers: utils.Ptr(testIPv4NameServers), + }, + } + payload.Ipv6 = &iaas.CreateNetworkIPv6{ + CreateNetworkIPv6WithPrefixLength: &iaas.CreateNetworkIPv6WithPrefixLength{ + PrefixLength: utils.Ptr(testIPv6PrefixLength), + Nameservers: utils.Ptr(testIPv6NameServers), }, } for _, mod := range mods { @@ -137,15 +233,21 @@ func TestParseInput(t *testing.T) { }, { description: "required only", - flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, ipv4DnsNameServersFlag) - delete(flagValues, ipv4PrefixLengthFlag) - }), + flagValues: map[string]string{ + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + nameFlag: testNetworkName, + }, isValid: true, - expectedModel: fixtureInputModel(func(model *inputModel) { - model.IPv4DnsNameServers = nil - model.IPv4PrefixLength = nil - }), + expectedModel: &inputModel{ + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Verbosity: globalflags.VerbosityDefault, + Region: testRegion, + }, + Name: utils.Ptr(testNetworkName), + }, }, { description: "name missing", @@ -162,66 +264,110 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, { - description: "use dns servers, prefix, gateway and prefix length", - flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[ipv4DnsNameServersFlag] = "1.1.1.1" - flagValues[ipv4PrefixLengthFlag] = "25" - flagValues[ipv4PrefixFlag] = "10.1.2.0/24" - flagValues[ipv4GatewayFlag] = "10.1.2.3" + description: "use with prefix", + flagValues: fixtureFlagValuesWithPrefix(), + isValid: true, + expectedModel: fixtureInputModelWithPrefix(), + }, + { + description: "use with prefix only ipv4", + flagValues: fixtureFlagValuesWithPrefix(func(flagValues map[string]string) { + delete(flagValues, ipv6GatewayFlag) + delete(flagValues, ipv6PrefixFlag) + delete(flagValues, ipv6PrefixLengthFlag) + delete(flagValues, ipv6DnsNameServersFlag) }), isValid: true, - expectedModel: fixtureInputModel(func(model *inputModel) { - model.IPv4DnsNameServers = utils.Ptr([]string{"1.1.1.1"}) - model.IPv4PrefixLength = utils.Ptr(int64(25)) - model.IPv4Prefix = utils.Ptr("10.1.2.0/24") - model.IPv4Gateway = utils.Ptr("10.1.2.3") + expectedModel: fixtureInputModelWithPrefix(func(model *inputModel) { + model.IPv6PrefixLength = nil + model.IPv6Prefix = nil + model.IPv6DnsNameServers = nil + model.IPv6Gateway = nil }), }, { - description: "use ipv4 gateway nil", - flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[noIpv4GatewayFlag] = "true" + description: "use with prefix only ipv6", + flagValues: fixtureFlagValuesWithPrefix(func(flagValues map[string]string) { delete(flagValues, ipv4GatewayFlag) + delete(flagValues, ipv4PrefixFlag) + delete(flagValues, ipv4PrefixLengthFlag) + delete(flagValues, ipv4DnsNameServersFlag) }), isValid: true, - expectedModel: fixtureInputModel(func(model *inputModel) { - model.NoIPv4Gateway = true + expectedModel: fixtureInputModelWithPrefix(func(model *inputModel) { + model.IPv4PrefixLength = nil + model.IPv4Prefix = nil + model.IPv4DnsNameServers = nil + model.IPv4Gateway = nil + }), + }, + { + description: "use with prefixLength", + flagValues: fixtureFlagValuesWithPrefixLength(), + isValid: true, + expectedModel: fixtureInputModelWithPrefixLength(), + }, + { + description: "use with prefixLength only ipv4", + flagValues: fixtureFlagValuesWithPrefixLength(func(flagValues map[string]string) { + delete(flagValues, ipv6GatewayFlag) + delete(flagValues, ipv6PrefixFlag) + delete(flagValues, ipv6PrefixLengthFlag) + delete(flagValues, ipv6DnsNameServersFlag) + }), + isValid: true, + expectedModel: fixtureInputModelWithPrefixLength(func(model *inputModel) { + model.IPv6PrefixLength = nil + model.IPv6Prefix = nil + model.IPv6DnsNameServers = nil + model.IPv6Gateway = nil + }), + }, + { + description: "use with prefixLength only ipv6", + flagValues: fixtureFlagValuesWithPrefixLength(func(flagValues map[string]string) { + delete(flagValues, ipv4GatewayFlag) + delete(flagValues, ipv4PrefixFlag) + delete(flagValues, ipv4PrefixLengthFlag) + delete(flagValues, ipv4DnsNameServersFlag) + }), + isValid: true, + expectedModel: fixtureInputModelWithPrefixLength(func(model *inputModel) { + model.IPv4PrefixLength = nil + model.IPv4Prefix = nil + model.IPv4DnsNameServers = nil model.IPv4Gateway = nil }), }, { - description: "use ipv6 dns servers, prefix, gateway and prefix length", + description: "use ipv4 gateway nil", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[ipv6DnsNameServersFlag] = "2001:4860:4860::8888" - flagValues[ipv6PrefixLengthFlag] = "25" - flagValues[ipv6PrefixFlag] = "2001:4860:4860::8888" - flagValues[ipv6GatewayFlag] = "2001:4860:4860::8888" + flagValues[noIpv4GatewayFlag] = "true" + delete(flagValues, ipv4GatewayFlag) }), isValid: true, expectedModel: fixtureInputModel(func(model *inputModel) { - model.IPv6DnsNameServers = utils.Ptr([]string{"2001:4860:4860::8888"}) - model.IPv6PrefixLength = utils.Ptr(int64(25)) - model.IPv6Prefix = utils.Ptr("2001:4860:4860::8888") - model.IPv6Gateway = utils.Ptr("2001:4860:4860::8888") + model.NoIPv4Gateway = true + model.IPv4Gateway = nil }), }, { @@ -236,6 +382,72 @@ func TestParseInput(t *testing.T) { model.IPv6Gateway = nil }), }, + { + description: "ipv4 prefix length and prefix conflict", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4PrefixFlag] = testIPv4Prefix + flagValues[ipv4PrefixLengthFlag] = strconv.FormatInt(testIPv4PrefixLength, 10) + }), + isValid: false, + expectedModel: nil, + }, + { + description: "ipv6 prefix length and prefix conflict", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv6PrefixFlag] = testIPv6Prefix + flagValues[ipv6PrefixLengthFlag] = strconv.FormatInt(testIPv6PrefixLength, 10) + }), + isValid: false, + expectedModel: nil, + }, + { + description: "ipv4 nameserver with missing prefix or prefix length", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4DnsNameServersFlag] = strings.Join(testIPv4NameServers, ",") + }), + isValid: false, + expectedModel: nil, + }, + { + description: "ipv6 nameserver with missing prefix or prefix length", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv6DnsNameServersFlag] = strings.Join(testIPv6NameServers, ",") + }), + isValid: false, + expectedModel: nil, + }, + { + description: "ipv4 gateway and no-gateway flag conflict", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4GatewayFlag] = testIPv4Gateway + flagValues[noIpv4GatewayFlag] = "true" + }), + isValid: false, + }, + { + description: "ipv6 gateway and no-gateway flag conflict", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv6GatewayFlag] = testIPv4Gateway + flagValues[noIpv6GatewayFlag] = "true" + }), + isValid: false, + }, + { + description: "ipv4 gateway and prefixLength flag conflict", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv4GatewayFlag] = testIPv4Gateway + flagValues[ipv4PrefixLengthFlag] = strconv.FormatInt(testIPv4PrefixLength, 10) + }), + isValid: false, + }, + { + description: "ipv6 gateway and prefixLength flag conflict", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[ipv6GatewayFlag] = testIPv6Gateway + flagValues[ipv6PrefixLengthFlag] = strconv.FormatInt(testIPv6PrefixLength, 10) + }), + isValid: false, + }, { description: "non-routed network", flagValues: fixtureFlagValues(func(flagValues map[string]string) { @@ -282,107 +494,98 @@ func TestBuildRequest(t *testing.T) { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - Name: utils.Ptr("example-network-name"), + Name: utils.Ptr(testNetworkName), }, expectedRequest: fixtureRequiredRequest(), }, + { + description: "use prefix length", + model: fixtureInputModelWithPrefixLength(), + expectedRequest: fixtureRequest(func(request *iaas.ApiCreateNetworkRequest) { + *request = (*request).CreateNetworkPayload(fixturePayloadWithPrefixLength()) + }), + }, + { + description: "use prefix", + model: fixtureInputModelWithPrefix(), + expectedRequest: fixtureRequest(func(request *iaas.ApiCreateNetworkRequest) { + *request = (*request).CreateNetworkPayload(fixturePayloadWithPrefix()) + }), + }, { description: "non-routed network", model: &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, - Name: utils.Ptr("example-network-name"), + Name: utils.Ptr(testNetworkName), NonRouted: true, }, - expectedRequest: testClient.CreateNetwork(testCtx, testProjectId).CreateNetworkPayload(iaas.CreateNetworkPayload{ - Name: utils.Ptr("example-network-name"), + expectedRequest: testClient.CreateNetwork(testCtx, testProjectId, testRegion).CreateNetworkPayload(iaas.CreateNetworkPayload{ + Name: utils.Ptr(testNetworkName), Routed: utils.Ptr(false), }), }, { - description: "use dns servers, prefix, gateway and prefix length", + description: "use ipv4 dns servers and prefix length", model: &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, IPv4DnsNameServers: utils.Ptr([]string{"1.1.1.1"}), IPv4PrefixLength: utils.Ptr(int64(25)), - IPv4Prefix: utils.Ptr("10.1.2.0/24"), - IPv4Gateway: utils.Ptr("10.1.2.3"), }, - expectedRequest: testClient.CreateNetwork(testCtx, testProjectId).CreateNetworkPayload(iaas.CreateNetworkPayload{ - AddressFamily: &iaas.CreateNetworkAddressFamily{ - Ipv4: &iaas.CreateNetworkIPv4Body{ - Nameservers: utils.Ptr([]string{"1.1.1.1"}), - PrefixLength: utils.Ptr(int64(25)), - Prefix: utils.Ptr("10.1.2.0/24"), - Gateway: iaas.NewNullableString(utils.Ptr("10.1.2.3")), + expectedRequest: fixtureRequest(func(request *iaas.ApiCreateNetworkRequest) { + *request = (*request).CreateNetworkPayload(iaas.CreateNetworkPayload{ + Ipv4: &iaas.CreateNetworkIPv4{ + CreateNetworkIPv4WithPrefixLength: &iaas.CreateNetworkIPv4WithPrefixLength{ + Nameservers: utils.Ptr([]string{"1.1.1.1"}), + PrefixLength: utils.Ptr(int64(25)), + }, }, - }, - Routed: utils.Ptr(true), + Routed: utils.Ptr(true), + }) }), }, { - description: "use ipv4 gateway nil", - model: &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ - ProjectId: testProjectId, - Verbosity: globalflags.VerbosityDefault, - }, - NoIPv4Gateway: true, - IPv4Gateway: nil, - }, - expectedRequest: testClient.CreateNetwork(testCtx, testProjectId).CreateNetworkPayload(iaas.CreateNetworkPayload{ - AddressFamily: &iaas.CreateNetworkAddressFamily{ - Ipv4: &iaas.CreateNetworkIPv4Body{ - Gateway: iaas.NewNullableString(nil), - }, - }, - Routed: utils.Ptr(true), + description: "use prefix with no gateway", + model: fixtureInputModelWithPrefix(func(model *inputModel) { + model.NoIPv4Gateway = true + model.NoIPv6Gateway = true + }), + expectedRequest: fixtureRequest(func(request *iaas.ApiCreateNetworkRequest) { + *request = (*request).CreateNetworkPayload( + fixturePayloadWithPrefix(func(payload *iaas.CreateNetworkPayload) { + payload.Ipv4.CreateNetworkIPv4WithPrefix.Gateway = iaas.NewNullableString(nil) + payload.Ipv6.CreateNetworkIPv6WithPrefix.Gateway = iaas.NewNullableString(nil) + }), + ) }), }, { - description: "use ipv6 dns servers, prefix, gateway and prefix length", + description: "use ipv6 dns servers, prefix and gateway", model: &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, IPv6DnsNameServers: utils.Ptr([]string{"2001:4860:4860::8888"}), - IPv6PrefixLength: utils.Ptr(int64(25)), IPv6Prefix: utils.Ptr("2001:4860:4860::8888"), IPv6Gateway: utils.Ptr("2001:4860:4860::8888"), }, - expectedRequest: testClient.CreateNetwork(testCtx, testProjectId).CreateNetworkPayload(iaas.CreateNetworkPayload{ - AddressFamily: &iaas.CreateNetworkAddressFamily{ - Ipv6: &iaas.CreateNetworkIPv6Body{ - Nameservers: utils.Ptr([]string{"2001:4860:4860::8888"}), - PrefixLength: utils.Ptr(int64(25)), - Prefix: utils.Ptr("2001:4860:4860::8888"), - Gateway: iaas.NewNullableString(utils.Ptr("2001:4860:4860::8888")), - }, - }, - Routed: utils.Ptr(true), - }), - }, - { - description: "use ipv6 gateway nil", - model: &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ - ProjectId: testProjectId, - Verbosity: globalflags.VerbosityDefault, - }, - NoIPv6Gateway: true, - IPv6Gateway: nil, - }, - expectedRequest: testClient.CreateNetwork(testCtx, testProjectId).CreateNetworkPayload(iaas.CreateNetworkPayload{ - AddressFamily: &iaas.CreateNetworkAddressFamily{ - Ipv6: &iaas.CreateNetworkIPv6Body{ - Gateway: iaas.NewNullableString(nil), + expectedRequest: testClient.CreateNetwork(testCtx, testProjectId, testRegion).CreateNetworkPayload(iaas.CreateNetworkPayload{ + Ipv6: &iaas.CreateNetworkIPv6{ + CreateNetworkIPv6WithPrefix: &iaas.CreateNetworkIPv6WithPrefix{ + Nameservers: utils.Ptr([]string{"2001:4860:4860::8888"}), + Prefix: utils.Ptr("2001:4860:4860::8888"), + Gateway: iaas.NewNullableString(utils.Ptr("2001:4860:4860::8888")), }, }, Routed: utils.Ptr(true), @@ -393,7 +596,7 @@ func TestBuildRequest(t *testing.T) { t.Run(tt.description, func(t *testing.T) { request := buildRequest(testCtx, tt.model, testClient) - diff := cmp.Diff(request, tt.expectedRequest, + diff := cmp.Diff(tt.expectedRequest, request, cmp.AllowUnexported(tt.expectedRequest), cmpopts.EquateComparable(testCtx), cmp.AllowUnexported(iaas.NullableString{}), diff --git a/internal/cmd/network/delete/delete.go b/internal/cmd/network/delete/delete.go index 473edf34b..e101edf0a 100644 --- a/internal/cmd/network/delete/delete.go +++ b/internal/cmd/network/delete/delete.go @@ -57,7 +57,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.NetworkId) + networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.Region, model.NetworkId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network name: %v", err) networkLabel = model.NetworkId @@ -84,7 +84,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deleting network") - _, err = wait.DeleteNetworkWaitHandler(ctx, apiClient, model.ProjectId, model.NetworkId).WaitWithContext(ctx) + _, err = wait.DeleteNetworkWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.NetworkId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for network deletion: %w", err) } @@ -120,5 +120,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteNetworkRequest { - return apiClient.DeleteNetwork(ctx, model.ProjectId, model.NetworkId) + return apiClient.DeleteNetwork(ctx, model.ProjectId, model.Region, model.NetworkId) } diff --git a/internal/cmd/network/delete/delete_test.go b/internal/cmd/network/delete/delete_test.go index 20c5eed47..76627b697 100644 --- a/internal/cmd/network/delete/delete_test.go +++ b/internal/cmd/network/delete/delete_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, NetworkId: testNetworkId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteNetworkRequest)) iaas.ApiDeleteNetworkRequest { - request := testClient.DeleteNetwork(testCtx, testProjectId, testNetworkId) + request := testClient.DeleteNetwork(testCtx, testProjectId, testRegion, testNetworkId) for _, mod := range mods { mod(&request) } @@ -101,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -109,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -117,7 +121,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/network/describe/describe.go b/internal/cmd/network/describe/describe.go index e7315519a..c7f0d08bc 100644 --- a/internal/cmd/network/describe/describe.go +++ b/internal/cmd/network/describe/describe.go @@ -88,7 +88,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetNetworkRequest { - return apiClient.GetNetwork(ctx, model.ProjectId, model.NetworkId) + return apiClient.GetNetwork(ctx, model.ProjectId, model.Region, model.NetworkId) } func outputResult(p *print.Printer, outputFormat string, network *iaas.Network) error { @@ -96,36 +96,49 @@ func outputResult(p *print.Printer, outputFormat string, network *iaas.Network) return fmt.Errorf("network cannot be nil") } return p.OutputResult(outputFormat, network, func() error { - var ipv4nameservers []string - if network.Nameservers != nil { - ipv4nameservers = append(ipv4nameservers, *network.Nameservers...) - } - - var ipv4prefixes []string - if network.Prefixes != nil { - ipv4prefixes = append(ipv4prefixes, *network.Prefixes...) - } - - var ipv6nameservers []string - if network.NameserversV6 != nil { - ipv6nameservers = append(ipv6nameservers, *network.NameserversV6...) + // IPv4 + var ipv4Nameservers, ipv4Prefixes []string + var publicIp, ipv4Gateway *string + if ipv4 := network.Ipv4; ipv4 != nil { + if ipv4.Nameservers != nil { + ipv4Nameservers = append(ipv4Nameservers, *ipv4.Nameservers...) + } + if ipv4.Prefixes != nil { + ipv4Prefixes = append(ipv4Prefixes, *ipv4.Prefixes...) + } + if ipv4.PublicIp != nil { + publicIp = ipv4.PublicIp + } + if ipv4.Gateway != nil && ipv4.Gateway.IsSet() { + ipv4Gateway = ipv4.Gateway.Get() + } } - var ipv6prefixes []string - if network.PrefixesV6 != nil { - ipv6prefixes = append(ipv6prefixes, *network.PrefixesV6...) + // IPv6 + var ipv6Nameservers, ipv6Prefixes []string + var ipv6Gateway *string + if ipv6 := network.Ipv6; ipv6 != nil { + if ipv6.Nameservers != nil { + ipv6Nameservers = append(ipv6Nameservers, *ipv6.Nameservers...) + } + if ipv6.Prefixes != nil { + ipv6Prefixes = append(ipv6Prefixes, *ipv6.Prefixes...) + } + if ipv6.Gateway != nil && ipv6.Gateway.IsSet() { + ipv6Gateway = ipv6.Gateway.Get() + } } table := tables.NewTable() - table.AddRow("ID", utils.PtrString(network.NetworkId)) + table.AddRow("ID", utils.PtrString(network.Id)) table.AddSeparator() table.AddRow("NAME", utils.PtrString(network.Name)) table.AddSeparator() - table.AddRow("STATE", utils.PtrString(network.State)) + table.AddRow("STATE", utils.PtrString(network.Status)) table.AddSeparator() - if network.PublicIp != nil { - table.AddRow("PUBLIC IP", *network.PublicIp) + if publicIp != nil { + table.AddRow("PUBLIC IP", *publicIp) table.AddSeparator() } @@ -137,33 +150,33 @@ func outputResult(p *print.Printer, outputFormat string, network *iaas.Network) table.AddRow("ROUTED", routed) table.AddSeparator() - if network.Gateway != nil { - table.AddRow("IPv4 GATEWAY", *network.Gateway.Get()) + if ipv4Gateway != nil { + table.AddRow("IPv4 GATEWAY", *ipv4Gateway) table.AddSeparator() } - if len(ipv4nameservers) > 0 { - table.AddRow("IPv4 NAME SERVERS", strings.Join(ipv4nameservers, ", ")) + if len(ipv4Nameservers) > 0 { + table.AddRow("IPv4 NAME SERVERS", strings.Join(ipv4Nameservers, ", ")) } table.AddSeparator() - if len(ipv4prefixes) > 0 { - table.AddRow("IPv4 PREFIXES", strings.Join(ipv4prefixes, ", ")) + if len(ipv4Prefixes) > 0 { + table.AddRow("IPv4 PREFIXES", strings.Join(ipv4Prefixes, ", ")) } table.AddSeparator() - if network.Gatewayv6 != nil { - table.AddRow("IPv6 GATEWAY", *network.Gatewayv6.Get()) + if ipv6Gateway != nil { + table.AddRow("IPv6 GATEWAY", *ipv6Gateway) table.AddSeparator() } - if len(ipv6nameservers) > 0 { - table.AddRow("IPv6 NAME SERVERS", strings.Join(ipv6nameservers, ", ")) + if len(ipv6Nameservers) > 0 { + table.AddRow("IPv6 NAME SERVERS", strings.Join(ipv6Nameservers, ", ")) + table.AddSeparator() } - table.AddSeparator() - if len(ipv6prefixes) > 0 { - table.AddRow("IPv6 PREFIXES", strings.Join(ipv6prefixes, ", ")) + if len(ipv6Prefixes) > 0 { + table.AddRow("IPv6 PREFIXES", strings.Join(ipv6Prefixes, ", ")) + table.AddSeparator() } - table.AddSeparator() if network.Labels != nil && len(*network.Labels) > 0 { var labels []string for key, value := range *network.Labels { diff --git a/internal/cmd/network/describe/describe_test.go b/internal/cmd/network/describe/describe_test.go index 098baa905..5a9015489 100644 --- a/internal/cmd/network/describe/describe_test.go +++ b/internal/cmd/network/describe/describe_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,7 +38,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -49,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, NetworkId: testNetworkId, } @@ -59,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetNetworkRequest)) iaas.ApiGetNetworkRequest { - request := testClient.GetNetwork(testCtx, testProjectId, testNetworkId) + request := testClient.GetNetwork(testCtx, testProjectId, testRegion, testNetworkId) for _, mod := range mods { mod(&request) } @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -111,7 +115,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -119,7 +123,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, @@ -194,6 +198,24 @@ func TestOutputResult(t *testing.T) { }, wantErr: false, }, + { + name: "set empty ipv4", + args: args{ + network: &iaas.Network{ + Ipv4: &iaas.NetworkIPv4{}, + }, + }, + wantErr: false, + }, + { + name: "set empty ipv6", + args: args{ + network: &iaas.Network{ + Ipv6: &iaas.NetworkIPv6{}, + }, + }, + wantErr: false, + }, } p := print.NewPrinter() p.Cmd = NewCmd(¶ms.CmdParams{Printer: p}) diff --git a/internal/cmd/network/list/list.go b/internal/cmd/network/list/list.go index a0c871466..e92ab31cc 100644 --- a/internal/cmd/network/list/list.go +++ b/internal/cmd/network/list/list.go @@ -130,7 +130,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworksRequest { - req := apiClient.ListNetworks(ctx, model.ProjectId) + req := apiClient.ListNetworks(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } @@ -143,18 +143,21 @@ func outputResult(p *print.Printer, outputFormat string, networks []iaas.Network table.SetHeader("ID", "NAME", "STATUS", "PUBLIC IP", "PREFIXES", "ROUTED") for _, network := range networks { - publicIp := utils.PtrString(network.PublicIp) + var publicIp, prefixes string + if ipv4 := network.Ipv4; ipv4 != nil { + publicIp = utils.PtrString(ipv4.PublicIp) + prefixes = utils.JoinStringPtr(ipv4.Prefixes, ", ") + } routed := false if network.Routed != nil { routed = *network.Routed } - prefixes := utils.JoinStringPtr(network.Prefixes, ", ") table.AddRow( - utils.PtrString(network.NetworkId), + utils.PtrString(network.Id), utils.PtrString(network.Name), - utils.PtrString(network.State), + utils.PtrString(network.Status), publicIp, prefixes, routed, diff --git a/internal/cmd/network/list/list_test.go b/internal/cmd/network/list/list_test.go index f408eeb78..d753ab11d 100644 --- a/internal/cmd/network/list/list_test.go +++ b/internal/cmd/network/list/list_test.go @@ -16,18 +16,22 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" + testLabelSelector = "foo=bar" +) type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &iaas.APIClient{} var testProjectId = uuid.NewString() -var testLabelSelector = "foo=bar" func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", labelSelectorFlag: testLabelSelector, } @@ -42,6 +46,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), @@ -53,7 +58,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListNetworksRequest)) iaas.ApiListNetworksRequest { - request := testClient.ListNetworks(testCtx, testProjectId) + request := testClient.ListNetworks(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabelSelector) for _, mod := range mods { mod(&request) @@ -88,21 +93,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/network/update/update.go b/internal/cmd/network/update/update.go index 8527a901f..b1891fd34 100644 --- a/internal/cmd/network/update/update.go +++ b/internal/cmd/network/update/update.go @@ -84,7 +84,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.NetworkId) + networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.Region, model.NetworkId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network name: %v", err) networkLabel = model.NetworkId @@ -112,7 +112,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Updating network") - _, err = wait.UpdateNetworkWaitHandler(ctx, apiClient, model.ProjectId, networkId).WaitWithContext(ctx) + _, err = wait.UpdateNetworkWaitHandler(ctx, apiClient, model.ProjectId, model.Region, networkId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for network update: %w", err) } @@ -168,41 +168,40 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiPartialUpdateNetworkRequest { - req := apiClient.PartialUpdateNetwork(ctx, model.ProjectId, model.NetworkId) - addressFamily := &iaas.UpdateNetworkAddressFamily{} + req := apiClient.PartialUpdateNetwork(ctx, model.ProjectId, model.Region, model.NetworkId) + var payloadIPv4 *iaas.UpdateNetworkIPv4Body + var payloadIPv6 *iaas.UpdateNetworkIPv6Body if model.IPv6DnsNameServers != nil || model.NoIPv6Gateway || model.IPv6Gateway != nil { - addressFamily.Ipv6 = &iaas.UpdateNetworkIPv6Body{ + payloadIPv6 = &iaas.UpdateNetworkIPv6Body{ Nameservers: model.IPv6DnsNameServers, } if model.NoIPv6Gateway { - addressFamily.Ipv6.Gateway = iaas.NewNullableString(nil) + payloadIPv6.Gateway = iaas.NewNullableString(nil) } else if model.IPv6Gateway != nil { - addressFamily.Ipv6.Gateway = iaas.NewNullableString(model.IPv6Gateway) + payloadIPv6.Gateway = iaas.NewNullableString(model.IPv6Gateway) } } if model.IPv4DnsNameServers != nil || model.NoIPv4Gateway || model.IPv4Gateway != nil { - addressFamily.Ipv4 = &iaas.UpdateNetworkIPv4Body{ + payloadIPv4 = &iaas.UpdateNetworkIPv4Body{ Nameservers: model.IPv4DnsNameServers, } if model.NoIPv4Gateway { - addressFamily.Ipv4.Gateway = iaas.NewNullableString(nil) + payloadIPv4.Gateway = iaas.NewNullableString(nil) } else if model.IPv4Gateway != nil { - addressFamily.Ipv4.Gateway = iaas.NewNullableString(model.IPv4Gateway) + payloadIPv4.Gateway = iaas.NewNullableString(model.IPv4Gateway) } } payload := iaas.PartialUpdateNetworkPayload{ Name: model.Name, + Ipv4: payloadIPv4, + Ipv6: payloadIPv6, Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), } - if addressFamily.Ipv4 != nil || addressFamily.Ipv6 != nil { - payload.AddressFamily = addressFamily - } - return req.PartialUpdateNetworkPayload(payload) } diff --git a/internal/cmd/network/update/update_test.go b/internal/cmd/network/update/update_test.go index d05624840..236fbcd8b 100644 --- a/internal/cmd/network/update/update_test.go +++ b/internal/cmd/network/update/update_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +39,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + nameFlag: "example-network-name", - projectIdFlag: testProjectId, ipv4DnsNameServersFlag: "1.1.1.0,1.1.2.0", ipv4GatewayFlag: "10.1.2.3", ipv6DnsNameServersFlag: "2001:4860:4860::8888,2001:4860:4860::8844", @@ -56,6 +60,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, Name: utils.Ptr("example-network-name"), NetworkId: testNetworkId, @@ -74,7 +79,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiPartialUpdateNetworkRequest)) iaas.ApiPartialUpdateNetworkRequest { - request := testClient.PartialUpdateNetwork(testCtx, testProjectId, testNetworkId) + request := testClient.PartialUpdateNetwork(testCtx, testProjectId, testRegion, testNetworkId) request = request.PartialUpdateNetworkPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -88,15 +93,13 @@ func fixturePayload(mods ...func(payload *iaas.PartialUpdateNetworkPayload)) iaa Labels: utils.Ptr(map[string]interface{}{ "key": "value", }), - AddressFamily: &iaas.UpdateNetworkAddressFamily{ - Ipv4: &iaas.UpdateNetworkIPv4Body{ - Nameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), - Gateway: iaas.NewNullableString(utils.Ptr("10.1.2.3")), - }, - Ipv6: &iaas.UpdateNetworkIPv6Body{ - Nameservers: utils.Ptr([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"}), - Gateway: iaas.NewNullableString(utils.Ptr("2001:4860:4860::8888")), - }, + Ipv4: &iaas.UpdateNetworkIPv4Body{ + Nameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}), + Gateway: iaas.NewNullableString(utils.Ptr("10.1.2.3")), + }, + Ipv6: &iaas.UpdateNetworkIPv6Body{ + Nameservers: utils.Ptr([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"}), + Gateway: iaas.NewNullableString(utils.Ptr("2001:4860:4860::8888")), }, } for _, mod := range mods { @@ -142,7 +145,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -150,7 +153,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -158,7 +161,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/associate/associate.go b/internal/cmd/public-ip/associate/associate.go index e2398fe08..ec2ac72c3 100644 --- a/internal/cmd/public-ip/associate/associate.go +++ b/internal/cmd/public-ip/associate/associate.go @@ -56,7 +56,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.PublicIpId) + publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.Region, model.PublicIpId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get public IP: %v", err) publicIpLabel = model.PublicIpId @@ -113,7 +113,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdatePublicIPRequest { - req := apiClient.UpdatePublicIP(ctx, model.ProjectId, model.PublicIpId) + req := apiClient.UpdatePublicIP(ctx, model.ProjectId, model.Region, model.PublicIpId) payload := iaas.UpdatePublicIPPayload{ NetworkInterface: iaas.NewNullableString(model.AssociatedResourceId), diff --git a/internal/cmd/public-ip/associate/associate_test.go b/internal/cmd/public-ip/associate/associate_test.go index bc2b890e7..18084731d 100644 --- a/internal/cmd/public-ip/associate/associate_test.go +++ b/internal/cmd/public-ip/associate/associate_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +39,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + associatedResourceIdFlag: testAssociatedResourceId, } for _, mod := range mods { @@ -51,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, PublicIpId: testPublicIpId, AssociatedResourceId: utils.Ptr(testAssociatedResourceId), @@ -62,7 +67,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdatePublicIPRequest)) iaas.ApiUpdatePublicIPRequest { - request := testClient.UpdatePublicIP(testCtx, testProjectId, testPublicIpId) + request := testClient.UpdatePublicIP(testCtx, testProjectId, testRegion, testPublicIpId) request = request.UpdatePublicIPPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -105,7 +110,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -113,7 +118,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -121,7 +126,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/create/create.go b/internal/cmd/public-ip/create/create.go index 1929e81e6..872a95057 100644 --- a/internal/cmd/public-ip/create/create.go +++ b/internal/cmd/public-ip/create/create.go @@ -114,7 +114,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreatePublicIPRequest { - req := apiClient.CreatePublicIP(ctx, model.ProjectId) + req := apiClient.CreatePublicIP(ctx, model.ProjectId, model.Region) payload := iaas.CreatePublicIPPayload{ NetworkInterface: iaas.NewNullableString(model.AssociatedResourceId), diff --git a/internal/cmd/public-ip/create/create_test.go b/internal/cmd/public-ip/create/create_test.go index 5e946f386..3602a422b 100644 --- a/internal/cmd/public-ip/create/create_test.go +++ b/internal/cmd/public-ip/create/create_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -28,7 +30,9 @@ var testAssociatedResourceId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + associatedResourceIdFlag: testAssociatedResourceId, labelFlag: "key=value", } @@ -43,6 +47,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, AssociatedResourceId: utils.Ptr(testAssociatedResourceId), Labels: utils.Ptr(map[string]string{ @@ -56,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreatePublicIPRequest)) iaas.ApiCreatePublicIPRequest { - request := testClient.CreatePublicIP(testCtx, testProjectId) + request := testClient.CreatePublicIP(testCtx, testProjectId, testRegion) request = request.CreatePublicIPPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -122,21 +127,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/delete/delete.go b/internal/cmd/public-ip/delete/delete.go index 525318184..f5f8e340a 100644 --- a/internal/cmd/public-ip/delete/delete.go +++ b/internal/cmd/public-ip/delete/delete.go @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.PublicIpId) + publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.Region, model.PublicIpId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get public IP: %v", err) publicIpLabel = model.PublicIpId @@ -102,5 +102,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeletePublicIPRequest { - return apiClient.DeletePublicIP(ctx, model.ProjectId, model.PublicIpId) + return apiClient.DeletePublicIP(ctx, model.ProjectId, model.Region, model.PublicIpId) } diff --git a/internal/cmd/public-ip/delete/delete_test.go b/internal/cmd/public-ip/delete/delete_test.go index 115c9d2e7..25290233e 100644 --- a/internal/cmd/public-ip/delete/delete_test.go +++ b/internal/cmd/public-ip/delete/delete_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, PublicIpId: testPublicIpId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeletePublicIPRequest)) iaas.ApiDeletePublicIPRequest { - request := testClient.DeletePublicIP(testCtx, testProjectId, testPublicIpId) + request := testClient.DeletePublicIP(testCtx, testProjectId, testRegion, testPublicIpId) for _, mod := range mods { mod(&request) } @@ -101,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -109,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -117,7 +121,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/describe/describe.go b/internal/cmd/public-ip/describe/describe.go index 4ec7836f2..94ff1a5c9 100644 --- a/internal/cmd/public-ip/describe/describe.go +++ b/internal/cmd/public-ip/describe/describe.go @@ -88,7 +88,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetPublicIPRequest { - return apiClient.GetPublicIP(ctx, model.ProjectId, model.PublicIpId) + return apiClient.GetPublicIP(ctx, model.ProjectId, model.Region, model.PublicIpId) } func outputResult(p *print.Printer, outputFormat string, publicIp iaas.PublicIp) error { diff --git a/internal/cmd/public-ip/describe/describe_test.go b/internal/cmd/public-ip/describe/describe_test.go index 05ceefe6e..581eb0496 100644 --- a/internal/cmd/public-ip/describe/describe_test.go +++ b/internal/cmd/public-ip/describe/describe_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,7 +38,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -49,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, PublicIpId: testPublicIpId, } @@ -59,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetPublicIPRequest)) iaas.ApiGetPublicIPRequest { - request := testClient.GetPublicIP(testCtx, testProjectId, testPublicIpId) + request := testClient.GetPublicIP(testCtx, testProjectId, testRegion, testPublicIpId) for _, mod := range mods { mod(&request) } @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -111,7 +115,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -119,7 +123,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/disassociate/disassociate.go b/internal/cmd/public-ip/disassociate/disassociate.go index 7af16991d..3a54d40cb 100644 --- a/internal/cmd/public-ip/disassociate/disassociate.go +++ b/internal/cmd/public-ip/disassociate/disassociate.go @@ -52,7 +52,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - publicIpLabel, associatedResourceId, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.PublicIpId) + publicIpLabel, associatedResourceId, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.Region, model.PublicIpId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get public IP: %v", err) publicIpLabel = model.PublicIpId @@ -100,7 +100,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdatePublicIPRequest { - req := apiClient.UpdatePublicIP(ctx, model.ProjectId, model.PublicIpId) + req := apiClient.UpdatePublicIP(ctx, model.ProjectId, model.Region, model.PublicIpId) payload := iaas.UpdatePublicIPPayload{ NetworkInterface: iaas.NewNullableString(nil), diff --git a/internal/cmd/public-ip/disassociate/disassociate_test.go b/internal/cmd/public-ip/disassociate/disassociate_test.go index 956be6b23..1edc96014 100644 --- a/internal/cmd/public-ip/disassociate/disassociate_test.go +++ b/internal/cmd/public-ip/disassociate/disassociate_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,7 +38,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -49,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, PublicIpId: testPublicIpId, } @@ -59,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdatePublicIPRequest)) iaas.ApiUpdatePublicIPRequest { - request := testClient.UpdatePublicIP(testCtx, testProjectId, testPublicIpId) + request := testClient.UpdatePublicIP(testCtx, testProjectId, testRegion, testPublicIpId) request = request.UpdatePublicIPPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -102,7 +106,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -110,7 +114,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -118,7 +122,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/list/list.go b/internal/cmd/public-ip/list/list.go index 4501c1cab..ec95cb0c6 100644 --- a/internal/cmd/public-ip/list/list.go +++ b/internal/cmd/public-ip/list/list.go @@ -130,7 +130,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListPublicIPsRequest { - req := apiClient.ListPublicIPs(ctx, model.ProjectId) + req := apiClient.ListPublicIPs(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/public-ip/list/list_test.go b/internal/cmd/public-ip/list/list_test.go index 1d6f7b20d..2256ed99c 100644 --- a/internal/cmd/public-ip/list/list_test.go +++ b/internal/cmd/public-ip/list/list_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,9 @@ var testLabelSelector = "label" func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", labelSelectorFlag: testLabelSelector, } @@ -42,6 +46,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), @@ -53,7 +58,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListPublicIPsRequest)) iaas.ApiListPublicIPsRequest { - request := testClient.ListPublicIPs(testCtx, testProjectId) + request := testClient.ListPublicIPs(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabelSelector) for _, mod := range mods { mod(&request) @@ -88,21 +93,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/public-ip/update/update.go b/internal/cmd/public-ip/update/update.go index 4146fb6ee..c4498a032 100644 --- a/internal/cmd/public-ip/update/update.go +++ b/internal/cmd/public-ip/update/update.go @@ -60,7 +60,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.PublicIpId) + publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.Region, model.PublicIpId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get public IP: %v", err) publicIpLabel = model.PublicIpId @@ -117,7 +117,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdatePublicIPRequest { - req := apiClient.UpdatePublicIP(ctx, model.ProjectId, model.PublicIpId) + req := apiClient.UpdatePublicIP(ctx, model.ProjectId, model.Region, model.PublicIpId) payload := iaas.UpdatePublicIPPayload{ Labels: utils.ConvertStringMapToInterfaceMap(model.Labels), diff --git a/internal/cmd/public-ip/update/update_test.go b/internal/cmd/public-ip/update/update_test.go index 87c598665..bf987a524 100644 --- a/internal/cmd/public-ip/update/update_test.go +++ b/internal/cmd/public-ip/update/update_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +39,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - labelFlag: "key=value", + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + labelFlag: "key=value", } for _, mod := range mods { mod(flagValues) @@ -51,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, PublicIpId: testPublicIpId, Labels: utils.Ptr(map[string]string{ @@ -64,7 +69,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdatePublicIPRequest)) iaas.ApiUpdatePublicIPRequest { - request := testClient.UpdatePublicIP(testCtx, testProjectId, testPublicIpId) + request := testClient.UpdatePublicIP(testCtx, testProjectId, testRegion, testPublicIpId) request = request.UpdatePublicIPPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -109,7 +114,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -117,7 +122,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -125,7 +130,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/quota/list/list.go b/internal/cmd/quota/list/list.go index 84835b555..f61151f24 100644 --- a/internal/cmd/quota/list/list.go +++ b/internal/cmd/quota/list/list.go @@ -93,7 +93,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListQuotasRequest { - request := apiClient.ListQuotas(ctx, model.ProjectId) + request := apiClient.ListQuotas(ctx, model.ProjectId, model.Region) return request } diff --git a/internal/cmd/quota/list/list_test.go b/internal/cmd/quota/list/list_test.go index 973f28abb..358749384 100644 --- a/internal/cmd/quota/list/list_test.go +++ b/internal/cmd/quota/list/list_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,8 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -37,7 +40,11 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, } for _, mod := range mods { mod(model) @@ -46,7 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListQuotasRequest)) iaas.ApiListQuotasRequest { - request := testClient.ListQuotas(testCtx, testProjectId) + request := testClient.ListQuotas(testCtx, testProjectId, testRegion) for _, mod := range mods { mod(&request) } @@ -75,21 +82,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/create/create.go b/internal/cmd/security-group/create/create.go index 9598ef794..fd10a585d 100644 --- a/internal/cmd/security-group/create/create.go +++ b/internal/cmd/security-group/create/create.go @@ -115,7 +115,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateSecurityGroupRequest { - request := apiClient.CreateSecurityGroup(ctx, model.ProjectId) + request := apiClient.CreateSecurityGroup(ctx, model.ProjectId, model.Region) payload := iaas.CreateSecurityGroupPayload{ Description: model.Description, diff --git a/internal/cmd/security-group/create/create_test.go b/internal/cmd/security-group/create/create_test.go index 3f936f5ab..9b6d8f92c 100644 --- a/internal/cmd/security-group/create/create_test.go +++ b/internal/cmd/security-group/create/create_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -35,7 +37,9 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + descriptionFlag: testDescription, labelsFlag: "fooKey=fooValue,barKey=barValue,bazKey=bazValue", statefulFlag: "true", @@ -49,11 +53,15 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - Labels: &testLabels, - Description: &testDescription, - Name: &testName, - Stateful: &testStateful, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, + Labels: &testLabels, + Description: &testDescription, + Name: &testName, + Stateful: &testStateful, } for _, mod := range mods { mod(model) @@ -72,7 +80,7 @@ func toStringAnyMapPtr(m map[string]string) map[string]any { return result } func fixtureRequest(mods ...func(request *iaas.ApiCreateSecurityGroupRequest)) iaas.ApiCreateSecurityGroupRequest { - request := testClient.CreateSecurityGroup(testCtx, testProjectId) + request := testClient.CreateSecurityGroup(testCtx, testProjectId, testRegion) request = request.CreateSecurityGroupPayload(iaas.CreateSecurityGroupPayload{ Description: &testDescription, @@ -109,21 +117,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/delete/delete.go b/internal/cmd/security-group/delete/delete.go index 376435432..506dce800 100644 --- a/internal/cmd/security-group/delete/delete.go +++ b/internal/cmd/security-group/delete/delete.go @@ -53,7 +53,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - groupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.SecurityGroupId) + groupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) if err != nil { params.Printer.Warn("get security group name: %v", err) groupLabel = model.SecurityGroupId @@ -98,6 +98,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, cliArgs []string) (*inputM } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteSecurityGroupRequest { - request := apiClient.DeleteSecurityGroup(ctx, model.ProjectId, model.SecurityGroupId) + request := apiClient.DeleteSecurityGroup(ctx, model.ProjectId, model.Region, model.SecurityGroupId) return request } diff --git a/internal/cmd/security-group/delete/delete_test.go b/internal/cmd/security-group/delete/delete_test.go index 5a4787576..e29d614e6 100644 --- a/internal/cmd/security-group/delete/delete_test.go +++ b/internal/cmd/security-group/delete/delete_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,8 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -37,7 +40,11 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, SecurityGroupId: testGroupId, } for _, mod := range mods { @@ -47,7 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteSecurityGroupRequest)) iaas.ApiDeleteSecurityGroupRequest { - request := testClient.DeleteSecurityGroup(testCtx, testProjectId, testGroupId) + request := testClient.DeleteSecurityGroup(testCtx, testProjectId, testRegion, testGroupId) for _, mod := range mods { mod(&request) } @@ -73,14 +80,14 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/describe/describe.go b/internal/cmd/security-group/describe/describe.go index 80fd5cb0c..6d8d615b0 100644 --- a/internal/cmd/security-group/describe/describe.go +++ b/internal/cmd/security-group/describe/describe.go @@ -68,7 +68,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetSecurityGroupRequest { - request := apiClient.GetSecurityGroup(ctx, model.ProjectId, model.SecurityGroupId) + request := apiClient.GetSecurityGroup(ctx, model.ProjectId, model.Region, model.SecurityGroupId) return request } diff --git a/internal/cmd/security-group/describe/describe_test.go b/internal/cmd/security-group/describe/describe_test.go index 62bf425be..1c6f15431 100644 --- a/internal/cmd/security-group/describe/describe_test.go +++ b/internal/cmd/security-group/describe/describe_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -26,7 +28,8 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -36,7 +39,11 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, SecurityGroupId: testSecurityGroupId[0], } for _, mod := range mods { @@ -46,7 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetSecurityGroupRequest)) iaas.ApiGetSecurityGroupRequest { - request := testClient.GetSecurityGroup(testCtx, testProjectId, testSecurityGroupId[0]) + request := testClient.GetSecurityGroup(testCtx, testProjectId, testRegion, testSecurityGroupId[0]) for _, mod := range mods { mod(&request) } @@ -78,7 +85,7 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), args: testSecurityGroupId, isValid: false, @@ -86,7 +93,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), args: testSecurityGroupId, isValid: false, @@ -94,7 +101,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), args: testSecurityGroupId, isValid: false, diff --git a/internal/cmd/security-group/list/list.go b/internal/cmd/security-group/list/list.go index ae9ecdd10..159995162 100644 --- a/internal/cmd/security-group/list/list.go +++ b/internal/cmd/security-group/list/list.go @@ -102,7 +102,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListSecurityGroupsRequest { - request := apiClient.ListSecurityGroups(ctx, model.ProjectId) + request := apiClient.ListSecurityGroups(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { request = request.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/security-group/list/list_test.go b/internal/cmd/security-group/list/list_test.go index 806ab98e3..7e5515059 100644 --- a/internal/cmd/security-group/list/list_test.go +++ b/internal/cmd/security-group/list/list_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -28,7 +30,9 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + labelSelectorFlag: testLabels, } for _, mod := range mods { @@ -39,8 +43,12 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, - LabelSelector: utils.Ptr(testLabels), + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, + LabelSelector: utils.Ptr(testLabels), } for _, mod := range mods { mod(model) @@ -49,7 +57,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListSecurityGroupsRequest)) iaas.ApiListSecurityGroupsRequest { - request := testClient.ListSecurityGroups(testCtx, testProjectId) + request := testClient.ListSecurityGroups(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabels) for _, mod := range mods { mod(&request) @@ -79,21 +87,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/rule/create/create.go b/internal/cmd/security-group/rule/create/create.go index cee025e98..9c87570f3 100644 --- a/internal/cmd/security-group/rule/create/create.go +++ b/internal/cmd/security-group/rule/create/create.go @@ -94,7 +94,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.SecurityGroupId) + securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get security group name: %v", err) securityGroupLabel = model.SecurityGroupId @@ -168,7 +168,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateSecurityGroupRuleRequest { - req := apiClient.CreateSecurityGroupRule(ctx, model.ProjectId, model.SecurityGroupId) + req := apiClient.CreateSecurityGroupRule(ctx, model.ProjectId, model.Region, model.SecurityGroupId) icmpParameters := &iaas.ICMPParameters{} portRange := &iaas.PortRange{} protocol := &iaas.CreateProtocol{} diff --git a/internal/cmd/security-group/rule/create/create_test.go b/internal/cmd/security-group/rule/create/create_test.go index 2432c55ae..4088823e4 100644 --- a/internal/cmd/security-group/rule/create/create_test.go +++ b/internal/cmd/security-group/rule/create/create_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -29,7 +31,9 @@ var testRemoteSecurityGroupId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + securityGroupIdFlag: testSecurityGroupId, directionFlag: "ingress", descriptionFlag: "example-description", @@ -53,6 +57,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, SecurityGroupId: testSecurityGroupId, @@ -75,7 +80,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateSecurityGroupRuleRequest)) iaas.ApiCreateSecurityGroupRuleRequest { - request := testClient.CreateSecurityGroupRule(testCtx, testProjectId, testSecurityGroupId) + request := testClient.CreateSecurityGroupRule(testCtx, testProjectId, testRegion, testSecurityGroupId) request = request.CreateSecurityGroupRulePayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -84,7 +89,7 @@ func fixtureRequest(mods ...func(request *iaas.ApiCreateSecurityGroupRuleRequest } func fixtureRequiredRequest(mods ...func(request *iaas.ApiCreateSecurityGroupRuleRequest)) iaas.ApiCreateSecurityGroupRuleRequest { - request := testClient.CreateSecurityGroupRule(testCtx, testProjectId, testSecurityGroupId) + request := testClient.CreateSecurityGroupRule(testCtx, testProjectId, testRegion, testSecurityGroupId) request = request.CreateSecurityGroupRulePayload(iaas.CreateSecurityGroupRulePayload{ Direction: utils.Ptr("ingress"), }) @@ -203,21 +208,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, @@ -267,6 +272,7 @@ func TestBuildRequest(t *testing.T) { model: &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Direction: utils.Ptr("ingress"), diff --git a/internal/cmd/security-group/rule/delete/delete.go b/internal/cmd/security-group/rule/delete/delete.go index 9248663cf..f0426854b 100644 --- a/internal/cmd/security-group/rule/delete/delete.go +++ b/internal/cmd/security-group/rule/delete/delete.go @@ -27,7 +27,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel SecurityGroupRuleId string - SecurityGroupId *string + SecurityGroupId string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -58,13 +58,13 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, *model.SecurityGroupId) + securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get security group name: %v", err) - securityGroupLabel = *model.SecurityGroupId + securityGroupLabel = model.SecurityGroupId } - securityGroupRuleLabel, err := iaasUtils.GetSecurityGroupRuleName(ctx, apiClient, model.ProjectId, model.SecurityGroupRuleId, *model.SecurityGroupId) + securityGroupRuleLabel, err := iaasUtils.GetSecurityGroupRuleName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupRuleId, model.SecurityGroupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get security group rule name: %v", err) securityGroupRuleLabel = model.SecurityGroupRuleId @@ -111,7 +111,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, SecurityGroupRuleId: securityGroupRuleId, - SecurityGroupId: flags.FlagToStringPointer(p, cmd, securityGroupIdFlag), + SecurityGroupId: flags.FlagToStringValue(p, cmd, securityGroupIdFlag), } p.DebugInputModel(model) @@ -119,5 +119,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteSecurityGroupRuleRequest { - return apiClient.DeleteSecurityGroupRule(ctx, model.ProjectId, *model.SecurityGroupId, model.SecurityGroupRuleId) + return apiClient.DeleteSecurityGroupRule(ctx, model.ProjectId, model.Region, model.SecurityGroupId, model.SecurityGroupRuleId) } diff --git a/internal/cmd/security-group/rule/delete/delete_test.go b/internal/cmd/security-group/rule/delete/delete_test.go index ebf83035c..9f78a7e1a 100644 --- a/internal/cmd/security-group/rule/delete/delete_test.go +++ b/internal/cmd/security-group/rule/delete/delete_test.go @@ -4,18 +4,18 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/cmd/params" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -38,7 +38,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + securityGroupIdFlag: testSecurityGroupId, } for _, mod := range mods { @@ -51,9 +53,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, - SecurityGroupId: utils.Ptr(testSecurityGroupId), + SecurityGroupId: testSecurityGroupId, SecurityGroupRuleId: testSecurityGroupRuleId, } for _, mod := range mods { @@ -63,7 +66,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteSecurityGroupRuleRequest)) iaas.ApiDeleteSecurityGroupRuleRequest { - request := testClient.DeleteSecurityGroupRule(testCtx, testProjectId, testSecurityGroupId, testSecurityGroupRuleId) + request := testClient.DeleteSecurityGroupRule(testCtx, testProjectId, testRegion, testSecurityGroupId, testSecurityGroupRuleId) for _, mod := range mods { mod(&request) } @@ -95,7 +98,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -103,7 +106,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -111,7 +114,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/rule/describe/describe.go b/internal/cmd/security-group/rule/describe/describe.go index 23407466d..12d6edece 100644 --- a/internal/cmd/security-group/rule/describe/describe.go +++ b/internal/cmd/security-group/rule/describe/describe.go @@ -28,7 +28,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel SecurityGroupRuleId string - SecurityGroupId *string + SecurityGroupId string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -92,7 +92,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, SecurityGroupRuleId: securityGroupRuleId, - SecurityGroupId: flags.FlagToStringPointer(p, cmd, securityGroupIdFlag), + SecurityGroupId: flags.FlagToStringValue(p, cmd, securityGroupIdFlag), } p.DebugInputModel(model) @@ -100,7 +100,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetSecurityGroupRuleRequest { - return apiClient.GetSecurityGroupRule(ctx, model.ProjectId, *model.SecurityGroupId, model.SecurityGroupRuleId) + return apiClient.GetSecurityGroupRule(ctx, model.ProjectId, model.Region, model.SecurityGroupId, model.SecurityGroupRuleId) } func outputResult(p *print.Printer, outputFormat string, securityGroupRule *iaas.SecurityGroupRule) error { diff --git a/internal/cmd/security-group/rule/describe/describe_test.go b/internal/cmd/security-group/rule/describe/describe_test.go index 68c84b395..357457705 100644 --- a/internal/cmd/security-group/rule/describe/describe_test.go +++ b/internal/cmd/security-group/rule/describe/describe_test.go @@ -11,11 +11,12 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +38,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + securityGroupIdFlag: testSecurityGroupId, } for _, mod := range mods { @@ -50,9 +53,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, - SecurityGroupId: utils.Ptr(testSecurityGroupId), + SecurityGroupId: testSecurityGroupId, SecurityGroupRuleId: testSecurityGroupRuleId, } for _, mod := range mods { @@ -62,7 +66,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetSecurityGroupRuleRequest)) iaas.ApiGetSecurityGroupRuleRequest { - request := testClient.GetSecurityGroupRule(testCtx, testProjectId, testSecurityGroupId, testSecurityGroupRuleId) + request := testClient.GetSecurityGroupRule(testCtx, testProjectId, testRegion, testSecurityGroupId, testSecurityGroupRuleId) for _, mod := range mods { mod(&request) } @@ -106,7 +110,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -114,7 +118,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -122,7 +126,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/rule/list/list.go b/internal/cmd/security-group/rule/list/list.go index 4984d6b17..7ddb33c7a 100644 --- a/internal/cmd/security-group/rule/list/list.go +++ b/internal/cmd/security-group/rule/list/list.go @@ -30,7 +30,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel Limit *int64 - SecurityGroupId *string + SecurityGroupId string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -74,10 +74,10 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } if resp.Items == nil || len(*resp.Items) == 0 { - securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, *model.SecurityGroupId) + securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get security group name: %v", err) - securityGroupLabel = *model.SecurityGroupId + securityGroupLabel = model.SecurityGroupId } projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) @@ -127,7 +127,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, Limit: limit, - SecurityGroupId: flags.FlagToStringPointer(p, cmd, securityGroupIdFlag), + SecurityGroupId: flags.FlagToStringValue(p, cmd, securityGroupIdFlag), } p.DebugInputModel(model) @@ -135,7 +135,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListSecurityGroupRulesRequest { - return apiClient.ListSecurityGroupRules(ctx, model.ProjectId, *model.SecurityGroupId) + return apiClient.ListSecurityGroupRules(ctx, model.ProjectId, model.Region, model.SecurityGroupId) } func outputResult(p *print.Printer, outputFormat string, securityGroupRules []iaas.SecurityGroupRule) error { diff --git a/internal/cmd/security-group/rule/list/list_test.go b/internal/cmd/security-group/rule/list/list_test.go index ab41b1d87..92ba77801 100644 --- a/internal/cmd/security-group/rule/list/list_test.go +++ b/internal/cmd/security-group/rule/list/list_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -26,7 +28,9 @@ var testSecurityGroupId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", securityGroupIdFlag: testSecurityGroupId, } @@ -41,9 +45,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), - SecurityGroupId: utils.Ptr(testSecurityGroupId), + SecurityGroupId: testSecurityGroupId, } for _, mod := range mods { mod(model) @@ -52,7 +57,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListSecurityGroupRulesRequest)) iaas.ApiListSecurityGroupRulesRequest { - request := testClient.ListSecurityGroupRules(testCtx, testProjectId, testSecurityGroupId) + request := testClient.ListSecurityGroupRules(testCtx, testProjectId, testRegion, testSecurityGroupId) for _, mod := range mods { mod(&request) } @@ -86,21 +91,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/security-group/update/update.go b/internal/cmd/security-group/update/update.go index d0aae546e..c9e255929 100644 --- a/internal/cmd/security-group/update/update.go +++ b/internal/cmd/security-group/update/update.go @@ -64,7 +64,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - groupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.SecurityGroupId) + groupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) if err != nil { params.Printer.Warn("cannot retrieve groupname: %v", err) groupLabel = model.SecurityGroupId @@ -124,7 +124,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, cliArgs []string) (*inputM } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateSecurityGroupRequest { - request := apiClient.UpdateSecurityGroup(ctx, model.ProjectId, model.SecurityGroupId) + request := apiClient.UpdateSecurityGroup(ctx, model.ProjectId, model.Region, model.SecurityGroupId) payload := iaas.NewUpdateSecurityGroupPayload() payload.Description = model.Description payload.Labels = utils.ConvertStringMapToInterfaceMap(model.Labels) diff --git a/internal/cmd/security-group/update/update_test.go b/internal/cmd/security-group/update/update_test.go index e7c6c4f00..081875080 100644 --- a/internal/cmd/security-group/update/update_test.go +++ b/internal/cmd/security-group/update/update_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -46,7 +48,9 @@ func toStringAnyMapPtr(m map[string]string) map[string]any { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + descriptionArg: testDescription, labelsArg: "fooKey=fooValue,barKey=barValue,bazKey=bazValue", nameArg: testName, @@ -59,7 +63,11 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault}, + GlobalFlagModel: &globalflags.GlobalFlagModel{ + ProjectId: testProjectId, + Region: testRegion, + Verbosity: globalflags.VerbosityDefault, + }, Labels: &testLabels, Description: &testDescription, Name: &testName, @@ -72,7 +80,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateSecurityGroupRequest)) iaas.ApiUpdateSecurityGroupRequest { - request := testClient.UpdateSecurityGroup(testCtx, testProjectId, testGroupId[0]) + request := testClient.UpdateSecurityGroup(testCtx, testProjectId, testRegion, testGroupId[0]) request = request.UpdateSecurityGroupPayload(iaas.UpdateSecurityGroupPayload{ Description: &testDescription, Labels: utils.Ptr(toStringAnyMapPtr(testLabels)), @@ -103,7 +111,7 @@ func TestParseInput(t *testing.T) { { description: "no values but valid group id", flagValues: map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, }, args: testGroupId, isValid: false, @@ -116,7 +124,7 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), args: testGroupId, isValid: false, @@ -124,7 +132,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), args: testGroupId, isValid: false, @@ -132,7 +140,7 @@ func TestParseInput(t *testing.T) { { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), args: testGroupId, isValid: false, diff --git a/internal/cmd/server/backup/create/create.go b/internal/cmd/server/backup/create/create.go index 824bbb0b9..4ee1b42a4 100644 --- a/internal/cmd/server/backup/create/create.go +++ b/internal/cmd/server/backup/create/create.go @@ -70,7 +70,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/backup/disable/disable.go b/internal/cmd/server/backup/disable/disable.go index 18acc9627..7fc57c79b 100644 --- a/internal/cmd/server/backup/disable/disable.go +++ b/internal/cmd/server/backup/disable/disable.go @@ -56,7 +56,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/backup/enable/enable.go b/internal/cmd/server/backup/enable/enable.go index 8194ca95e..369434d55 100644 --- a/internal/cmd/server/backup/enable/enable.go +++ b/internal/cmd/server/backup/enable/enable.go @@ -56,7 +56,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/backup/list/list.go b/internal/cmd/server/backup/list/list.go index 58259611f..0e9856d4f 100644 --- a/internal/cmd/server/backup/list/list.go +++ b/internal/cmd/server/backup/list/list.go @@ -70,7 +70,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/backup/schedule/create/create.go b/internal/cmd/server/backup/schedule/create/create.go index 658ab27ee..415f58a8f 100644 --- a/internal/cmd/server/backup/schedule/create/create.go +++ b/internal/cmd/server/backup/schedule/create/create.go @@ -78,7 +78,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/backup/schedule/delete/delete.go b/internal/cmd/server/backup/schedule/delete/delete.go index 3dd8632f4..344ad02c0 100644 --- a/internal/cmd/server/backup/schedule/delete/delete.go +++ b/internal/cmd/server/backup/schedule/delete/delete.go @@ -57,7 +57,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/backup/schedule/list/list.go b/internal/cmd/server/backup/schedule/list/list.go index 1c396d0e1..3111ea55f 100644 --- a/internal/cmd/server/backup/schedule/list/list.go +++ b/internal/cmd/server/backup/schedule/list/list.go @@ -62,7 +62,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/command/create/create.go b/internal/cmd/server/command/create/create.go index 0f489ee7a..a95838116 100644 --- a/internal/cmd/server/command/create/create.go +++ b/internal/cmd/server/command/create/create.go @@ -66,7 +66,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/command/list/list.go b/internal/cmd/server/command/list/list.go index f917b1689..052f13766 100644 --- a/internal/cmd/server/command/list/list.go +++ b/internal/cmd/server/command/list/list.go @@ -62,7 +62,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/console/console.go b/internal/cmd/server/console/console.go index 45d884cec..ea363c540 100644 --- a/internal/cmd/server/console/console.go +++ b/internal/cmd/server/console/console.go @@ -57,7 +57,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -96,7 +96,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetServerConsoleRequest { - return apiClient.GetServerConsole(ctx, model.ProjectId, model.ServerId) + return apiClient.GetServerConsole(ctx, model.ProjectId, model.Region, model.ServerId) } func outputResult(p *print.Printer, outputFormat, serverLabel string, serverUrl iaas.ServerConsoleUrl) error { diff --git a/internal/cmd/server/console/console_test.go b/internal/cmd/server/console/console_test.go index ab80a7fc4..a449d49bc 100644 --- a/internal/cmd/server/console/console_test.go +++ b/internal/cmd/server/console/console_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +39,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -50,6 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, } @@ -60,7 +64,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetServerConsoleRequest)) iaas.ApiGetServerConsoleRequest { - request := testClient.GetServerConsole(testCtx, testProjectId, testServerId) + request := testClient.GetServerConsole(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -98,7 +102,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -106,7 +110,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/create/create.go b/internal/cmd/server/create/create.go index b0142acec..00ebd8254 100644 --- a/internal/cmd/server/create/create.go +++ b/internal/cmd/server/create/create.go @@ -147,7 +147,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Creating server") - _, err = wait.CreateServerWaitHandler(ctx, apiClient, model.ProjectId, serverId).WaitWithContext(ctx) + _, err = wait.CreateServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, serverId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server creation: %w", err) } @@ -185,6 +185,7 @@ func configureFlags(cmd *cobra.Command) { cmd.MarkFlagsMutuallyExclusive(imageIdFlag, bootVolumeSourceIdFlag) cmd.MarkFlagsMutuallyExclusive(imageIdFlag, bootVolumeSourceTypeFlag) cmd.MarkFlagsMutuallyExclusive(networkIdFlag, networkInterfaceIdsFlag) + cmd.MarkFlagsOneRequired(networkIdFlag, networkInterfaceIdsFlag) cobra.CheckErr(err) } @@ -270,7 +271,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateServerRequest { - req := apiClient.CreateServer(ctx, model.ProjectId) + req := apiClient.CreateServer(ctx, model.ProjectId, model.Region) var userData *[]byte if model.UserData != nil { @@ -293,7 +294,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli } if model.BootVolumePerformanceClass != nil || model.BootVolumeSize != nil || model.BootVolumeDeleteOnTermination != nil || model.BootVolumeSourceId != nil || model.BootVolumeSourceType != nil { - payload.BootVolume = &iaas.CreateServerPayloadBootVolume{ + payload.BootVolume = &iaas.ServerBootVolume{ PerformanceClass: model.BootVolumePerformanceClass, Size: model.BootVolumeSize, DeleteOnTermination: model.BootVolumeDeleteOnTermination, @@ -305,7 +306,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli } if model.NetworkInterfaceIds != nil || model.NetworkId != nil { - payload.Networking = &iaas.CreateServerPayloadNetworking{} + payload.Networking = &iaas.CreateServerPayloadAllOfNetworking{} if model.NetworkInterfaceIds != nil { payload.Networking.CreateServerNetworkingWithNics = &iaas.CreateServerNetworkingWithNics{ diff --git a/internal/cmd/server/create/create_test.go b/internal/cmd/server/create/create_test.go index 192caac02..1270eed51 100644 --- a/internal/cmd/server/create/create_test.go +++ b/internal/cmd/server/create/create_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -31,7 +33,9 @@ var testVolumeId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + availabilityZoneFlag: "eu01-1", nameFlag: "test-server-name", machineTypeFlag: "t1.1", @@ -59,6 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, AvailabilityZone: utils.Ptr("eu01-1"), @@ -87,7 +92,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateServerRequest)) iaas.ApiCreateServerRequest { - request := testClient.CreateServer(testCtx, testProjectId) + request := testClient.CreateServer(testCtx, testProjectId, testRegion) request = request.CreateServerPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -96,7 +101,7 @@ func fixtureRequest(mods ...func(request *iaas.ApiCreateServerRequest)) iaas.Api } func fixtureRequiredRequest(mods ...func(request *iaas.ApiCreateServerRequest)) iaas.ApiCreateServerRequest { - request := testClient.CreateServer(testCtx, testProjectId) + request := testClient.CreateServer(testCtx, testProjectId, testRegion) request = request.CreateServerPayload(iaas.CreateServerPayload{ MachineType: utils.Ptr("t1.1"), Name: utils.Ptr("test-server-name"), @@ -121,7 +126,7 @@ func fixturePayload(mods ...func(payload *iaas.CreateServerPayload)) iaas.Create ServiceAccountMails: utils.Ptr([]string{"test-service-account"}), UserData: utils.Ptr([]byte("test-user-data")), Volumes: utils.Ptr([]string{testVolumeId}), - BootVolume: &iaas.CreateServerPayloadBootVolume{ + BootVolume: &iaas.ServerBootVolume{ PerformanceClass: utils.Ptr("test-perf-class"), Size: utils.Ptr(int64(5)), DeleteOnTermination: utils.Ptr(false), @@ -130,7 +135,7 @@ func fixturePayload(mods ...func(payload *iaas.CreateServerPayload)) iaas.Create Type: utils.Ptr("test-source-type"), }, }, - Networking: &iaas.CreateServerPayloadNetworking{ + Networking: &iaas.CreateServerPayloadAllOfNetworking{ CreateServerNetworking: &iaas.CreateServerNetworking{ NetworkId: utils.Ptr(testNetworkId), }, @@ -168,7 +173,6 @@ func TestParseInput(t *testing.T) { delete(flagValues, bootVolumePerformanceClassFlag) delete(flagValues, bootVolumeDeleteOnTerminationFlag) delete(flagValues, keypairNameFlag) - delete(flagValues, networkIdFlag) delete(flagValues, networkInterfaceIdsFlag) delete(flagValues, securityGroupsFlag) delete(flagValues, serviceAccountEmailsFlag) @@ -187,7 +191,6 @@ func TestParseInput(t *testing.T) { model.BootVolumePerformanceClass = nil model.BootVolumeDeleteOnTermination = nil model.KeypairName = nil - model.NetworkId = nil model.NetworkInterfaceIds = nil model.SecurityGroups = nil model.ServiceAccountMails = nil @@ -218,21 +221,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, @@ -350,6 +353,7 @@ func TestBuildRequest(t *testing.T) { model: &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, MachineType: utils.Ptr("t1.1"), diff --git a/internal/cmd/server/deallocate/deallocate.go b/internal/cmd/server/deallocate/deallocate.go index 7d1d4e37d..b55da54b2 100644 --- a/internal/cmd/server/deallocate/deallocate.go +++ b/internal/cmd/server/deallocate/deallocate.go @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -81,7 +81,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deallocating server") - _, err = wait.DeallocateServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.DeallocateServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server deallocating: %w", err) } @@ -118,5 +118,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeallocateServerRequest { - return apiClient.DeallocateServer(ctx, model.ProjectId, model.ServerId) + return apiClient.DeallocateServer(ctx, model.ProjectId, model.Region, model.ServerId) } diff --git a/internal/cmd/server/deallocate/deallocate_test.go b/internal/cmd/server/deallocate/deallocate_test.go index 5f1c06bea..efb00e27f 100644 --- a/internal/cmd/server/deallocate/deallocate_test.go +++ b/internal/cmd/server/deallocate/deallocate_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -46,6 +49,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, + Region: testRegion, ProjectId: testProjectId, }, ServerId: testServerId, @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeallocateServerRequest)) iaas.ApiDeallocateServerRequest { - request := testClient.DeallocateServer(testCtx, testProjectId, testServerId) + request := testClient.DeallocateServer(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -95,7 +99,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/delete/delete.go b/internal/cmd/server/delete/delete.go index f2f5e80db..1a63f5ae1 100644 --- a/internal/cmd/server/delete/delete.go +++ b/internal/cmd/server/delete/delete.go @@ -57,7 +57,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -84,7 +84,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deleting server") - _, err = wait.DeleteServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.DeleteServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server deletion: %w", err) } @@ -120,5 +120,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteServerRequest { - return apiClient.DeleteServer(ctx, model.ProjectId, model.ServerId) + return apiClient.DeleteServer(ctx, model.ProjectId, model.Region, model.ServerId) } diff --git a/internal/cmd/server/delete/delete_test.go b/internal/cmd/server/delete/delete_test.go index 3b72baca3..9534c8b22 100644 --- a/internal/cmd/server/delete/delete_test.go +++ b/internal/cmd/server/delete/delete_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteServerRequest)) iaas.ApiDeleteServerRequest { - request := testClient.DeleteServer(testCtx, testProjectId, testServerId) + request := testClient.DeleteServer(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -101,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -109,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -117,7 +121,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/describe/describe.go b/internal/cmd/server/describe/describe.go index 760444d26..3058cd465 100644 --- a/internal/cmd/server/describe/describe.go +++ b/internal/cmd/server/describe/describe.go @@ -90,7 +90,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetServerRequest { - req := apiClient.GetServer(ctx, model.ProjectId, model.ServerId) + req := apiClient.GetServer(ctx, model.ProjectId, model.Region, model.ServerId) req = req.Details(true) return req diff --git a/internal/cmd/server/describe/describe_test.go b/internal/cmd/server/describe/describe_test.go index 0d416e464..af975d7c6 100644 --- a/internal/cmd/server/describe/describe_test.go +++ b/internal/cmd/server/describe/describe_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,7 +38,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -48,6 +51,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ServerId: testServerId, @@ -59,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetServerRequest)) iaas.ApiGetServerRequest { - request := testClient.GetServer(testCtx, testProjectId, testServerId) + request := testClient.GetServer(testCtx, testProjectId, testRegion, testServerId) request = request.Details(true) for _, mod := range mods { mod(&request) @@ -104,7 +108,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -112,7 +116,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -120,7 +124,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index 0918e1d91..98faf6365 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -130,7 +130,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListServersRequest { - req := apiClient.ListServers(ctx, model.ProjectId) + req := apiClient.ListServers(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/server/list/list_test.go b/internal/cmd/server/list/list_test.go index 1507be485..f23efc370 100644 --- a/internal/cmd/server/list/list_test.go +++ b/internal/cmd/server/list/list_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,9 @@ var testLabelSelector = "label" func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", labelSelectorFlag: testLabelSelector, } @@ -42,6 +46,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), @@ -53,7 +58,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListServersRequest)) iaas.ApiListServersRequest { - request := testClient.ListServers(testCtx, testProjectId) + request := testClient.ListServers(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabelSelector) request = request.Details(true) for _, mod := range mods { @@ -89,21 +94,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/log/log.go b/internal/cmd/server/log/log.go index f4015c298..6b6a59f67 100644 --- a/internal/cmd/server/log/log.go +++ b/internal/cmd/server/log/log.go @@ -66,7 +66,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -128,7 +128,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetServerLogRequest { - return apiClient.GetServerLog(ctx, model.ProjectId, model.ServerId) + return apiClient.GetServerLog(ctx, model.ProjectId, model.Region, model.ServerId) } func outputResult(p *print.Printer, outputFormat, serverLabel, log string) error { diff --git a/internal/cmd/server/log/log_test.go b/internal/cmd/server/log/log_test.go index c1768f672..e9c0c657a 100644 --- a/internal/cmd/server/log/log_test.go +++ b/internal/cmd/server/log/log_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +39,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + lengthLimitFlag: "3000", } for _, mod := range mods { @@ -51,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, Length: utils.Ptr(int64(3000)), @@ -62,7 +67,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetServerLogRequest)) iaas.ApiGetServerLogRequest { - request := testClient.GetServerLog(testCtx, testProjectId, testServerId) + request := testClient.GetServerLog(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -100,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -108,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/machine-type/describe/describe.go b/internal/cmd/server/machine-type/describe/describe.go index 83544b540..2fbdae1de 100644 --- a/internal/cmd/server/machine-type/describe/describe.go +++ b/internal/cmd/server/machine-type/describe/describe.go @@ -87,7 +87,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetMachineTypeRequest { - return apiClient.GetMachineType(ctx, model.ProjectId, model.MachineType) + return apiClient.GetMachineType(ctx, model.ProjectId, model.Region, model.MachineType) } func outputResult(p *print.Printer, outputFormat string, machineType *iaas.MachineType) error { diff --git a/internal/cmd/server/machine-type/describe/describe_test.go b/internal/cmd/server/machine-type/describe/describe_test.go index 81c992468..f423455f6 100644 --- a/internal/cmd/server/machine-type/describe/describe_test.go +++ b/internal/cmd/server/machine-type/describe/describe_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,7 +38,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -48,6 +51,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, MachineType: testMachineType, @@ -59,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetMachineTypeRequest)) iaas.ApiGetMachineTypeRequest { - request := testClient.GetMachineType(testCtx, testProjectId, testMachineType) + request := testClient.GetMachineType(testCtx, testProjectId, testRegion, testMachineType) for _, mod := range mods { mod(&request) } @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -111,7 +115,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -119,7 +123,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/machine-type/list/list.go b/internal/cmd/server/machine-type/list/list.go index 833de684e..db88e7be5 100644 --- a/internal/cmd/server/machine-type/list/list.go +++ b/internal/cmd/server/machine-type/list/list.go @@ -120,7 +120,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListMachineTypesRequest { - return apiClient.ListMachineTypes(ctx, model.ProjectId) + return apiClient.ListMachineTypes(ctx, model.ProjectId, model.Region) } func outputResult(p *print.Printer, outputFormat string, machineTypes iaas.MachineTypeListResponse) error { diff --git a/internal/cmd/server/machine-type/list/list_test.go b/internal/cmd/server/machine-type/list/list_test.go index db8906209..55b5c3c4a 100644 --- a/internal/cmd/server/machine-type/list/list_test.go +++ b/internal/cmd/server/machine-type/list/list_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -26,8 +28,10 @@ var testProjectId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - limitFlag: "10", + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + limitFlag: "10", } for _, mod := range mods { mod(flagValues) @@ -40,6 +44,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), } @@ -50,7 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListMachineTypesRequest)) iaas.ApiListMachineTypesRequest { - request := testClient.ListMachineTypes(testCtx, testProjectId) + request := testClient.ListMachineTypes(testCtx, testProjectId, testRegion) for _, mod := range mods { mod(&request) } @@ -84,21 +89,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/network-interface/attach/attach.go b/internal/cmd/server/network-interface/attach/attach.go index 1d774ffea..639c070a0 100644 --- a/internal/cmd/server/network-interface/attach/attach.go +++ b/internal/cmd/server/network-interface/attach/attach.go @@ -65,7 +65,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, *model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = *model.ServerId @@ -73,7 +73,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { // if the create flag is provided a network interface will be created and attached if model.Create != nil && *model.Create { - networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, *model.NetworkId) + networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.Region, *model.NetworkId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network name: %v", err) networkLabel = *model.NetworkId @@ -157,9 +157,9 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequestAttach(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiAddNicToServerRequest { - return apiClient.AddNicToServer(ctx, model.ProjectId, *model.ServerId, *model.NicId) + return apiClient.AddNicToServer(ctx, model.ProjectId, model.Region, *model.ServerId, *model.NicId) } func buildRequestCreateAndAttach(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiAddNetworkToServerRequest { - return apiClient.AddNetworkToServer(ctx, model.ProjectId, *model.ServerId, *model.NetworkId) + return apiClient.AddNetworkToServer(ctx, model.ProjectId, model.Region, *model.ServerId, *model.NetworkId) } diff --git a/internal/cmd/server/network-interface/attach/attach_test.go b/internal/cmd/server/network-interface/attach/attach_test.go index 697562536..6e2898b32 100644 --- a/internal/cmd/server/network-interface/attach/attach_test.go +++ b/internal/cmd/server/network-interface/attach/attach_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -28,7 +30,9 @@ var testNetworkId = uuid.NewString() // contains nic id func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + serverIdFlag: testServerId, networkInterfaceIdFlag: testNicId, } @@ -43,6 +47,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: utils.Ptr(testServerId), NicId: utils.Ptr(testNicId), @@ -54,7 +59,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequestAttach(mods ...func(request *iaas.ApiAddNicToServerRequest)) iaas.ApiAddNicToServerRequest { - request := testClient.AddNicToServer(testCtx, testProjectId, testServerId, testNicId) + request := testClient.AddNicToServer(testCtx, testProjectId, testRegion, testServerId, testNicId) for _, mod := range mods { mod(&request) } @@ -62,7 +67,7 @@ func fixtureRequestAttach(mods ...func(request *iaas.ApiAddNicToServerRequest)) } func fixtureRequestCreateAndAttach(mods ...func(request *iaas.ApiAddNetworkToServerRequest)) iaas.ApiAddNetworkToServerRequest { - request := testClient.AddNetworkToServer(testCtx, testProjectId, testServerId, testNetworkId) + request := testClient.AddNetworkToServer(testCtx, testProjectId, testRegion, testServerId, testNetworkId) for _, mod := range mods { mod(&request) } @@ -91,21 +96,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/network-interface/detach/detach.go b/internal/cmd/server/network-interface/detach/detach.go index b8afad878..287b715f4 100644 --- a/internal/cmd/server/network-interface/detach/detach.go +++ b/internal/cmd/server/network-interface/detach/detach.go @@ -65,7 +65,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, *model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = *model.ServerId @@ -75,7 +75,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { // if the delete flag is provided a network interface is detached and deleted if model.Delete != nil && *model.Delete { - networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, *model.NetworkId) + networkLabel, err := iaasUtils.GetNetworkName(ctx, apiClient, model.ProjectId, model.Region, *model.NetworkId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network name: %v", err) networkLabel = *model.NetworkId @@ -159,9 +159,9 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequestDetach(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRemoveNicFromServerRequest { - return apiClient.RemoveNicFromServer(ctx, model.ProjectId, *model.ServerId, *model.NicId) + return apiClient.RemoveNicFromServer(ctx, model.ProjectId, model.Region, *model.ServerId, *model.NicId) } func buildRequestDetachAndDelete(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRemoveNetworkFromServerRequest { - return apiClient.RemoveNetworkFromServer(ctx, model.ProjectId, *model.ServerId, *model.NetworkId) + return apiClient.RemoveNetworkFromServer(ctx, model.ProjectId, model.Region, *model.ServerId, *model.NetworkId) } diff --git a/internal/cmd/server/network-interface/detach/detach_test.go b/internal/cmd/server/network-interface/detach/detach_test.go index 1eef8529a..4946e3e41 100644 --- a/internal/cmd/server/network-interface/detach/detach_test.go +++ b/internal/cmd/server/network-interface/detach/detach_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -28,7 +30,9 @@ var testNetworkId = uuid.NewString() // contains nic id func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + serverIdFlag: testServerId, networkInterfaceIdFlag: testNicId, } @@ -43,6 +47,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: utils.Ptr(testServerId), NicId: utils.Ptr(testNicId), @@ -54,7 +59,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequestDetach(mods ...func(request *iaas.ApiRemoveNicFromServerRequest)) iaas.ApiRemoveNicFromServerRequest { - request := testClient.RemoveNicFromServer(testCtx, testProjectId, testServerId, testNicId) + request := testClient.RemoveNicFromServer(testCtx, testProjectId, testRegion, testServerId, testNicId) for _, mod := range mods { mod(&request) } @@ -62,7 +67,7 @@ func fixtureRequestDetach(mods ...func(request *iaas.ApiRemoveNicFromServerReque } func fixtureRequestDetachAndDelete(mods ...func(request *iaas.ApiRemoveNetworkFromServerRequest)) iaas.ApiRemoveNetworkFromServerRequest { - request := testClient.RemoveNetworkFromServer(testCtx, testProjectId, testServerId, testNetworkId) + request := testClient.RemoveNetworkFromServer(testCtx, testProjectId, testRegion, testServerId, testNetworkId) for _, mod := range mods { mod(&request) } @@ -91,21 +96,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/network-interface/list/list.go b/internal/cmd/server/network-interface/list/list.go index ef8f70ca7..a63095dd6 100644 --- a/internal/cmd/server/network-interface/list/list.go +++ b/internal/cmd/server/network-interface/list/list.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string Limit *int64 } @@ -71,12 +71,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } if resp.Items == nil || len(*resp.Items) == 0 { - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } params.Printer.Info("No attached network interfaces found for server %q\n", serverLabel) return nil @@ -88,7 +88,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, *model.ServerId, items) + return outputResult(params.Printer, model.OutputFormat, model.ServerId, items) }, } configureFlags(cmd) @@ -119,7 +119,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), Limit: limit, } @@ -127,8 +127,8 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, return &model, nil } -func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListServerNicsRequest { - return apiClient.ListServerNics(ctx, model.ProjectId, *model.ServerId) +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListServerNICsRequest { + return apiClient.ListServerNICs(ctx, model.ProjectId, model.Region, model.ServerId) } func outputResult(p *print.Printer, outputFormat, serverId string, serverNics []iaas.NIC) error { diff --git a/internal/cmd/server/network-interface/list/list_test.go b/internal/cmd/server/network-interface/list/list_test.go index 4b91f4742..3c93f92c3 100644 --- a/internal/cmd/server/network-interface/list/list_test.go +++ b/internal/cmd/server/network-interface/list/list_test.go @@ -16,7 +16,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,9 +29,11 @@ var testServerId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - limitFlag: "10", - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + limitFlag: "10", + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -42,9 +46,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, } for _, mod := range mods { mod(model) @@ -52,8 +57,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { return model } -func fixtureRequest(mods ...func(request *iaas.ApiListServerNicsRequest)) iaas.ApiListServerNicsRequest { - request := testClient.ListServerNics(testCtx, testProjectId, testServerId) +func fixtureRequest(mods ...func(request *iaas.ApiListServerNICsRequest)) iaas.ApiListServerNICsRequest { + request := testClient.ListServerNICs(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -82,21 +87,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, @@ -148,7 +153,7 @@ func TestBuildRequest(t *testing.T) { tests := []struct { description string model *inputModel - expectedRequest iaas.ApiListServerNicsRequest + expectedRequest iaas.ApiListServerNICsRequest }{ { description: "base", diff --git a/internal/cmd/server/os-update/create/create.go b/internal/cmd/server/os-update/create/create.go index 7af78387a..1c8bddf44 100644 --- a/internal/cmd/server/os-update/create/create.go +++ b/internal/cmd/server/os-update/create/create.go @@ -65,7 +65,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/os-update/disable/disable.go b/internal/cmd/server/os-update/disable/disable.go index 3c9510b98..81086b85f 100644 --- a/internal/cmd/server/os-update/disable/disable.go +++ b/internal/cmd/server/os-update/disable/disable.go @@ -55,7 +55,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/os-update/enable/enable.go b/internal/cmd/server/os-update/enable/enable.go index c81c27b44..c2538aa0f 100644 --- a/internal/cmd/server/os-update/enable/enable.go +++ b/internal/cmd/server/os-update/enable/enable.go @@ -56,7 +56,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/os-update/list/list.go b/internal/cmd/server/os-update/list/list.go index 5ce2a5c27..94112f256 100644 --- a/internal/cmd/server/os-update/list/list.go +++ b/internal/cmd/server/os-update/list/list.go @@ -71,7 +71,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/os-update/schedule/create/create.go b/internal/cmd/server/os-update/schedule/create/create.go index 76dd76235..b9c1e3a1a 100644 --- a/internal/cmd/server/os-update/schedule/create/create.go +++ b/internal/cmd/server/os-update/schedule/create/create.go @@ -73,7 +73,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/os-update/schedule/list/list.go b/internal/cmd/server/os-update/schedule/list/list.go index b9721cca8..4047fba6d 100644 --- a/internal/cmd/server/os-update/schedule/list/list.go +++ b/internal/cmd/server/os-update/schedule/list/list.go @@ -70,7 +70,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serverLabel := model.ServerId // Get server name if iaasApiClient, err := iaasClient.ConfigureClient(params.Printer, params.CliVersion); err == nil { - serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, iaasApiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) } else if serverName != "" { diff --git a/internal/cmd/server/public-ip/attach/attach.go b/internal/cmd/server/public-ip/attach/attach.go index 763583606..3f76d8852 100644 --- a/internal/cmd/server/public-ip/attach/attach.go +++ b/internal/cmd/server/public-ip/attach/attach.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string PublicIpId string } @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.PublicIpId) + publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.Region, model.PublicIpId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get public ip name: %v", err) publicIpLabel = model.PublicIpId @@ -62,12 +62,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { publicIpLabel = model.PublicIpId } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -109,7 +109,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), PublicIpId: volumeId, } @@ -118,5 +118,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiAddPublicIpToServerRequest { - return apiClient.AddPublicIpToServer(ctx, model.ProjectId, *model.ServerId, model.PublicIpId) + return apiClient.AddPublicIpToServer(ctx, model.ProjectId, model.Region, model.ServerId, model.PublicIpId) } diff --git a/internal/cmd/server/public-ip/attach/attach_test.go b/internal/cmd/server/public-ip/attach/attach_test.go index c58f7b280..3f0e10763 100644 --- a/internal/cmd/server/public-ip/attach/attach_test.go +++ b/internal/cmd/server/public-ip/attach/attach_test.go @@ -4,18 +4,18 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/cmd/params" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +37,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -51,8 +53,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, PublicIpId: testPublicIpId, } for _, mod := range mods { @@ -62,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiAddPublicIpToServerRequest)) iaas.ApiAddPublicIpToServerRequest { - request := testClient.AddPublicIpToServer(testCtx, testProjectId, testServerId, testPublicIpId) + request := testClient.AddPublicIpToServer(testCtx, testProjectId, testRegion, testServerId, testPublicIpId) for _, mod := range mods { mod(&request) } @@ -94,7 +97,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -102,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -110,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/public-ip/detach/detach.go b/internal/cmd/server/public-ip/detach/detach.go index 6294187d8..ecf43cba5 100644 --- a/internal/cmd/server/public-ip/detach/detach.go +++ b/internal/cmd/server/public-ip/detach/detach.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string PublicIpId string } @@ -55,7 +55,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.PublicIpId) + publicIpLabel, _, err := iaasUtils.GetPublicIP(ctx, apiClient, model.ProjectId, model.Region, model.PublicIpId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get public ip: %v", err) publicIpLabel = model.PublicIpId @@ -63,12 +63,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { publicIpLabel = model.PublicIpId } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -110,7 +110,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), PublicIpId: publicIpId, } @@ -119,5 +119,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRemovePublicIpFromServerRequest { - return apiClient.RemovePublicIpFromServer(ctx, model.ProjectId, *model.ServerId, model.PublicIpId) + return apiClient.RemovePublicIpFromServer(ctx, model.ProjectId, model.Region, model.ServerId, model.PublicIpId) } diff --git a/internal/cmd/server/public-ip/detach/detach_test.go b/internal/cmd/server/public-ip/detach/detach_test.go index 8a46591a7..ccea98e12 100644 --- a/internal/cmd/server/public-ip/detach/detach_test.go +++ b/internal/cmd/server/public-ip/detach/detach_test.go @@ -7,7 +7,6 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" @@ -15,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +38,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -51,8 +53,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, PublicIpId: testPublicIpId, } for _, mod := range mods { @@ -62,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiRemovePublicIpFromServerRequest)) iaas.ApiRemovePublicIpFromServerRequest { - request := testClient.RemovePublicIpFromServer(testCtx, testProjectId, testServerId, testPublicIpId) + request := testClient.RemovePublicIpFromServer(testCtx, testProjectId, testRegion, testServerId, testPublicIpId) for _, mod := range mods { mod(&request) } @@ -93,7 +96,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -101,7 +104,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -109,7 +112,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/reboot/reboot.go b/internal/cmd/server/reboot/reboot.go index 445321295..ed13d02ce 100644 --- a/internal/cmd/server/reboot/reboot.go +++ b/internal/cmd/server/reboot/reboot.go @@ -62,7 +62,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -116,7 +116,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRebootServerRequest { - req := apiClient.RebootServer(ctx, model.ProjectId, model.ServerId) + req := apiClient.RebootServer(ctx, model.ProjectId, model.Region, model.ServerId) // if hard reboot is set the action must be set (soft is default) if model.HardReboot { req = req.Action(hardRebootAction) diff --git a/internal/cmd/server/reboot/reboot_test.go b/internal/cmd/server/reboot/reboot_test.go index 074ba2a84..1a05016e1 100644 --- a/internal/cmd/server/reboot/reboot_test.go +++ b/internal/cmd/server/reboot/reboot_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + hardRebootFlag: "false", } for _, mod := range mods { @@ -48,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, HardReboot: false, @@ -59,7 +64,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiRebootServerRequest)) iaas.ApiRebootServerRequest { - request := testClient.RebootServer(testCtx, testProjectId, testServerId) + request := testClient.RebootServer(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -97,7 +102,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -105,7 +110,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/rescue/rescue.go b/internal/cmd/server/rescue/rescue.go index 65dc2633d..3ae4f99b5 100644 --- a/internal/cmd/server/rescue/rescue.go +++ b/internal/cmd/server/rescue/rescue.go @@ -58,7 +58,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -85,7 +85,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Rescuing server") - _, err = wait.RescueServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.RescueServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server rescuing: %w", err) } @@ -131,7 +131,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRescueServerRequest { - req := apiClient.RescueServer(ctx, model.ProjectId, model.ServerId) + req := apiClient.RescueServer(ctx, model.ProjectId, model.Region, model.ServerId) payload := iaas.RescueServerPayload{ Image: model.ImageId, } diff --git a/internal/cmd/server/rescue/rescue_test.go b/internal/cmd/server/rescue/rescue_test.go index d3e6e3c50..b7ec93e90 100644 --- a/internal/cmd/server/rescue/rescue_test.go +++ b/internal/cmd/server/rescue/rescue_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,8 +38,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - imageIdFlag: testImageId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + imageIdFlag: testImageId, } for _, mod := range mods { mod(flagValues) @@ -50,6 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, ImageId: utils.Ptr(testImageId), @@ -61,7 +66,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiRescueServerRequest)) iaas.ApiRescueServerRequest { - request := testClient.RescueServer(testCtx, testProjectId, testServerId) + request := testClient.RescueServer(testCtx, testProjectId, testRegion, testServerId) request = request.RescueServerPayload(iaas.RescueServerPayload{ Image: utils.Ptr(testImageId), }) @@ -104,7 +109,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -112,7 +117,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -120,7 +125,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/resize/resize.go b/internal/cmd/server/resize/resize.go index f23826188..329d5a6b4 100644 --- a/internal/cmd/server/resize/resize.go +++ b/internal/cmd/server/resize/resize.go @@ -58,7 +58,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -85,7 +85,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Resizing server") - _, err = wait.ResizeServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.ResizeServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server resizing: %w", err) } @@ -131,7 +131,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiResizeServerRequest { - req := apiClient.ResizeServer(ctx, model.ProjectId, model.ServerId) + req := apiClient.ResizeServer(ctx, model.ProjectId, model.Region, model.ServerId) payload := iaas.ResizeServerPayload{ MachineType: model.MachineType, } diff --git a/internal/cmd/server/resize/resize_test.go b/internal/cmd/server/resize/resize_test.go index 231d7c1c0..3ba39088f 100644 --- a/internal/cmd/server/resize/resize_test.go +++ b/internal/cmd/server/resize/resize_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -35,7 +37,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + machineTypeFlag: "t1.2", } for _, mod := range mods { @@ -49,6 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, MachineType: utils.Ptr("t1.2"), @@ -60,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiResizeServerRequest)) iaas.ApiResizeServerRequest { - request := testClient.ResizeServer(testCtx, testProjectId, testServerId) + request := testClient.ResizeServer(testCtx, testProjectId, testRegion, testServerId) request = request.ResizeServerPayload(iaas.ResizeServerPayload{ MachineType: utils.Ptr("t1.2"), }) @@ -103,7 +108,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -111,7 +116,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -119,7 +124,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/service-account/attach/attach.go b/internal/cmd/server/service-account/attach/attach.go index 3979e0398..5644ee45f 100644 --- a/internal/cmd/server/service-account/attach/attach.go +++ b/internal/cmd/server/service-account/attach/attach.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string ServiceAccMail string } @@ -54,12 +54,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -100,7 +100,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), ServiceAccMail: serviceAccMail, } @@ -109,7 +109,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiAddServiceAccountToServerRequest { - req := apiClient.AddServiceAccountToServer(ctx, model.ProjectId, *model.ServerId, model.ServiceAccMail) + req := apiClient.AddServiceAccountToServer(ctx, model.ProjectId, model.Region, model.ServerId, model.ServiceAccMail) return req } diff --git a/internal/cmd/server/service-account/attach/attach_test.go b/internal/cmd/server/service-account/attach/attach_test.go index 96ed151ce..0edf073b4 100644 --- a/internal/cmd/server/service-account/attach/attach_test.go +++ b/internal/cmd/server/service-account/attach/attach_test.go @@ -7,7 +7,6 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/google/go-cmp/cmp" @@ -15,7 +14,9 @@ import ( "github.com/google/uuid" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +38,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -51,8 +54,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, ServiceAccMail: testServiceAccount, } for _, mod := range mods { @@ -62,7 +66,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiAddServiceAccountToServerRequest)) iaas.ApiAddServiceAccountToServerRequest { - request := testClient.AddServiceAccountToServer(testCtx, testProjectId, testServerId, testServiceAccount) + request := testClient.AddServiceAccountToServer(testCtx, testProjectId, testRegion, testServerId, testServiceAccount) for _, mod := range mods { mod(&request) } @@ -94,7 +98,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -102,7 +106,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -110,7 +114,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/service-account/detach/detach.go b/internal/cmd/server/service-account/detach/detach.go index 934ed766d..59966f6d5 100644 --- a/internal/cmd/server/service-account/detach/detach.go +++ b/internal/cmd/server/service-account/detach/detach.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string ServiceAccMail string } @@ -54,12 +54,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -100,7 +100,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), ServiceAccMail: serviceAccMail, } @@ -109,7 +109,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRemoveServiceAccountFromServerRequest { - req := apiClient.RemoveServiceAccountFromServer(ctx, model.ProjectId, *model.ServerId, model.ServiceAccMail) + req := apiClient.RemoveServiceAccountFromServer(ctx, model.ProjectId, model.Region, model.ServerId, model.ServiceAccMail) return req } diff --git a/internal/cmd/server/service-account/detach/detach_test.go b/internal/cmd/server/service-account/detach/detach_test.go index acfd02802..a1e6c89cd 100644 --- a/internal/cmd/server/service-account/detach/detach_test.go +++ b/internal/cmd/server/service-account/detach/detach_test.go @@ -7,7 +7,6 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/iaas" "github.com/google/go-cmp/cmp" @@ -15,7 +14,9 @@ import ( "github.com/google/uuid" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +38,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -51,8 +54,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, ServiceAccMail: testServiceAccount, } for _, mod := range mods { @@ -62,7 +66,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiRemoveServiceAccountFromServerRequest)) iaas.ApiRemoveServiceAccountFromServerRequest { - request := testClient.RemoveServiceAccountFromServer(testCtx, testProjectId, testServerId, testServiceAccount) + request := testClient.RemoveServiceAccountFromServer(testCtx, testProjectId, testRegion, testServerId, testServiceAccount) for _, mod := range mods { mod(&request) } @@ -94,7 +98,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -102,7 +106,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -110,7 +114,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/service-account/list/list.go b/internal/cmd/server/service-account/list/list.go index 5bf727bc7..95773fc6e 100644 --- a/internal/cmd/server/service-account/list/list.go +++ b/internal/cmd/server/service-account/list/list.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel Limit *int64 - ServerId *string + ServerId string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -62,12 +62,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverName, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverName, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverName = *model.ServerId + serverName = model.ServerId } else if serverName == "" { - serverName = *model.ServerId + serverName = model.ServerId } // Call API @@ -86,7 +86,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { serviceAccounts = serviceAccounts[:int(*model.Limit)] } - return outputResult(params.Printer, model.OutputFormat, *model.ServerId, serverName, serviceAccounts) + return outputResult(params.Printer, model.OutputFormat, model.ServerId, serverName, serviceAccounts) }, } configureFlags(cmd) @@ -118,7 +118,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, Limit: limit, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), } p.DebugInputModel(model) @@ -126,7 +126,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListServerServiceAccountsRequest { - req := apiClient.ListServerServiceAccounts(ctx, model.ProjectId, *model.ServerId) + req := apiClient.ListServerServiceAccounts(ctx, model.ProjectId, model.Region, model.ServerId) return req } diff --git a/internal/cmd/server/service-account/list/list_test.go b/internal/cmd/server/service-account/list/list_test.go index d2a0c159a..a58d5e671 100644 --- a/internal/cmd/server/service-account/list/list_test.go +++ b/internal/cmd/server/service-account/list/list_test.go @@ -17,7 +17,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -29,9 +31,11 @@ var testLimit = int64(10) func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, - limitFlag: strconv.FormatInt(testLimit, 10), + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, + limitFlag: strconv.FormatInt(testLimit, 10), } for _, mod := range mods { mod(flagValues) @@ -44,8 +48,9 @@ func fixtureInputModel(mods ...func(inputModel *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, Limit: utils.Ptr(testLimit), } for _, mod := range mods { @@ -55,7 +60,7 @@ func fixtureInputModel(mods ...func(inputModel *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListServerServiceAccountsRequest)) iaas.ApiListServerServiceAccountsRequest { - request := testClient.ListServerServiceAccounts(testCtx, testProjectId, testServerId) + request := testClient.ListServerServiceAccounts(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -84,21 +89,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/start/start.go b/internal/cmd/server/start/start.go index 9ebabdf70..e025e2890 100644 --- a/internal/cmd/server/start/start.go +++ b/internal/cmd/server/start/start.go @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -73,7 +73,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Starting server") - _, err = wait.StartServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.StartServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server starting: %w", err) } @@ -110,5 +110,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiStartServerRequest { - return apiClient.StartServer(ctx, model.ProjectId, model.ServerId) + return apiClient.StartServer(ctx, model.ProjectId, model.Region, model.ServerId) } diff --git a/internal/cmd/server/start/start_test.go b/internal/cmd/server/start/start_test.go index f028d85d9..f5e64b2d2 100644 --- a/internal/cmd/server/start/start_test.go +++ b/internal/cmd/server/start/start_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiStartServerRequest)) iaas.ApiStartServerRequest { - request := testClient.StartServer(testCtx, testProjectId, testServerId) + request := testClient.StartServer(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -95,7 +99,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/stop/stop.go b/internal/cmd/server/stop/stop.go index d91c1931c..958127da7 100644 --- a/internal/cmd/server/stop/stop.go +++ b/internal/cmd/server/stop/stop.go @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -81,7 +81,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Stopping server") - _, err = wait.StopServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.StopServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server stopping: %w", err) } @@ -118,5 +118,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiStopServerRequest { - return apiClient.StopServer(ctx, model.ProjectId, model.ServerId) + return apiClient.StopServer(ctx, model.ProjectId, model.Region, model.ServerId) } diff --git a/internal/cmd/server/stop/stop_test.go b/internal/cmd/server/stop/stop_test.go index 7aba2f968..29980a4b9 100644 --- a/internal/cmd/server/stop/stop_test.go +++ b/internal/cmd/server/stop/stop_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiStopServerRequest)) iaas.ApiStopServerRequest { - request := testClient.StopServer(testCtx, testProjectId, testServerId) + request := testClient.StopServer(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -95,7 +99,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/unrescue/unrescue.go b/internal/cmd/server/unrescue/unrescue.go index 47b6cf018..6f433ebeb 100644 --- a/internal/cmd/server/unrescue/unrescue.go +++ b/internal/cmd/server/unrescue/unrescue.go @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -81,7 +81,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Unrescuing server") - _, err = wait.UnrescueServerWaitHandler(ctx, apiClient, model.ProjectId, model.ServerId).WaitWithContext(ctx) + _, err = wait.UnrescueServerWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for server unrescuing: %w", err) } @@ -118,5 +118,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUnrescueServerRequest { - return apiClient.UnrescueServer(ctx, model.ProjectId, model.ServerId) + return apiClient.UnrescueServer(ctx, model.ProjectId, model.Region, model.ServerId) } diff --git a/internal/cmd/server/unrescue/unrescue_test.go b/internal/cmd/server/unrescue/unrescue_test.go index 8161f03d4..708fe68d8 100644 --- a/internal/cmd/server/unrescue/unrescue_test.go +++ b/internal/cmd/server/unrescue/unrescue_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, ServerId: testServerId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUnrescueServerRequest)) iaas.ApiUnrescueServerRequest { - request := testClient.UnrescueServer(testCtx, testProjectId, testServerId) + request := testClient.UnrescueServer(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -95,7 +99,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/update/update.go b/internal/cmd/server/update/update.go index 5567be1bf..f8b404794 100644 --- a/internal/cmd/server/update/update.go +++ b/internal/cmd/server/update/update.go @@ -61,7 +61,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) serverLabel = model.ServerId @@ -116,7 +116,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateServerRequest { - req := apiClient.UpdateServer(ctx, model.ProjectId, model.ServerId) + req := apiClient.UpdateServer(ctx, model.ProjectId, model.Region, model.ServerId) payload := iaas.UpdateServerPayload{ Name: model.Name, diff --git a/internal/cmd/server/update/update_test.go b/internal/cmd/server/update/update_test.go index 63398311e..d13d32c87 100644 --- a/internal/cmd/server/update/update_test.go +++ b/internal/cmd/server/update/update_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,9 +39,11 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - nameFlag: "example-server-name", - projectIdFlag: testProjectId, - labelFlag: "key=value", + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + nameFlag: "example-server-name", + labelFlag: "key=value", } for _, mod := range mods { mod(flagValues) @@ -51,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Name: utils.Ptr("example-server-name"), @@ -66,7 +71,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateServerRequest)) iaas.ApiUpdateServerRequest { - request := testClient.UpdateServer(testCtx, testProjectId, testServerId) + request := testClient.UpdateServer(testCtx, testProjectId, testRegion, testServerId) request = request.UpdateServerPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -112,7 +117,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -120,7 +125,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -128,7 +133,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/volume/attach/attach.go b/internal/cmd/server/volume/attach/attach.go index ba736f285..65a631ddf 100644 --- a/internal/cmd/server/volume/attach/attach.go +++ b/internal/cmd/server/volume/attach/attach.go @@ -29,7 +29,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string VolumeId string DeleteOnTermination *bool } @@ -63,18 +63,18 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -116,7 +116,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), DeleteOnTermination: flags.FlagToBoolPointer(p, cmd, deleteOnTerminationFlag), VolumeId: volumeId, } @@ -126,7 +126,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiAddVolumeToServerRequest { - req := apiClient.AddVolumeToServer(ctx, model.ProjectId, *model.ServerId, model.VolumeId) + req := apiClient.AddVolumeToServer(ctx, model.ProjectId, model.Region, model.ServerId, model.VolumeId) payload := iaas.AddVolumeToServerPayload{ DeleteOnTermination: model.DeleteOnTermination, } diff --git a/internal/cmd/server/volume/attach/attach_test.go b/internal/cmd/server/volume/attach/attach_test.go index 9a180a4c0..2f3ed3e69 100644 --- a/internal/cmd/server/volume/attach/attach_test.go +++ b/internal/cmd/server/volume/attach/attach_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +39,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + serverIdFlag: testServerId, deleteOnTerminationFlag: "true", } @@ -52,8 +56,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, VolumeId: testVolumeId, DeleteOnTermination: utils.Ptr(true), } @@ -74,7 +79,7 @@ func fixturePayload(mods ...func(payload *iaas.AddVolumeToServerPayload)) iaas.A } func fixtureRequest(mods ...func(request *iaas.ApiAddVolumeToServerRequest)) iaas.ApiAddVolumeToServerRequest { - request := testClient.AddVolumeToServer(testCtx, testProjectId, testServerId, testVolumeId) + request := testClient.AddVolumeToServer(testCtx, testProjectId, testRegion, testServerId, testVolumeId) request = request.AddVolumeToServerPayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -107,7 +112,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -115,7 +120,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -123,7 +128,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/volume/describe/describe.go b/internal/cmd/server/volume/describe/describe.go index 2a0a97d24..4c0288851 100644 --- a/internal/cmd/server/volume/describe/describe.go +++ b/internal/cmd/server/volume/describe/describe.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string VolumeId string } @@ -63,18 +63,18 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } // Call API @@ -107,7 +107,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), VolumeId: volumeId, } @@ -116,7 +116,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetAttachedVolumeRequest { - req := apiClient.GetAttachedVolume(ctx, model.ProjectId, *model.ServerId, model.VolumeId) + req := apiClient.GetAttachedVolume(ctx, model.ProjectId, model.Region, model.ServerId, model.VolumeId) return req } diff --git a/internal/cmd/server/volume/describe/describe_test.go b/internal/cmd/server/volume/describe/describe_test.go index f2182f04c..3d6634075 100644 --- a/internal/cmd/server/volume/describe/describe_test.go +++ b/internal/cmd/server/volume/describe/describe_test.go @@ -4,18 +4,18 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/cmd/params" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +37,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -51,8 +53,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, VolumeId: testVolumeId, } for _, mod := range mods { @@ -62,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetAttachedVolumeRequest)) iaas.ApiGetAttachedVolumeRequest { - request := testClient.GetAttachedVolume(testCtx, testProjectId, testServerId, testVolumeId) + request := testClient.GetAttachedVolume(testCtx, testProjectId, testRegion, testServerId, testVolumeId) for _, mod := range mods { mod(&request) } @@ -94,7 +97,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -102,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -110,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/volume/detach/detach.go b/internal/cmd/server/volume/detach/detach.go index e081295d6..5c271b8fe 100644 --- a/internal/cmd/server/volume/detach/detach.go +++ b/internal/cmd/server/volume/detach/detach.go @@ -26,7 +26,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string VolumeId string } @@ -55,18 +55,18 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -108,7 +108,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), VolumeId: volumeId, } @@ -117,6 +117,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRemoveVolumeFromServerRequest { - req := apiClient.RemoveVolumeFromServer(ctx, model.ProjectId, *model.ServerId, model.VolumeId) + req := apiClient.RemoveVolumeFromServer(ctx, model.ProjectId, model.Region, model.ServerId, model.VolumeId) return req } diff --git a/internal/cmd/server/volume/detach/detach_test.go b/internal/cmd/server/volume/detach/detach_test.go index 4934e778d..e9ebecb32 100644 --- a/internal/cmd/server/volume/detach/detach_test.go +++ b/internal/cmd/server/volume/detach/detach_test.go @@ -4,18 +4,18 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/cmd/params" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/cmd/params" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +37,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -51,8 +53,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, VolumeId: testVolumeId, } for _, mod := range mods { @@ -62,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiRemoveVolumeFromServerRequest)) iaas.ApiRemoveVolumeFromServerRequest { - request := testClient.RemoveVolumeFromServer(testCtx, testProjectId, testServerId, testVolumeId) + request := testClient.RemoveVolumeFromServer(testCtx, testProjectId, testRegion, testServerId, testVolumeId) for _, mod := range mods { mod(&request) } @@ -93,7 +96,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -101,7 +104,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -109,7 +112,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/volume/list/list.go b/internal/cmd/server/volume/list/list.go index 6f25321db..4dddab072 100644 --- a/internal/cmd/server/volume/list/list.go +++ b/internal/cmd/server/volume/list/list.go @@ -25,7 +25,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string } func NewCmd(params *params.CmdParams) *cobra.Command { @@ -55,12 +55,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } // Call API @@ -78,7 +78,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { // get volume names var volumeNames []string for i := range volumes { - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, *volumes[i].VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, *volumes[i].VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = "" @@ -108,7 +108,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), } p.DebugInputModel(model) @@ -116,7 +116,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListAttachedVolumesRequest { - req := apiClient.ListAttachedVolumes(ctx, model.ProjectId, *model.ServerId) + req := apiClient.ListAttachedVolumes(ctx, model.ProjectId, model.Region, model.ServerId) return req } diff --git a/internal/cmd/server/volume/list/list_test.go b/internal/cmd/server/volume/list/list_test.go index 6be36d7d6..82e73dff8 100644 --- a/internal/cmd/server/volume/list/list_test.go +++ b/internal/cmd/server/volume/list/list_test.go @@ -4,19 +4,19 @@ import ( "context" "testing" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/uuid" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-cli/internal/pkg/testutils" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/google/uuid" "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,8 +27,10 @@ var testServerId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - serverIdFlag: testServerId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + serverIdFlag: testServerId, } for _, mod := range mods { mod(flagValues) @@ -41,8 +43,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, } for _, mod := range mods { mod(model) @@ -51,7 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListAttachedVolumesRequest)) iaas.ApiListAttachedVolumesRequest { - request := testClient.ListAttachedVolumes(testCtx, testProjectId, testServerId) + request := testClient.ListAttachedVolumes(testCtx, testProjectId, testRegion, testServerId) for _, mod := range mods { mod(&request) } @@ -80,21 +83,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/server/volume/update/update.go b/internal/cmd/server/volume/update/update.go index 471dde5c0..12c7e66ee 100644 --- a/internal/cmd/server/volume/update/update.go +++ b/internal/cmd/server/volume/update/update.go @@ -29,7 +29,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel - ServerId *string + ServerId string VolumeId string DeleteOnTermination *bool } @@ -59,18 +59,18 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId } - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, *model.ServerId) + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = *model.ServerId + serverLabel = model.ServerId } else if serverLabel == "" { - serverLabel = *model.ServerId + serverLabel = model.ServerId } if !model.AssumeYes { @@ -112,7 +112,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu model := inputModel{ GlobalFlagModel: globalFlags, - ServerId: flags.FlagToStringPointer(p, cmd, serverIdFlag), + ServerId: flags.FlagToStringValue(p, cmd, serverIdFlag), DeleteOnTermination: flags.FlagToBoolPointer(p, cmd, deleteOnTerminationFlag), VolumeId: volumeId, } @@ -122,7 +122,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateAttachedVolumeRequest { - req := apiClient.UpdateAttachedVolume(ctx, model.ProjectId, *model.ServerId, model.VolumeId) + req := apiClient.UpdateAttachedVolume(ctx, model.ProjectId, model.Region, model.ServerId, model.VolumeId) payload := iaas.UpdateAttachedVolumePayload{ DeleteOnTermination: model.DeleteOnTermination, } diff --git a/internal/cmd/server/volume/update/update_test.go b/internal/cmd/server/volume/update/update_test.go index 1f820cff2..a15d5e810 100644 --- a/internal/cmd/server/volume/update/update_test.go +++ b/internal/cmd/server/volume/update/update_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,7 +39,9 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + serverIdFlag: testServerId, deleteOnTerminationFlag: "true", } @@ -52,8 +56,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, - ServerId: utils.Ptr(testServerId), + ServerId: testServerId, VolumeId: testVolumeId, DeleteOnTermination: utils.Ptr(true), } @@ -74,7 +79,7 @@ func fixturePayload(mods ...func(payload *iaas.UpdateAttachedVolumePayload)) iaa } func fixtureRequest(mods ...func(request *iaas.ApiUpdateAttachedVolumeRequest)) iaas.ApiUpdateAttachedVolumeRequest { - request := testClient.UpdateAttachedVolume(testCtx, testProjectId, testServerId, testVolumeId) + request := testClient.UpdateAttachedVolume(testCtx, testProjectId, testRegion, testServerId, testVolumeId) request = request.UpdateAttachedVolumePayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -106,7 +111,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -114,7 +119,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -122,7 +127,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/backup/create/create.go b/internal/cmd/volume/backup/create/create.go index 4245716e9..316efc520 100644 --- a/internal/cmd/volume/backup/create/create.go +++ b/internal/cmd/volume/backup/create/create.go @@ -78,14 +78,14 @@ func NewCmd(params *params.CmdParams) *cobra.Command { // Get source name for label (use ID if name not available) sourceLabel := model.SourceID if model.SourceType == "volume" { - name, err := iaasutils.GetVolumeName(ctx, apiClient, model.ProjectId, model.SourceID) + name, err := iaasutils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.SourceID) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) } else if name != "" { sourceLabel = name } } else if model.SourceType == "snapshot" { - name, err := iaasutils.GetSnapshotName(ctx, apiClient, model.ProjectId, model.SourceID) + name, err := iaasutils.GetSnapshotName(ctx, apiClient, model.ProjectId, model.Region, model.SourceID) if err != nil { params.Printer.Debug(print.ErrorLevel, "get snapshot name: %v", err) } else if name != "" { @@ -107,12 +107,16 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("create volume backup: %w", err) } + if resp == nil || resp.Id == nil { + return fmt.Errorf("create volume: empty response") + } + volumeId := *resp.Id // Wait for async operation, if async mode not enabled if !model.Async { s := spinner.New(params.Printer) s.Start("Creating backup") - resp, err = wait.CreateBackupWaitHandler(ctx, apiClient, model.ProjectId, *resp.Id).WaitWithContext(ctx) + resp, err = wait.CreateBackupWaitHandler(ctx, apiClient, model.ProjectId, model.Region, volumeId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for backup creation: %w", err) } @@ -169,7 +173,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateBackupRequest { - req := apiClient.CreateBackup(ctx, model.ProjectId) + req := apiClient.CreateBackup(ctx, model.ProjectId, model.Region) payload := iaas.CreateBackupPayload{ Name: model.Name, diff --git a/internal/cmd/volume/backup/create/create_test.go b/internal/cmd/volume/backup/create/create_test.go index 2132d89f8..3f4e64d15 100644 --- a/internal/cmd/volume/backup/create/create_test.go +++ b/internal/cmd/volume/backup/create/create_test.go @@ -16,13 +16,14 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -type testCtxKey struct{} - const ( + testRegion = "eu01" testName = "my-backup" testSourceType = "volume" ) +type testCtxKey struct{} + var ( testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") testClient = &iaas.APIClient{} @@ -34,10 +35,12 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, - sourceIdFlag: testSourceId, - sourceTypeFlag: testSourceType, - nameFlag: testName, - labelsFlag: "key1=value1", + globalflags.RegionFlag: testRegion, + + sourceIdFlag: testSourceId, + sourceTypeFlag: testSourceType, + nameFlag: testName, + labelsFlag: "key1=value1", } for _, mod := range mods { mod(flagValues) @@ -50,6 +53,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, SourceID: testSourceId, SourceType: testSourceType, @@ -63,7 +67,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateBackupRequest)) iaas.ApiCreateBackupRequest { - request := testClient.CreateBackup(testCtx, testProjectId) + request := testClient.CreateBackup(testCtx, testProjectId, testRegion) createPayload := iaas.NewCreateBackupPayloadWithDefaults() createPayload.Name = utils.Ptr(testName) diff --git a/internal/cmd/volume/backup/delete/delete.go b/internal/cmd/volume/backup/delete/delete.go index de63990bd..b439f0d6d 100644 --- a/internal/cmd/volume/backup/delete/delete.go +++ b/internal/cmd/volume/backup/delete/delete.go @@ -52,7 +52,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - backupLabel, err := iaasutils.GetBackupName(ctx, apiClient, model.ProjectId, model.BackupId) + backupLabel, err := iaasutils.GetBackupName(ctx, apiClient, model.ProjectId, model.Region, model.BackupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get backup name: %v", err) } @@ -76,7 +76,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deleting backup") - _, err = wait.DeleteBackupWaitHandler(ctx, apiClient, model.ProjectId, model.BackupId).WaitWithContext(ctx) + _, err = wait.DeleteBackupWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.BackupId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for backup deletion: %w", err) } @@ -112,6 +112,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteBackupRequest { - req := apiClient.DeleteBackup(ctx, model.ProjectId, model.BackupId) + req := apiClient.DeleteBackup(ctx, model.ProjectId, model.Region, model.BackupId) return req } diff --git a/internal/cmd/volume/backup/delete/delete_test.go b/internal/cmd/volume/backup/delete/delete_test.go index a0146e406..26623975f 100644 --- a/internal/cmd/volume/backup/delete/delete_test.go +++ b/internal/cmd/volume/backup/delete/delete_test.go @@ -13,6 +13,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -35,6 +39,7 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, BackupId: testBackupId, } @@ -57,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteBackupRequest)) iaas.ApiDeleteBackupRequest { - request := testClient.DeleteBackup(testCtx, testProjectId, testBackupId) + request := testClient.DeleteBackup(testCtx, testProjectId, testRegion, testBackupId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/volume/backup/describe/describe.go b/internal/cmd/volume/backup/describe/describe.go index f836b32b2..3f95fe355 100644 --- a/internal/cmd/volume/backup/describe/describe.go +++ b/internal/cmd/volume/backup/describe/describe.go @@ -86,7 +86,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetBackupRequest { - req := apiClient.GetBackup(ctx, model.ProjectId, model.BackupId) + req := apiClient.GetBackup(ctx, model.ProjectId, model.Region, model.BackupId) return req } diff --git a/internal/cmd/volume/backup/describe/describe_test.go b/internal/cmd/volume/backup/describe/describe_test.go index 0ff77ca24..1ba033cb2 100644 --- a/internal/cmd/volume/backup/describe/describe_test.go +++ b/internal/cmd/volume/backup/describe/describe_test.go @@ -15,6 +15,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -37,6 +41,7 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -49,6 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, BackupId: testBackupId, } @@ -59,7 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetBackupRequest)) iaas.ApiGetBackupRequest { - request := testClient.GetBackup(testCtx, testProjectId, testBackupId) + request := testClient.GetBackup(testCtx, testProjectId, testRegion, testBackupId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/volume/backup/list/list.go b/internal/cmd/volume/backup/list/list.go index 82580a440..825a6793e 100644 --- a/internal/cmd/volume/backup/list/list.go +++ b/internal/cmd/volume/backup/list/list.go @@ -126,7 +126,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListBackupsRequest { - req := apiClient.ListBackups(ctx, model.ProjectId) + req := apiClient.ListBackups(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) diff --git a/internal/cmd/volume/backup/list/list_test.go b/internal/cmd/volume/backup/list/list_test.go index f3616ef3c..3734dc1f7 100644 --- a/internal/cmd/volume/backup/list/list_test.go +++ b/internal/cmd/volume/backup/list/list_test.go @@ -16,6 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -27,8 +31,10 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, - limitFlag: "10", - labelSelectorFlag: "key1=value1", + globalflags.RegionFlag: testRegion, + + limitFlag: "10", + labelSelectorFlag: "key1=value1", } for _, mod := range mods { mod(flagValues) @@ -40,6 +46,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Limit: utils.Ptr(int64(10)), @@ -52,7 +59,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListBackupsRequest)) iaas.ApiListBackupsRequest { - request := testClient.ListBackups(testCtx, testProjectId) + request := testClient.ListBackups(testCtx, testProjectId, testRegion) request = request.LabelSelector("key1=value1") for _, mod := range mods { mod(&request) diff --git a/internal/cmd/volume/backup/restore/restore.go b/internal/cmd/volume/backup/restore/restore.go index 04301a51d..3922c4ae8 100644 --- a/internal/cmd/volume/backup/restore/restore.go +++ b/internal/cmd/volume/backup/restore/restore.go @@ -52,17 +52,17 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - backupLabel, err := iaasutils.GetBackupName(ctx, apiClient, model.ProjectId, model.BackupId) + backupLabel, err := iaasutils.GetBackupName(ctx, apiClient, model.ProjectId, model.Region, model.BackupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get backup details: %v", err) } // Get source details for labels var sourceLabel string - backup, err := apiClient.GetBackup(ctx, model.ProjectId, model.BackupId).Execute() + backup, err := apiClient.GetBackup(ctx, model.ProjectId, model.Region, model.BackupId).Execute() if err == nil && backup != nil && backup.VolumeId != nil { sourceLabel = *backup.VolumeId - name, err := iaasutils.GetVolumeName(ctx, apiClient, model.ProjectId, *backup.VolumeId) + name, err := iaasutils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, *backup.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume details: %v", err) } else if name != "" { @@ -89,7 +89,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Restoring backup") - _, err = wait.RestoreBackupWaitHandler(ctx, apiClient, model.ProjectId, model.BackupId).WaitWithContext(ctx) + _, err = wait.RestoreBackupWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.BackupId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for backup restore: %w", err) } @@ -125,6 +125,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRestoreBackupRequest { - req := apiClient.RestoreBackup(ctx, model.ProjectId, model.BackupId) + req := apiClient.RestoreBackup(ctx, model.ProjectId, model.Region, model.BackupId) return req } diff --git a/internal/cmd/volume/backup/restore/restore_test.go b/internal/cmd/volume/backup/restore/restore_test.go index 8532a05ee..1bd31ce17 100644 --- a/internal/cmd/volume/backup/restore/restore_test.go +++ b/internal/cmd/volume/backup/restore/restore_test.go @@ -13,6 +13,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -35,6 +39,7 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, BackupId: testBackupId, } @@ -57,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiRestoreBackupRequest)) iaas.ApiRestoreBackupRequest { - request := testClient.RestoreBackup(testCtx, testProjectId, testBackupId) + request := testClient.RestoreBackup(testCtx, testProjectId, testRegion, testBackupId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/volume/backup/update/update.go b/internal/cmd/volume/backup/update/update.go index 9ede68fac..920ef6667 100644 --- a/internal/cmd/volume/backup/update/update.go +++ b/internal/cmd/volume/backup/update/update.go @@ -59,7 +59,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - backupLabel, err := iaasutils.GetBackupName(ctx, apiClient, model.ProjectId, model.BackupId) + backupLabel, err := iaasutils.GetBackupName(ctx, apiClient, model.ProjectId, model.Region, model.BackupId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get backup name: %v", err) } @@ -118,7 +118,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateBackupRequest { - req := apiClient.UpdateBackup(ctx, model.ProjectId, model.BackupId) + req := apiClient.UpdateBackup(ctx, model.ProjectId, model.Region, model.BackupId) payload := iaas.UpdateBackupPayload{ Name: model.Name, diff --git a/internal/cmd/volume/backup/update/update_test.go b/internal/cmd/volume/backup/update/update_test.go index 85faf0764..94860245a 100644 --- a/internal/cmd/volume/backup/update/update_test.go +++ b/internal/cmd/volume/backup/update/update_test.go @@ -14,6 +14,11 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" + testName = "test-backup" +) + type testCtxKey struct{} var ( @@ -21,7 +26,6 @@ var ( testClient = &iaas.APIClient{} testProjectId = uuid.NewString() testBackupId = uuid.NewString() - testName = "test-backup" testLabels = map[string]string{"key1": "value1"} ) @@ -38,8 +42,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, - nameFlag: testName, - labelsFlag: "key1=value1", + globalflags.RegionFlag: testRegion, + + nameFlag: testName, + labelsFlag: "key1=value1", } for _, mod := range mods { mod(flagValues) @@ -52,9 +58,10 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, BackupId: testBackupId, - Name: &testName, + Name: utils.Ptr(testName), Labels: testLabels, } for _, mod := range mods { @@ -64,9 +71,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateBackupRequest)) iaas.ApiUpdateBackupRequest { - request := testClient.UpdateBackup(testCtx, testProjectId, testBackupId) + request := testClient.UpdateBackup(testCtx, testProjectId, testRegion, testBackupId) payload := iaas.NewUpdateBackupPayloadWithDefaults() - payload.Name = &testName + payload.Name = utils.Ptr(testName) payload.Labels = utils.ConvertStringMapToInterfaceMap(utils.Ptr(testLabels)) diff --git a/internal/cmd/volume/create/create.go b/internal/cmd/volume/create/create.go index f5024261a..a9b624c67 100644 --- a/internal/cmd/volume/create/create.go +++ b/internal/cmd/volume/create/create.go @@ -107,7 +107,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Creating volume") - _, err = wait.CreateVolumeWaitHandler(ctx, apiClient, model.ProjectId, volumeId).WaitWithContext(ctx) + _, err = wait.CreateVolumeWaitHandler(ctx, apiClient, model.ProjectId, model.Region, volumeId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for volume creation: %w", err) } @@ -158,7 +158,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateVolumeRequest { - req := apiClient.CreateVolume(ctx, model.ProjectId) + req := apiClient.CreateVolume(ctx, model.ProjectId, model.Region) source := &iaas.VolumeSource{ Id: model.SourceId, Type: model.SourceType, diff --git a/internal/cmd/volume/create/create_test.go b/internal/cmd/volume/create/create_test.go index 35f163e21..dde4f7893 100644 --- a/internal/cmd/volume/create/create_test.go +++ b/internal/cmd/volume/create/create_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -27,7 +29,9 @@ var testSourceId = uuid.NewString() func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + availabilityZoneFlag: "eu01-1", nameFlag: "example-volume-name", descriptionFlag: "example-volume-description", @@ -48,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, AvailabilityZone: utils.Ptr("eu01-1"), Name: utils.Ptr("example-volume-name"), @@ -67,7 +72,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateVolumeRequest)) iaas.ApiCreateVolumeRequest { - request := testClient.CreateVolume(testCtx, testProjectId) + request := testClient.CreateVolume(testCtx, testProjectId, testRegion) request = request.CreateVolumePayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -76,7 +81,7 @@ func fixtureRequest(mods ...func(request *iaas.ApiCreateVolumeRequest)) iaas.Api } func fixtureRequiredRequest(mods ...func(request *iaas.ApiCreateVolumeRequest)) iaas.ApiCreateVolumeRequest { - request := testClient.CreateVolume(testCtx, testProjectId) + request := testClient.CreateVolume(testCtx, testProjectId, testRegion) request = request.CreateVolumePayload(iaas.CreateVolumePayload{ AvailabilityZone: utils.Ptr("eu01-1"), }) @@ -158,21 +163,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, @@ -226,6 +231,7 @@ func TestBuildRequest(t *testing.T) { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, AvailabilityZone: utils.Ptr("eu01-1"), }, diff --git a/internal/cmd/volume/delete/delete.go b/internal/cmd/volume/delete/delete.go index 1c94e3dc2..58d47c8ae 100644 --- a/internal/cmd/volume/delete/delete.go +++ b/internal/cmd/volume/delete/delete.go @@ -57,7 +57,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId @@ -82,7 +82,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deleting volume") - _, err = wait.DeleteVolumeWaitHandler(ctx, apiClient, model.ProjectId, model.VolumeId).WaitWithContext(ctx) + _, err = wait.DeleteVolumeWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for volume deletion: %w", err) } @@ -118,5 +118,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteVolumeRequest { - return apiClient.DeleteVolume(ctx, model.ProjectId, model.VolumeId) + return apiClient.DeleteVolume(ctx, model.ProjectId, model.Region, model.VolumeId) } diff --git a/internal/cmd/volume/delete/delete_test.go b/internal/cmd/volume/delete/delete_test.go index db5545312..42d63db2b 100644 --- a/internal/cmd/volume/delete/delete_test.go +++ b/internal/cmd/volume/delete/delete_test.go @@ -13,7 +13,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -34,7 +36,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, VolumeId: testVolumeId, } @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteVolumeRequest)) iaas.ApiDeleteVolumeRequest { - request := testClient.DeleteVolume(testCtx, testProjectId, testVolumeId) + request := testClient.DeleteVolume(testCtx, testProjectId, testRegion, testVolumeId) for _, mod := range mods { mod(&request) } @@ -101,7 +105,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -109,7 +113,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -117,7 +121,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/describe/describe.go b/internal/cmd/volume/describe/describe.go index 19e536d7b..0683ae255 100644 --- a/internal/cmd/volume/describe/describe.go +++ b/internal/cmd/volume/describe/describe.go @@ -88,7 +88,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetVolumeRequest { - return apiClient.GetVolume(ctx, model.ProjectId, model.VolumeId) + return apiClient.GetVolume(ctx, model.ProjectId, model.Region, model.VolumeId) } func outputResult(p *print.Printer, outputFormat string, volume *iaas.Volume) error { diff --git a/internal/cmd/volume/describe/describe_test.go b/internal/cmd/volume/describe/describe_test.go index 1c4e2b907..9396645d4 100644 --- a/internal/cmd/volume/describe/describe_test.go +++ b/internal/cmd/volume/describe/describe_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -35,7 +37,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -48,6 +51,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, + Region: testRegion, }, VolumeId: testVolumeId, } @@ -58,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetVolumeRequest)) iaas.ApiGetVolumeRequest { - request := testClient.GetVolume(testCtx, testProjectId, testVolumeId) + request := testClient.GetVolume(testCtx, testProjectId, testRegion, testVolumeId) for _, mod := range mods { mod(&request) } @@ -102,7 +106,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -110,7 +114,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -118,7 +122,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/list/list.go b/internal/cmd/volume/list/list.go index d1c7b884f..586f8b721 100644 --- a/internal/cmd/volume/list/list.go +++ b/internal/cmd/volume/list/list.go @@ -127,7 +127,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListVolumesRequest { - req := apiClient.ListVolumes(ctx, model.ProjectId) + req := apiClient.ListVolumes(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/volume/list/list_test.go b/internal/cmd/volume/list/list_test.go index cb54d2e1f..4fdeab7b2 100644 --- a/internal/cmd/volume/list/list_test.go +++ b/internal/cmd/volume/list/list_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -26,7 +28,9 @@ var testLabelSelector = "label" func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", labelSelectorFlag: testLabelSelector, } @@ -41,6 +45,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), @@ -52,7 +57,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListVolumesRequest)) iaas.ApiListVolumesRequest { - request := testClient.ListVolumes(testCtx, testProjectId) + request := testClient.ListVolumes(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabelSelector) for _, mod := range mods { mod(&request) @@ -87,21 +92,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/performance-class/describe/describe.go b/internal/cmd/volume/performance-class/describe/describe.go index 24a158239..324609ada 100644 --- a/internal/cmd/volume/performance-class/describe/describe.go +++ b/internal/cmd/volume/performance-class/describe/describe.go @@ -88,7 +88,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetVolumePerformanceClassRequest { - return apiClient.GetVolumePerformanceClass(ctx, model.ProjectId, model.VolumePerformanceClass) + return apiClient.GetVolumePerformanceClass(ctx, model.ProjectId, model.Region, model.VolumePerformanceClass) } func outputResult(p *print.Printer, outputFormat string, performanceClass *iaas.VolumePerformanceClass) error { diff --git a/internal/cmd/volume/performance-class/describe/describe_test.go b/internal/cmd/volume/performance-class/describe/describe_test.go index 737335164..269dae052 100644 --- a/internal/cmd/volume/performance-class/describe/describe_test.go +++ b/internal/cmd/volume/performance-class/describe/describe_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,7 +38,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -48,6 +51,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, VolumePerformanceClass: testVolumePerformanceClass, @@ -59,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetVolumePerformanceClassRequest)) iaas.ApiGetVolumePerformanceClassRequest { - request := testClient.GetVolumePerformanceClass(testCtx, testProjectId, testVolumePerformanceClass) + request := testClient.GetVolumePerformanceClass(testCtx, testProjectId, testRegion, testVolumePerformanceClass) for _, mod := range mods { mod(&request) } @@ -103,7 +107,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -111,7 +115,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -119,7 +123,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/performance-class/list/list.go b/internal/cmd/volume/performance-class/list/list.go index 0c8a5de64..46ef6574b 100644 --- a/internal/cmd/volume/performance-class/list/list.go +++ b/internal/cmd/volume/performance-class/list/list.go @@ -128,7 +128,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListVolumePerformanceClassesRequest { - req := apiClient.ListVolumePerformanceClasses(ctx, model.ProjectId) + req := apiClient.ListVolumePerformanceClasses(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/volume/performance-class/list/list_test.go b/internal/cmd/volume/performance-class/list/list_test.go index 4a36b5333..7bbd048f0 100644 --- a/internal/cmd/volume/performance-class/list/list_test.go +++ b/internal/cmd/volume/performance-class/list/list_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -26,7 +28,9 @@ var testLabelSelector = "label" func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", labelSelectorFlag: testLabelSelector, } @@ -41,6 +45,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, ProjectId: testProjectId, + Region: testRegion, }, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), @@ -52,7 +57,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiListVolumePerformanceClassesRequest)) iaas.ApiListVolumePerformanceClassesRequest { - request := testClient.ListVolumePerformanceClasses(testCtx, testProjectId) + request := testClient.ListVolumePerformanceClasses(testCtx, testProjectId, testRegion) request = request.LabelSelector(testLabelSelector) for _, mod := range mods { mod(&request) @@ -87,21 +92,21 @@ func TestParseInput(t *testing.T) { { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, { description: "project id invalid 1", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, { description: "project id invalid 2", flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/resize/resize.go b/internal/cmd/volume/resize/resize.go index 4d1a0d03a..58be4800d 100644 --- a/internal/cmd/volume/resize/resize.go +++ b/internal/cmd/volume/resize/resize.go @@ -56,7 +56,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId @@ -111,7 +111,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiResizeVolumeRequest { - req := apiClient.ResizeVolume(ctx, model.ProjectId, model.VolumeId) + req := apiClient.ResizeVolume(ctx, model.ProjectId, model.Region, model.VolumeId) payload := iaas.ResizeVolumePayload{ Size: model.Size, diff --git a/internal/cmd/volume/resize/resize_test.go b/internal/cmd/volume/resize/resize_test.go index 54d02a47f..094cb7864 100644 --- a/internal/cmd/volume/resize/resize_test.go +++ b/internal/cmd/volume/resize/resize_test.go @@ -15,7 +15,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -37,8 +39,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - sizeFlag: "10", - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + + sizeFlag: "10", } for _, mod := range mods { mod(flagValues) @@ -50,6 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Size: utils.Ptr(int64(10)), @@ -62,7 +67,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiResizeVolumeRequest)) iaas.ApiResizeVolumeRequest { - request := testClient.ResizeVolume(testCtx, testProjectId, testVolumeId) + request := testClient.ResizeVolume(testCtx, testProjectId, testRegion, testVolumeId) request = request.ResizeVolumePayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -105,7 +110,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -113,7 +118,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -121,7 +126,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/cmd/volume/snapshot/create/create.go b/internal/cmd/volume/snapshot/create/create.go index 1146ccaba..a49b89da4 100644 --- a/internal/cmd/volume/snapshot/create/create.go +++ b/internal/cmd/volume/snapshot/create/create.go @@ -72,7 +72,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Get volume name for label - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeID) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeID) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeID @@ -97,7 +97,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Creating snapshot") - resp, err = wait.CreateSnapshotWaitHandler(ctx, apiClient, model.ProjectId, *resp.Id).WaitWithContext(ctx) + resp, err = wait.CreateSnapshotWaitHandler(ctx, apiClient, model.ProjectId, model.Region, *resp.Id).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for snapshot creation: %w", err) } @@ -152,7 +152,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateSnapshotRequest { - req := apiClient.CreateSnapshot(ctx, model.ProjectId) + req := apiClient.CreateSnapshot(ctx, model.ProjectId, model.Region) payload := iaas.NewCreateSnapshotPayloadWithDefaults() payload.VolumeId = &model.VolumeID payload.Name = model.Name diff --git a/internal/cmd/volume/snapshot/create/create_test.go b/internal/cmd/volume/snapshot/create/create_test.go index 00111c28f..d2ee79608 100644 --- a/internal/cmd/volume/snapshot/create/create_test.go +++ b/internal/cmd/volume/snapshot/create/create_test.go @@ -16,7 +16,8 @@ import ( type testCtxKey struct{} const ( - testName = "test-snapshot" + testRegion = "eu01" + testName = "test-snapshot" ) var ( @@ -30,9 +31,11 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, - volumeIdFlag: testVolumeId, - nameFlag: testName, - labelsFlag: "key1=value1", + globalflags.RegionFlag: testRegion, + + volumeIdFlag: testVolumeId, + nameFlag: testName, + labelsFlag: "key1=value1", } for _, mod := range mods { mod(flagValues) @@ -44,6 +47,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, VolumeID: testVolumeId, @@ -57,7 +61,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiCreateSnapshotRequest)) iaas.ApiCreateSnapshotRequest { - request := testClient.CreateSnapshot(testCtx, testProjectId) + request := testClient.CreateSnapshot(testCtx, testProjectId, testRegion) payload := iaas.NewCreateSnapshotPayloadWithDefaults() payload.VolumeId = &testVolumeId payload.Name = utils.Ptr(testName) diff --git a/internal/cmd/volume/snapshot/delete/delete.go b/internal/cmd/volume/snapshot/delete/delete.go index 11c4d1f1d..a94ef6bf1 100644 --- a/internal/cmd/volume/snapshot/delete/delete.go +++ b/internal/cmd/volume/snapshot/delete/delete.go @@ -54,7 +54,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Get snapshot name for label - snapshotLabel, err := iaasUtils.GetSnapshotName(ctx, apiClient, model.ProjectId, model.SnapshotId) + snapshotLabel, err := iaasUtils.GetSnapshotName(ctx, apiClient, model.ProjectId, model.Region, model.SnapshotId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get snapshot name: %v", err) snapshotLabel = model.SnapshotId @@ -79,7 +79,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deleting snapshot") - _, err = wait.DeleteSnapshotWaitHandler(ctx, apiClient, model.ProjectId, model.SnapshotId).WaitWithContext(ctx) + _, err = wait.DeleteSnapshotWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.SnapshotId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for snapshot deletion: %w", err) } @@ -115,5 +115,5 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteSnapshotRequest { - return apiClient.DeleteSnapshot(ctx, model.ProjectId, model.SnapshotId) + return apiClient.DeleteSnapshot(ctx, model.ProjectId, model.Region, model.SnapshotId) } diff --git a/internal/cmd/volume/snapshot/delete/delete_test.go b/internal/cmd/volume/snapshot/delete/delete_test.go index f97165703..6ffa3d880 100644 --- a/internal/cmd/volume/snapshot/delete/delete_test.go +++ b/internal/cmd/volume/snapshot/delete/delete_test.go @@ -13,6 +13,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -35,6 +39,7 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -46,6 +51,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, SnapshotId: testSnapshotId, @@ -57,7 +63,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiDeleteSnapshotRequest)) iaas.ApiDeleteSnapshotRequest { - request := testClient.DeleteSnapshot(testCtx, testProjectId, testSnapshotId) + request := testClient.DeleteSnapshot(testCtx, testProjectId, testRegion, testSnapshotId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/volume/snapshot/describe/describe.go b/internal/cmd/volume/snapshot/describe/describe.go index bf78cb603..17ed41c88 100644 --- a/internal/cmd/volume/snapshot/describe/describe.go +++ b/internal/cmd/volume/snapshot/describe/describe.go @@ -86,7 +86,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiGetSnapshotRequest { - return apiClient.GetSnapshot(ctx, model.ProjectId, model.SnapshotId) + return apiClient.GetSnapshot(ctx, model.ProjectId, model.Region, model.SnapshotId) } func outputResult(p *print.Printer, outputFormat string, snapshot *iaas.Snapshot) error { diff --git a/internal/cmd/volume/snapshot/describe/describe_test.go b/internal/cmd/volume/snapshot/describe/describe_test.go index 7da9d09a4..ff1e25aec 100644 --- a/internal/cmd/volume/snapshot/describe/describe_test.go +++ b/internal/cmd/volume/snapshot/describe/describe_test.go @@ -16,6 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -38,6 +42,7 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -49,6 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, SnapshotId: testSnapshotId, @@ -60,7 +66,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiGetSnapshotRequest)) iaas.ApiGetSnapshotRequest { - request := testClient.GetSnapshot(testCtx, testProjectId, testSnapshotId) + request := testClient.GetSnapshot(testCtx, testProjectId, testRegion, testSnapshotId) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/volume/snapshot/list/list.go b/internal/cmd/volume/snapshot/list/list.go index 2ef8c9d4d..ce8052287 100644 --- a/internal/cmd/volume/snapshot/list/list.go +++ b/internal/cmd/volume/snapshot/list/list.go @@ -126,8 +126,8 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, return &model, nil } -func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListSnapshotsRequest { - req := apiClient.ListSnapshots(ctx, model.ProjectId) +func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListSnapshotsInProjectRequest { + req := apiClient.ListSnapshotsInProject(ctx, model.ProjectId, model.Region) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/volume/snapshot/list/list_test.go b/internal/cmd/volume/snapshot/list/list_test.go index c9facab11..5e9c8b0c8 100644 --- a/internal/cmd/volume/snapshot/list/list_test.go +++ b/internal/cmd/volume/snapshot/list/list_test.go @@ -16,6 +16,10 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" +) + type testCtxKey struct{} var ( @@ -27,8 +31,10 @@ var ( func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, - limitFlag: "10", - labelSelectorFlag: "key1=value1", + globalflags.RegionFlag: testRegion, + + limitFlag: "10", + labelSelectorFlag: "key1=value1", } for _, mod := range mods { mod(flagValues) @@ -40,6 +46,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Limit: utils.Ptr(int64(10)), @@ -51,8 +58,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { return model } -func fixtureRequest(mods ...func(request *iaas.ApiListSnapshotsRequest)) iaas.ApiListSnapshotsRequest { - request := testClient.ListSnapshots(testCtx, testProjectId) +func fixtureRequest(mods ...func(request *iaas.ApiListSnapshotsInProjectRequest)) iaas.ApiListSnapshotsInProjectRequest { + request := testClient.ListSnapshotsInProject(testCtx, testProjectId, testRegion) request = request.LabelSelector("key1=value1") for _, mod := range mods { mod(&request) @@ -139,7 +146,7 @@ func TestBuildRequest(t *testing.T) { tests := []struct { description string model *inputModel - expectedRequest iaas.ApiListSnapshotsRequest + expectedRequest iaas.ApiListSnapshotsInProjectRequest }{ { description: "base", @@ -151,8 +158,8 @@ func TestBuildRequest(t *testing.T) { model: fixtureInputModel(func(model *inputModel) { model.LabelSelector = nil }), - expectedRequest: fixtureRequest(func(request *iaas.ApiListSnapshotsRequest) { - *request = testClient.ListSnapshots(testCtx, testProjectId) + expectedRequest: fixtureRequest(func(request *iaas.ApiListSnapshotsInProjectRequest) { + *request = testClient.ListSnapshotsInProject(testCtx, testProjectId, testRegion) }), }, } diff --git a/internal/cmd/volume/snapshot/update/update.go b/internal/cmd/volume/snapshot/update/update.go index 889b2cae4..766c33b34 100644 --- a/internal/cmd/volume/snapshot/update/update.go +++ b/internal/cmd/volume/snapshot/update/update.go @@ -60,7 +60,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Get snapshot name for label - snapshotLabel, err := iaasUtils.GetSnapshotName(ctx, apiClient, model.ProjectId, model.SnapshotId) + snapshotLabel, err := iaasUtils.GetSnapshotName(ctx, apiClient, model.ProjectId, model.Region, model.SnapshotId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get snapshot name: %v", err) snapshotLabel = model.SnapshotId @@ -125,7 +125,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateSnapshotRequest { - req := apiClient.UpdateSnapshot(ctx, model.ProjectId, model.SnapshotId) + req := apiClient.UpdateSnapshot(ctx, model.ProjectId, model.Region, model.SnapshotId) payload := iaas.NewUpdateSnapshotPayloadWithDefaults() payload.Name = model.Name payload.Labels = utils.ConvertStringMapToInterfaceMap(utils.Ptr(model.Labels)) diff --git a/internal/cmd/volume/snapshot/update/update_test.go b/internal/cmd/volume/snapshot/update/update_test.go index b96da76f1..d5e159315 100644 --- a/internal/cmd/volume/snapshot/update/update_test.go +++ b/internal/cmd/volume/snapshot/update/update_test.go @@ -14,6 +14,11 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +const ( + testRegion = "eu01" + testName = "test-snapshot" +) + type testCtxKey struct{} var ( @@ -21,7 +26,6 @@ var ( testClient = &iaas.APIClient{} testProjectId = uuid.NewString() testSnapshotId = uuid.NewString() - testName = "test-snapshot" testLabels = map[string]string{"key1": "value1"} ) @@ -38,8 +42,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ globalflags.ProjectIdFlag: testProjectId, - nameFlag: testName, - labelsFlag: "key1=value1", + globalflags.RegionFlag: testRegion, + + nameFlag: testName, + labelsFlag: "key1=value1", } for _, mod := range mods { mod(flagValues) @@ -51,10 +57,11 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, SnapshotId: testSnapshotId, - Name: &testName, + Name: utils.Ptr(testName), Labels: testLabels, } for _, mod := range mods { @@ -64,9 +71,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateSnapshotRequest)) iaas.ApiUpdateSnapshotRequest { - request := testClient.UpdateSnapshot(testCtx, testProjectId, testSnapshotId) + request := testClient.UpdateSnapshot(testCtx, testProjectId, testRegion, testSnapshotId) payload := iaas.NewUpdateSnapshotPayloadWithDefaults() - payload.Name = &testName + payload.Name = utils.Ptr(testName) payload.Labels = utils.ConvertStringMapToInterfaceMap(utils.Ptr(testLabels)) request = request.UpdateSnapshotPayload(*payload) diff --git a/internal/cmd/volume/update/update.go b/internal/cmd/volume/update/update.go index 0af92ab77..55e2e2a70 100644 --- a/internal/cmd/volume/update/update.go +++ b/internal/cmd/volume/update/update.go @@ -67,7 +67,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.VolumeId) + volumeLabel, err := iaasUtils.GetVolumeName(ctx, apiClient, model.ProjectId, model.Region, model.VolumeId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get volume name: %v", err) volumeLabel = model.VolumeId @@ -122,7 +122,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateVolumeRequest { - req := apiClient.UpdateVolume(ctx, model.ProjectId, model.VolumeId) + req := apiClient.UpdateVolume(ctx, model.ProjectId, model.Region, model.VolumeId) payload := iaas.UpdateVolumePayload{ Name: model.Name, diff --git a/internal/cmd/volume/update/update_test.go b/internal/cmd/volume/update/update_test.go index 1628bf26a..6b890a82c 100644 --- a/internal/cmd/volume/update/update_test.go +++ b/internal/cmd/volume/update/update_test.go @@ -14,7 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) -var projectIdFlag = globalflags.ProjectIdFlag +const ( + testRegion = "eu01" +) type testCtxKey struct{} @@ -36,8 +38,10 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + nameFlag: "example-volume-name", - projectIdFlag: testProjectId, descriptionFlag: "example-volume-desc", labelFlag: "key=value", } @@ -51,6 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Name: utils.Ptr("example-volume-name"), @@ -67,7 +72,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *iaas.ApiUpdateVolumeRequest)) iaas.ApiUpdateVolumeRequest { - request := testClient.UpdateVolume(testCtx, testProjectId, testVolumeId) + request := testClient.UpdateVolume(testCtx, testProjectId, testRegion, testVolumeId) request = request.UpdateVolumePayload(fixturePayload()) for _, mod := range mods { mod(&request) @@ -114,7 +119,7 @@ func TestParseInput(t *testing.T) { description: "project id missing", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - delete(flagValues, projectIdFlag) + delete(flagValues, globalflags.ProjectIdFlag) }), isValid: false, }, @@ -122,7 +127,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 1", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "" + flagValues[globalflags.ProjectIdFlag] = "" }), isValid: false, }, @@ -130,7 +135,7 @@ func TestParseInput(t *testing.T) { description: "project id invalid 2", argValues: fixtureArgValues(), flagValues: fixtureFlagValues(func(flagValues map[string]string) { - flagValues[projectIdFlag] = "invalid-uuid" + flagValues[globalflags.ProjectIdFlag] = "invalid-uuid" }), isValid: false, }, diff --git a/internal/pkg/errors/errors.go b/internal/pkg/errors/errors.go index 9c83fb4f1..814929497 100644 --- a/internal/pkg/errors/errors.go +++ b/internal/pkg/errors/errors.go @@ -18,6 +18,16 @@ You can configure it for all commands by running: or you can also set it through the environment variable [STACKIT_PROJECT_ID]` + MISSING_REGION = `the region is not currently set. + +It can be set on the command level by re-running your command with the --region flag. + +You can configure it for all commands by running: + + $ stackit config set --region xxx + +or you can also set it through the environment variable [STACKIT_REGION]` + EMPTY_UPDATE = `please specify at least one field to update. Get details on the available flags by re-running your command with the --help flag.` @@ -178,6 +188,12 @@ To list all profiles, run: $ stackit config profile list` FILE_ALREADY_EXISTS = `file %q already exists in the export path. Delete the existing file or define a different export path` + + FLAG_MUST_BE_PROVIDED_WHEN_ANOTHER_FLAG_IS_SET = `The flag %[1]q must be provided when %[2]q is set` + + MULTIPLE_FLAGS_MUST_BE_PROVIDED_WHEN_ANOTHER_FLAG_IS_SET = `The flags %[1]v must be provided when one of the flags %[2]v is set` + + ONE_OF_THE_FLAGS_MUST_BE_PROVIDED_WHEN_ANOTHER_FLAG_IS_SET = `One of the flags %[1]v must be provided when %[2]q is set` ) type ServerNicAttachMissingNicIdError struct { @@ -234,6 +250,12 @@ func (e *ProjectIdError) Error() string { return MISSING_PROJECT_ID } +type RegionError struct{} + +func (e *RegionError) Error() string { + return MISSING_REGION +} + type EmptyUpdateError struct{} func (e *EmptyUpdateError) Error() string { @@ -499,3 +521,30 @@ type FileAlreadyExistsError struct { } func (e *FileAlreadyExistsError) Error() string { return fmt.Sprintf(FILE_ALREADY_EXISTS, e.Filename) } + +type DependingFlagIsMissing struct { + MissingFlag string + SetFlag string +} + +func (e *DependingFlagIsMissing) Error() string { + return fmt.Sprintf(FLAG_MUST_BE_PROVIDED_WHEN_ANOTHER_FLAG_IS_SET, fmt.Sprintf("--%s", e.MissingFlag), fmt.Sprintf("--%s", e.SetFlag)) +} + +type MultipleFlagsAreMissing struct { + MissingFlags []string + SetFlags []string +} + +func (e *MultipleFlagsAreMissing) Error() string { + return fmt.Sprintf(MULTIPLE_FLAGS_MUST_BE_PROVIDED_WHEN_ANOTHER_FLAG_IS_SET, e.MissingFlags, e.SetFlags) +} + +type OneOfFlagsIsMissing struct { + MissingFlags []string + SetFlag string +} + +func (e *OneOfFlagsIsMissing) Error() string { + return fmt.Sprintf(ONE_OF_THE_FLAGS_MUST_BE_PROVIDED_WHEN_ANOTHER_FLAG_IS_SET, e.MissingFlags, e.SetFlag) +} diff --git a/internal/pkg/services/iaas/client/client.go b/internal/pkg/services/iaas/client/client.go index c9401016a..a49f04b7c 100644 --- a/internal/pkg/services/iaas/client/client.go +++ b/internal/pkg/services/iaas/client/client.go @@ -10,5 +10,5 @@ import ( ) func ConfigureClient(p *print.Printer, cliVersion string) (*iaas.APIClient, error) { - return genericclient.ConfigureClientGeneric(p, cliVersion, viper.GetString(config.IaaSCustomEndpointKey), true, genericclient.CreateApiClient[*iaas.APIClient](iaas.NewAPIClient)) + return genericclient.ConfigureClientGeneric(p, cliVersion, viper.GetString(config.IaaSCustomEndpointKey), false, genericclient.CreateApiClient[*iaas.APIClient](iaas.NewAPIClient)) } diff --git a/internal/pkg/services/iaas/utils/utils.go b/internal/pkg/services/iaas/utils/utils.go index 2cf460334..b7973c265 100644 --- a/internal/pkg/services/iaas/utils/utils.go +++ b/internal/pkg/services/iaas/utils/utils.go @@ -15,23 +15,23 @@ var ( ) type IaaSClient interface { - GetSecurityGroupRuleExecute(ctx context.Context, projectId, securityGroupRuleId, securityGroupId string) (*iaas.SecurityGroupRule, error) - GetSecurityGroupExecute(ctx context.Context, projectId, securityGroupId string) (*iaas.SecurityGroup, error) - GetPublicIPExecute(ctx context.Context, projectId, publicIpId string) (*iaas.PublicIp, error) - GetServerExecute(ctx context.Context, projectId, serverId string) (*iaas.Server, error) - GetVolumeExecute(ctx context.Context, projectId, volumeId string) (*iaas.Volume, error) - GetNetworkExecute(ctx context.Context, projectId, networkId string) (*iaas.Network, error) + GetSecurityGroupRuleExecute(ctx context.Context, projectId, region, securityGroupRuleId, securityGroupId string) (*iaas.SecurityGroupRule, error) + GetSecurityGroupExecute(ctx context.Context, projectId, region, securityGroupId string) (*iaas.SecurityGroup, error) + GetPublicIPExecute(ctx context.Context, projectId, region, publicIpId string) (*iaas.PublicIp, error) + GetServerExecute(ctx context.Context, projectId, region, serverId string) (*iaas.Server, error) + GetVolumeExecute(ctx context.Context, projectId, region, volumeId string) (*iaas.Volume, error) + GetNetworkExecute(ctx context.Context, projectId, region, networkId string) (*iaas.Network, error) GetNetworkAreaExecute(ctx context.Context, organizationId, areaId string) (*iaas.NetworkArea, error) ListNetworkAreaProjectsExecute(ctx context.Context, organizationId, areaId string) (*iaas.ProjectListResponse, error) - GetNetworkAreaRangeExecute(ctx context.Context, organizationId, areaId, networkRangeId string) (*iaas.NetworkRange, error) - GetImageExecute(ctx context.Context, projectId string, imageId string) (*iaas.Image, error) - GetAffinityGroupExecute(ctx context.Context, projectId string, affinityGroupId string) (*iaas.AffinityGroup, error) - GetSnapshotExecute(ctx context.Context, projectId, snapshotId string) (*iaas.Snapshot, error) - GetBackupExecute(ctx context.Context, projectId, backupId string) (*iaas.Backup, error) + GetNetworkAreaRangeExecute(ctx context.Context, organizationId, areaId, region, networkRangeId string) (*iaas.NetworkRange, error) + GetImageExecute(ctx context.Context, projectId, region, imageId string) (*iaas.Image, error) + GetAffinityGroupExecute(ctx context.Context, projectId, region, affinityGroupId string) (*iaas.AffinityGroup, error) + GetSnapshotExecute(ctx context.Context, projectId, region, snapshotId string) (*iaas.Snapshot, error) + GetBackupExecute(ctx context.Context, projectId, region, backupId string) (*iaas.Backup, error) } -func GetSecurityGroupRuleName(ctx context.Context, apiClient IaaSClient, projectId, securityGroupRuleId, securityGroupId string) (string, error) { - resp, err := apiClient.GetSecurityGroupRuleExecute(ctx, projectId, securityGroupRuleId, securityGroupId) +func GetSecurityGroupRuleName(ctx context.Context, apiClient IaaSClient, projectId, region, securityGroupRuleId, securityGroupId string) (string, error) { + resp, err := apiClient.GetSecurityGroupRuleExecute(ctx, projectId, region, securityGroupRuleId, securityGroupId) if err != nil { return "", fmt.Errorf("get security group rule: %w", err) } @@ -39,8 +39,8 @@ func GetSecurityGroupRuleName(ctx context.Context, apiClient IaaSClient, project return securityGroupRuleName, nil } -func GetSecurityGroupName(ctx context.Context, apiClient IaaSClient, projectId, securityGroupId string) (string, error) { - resp, err := apiClient.GetSecurityGroupExecute(ctx, projectId, securityGroupId) +func GetSecurityGroupName(ctx context.Context, apiClient IaaSClient, projectId, region, securityGroupId string) (string, error) { + resp, err := apiClient.GetSecurityGroupExecute(ctx, projectId, region, securityGroupId) if err != nil { return "", fmt.Errorf("get security group: %w", err) } else if resp == nil { @@ -51,8 +51,8 @@ func GetSecurityGroupName(ctx context.Context, apiClient IaaSClient, projectId, return *resp.Name, nil } -func GetPublicIP(ctx context.Context, apiClient IaaSClient, projectId, publicIpId string) (ip, associatedResource string, err error) { - resp, err := apiClient.GetPublicIPExecute(ctx, projectId, publicIpId) +func GetPublicIP(ctx context.Context, apiClient IaaSClient, projectId, region, publicIpId string) (ip, associatedResource string, err error) { + resp, err := apiClient.GetPublicIPExecute(ctx, projectId, region, publicIpId) if err != nil { return "", "", fmt.Errorf("get public ip: %w", err) } @@ -63,16 +63,16 @@ func GetPublicIP(ctx context.Context, apiClient IaaSClient, projectId, publicIpI return *resp.Ip, associatedResourceId, nil } -func GetServerName(ctx context.Context, apiClient IaaSClient, projectId, serverId string) (string, error) { - resp, err := apiClient.GetServerExecute(ctx, projectId, serverId) +func GetServerName(ctx context.Context, apiClient IaaSClient, projectId, region, serverId string) (string, error) { + resp, err := apiClient.GetServerExecute(ctx, projectId, region, serverId) if err != nil { return "", fmt.Errorf("get server: %w", err) } return *resp.Name, nil } -func GetVolumeName(ctx context.Context, apiClient IaaSClient, projectId, volumeId string) (string, error) { - resp, err := apiClient.GetVolumeExecute(ctx, projectId, volumeId) +func GetVolumeName(ctx context.Context, apiClient IaaSClient, projectId, region, volumeId string) (string, error) { + resp, err := apiClient.GetVolumeExecute(ctx, projectId, region, volumeId) if err != nil { return "", fmt.Errorf("get volume: %w", err) } else if resp == nil { @@ -83,8 +83,8 @@ func GetVolumeName(ctx context.Context, apiClient IaaSClient, projectId, volumeI return *resp.Name, nil } -func GetNetworkName(ctx context.Context, apiClient IaaSClient, projectId, networkId string) (string, error) { - resp, err := apiClient.GetNetworkExecute(ctx, projectId, networkId) +func GetNetworkName(ctx context.Context, apiClient IaaSClient, projectId, region, networkId string) (string, error) { + resp, err := apiClient.GetNetworkExecute(ctx, projectId, region, networkId) if err != nil { return "", fmt.Errorf("get network: %w", err) } else if resp == nil { @@ -119,8 +119,8 @@ func ListAttachedProjects(ctx context.Context, apiClient IaaSClient, organizatio return *resp.Items, nil } -func GetNetworkRangePrefix(ctx context.Context, apiClient IaaSClient, organizationId, areaId, networkRangeId string) (string, error) { - resp, err := apiClient.GetNetworkAreaRangeExecute(ctx, organizationId, areaId, networkRangeId) +func GetNetworkRangePrefix(ctx context.Context, apiClient IaaSClient, organizationId, areaId, region, networkRangeId string) (string, error) { + resp, err := apiClient.GetNetworkAreaRangeExecute(ctx, organizationId, areaId, region, networkRangeId) if err != nil { return "", fmt.Errorf("get network range: %w", err) } @@ -129,10 +129,47 @@ func GetNetworkRangePrefix(ctx context.Context, apiClient IaaSClient, organizati // GetRouteFromAPIResponse returns the static route from the API response that matches the prefix and nexthop // This works because static routes are unique by prefix and nexthop -func GetRouteFromAPIResponse(prefix, nexthop string, routes *[]iaas.Route) (iaas.Route, error) { +func GetRouteFromAPIResponse(destination, nexthop string, routes *[]iaas.Route) (iaas.Route, error) { for _, route := range *routes { - if *route.Prefix == prefix && *route.Nexthop == nexthop { - return route, nil + // Check if destination matches + if dest := route.Destination; dest != nil { + match := false + if destV4 := dest.DestinationCIDRv4; destV4 != nil { + if destV4.Value != nil && *destV4.Value == destination { + match = true + } + } else if destV6 := dest.DestinationCIDRv6; destV6 != nil { + if destV6.Value != nil && *destV6.Value == destination { + match = true + } + } + if !match { + continue + } + } + // Check if nexthop matches + if routeNexthop := route.Nexthop; routeNexthop != nil { + match := false + if nexthopIPv4 := routeNexthop.NexthopIPv4; nexthopIPv4 != nil { + if nexthopIPv4.Value != nil && *nexthopIPv4.Value == nexthop { + match = true + } + } else if nexthopIPv6 := routeNexthop.NexthopIPv6; nexthopIPv6 != nil { + if nexthopIPv6.Value != nil && *nexthopIPv6.Value == nexthop { + match = true + } + } else if nexthopInternet := routeNexthop.NexthopInternet; nexthopInternet != nil { + if nexthopInternet.Type != nil && *nexthopInternet.Type == nexthop { + match = true + } + } else if nexthopBlackhole := routeNexthop.NexthopBlackhole; nexthopBlackhole != nil { + if nexthopBlackhole.Type != nil && *nexthopBlackhole.Type == nexthop { + match = true + } + } + if match { + return route, nil + } } } return iaas.Route{}, fmt.Errorf("new static route not found in API response") @@ -149,8 +186,8 @@ func GetNetworkRangeFromAPIResponse(prefix string, networkRanges *[]iaas.Network return iaas.NetworkRange{}, fmt.Errorf("new network range not found in API response") } -func GetImageName(ctx context.Context, apiClient IaaSClient, projectId, imageId string) (string, error) { - resp, err := apiClient.GetImageExecute(ctx, projectId, imageId) +func GetImageName(ctx context.Context, apiClient IaaSClient, projectId, region, imageId string) (string, error) { + resp, err := apiClient.GetImageExecute(ctx, projectId, region, imageId) if err != nil { return "", fmt.Errorf("get image: %w", err) } else if resp == nil { @@ -161,8 +198,8 @@ func GetImageName(ctx context.Context, apiClient IaaSClient, projectId, imageId return *resp.Name, nil } -func GetAffinityGroupName(ctx context.Context, apiClient IaaSClient, projectId, affinityGroupId string) (string, error) { - resp, err := apiClient.GetAffinityGroupExecute(ctx, projectId, affinityGroupId) +func GetAffinityGroupName(ctx context.Context, apiClient IaaSClient, projectId, region, affinityGroupId string) (string, error) { + resp, err := apiClient.GetAffinityGroupExecute(ctx, projectId, region, affinityGroupId) if err != nil { return "", fmt.Errorf("get affinity group: %w", err) } else if resp == nil { @@ -173,8 +210,8 @@ func GetAffinityGroupName(ctx context.Context, apiClient IaaSClient, projectId, return *resp.Name, nil } -func GetSnapshotName(ctx context.Context, apiClient IaaSClient, projectId, snapshotId string) (string, error) { - resp, err := apiClient.GetSnapshotExecute(ctx, projectId, snapshotId) +func GetSnapshotName(ctx context.Context, apiClient IaaSClient, projectId, region, snapshotId string) (string, error) { + resp, err := apiClient.GetSnapshotExecute(ctx, projectId, region, snapshotId) if err != nil { return "", fmt.Errorf("get snapshot: %w", err) } else if resp == nil { @@ -185,8 +222,8 @@ func GetSnapshotName(ctx context.Context, apiClient IaaSClient, projectId, snaps return *resp.Name, nil } -func GetBackupName(ctx context.Context, apiClient IaaSClient, projectId, backupId string) (string, error) { - resp, err := apiClient.GetBackupExecute(ctx, projectId, backupId) +func GetBackupName(ctx context.Context, apiClient IaaSClient, projectId, region, backupId string) (string, error) { + resp, err := apiClient.GetBackupExecute(ctx, projectId, region, backupId) if err != nil { return backupId, fmt.Errorf("get backup: %w", err) } diff --git a/internal/pkg/services/iaas/utils/utils_test.go b/internal/pkg/services/iaas/utils/utils_test.go index e2ccdc469..a8f530533 100644 --- a/internal/pkg/services/iaas/utils/utils_test.go +++ b/internal/pkg/services/iaas/utils/utils_test.go @@ -10,6 +10,8 @@ import ( "github.com/stackitcloud/stackit-sdk-go/services/iaas" ) +var _ IaaSClient = &IaaSClientMocked{} + type IaaSClientMocked struct { GetSecurityGroupRuleFails bool GetSecurityGroupRuleResp *iaas.SecurityGroupRule @@ -39,49 +41,49 @@ type IaaSClientMocked struct { GetSnapshotResp *iaas.Snapshot } -func (m *IaaSClientMocked) GetAffinityGroupExecute(_ context.Context, _, _ string) (*iaas.AffinityGroup, error) { +func (m *IaaSClientMocked) GetAffinityGroupExecute(_ context.Context, _, _, _ string) (*iaas.AffinityGroup, error) { if m.GetAffinityGroupsFails { return nil, fmt.Errorf("could not get affinity groups") } return m.GetAffinityGroupResp, nil } -func (m *IaaSClientMocked) GetSecurityGroupRuleExecute(_ context.Context, _, _, _ string) (*iaas.SecurityGroupRule, error) { +func (m *IaaSClientMocked) GetSecurityGroupRuleExecute(_ context.Context, _, _, _, _ string) (*iaas.SecurityGroupRule, error) { if m.GetSecurityGroupRuleFails { return nil, fmt.Errorf("could not get security group rule") } return m.GetSecurityGroupRuleResp, nil } -func (m *IaaSClientMocked) GetSecurityGroupExecute(_ context.Context, _, _ string) (*iaas.SecurityGroup, error) { +func (m *IaaSClientMocked) GetSecurityGroupExecute(_ context.Context, _, _, _ string) (*iaas.SecurityGroup, error) { if m.GetSecurityGroupFails { return nil, fmt.Errorf("could not get security group") } return m.GetSecurityGroupResp, nil } -func (m *IaaSClientMocked) GetPublicIPExecute(_ context.Context, _, _ string) (*iaas.PublicIp, error) { +func (m *IaaSClientMocked) GetPublicIPExecute(_ context.Context, _, _, _ string) (*iaas.PublicIp, error) { if m.GetPublicIpFails { return nil, fmt.Errorf("could not get public ip") } return m.GetPublicIpResp, nil } -func (m *IaaSClientMocked) GetServerExecute(_ context.Context, _, _ string) (*iaas.Server, error) { +func (m *IaaSClientMocked) GetServerExecute(_ context.Context, _, _, _ string) (*iaas.Server, error) { if m.GetServerFails { return nil, fmt.Errorf("could not get server") } return m.GetServerResp, nil } -func (m *IaaSClientMocked) GetVolumeExecute(_ context.Context, _, _ string) (*iaas.Volume, error) { +func (m *IaaSClientMocked) GetVolumeExecute(_ context.Context, _, _, _ string) (*iaas.Volume, error) { if m.GetVolumeFails { return nil, fmt.Errorf("could not get volume") } return m.GetVolumeResp, nil } -func (m *IaaSClientMocked) GetNetworkExecute(_ context.Context, _, _ string) (*iaas.Network, error) { +func (m *IaaSClientMocked) GetNetworkExecute(_ context.Context, _, _, _ string) (*iaas.Network, error) { if m.GetNetworkFails { return nil, fmt.Errorf("could not get network") } @@ -102,28 +104,28 @@ func (m *IaaSClientMocked) ListNetworkAreaProjectsExecute(_ context.Context, _, return m.GetAttachedProjectsResp, nil } -func (m *IaaSClientMocked) GetNetworkAreaRangeExecute(_ context.Context, _, _, _ string) (*iaas.NetworkRange, error) { +func (m *IaaSClientMocked) GetNetworkAreaRangeExecute(_ context.Context, _, _, _, _ string) (*iaas.NetworkRange, error) { if m.GetNetworkAreaRangeFails { return nil, fmt.Errorf("could not get network range") } return m.GetNetworkAreaRangeResp, nil } -func (m *IaaSClientMocked) GetImageExecute(_ context.Context, _, _ string) (*iaas.Image, error) { +func (m *IaaSClientMocked) GetImageExecute(_ context.Context, _, _, _ string) (*iaas.Image, error) { if m.GetImageFails { return nil, fmt.Errorf("could not get image") } return m.GetImageResp, nil } -func (m *IaaSClientMocked) GetBackupExecute(_ context.Context, _, _ string) (*iaas.Backup, error) { +func (m *IaaSClientMocked) GetBackupExecute(_ context.Context, _, _, _ string) (*iaas.Backup, error) { if m.GetBackupFails { return nil, fmt.Errorf("could not get backup") } return m.GetBackupResp, nil } -func (m *IaaSClientMocked) GetSnapshotExecute(_ context.Context, _, _ string) (*iaas.Snapshot, error) { +func (m *IaaSClientMocked) GetSnapshotExecute(_ context.Context, _, _, _ string) (*iaas.Snapshot, error) { if m.GetSnapshotFails { return nil, fmt.Errorf("could not get snapshot") } @@ -164,7 +166,7 @@ func TestGetSecurityGroupRuleName(t *testing.T) { GetSecurityGroupRuleFails: tt.args.getInstanceFails, GetSecurityGroupRuleResp: tt.args.getInstanceResp, } - got, err := GetSecurityGroupRuleName(context.Background(), m, "", "", "") + got, err := GetSecurityGroupRuleName(context.Background(), m, "", "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetSecurityGroupRuleName() error = %v, wantErr %v", err, tt.wantErr) return @@ -230,7 +232,7 @@ func TestGetSecurityGroupName(t *testing.T) { GetSecurityGroupFails: tt.args.getInstanceFails, GetSecurityGroupResp: tt.args.getInstanceResp, } - got, err := GetSecurityGroupName(context.Background(), m, "", "") + got, err := GetSecurityGroupName(context.Background(), m, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetSecurityGroupName() error = %v, wantErr %v", err, tt.wantErr) return @@ -279,7 +281,7 @@ func TestGetPublicIp(t *testing.T) { GetPublicIpFails: tt.args.getPublicIpFails, GetPublicIpResp: tt.args.getPublicIpResp, } - gotPublicIP, gotAssociatedResource, err := GetPublicIP(context.Background(), m, "", "") + gotPublicIP, gotAssociatedResource, err := GetPublicIP(context.Background(), m, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetPublicIP() error = %v, wantErr %v", err, tt.wantErr) return @@ -328,7 +330,7 @@ func TestGetServerName(t *testing.T) { GetServerFails: tt.args.getInstanceFails, GetServerResp: tt.args.getInstanceResp, } - got, err := GetServerName(context.Background(), m, "", "") + got, err := GetServerName(context.Background(), m, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetServerName() error = %v, wantErr %v", err, tt.wantErr) return @@ -394,7 +396,7 @@ func TestGetVolumeName(t *testing.T) { GetVolumeFails: tt.args.getInstanceFails, GetVolumeResp: tt.args.getInstanceResp, } - got, err := GetVolumeName(context.Background(), m, "", "") + got, err := GetVolumeName(context.Background(), m, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetVolumeName() error = %v, wantErr %v", err, tt.wantErr) return @@ -460,7 +462,7 @@ func TestGetNetworkName(t *testing.T) { GetNetworkFails: tt.args.getInstanceFails, GetNetworkResp: tt.args.getInstanceResp, } - got, err := GetNetworkName(context.Background(), m, "", "") + got, err := GetNetworkName(context.Background(), m, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetNetworkName() error = %v, wantErr %v", err, tt.wantErr) return @@ -619,7 +621,7 @@ func TestGetNetworkRangePrefix(t *testing.T) { GetNetworkAreaRangeFails: tt.args.getNetworkAreaRangeFails, GetNetworkAreaRangeResp: tt.args.getNetworkAreaRangeResp, } - got, err := GetNetworkRangePrefix(context.Background(), m, "", "", "") + got, err := GetNetworkRangePrefix(context.Background(), m, "", "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetNetworkRangePrefix() error = %v, wantErr %v", err, tt.wantErr) return @@ -650,22 +652,210 @@ func TestGetRouteFromAPIResponse(t *testing.T) { nexthop: "1.1.1.1", routes: &[]iaas.Route{ { - Prefix: utils.Ptr("1.1.1.0/24"), - Nexthop: utils.Ptr("1.1.1.1"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Type: utils.Ptr("cidrv4"), + Value: utils.Ptr("1.1.1.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Type: utils.Ptr("ipv4"), + Value: utils.Ptr("1.1.1.1"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Type: utils.Ptr("cidrv4"), + Value: utils.Ptr("2.2.2.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Type: utils.Ptr("ipv4"), + Value: utils.Ptr("2.2.2.2"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("3.3.3.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopBlackhole: &iaas.NexthopBlackhole{ + Type: utils.Ptr("blackhole"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("4.4.4.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopInternet: &iaas.NexthopInternet{ + Type: utils.Ptr("internet"), + }, + }, + }, + }, + }, + want: iaas.Route{ + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Type: utils.Ptr("cidrv4"), + Value: utils.Ptr("1.1.1.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Type: utils.Ptr("ipv4"), + Value: utils.Ptr("1.1.1.1"), + }, + }, + }, + }, + { + name: "nexthop internet", + args: args{ + prefix: "4.4.4.0/24", + nexthop: "internet", + routes: &[]iaas.Route{ + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("1.1.1.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Value: utils.Ptr("1.1.1.1"), + }, + }, }, { - Prefix: utils.Ptr("2.2.2.0/24"), - Nexthop: utils.Ptr("2.2.2.2"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("2.2.2.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Value: utils.Ptr("2.2.2.2"), + }, + }, }, { - Prefix: utils.Ptr("3.3.3.0/24"), - Nexthop: utils.Ptr("3.3.3.3"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("3.3.3.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopBlackhole: &iaas.NexthopBlackhole{ + Type: utils.Ptr("blackhole"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("4.4.4.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopInternet: &iaas.NexthopInternet{ + Type: utils.Ptr("internet"), + }, + }, }, }, }, want: iaas.Route{ - Prefix: utils.Ptr("1.1.1.0/24"), - Nexthop: utils.Ptr("1.1.1.1"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("4.4.4.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopInternet: &iaas.NexthopInternet{ + Type: utils.Ptr("internet"), + }, + }, + }, + }, + { + name: "nexthop backhole", + args: args{ + prefix: "3.3.3.0/24", + nexthop: "blackhole", + routes: &[]iaas.Route{ + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("1.1.1.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Value: utils.Ptr("1.1.1.1"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("2.2.2.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Value: utils.Ptr("2.2.2.2"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("3.3.3.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopBlackhole: &iaas.NexthopBlackhole{ + Type: utils.Ptr("blackhole"), + }, + }, + }, + { + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("4.4.4.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopInternet: &iaas.NexthopInternet{ + Type: utils.Ptr("internet"), + }, + }, + }, + }, + }, + want: iaas.Route{ + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("3.3.3.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopBlackhole: &iaas.NexthopBlackhole{ + Type: utils.Ptr("blackhole"), + }, + }, }, }, { @@ -675,12 +865,28 @@ func TestGetRouteFromAPIResponse(t *testing.T) { nexthop: "1.1.1.1", routes: &[]iaas.Route{ { - Prefix: utils.Ptr("2.2.2.0/24"), - Nexthop: utils.Ptr("2.2.2.2"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("2.2.2.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Value: utils.Ptr("2.2.2.2"), + }, + }, }, { - Prefix: utils.Ptr("3.3.3.0/24"), - Nexthop: utils.Ptr("3.3.3.3"), + Destination: &iaas.RouteDestination{ + DestinationCIDRv4: &iaas.DestinationCIDRv4{ + Value: utils.Ptr("3.3.3.0/24"), + }, + }, + Nexthop: &iaas.RouteNexthop{ + NexthopIPv4: &iaas.NexthopIPv4{ + Value: utils.Ptr("3.3.3.3"), + }, + }, }, }, }, @@ -819,7 +1025,7 @@ func TestGetImageName(t *testing.T) { GetImageFails: tt.imageErr, GetImageResp: tt.imageResp, } - got, err := GetImageName(context.Background(), client, "", "") + got, err := GetImageName(context.Background(), client, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetImageName() error = %v, wantErr %v", err, tt.wantErr) return @@ -876,7 +1082,7 @@ func TestGetAffinityGroupName(t *testing.T) { GetAffinityGroupsFails: tt.affinityErr, GetAffinityGroupResp: tt.affinityResp, } - got, err := GetAffinityGroupName(ctx, client, "", "") + got, err := GetAffinityGroupName(ctx, client, "", "", "") if (err != nil) != tt.wantErr { t.Errorf("GetAffinityGroupName() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/internal/pkg/utils/utils.go b/internal/pkg/utils/utils.go index 2a68bc14c..862b92c8f 100644 --- a/internal/pkg/utils/utils.go +++ b/internal/pkg/utils/utils.go @@ -168,29 +168,29 @@ func (b Base64Bytes) MarshalYAML() (interface{}, error) { } type Base64PatchedServer struct { - Id *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Status *string `json:"status,omitempty"` - AvailabilityZone *string `json:"availabilityZone,omitempty"` - BootVolume *iaas.CreateServerPayloadBootVolume `json:"bootVolume,omitempty"` - CreatedAt *time.Time `json:"createdAt,omitempty"` - ErrorMessage *string `json:"errorMessage,omitempty"` - PowerStatus *string `json:"powerStatus,omitempty"` - AffinityGroup *string `json:"affinityGroup,omitempty"` - ImageId *string `json:"imageId,omitempty"` - KeypairName *string `json:"keypairName,omitempty"` - MachineType *string `json:"machineType,omitempty"` - Labels *map[string]interface{} `json:"labels,omitempty"` - LaunchedAt *time.Time `json:"launchedAt,omitempty"` - MaintenanceWindow *iaas.ServerMaintenance `json:"maintenanceWindow,omitempty"` - Metadata *map[string]interface{} `json:"metadata,omitempty"` - Networking *iaas.CreateServerPayloadNetworking `json:"networking,omitempty"` - Nics *[]iaas.ServerNetwork `json:"nics,omitempty"` - SecurityGroups *[]string `json:"securityGroups,omitempty"` - ServiceAccountMails *[]string `json:"serviceAccountMails,omitempty"` - UpdatedAt *time.Time `json:"updatedAt,omitempty"` - UserData *Base64Bytes `json:"userData,omitempty"` - Volumes *[]string `json:"volumes,omitempty"` + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Status *string `json:"status,omitempty"` + AvailabilityZone *string `json:"availabilityZone,omitempty"` + BootVolume *iaas.ServerBootVolume `json:"bootVolume,omitempty"` + CreatedAt *time.Time `json:"createdAt,omitempty"` + ErrorMessage *string `json:"errorMessage,omitempty"` + PowerStatus *string `json:"powerStatus,omitempty"` + AffinityGroup *string `json:"affinityGroup,omitempty"` + ImageId *string `json:"imageId,omitempty"` + KeypairName *string `json:"keypairName,omitempty"` + MachineType *string `json:"machineType,omitempty"` + Labels *map[string]interface{} `json:"labels,omitempty"` + LaunchedAt *time.Time `json:"launchedAt,omitempty"` + MaintenanceWindow *iaas.ServerMaintenance `json:"maintenanceWindow,omitempty"` + Metadata *map[string]interface{} `json:"metadata,omitempty"` + Networking *iaas.ServerNetworking `json:"networking,omitempty"` + Nics *[]iaas.ServerNetwork `json:"nics,omitempty"` + SecurityGroups *[]string `json:"securityGroups,omitempty"` + ServiceAccountMails *[]string `json:"serviceAccountMails,omitempty"` + UpdatedAt *time.Time `json:"updatedAt,omitempty"` + UserData *Base64Bytes `json:"userData,omitempty"` + Volumes *[]string `json:"volumes,omitempty"` } // ConvertToBase64PatchedServer converts an iaas.Server to Base64PatchedServer