Skip to content

Commit

Permalink
Added VolumeRef to Machine status (#1125)
Browse files Browse the repository at this point in the history
  • Loading branch information
ushabelgur authored Oct 7, 2024
1 parent 07f85be commit 8167537
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 20 deletions.
2 changes: 2 additions & 0 deletions api/compute/v1alpha1/machine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ type VolumeStatus struct {
State VolumeState `json:"state,omitempty"`
// LastStateTransitionTime is the last time the State transitioned.
LastStateTransitionTime *metav1.Time `json:"lastStateTransitionTime,omitempty"`
// VolumeRef reference to the claimed Volume
VolumeRef corev1.LocalObjectReference `json:"volumeRef,omitempty"`
}

// VolumeState is the infrastructure attachment state a Volume can be in.
Expand Down
1 change: 1 addition & 0 deletions api/compute/v1alpha1/zz_generated.deepcopy.go

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

18 changes: 14 additions & 4 deletions client-go/applyconfigurations/compute/v1alpha1/volumestatus.go

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

4 changes: 4 additions & 0 deletions client-go/applyconfigurations/internal/internal.go

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

9 changes: 8 additions & 1 deletion client-go/openapi/zz_generated.openapi.go

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

4 changes: 4 additions & 0 deletions gen/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -65371,6 +65371,10 @@
"state": {
"description": "State represents the attachment state of a Volume.",
"type": "string"
},
"volumeRef": {
"description": "VolumeRef reference to the claimed Volume",
"$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference"
}
}
},
Expand Down
9 changes: 9 additions & 0 deletions gen/v3/apis__compute.ironcore.dev__v1alpha1_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -4883,6 +4883,15 @@
"state": {
"description": "State represents the attachment state of a Volume.",
"type": "string"
},
"volumeRef": {
"description": "VolumeRef reference to the claimed Volume",
"default": {},
"allOf": [
{
"$ref": "#/components/schemas/io.k8s.api.core.v1.LocalObjectReference"
}
]
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions internal/apis/compute/machine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ type VolumeStatus struct {
State VolumeState
// LastStateTransitionTime is the last time the State transitioned.
LastStateTransitionTime *metav1.Time
//VolumeRef reference to the claimed Volume
VolumeRef corev1.LocalObjectReference
}

// VolumeState is the infrastructure attachment state a Volume can be in.
Expand Down
2 changes: 2 additions & 0 deletions internal/apis/compute/v1alpha1/zz_generated.conversion.go

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

1 change: 1 addition & 0 deletions internal/apis/compute/zz_generated.deepcopy.go

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

2 changes: 1 addition & 1 deletion internal/app/app_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (

const (
pollingInterval = 50 * time.Millisecond
eventuallyTimeout = 3 * time.Second
eventuallyTimeout = 5 * time.Second
consistentlyDuration = 1 * time.Second
apiServiceTimeout = 5 * time.Minute
)
Expand Down
14 changes: 7 additions & 7 deletions internal/app/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ var _ = Describe("Core", func() {
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed())

By("getting the resource quota")
By("waiting for the resource quota to be updated")
resourceQuotaKey := client.ObjectKeyFromObject(resourceQuota)
Expect(k8sClient.Get(ctx, resourceQuotaKey, resourceQuota)).To(Succeed())

By("inspecting the resource quota")
Expect(resourceQuota.Status.Used).To(Equal(corev1alpha1.ResourceList{
corev1alpha1.ResourceRequestsCPU: resource.MustParse("1"),
}))
Eventually(func(g Gomega) {
Expect(k8sClient.Get(ctx, resourceQuotaKey, resourceQuota)).To(Succeed())
g.Expect(resourceQuota.Status.Used).To(Equal(corev1alpha1.ResourceList{
corev1alpha1.ResourceRequestsCPU: resource.MustParse("1"),
}))
}).Should(Succeed())
})
})
})
100 changes: 100 additions & 0 deletions poollet/machinepoollet/controllers/machine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
. "github.com/onsi/gomega/gstruct"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
. "sigs.k8s.io/controller-runtime/pkg/envtest/komega"
)
Expand Down Expand Up @@ -325,6 +326,13 @@ var _ = Describe("MachineController", func() {
Eventually(srv.Machines[iriMachine.Metadata.Id]).Should(SatisfyAll(
HaveField("Spec.NetworkInterfaces", BeEmpty()),
))

By("Verifying ironcore machine volume status with correct volume reference")
Eventually(Object(machine)).Should(HaveField("Status.Volumes", ConsistOf(MatchFields(IgnoreExtras, Fields{
"Name": Equal("primary"),
"State": Equal(computev1alpha1.VolumeStatePending),
"VolumeRef": Equal(corev1.LocalObjectReference{Name: volume.Name}),
}))))
})

