Skip to content

Commit

Permalink
Merge pull request #117 from hivelocity/ani/issues/114
Browse files Browse the repository at this point in the history
✨ HV device tag Label Selector
  • Loading branch information
aniruddha2000 authored Dec 14, 2023
2 parents 25c0155 + 65a9df9 commit 8cf7a01
Show file tree
Hide file tree
Showing 20 changed files with 331 additions and 132 deletions.
25 changes: 23 additions & 2 deletions api/v1alpha1/hivelocitymachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/hivelocity/cluster-api-provider-hivelocity/pkg/services/hivelocity/hvtag"
hv "github.com/hivelocity/hivelocity-client-go/client"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/selection"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
capierrors "sigs.k8s.io/cluster-api/errors"
)
Expand Down Expand Up @@ -91,8 +92,9 @@ type HivelocityMachineSpec struct {
// +optional
ProviderID *string `json:"providerID,omitempty"`

// Type is the Hivelocity Machine Type for this machine.
Type HivelocityDeviceType `json:"type"`
// DeviceSelector can be used to limit the set of devices that this HivelocityMachine can claim.
// +optional
DeviceSelector DeviceSelector `json:"deviceSelector,omitempty"`

// ImageName is the reference to the Machine Image from which to create the device.
// +kubebuilder:validation:MinLength=1
Expand All @@ -103,6 +105,25 @@ type HivelocityMachineSpec struct {
Status ControllerGeneratedStatus `json:"status,omitempty"`
}

// DeviceSelector specifies matching criteria for tags on devices.
// This is used to target a specific set of devices that can be claimed by the HivelocityMachine.
type DeviceSelector struct {
// Key/value pairs of labels that must exist on a chosen Device
// +optional
MatchLabels map[string]string `json:"matchLabels,omitempty"`

// MatchExpressions match expressions that must be true on a chosen Device
// +optional
MatchExpressions []DeviceSelectorRequirement `json:"matchExpressions,omitempty"`
}

// DeviceSelectorRequirement defines a requirement used for MatchExpressions to select device.
type DeviceSelectorRequirement struct {
Key string `json:"key"`
Operator selection.Operator `json:"operator"`
Values []string `json:"values"`
}

// ControllerGeneratedStatus contains all status information which is important to persist.
type ControllerGeneratedStatus struct {
// Information tracked by the provisioner.
Expand Down
6 changes: 3 additions & 3 deletions api/v1alpha1/hivelocitymachine_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ func (r *HivelocityMachine) ValidateUpdate(oldRaw runtime.Object) error {

var allErrs field.ErrorList

// Type is immutable
if !reflect.DeepEqual(old.Spec.Type, r.Spec.Type) {
// DeviceSelector is immutable
if !reflect.DeepEqual(old.Spec.DeviceSelector, r.Spec.DeviceSelector) {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec", "type"), r.Spec.Type, "field is immutable"),
field.Invalid(field.NewPath("spec", "DeviceSelector"), r.Spec.DeviceSelector, "field is immutable"),
)
}

Expand Down
50 changes: 50 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,41 @@ spec:
spec:
description: HivelocityMachineSpec defines the desired state of HivelocityMachine.
properties:
deviceSelector:
description: DeviceSelector can be used to limit the set of devices
that this HivelocityMachine can claim.
properties:
matchExpressions:
description: MatchExpressions match expressions that must be true
on a chosen Device
items:
description: DeviceSelectorRequirement defines a requirement
used for MatchExpressions to select device.
properties:
key:
type: string
operator:
description: Operator represents a key/field's relationship
to value(s). See labels.Requirement and fields.Requirement
for more details.
type: string
values:
items:
type: string
type: array
required:
- key
- operator
- values
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: Key/value pairs of labels that must exist on a chosen
Device
type: object
type: object
imageName:
description: ImageName is the reference to the Machine Image from
which to create the device.
Expand All @@ -97,19 +132,8 @@ spec:
description: Information tracked by the provisioner.
type: string
type: object
type:
description: Type is the Hivelocity Machine Type for this machine.
enum:
- pool
- hvCustom
- hvControlPlane
- hvWorker
- e2eControlPlane
- e2eWorker
type: string
required:
- imageName
- type
type: object
status:
description: HivelocityMachineStatus defines the observed state of HivelocityMachine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,41 @@ spec:
description: Spec is the specification of the desired behavior
of the machine.
properties:
deviceSelector:
description: DeviceSelector can be used to limit the set of
devices that this HivelocityMachine can claim.
properties:
matchExpressions:
description: MatchExpressions match expressions that must
be true on a chosen Device
items:
description: DeviceSelectorRequirement defines a requirement
used for MatchExpressions to select device.
properties:
key:
type: string
operator:
description: Operator represents a key/field's relationship
to value(s). See labels.Requirement and fields.Requirement
for more details.
type: string
values:
items:
type: string
type: array
required:
- key
- operator
- values
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: Key/value pairs of labels that must exist
on a chosen Device
type: object
type: object
imageName:
description: ImageName is the reference to the Machine Image
from which to create the device.
Expand All @@ -99,20 +134,8 @@ spec:
description: Information tracked by the provisioner.
type: string
type: object
type:
description: Type is the Hivelocity Machine Type for this
machine.
enum:
- pool
- hvCustom
- hvControlPlane
- hvWorker
- e2eControlPlane
- e2eWorker
type: string
required:
- imageName
- type
type: object
required:
- spec
Expand Down
11 changes: 4 additions & 7 deletions controllers/hivelocitycluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,23 +185,20 @@ func (r *HivelocityClusterReconciler) reconcileNormal(ctx context.Context, clust
if hvCluster.Spec.ControlPlaneEndpoint.Host == "" {
var hmt = infrav1.HivelocityMachineTemplate{}
name := hvCluster.Name + "-control-plane"

err := r.Client.Get(ctx, client.ObjectKey{
Namespace: hvCluster.ObjectMeta.Namespace,
Name: name,
}, &hmt)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to get HivelocityMachineTemplate %q: %w", name, err)
}
machineType := hmt.Spec.Template.Spec.Type
if machineType == "" {
return ctrl.Result{}, fmt.Errorf("Spec.Template.Spec.Type of HivelocityMachineTemplate %q is empty", name)
}
hvDevice, err := device.GetFirstFreeDevice(ctx, clusterScope.HVClient, machineType, hvCluster, "")

hvDevice, err := device.GetFirstFreeDevice(ctx, clusterScope.HVClient, hmt.Spec.Template.Spec, hvCluster)
if err != nil {
return ctrl.Result{}, fmt.Errorf("device.GetFirstFreeDevice() failed: %w", err)
}
log.Info(fmt.Sprintf("Setting hvCluster.Spec.ControlPlaneEndpoint.Host to %q (machineType=%s).",
hvDevice.PrimaryIp, machineType))
log.Info(fmt.Sprintf("Setting hvCluster.Spec.ControlPlaneEndpoint.Host to %q", hvDevice.PrimaryIp))
hvCluster.Spec.ControlPlaneEndpoint.Host = hvDevice.PrimaryIp
hvCluster.Spec.ControlPlaneEndpoint.Port = 6443
}
Expand Down
6 changes: 5 additions & 1 deletion controllers/hivelocitycluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,11 @@ var _ = Describe("Hivelocity ClusterReconciler", func() {
},
Spec: infrav1.HivelocityMachineSpec{
ImageName: "Ubuntu 20.x",
Type: "pool",
DeviceSelector: infrav1.DeviceSelector{
MatchLabels: map[string]string{
"deviceType": "pool",
},
},
},
}
Expect(testEnv.Create(ctx, hvMachine)).To(Succeed())
Expand Down
20 changes: 11 additions & 9 deletions controllers/hivelocitymachine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ var _ = Describe("HivelocityMachineReconciler", func() {
},
Spec: infrav1.HivelocityMachineSpec{
ImageName: "Ubuntu 20.x",
Type: "hvCustom",
DeviceSelector: infrav1.DeviceSelector{
MatchLabels: map[string]string{
"deviceType": "hvCustom",
},
},
},
}

Expand Down Expand Up @@ -231,7 +235,7 @@ var _ = Describe("HivelocityMachineReconciler", func() {
device, err := hvClient.GetDevice(ctx, mock.FreeDeviceID)
Expect(err).ShouldNot(HaveOccurred())
Expect(device.Tags).Should(BeEquivalentTo([]string{
"caphv-device-type=hvCustom",
"caphvlabel:deviceType=hvCustom",
"caphv-use=allow",
"caphv-cluster-hv-test1=owned",
"caphv-cluster-name=hv-test1",
Expand Down Expand Up @@ -337,7 +341,11 @@ var _ = Describe("Hivelocity secret", func() {
},
Spec: infrav1.HivelocityMachineSpec{
ImageName: "Ubuntu 20.x",
Type: "hvCustom",
DeviceSelector: infrav1.DeviceSelector{
MatchLabels: map[string]string{
"deviceType": "hvCustom",
},
},
},
}
Expect(testEnv.Create(ctx, hivelocityMachine)).To(Succeed())
Expand Down Expand Up @@ -427,7 +435,6 @@ var _ = Describe("HivelocityMachine validation", func() {
},
Spec: infrav1.HivelocityMachineSpec{
ImageName: "Ubuntu 20.x",
Type: "hvCustom",
},
}
})
Expand All @@ -436,11 +443,6 @@ var _ = Describe("HivelocityMachine validation", func() {
Expect(testEnv.Cleanup(ctx, testNs, hvMachine)).To(Succeed())
})

It("should fail with wrong type", func() {
hvMachine.Spec.Type = "wrong-type"
Expect(testEnv.Create(ctx, hvMachine)).ToNot(Succeed())
})

It("should fail without imageName", func() {
hvMachine.Spec.ImageName = ""
Expect(testEnv.Create(ctx, hvMachine)).ToNot(Succeed())
Expand Down
Loading

0 comments on commit 8cf7a01

Please sign in to comment.