Skip to content

Commit 1a0ae0b

Browse files
committed
add key-pair commands:
- create - delete - describe - list - update
1 parent c715b0a commit 1a0ae0b

File tree

7 files changed

+768
-1
lines changed

7 files changed

+768
-1
lines changed

internal/cmd/beta/beta.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package beta
22

33
import (
44
"fmt"
5-
5+
keypair "github.com/stackitcloud/stackit-cli/internal/cmd/beta/key-pair"
66
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/network"
77
networkArea "github.com/stackitcloud/stackit-cli/internal/cmd/beta/network-area"
88
networkinterface "github.com/stackitcloud/stackit-cli/internal/cmd/beta/network-interface"
@@ -48,4 +48,5 @@ func addSubcommands(cmd *cobra.Command, p *print.Printer) {
4848
cmd.AddCommand(volume.NewCmd(p))
4949
cmd.AddCommand(networkinterface.NewCmd(p))
5050
cmd.AddCommand(publicip.NewCmd(p))
51+
cmd.AddCommand(keypair.NewCmd(p))
5152
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package create
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client"
12+
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
13+
14+
"github.com/goccy/go-yaml"
15+
"github.com/spf13/cobra"
16+
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
17+
)
18+
19+
const (
20+
nameFlag = "name"
21+
publicKeyFlag = "public-key"
22+
labelFlag = "labels"
23+
)
24+
25+
type inputModel struct {
26+
*globalflags.GlobalFlagModel
27+
Name *string
28+
PublicKey *string
29+
Labels *map[string]string
30+
}
31+
32+
func NewCmd(p *print.Printer) *cobra.Command {
33+
cmd := &cobra.Command{
34+
Use: "create",
35+
Short: "Create a keypair",
36+
Long: "Create a keypair.",
37+
Args: cobra.NoArgs,
38+
Example: examples.Build(
39+
examples.NewExample(
40+
`Create a new key-pair with public-key "ssh-rsa xxx"`,
41+
"$ stackit beta key-pair create --public-key ssh-rsa xxx",
42+
),
43+
examples.NewExample(
44+
`Create a new key-pair with public-key from file "/Users/username/.ssh/id_rsa.pub"`,
45+
"$ stackit beta key-pair create --public-key @/Users/username/.ssh/id_rsa.pub",
46+
),
47+
examples.NewExample(
48+
`Create a new key-pair with name "KEYPAIR_NAME" and public-key "ssh-rsa yyy"`,
49+
"$ stackit beta key-pair create --name KEYPAIR_NAME --public-key ssh-rsa yyy",
50+
),
51+
examples.NewExample(
52+
`Create a new key-pair with public-key "ssh-rsa xxx" and labels "key=value,key1=value1"`,
53+
"$ stackit beta key-pair create --public-key ssh-rsa xxx --labels key=value,key1=value1",
54+
),
55+
),
56+
RunE: func(cmd *cobra.Command, args []string) error {
57+
ctx := context.Background()
58+
model, err := parseInput(p, cmd)
59+
if err != nil {
60+
return err
61+
}
62+
63+
// Configure client
64+
apiClient, err := client.ConfigureClient(p)
65+
if err != nil {
66+
return err
67+
}
68+
69+
if !model.AssumeYes {
70+
prompt := fmt.Sprintf("Are your sure you want to create a keypair")
71+
err = p.PromptForConfirmation(prompt)
72+
if err != nil {
73+
return err
74+
}
75+
}
76+
77+
// Call API
78+
req := buildRequest(ctx, model, apiClient)
79+
resp, err := req.Execute()
80+
if err != nil {
81+
return fmt.Errorf("create keypair: %w", err)
82+
}
83+
84+
return outputResult(p, model, resp)
85+
},
86+
}
87+
configureFlags(cmd)
88+
return cmd
89+
}
90+
91+
func configureFlags(cmd *cobra.Command) {
92+
cmd.Flags().String(nameFlag, "", "Name of the key which will be created")
93+
cmd.Flags().Var(flags.ReadFromFileFlag(), publicKeyFlag, "Public key which should be add (format: ssh-rsa|sha-ed25519)")
94+
cmd.Flags().StringToString(labelFlag, nil, "Labels are key-value string pairs which can be attached to a server. E.g. '--labels key1=value1,key2=value2,...'")
95+
96+
err := cmd.MarkFlagRequired(publicKeyFlag)
97+
cobra.CheckErr(err)
98+
}
99+
100+
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
101+
globalFlags := globalflags.Parse(p, cmd)
102+
103+
model := inputModel{
104+
GlobalFlagModel: globalFlags,
105+
Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag),
106+
Name: flags.FlagToStringPointer(p, cmd, nameFlag),
107+
PublicKey: flags.FlagToStringPointer(p, cmd, publicKeyFlag),
108+
}
109+
110+
if p.IsVerbosityDebug() {
111+
modelStr, err := print.BuildDebugStrFromInputModel(model)
112+
if err != nil {
113+
p.Debug(print.ErrorLevel, "convert model to string fo debugging: %v", err)
114+
} else {
115+
p.Debug(print.DebugLevel, "parsed input values: %s", modelStr)
116+
}
117+
}
118+
119+
return &model, nil
120+
}
121+
122+
func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiCreateKeyPairRequest {
123+
req := apiClient.CreateKeyPair(ctx)
124+
125+
var labelsMap *map[string]interface{}
126+
if model.Labels != nil && len(*model.Labels) > 0 {
127+
// convert map[string]string to map[string]interface{}
128+
labelsMap = utils.Ptr(map[string]interface{}{})
129+
for k, v := range *model.Labels {
130+
(*labelsMap)[k] = v
131+
}
132+
}
133+
134+
payload := iaas.CreateKeyPairPayload{
135+
Name: model.Name,
136+
Labels: labelsMap,
137+
PublicKey: model.PublicKey,
138+
}
139+
140+
return req.CreateKeyPairPayload(payload)
141+
}
142+
143+
func outputResult(p *print.Printer, model *inputModel, item *iaas.Keypair) error {
144+
switch model.OutputFormat {
145+
case print.JSONOutputFormat:
146+
details, err := json.MarshalIndent(item, "", " ")
147+
if err != nil {
148+
return fmt.Errorf("marshal keypair: %w", err)
149+
}
150+
p.Outputln(string(details))
151+
case print.YAMLOutputFormat:
152+
details, err := yaml.MarshalWithOptions(item, yaml.IndentSequence(true))
153+
if err != nil {
154+
return fmt.Errorf("marshal keypair: %w", err)
155+
}
156+
p.Outputln(string(details))
157+
default:
158+
p.Outputf("Created keypair %q.\nKeypair Fingerprint: %q\n", *item.Name, *item.Fingerprint)
159+
}
160+
return nil
161+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package delete
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/spf13/cobra"
7+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client"
12+
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
13+
)
14+
15+
const (
16+
keypairNameArg = "KEYPAIR_NAME"
17+
)
18+
19+
type inputModel struct {
20+
*globalflags.GlobalFlagModel
21+
KeypairName string
22+
}
23+
24+
func NewCmd(p *print.Printer) *cobra.Command {
25+
cmd := &cobra.Command{
26+
Use: "delete",
27+
Short: "Delete a keypair",
28+
Long: "Delete a keypair.",
29+
Args: args.SingleArg(keypairNameArg, nil),
30+
Example: examples.Build(
31+
examples.NewExample(
32+
`Delete keypair with name "XXX"`,
33+
"$ stackit beta keypair delete XXX",
34+
),
35+
),
36+
RunE: func(cmd *cobra.Command, args []string) error {
37+
ctx := context.Background()
38+
model, err := parseInput(p, cmd, args)
39+
if err != nil {
40+
return err
41+
}
42+
43+
// Configure API client
44+
apiClient, err := client.ConfigureClient(p)
45+
if err != nil {
46+
return err
47+
}
48+
49+
if !model.AssumeYes {
50+
prompt := fmt.Sprintf("Are you sure you want to delete keypair %q?", model.KeypairName)
51+
err = p.PromptForConfirmation(prompt)
52+
if err != nil {
53+
return err
54+
}
55+
}
56+
57+
// Call API
58+
req := buildRequest(ctx, model, apiClient)
59+
err = req.Execute()
60+
if err != nil {
61+
return fmt.Errorf("delete keypair: %w", err)
62+
}
63+
64+
p.Info("Deleted keypair %q\n", model.KeypairName)
65+
66+
return nil
67+
},
68+
}
69+
return cmd
70+
}
71+
72+
func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
73+
keypairName := inputArgs[0]
74+
75+
globalFlags := globalflags.Parse(p, cmd)
76+
77+
model := inputModel{
78+
GlobalFlagModel: globalFlags,
79+
KeypairName: keypairName,
80+
}
81+
82+
if p.IsVerbosityDebug() {
83+
modelStr, err := print.BuildDebugStrFromInputModel(model)
84+
if err != nil {
85+
p.Debug(print.ErrorLevel, "convert model to string for debugging: %v", err)
86+
} else {
87+
p.Debug(print.DebugLevel, "parsed input values: %s", modelStr)
88+
}
89+
}
90+
91+
return &model, nil
92+
}
93+
94+
func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiDeleteKeyPairRequest {
95+
return apiClient.DeleteKeyPair(ctx, model.KeypairName)
96+
}

0 commit comments

Comments
 (0)