Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added VolumeRef to Machine status #1125

Merged
merged 4 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}