Skip to content

Commit f537f59

Browse files
committed
Onboard: Labels for network
Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>
1 parent 3dcaba4 commit f537f59

File tree

7 files changed

+108
-7
lines changed

7 files changed

+108
-7
lines changed

internal/cmd/beta/network/create/create.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const (
3535
nonRoutedFlag = "non-routed"
3636
noIpv4GatewayFlag = "no-ipv4-gateway"
3737
noIpv6GatewayFlag = "no-ipv6-gateway"
38+
labelFlag = "labels"
3839
)
3940

4041
type inputModel struct {
@@ -51,6 +52,7 @@ type inputModel struct {
5152
NonRouted bool
5253
NoIPv4Gateway bool
5354
NoIPv6Gateway bool
55+
Labels *map[string]string
5456
}
5557

5658
func NewCmd(p *print.Printer) *cobra.Command {
@@ -72,6 +74,10 @@ func NewCmd(p *print.Printer) *cobra.Command {
7274
`Create a network with name "network-1" and no gateway`,
7375
`$ stackit beta network create --name network-1 --no-ipv4-gateway`,
7476
),
77+
examples.NewExample(
78+
`Create a network with name "network-1" and labels "key=value,key1=value1"`,
79+
`$ stackit beta network create --name network-1 --labels key=value,key1=value1`,
80+
),
7581
examples.NewExample(
7682
`Create an IPv4 network with name "network-1" with DNS name servers, a prefix and a gateway`,
7783
`$ stackit beta 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"`,
@@ -149,6 +155,7 @@ func configureFlags(cmd *cobra.Command) {
149155
cmd.Flags().Bool(nonRoutedFlag, false, "If set to true, the network is not routed and therefore not accessible from other networks")
150156
cmd.Flags().Bool(noIpv4GatewayFlag, false, "If set to true, the network doesn't have an IPv4 gateway")
151157
cmd.Flags().Bool(noIpv6GatewayFlag, false, "If set to true, the network doesn't have an IPv6 gateway")
158+
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,...'")
152159

153160
err := flags.MarkFlagsRequired(cmd, nameFlag)
154161
cobra.CheckErr(err)
@@ -174,6 +181,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
174181
NonRouted: flags.FlagToBoolValue(p, cmd, nonRoutedFlag),
175182
NoIPv4Gateway: flags.FlagToBoolValue(p, cmd, noIpv4GatewayFlag),
176183
NoIPv6Gateway: flags.FlagToBoolValue(p, cmd, noIpv6GatewayFlag),
184+
Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag),
177185
}
178186

179187
if p.IsVerbosityDebug() {
@@ -220,13 +228,23 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli
220228
}
221229
}
222230

231+
var labelsMap *map[string]interface{}
232+
if model.Labels != nil && len(*model.Labels) > 0 {
233+
// convert map[string]string to map[string]interface{}
234+
labelsMap = utils.Ptr(map[string]interface{}{})
235+
for k, v := range *model.Labels {
236+
(*labelsMap)[k] = v
237+
}
238+
}
239+
223240
routed := true
224241
if model.NonRouted {
225242
routed = false
226243
}
227244

228245
payload := iaas.CreateNetworkPayload{
229246
Name: model.Name,
247+
Labels: labelsMap,
230248
Routed: &routed,
231249
}
232250

internal/cmd/beta/network/create/create_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st
3636
ipv6PrefixFlag: "2001:4860:4860::8888",
3737
ipv6GatewayFlag: "2001:4860:4860::8888",
3838
nonRoutedFlag: "false",
39+
labelFlag: "key=value",
3940
}
4041
for _, mod := range mods {
4142
mod(flagValues)
@@ -59,6 +60,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
5960
IPv6Prefix: utils.Ptr("2001:4860:4860::8888"),
6061
IPv6Gateway: utils.Ptr("2001:4860:4860::8888"),
6162
NonRouted: false,
63+
Labels: utils.Ptr(map[string]string{
64+
"key": "value",
65+
}),
6266
}
6367
for _, mod := range mods {
6468
mod(model)
@@ -91,6 +95,9 @@ func fixturePayload(mods ...func(payload *iaas.CreateNetworkPayload)) iaas.Creat
9195
payload := iaas.CreateNetworkPayload{
9296
Name: utils.Ptr("example-network-name"),
9397
Routed: utils.Ptr(true),
98+
Labels: utils.Ptr(map[string]interface{}{
99+
"key": "value",
100+
}),
94101
AddressFamily: &iaas.CreateNetworkAddressFamily{
95102
Ipv4: &iaas.CreateNetworkIPv4Body{
96103
Nameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}),
@@ -236,6 +243,16 @@ func TestParseInput(t *testing.T) {
236243
model.NonRouted = true
237244
}),
238245
},
246+
{
247+
description: "labels missing",
248+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
249+
delete(flagValues, labelFlag)
250+
}),
251+
expectedModel: fixtureInputModel(func(model *inputModel) {
252+
model.Labels = nil
253+
}),
254+
isValid: true,
255+
},
239256
}
240257

