Skip to content

Commit 9ba0896

Browse files
authored
feat: Onboard affinity-group command (#594)
* Onboard affinity-group command - create - delete AFFINITY_GROUP_ID - describe AFFINITY_GROUP_ID - list * Add `yaml.UseJSONMarshaler()` to `yaml.MarshalWithOptions()`` calls
1 parent 8479ad9 commit 9ba0896

18 files changed

+1689
-1
lines changed

docs/stackit_beta.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ stackit beta [flags]
4141
### SEE ALSO
4242

4343
* [stackit](./stackit.md) - Manage STACKIT resources using the command line
44+
* [stackit beta affinity-group](./stackit_beta_affinity-group.md) - Manage server affinity groups
4445
* [stackit beta image](./stackit_beta_image.md) - Manage server images
4546
* [stackit beta key-pair](./stackit_beta_key-pair.md) - Provides functionality for SSH key pairs
4647
* [stackit beta network](./stackit_beta_network.md) - Provides functionality for networks

docs/stackit_beta_affinity-group.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## stackit beta affinity-group
2+
3+
Manage server affinity groups
4+
5+
### Synopsis
6+
7+
Manage the lifecycle of server affinity groups.
8+
9+
```
10+
stackit beta affinity-group [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
-h, --help Help for "stackit beta affinity-group"
17+
```
18+
19+
### Options inherited from parent commands
20+
21+
```
22+
-y, --assume-yes If set, skips all confirmation prompts
23+
--async If set, runs the command asynchronously
24+
-o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"]
25+
-p, --project-id string Project ID
26+
--region string Target region for region-specific requests
27+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
28+
```
29+
30+
### SEE ALSO
31+
32+
* [stackit beta](./stackit_beta.md) - Contains beta STACKIT CLI commands
33+
* [stackit beta affinity-group create](./stackit_beta_affinity-group_create.md) - Creates an affinity groups
34+
* [stackit beta affinity-group delete](./stackit_beta_affinity-group_delete.md) - Deletes an affinity group
35+
* [stackit beta affinity-group describe](./stackit_beta_affinity-group_describe.md) - Show details of an affinity group
36+
* [stackit beta affinity-group list](./stackit_beta_affinity-group_list.md) - Lists affinity groups
37+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## stackit beta affinity-group create
2+
3+
Creates an affinity groups
4+
5+
### Synopsis
6+
7+
Creates an affinity groups.
8+
9+
```
10+
stackit beta affinity-group create [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Create an affinity group with name "AFFINITY_GROUP_NAME" and policy "soft-affinity"
17+
$ stackit beta affinity-group create --name AFFINITY_GROUP_NAME --policy soft-affinity
18+
```
19+
20+
### Options
21+
22+
```
23+
-h, --help Help for "stackit beta affinity-group create"
24+
--name string The name of the affinity group.
25+
--policy string The policy for the affinity group. Valid values for the policy are: "hard-affinity", "hard-anti-affinity", "soft-affinity", "soft-anti-affinity"
26+
```
27+
28+
### Options inherited from parent commands
29+
30+
```
31+
-y, --assume-yes If set, skips all confirmation prompts
32+
--async If set, runs the command asynchronously
33+
-o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"]
34+
-p, --project-id string Project ID
35+
--region string Target region for region-specific requests
36+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
37+
```
38+
39+
### SEE ALSO
40+
41+
* [stackit beta affinity-group](./stackit_beta_affinity-group.md) - Manage server affinity groups
42+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## stackit beta affinity-group delete
2+
3+
Deletes an affinity group
4+
5+
### Synopsis
6+
7+
Deletes an affinity group.
8+
9+
```
10+
stackit beta affinity-group delete AFFINITY_GROUP [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Delete an affinity group with ID "xxx"
17+
$ stackit beta affinity-group delete xxx
18+
```
19+
20+
### Options
21+
22+
```
23+
-h, --help Help for "stackit beta affinity-group delete"
24+
```
25+
26+
### Options inherited from parent commands
27+
28+
```
29+
-y, --assume-yes If set, skips all confirmation prompts
30+
--async If set, runs the command asynchronously
31+
-o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"]
32+
-p, --project-id string Project ID
33+
--region string Target region for region-specific requests
34+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
35+
```
36+
37+
### SEE ALSO
38+
39+
* [stackit beta affinity-group](./stackit_beta_affinity-group.md) - Manage server affinity groups
40+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## stackit beta affinity-group describe
2+
3+
Show details of an affinity group
4+
5+
### Synopsis
6+
7+
Show details of an affinity group.
8+
9+
```
10+
stackit beta affinity-group describe AFFINITY_GROUP_ID [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Get details about an affinity group with the ID "xxx"
17+
$ stackit beta affinity-group describe xxx
18+
```
19+
20+
### Options
21+
22+
```
23+
-h, --help Help for "stackit beta affinity-group describe"
24+
```
25+
26+
### Options inherited from parent commands
27+
28+
```
29+
-y, --assume-yes If set, skips all confirmation prompts
30+
--async If set, runs the command asynchronously
31+
-o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"]
32+
-p, --project-id string Project ID
33+
--region string Target region for region-specific requests
34+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
35+
```
36+
37+
### SEE ALSO
38+
39+
* [stackit beta affinity-group](./stackit_beta_affinity-group.md) - Manage server affinity groups
40+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## stackit beta affinity-group list
2+
3+
Lists affinity groups
4+
5+
### Synopsis
6+
7+
Lists affinity groups.
8+
9+
```
10+
stackit beta affinity-group list [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Lists all affinity groups
17+
$ stackit beta affinity-group list
18+
19+
Lists up to 10 affinity groups
20+
$ stackit beta affinity-group list --limit=10
21+
```
22+
23+
### Options
24+
25+
```
26+
-h, --help Help for "stackit beta affinity-group list"
27+
--limit int Limit the output to the first n elements
28+
```
29+
30+
### Options inherited from parent commands
31+
32+
```
33+
-y, --assume-yes If set, skips all confirmation prompts
34+
--async If set, runs the command asynchronously
35+
-o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"]
36+
-p, --project-id string Project ID
37+
--region string Target region for region-specific requests
38+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
39+
```
40+
41+
### SEE ALSO
42+
43+
* [stackit beta affinity-group](./stackit_beta_affinity-group.md) - Manage server affinity groups
44+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package affinity_groups
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/affinity-groups/create"
6+
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/affinity-groups/delete"
7+
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/affinity-groups/describe"
8+
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/affinity-groups/list"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
12+
)
13+
14+
func NewCmd(p *print.Printer) *cobra.Command {
15+
cmd := &cobra.Command{
16+
Use: "affinity-group",
17+
Short: "Manage server affinity groups",
18+
Long: "Manage the lifecycle of server affinity groups.",
19+
Args: args.NoArgs,
20+
Run: utils.CmdHelp,
21+
}
22+
addSubcommands(cmd, p)
23+
return cmd
24+
}
25+
26+
func addSubcommands(cmd *cobra.Command, p *print.Printer) {
27+
cmd.AddCommand(
28+
create.NewCmd(p),
29+
delete.NewCmd(p),
30+
describe.NewCmd(p),
31+
list.NewCmd(p),
32+
)
33+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package create
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
8+
"github.com/goccy/go-yaml"
9+
"github.com/spf13/cobra"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
12+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
13+
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
14+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
15+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
16+
"github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client"
17+
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
18+
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
19+
)
20+
21+
const (
22+
nameFlag = "name"
23+
policyFlag = "policy"
24+
)
25+
26+
type inputModel struct {
27+
*globalflags.GlobalFlagModel
28+
Name string
29+
Policy string
30+
}
31+
32+
func NewCmd(p *print.Printer) *cobra.Command {
33+
cmd := &cobra.Command{
34+
Use: "create",
35+
Short: "Creates an affinity groups",
36+
Long: `Creates an affinity groups.`,
37+
Args: args.NoArgs,
38+
Example: examples.Build(
39+
examples.NewExample(
40+
`Create an affinity group with name "AFFINITY_GROUP_NAME" and policy "soft-affinity"`,
41+
"$ stackit beta affinity-group create --name AFFINITY_GROUP_NAME --policy soft-affinity",
42+
),
43+
),
44+
RunE: func(cmd *cobra.Command, _ []string) error {
45+
ctx := context.Background()
46+
model, err := parseInput(p, cmd)
47+
if err != nil {
48+
return err
49+
}
50+
51+
// Configure API client
52+
apiClient, err := client.ConfigureClient(p)
53+
if err != nil {
54+
return err
55+
}
56+
57+
if !model.AssumeYes {
58+
prompt := fmt.Sprintf("Are you sure you want to create the affinity group %q?", model.Name)
59+
err = p.PromptForConfirmation(prompt)
60+
if err != nil {
61+
return err
62+
}
63+
}
64+
65+
// Call API
66+
request := buildRequest(ctx, *model, apiClient)
67+
68+
result, err := request.Execute()
69+
if err != nil {
70+
return fmt.Errorf("create affinity group: %w", err)
71+
}
72+
if resp := result; resp != nil {
73+
return outputResult(p, *model, *resp)
74+
}
75+
return fmt.Errorf("create affinity group: nil result")
76+
},
77+
}
78+
configureFlags(cmd)
79+
return cmd
80+
}
81+
82+
func configureFlags(cmd *cobra.Command) {
83+
cmd.Flags().String(nameFlag, "", "The name of the affinity group.")
84+
cmd.Flags().String(policyFlag, "", `The policy for the affinity group. Valid values for the policy are: "hard-affinity", "hard-anti-affinity", "soft-affinity", "soft-anti-affinity"`)
85+
86+
if err := flags.MarkFlagsRequired(cmd, nameFlag, policyFlag); err != nil {
87+
cobra.CheckErr(err)
88+
}
89+
}
90+
91+
func buildRequest(ctx context.Context, model inputModel, apiClient *iaas.APIClient) iaas.ApiCreateAffinityGroupRequest {
92+
req := apiClient.CreateAffinityGroup(ctx, model.ProjectId)
93+
req = req.CreateAffinityGroupPayload(
94+
iaas.CreateAffinityGroupPayload{
95+
Name: utils.Ptr(model.Name),
96+
Policy: utils.Ptr(model.Policy),
97+
},
98+
)
99+
return req
100+
}
101+
102+
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
103+
globalFlags := globalflags.Parse(p, cmd)
104+
if globalFlags.ProjectId == "" {
105+
return nil, &errors.ProjectIdError{}
106+
}
107+
108+
model := inputModel{
109+
GlobalFlagModel: globalFlags,
110+
Name: flags.FlagToStringValue(p, cmd, nameFlag),
111+
Policy: flags.FlagToStringValue(p, cmd, policyFlag),
112+
}
113+
114+
if p.IsVerbosityDebug() {
115+
modelStr, err := print.BuildDebugStrFromInputModel(model)
116+
if err != nil {
117+
p.Debug(print.ErrorLevel, "convert model to string for debugging: %v", err)
118+
} else {
119+
p.Debug(print.DebugLevel, "parsed input values: %s", modelStr)
120+
}
121+
}
122+
123+
return &model, nil
124+
}
125+
126+
func outputResult(p *print.Printer, model inputModel, resp iaas.AffinityGroup) error {
127+
outputFormat := ""
128+
if model.GlobalFlagModel != nil {
129+
outputFormat = model.GlobalFlagModel.OutputFormat
130+
}
131+
switch outputFormat {
132+
case print.JSONOutputFormat:
133+
details, err := json.MarshalIndent(resp, "", " ")
134+
if err != nil {
135+
return fmt.Errorf("marshal affinity group: %w", err)
136+
}
137+
p.Outputln(string(details))
138+
case print.YAMLOutputFormat:
139+
details, err := yaml.MarshalWithOptions(resp, yaml.IndentSequence(true), yaml.UseJSONMarshaler())
140+
if err != nil {
141+
return fmt.Errorf("marshal affinity group: %w", err)
142+
}
143+
p.Outputln(string(details))
144+
default:
145+
p.Outputf("Created affinity group %q with id %s\n", model.Name, utils.PtrString(resp.Id))
146+
}
147+
return nil
148+
}

0 commit comments

Comments
 (0)