It("should correctly manage the power state of a machine", func(ctx SpecContext) {
Expand Down Expand Up @@ -392,6 +400,98 @@ var _ = Describe("MachineController", func() {
srv.SetMachines([]*testingmachine.FakeMachine{iriMachine})
Eventually(Object(machine)).Should(HaveField("Status.State", Equal(computev1alpha1.MachineStateTerminating)))
})

It("should create a machine and verify claimed volume reference with ephemeral volume", func(ctx SpecContext) {
By("creating a machine")
const fooAnnotationValue = "bar"
machine := &computev1alpha1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: ns.Name,
GenerateName: "machine-",
Annotations: map[string]string{
fooAnnotation: fooAnnotationValue,
},
},
Spec: computev1alpha1.MachineSpec{
MachineClassRef: corev1.LocalObjectReference{Name: mc.Name},
MachinePoolRef: &corev1.LocalObjectReference{Name: mp.Name},
Volumes: []computev1alpha1.Volume{
{
Name: "primary",
VolumeSource: computev1alpha1.VolumeSource{
Ephemeral: &computev1alpha1.EphemeralVolumeSource{
VolumeTemplate: &storagev1alpha1.VolumeTemplateSpec{
Spec: storagev1alpha1.VolumeSpec{},
},
},
},
},
},
},
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed())
By("By getting ephimeral volume")
volumeKey := types.NamespacedName{
Namespace: ns.Name,
Name: computev1alpha1.MachineEphemeralVolumeName(machine.Name, "primary"),
}
ephimeralVolume := &storagev1alpha1.Volume{}
Eventually(func(g Gomega) {
err := k8sClient.Get(ctx, volumeKey, ephimeralVolume)
Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
g.Expect(err).NotTo(HaveOccurred())
}).Should(Succeed())

By("patching the volume to be available")
Eventually(UpdateStatus(ephimeralVolume, func() {
ephimeralVolume.Status.State = storagev1alpha1.VolumeStateAvailable
ephimeralVolume.Status.Access = &storagev1alpha1.VolumeAccess{
Driver: "test",
Handle: "testhandle",
}
})).Should(Succeed())

By("waiting for the runtime to report the machine and volume")
Eventually(srv).Should(SatisfyAll(
HaveField("Machines", HaveLen(1)),
))
_, iriMachine := GetSingleMapEntry(srv.Machines)

By("inspecting the iri machine")
Expect(iriMachine.Metadata.Labels).To(HaveKeyWithValue(machinepoolletv1alpha1.DownwardAPILabel(fooDownwardAPILabel), fooAnnotationValue))
Expect(iriMachine.Spec.Class).To(Equal(mc.Name))
Expect(iriMachine.Spec.Power).To(Equal(iri.Power_POWER_ON))
Expect(iriMachine.Spec.Volumes).To(ConsistOf(&iri.Volume{
Name: "primary",
Device: "oda",
Connection: &iri.VolumeConnection{
Driver: "test",
Handle: "testhandle",
},
}))

By("waiting for the ironcore machine status to be up-to-date")
expectedMachineID := machinepoolletmachine.MakeID(testingmachine.FakeRuntimeName, iriMachine.Metadata.Id)
Eventually(Object(machine)).Should(SatisfyAll(
HaveField("Status.MachineID", expectedMachineID.String()),
HaveField("Status.ObservedGeneration", machine.Generation),
))

By("setting the network interface id in the machine status")
iriMachine = &testingmachine.FakeMachine{Machine: *proto.Clone(&iriMachine.Machine).(*iri.Machine)}
iriMachine.Metadata.Generation = 1
iriMachine.Status.ObservedGeneration = 1

srv.SetMachines([]*testingmachine.FakeMachine{iriMachine})

By("Verifying ironcore machine volume status with correct volume reference")
Eventually(Object(machine)).Should(HaveField("Status.Volumes", ConsistOf(MatchFields(IgnoreExtras, Fields{
"Name": Equal("primary"),
"State": Equal(computev1alpha1.VolumeStatePending),
"VolumeRef": Equal(corev1.LocalObjectReference{Name: ephimeralVolume.Name}),
}))))
})

})

func GetSingleMapEntry[K comparable, V any](m map[K]V) (K, V) {
Expand Down
18 changes: 11 additions & 7 deletions poollet/machinepoollet/controllers/machine_controller_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,16 +347,18 @@ func (r *MachineReconciler) getVolumeStatusesForMachine(
iriVolumeStatus, ok = iriVolumeStatusByName[machineVolume.Name]
volumeStatusValues computev1alpha1.VolumeStatus
)
volumeName := computev1alpha1.MachineVolumeName(machine.Name, machineVolume)
if ok {
var err error
volumeStatusValues, err = r.convertIRIVolumeStatus(iriVolumeStatus)
volumeStatusValues, err = r.convertIRIVolumeStatus(iriVolumeStatus, volumeName)
if err != nil {
return nil, fmt.Errorf("[volume %s] %w", machineVolume.Name, err)
}
} else {
volumeStatusValues = computev1alpha1.VolumeStatus{
Name: machineVolume.Name,
State: computev1alpha1.VolumeStatePending,
Name: machineVolume.Name,
State: computev1alpha1.VolumeStatePending,
VolumeRef: corev1.LocalObjectReference{Name: volumeName},
}
}

Expand All @@ -382,16 +384,17 @@ func (r *MachineReconciler) convertIRIVolumeState(iriState iri.VolumeState) (com
return "", fmt.Errorf("unknown iri volume state %v", iriState)
}

func (r *MachineReconciler) convertIRIVolumeStatus(iriVolumeStatus *iri.VolumeStatus) (computev1alpha1.VolumeStatus, error) {
func (r *MachineReconciler) convertIRIVolumeStatus(iriVolumeStatus *iri.VolumeStatus, volumeName string) (computev1alpha1.VolumeStatus, error) {
state, err := r.convertIRIVolumeState(iriVolumeStatus.State)
if err != nil {
return computev1alpha1.VolumeStatus{}, err
}

return computev1alpha1.VolumeStatus{
Name: iriVolumeStatus.Name,
Handle: iriVolumeStatus.Handle,
State: state,
Name: iriVolumeStatus.Name,
Handle: iriVolumeStatus.Handle,
State: state,
VolumeRef: corev1.LocalObjectReference{Name: volumeName},
}, nil
}

Expand All @@ -402,4 +405,5 @@ func (r *MachineReconciler) addVolumeStatusValues(now metav1.Time, existing, new
existing.Name = newValues.Name
existing.State = newValues.State
existing.Handle = newValues.Handle
existing.VolumeRef = newValues.VolumeRef
}

0 comments on commit 8167537

Please sign in to comment.