241258
for _, tt := range tests {

internal/cmd/beta/network/describe/describe.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ func outputResult(p *print.Printer, outputFormat string, network *iaas.Network)
190190
table.AddRow("IPv6 PREFIXES", strings.Join(ipv6prefixes, ", "))
191191
}
192192
table.AddSeparator()
193+
if network.Labels != nil && len(*network.Labels) > 0 {
194+
var labels []string
195+
for key, value := range *network.Labels {
196+
labels = append(labels, fmt.Sprintf("%s: %s", key, value))
197+
}
198+
table.AddRow("LABELS", strings.Join(labels, "\n"))
199+
table.AddSeparator()
200+
}
193201

194202
err := table.Display(p)
195203
if err != nil {

internal/cmd/beta/network/list/list.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ import (
2222
)
2323

2424
const (
25-
limitFlag = "limit"
25+
limitFlag = "limit"
26+
labelSelectorFlag = "label-selector"
2627
)
2728

2829
type inputModel struct {
2930
*globalflags.GlobalFlagModel
30-
Limit *int64
31+
Limit *int64
32+
LabelSelector *string
3133
}
3234

3335
func NewCmd(p *print.Printer) *cobra.Command {
@@ -49,6 +51,10 @@ func NewCmd(p *print.Printer) *cobra.Command {
4951
`Lists up to 10 networks`,
5052
"$ stackit beta network list --limit 10",
5153
),
54+
examples.NewExample(
55+
`Lists all networks which contains the label xxx`,
56+
"$ tackit beta network list --label-selector xxx",
57+
),
5258
),
5359
RunE: func(cmd *cobra.Command, _ []string) error {
5460
ctx := context.Background()
@@ -97,6 +103,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
97103

98104
func configureFlags(cmd *cobra.Command) {
99105
cmd.Flags().Int64(limitFlag, 0, "Maximum number of entries to list")
106+
cmd.Flags().String(labelSelectorFlag, "", "Filter by label")
100107
}
101108

102109
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
@@ -116,6 +123,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
116123
model := inputModel{
117124
GlobalFlagModel: globalFlags,
118125
Limit: limit,
126+
LabelSelector: flags.FlagToStringPointer(p, cmd, labelSelectorFlag),
119127
}
120128

121129
if p.IsVerbosityDebug() {
@@ -131,7 +139,11 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
131139
}
132140

133141
func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworksRequest {
134-
return apiClient.ListNetworks(ctx, model.ProjectId)
142+
req := apiClient.ListNetworks(ctx, model.ProjectId)
143+
if model.LabelSelector != nil {
144+
req = req.LabelSelector(*model.LabelSelector)
145+
}
146+
return req
135147
}
136148

137149
func outputResult(p *print.Printer, outputFormat string, networks []iaas.Network) error {

internal/cmd/beta/network/list/list_test.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ type testCtxKey struct{}
2121
var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo")
2222
var testClient = &iaas.APIClient{}
2323
var testProjectId = uuid.NewString()
24+
var testLabelSelector = "foo=bar"
2425

2526
func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
2627
flagValues := map[string]string{
27-
projectIdFlag: testProjectId,
28-
limitFlag: "10",
28+
projectIdFlag: testProjectId,
29+
limitFlag: "10",
30+
labelSelectorFlag: testLabelSelector,
2931
}
3032
for _, mod := range mods {
3133
mod(flagValues)
@@ -39,7 +41,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
3941
Verbosity: globalflags.VerbosityDefault,
4042
ProjectId: testProjectId,
4143
},
42-
Limit: utils.Ptr(int64(10)),
44+
Limit: utils.Ptr(int64(10)),
45+
LabelSelector: utils.Ptr(testLabelSelector),
4346
}
4447
for _, mod := range mods {
4548
mod(model)
@@ -49,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
4952

5053
func fixtureRequest(mods ...func(request *iaas.ApiListNetworksRequest)) iaas.ApiListNetworksRequest {
5154
request := testClient.ListNetworks(testCtx, testProjectId)
55+
request = request.LabelSelector(testLabelSelector)
5256
for _, mod := range mods {
5357
mod(&request)
5458
}
@@ -113,6 +117,16 @@ func TestParseInput(t *testing.T) {
113117
}),
114118
isValid: false,
115119
},
120+
{
121+
description: "label selector empty",
122+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
123+
flagValues[labelSelectorFlag] = ""
124+
}),
125+
isValid: true,
126+
expectedModel: fixtureInputModel(func(inputModel *inputModel) {
127+
inputModel.LabelSelector = utils.Ptr("")
128+
}),
129+
},
116130
}
117131

118132
for _, tt := range tests {

internal/cmd/beta/network/update/update.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
ipv6GatewayFlag = "ipv6-gateway"
3131
noIpv4GatewayFlag = "no-ipv4-gateway"
3232
noIpv6GatewayFlag = "no-ipv6-gateway"
33+
labelFlag = "labels"
3334
)
3435

