Skip to content

Commit 4fd0cb6

Browse files
authored
Add custom tags to machines (#158)
* Add custom tags to machines * Add test cases * Revive add tags * Revive tags * Address reviews * Remove default description * Add kustomize when running e2e
1 parent aacb59c commit 4fd0cb6

13 files changed

+168
-7
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ e2e-image:
313313
docker build --tag="$(REPOSITORY):e2e" .
314314

315315
.PHONY: test-e2e
316-
test-e2e: $(ENVSUBST) $(KUBECTL) $(GINKGO) e2e-image ## Run the end-to-end tests
316+
test-e2e: $(ENVSUBST) $(KUBECTL) $(GINKGO) kustomize e2e-image ## Run the end-to-end tests
317317
$(ENVSUBST) < $(E2E_CONF_FILE) > $(E2E_CONF_FILE_ENVSUBST) && \
318318
time $(GINKGO) -v --trace -poll-progress-after=$(GINKGO_POLL_PROGRESS_AFTER) -poll-progress-interval=$(GINKGO_POLL_PROGRESS_INTERVAL) \
319319
--tags=e2e --focus="$(GINKGO_FOCUS)" -skip="$(GINKGO_SKIP)" --nodes=$(GINKGO_NODES) --no-color=$(GINKGO_NOCOLOR) \

api/v1alpha1/proxmoxmachine_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ type ProxmoxMachineSpec struct {
123123
// If not set, the ProxmoxCluster will be used to determine the nodes.
124124
// +optional
125125
AllowedNodes []string `json:"allowedNodes,omitempty"`
126+
127+
// Tags is a list of tags to be applied to the virtual machine.
128+
// +optional
129+
// +immutable
130+
// +listType=set
131+
// +kubebuilder:validation:MinItems=1
132+
// +kubebuilder:validation:items:Pattern=`^(?i)[a-z0-9_][a-z0-9_\-\+\.]*$`
133+
Tags []string `json:"tags,omitempty"`
126134
}
127135

128136
// Storage is the physical storage on the node.

api/v1alpha1/proxmoxmachine_types_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,4 +404,32 @@ var _ = Describe("ProxmoxMachine Test", func() {
404404
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("spec.vmIDRange.start in body should be greater than or equal to 100")))
405405
})
406406
})
407+
408+
Context("Tags", func() {
409+
It("should disallow invalid tags", func() {
410+
dm := defaultMachine()
411+
dm.Spec.Tags = []string{"foo=bar"}
412+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("Invalid value")))
413+
414+
dm.Spec.Tags = []string{"foo$bar"}
415+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("Invalid value")))
416+
417+
dm.Spec.Tags = []string{"foo^bar"}
418+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("Invalid value")))
419+
420+
dm.Spec.Tags = []string{"foo bar"}
421+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("Invalid value")))
422+
423+
dm.Spec.Tags = []string{"foo "}
424+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("Invalid value")))
425+
})
426+
427+
It("Should not allow duplicated tags", func() {
428+
dm := defaultMachine()
429+
dm.Spec.Tags = []string{"foo", "bar", "foo"}
430+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("Duplicate value")))
431+
dm.Spec.Tags = []string{"foo", "bar"}
432+
Expect(k8sClient.Create(context.Background(), dm)).To(Succeed())
433+
})
434+
})
407435
})

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxclusters.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,15 @@ spec:
558558
storage:
559559
description: Storage for full clone.
560560
type: string
561+
tags:
562+
description: Tags is a list of tags to be applied to the
563+
virtual machine.
564+
items:
565+
pattern: ^(?i)[a-z0-9_][a-z0-9_\-\+\.]*$
566+
type: string
567+
minItems: 1
568+
type: array
569+
x-kubernetes-list-type: set
561570
target:
562571
description: Target node. Only allowed if the original VM
563572
is on shared storage.

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxclustertemplates.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,15 @@ spec:
599599
storage:
600600
description: Storage for full clone.
601601
type: string
602+
tags:
603+
description: Tags is a list of tags to be applied
604+
to the virtual machine.
605+
items:
606+
pattern: ^(?i)[a-z0-9_][a-z0-9_\-\+\.]*$
607+
type: string
608+
minItems: 1
609+
type: array
610+
x-kubernetes-list-type: set
602611
target:
603612
description: Target node. Only allowed if the original
604613
VM is on shared storage.

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachines.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,14 @@ spec:
526526
storage:
527527
description: Storage for full clone.
528528
type: string
529+
tags:
530+
description: Tags is a list of tags to be applied to the virtual machine.
531+
items:
532+
pattern: ^(?i)[a-z0-9_][a-z0-9_\-\+\.]*$
533+
type: string
534+
minItems: 1
535+
type: array
536+
x-kubernetes-list-type: set
529537
target:
530538
description: Target node. Only allowed if the original VM is on shared
531539
storage.

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachinetemplates.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,15 @@ spec:
558558
storage:
559559
description: Storage for full clone.
560560
type: string
561+
tags:
562+
description: Tags is a list of tags to be applied to the virtual
563+
machine.
564+
items:
565+
pattern: ^(?i)[a-z0-9_][a-z0-9_\-\+\.]*$
566+
type: string
567+
minItems: 1
568+
type: array
569+
x-kubernetes-list-type: set
561570
target:
562571
description: Target node. Only allowed if the original VM
563572
is on shared storage.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ replace sigs.k8s.io/cluster-api => sigs.k8s.io/cluster-api v1.9.5
77
require (
88
github.com/flatcar/ignition v0.36.2
99
github.com/go-logr/logr v1.4.2
10+
github.com/google/go-cmp v0.6.0
1011
github.com/google/uuid v1.6.0
1112
github.com/jarcoal/httpmock v1.3.1
1213
github.com/luthermonson/go-proxmox v0.2.1
@@ -74,7 +75,6 @@ require (
7475
github.com/golang/protobuf v1.5.4 // indirect
7576
github.com/google/cel-go v0.20.1 // indirect
7677
github.com/google/gnostic-models v0.6.8 // indirect
77-
github.com/google/go-cmp v0.6.0 // indirect
7878
github.com/google/go-github/v53 v53.2.0 // indirect
7979
github.com/google/go-querystring v1.1.0 // indirect
8080
github.com/google/gofuzz v1.2.0 // indirect

internal/service/vmservice/vm.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package vmservice
2020
import (
2121
"context"
2222
"slices"
23+
"strings"
2324

2425
"github.com/pkg/errors"
2526
corev1 "k8s.io/api/core/v1"
@@ -42,9 +43,11 @@ const (
4243
// See the following link for a list of available config options:
4344
// https://pve.proxmox.com/pve-docs/api-viewer/index.html#/nodes/{node}/qemu/{vmid}/config
4445

45-
optionSockets = "sockets"
46-
optionCores = "cores"
47-
optionMemory = "memory"
46+
optionSockets = "sockets"
47+
optionCores = "cores"
48+
optionMemory = "memory"
49+
optionTags = "tags"
50+
optionDescription = "description"
4851
)
4952

5053
// ErrNoVMIDInRangeFree is returned if no free VMID is found in the specified vmIDRange.
@@ -240,6 +243,13 @@ func reconcileVirtualMachineConfig(ctx context.Context, machineScope *scope.Mach
240243
vmOptions = append(vmOptions, proxmox.VirtualMachineOption{Name: optionMemory, Value: value})
241244
}
242245

246+
// Description
247+
if machineScope.ProxmoxMachine.Spec.Description != nil {
248+
if machineScope.VirtualMachine.VirtualMachineConfig.Description != *machineScope.ProxmoxMachine.Spec.Description {
249+
vmOptions = append(vmOptions, proxmox.VirtualMachineOption{Name: optionDescription, Value: machineScope.ProxmoxMachine.Spec.Description})
250+
}
251+
}
252+
243253
// Network vmbrs.
244254
if machineScope.ProxmoxMachine.Spec.Network != nil && shouldUpdateNetworkDevices(machineScope) {
245255
// adding the default network device.
@@ -263,6 +273,20 @@ func reconcileVirtualMachineConfig(ctx context.Context, machineScope *scope.Mach
263273
}
264274
}
265275

276+
// custom tags
277+
if machineScope.ProxmoxMachine.Spec.Tags != nil {
278+
machineScope.VirtualMachine.SplitTags()
279+
length := len(machineScope.VirtualMachine.VirtualMachineConfig.TagsSlice)
280+
for _, tag := range machineScope.ProxmoxMachine.Spec.Tags {
281+
if !machineScope.VirtualMachine.HasTag(tag) {
282+
machineScope.VirtualMachine.VirtualMachineConfig.TagsSlice = append(machineScope.VirtualMachine.VirtualMachineConfig.TagsSlice, tag)
283+
}
284+
}
285+
if len(machineScope.VirtualMachine.VirtualMachineConfig.TagsSlice) > length {
286+
vmOptions = append(vmOptions, proxmox.VirtualMachineOption{Name: optionTags, Value: strings.Join(machineScope.VirtualMachine.VirtualMachineConfig.TagsSlice, ";")})
287+
}
288+
}
289+
266290
if len(vmOptions) == 0 {
267291
return false, nil
268292
}

0 commit comments

Comments
 (0)