3536
type inputModel struct {
@@ -42,6 +43,7 @@ type inputModel struct {
4243
IPv6Gateway *string
4344
NoIPv4Gateway bool
4445
NoIPv6Gateway bool
46+
Labels *map[string]string
4547
}
4648

4749
func NewCmd(p *print.Printer) *cobra.Command {
@@ -136,6 +138,7 @@ func configureFlags(cmd *cobra.Command) {
136138
cmd.Flags().String(ipv6GatewayFlag, "", "The IPv6 gateway of a network. If not specified, the first IP of the network will be assigned as the gateway")
137139
cmd.Flags().Bool(noIpv4GatewayFlag, false, "If set to true, the network doesn't have an IPv4 gateway")
138140
cmd.Flags().Bool(noIpv6GatewayFlag, false, "If set to true, the network doesn't have an IPv6 gateway")
141+
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,...'")
139142
}
140143

141144
func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
@@ -156,6 +159,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu
156159
IPv6Gateway: flags.FlagToStringPointer(p, cmd, ipv6GatewayFlag),
157160
NoIPv4Gateway: flags.FlagToBoolValue(p, cmd, noIpv4GatewayFlag),
158161
NoIPv6Gateway: flags.FlagToBoolValue(p, cmd, noIpv6GatewayFlag),
162+
Labels: flags.FlagToStringToStringPointer(p, cmd, labelFlag),
159163
}
160164

161165
if p.IsVerbosityDebug() {
@@ -174,6 +178,15 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli
174178
req := apiClient.PartialUpdateNetwork(ctx, model.ProjectId, model.NetworkId)
175179
addressFamily := &iaas.UpdateNetworkAddressFamily{}
176180

181+
var labelsMap *map[string]interface{}
182+
if model.Labels != nil && len(*model.Labels) > 0 {
183+
// convert map[string]string to map[string]interface{}
184+
labelsMap = utils.Ptr(map[string]interface{}{})
185+
for k, v := range *model.Labels {
186+
(*labelsMap)[k] = v
187+
}
188+
}
189+
177190
if model.IPv6DnsNameServers != nil || model.NoIPv6Gateway || model.IPv6Gateway != nil {
178191
addressFamily.Ipv6 = &iaas.UpdateNetworkIPv6Body{
179192
Nameservers: model.IPv6DnsNameServers,
@@ -199,7 +212,8 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli
199212
}
200213

201214
payload := iaas.PartialUpdateNetworkPayload{
202-
Name: model.Name,
215+
Name: model.Name,
216+
Labels: labelsMap,
203217
}
204218

205219
if addressFamily.Ipv4 != nil || addressFamily.Ipv6 != nil {

internal/cmd/beta/network/update/update_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st
4242
ipv4GatewayFlag: "10.1.2.3",
4343
ipv6DnsNameServersFlag: "2001:4860:4860::8888,2001:4860:4860::8844",
4444
ipv6GatewayFlag: "2001:4860:4860::8888",
45+
labelFlag: "key=value",
4546
}
4647
for _, mod := range mods {
4748
mod(flagValues)
@@ -61,6 +62,9 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
6162
IPv4Gateway: utils.Ptr("10.1.2.3"),
6263
IPv6DnsNameServers: utils.Ptr([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"}),
6364
IPv6Gateway: utils.Ptr("2001:4860:4860::8888"),
65+
Labels: utils.Ptr(map[string]string{
66+
"key": "value",
67+
}),
6468
}
6569
for _, mod := range mods {
6670
mod(model)
@@ -80,6 +84,9 @@ func fixtureRequest(mods ...func(request *iaas.ApiPartialUpdateNetworkRequest))
8084
func fixturePayload(mods ...func(payload *iaas.PartialUpdateNetworkPayload)) iaas.PartialUpdateNetworkPayload {
8185
payload := iaas.PartialUpdateNetworkPayload{
8286
Name: utils.Ptr("example-network-name"),
87+
Labels: utils.Ptr(map[string]interface{}{
88+
"key": "value",
89+
}),
8390
AddressFamily: &iaas.UpdateNetworkAddressFamily{
8491
Ipv4: &iaas.UpdateNetworkIPv4Body{
8592
Nameservers: utils.Ptr([]string{"1.1.1.0", "1.1.2.0"}),
@@ -218,6 +225,17 @@ func TestParseInput(t *testing.T) {
218225
model.IPv6Gateway = nil
219226
}),
220227
},
228+
{
229+
description: "labels missing",
230+
argValues: fixtureArgValues(),
231+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
232+
delete(flagValues, labelFlag)
233+
}),
234+
expectedModel: fixtureInputModel(func(model *inputModel) {
235+
model.Labels = nil
236+
}),
237+
isValid: true,
238+
},
221239
}
222240

223241
for _, tt := range tests {

0 commit comments

Comments
 (0)