diff --git a/api/compute/v1alpha1/machinereservation_types.go b/api/compute/v1alpha1/machinereservation_types.go new file mode 100644 index 000000000..443badc4a --- /dev/null +++ b/api/compute/v1alpha1/machinereservation_types.go @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ReservationSpec defines the desired state of Reservation +type ReservationSpec struct { + Pools []corev1.LocalObjectReference `json:"pools"` + Resources corev1alpha1.ResourceList `json:"resources,omitempty"` + // TODO we might want to add a weight to indicate preference/priority +} + +// ReservationStatus defines the observed state of Reservation +type ReservationStatus struct { + Pools []ReservationPoolStatus `json:"pools,omitempty"` + Conditions []ReservationCondition `json:"conditions,omitempty"` +} + +// ReservationState is the state of a Reservation. +// +enum +type ReservationState string + +const ( + // ReservationStatePending means the Reservation is being reconciled. + ReservationStatePending ReservationState = "Pending" + // ReservationStateAccepted means the pool accepted the reservation and reserved the requested resources. + ReservationStateAccepted ReservationState = "Accepted" + // ReservationStateRejected means the pool rejected the reservation. + ReservationStateRejected ReservationState = "Rejected" +) + +// ReservationConditionType is a type a ReservationCondition can have. +type ReservationConditionType string + +// ReservationCondition is one of the conditions of a volume. +type ReservationCondition struct { + // Type is the type of the condition. + Type ReservationConditionType `json:"type"` + // Status is the status of the condition. + Status corev1.ConditionStatus `json:"status"` + // Reason is a machine-readable indication of why the condition is in a certain state. + Reason string `json:"reason"` + // Message is a human-readable explanation of why the condition has a certain reason / state. + Message string `json:"message"` + // ObservedGeneration represents the .metadata.generation that the condition was set based upon. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + // LastTransitionTime is the last time the status of a condition has transitioned from one state to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` +} + +type ReservationPoolStatus struct { + Name string `json:"ref,omitempty"` + State ReservationState `json:"state,omitempty"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Reservation is the Schema for the machines API +type Reservation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ReservationSpec `json:"spec,omitempty"` + Status ReservationStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ReservationList contains a list of Reservation +type ReservationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Reservation `json:"items"` +} diff --git a/api/compute/v1alpha1/register.go b/api/compute/v1alpha1/register.go index 74bc4abd2..b0a8b06f2 100644 --- a/api/compute/v1alpha1/register.go +++ b/api/compute/v1alpha1/register.go @@ -35,6 +35,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &MachineClassList{}, &MachinePool{}, &MachinePoolList{}, + &Reservation{}, + &ReservationList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/api/compute/v1alpha1/zz_generated.deepcopy.go b/api/compute/v1alpha1/zz_generated.deepcopy.go index 7910e66dd..18930c563 100644 --- a/api/compute/v1alpha1/zz_generated.deepcopy.go +++ b/api/compute/v1alpha1/zz_generated.deepcopy.go @@ -601,6 +601,156 @@ func (in *NetworkInterfaceStatus) DeepCopy() *NetworkInterfaceStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Reservation) DeepCopyInto(out *Reservation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Reservation. +func (in *Reservation) DeepCopy() *Reservation { + if in == nil { + return nil + } + out := new(Reservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Reservation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationCondition) DeepCopyInto(out *ReservationCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationCondition. +func (in *ReservationCondition) DeepCopy() *ReservationCondition { + if in == nil { + return nil + } + out := new(ReservationCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationList) DeepCopyInto(out *ReservationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Reservation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationList. +func (in *ReservationList) DeepCopy() *ReservationList { + if in == nil { + return nil + } + out := new(ReservationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReservationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationPoolStatus) DeepCopyInto(out *ReservationPoolStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationPoolStatus. +func (in *ReservationPoolStatus) DeepCopy() *ReservationPoolStatus { + if in == nil { + return nil + } + out := new(ReservationPoolStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationSpec) DeepCopyInto(out *ReservationSpec) { + *out = *in + if in.Pools != nil { + in, out := &in.Pools, &out.Pools + *out = make([]v1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make(corev1alpha1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationSpec. +func (in *ReservationSpec) DeepCopy() *ReservationSpec { + if in == nil { + return nil + } + out := new(ReservationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationStatus) DeepCopyInto(out *ReservationStatus) { + *out = *in + if in.Pools != nil { + in, out := &in.Pools, &out.Pools + *out = make([]ReservationPoolStatus, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ReservationCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationStatus. +func (in *ReservationStatus) DeepCopy() *ReservationStatus { + if in == nil { + return nil + } + out := new(ReservationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Volume) DeepCopyInto(out *Volume) { *out = *in diff --git a/broker/machinebroker/api/v1alpha1/common_types.go b/broker/machinebroker/api/v1alpha1/common_types.go index a81c6c93c..fdf7dcae7 100644 --- a/broker/machinebroker/api/v1alpha1/common_types.go +++ b/broker/machinebroker/api/v1alpha1/common_types.go @@ -15,7 +15,8 @@ const ( ) const ( - MachineBrokerManager = "machinebroker" + MachineBrokerManager = "machinebroker" + ReservationBrokerManager = "reservationbroker" VolumeAccessPurpose = "volume-access" ) diff --git a/broker/machinebroker/server/reservation.go b/broker/machinebroker/server/reservation.go new file mode 100644 index 000000000..fb5f95ec2 --- /dev/null +++ b/broker/machinebroker/server/reservation.go @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server + +import ( + "fmt" + + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + "github.com/ironcore-dev/ironcore/broker/machinebroker/apiutils" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" +) + +var ironcoreReservationStateToReservationState = map[computev1alpha1.ReservationState]iri.ReservationState{ + computev1alpha1.ReservationStatePending: iri.ReservationState_RESERVATION_STATE_PENDING, + computev1alpha1.ReservationStateAccepted: iri.ReservationState_RESERVATION_STATE_ACCEPTED, + computev1alpha1.ReservationStateRejected: iri.ReservationState_RESERVATION_STATE_REJECTED, +} + +func (s *Server) convertIronCoreReservationState(state computev1alpha1.ReservationState) (iri.ReservationState, error) { + if res, ok := ironcoreReservationStateToReservationState[state]; ok { + return res, nil + } + return 0, fmt.Errorf("unknown ironcore reservation state %q", state) +} + +func (s *Server) convertIronCoreReservationStatus(ironCoreReservation *computev1alpha1.Reservation) (iri.ReservationState, error) { + if ironCoreReservation.Spec.Pools == nil || ironCoreReservation.Status.Pools == nil { + return iri.ReservationState_RESERVATION_STATE_PENDING, nil + } + + //TODO make configurable + for _, pool := range ironCoreReservation.Status.Pools { + state, err := s.convertIronCoreReservationState(pool.State) + if err != nil { + return iri.ReservationState_RESERVATION_STATE_PENDING, err + } + + switch state { + case iri.ReservationState_RESERVATION_STATE_REJECTED: + return state, nil + case iri.ReservationState_RESERVATION_STATE_PENDING: + return state, nil + + } + } + + return iri.ReservationState_RESERVATION_STATE_REJECTED, nil +} + +func (s *Server) convertIronCoreReservation(ironCoreReservation *computev1alpha1.Reservation) (*iri.Reservation, error) { + metadata, err := apiutils.GetObjectMetadata(ironCoreReservation) + if err != nil { + return nil, err + } + + state, err := s.convertIronCoreReservationStatus(ironCoreReservation) + if err != nil { + return nil, err + } + + return &iri.Reservation{ + Metadata: metadata, + Spec: &iri.ReservationSpec{ + Resources: nil, + }, + Status: &iri.ReservationStatus{ + State: state, + }, + }, nil +} diff --git a/broker/machinebroker/server/reservation_create.go b/broker/machinebroker/server/reservation_create.go new file mode 100644 index 000000000..2488a4a1c --- /dev/null +++ b/broker/machinebroker/server/reservation_create.go @@ -0,0 +1,115 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + "github.com/ironcore-dev/ironcore/api/core/v1alpha1" + "github.com/ironcore-dev/ironcore/broker/common/cleaner" + brokerutils "github.com/ironcore-dev/ironcore/broker/common/utils" + machinebrokerv1alpha1 "github.com/ironcore-dev/ironcore/broker/machinebroker/api/v1alpha1" + "github.com/ironcore-dev/ironcore/broker/machinebroker/apiutils" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + metav1alpha1 "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + machinepoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + "github.com/ironcore-dev/ironcore/utils/maps" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func prepareIronCoreAnnotations[T metav1alpha1.Object](obj T) (map[string]string, error) { + annotationsValue, err := apiutils.EncodeAnnotationsAnnotation(obj.GetMetadata().GetAnnotations()) + if err != nil { + return nil, fmt.Errorf("error encoding annotations: %w", err) + } + + labelsValue, err := apiutils.EncodeLabelsAnnotation(obj.GetMetadata().GetLabels()) + if err != nil { + return nil, fmt.Errorf("error encoding labels: %w", err) + } + + return map[string]string{ + machinebrokerv1alpha1.AnnotationsAnnotation: annotationsValue, + machinebrokerv1alpha1.LabelsAnnotation: labelsValue, + }, nil +} + +func (s *Server) createIronCoreReservation( + ctx context.Context, + log logr.Logger, + iriReservation *iri.Reservation, +) (res *computev1alpha1.Reservation, retErr error) { + + labels := brokerutils.PrepareDownwardAPILabels( + iriReservation.GetMetadata().GetLabels(), + s.brokerDownwardAPILabels, + machinepoolletv1alpha1.MachineDownwardAPIPrefix, + ) + + annotations, err := prepareIronCoreAnnotations(iriReservation) + if err != nil { + return nil, fmt.Errorf("error preparing ironcore reservation annotations: %w", err) + } + + var resources = v1alpha1.ResourceList{} + for name, quantity := range iriReservation.Spec.Resources { + var q resource.Quantity + if err := q.Unmarshal(quantity); err != nil { + return nil, fmt.Errorf("error unmarshaling resource quantity: %w", err) + } + resources[v1alpha1.ResourceName(name)] = q + } + + c, cleanup := s.setupCleaner(ctx, log, &retErr) + defer cleanup() + + ironcoreReservation := &computev1alpha1.Reservation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: s.cluster.Namespace(), + Name: s.cluster.IDGen().Generate(), + Annotations: annotations, + Labels: maps.AppendMap(labels, map[string]string{ + machinebrokerv1alpha1.ManagerLabel: machinebrokerv1alpha1.ReservationBrokerManager, + }), + }, + Spec: computev1alpha1.ReservationSpec{ + Resources: resources, + }, + } + log.V(1).Info("Creating ironcore reservation") + if err := s.cluster.Client().Create(ctx, ironcoreReservation); err != nil { + return nil, fmt.Errorf("error creating ironcore reservation: %w", err) + } + c.Add(cleaner.CleanupObject(s.cluster.Client(), ironcoreReservation)) + + log.V(1).Info("Patching ironcore reservation as created") + if err := apiutils.PatchCreated(ctx, s.cluster.Client(), ironcoreReservation); err != nil { + return nil, fmt.Errorf("error patching ironcore reservation as created: %w", err) + } + + return ironcoreReservation, nil +} + +func (s *Server) CreateReservation(ctx context.Context, req *iri.CreateReservationRequest) (res *iri.CreateReservationResponse, retErr error) { + log := s.loggerFrom(ctx) + + log.V(1).Info("Creating ironcore reservation") + ironcoreReservation, err := s.createIronCoreReservation(ctx, log, req.Reservation) + if err != nil { + return nil, fmt.Errorf("error creating ironcore reservation: %w", err) + } + + r, err := s.convertIronCoreReservation(ironcoreReservation) + if err != nil { + return nil, fmt.Errorf("error converting ironcore reservation: %w", err) + } + + return &iri.CreateReservationResponse{ + Reservation: r, + }, nil +} diff --git a/broker/machinebroker/server/reservation_create_test.go b/broker/machinebroker/server/reservation_create_test.go new file mode 100644 index 000000000..bcba87377 --- /dev/null +++ b/broker/machinebroker/server/reservation_create_test.go @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server_test + +import ( + "fmt" + + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1" + machinebrokerv1alpha1 "github.com/ironcore-dev/ironcore/broker/machinebroker/api/v1alpha1" + "github.com/ironcore-dev/ironcore/broker/machinebroker/apiutils" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + machinepoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/resource" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("CreateReservation", func() { + ns, srv := SetupTest() + + cpuResource := resource.MustParse("1") + cpu, err := cpuResource.Marshal() + Expect(err).NotTo(HaveOccurred()) + + It("should correctly create a reservation", func(ctx SpecContext) { + By("creating a reservation") + res, err := srv.CreateReservation(ctx, &iri.CreateReservationRequest{ + Reservation: &iri.Reservation{ + Metadata: &irimeta.ObjectMetadata{ + Labels: map[string]string{ + machinepoolletv1alpha1.ReservationUIDLabel: "foobar", + }, + }, + Spec: &iri.ReservationSpec{ + Resources: map[string][]byte{ + string(corev1alpha1.ResourceCPU): cpu, + }, + }, + }, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(res).NotTo(BeNil()) + + By("getting the ironcore reservation") + ironcoreReservation := &computev1alpha1.Reservation{} + ironcoreReservationKey := client.ObjectKey{Namespace: ns.Name, Name: res.Reservation.Metadata.Id} + Expect(k8sClient.Get(ctx, ironcoreReservationKey, ironcoreReservation)).To(Succeed()) + + By("inspecting the ironcore reservation") + Expect(ironcoreReservation.Labels).To(Equal(map[string]string{ + fmt.Sprint(machinepoolletv1alpha1.MachineDownwardAPIPrefix, "root-reservation-uid"): "foobar", + machinebrokerv1alpha1.CreatedLabel: "true", + machinebrokerv1alpha1.ManagerLabel: machinebrokerv1alpha1.ReservationBrokerManager, + })) + encodedIRIAnnotations, err := apiutils.EncodeAnnotationsAnnotation(nil) + Expect(err).NotTo(HaveOccurred()) + encodedIRILabels, err := apiutils.EncodeLabelsAnnotation(map[string]string{ + machinepoolletv1alpha1.ReservationUIDLabel: "foobar", + }) + Expect(err).NotTo(HaveOccurred()) + Expect(ironcoreReservation.Annotations).To(Equal(map[string]string{ + machinebrokerv1alpha1.AnnotationsAnnotation: encodedIRIAnnotations, + machinebrokerv1alpha1.LabelsAnnotation: encodedIRILabels, + })) + + Expect(ironcoreReservation.Spec.Resources).To(Equal(corev1alpha1.ResourceList{ + corev1alpha1.ResourceCPU: resource.MustParse("1"), + })) + }) +}) diff --git a/broker/machinebroker/server/reservation_delete.go b/broker/machinebroker/server/reservation_delete.go new file mode 100644 index 000000000..b4db07903 --- /dev/null +++ b/broker/machinebroker/server/reservation_delete.go @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server + +import ( + "context" + "fmt" + + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + apierrors "k8s.io/apimachinery/pkg/api/errors" +) + +func (s *Server) DeleteReservation(ctx context.Context, req *iri.DeleteReservationRequest) (*iri.DeleteReservationResponse, error) { + reservationID := req.ReservationId + log := s.loggerFrom(ctx, "ReservationID", reservationID) + + ironcoreReservation, err := s.getIronCoreReservation(ctx, reservationID) + if err != nil { + return nil, err + } + + log.V(1).Info("Deleting ironcore reservation") + if err := s.cluster.Client().Delete(ctx, ironcoreReservation); err != nil { + if !apierrors.IsNotFound(err) { + return nil, fmt.Errorf("error deleting ironcore reservation: %w", err) + } + return nil, status.Errorf(codes.NotFound, "reservation %s not found", reservationID) + } + + return &iri.DeleteReservationResponse{}, nil +} diff --git a/broker/machinebroker/server/reservation_delete_test.go b/broker/machinebroker/server/reservation_delete_test.go new file mode 100644 index 000000000..28aff1eca --- /dev/null +++ b/broker/machinebroker/server/reservation_delete_test.go @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server_test + +import ( + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + machinepoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("DeleteReservation", func() { + ns, srv := SetupTest() + + It("should correctly delete a reservation", func(ctx SpecContext) { + By("creating a reservation") + + res, err := srv.CreateReservation(ctx, &iri.CreateReservationRequest{Reservation: &iri.Reservation{ + Metadata: &irimeta.ObjectMetadata{ + Labels: map[string]string{ + machinepoolletv1alpha1.ReservationUIDLabel: "foobar", + }, + }, + Spec: &iri.ReservationSpec{}, + }}) + Expect(err).NotTo(HaveOccurred()) + Expect(res).NotTo(BeNil()) + + By("deleting the reservation") + reservationID := res.Reservation.Metadata.Id + Expect(srv.DeleteReservation(ctx, &iri.DeleteReservationRequest{ + ReservationId: reservationID, + })).Error().NotTo(HaveOccurred()) + + By("listing for ironcore reservations in the namespace") + ironcoreReservationList := &computev1alpha1.ReservationList{} + Expect(k8sClient.List(ctx, ironcoreReservationList, client.InNamespace(ns.Name))).To(Succeed()) + + By("asserting there are no ironcore reservations in the returned list") + Expect(ironcoreReservationList.Items).To(BeEmpty()) + }) +}) diff --git a/broker/machinebroker/server/reservation_list.go b/broker/machinebroker/server/reservation_list.go new file mode 100644 index 000000000..fbb18949a --- /dev/null +++ b/broker/machinebroker/server/reservation_list.go @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server + +import ( + "context" + "fmt" + + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + machinebrokerv1alpha1 "github.com/ironcore-dev/ironcore/broker/machinebroker/api/v1alpha1" + "github.com/ironcore-dev/ironcore/broker/machinebroker/apiutils" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func (s *Server) listIroncoreReservations(ctx context.Context) (*computev1alpha1.ReservationList, error) { + ironcoreReservationList := &computev1alpha1.ReservationList{} + if err := s.cluster.Client().List(ctx, ironcoreReservationList, + client.InNamespace(s.cluster.Namespace()), + client.MatchingLabels{ + machinebrokerv1alpha1.ManagerLabel: machinebrokerv1alpha1.ReservationBrokerManager, + machinebrokerv1alpha1.CreatedLabel: "true", + }, + ); err != nil { + return nil, err + } + return ironcoreReservationList, nil +} + +func (s *Server) getIronCoreReservation(ctx context.Context, id string) (*computev1alpha1.Reservation, error) { + ironcoreReservation := &computev1alpha1.Reservation{} + ironcoreReservationKey := client.ObjectKey{Namespace: s.cluster.Namespace(), Name: id} + if err := s.cluster.Client().Get(ctx, ironcoreReservationKey, ironcoreReservation); err != nil { + if !apierrors.IsNotFound(err) { + return nil, fmt.Errorf("error getting ironcore reservation %s: %w", id, err) + } + return nil, status.Errorf(codes.NotFound, "reservation %s not found", id) + } + if !apiutils.IsManagedBy(ironcoreReservation, machinebrokerv1alpha1.ReservationBrokerManager) || !apiutils.IsCreated(ironcoreReservation) { + return nil, status.Errorf(codes.NotFound, "reservation %s not found", id) + } + return ironcoreReservation, nil +} + +func (s *Server) listReservations(ctx context.Context) ([]*iri.Reservation, error) { + ironcoreReservations, err := s.listIroncoreReservations(ctx) + if err != nil { + return nil, fmt.Errorf("error listing ironcore reservations: %w", err) + } + var res []*iri.Reservation + for _, ironcoreReservation := range ironcoreReservations.Items { + reservation, err := s.convertIronCoreReservation(&ironcoreReservation) + if err != nil { + return nil, err + } + + res = append(res, reservation) + } + return res, nil +} + +func (s *Server) filterReservations(reservations []*iri.Reservation, filter *iri.ReservationFilter) []*iri.Reservation { + if filter == nil { + return reservations + } + + var ( + res []*iri.Reservation + sel = labels.SelectorFromSet(filter.LabelSelector) + ) + for _, iriReservation := range reservations { + if !sel.Matches(labels.Set(iriReservation.Metadata.Labels)) { + continue + } + + res = append(res, iriReservation) + } + return res +} + +func (s *Server) getReservation(ctx context.Context, id string) (*iri.Reservation, error) { + ironCoreReservation, err := s.getIronCoreReservation(ctx, id) + if err != nil { + return nil, err + } + + return s.convertIronCoreReservation(ironCoreReservation) +} + +func (s *Server) ListReservations(ctx context.Context, req *iri.ListReservationsRequest) (*iri.ListReservationsResponse, error) { + if filter := req.Filter; filter != nil && filter.Id != "" { + reservation, err := s.getReservation(ctx, filter.Id) + if err != nil { + if status.Code(err) != codes.NotFound { + return nil, err + } + return &iri.ListReservationsResponse{ + Reservations: []*iri.Reservation{}, + }, nil + } + + return &iri.ListReservationsResponse{ + Reservations: []*iri.Reservation{reservation}, + }, nil + } + + reservations, err := s.listReservations(ctx) + if err != nil { + return nil, err + } + + reservations = s.filterReservations(reservations, req.Filter) + + return &iri.ListReservationsResponse{ + Reservations: reservations, + }, nil +} diff --git a/broker/machinebroker/server/reservation_list_test.go b/broker/machinebroker/server/reservation_list_test.go new file mode 100644 index 000000000..21a1efa05 --- /dev/null +++ b/broker/machinebroker/server/reservation_list_test.go @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package server_test + +import ( + corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + machinepoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/resource" +) + +var _ = Describe("ListReservations", func() { + _, srv := SetupTest() + + cpuResource := resource.MustParse("1") + cpu, err := cpuResource.Marshal() + Expect(err).NotTo(HaveOccurred()) + + It("should correctly list reservations", func(ctx SpecContext) { + By("creating multiple reservations") + const noOfReservations = 4 + + reservations := make([]any, noOfReservations) + for i := 0; i < noOfReservations; i++ { + res, err := srv.CreateReservation(ctx, &iri.CreateReservationRequest{ + Reservation: &iri.Reservation{ + Metadata: &irimeta.ObjectMetadata{ + Labels: map[string]string{ + machinepoolletv1alpha1.ReservationUIDLabel: "foobar", + }, + }, + Spec: &iri.ReservationSpec{ + Resources: map[string][]byte{ + string(corev1alpha1.ResourceCPU): cpu, + }, + }, + }, + }) + Expect(err).NotTo(HaveOccurred()) + Expect(res).NotTo(BeNil()) + reservations[i] = res.Reservation + } + + By("listing the reservations") + Expect(srv.ListReservations(ctx, &iri.ListReservationsRequest{})).To(HaveField("Reservations", ConsistOf(reservations...))) + }) +}) diff --git a/broker/machinebroker/server/server.go b/broker/machinebroker/server/server.go index b0bb233ba..7dc987217 100644 --- a/broker/machinebroker/server/server.go +++ b/broker/machinebroker/server/server.go @@ -34,6 +34,7 @@ var _ iri.MachineRuntimeServer = (*Server)(nil) //+kubebuilder:rbac:groups=networking.ironcore.dev,resources=loadbalancerroutings,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=networking.ironcore.dev,resources=natgateways,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=networking.ironcore.dev,resources=natgateways/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=compute.ironcore.dev,resources=reservations,verbs=get;list;watch;create;update;patch;delete type BrokerLabel struct { DefaultLabel string diff --git a/broker/machinebroker/server/server_suite_test.go b/broker/machinebroker/server/server_suite_test.go index de315d058..b3d2e31a2 100644 --- a/broker/machinebroker/server/server_suite_test.go +++ b/broker/machinebroker/server/server_suite_test.go @@ -136,9 +136,10 @@ func SetupTest() (*corev1.Namespace, *server.Server) { newSrv, err := server.New(cfg, ns.Name, server.Options{ BaseURL: baseURL, BrokerDownwardAPILabels: map[string]string{ - "root-machine-uid": machinepoolletv1alpha1.MachineUIDLabel, - "root-nic-uid": machinepoolletv1alpha1.NetworkInterfaceUIDLabel, - "root-network-uid": machinepoolletv1alpha1.NetworkUIDLabel, + "root-machine-uid": machinepoolletv1alpha1.MachineUIDLabel, + "root-nic-uid": machinepoolletv1alpha1.NetworkInterfaceUIDLabel, + "root-network-uid": machinepoolletv1alpha1.NetworkUIDLabel, + "root-reservation-uid": machinepoolletv1alpha1.ReservationUIDLabel, }, }) Expect(err).NotTo(HaveOccurred()) diff --git a/client-go/applyconfigurations/compute/v1alpha1/reservation.go b/client-go/applyconfigurations/compute/v1alpha1/reservation.go new file mode 100644 index 000000000..ab7a4ed6c --- /dev/null +++ b/client-go/applyconfigurations/compute/v1alpha1/reservation.go @@ -0,0 +1,251 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + internal "github.com/ironcore-dev/ironcore/client-go/applyconfigurations/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ReservationApplyConfiguration represents a declarative configuration of the Reservation type for use +// with apply. +type ReservationApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *ReservationSpecApplyConfiguration `json:"spec,omitempty"` + Status *ReservationStatusApplyConfiguration `json:"status,omitempty"` +} + +// Reservation constructs a declarative configuration of the Reservation type for use with +// apply. +func Reservation(name, namespace string) *ReservationApplyConfiguration { + b := &ReservationApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("Reservation") + b.WithAPIVersion("compute.ironcore.dev/v1alpha1") + return b +} + +// ExtractReservation extracts the applied configuration owned by fieldManager from +// reservation. If no managedFields are found in reservation for fieldManager, a +// ReservationApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// reservation must be a unmodified Reservation API object that was retrieved from the Kubernetes API. +// ExtractReservation provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractReservation(reservation *computev1alpha1.Reservation, fieldManager string) (*ReservationApplyConfiguration, error) { + return extractReservation(reservation, fieldManager, "") +} + +// ExtractReservationStatus is the same as ExtractReservation except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractReservationStatus(reservation *computev1alpha1.Reservation, fieldManager string) (*ReservationApplyConfiguration, error) { + return extractReservation(reservation, fieldManager, "status") +} + +func extractReservation(reservation *computev1alpha1.Reservation, fieldManager string, subresource string) (*ReservationApplyConfiguration, error) { + b := &ReservationApplyConfiguration{} + err := managedfields.ExtractInto(reservation, internal.Parser().Type("com.github.ironcore-dev.ironcore.api.compute.v1alpha1.Reservation"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(reservation.Name) + b.WithNamespace(reservation.Namespace) + + b.WithKind("Reservation") + b.WithAPIVersion("compute.ironcore.dev/v1alpha1") + return b, nil +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithKind(value string) *ReservationApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithAPIVersion(value string) *ReservationApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithName(value string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithGenerateName(value string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithNamespace(value string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithUID(value types.UID) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithResourceVersion(value string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithGeneration(value int64) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithCreationTimestamp(value metav1.Time) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ReservationApplyConfiguration) WithLabels(entries map[string]string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ReservationApplyConfiguration) WithAnnotations(entries map[string]string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ReservationApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ReservationApplyConfiguration) WithFinalizers(values ...string) *ReservationApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ReservationApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithSpec(value *ReservationSpecApplyConfiguration) *ReservationApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ReservationApplyConfiguration) WithStatus(value *ReservationStatusApplyConfiguration) *ReservationApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ReservationApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/client-go/applyconfigurations/compute/v1alpha1/reservationcondition.go b/client-go/applyconfigurations/compute/v1alpha1/reservationcondition.go new file mode 100644 index 000000000..f1ea576bd --- /dev/null +++ b/client-go/applyconfigurations/compute/v1alpha1/reservationcondition.go @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ReservationConditionApplyConfiguration represents a declarative configuration of the ReservationCondition type for use +// with apply. +type ReservationConditionApplyConfiguration struct { + Type *computev1alpha1.ReservationConditionType `json:"type,omitempty"` + Status *v1.ConditionStatus `json:"status,omitempty"` + Reason *string `json:"reason,omitempty"` + Message *string `json:"message,omitempty"` + ObservedGeneration *int64 `json:"observedGeneration,omitempty"` + LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"` +} + +// ReservationConditionApplyConfiguration constructs a declarative configuration of the ReservationCondition type for use with +// apply. +func ReservationCondition() *ReservationConditionApplyConfiguration { + return &ReservationConditionApplyConfiguration{} +} + +// WithType sets the Type field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Type field is set to the value of the last call. +func (b *ReservationConditionApplyConfiguration) WithType(value computev1alpha1.ReservationConditionType) *ReservationConditionApplyConfiguration { + b.Type = &value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ReservationConditionApplyConfiguration) WithStatus(value v1.ConditionStatus) *ReservationConditionApplyConfiguration { + b.Status = &value + return b +} + +// WithReason sets the Reason field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Reason field is set to the value of the last call. +func (b *ReservationConditionApplyConfiguration) WithReason(value string) *ReservationConditionApplyConfiguration { + b.Reason = &value + return b +} + +// WithMessage sets the Message field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Message field is set to the value of the last call. +func (b *ReservationConditionApplyConfiguration) WithMessage(value string) *ReservationConditionApplyConfiguration { + b.Message = &value + return b +} + +// WithObservedGeneration sets the ObservedGeneration field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ObservedGeneration field is set to the value of the last call. +func (b *ReservationConditionApplyConfiguration) WithObservedGeneration(value int64) *ReservationConditionApplyConfiguration { + b.ObservedGeneration = &value + return b +} + +// WithLastTransitionTime sets the LastTransitionTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastTransitionTime field is set to the value of the last call. +func (b *ReservationConditionApplyConfiguration) WithLastTransitionTime(value metav1.Time) *ReservationConditionApplyConfiguration { + b.LastTransitionTime = &value + return b +} diff --git a/client-go/applyconfigurations/compute/v1alpha1/reservationpoolstatus.go b/client-go/applyconfigurations/compute/v1alpha1/reservationpoolstatus.go new file mode 100644 index 000000000..7466bd8f1 --- /dev/null +++ b/client-go/applyconfigurations/compute/v1alpha1/reservationpoolstatus.go @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" +) + +// ReservationPoolStatusApplyConfiguration represents a declarative configuration of the ReservationPoolStatus type for use +// with apply. +type ReservationPoolStatusApplyConfiguration struct { + Name *string `json:"ref,omitempty"` + State *computev1alpha1.ReservationState `json:"state,omitempty"` +} + +// ReservationPoolStatusApplyConfiguration constructs a declarative configuration of the ReservationPoolStatus type for use with +// apply. +func ReservationPoolStatus() *ReservationPoolStatusApplyConfiguration { + return &ReservationPoolStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ReservationPoolStatusApplyConfiguration) WithName(value string) *ReservationPoolStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithState sets the State field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the State field is set to the value of the last call. +func (b *ReservationPoolStatusApplyConfiguration) WithState(value computev1alpha1.ReservationState) *ReservationPoolStatusApplyConfiguration { + b.State = &value + return b +} diff --git a/client-go/applyconfigurations/compute/v1alpha1/reservationspec.go b/client-go/applyconfigurations/compute/v1alpha1/reservationspec.go new file mode 100644 index 000000000..a8d31d1ca --- /dev/null +++ b/client-go/applyconfigurations/compute/v1alpha1/reservationspec.go @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1" + v1 "k8s.io/api/core/v1" +) + +// ReservationSpecApplyConfiguration represents a declarative configuration of the ReservationSpec type for use +// with apply. +type ReservationSpecApplyConfiguration struct { + Pools []v1.LocalObjectReference `json:"pools,omitempty"` + Resources *corev1alpha1.ResourceList `json:"resources,omitempty"` +} + +// ReservationSpecApplyConfiguration constructs a declarative configuration of the ReservationSpec type for use with +// apply. +func ReservationSpec() *ReservationSpecApplyConfiguration { + return &ReservationSpecApplyConfiguration{} +} + +// WithPools adds the given value to the Pools field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Pools field. +func (b *ReservationSpecApplyConfiguration) WithPools(values ...v1.LocalObjectReference) *ReservationSpecApplyConfiguration { + for i := range values { + b.Pools = append(b.Pools, values[i]) + } + return b +} + +// WithResources sets the Resources field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resources field is set to the value of the last call. +func (b *ReservationSpecApplyConfiguration) WithResources(value corev1alpha1.ResourceList) *ReservationSpecApplyConfiguration { + b.Resources = &value + return b +} diff --git a/client-go/applyconfigurations/compute/v1alpha1/reservationstatus.go b/client-go/applyconfigurations/compute/v1alpha1/reservationstatus.go new file mode 100644 index 000000000..028b74d96 --- /dev/null +++ b/client-go/applyconfigurations/compute/v1alpha1/reservationstatus.go @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// ReservationStatusApplyConfiguration represents a declarative configuration of the ReservationStatus type for use +// with apply. +type ReservationStatusApplyConfiguration struct { + Pools []ReservationPoolStatusApplyConfiguration `json:"pools,omitempty"` + Conditions []ReservationConditionApplyConfiguration `json:"conditions,omitempty"` +} + +// ReservationStatusApplyConfiguration constructs a declarative configuration of the ReservationStatus type for use with +// apply. +func ReservationStatus() *ReservationStatusApplyConfiguration { + return &ReservationStatusApplyConfiguration{} +} + +// WithPools adds the given value to the Pools field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Pools field. +func (b *ReservationStatusApplyConfiguration) WithPools(values ...*ReservationPoolStatusApplyConfiguration) *ReservationStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithPools") + } + b.Pools = append(b.Pools, *values[i]) + } + return b +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *ReservationStatusApplyConfiguration) WithConditions(values ...*ReservationConditionApplyConfiguration) *ReservationStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} diff --git a/client-go/applyconfigurations/internal/internal.go b/client-go/applyconfigurations/internal/internal.go index 0d72ec8ae..de7bf0c6a 100644 --- a/client-go/applyconfigurations/internal/internal.go +++ b/client-go/applyconfigurations/internal/internal.go @@ -389,6 +389,90 @@ var schemaYAML = typed.YAMLObject(`types: - name: state type: scalar: string +- name: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.Reservation + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationSpec + default: {} + - name: status + type: + namedType: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationStatus + default: {} +- name: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationCondition + map: + fields: + - name: lastTransitionTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: message + type: + scalar: string + default: "" + - name: observedGeneration + type: + scalar: numeric + - name: reason + type: + scalar: string + default: "" + - name: status + type: + scalar: string + default: "" + - name: type + type: + scalar: string + default: "" +- name: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationPoolStatus + map: + fields: + - name: ref + type: + scalar: string + - name: state + type: + scalar: string +- name: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationSpec + map: + fields: + - name: pools + type: + list: + elementType: + namedType: io.k8s.api.core.v1.LocalObjectReference + elementRelationship: atomic + - name: resources + type: + map: + elementType: + namedType: io.k8s.apimachinery.pkg.api.resource.Quantity +- name: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationCondition + elementRelationship: atomic + - name: pools + type: + list: + elementType: + namedType: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.ReservationPoolStatus + elementRelationship: atomic - name: com.github.ironcore-dev.ironcore.api.compute.v1alpha1.Volume map: fields: diff --git a/client-go/applyconfigurations/utils.go b/client-go/applyconfigurations/utils.go index af14dfdba..a4654f7cf 100644 --- a/client-go/applyconfigurations/utils.go +++ b/client-go/applyconfigurations/utils.go @@ -63,6 +63,16 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &computev1alpha1.NetworkInterfaceSourceApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NetworkInterfaceStatus"): return &computev1alpha1.NetworkInterfaceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("Reservation"): + return &computev1alpha1.ReservationApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ReservationCondition"): + return &computev1alpha1.ReservationConditionApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ReservationPoolStatus"): + return &computev1alpha1.ReservationPoolStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ReservationSpec"): + return &computev1alpha1.ReservationSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ReservationStatus"): + return &computev1alpha1.ReservationStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Volume"): return &computev1alpha1.VolumeApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("VolumeSource"): diff --git a/client-go/informers/externalversions/compute/v1alpha1/interface.go b/client-go/informers/externalversions/compute/v1alpha1/interface.go index 97111509a..3edbd25d0 100644 --- a/client-go/informers/externalversions/compute/v1alpha1/interface.go +++ b/client-go/informers/externalversions/compute/v1alpha1/interface.go @@ -17,6 +17,8 @@ type Interface interface { MachineClasses() MachineClassInformer // MachinePools returns a MachinePoolInformer. MachinePools() MachinePoolInformer + // Reservations returns a ReservationInformer. + Reservations() ReservationInformer } type version struct { @@ -44,3 +46,8 @@ func (v *version) MachineClasses() MachineClassInformer { func (v *version) MachinePools() MachinePoolInformer { return &machinePoolInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } + +// Reservations returns a ReservationInformer. +func (v *version) Reservations() ReservationInformer { + return &reservationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/client-go/informers/externalversions/compute/v1alpha1/reservation.go b/client-go/informers/externalversions/compute/v1alpha1/reservation.go new file mode 100644 index 000000000..33d73a91a --- /dev/null +++ b/client-go/informers/externalversions/compute/v1alpha1/reservation.go @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + apicomputev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + internalinterfaces "github.com/ironcore-dev/ironcore/client-go/informers/externalversions/internalinterfaces" + versioned "github.com/ironcore-dev/ironcore/client-go/ironcore/versioned" + computev1alpha1 "github.com/ironcore-dev/ironcore/client-go/listers/compute/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ReservationInformer provides access to a shared informer and lister for +// Reservations. +type ReservationInformer interface { + Informer() cache.SharedIndexInformer + Lister() computev1alpha1.ReservationLister +} + +type reservationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewReservationInformer constructs a new informer for Reservation type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewReservationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredReservationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredReservationInformer constructs a new informer for Reservation type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredReservationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ComputeV1alpha1().Reservations(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ComputeV1alpha1().Reservations(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ComputeV1alpha1().Reservations(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ComputeV1alpha1().Reservations(namespace).Watch(ctx, options) + }, + }, + &apicomputev1alpha1.Reservation{}, + resyncPeriod, + indexers, + ) +} + +func (f *reservationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredReservationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *reservationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apicomputev1alpha1.Reservation{}, f.defaultInformer) +} + +func (f *reservationInformer) Lister() computev1alpha1.ReservationLister { + return computev1alpha1.NewReservationLister(f.Informer().GetIndexer()) +} diff --git a/client-go/informers/externalversions/generic.go b/client-go/informers/externalversions/generic.go index 2889845ae..cd158808a 100644 --- a/client-go/informers/externalversions/generic.go +++ b/client-go/informers/externalversions/generic.go @@ -50,6 +50,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Compute().V1alpha1().MachineClasses().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("machinepools"): return &genericInformer{resource: resource.GroupResource(), informer: f.Compute().V1alpha1().MachinePools().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("reservations"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Compute().V1alpha1().Reservations().Informer()}, nil // Group=core.ironcore.dev, Version=v1alpha1 case corev1alpha1.SchemeGroupVersion.WithResource("resourcequotas"): diff --git a/client-go/ironcore/versioned/typed/compute/v1alpha1/compute_client.go b/client-go/ironcore/versioned/typed/compute/v1alpha1/compute_client.go index 347030c3a..f4aeb1332 100644 --- a/client-go/ironcore/versioned/typed/compute/v1alpha1/compute_client.go +++ b/client-go/ironcore/versioned/typed/compute/v1alpha1/compute_client.go @@ -18,6 +18,7 @@ type ComputeV1alpha1Interface interface { MachinesGetter MachineClassesGetter MachinePoolsGetter + ReservationsGetter } // ComputeV1alpha1Client is used to interact with features provided by the compute.ironcore.dev group. @@ -37,6 +38,10 @@ func (c *ComputeV1alpha1Client) MachinePools() MachinePoolInterface { return newMachinePools(c) } +func (c *ComputeV1alpha1Client) Reservations(namespace string) ReservationInterface { + return newReservations(c, namespace) +} + // NewForConfig creates a new ComputeV1alpha1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). diff --git a/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_compute_client.go b/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_compute_client.go index 39c979a4b..ae38dc963 100644 --- a/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_compute_client.go +++ b/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_compute_client.go @@ -27,6 +27,10 @@ func (c *FakeComputeV1alpha1) MachinePools() v1alpha1.MachinePoolInterface { return newFakeMachinePools(c) } +func (c *FakeComputeV1alpha1) Reservations(namespace string) v1alpha1.ReservationInterface { + return newFakeReservations(c, namespace) +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeComputeV1alpha1) RESTClient() rest.Interface { diff --git a/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_reservation.go b/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_reservation.go new file mode 100644 index 000000000..94e748989 --- /dev/null +++ b/client-go/ironcore/versioned/typed/compute/v1alpha1/fake/fake_reservation.go @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + computev1alpha1 "github.com/ironcore-dev/ironcore/client-go/applyconfigurations/compute/v1alpha1" + typedcomputev1alpha1 "github.com/ironcore-dev/ironcore/client-go/ironcore/versioned/typed/compute/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeReservations implements ReservationInterface +type fakeReservations struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.Reservation, *v1alpha1.ReservationList, *computev1alpha1.ReservationApplyConfiguration] + Fake *FakeComputeV1alpha1 +} + +func newFakeReservations(fake *FakeComputeV1alpha1, namespace string) typedcomputev1alpha1.ReservationInterface { + return &fakeReservations{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.Reservation, *v1alpha1.ReservationList, *computev1alpha1.ReservationApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("reservations"), + v1alpha1.SchemeGroupVersion.WithKind("Reservation"), + func() *v1alpha1.Reservation { return &v1alpha1.Reservation{} }, + func() *v1alpha1.ReservationList { return &v1alpha1.ReservationList{} }, + func(dst, src *v1alpha1.ReservationList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.ReservationList) []*v1alpha1.Reservation { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.ReservationList, items []*v1alpha1.Reservation) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/client-go/ironcore/versioned/typed/compute/v1alpha1/generated_expansion.go b/client-go/ironcore/versioned/typed/compute/v1alpha1/generated_expansion.go index 34bdf7a15..345fcfe54 100644 --- a/client-go/ironcore/versioned/typed/compute/v1alpha1/generated_expansion.go +++ b/client-go/ironcore/versioned/typed/compute/v1alpha1/generated_expansion.go @@ -10,3 +10,5 @@ type MachineExpansion interface{} type MachineClassExpansion interface{} type MachinePoolExpansion interface{} + +type ReservationExpansion interface{} diff --git a/client-go/ironcore/versioned/typed/compute/v1alpha1/reservation.go b/client-go/ironcore/versioned/typed/compute/v1alpha1/reservation.go new file mode 100644 index 000000000..3b2c8bc84 --- /dev/null +++ b/client-go/ironcore/versioned/typed/compute/v1alpha1/reservation.go @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + applyconfigurationscomputev1alpha1 "github.com/ironcore-dev/ironcore/client-go/applyconfigurations/compute/v1alpha1" + scheme "github.com/ironcore-dev/ironcore/client-go/ironcore/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// ReservationsGetter has a method to return a ReservationInterface. +// A group's client should implement this interface. +type ReservationsGetter interface { + Reservations(namespace string) ReservationInterface +} + +// ReservationInterface has methods to work with Reservation resources. +type ReservationInterface interface { + Create(ctx context.Context, reservation *computev1alpha1.Reservation, opts v1.CreateOptions) (*computev1alpha1.Reservation, error) + Update(ctx context.Context, reservation *computev1alpha1.Reservation, opts v1.UpdateOptions) (*computev1alpha1.Reservation, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, reservation *computev1alpha1.Reservation, opts v1.UpdateOptions) (*computev1alpha1.Reservation, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*computev1alpha1.Reservation, error) + List(ctx context.Context, opts v1.ListOptions) (*computev1alpha1.ReservationList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *computev1alpha1.Reservation, err error) + Apply(ctx context.Context, reservation *applyconfigurationscomputev1alpha1.ReservationApplyConfiguration, opts v1.ApplyOptions) (result *computev1alpha1.Reservation, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, reservation *applyconfigurationscomputev1alpha1.ReservationApplyConfiguration, opts v1.ApplyOptions) (result *computev1alpha1.Reservation, err error) + ReservationExpansion +} + +// reservations implements ReservationInterface +type reservations struct { + *gentype.ClientWithListAndApply[*computev1alpha1.Reservation, *computev1alpha1.ReservationList, *applyconfigurationscomputev1alpha1.ReservationApplyConfiguration] +} + +// newReservations returns a Reservations +func newReservations(c *ComputeV1alpha1Client, namespace string) *reservations { + return &reservations{ + gentype.NewClientWithListAndApply[*computev1alpha1.Reservation, *computev1alpha1.ReservationList, *applyconfigurationscomputev1alpha1.ReservationApplyConfiguration]( + "reservations", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *computev1alpha1.Reservation { return &computev1alpha1.Reservation{} }, + func() *computev1alpha1.ReservationList { return &computev1alpha1.ReservationList{} }, + ), + } +} diff --git a/client-go/listers/compute/v1alpha1/expansion_generated.go b/client-go/listers/compute/v1alpha1/expansion_generated.go index 84b77ce16..ca63aa7c8 100644 --- a/client-go/listers/compute/v1alpha1/expansion_generated.go +++ b/client-go/listers/compute/v1alpha1/expansion_generated.go @@ -20,3 +20,11 @@ type MachineClassListerExpansion interface{} // MachinePoolListerExpansion allows custom methods to be added to // MachinePoolLister. type MachinePoolListerExpansion interface{} + +// ReservationListerExpansion allows custom methods to be added to +// ReservationLister. +type ReservationListerExpansion interface{} + +// ReservationNamespaceListerExpansion allows custom methods to be added to +// ReservationNamespaceLister. +type ReservationNamespaceListerExpansion interface{} diff --git a/client-go/listers/compute/v1alpha1/reservation.go b/client-go/listers/compute/v1alpha1/reservation.go new file mode 100644 index 000000000..f4a869beb --- /dev/null +++ b/client-go/listers/compute/v1alpha1/reservation.go @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// ReservationLister helps list Reservations. +// All objects returned here must be treated as read-only. +type ReservationLister interface { + // List lists all Reservations in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*computev1alpha1.Reservation, err error) + // Reservations returns an object that can list and get Reservations. + Reservations(namespace string) ReservationNamespaceLister + ReservationListerExpansion +} + +// reservationLister implements the ReservationLister interface. +type reservationLister struct { + listers.ResourceIndexer[*computev1alpha1.Reservation] +} + +// NewReservationLister returns a new ReservationLister. +func NewReservationLister(indexer cache.Indexer) ReservationLister { + return &reservationLister{listers.New[*computev1alpha1.Reservation](indexer, computev1alpha1.Resource("reservation"))} +} + +// Reservations returns an object that can list and get Reservations. +func (s *reservationLister) Reservations(namespace string) ReservationNamespaceLister { + return reservationNamespaceLister{listers.NewNamespaced[*computev1alpha1.Reservation](s.ResourceIndexer, namespace)} +} + +// ReservationNamespaceLister helps list and get Reservations. +// All objects returned here must be treated as read-only. +type ReservationNamespaceLister interface { + // List lists all Reservations in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*computev1alpha1.Reservation, err error) + // Get retrieves the Reservation from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*computev1alpha1.Reservation, error) + ReservationNamespaceListerExpansion +} + +// reservationNamespaceLister implements the ReservationNamespaceLister +// interface. +type reservationNamespaceLister struct { + listers.ResourceIndexer[*computev1alpha1.Reservation] +} diff --git a/client-go/openapi/api_violations.report b/client-go/openapi/api_violations.report index a4c8c3576..37f562c48 100644 --- a/client-go/openapi/api_violations.report +++ b/client-go/openapi/api_violations.report @@ -8,6 +8,9 @@ API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compu API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,MachineSpec,Volumes API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,MachineStatus,NetworkInterfaces API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,MachineStatus,Volumes +API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,ReservationSpec,Pools +API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,ReservationStatus,Conditions +API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,ReservationStatus,Pools API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/core/v1alpha1,ResourceScopeSelector,MatchExpressions API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/core/v1alpha1,ResourceScopeSelectorRequirement,Values API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/ipam/v1alpha1,PrefixStatus,Used @@ -46,6 +49,7 @@ API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/stora API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/storage/v1alpha1,VolumeSpec,Tolerations API rule violation: list_type_missing,github.com/ironcore-dev/ironcore/api/storage/v1alpha1,VolumeStatus,Conditions API rule violation: names_match,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,MachineSpec,ImagePullSecretRef +API rule violation: names_match,github.com/ironcore-dev/ironcore/api/compute/v1alpha1,ReservationPoolStatus,Name API rule violation: names_match,github.com/ironcore-dev/ironcore/api/networking/v1alpha1,LoadBalancerSpec,IPs API rule violation: names_match,github.com/ironcore-dev/ironcore/api/networking/v1alpha1,LoadBalancerStatus,IPs API rule violation: names_match,github.com/ironcore-dev/ironcore/api/networking/v1alpha1,NATGatewayStatus,IPs diff --git a/client-go/openapi/zz_generated.openapi.go b/client-go/openapi/zz_generated.openapi.go index 212643d59..690a5aee4 100644 --- a/client-go/openapi/zz_generated.openapi.go +++ b/client-go/openapi/zz_generated.openapi.go @@ -50,6 +50,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.NetworkInterface": schema_ironcore_api_compute_v1alpha1_NetworkInterface(ref), "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.NetworkInterfaceSource": schema_ironcore_api_compute_v1alpha1_NetworkInterfaceSource(ref), "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.NetworkInterfaceStatus": schema_ironcore_api_compute_v1alpha1_NetworkInterfaceStatus(ref), + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.Reservation": schema_ironcore_api_compute_v1alpha1_Reservation(ref), + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationCondition": schema_ironcore_api_compute_v1alpha1_ReservationCondition(ref), + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationList": schema_ironcore_api_compute_v1alpha1_ReservationList(ref), + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationPoolStatus": schema_ironcore_api_compute_v1alpha1_ReservationPoolStatus(ref), + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationSpec": schema_ironcore_api_compute_v1alpha1_ReservationSpec(ref), + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationStatus": schema_ironcore_api_compute_v1alpha1_ReservationStatus(ref), "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.Volume": schema_ironcore_api_compute_v1alpha1_Volume(ref), "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.VolumeSource": schema_ironcore_api_compute_v1alpha1_VolumeSource(ref), "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.VolumeStatus": schema_ironcore_api_compute_v1alpha1_VolumeStatus(ref), @@ -1714,6 +1720,272 @@ func schema_ironcore_api_compute_v1alpha1_NetworkInterfaceStatus(ref common.Refe } } +func schema_ironcore_api_compute_v1alpha1_Reservation(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Reservation is the Schema for the machines API", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationSpec", "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_ironcore_api_compute_v1alpha1_ReservationCondition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ReservationCondition is one of the conditions of a volume.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type is the type of the condition.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "Status is the status of the condition.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "Reason is a machine-readable indication of why the condition is in a certain state.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "Message is a human-readable explanation of why the condition has a certain reason / state.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "observedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "ObservedGeneration represents the .metadata.generation that the condition was set based upon.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "lastTransitionTime": { + SchemaProps: spec.SchemaProps{ + Description: "LastTransitionTime is the last time the status of a condition has transitioned from one state to another.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + Required: []string{"type", "status", "reason", "message"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_ironcore_api_compute_v1alpha1_ReservationList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ReservationList contains a list of Reservation", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore/api/compute/v1alpha1.Reservation"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.Reservation", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_ironcore_api_compute_v1alpha1_ReservationPoolStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "ref": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "state": { + SchemaProps: spec.SchemaProps{ + Description: "Possible enum values:\n - `\"Accepted\"` means the pool accepted the reservation and reserved the requested resources.\n - `\"Pending\"` means the Reservation is being reconciled.\n - `\"Rejected\"` means the pool rejected the reservation.", + Type: []string{"string"}, + Format: "", + Enum: []interface{}{"Accepted", "Pending", "Rejected"}, + }, + }, + }, + }, + }, + } +} + +func schema_ironcore_api_compute_v1alpha1_ReservationSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ReservationSpec defines the desired state of Reservation", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "pools": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), + }, + }, + }, + }, + }, + "resources": { + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + }, + Required: []string{"pools"}, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_ironcore_api_compute_v1alpha1_ReservationStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ReservationStatus defines the observed state of Reservation", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "pools": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationPoolStatus"), + }, + }, + }, + }, + }, + "conditions": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationCondition"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationCondition", "github.com/ironcore-dev/ironcore/api/compute/v1alpha1.ReservationPoolStatus"}, + } +} + func schema_ironcore_api_compute_v1alpha1_Volume(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/config/apiserver/rbac/machinepool_role.yaml b/config/apiserver/rbac/machinepool_role.yaml index df3c34b8b..672c27e2d 100644 --- a/config/apiserver/rbac/machinepool_role.yaml +++ b/config/apiserver/rbac/machinepool_role.yaml @@ -73,6 +73,7 @@ rules: resources: - machinepools/status - machines/status + - reservations/status verbs: - get - patch @@ -81,6 +82,7 @@ rules: - compute.ironcore.dev resources: - machines + - reservations verbs: - get - list @@ -91,6 +93,7 @@ rules: - compute.ironcore.dev resources: - machines/finalizers + - reservations/finalizers verbs: - update - apiGroups: diff --git a/config/machinepoollet-broker/broker-rbac/role.yaml b/config/machinepoollet-broker/broker-rbac/role.yaml index 8cfd86258..d56b3b30e 100644 --- a/config/machinepoollet-broker/broker-rbac/role.yaml +++ b/config/machinepoollet-broker/broker-rbac/role.yaml @@ -28,6 +28,7 @@ rules: - compute.ironcore.dev resources: - machines + - reservations verbs: - create - delete diff --git a/config/machinepoollet-broker/poollet-rbac/role.yaml b/config/machinepoollet-broker/poollet-rbac/role.yaml index 26f4f1faa..a76a52349 100644 --- a/config/machinepoollet-broker/poollet-rbac/role.yaml +++ b/config/machinepoollet-broker/poollet-rbac/role.yaml @@ -73,6 +73,7 @@ rules: resources: - machinepools/status - machines/status + - reservations/status verbs: - get - patch @@ -81,6 +82,7 @@ rules: - compute.ironcore.dev resources: - machines + - reservations verbs: - get - list @@ -91,6 +93,7 @@ rules: - compute.ironcore.dev resources: - machines/finalizers + - reservations/finalizers verbs: - update - apiGroups: diff --git a/internal/apis/compute/machinereservation_types.go b/internal/apis/compute/machinereservation_types.go new file mode 100644 index 000000000..540ca38b6 --- /dev/null +++ b/internal/apis/compute/machinereservation_types.go @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package compute + +import ( + "github.com/ironcore-dev/ironcore/internal/apis/core" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ReservationSpec defines the desired state of Reservation +type ReservationSpec struct { + Pools []corev1.LocalObjectReference + Resources core.ResourceList +} + +// ReservationStatus defines the observed state of Reservation +type ReservationStatus struct { + Pools []ReservationPoolStatus + Conditions []ReservationCondition +} + +// ReservationState is the state of a Reservation. +// +enum +type ReservationState string + +const ( + // ReservationStatePending means the Reservation is being reconciled. + ReservationStatePending MachineState = "Pending" + // ReservationStateAccepted means the pool accepted the reservation and reserved the requested resources. + ReservationStateAccepted MachineState = "Accepted" + // ReservationStateRejected means the pool rejected the reservation. + ReservationStateRejected MachineState = "Rejected" +) + +type ReservationPoolStatus struct { + Name string + State ReservationState +} + +// ReservationConditionType is a type a ReservationCondition can have. +type ReservationConditionType string + +// ReservationCondition is one of the conditions of a volume. +type ReservationCondition struct { + // Type is the type of the condition. + Type ReservationConditionType + // Status is the status of the condition. + Status corev1.ConditionStatus + // Reason is a machine-readable indication of why the condition is in a certain state. + Reason string + // Message is a human-readable explanation of why the condition has a certain reason / state. + Message string + // ObservedGeneration represents the .metadata.generation that the condition was set based upon. + ObservedGeneration int64 + // LastTransitionTime is the last time the status of a condition has transitioned from one state to another. + LastTransitionTime metav1.Time +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Reservation is the Schema for the machines API +type Reservation struct { + metav1.TypeMeta + metav1.ObjectMeta + + Spec ReservationSpec + Status ReservationStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ReservationList contains a list of Reservation +type ReservationList struct { + metav1.TypeMeta + metav1.ListMeta + Items []Reservation +} diff --git a/internal/apis/compute/register.go b/internal/apis/compute/register.go index c2ea13215..7b7adea31 100644 --- a/internal/apis/compute/register.go +++ b/internal/apis/compute/register.go @@ -38,6 +38,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &MachineClassList{}, &MachinePool{}, &MachinePoolList{}, + &Reservation{}, + &ReservationList{}, ) return nil } diff --git a/internal/apis/compute/v1alpha1/zz_generated.conversion.go b/internal/apis/compute/v1alpha1/zz_generated.conversion.go index e4a4409a3..5e93878cc 100644 --- a/internal/apis/compute/v1alpha1/zz_generated.conversion.go +++ b/internal/apis/compute/v1alpha1/zz_generated.conversion.go @@ -255,6 +255,66 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*computev1alpha1.Reservation)(nil), (*compute.Reservation)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_Reservation_To_compute_Reservation(a.(*computev1alpha1.Reservation), b.(*compute.Reservation), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*compute.Reservation)(nil), (*computev1alpha1.Reservation)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_compute_Reservation_To_v1alpha1_Reservation(a.(*compute.Reservation), b.(*computev1alpha1.Reservation), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*computev1alpha1.ReservationCondition)(nil), (*compute.ReservationCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ReservationCondition_To_compute_ReservationCondition(a.(*computev1alpha1.ReservationCondition), b.(*compute.ReservationCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*compute.ReservationCondition)(nil), (*computev1alpha1.ReservationCondition)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_compute_ReservationCondition_To_v1alpha1_ReservationCondition(a.(*compute.ReservationCondition), b.(*computev1alpha1.ReservationCondition), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*computev1alpha1.ReservationList)(nil), (*compute.ReservationList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ReservationList_To_compute_ReservationList(a.(*computev1alpha1.ReservationList), b.(*compute.ReservationList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*compute.ReservationList)(nil), (*computev1alpha1.ReservationList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_compute_ReservationList_To_v1alpha1_ReservationList(a.(*compute.ReservationList), b.(*computev1alpha1.ReservationList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*computev1alpha1.ReservationPoolStatus)(nil), (*compute.ReservationPoolStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ReservationPoolStatus_To_compute_ReservationPoolStatus(a.(*computev1alpha1.ReservationPoolStatus), b.(*compute.ReservationPoolStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*compute.ReservationPoolStatus)(nil), (*computev1alpha1.ReservationPoolStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_compute_ReservationPoolStatus_To_v1alpha1_ReservationPoolStatus(a.(*compute.ReservationPoolStatus), b.(*computev1alpha1.ReservationPoolStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*computev1alpha1.ReservationSpec)(nil), (*compute.ReservationSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ReservationSpec_To_compute_ReservationSpec(a.(*computev1alpha1.ReservationSpec), b.(*compute.ReservationSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*compute.ReservationSpec)(nil), (*computev1alpha1.ReservationSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_compute_ReservationSpec_To_v1alpha1_ReservationSpec(a.(*compute.ReservationSpec), b.(*computev1alpha1.ReservationSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*computev1alpha1.ReservationStatus)(nil), (*compute.ReservationStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ReservationStatus_To_compute_ReservationStatus(a.(*computev1alpha1.ReservationStatus), b.(*compute.ReservationStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*compute.ReservationStatus)(nil), (*computev1alpha1.ReservationStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_compute_ReservationStatus_To_v1alpha1_ReservationStatus(a.(*compute.ReservationStatus), b.(*computev1alpha1.ReservationStatus), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*computev1alpha1.Volume)(nil), (*compute.Volume)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_Volume_To_compute_Volume(a.(*computev1alpha1.Volume), b.(*compute.Volume), scope) }); err != nil { @@ -905,6 +965,156 @@ func Convert_compute_NetworkInterfaceStatus_To_v1alpha1_NetworkInterfaceStatus(i return autoConvert_compute_NetworkInterfaceStatus_To_v1alpha1_NetworkInterfaceStatus(in, out, s) } +func autoConvert_v1alpha1_Reservation_To_compute_Reservation(in *computev1alpha1.Reservation, out *compute.Reservation, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_ReservationSpec_To_compute_ReservationSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_ReservationStatus_To_compute_ReservationStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_Reservation_To_compute_Reservation is an autogenerated conversion function. +func Convert_v1alpha1_Reservation_To_compute_Reservation(in *computev1alpha1.Reservation, out *compute.Reservation, s conversion.Scope) error { + return autoConvert_v1alpha1_Reservation_To_compute_Reservation(in, out, s) +} + +func autoConvert_compute_Reservation_To_v1alpha1_Reservation(in *compute.Reservation, out *computev1alpha1.Reservation, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_compute_ReservationSpec_To_v1alpha1_ReservationSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_compute_ReservationStatus_To_v1alpha1_ReservationStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_compute_Reservation_To_v1alpha1_Reservation is an autogenerated conversion function. +func Convert_compute_Reservation_To_v1alpha1_Reservation(in *compute.Reservation, out *computev1alpha1.Reservation, s conversion.Scope) error { + return autoConvert_compute_Reservation_To_v1alpha1_Reservation(in, out, s) +} + +func autoConvert_v1alpha1_ReservationCondition_To_compute_ReservationCondition(in *computev1alpha1.ReservationCondition, out *compute.ReservationCondition, s conversion.Scope) error { + out.Type = compute.ReservationConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.Reason = in.Reason + out.Message = in.Message + out.ObservedGeneration = in.ObservedGeneration + out.LastTransitionTime = in.LastTransitionTime + return nil +} + +// Convert_v1alpha1_ReservationCondition_To_compute_ReservationCondition is an autogenerated conversion function. +func Convert_v1alpha1_ReservationCondition_To_compute_ReservationCondition(in *computev1alpha1.ReservationCondition, out *compute.ReservationCondition, s conversion.Scope) error { + return autoConvert_v1alpha1_ReservationCondition_To_compute_ReservationCondition(in, out, s) +} + +func autoConvert_compute_ReservationCondition_To_v1alpha1_ReservationCondition(in *compute.ReservationCondition, out *computev1alpha1.ReservationCondition, s conversion.Scope) error { + out.Type = computev1alpha1.ReservationConditionType(in.Type) + out.Status = v1.ConditionStatus(in.Status) + out.Reason = in.Reason + out.Message = in.Message + out.ObservedGeneration = in.ObservedGeneration + out.LastTransitionTime = in.LastTransitionTime + return nil +} + +// Convert_compute_ReservationCondition_To_v1alpha1_ReservationCondition is an autogenerated conversion function. +func Convert_compute_ReservationCondition_To_v1alpha1_ReservationCondition(in *compute.ReservationCondition, out *computev1alpha1.ReservationCondition, s conversion.Scope) error { + return autoConvert_compute_ReservationCondition_To_v1alpha1_ReservationCondition(in, out, s) +} + +func autoConvert_v1alpha1_ReservationList_To_compute_ReservationList(in *computev1alpha1.ReservationList, out *compute.ReservationList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]compute.Reservation)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1alpha1_ReservationList_To_compute_ReservationList is an autogenerated conversion function. +func Convert_v1alpha1_ReservationList_To_compute_ReservationList(in *computev1alpha1.ReservationList, out *compute.ReservationList, s conversion.Scope) error { + return autoConvert_v1alpha1_ReservationList_To_compute_ReservationList(in, out, s) +} + +func autoConvert_compute_ReservationList_To_v1alpha1_ReservationList(in *compute.ReservationList, out *computev1alpha1.ReservationList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]computev1alpha1.Reservation)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_compute_ReservationList_To_v1alpha1_ReservationList is an autogenerated conversion function. +func Convert_compute_ReservationList_To_v1alpha1_ReservationList(in *compute.ReservationList, out *computev1alpha1.ReservationList, s conversion.Scope) error { + return autoConvert_compute_ReservationList_To_v1alpha1_ReservationList(in, out, s) +} + +func autoConvert_v1alpha1_ReservationPoolStatus_To_compute_ReservationPoolStatus(in *computev1alpha1.ReservationPoolStatus, out *compute.ReservationPoolStatus, s conversion.Scope) error { + out.Name = in.Name + out.State = compute.ReservationState(in.State) + return nil +} + +// Convert_v1alpha1_ReservationPoolStatus_To_compute_ReservationPoolStatus is an autogenerated conversion function. +func Convert_v1alpha1_ReservationPoolStatus_To_compute_ReservationPoolStatus(in *computev1alpha1.ReservationPoolStatus, out *compute.ReservationPoolStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_ReservationPoolStatus_To_compute_ReservationPoolStatus(in, out, s) +} + +func autoConvert_compute_ReservationPoolStatus_To_v1alpha1_ReservationPoolStatus(in *compute.ReservationPoolStatus, out *computev1alpha1.ReservationPoolStatus, s conversion.Scope) error { + out.Name = in.Name + out.State = computev1alpha1.ReservationState(in.State) + return nil +} + +// Convert_compute_ReservationPoolStatus_To_v1alpha1_ReservationPoolStatus is an autogenerated conversion function. +func Convert_compute_ReservationPoolStatus_To_v1alpha1_ReservationPoolStatus(in *compute.ReservationPoolStatus, out *computev1alpha1.ReservationPoolStatus, s conversion.Scope) error { + return autoConvert_compute_ReservationPoolStatus_To_v1alpha1_ReservationPoolStatus(in, out, s) +} + +func autoConvert_v1alpha1_ReservationSpec_To_compute_ReservationSpec(in *computev1alpha1.ReservationSpec, out *compute.ReservationSpec, s conversion.Scope) error { + out.Pools = *(*[]v1.LocalObjectReference)(unsafe.Pointer(&in.Pools)) + out.Resources = *(*core.ResourceList)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_v1alpha1_ReservationSpec_To_compute_ReservationSpec is an autogenerated conversion function. +func Convert_v1alpha1_ReservationSpec_To_compute_ReservationSpec(in *computev1alpha1.ReservationSpec, out *compute.ReservationSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_ReservationSpec_To_compute_ReservationSpec(in, out, s) +} + +func autoConvert_compute_ReservationSpec_To_v1alpha1_ReservationSpec(in *compute.ReservationSpec, out *computev1alpha1.ReservationSpec, s conversion.Scope) error { + out.Pools = *(*[]v1.LocalObjectReference)(unsafe.Pointer(&in.Pools)) + out.Resources = *(*corev1alpha1.ResourceList)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_compute_ReservationSpec_To_v1alpha1_ReservationSpec is an autogenerated conversion function. +func Convert_compute_ReservationSpec_To_v1alpha1_ReservationSpec(in *compute.ReservationSpec, out *computev1alpha1.ReservationSpec, s conversion.Scope) error { + return autoConvert_compute_ReservationSpec_To_v1alpha1_ReservationSpec(in, out, s) +} + +func autoConvert_v1alpha1_ReservationStatus_To_compute_ReservationStatus(in *computev1alpha1.ReservationStatus, out *compute.ReservationStatus, s conversion.Scope) error { + out.Pools = *(*[]compute.ReservationPoolStatus)(unsafe.Pointer(&in.Pools)) + out.Conditions = *(*[]compute.ReservationCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1alpha1_ReservationStatus_To_compute_ReservationStatus is an autogenerated conversion function. +func Convert_v1alpha1_ReservationStatus_To_compute_ReservationStatus(in *computev1alpha1.ReservationStatus, out *compute.ReservationStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_ReservationStatus_To_compute_ReservationStatus(in, out, s) +} + +func autoConvert_compute_ReservationStatus_To_v1alpha1_ReservationStatus(in *compute.ReservationStatus, out *computev1alpha1.ReservationStatus, s conversion.Scope) error { + out.Pools = *(*[]computev1alpha1.ReservationPoolStatus)(unsafe.Pointer(&in.Pools)) + out.Conditions = *(*[]computev1alpha1.ReservationCondition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_compute_ReservationStatus_To_v1alpha1_ReservationStatus is an autogenerated conversion function. +func Convert_compute_ReservationStatus_To_v1alpha1_ReservationStatus(in *compute.ReservationStatus, out *computev1alpha1.ReservationStatus, s conversion.Scope) error { + return autoConvert_compute_ReservationStatus_To_v1alpha1_ReservationStatus(in, out, s) +} + func autoConvert_v1alpha1_Volume_To_compute_Volume(in *computev1alpha1.Volume, out *compute.Volume, s conversion.Scope) error { out.Name = in.Name if err := metav1.Convert_Pointer_string_To_string(&in.Device, &out.Device, s); err != nil { diff --git a/internal/apis/compute/validation/reservation.go b/internal/apis/compute/validation/reservation.go new file mode 100644 index 000000000..d4c3b2265 --- /dev/null +++ b/internal/apis/compute/validation/reservation.go @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package validation + +import ( + "github.com/ironcore-dev/ironcore/internal/apis/core" + + ironcorevalidation "github.com/ironcore-dev/ironcore/internal/api/validation" + "github.com/ironcore-dev/ironcore/internal/apis/compute" + apivalidation "k8s.io/apimachinery/pkg/api/validation" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +// ValidateReservation validates a Reservation object. +func ValidateReservation(reservation *compute.Reservation) field.ErrorList { + var allErrs field.ErrorList + + allErrs = append(allErrs, apivalidation.ValidateObjectMetaAccessor(reservation, true, apivalidation.NameIsDNSLabel, field.NewPath("metadata"))...) + allErrs = append(allErrs, validateReservationSpec(&reservation.Spec, field.NewPath("spec"))...) + + return allErrs +} + +// ValidateReservationUpdate validates a Reservation object before an update. +func ValidateReservationUpdate(newReservation, oldReservation *compute.Reservation) field.ErrorList { + var allErrs field.ErrorList + + allErrs = append(allErrs, apivalidation.ValidateObjectMetaAccessorUpdate(newReservation, oldReservation, field.NewPath("metadata"))...) + allErrs = append(allErrs, validateReservationSpecUpdate(&newReservation.Spec, &oldReservation.Spec, newReservation.DeletionTimestamp != nil, field.NewPath("spec"))...) + allErrs = append(allErrs, ValidateReservation(newReservation)...) + + return allErrs +} + +// validateReservationSpec validates the spec of a Reservation object. +func validateReservationSpec(reservationSpec *compute.ReservationSpec, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + + allErrs = append(allErrs, validateReservationResources(reservationSpec.Resources, fldPath.Child("resources"))...) + + return allErrs +} + +func validateReservationResources(resources core.ResourceList, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + + for name, resource := range resources { + allErrs = append(allErrs, ironcorevalidation.ValidatePositiveQuantity(resource, fldPath.Key(string(name)))...) + } + + return allErrs +} + +// validateReservationSpecUpdate validates the spec of a Reservation object before an update. +func validateReservationSpecUpdate(new, old *compute.ReservationSpec, deletionTimestampSet bool, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + + allErrs = append(allErrs, ironcorevalidation.ValidateImmutableField(new.Resources, old.Resources, fldPath.Child("resources"))...) + + return allErrs +} diff --git a/internal/apis/compute/validation/reservation_test.go b/internal/apis/compute/validation/reservation_test.go new file mode 100644 index 000000000..5f20b5af0 --- /dev/null +++ b/internal/apis/compute/validation/reservation_test.go @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package validation + +import ( + "github.com/ironcore-dev/ironcore/internal/apis/compute" + "github.com/ironcore-dev/ironcore/internal/apis/core" + . "github.com/ironcore-dev/ironcore/internal/testutils/validation" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/types" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("Reservation", func() { + DescribeTable("ValidateReservation", + func(reservation *compute.Reservation, match types.GomegaMatcher) { + errList := ValidateReservation(reservation) + Expect(errList).To(match) + }, + Entry("missing name", + &compute.Reservation{}, + ContainElement(RequiredField("metadata.name")), + ), + Entry("missing namespace", + &compute.Reservation{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, + ContainElement(RequiredField("metadata.namespace")), + ), + Entry("bad name", + &compute.Reservation{ObjectMeta: metav1.ObjectMeta{Name: "foo*"}}, + ContainElement(InvalidField("metadata.name")), + ), + Entry("bad resources", + &compute.Reservation{ + ObjectMeta: metav1.ObjectMeta{Name: "foo"}, + Spec: compute.ReservationSpec{ + Resources: map[core.ResourceName]resource.Quantity{ + core.ResourceCPU: resource.MustParse("-1"), + }, + }, + }, + ContainElement(InvalidField("spec.resources[cpu]")), + ), + ) + + DescribeTable("ValidateReservationUpdate", + func(newReservation, oldReservation *compute.Reservation, match types.GomegaMatcher) { + errList := ValidateReservationUpdate(newReservation, oldReservation) + Expect(errList).To(match) + }, + Entry("immutable resources", + &compute.Reservation{ + Spec: compute.ReservationSpec{ + Resources: map[core.ResourceName]resource.Quantity{ + core.ResourceCPU: resource.MustParse("1"), + }, + }, + }, + &compute.Reservation{ + Spec: compute.ReservationSpec{ + Resources: map[core.ResourceName]resource.Quantity{ + core.ResourceCPU: resource.MustParse("2"), + }, + }, + }, + ContainElement(ImmutableField("spec.resources")), + ), + ) +}) diff --git a/internal/apis/compute/zz_generated.deepcopy.go b/internal/apis/compute/zz_generated.deepcopy.go index 508355b25..90fd7ada0 100644 --- a/internal/apis/compute/zz_generated.deepcopy.go +++ b/internal/apis/compute/zz_generated.deepcopy.go @@ -601,6 +601,156 @@ func (in *NetworkInterfaceStatus) DeepCopy() *NetworkInterfaceStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Reservation) DeepCopyInto(out *Reservation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Reservation. +func (in *Reservation) DeepCopy() *Reservation { + if in == nil { + return nil + } + out := new(Reservation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Reservation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationCondition) DeepCopyInto(out *ReservationCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationCondition. +func (in *ReservationCondition) DeepCopy() *ReservationCondition { + if in == nil { + return nil + } + out := new(ReservationCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationList) DeepCopyInto(out *ReservationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Reservation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationList. +func (in *ReservationList) DeepCopy() *ReservationList { + if in == nil { + return nil + } + out := new(ReservationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ReservationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationPoolStatus) DeepCopyInto(out *ReservationPoolStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationPoolStatus. +func (in *ReservationPoolStatus) DeepCopy() *ReservationPoolStatus { + if in == nil { + return nil + } + out := new(ReservationPoolStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationSpec) DeepCopyInto(out *ReservationSpec) { + *out = *in + if in.Pools != nil { + in, out := &in.Pools, &out.Pools + *out = make([]v1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make(core.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationSpec. +func (in *ReservationSpec) DeepCopy() *ReservationSpec { + if in == nil { + return nil + } + out := new(ReservationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReservationStatus) DeepCopyInto(out *ReservationStatus) { + *out = *in + if in.Pools != nil { + in, out := &in.Pools, &out.Pools + *out = make([]ReservationPoolStatus, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ReservationCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReservationStatus. +func (in *ReservationStatus) DeepCopy() *ReservationStatus { + if in == nil { + return nil + } + out := new(ReservationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Volume) DeepCopyInto(out *Volume) { *out = *in diff --git a/internal/registry/compute/reservation/storage/storage.go b/internal/registry/compute/reservation/storage/storage.go new file mode 100644 index 000000000..7ee95d660 --- /dev/null +++ b/internal/registry/compute/reservation/storage/storage.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package storage + +import ( + "context" + + "github.com/ironcore-dev/ironcore/internal/apis/compute" + "github.com/ironcore-dev/ironcore/internal/registry/compute/reservation" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/storage" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" +) + +type ReservationStorage struct { + Reservation *REST + Status *StatusREST +} + +type REST struct { + *genericregistry.Store +} + +func NewStorage(optsGetter generic.RESTOptionsGetter) (ReservationStorage, error) { + store := &genericregistry.Store{ + NewFunc: func() runtime.Object { + return &compute.Reservation{} + }, + NewListFunc: func() runtime.Object { + return &compute.ReservationList{} + }, + PredicateFunc: reservation.MatchReservation, + DefaultQualifiedResource: compute.Resource("reservations"), + SingularQualifiedResource: compute.Resource("reservation"), + + CreateStrategy: reservation.Strategy, + UpdateStrategy: reservation.Strategy, + DeleteStrategy: reservation.Strategy, + + TableConvertor: newTableConvertor(), + } + + options := &generic.StoreOptions{ + RESTOptions: optsGetter, + AttrFunc: reservation.GetAttrs, + TriggerFunc: map[string]storage.IndexerFunc{}, + Indexers: reservation.Indexers(), + } + if err := store.CompleteWithOptions(options); err != nil { + return ReservationStorage{}, err + } + + statusStore := *store + statusStore.UpdateStrategy = reservation.StatusStrategy + statusStore.ResetFieldsStrategy = reservation.StatusStrategy + + return ReservationStorage{ + Reservation: &REST{store}, + Status: &StatusREST{&statusStore}, + }, nil +} + +type StatusREST struct { + store *genericregistry.Store +} + +func (r *StatusREST) New() runtime.Object { + return &compute.Reservation{} +} + +func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return r.store.Get(ctx, name, options) +} + +func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) +} + +func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return r.store.GetResetFields() +} + +func (r *StatusREST) Destroy() {} diff --git a/internal/registry/compute/reservation/storage/tableconvertor.go b/internal/registry/compute/reservation/storage/tableconvertor.go new file mode 100644 index 000000000..f93bb4441 --- /dev/null +++ b/internal/registry/compute/reservation/storage/tableconvertor.go @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package storage + +import ( + "context" + "strings" + + "github.com/ironcore-dev/ironcore/internal/apis/compute" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/api/meta/table" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type convertor struct{} + +var ( + objectMetaSwaggerDoc = metav1.ObjectMeta{}.SwaggerDoc() + + headers = []metav1.TableColumnDefinition{ + {Name: "Name", Type: "string", Format: "name", Description: objectMetaSwaggerDoc["name"]}, + {Name: "Pools", Type: "string", Format: "name", Description: objectMetaSwaggerDoc["pools"]}, + {Name: "Age", Type: "string", Format: "date", Description: objectMetaSwaggerDoc["creationTimestamp"]}, + } +) + +func newTableConvertor() *convertor { + return &convertor{} +} + +func (c *convertor) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + tab := &metav1.Table{ + ColumnDefinitions: headers, + } + + if m, err := meta.ListAccessor(obj); err == nil { + tab.ResourceVersion = m.GetResourceVersion() + tab.Continue = m.GetContinue() + } else { + if m, err := meta.CommonAccessor(obj); err == nil { + tab.ResourceVersion = m.GetResourceVersion() + } + } + + var err error + tab.Rows, err = table.MetaToTableRow(obj, func(obj runtime.Object, m metav1.Object, name, age string) (cells []interface{}, err error) { + reservation := obj.(*compute.Reservation) + + cells = append(cells, name) + if pools := reservation.Spec.Pools; len(pools) != 0 { + var poolS []string + for _, pool := range pools { + poolS = append(poolS, pool.Name) + } + cells = append(cells, strings.Join(poolS, ", ")) + } else { + cells = append(cells, "") + } + cells = append(cells, age) + + return cells, nil + }) + return tab, err +} diff --git a/internal/registry/compute/reservation/strategy.go b/internal/registry/compute/reservation/strategy.go new file mode 100644 index 000000000..9198205d5 --- /dev/null +++ b/internal/registry/compute/reservation/strategy.go @@ -0,0 +1,129 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package reservation + +import ( + "context" + "fmt" + + "github.com/ironcore-dev/ironcore/internal/api" + "github.com/ironcore-dev/ironcore/internal/apis/compute" + "github.com/ironcore-dev/ironcore/internal/apis/compute/validation" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/generic" + apisrvstorage "k8s.io/apiserver/pkg/storage" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/client-go/tools/cache" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" +) + +func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { + reservation, ok := obj.(*compute.Reservation) + if !ok { + return nil, nil, fmt.Errorf("given object is not a Reservation") + } + return reservation.Labels, SelectableFields(reservation), nil +} + +func MatchReservation(label labels.Selector, field fields.Selector) apisrvstorage.SelectionPredicate { + return apisrvstorage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: GetAttrs, + } +} + +func SelectableFields(reservation *compute.Reservation) fields.Set { + fieldsSet := make(fields.Set) + return generic.AddObjectMetaFieldsSet(fieldsSet, &reservation.ObjectMeta, true) +} + +func Indexers() *cache.Indexers { + return &cache.Indexers{} +} + +type reservationStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +var Strategy = reservationStrategy{api.Scheme, names.SimpleNameGenerator} + +func (reservationStrategy) NamespaceScoped() bool { + return true +} + +func (reservationStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { +} + +func (reservationStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { +} + +func (reservationStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { + reservation := obj.(*compute.Reservation) + return validation.ValidateReservation(reservation) +} + +func (reservationStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { + return nil +} + +func (reservationStrategy) AllowCreateOnUpdate() bool { + return false +} + +func (reservationStrategy) AllowUnconditionalUpdate() bool { + return false +} + +func (reservationStrategy) Canonicalize(obj runtime.Object) { +} + +func (reservationStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + oldReservation := old.(*compute.Reservation) + newReservation := obj.(*compute.Reservation) + return validation.ValidateReservationUpdate(newReservation, oldReservation) +} + +func (reservationStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} + +type reservationStatusStrategy struct { + reservationStrategy +} + +var StatusStrategy = reservationStatusStrategy{Strategy} + +func (reservationStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return map[fieldpath.APIVersion]*fieldpath.Set{ + "compute.ironcore.dev/v1alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("spec"), + ), + } +} + +func (reservationStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newReservation := obj.(*compute.Reservation) + oldReservation := old.(*compute.Reservation) + newReservation.Spec = oldReservation.Spec +} + +func (reservationStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + newReservation := obj.(*compute.Reservation) + oldReservation := old.(*compute.Reservation) + return validation.ValidateReservationUpdate(newReservation, oldReservation) +} + +func (reservationStatusStrategy) WarningsOnUpdate(cxt context.Context, obj, old runtime.Object) []string { + return nil +} + +type ResourceGetter interface { + Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) +} diff --git a/internal/registry/compute/rest/rest.go b/internal/registry/compute/rest/rest.go index 604e0518e..9a139df3e 100644 --- a/internal/registry/compute/rest/rest.go +++ b/internal/registry/compute/rest/rest.go @@ -11,6 +11,7 @@ import ( machinestorage "github.com/ironcore-dev/ironcore/internal/registry/compute/machine/storage" machineclassstore "github.com/ironcore-dev/ironcore/internal/registry/compute/machineclass/storage" machinepoolstorage "github.com/ironcore-dev/ironcore/internal/registry/compute/machinepool/storage" + reservationstorage "github.com/ironcore-dev/ironcore/internal/registry/compute/reservation/storage" ironcoreserializer "github.com/ironcore-dev/ironcore/internal/serializer" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" @@ -68,5 +69,13 @@ func (p StorageProvider) v1alpha1Storage(restOptionsGetter generic.RESTOptionsGe storageMap["machines/status"] = machineStorage.Status storageMap["machines/exec"] = machineStorage.Exec + reservationStorage, err := reservationstorage.NewStorage(restOptionsGetter) + if err != nil { + return storageMap, err + } + + storageMap["reservation"] = reservationStorage.Reservation + storageMap["reservation/status"] = reservationStorage.Status + return storageMap, nil } diff --git a/iri/apis/machine/machine.go b/iri/apis/machine/machine.go index d05284057..b961ca5ed 100644 --- a/iri/apis/machine/machine.go +++ b/iri/apis/machine/machine.go @@ -22,6 +22,9 @@ type RuntimeService interface { UpdateVolume(context.Context, *api.UpdateVolumeRequest) (*api.UpdateVolumeResponse, error) AttachNetworkInterface(context.Context, *api.AttachNetworkInterfaceRequest) (*api.AttachNetworkInterfaceResponse, error) DetachNetworkInterface(context.Context, *api.DetachNetworkInterfaceRequest) (*api.DetachNetworkInterfaceResponse, error) + ListReservations(context.Context, *api.ListReservationsRequest) (*api.ListReservationsResponse, error) + CreateReservation(context.Context, *api.CreateReservationRequest) (*api.CreateReservationResponse, error) + DeleteReservation(context.Context, *api.DeleteReservationRequest) (*api.DeleteReservationResponse, error) Status(context.Context, *api.StatusRequest) (*api.StatusResponse, error) Exec(context.Context, *api.ExecRequest) (*api.ExecResponse, error) } diff --git a/iri/apis/machine/v1alpha1/api.pb.go b/iri/apis/machine/v1alpha1/api.pb.go index e1228182b..bc56bfff3 100644 --- a/iri/apis/machine/v1alpha1/api.pb.go +++ b/iri/apis/machine/v1alpha1/api.pb.go @@ -24,6 +24,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type ReservationState int32 + +const ( + ReservationState_RESERVATION_STATE_PENDING ReservationState = 0 + ReservationState_RESERVATION_STATE_ACCEPTED ReservationState = 1 + ReservationState_RESERVATION_STATE_REJECTED ReservationState = 2 +) + +// Enum value maps for ReservationState. +var ( + ReservationState_name = map[int32]string{ + 0: "RESERVATION_STATE_PENDING", + 1: "RESERVATION_STATE_ACCEPTED", + 2: "RESERVATION_STATE_REJECTED", + } + ReservationState_value = map[string]int32{ + "RESERVATION_STATE_PENDING": 0, + "RESERVATION_STATE_ACCEPTED": 1, + "RESERVATION_STATE_REJECTED": 2, + } +) + +func (x ReservationState) Enum() *ReservationState { + p := new(ReservationState) + *p = x + return p +} + +func (x ReservationState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ReservationState) Descriptor() protoreflect.EnumDescriptor { + return file_machine_v1alpha1_api_proto_enumTypes[0].Descriptor() +} + +func (ReservationState) Type() protoreflect.EnumType { + return &file_machine_v1alpha1_api_proto_enumTypes[0] +} + +func (x ReservationState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ReservationState.Descriptor instead. +func (ReservationState) EnumDescriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{0} +} + type Power int32 const ( @@ -54,11 +103,11 @@ func (x Power) String() string { } func (Power) Descriptor() protoreflect.EnumDescriptor { - return file_machine_v1alpha1_api_proto_enumTypes[0].Descriptor() + return file_machine_v1alpha1_api_proto_enumTypes[1].Descriptor() } func (Power) Type() protoreflect.EnumType { - return &file_machine_v1alpha1_api_proto_enumTypes[0] + return &file_machine_v1alpha1_api_proto_enumTypes[1] } func (x Power) Number() protoreflect.EnumNumber { @@ -67,7 +116,7 @@ func (x Power) Number() protoreflect.EnumNumber { // Deprecated: Use Power.Descriptor instead. func (Power) EnumDescriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{0} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{1} } type VolumeState int32 @@ -100,11 +149,11 @@ func (x VolumeState) String() string { } func (VolumeState) Descriptor() protoreflect.EnumDescriptor { - return file_machine_v1alpha1_api_proto_enumTypes[1].Descriptor() + return file_machine_v1alpha1_api_proto_enumTypes[2].Descriptor() } func (VolumeState) Type() protoreflect.EnumType { - return &file_machine_v1alpha1_api_proto_enumTypes[1] + return &file_machine_v1alpha1_api_proto_enumTypes[2] } func (x VolumeState) Number() protoreflect.EnumNumber { @@ -113,7 +162,7 @@ func (x VolumeState) Number() protoreflect.EnumNumber { // Deprecated: Use VolumeState.Descriptor instead. func (VolumeState) EnumDescriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{1} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{2} } type NetworkInterfaceState int32 @@ -146,11 +195,11 @@ func (x NetworkInterfaceState) String() string { } func (NetworkInterfaceState) Descriptor() protoreflect.EnumDescriptor { - return file_machine_v1alpha1_api_proto_enumTypes[2].Descriptor() + return file_machine_v1alpha1_api_proto_enumTypes[3].Descriptor() } func (NetworkInterfaceState) Type() protoreflect.EnumType { - return &file_machine_v1alpha1_api_proto_enumTypes[2] + return &file_machine_v1alpha1_api_proto_enumTypes[3] } func (x NetworkInterfaceState) Number() protoreflect.EnumNumber { @@ -159,7 +208,7 @@ func (x NetworkInterfaceState) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkInterfaceState.Descriptor instead. func (NetworkInterfaceState) EnumDescriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{2} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{3} } type MachineState int32 @@ -204,11 +253,11 @@ func (x MachineState) String() string { } func (MachineState) Descriptor() protoreflect.EnumDescriptor { - return file_machine_v1alpha1_api_proto_enumTypes[3].Descriptor() + return file_machine_v1alpha1_api_proto_enumTypes[4].Descriptor() } func (MachineState) Type() protoreflect.EnumType { - return &file_machine_v1alpha1_api_proto_enumTypes[3] + return &file_machine_v1alpha1_api_proto_enumTypes[4] } func (x MachineState) Number() protoreflect.EnumNumber { @@ -217,7 +266,7 @@ func (x MachineState) Number() protoreflect.EnumNumber { // Deprecated: Use MachineState.Descriptor instead. func (MachineState) EnumDescriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{3} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{4} } type VolumeSpec struct { @@ -422,14 +471,486 @@ func (x *MachineClassCapabilities) Reset() { ms.StoreMessageInfo(mi) } -func (x *MachineClassCapabilities) String() string { +func (x *MachineClassCapabilities) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MachineClassCapabilities) ProtoMessage() {} + +func (x *MachineClassCapabilities) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MachineClassCapabilities.ProtoReflect.Descriptor instead. +func (*MachineClassCapabilities) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{3} +} + +func (x *MachineClassCapabilities) GetResources() map[string]int64 { + if x != nil { + return x.Resources + } + return nil +} + +type Machine struct { + state protoimpl.MessageState `protogen:"open.v1"` + Metadata *v1alpha1.ObjectMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + Spec *MachineSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` + Status *MachineStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Machine) Reset() { + *x = Machine{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Machine) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Machine) ProtoMessage() {} + +func (x *Machine) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Machine.ProtoReflect.Descriptor instead. +func (*Machine) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{4} +} + +func (x *Machine) GetMetadata() *v1alpha1.ObjectMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *Machine) GetSpec() *MachineSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *Machine) GetStatus() *MachineStatus { + if x != nil { + return x.Status + } + return nil +} + +type ListReservationsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Filter *ReservationFilter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListReservationsRequest) Reset() { + *x = ListReservationsRequest{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListReservationsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListReservationsRequest) ProtoMessage() {} + +func (x *ListReservationsRequest) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListReservationsRequest.ProtoReflect.Descriptor instead. +func (*ListReservationsRequest) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{5} +} + +func (x *ListReservationsRequest) GetFilter() *ReservationFilter { + if x != nil { + return x.Filter + } + return nil +} + +type ListReservationsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reservations []*Reservation `protobuf:"bytes,1,rep,name=reservations,proto3" json:"reservations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListReservationsResponse) Reset() { + *x = ListReservationsResponse{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListReservationsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListReservationsResponse) ProtoMessage() {} + +func (x *ListReservationsResponse) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListReservationsResponse.ProtoReflect.Descriptor instead. +func (*ListReservationsResponse) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{6} +} + +func (x *ListReservationsResponse) GetReservations() []*Reservation { + if x != nil { + return x.Reservations + } + return nil +} + +type CreateReservationRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reservation *Reservation `protobuf:"bytes,1,opt,name=reservation,proto3" json:"reservation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateReservationRequest) Reset() { + *x = CreateReservationRequest{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateReservationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateReservationRequest) ProtoMessage() {} + +func (x *CreateReservationRequest) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateReservationRequest.ProtoReflect.Descriptor instead. +func (*CreateReservationRequest) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{7} +} + +func (x *CreateReservationRequest) GetReservation() *Reservation { + if x != nil { + return x.Reservation + } + return nil +} + +type CreateReservationResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reservation *Reservation `protobuf:"bytes,1,opt,name=reservation,proto3" json:"reservation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateReservationResponse) Reset() { + *x = CreateReservationResponse{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateReservationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateReservationResponse) ProtoMessage() {} + +func (x *CreateReservationResponse) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateReservationResponse.ProtoReflect.Descriptor instead. +func (*CreateReservationResponse) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{8} +} + +func (x *CreateReservationResponse) GetReservation() *Reservation { + if x != nil { + return x.Reservation + } + return nil +} + +type DeleteReservationRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ReservationId string `protobuf:"bytes,1,opt,name=reservation_id,json=reservationId,proto3" json:"reservation_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteReservationRequest) Reset() { + *x = DeleteReservationRequest{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteReservationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteReservationRequest) ProtoMessage() {} + +func (x *DeleteReservationRequest) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteReservationRequest.ProtoReflect.Descriptor instead. +func (*DeleteReservationRequest) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{9} +} + +func (x *DeleteReservationRequest) GetReservationId() string { + if x != nil { + return x.ReservationId + } + return "" +} + +type DeleteReservationResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteReservationResponse) Reset() { + *x = DeleteReservationResponse{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteReservationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteReservationResponse) ProtoMessage() {} + +func (x *DeleteReservationResponse) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteReservationResponse.ProtoReflect.Descriptor instead. +func (*DeleteReservationResponse) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{10} +} + +type ReservationFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + LabelSelector map[string]string `protobuf:"bytes,2,rep,name=label_selector,json=labelSelector,proto3" json:"label_selector,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReservationFilter) Reset() { + *x = ReservationFilter{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReservationFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReservationFilter) ProtoMessage() {} + +func (x *ReservationFilter) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReservationFilter.ProtoReflect.Descriptor instead. +func (*ReservationFilter) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{11} +} + +func (x *ReservationFilter) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ReservationFilter) GetLabelSelector() map[string]string { + if x != nil { + return x.LabelSelector + } + return nil +} + +type Reservation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Metadata *v1alpha1.ObjectMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + Spec *ReservationSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` + Status *ReservationStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Reservation) Reset() { + *x = Reservation{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Reservation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reservation) ProtoMessage() {} + +func (x *Reservation) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Reservation.ProtoReflect.Descriptor instead. +func (*Reservation) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{12} +} + +func (x *Reservation) GetMetadata() *v1alpha1.ObjectMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *Reservation) GetSpec() *ReservationSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *Reservation) GetStatus() *ReservationStatus { + if x != nil { + return x.Status + } + return nil +} + +type ReservationSpec struct { + state protoimpl.MessageState `protogen:"open.v1"` + Resources map[string][]byte `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReservationSpec) Reset() { + *x = ReservationSpec{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReservationSpec) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MachineClassCapabilities) ProtoMessage() {} +func (*ReservationSpec) ProtoMessage() {} -func (x *MachineClassCapabilities) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[3] +func (x *ReservationSpec) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -440,42 +961,40 @@ func (x *MachineClassCapabilities) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MachineClassCapabilities.ProtoReflect.Descriptor instead. -func (*MachineClassCapabilities) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{3} +// Deprecated: Use ReservationSpec.ProtoReflect.Descriptor instead. +func (*ReservationSpec) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{13} } -func (x *MachineClassCapabilities) GetResources() map[string]int64 { +func (x *ReservationSpec) GetResources() map[string][]byte { if x != nil { return x.Resources } return nil } -type Machine struct { - state protoimpl.MessageState `protogen:"open.v1"` - Metadata *v1alpha1.ObjectMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - Spec *MachineSpec `protobuf:"bytes,2,opt,name=spec,proto3" json:"spec,omitempty"` - Status *MachineStatus `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` +type ReservationStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + State ReservationState `protobuf:"varint,1,opt,name=state,proto3,enum=machine.v1alpha1.ReservationState" json:"state,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Machine) Reset() { - *x = Machine{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[4] +func (x *ReservationStatus) Reset() { + *x = ReservationStatus{} + mi := &file_machine_v1alpha1_api_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Machine) String() string { +func (x *ReservationStatus) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Machine) ProtoMessage() {} +func (*ReservationStatus) ProtoMessage() {} -func (x *Machine) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[4] +func (x *ReservationStatus) ProtoReflect() protoreflect.Message { + mi := &file_machine_v1alpha1_api_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -486,30 +1005,16 @@ func (x *Machine) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Machine.ProtoReflect.Descriptor instead. -func (*Machine) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{4} -} - -func (x *Machine) GetMetadata() *v1alpha1.ObjectMetadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *Machine) GetSpec() *MachineSpec { - if x != nil { - return x.Spec - } - return nil +// Deprecated: Use ReservationStatus.ProtoReflect.Descriptor instead. +func (*ReservationStatus) Descriptor() ([]byte, []int) { + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{14} } -func (x *Machine) GetStatus() *MachineStatus { +func (x *ReservationStatus) GetState() ReservationState { if x != nil { - return x.Status + return x.State } - return nil + return ReservationState_RESERVATION_STATE_PENDING } type ImageSpec struct { @@ -521,7 +1026,7 @@ type ImageSpec struct { func (x *ImageSpec) Reset() { *x = ImageSpec{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[5] + mi := &file_machine_v1alpha1_api_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -533,7 +1038,7 @@ func (x *ImageSpec) String() string { func (*ImageSpec) ProtoMessage() {} func (x *ImageSpec) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[5] + mi := &file_machine_v1alpha1_api_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -546,7 +1051,7 @@ func (x *ImageSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageSpec.ProtoReflect.Descriptor instead. func (*ImageSpec) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{5} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{15} } func (x *ImageSpec) GetImage() string { @@ -565,7 +1070,7 @@ type EmptyDisk struct { func (x *EmptyDisk) Reset() { *x = EmptyDisk{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[6] + mi := &file_machine_v1alpha1_api_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -577,7 +1082,7 @@ func (x *EmptyDisk) String() string { func (*EmptyDisk) ProtoMessage() {} func (x *EmptyDisk) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[6] + mi := &file_machine_v1alpha1_api_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -590,7 +1095,7 @@ func (x *EmptyDisk) ProtoReflect() protoreflect.Message { // Deprecated: Use EmptyDisk.ProtoReflect.Descriptor instead. func (*EmptyDisk) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{6} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{16} } func (x *EmptyDisk) GetSizeBytes() int64 { @@ -614,7 +1119,7 @@ type VolumeConnection struct { func (x *VolumeConnection) Reset() { *x = VolumeConnection{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[7] + mi := &file_machine_v1alpha1_api_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -626,7 +1131,7 @@ func (x *VolumeConnection) String() string { func (*VolumeConnection) ProtoMessage() {} func (x *VolumeConnection) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[7] + mi := &file_machine_v1alpha1_api_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -639,7 +1144,7 @@ func (x *VolumeConnection) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeConnection.ProtoReflect.Descriptor instead. func (*VolumeConnection) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{7} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{17} } func (x *VolumeConnection) GetDriver() string { @@ -696,7 +1201,7 @@ type Volume struct { func (x *Volume) Reset() { *x = Volume{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[8] + mi := &file_machine_v1alpha1_api_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -708,7 +1213,7 @@ func (x *Volume) String() string { func (*Volume) ProtoMessage() {} func (x *Volume) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[8] + mi := &file_machine_v1alpha1_api_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -721,7 +1226,7 @@ func (x *Volume) ProtoReflect() protoreflect.Message { // Deprecated: Use Volume.ProtoReflect.Descriptor instead. func (*Volume) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{8} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{18} } func (x *Volume) GetName() string { @@ -764,7 +1269,7 @@ type NetworkInterface struct { func (x *NetworkInterface) Reset() { *x = NetworkInterface{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[9] + mi := &file_machine_v1alpha1_api_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -776,7 +1281,7 @@ func (x *NetworkInterface) String() string { func (*NetworkInterface) ProtoMessage() {} func (x *NetworkInterface) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[9] + mi := &file_machine_v1alpha1_api_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -789,7 +1294,7 @@ func (x *NetworkInterface) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkInterface.ProtoReflect.Descriptor instead. func (*NetworkInterface) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{9} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{19} } func (x *NetworkInterface) GetName() string { @@ -834,7 +1339,7 @@ type MachineSpec struct { func (x *MachineSpec) Reset() { *x = MachineSpec{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[10] + mi := &file_machine_v1alpha1_api_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -846,7 +1351,7 @@ func (x *MachineSpec) String() string { func (*MachineSpec) ProtoMessage() {} func (x *MachineSpec) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[10] + mi := &file_machine_v1alpha1_api_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -859,7 +1364,7 @@ func (x *MachineSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use MachineSpec.ProtoReflect.Descriptor instead. func (*MachineSpec) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{10} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{20} } func (x *MachineSpec) GetPower() Power { @@ -917,7 +1422,7 @@ type MachineStatus struct { func (x *MachineStatus) Reset() { *x = MachineStatus{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[11] + mi := &file_machine_v1alpha1_api_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -929,7 +1434,7 @@ func (x *MachineStatus) String() string { func (*MachineStatus) ProtoMessage() {} func (x *MachineStatus) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[11] + mi := &file_machine_v1alpha1_api_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -942,7 +1447,7 @@ func (x *MachineStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use MachineStatus.ProtoReflect.Descriptor instead. func (*MachineStatus) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{11} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{21} } func (x *MachineStatus) GetObservedGeneration() int64 { @@ -991,7 +1496,7 @@ type VolumeStatus struct { func (x *VolumeStatus) Reset() { *x = VolumeStatus{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[12] + mi := &file_machine_v1alpha1_api_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1003,7 +1508,7 @@ func (x *VolumeStatus) String() string { func (*VolumeStatus) ProtoMessage() {} func (x *VolumeStatus) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[12] + mi := &file_machine_v1alpha1_api_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1016,7 +1521,7 @@ func (x *VolumeStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeStatus.ProtoReflect.Descriptor instead. func (*VolumeStatus) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{12} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{22} } func (x *VolumeStatus) GetName() string { @@ -1051,7 +1556,7 @@ type NetworkInterfaceStatus struct { func (x *NetworkInterfaceStatus) Reset() { *x = NetworkInterfaceStatus{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[13] + mi := &file_machine_v1alpha1_api_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1063,7 +1568,7 @@ func (x *NetworkInterfaceStatus) String() string { func (*NetworkInterfaceStatus) ProtoMessage() {} func (x *NetworkInterfaceStatus) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[13] + mi := &file_machine_v1alpha1_api_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1076,7 +1581,7 @@ func (x *NetworkInterfaceStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use NetworkInterfaceStatus.ProtoReflect.Descriptor instead. func (*NetworkInterfaceStatus) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{13} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{23} } func (x *NetworkInterfaceStatus) GetName() string { @@ -1110,7 +1615,7 @@ type MachineClass struct { func (x *MachineClass) Reset() { *x = MachineClass{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[14] + mi := &file_machine_v1alpha1_api_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1122,7 +1627,7 @@ func (x *MachineClass) String() string { func (*MachineClass) ProtoMessage() {} func (x *MachineClass) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[14] + mi := &file_machine_v1alpha1_api_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1135,7 +1640,7 @@ func (x *MachineClass) ProtoReflect() protoreflect.Message { // Deprecated: Use MachineClass.ProtoReflect.Descriptor instead. func (*MachineClass) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{14} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{24} } func (x *MachineClass) GetName() string { @@ -1162,7 +1667,7 @@ type MachineClassStatus struct { func (x *MachineClassStatus) Reset() { *x = MachineClassStatus{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[15] + mi := &file_machine_v1alpha1_api_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1174,7 +1679,7 @@ func (x *MachineClassStatus) String() string { func (*MachineClassStatus) ProtoMessage() {} func (x *MachineClassStatus) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[15] + mi := &file_machine_v1alpha1_api_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1187,7 +1692,7 @@ func (x *MachineClassStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use MachineClassStatus.ProtoReflect.Descriptor instead. func (*MachineClassStatus) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{15} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{25} } func (x *MachineClassStatus) GetMachineClass() *MachineClass { @@ -1213,7 +1718,7 @@ type VersionRequest struct { func (x *VersionRequest) Reset() { *x = VersionRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[16] + mi := &file_machine_v1alpha1_api_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1225,7 +1730,7 @@ func (x *VersionRequest) String() string { func (*VersionRequest) ProtoMessage() {} func (x *VersionRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[16] + mi := &file_machine_v1alpha1_api_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1238,7 +1743,7 @@ func (x *VersionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionRequest.ProtoReflect.Descriptor instead. func (*VersionRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{16} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{26} } func (x *VersionRequest) GetVersion() string { @@ -1261,7 +1766,7 @@ type VersionResponse struct { func (x *VersionResponse) Reset() { *x = VersionResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[17] + mi := &file_machine_v1alpha1_api_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1273,7 +1778,7 @@ func (x *VersionResponse) String() string { func (*VersionResponse) ProtoMessage() {} func (x *VersionResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[17] + mi := &file_machine_v1alpha1_api_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1286,7 +1791,7 @@ func (x *VersionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead. func (*VersionResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{17} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{27} } func (x *VersionResponse) GetRuntimeName() string { @@ -1312,7 +1817,7 @@ type ListMachinesRequest struct { func (x *ListMachinesRequest) Reset() { *x = ListMachinesRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[18] + mi := &file_machine_v1alpha1_api_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1324,7 +1829,7 @@ func (x *ListMachinesRequest) String() string { func (*ListMachinesRequest) ProtoMessage() {} func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[18] + mi := &file_machine_v1alpha1_api_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1337,7 +1842,7 @@ func (x *ListMachinesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListMachinesRequest.ProtoReflect.Descriptor instead. func (*ListMachinesRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{18} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{28} } func (x *ListMachinesRequest) GetFilter() *MachineFilter { @@ -1356,7 +1861,7 @@ type ListMachinesResponse struct { func (x *ListMachinesResponse) Reset() { *x = ListMachinesResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[19] + mi := &file_machine_v1alpha1_api_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1368,7 +1873,7 @@ func (x *ListMachinesResponse) String() string { func (*ListMachinesResponse) ProtoMessage() {} func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[19] + mi := &file_machine_v1alpha1_api_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1381,7 +1886,7 @@ func (x *ListMachinesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListMachinesResponse.ProtoReflect.Descriptor instead. func (*ListMachinesResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{19} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{29} } func (x *ListMachinesResponse) GetMachines() []*Machine { @@ -1400,7 +1905,7 @@ type ListEventsRequest struct { func (x *ListEventsRequest) Reset() { *x = ListEventsRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[20] + mi := &file_machine_v1alpha1_api_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1412,7 +1917,7 @@ func (x *ListEventsRequest) String() string { func (*ListEventsRequest) ProtoMessage() {} func (x *ListEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[20] + mi := &file_machine_v1alpha1_api_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1425,7 +1930,7 @@ func (x *ListEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListEventsRequest.ProtoReflect.Descriptor instead. func (*ListEventsRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{20} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{30} } func (x *ListEventsRequest) GetFilter() *EventFilter { @@ -1444,7 +1949,7 @@ type ListEventsResponse struct { func (x *ListEventsResponse) Reset() { *x = ListEventsResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[21] + mi := &file_machine_v1alpha1_api_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1456,7 +1961,7 @@ func (x *ListEventsResponse) String() string { func (*ListEventsResponse) ProtoMessage() {} func (x *ListEventsResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[21] + mi := &file_machine_v1alpha1_api_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1469,7 +1974,7 @@ func (x *ListEventsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListEventsResponse.ProtoReflect.Descriptor instead. func (*ListEventsResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{21} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{31} } func (x *ListEventsResponse) GetEvents() []*v1alpha11.Event { @@ -1488,7 +1993,7 @@ type CreateMachineRequest struct { func (x *CreateMachineRequest) Reset() { *x = CreateMachineRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[22] + mi := &file_machine_v1alpha1_api_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1500,7 +2005,7 @@ func (x *CreateMachineRequest) String() string { func (*CreateMachineRequest) ProtoMessage() {} func (x *CreateMachineRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[22] + mi := &file_machine_v1alpha1_api_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1513,7 +2018,7 @@ func (x *CreateMachineRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateMachineRequest.ProtoReflect.Descriptor instead. func (*CreateMachineRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{22} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{32} } func (x *CreateMachineRequest) GetMachine() *Machine { @@ -1532,7 +2037,7 @@ type CreateMachineResponse struct { func (x *CreateMachineResponse) Reset() { *x = CreateMachineResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[23] + mi := &file_machine_v1alpha1_api_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1544,7 +2049,7 @@ func (x *CreateMachineResponse) String() string { func (*CreateMachineResponse) ProtoMessage() {} func (x *CreateMachineResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[23] + mi := &file_machine_v1alpha1_api_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1557,7 +2062,7 @@ func (x *CreateMachineResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateMachineResponse.ProtoReflect.Descriptor instead. func (*CreateMachineResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{23} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{33} } func (x *CreateMachineResponse) GetMachine() *Machine { @@ -1576,7 +2081,7 @@ type DeleteMachineRequest struct { func (x *DeleteMachineRequest) Reset() { *x = DeleteMachineRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[24] + mi := &file_machine_v1alpha1_api_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1588,7 +2093,7 @@ func (x *DeleteMachineRequest) String() string { func (*DeleteMachineRequest) ProtoMessage() {} func (x *DeleteMachineRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[24] + mi := &file_machine_v1alpha1_api_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1601,7 +2106,7 @@ func (x *DeleteMachineRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteMachineRequest.ProtoReflect.Descriptor instead. func (*DeleteMachineRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{24} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{34} } func (x *DeleteMachineRequest) GetMachineId() string { @@ -1619,7 +2124,7 @@ type DeleteMachineResponse struct { func (x *DeleteMachineResponse) Reset() { *x = DeleteMachineResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[25] + mi := &file_machine_v1alpha1_api_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1631,7 +2136,7 @@ func (x *DeleteMachineResponse) String() string { func (*DeleteMachineResponse) ProtoMessage() {} func (x *DeleteMachineResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[25] + mi := &file_machine_v1alpha1_api_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1644,7 +2149,7 @@ func (x *DeleteMachineResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteMachineResponse.ProtoReflect.Descriptor instead. func (*DeleteMachineResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{25} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{35} } type UpdateMachineAnnotationsRequest struct { @@ -1657,7 +2162,7 @@ type UpdateMachineAnnotationsRequest struct { func (x *UpdateMachineAnnotationsRequest) Reset() { *x = UpdateMachineAnnotationsRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[26] + mi := &file_machine_v1alpha1_api_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1669,7 +2174,7 @@ func (x *UpdateMachineAnnotationsRequest) String() string { func (*UpdateMachineAnnotationsRequest) ProtoMessage() {} func (x *UpdateMachineAnnotationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[26] + mi := &file_machine_v1alpha1_api_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1682,7 +2187,7 @@ func (x *UpdateMachineAnnotationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateMachineAnnotationsRequest.ProtoReflect.Descriptor instead. func (*UpdateMachineAnnotationsRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{26} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{36} } func (x *UpdateMachineAnnotationsRequest) GetMachineId() string { @@ -1707,7 +2212,7 @@ type UpdateMachineAnnotationsResponse struct { func (x *UpdateMachineAnnotationsResponse) Reset() { *x = UpdateMachineAnnotationsResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[27] + mi := &file_machine_v1alpha1_api_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1719,7 +2224,7 @@ func (x *UpdateMachineAnnotationsResponse) String() string { func (*UpdateMachineAnnotationsResponse) ProtoMessage() {} func (x *UpdateMachineAnnotationsResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[27] + mi := &file_machine_v1alpha1_api_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1732,7 +2237,7 @@ func (x *UpdateMachineAnnotationsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateMachineAnnotationsResponse.ProtoReflect.Descriptor instead. func (*UpdateMachineAnnotationsResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{27} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{37} } type UpdateMachinePowerRequest struct { @@ -1745,7 +2250,7 @@ type UpdateMachinePowerRequest struct { func (x *UpdateMachinePowerRequest) Reset() { *x = UpdateMachinePowerRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[28] + mi := &file_machine_v1alpha1_api_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1757,7 +2262,7 @@ func (x *UpdateMachinePowerRequest) String() string { func (*UpdateMachinePowerRequest) ProtoMessage() {} func (x *UpdateMachinePowerRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[28] + mi := &file_machine_v1alpha1_api_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1770,7 +2275,7 @@ func (x *UpdateMachinePowerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateMachinePowerRequest.ProtoReflect.Descriptor instead. func (*UpdateMachinePowerRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{28} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{38} } func (x *UpdateMachinePowerRequest) GetMachineId() string { @@ -1795,7 +2300,7 @@ type UpdateMachinePowerResponse struct { func (x *UpdateMachinePowerResponse) Reset() { *x = UpdateMachinePowerResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[29] + mi := &file_machine_v1alpha1_api_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1807,7 +2312,7 @@ func (x *UpdateMachinePowerResponse) String() string { func (*UpdateMachinePowerResponse) ProtoMessage() {} func (x *UpdateMachinePowerResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[29] + mi := &file_machine_v1alpha1_api_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1820,7 +2325,7 @@ func (x *UpdateMachinePowerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateMachinePowerResponse.ProtoReflect.Descriptor instead. func (*UpdateMachinePowerResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{29} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{39} } type AttachVolumeRequest struct { @@ -1833,7 +2338,7 @@ type AttachVolumeRequest struct { func (x *AttachVolumeRequest) Reset() { *x = AttachVolumeRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[30] + mi := &file_machine_v1alpha1_api_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1845,7 +2350,7 @@ func (x *AttachVolumeRequest) String() string { func (*AttachVolumeRequest) ProtoMessage() {} func (x *AttachVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[30] + mi := &file_machine_v1alpha1_api_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1858,7 +2363,7 @@ func (x *AttachVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachVolumeRequest.ProtoReflect.Descriptor instead. func (*AttachVolumeRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{30} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{40} } func (x *AttachVolumeRequest) GetMachineId() string { @@ -1883,7 +2388,7 @@ type AttachVolumeResponse struct { func (x *AttachVolumeResponse) Reset() { *x = AttachVolumeResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[31] + mi := &file_machine_v1alpha1_api_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1895,7 +2400,7 @@ func (x *AttachVolumeResponse) String() string { func (*AttachVolumeResponse) ProtoMessage() {} func (x *AttachVolumeResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[31] + mi := &file_machine_v1alpha1_api_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1908,7 +2413,7 @@ func (x *AttachVolumeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachVolumeResponse.ProtoReflect.Descriptor instead. func (*AttachVolumeResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{31} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{41} } type DetachVolumeRequest struct { @@ -1921,7 +2426,7 @@ type DetachVolumeRequest struct { func (x *DetachVolumeRequest) Reset() { *x = DetachVolumeRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[32] + mi := &file_machine_v1alpha1_api_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1933,7 +2438,7 @@ func (x *DetachVolumeRequest) String() string { func (*DetachVolumeRequest) ProtoMessage() {} func (x *DetachVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[32] + mi := &file_machine_v1alpha1_api_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1946,7 +2451,7 @@ func (x *DetachVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachVolumeRequest.ProtoReflect.Descriptor instead. func (*DetachVolumeRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{32} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{42} } func (x *DetachVolumeRequest) GetMachineId() string { @@ -1971,7 +2476,7 @@ type DetachVolumeResponse struct { func (x *DetachVolumeResponse) Reset() { *x = DetachVolumeResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[33] + mi := &file_machine_v1alpha1_api_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1983,7 +2488,7 @@ func (x *DetachVolumeResponse) String() string { func (*DetachVolumeResponse) ProtoMessage() {} func (x *DetachVolumeResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[33] + mi := &file_machine_v1alpha1_api_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1996,7 +2501,7 @@ func (x *DetachVolumeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachVolumeResponse.ProtoReflect.Descriptor instead. func (*DetachVolumeResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{33} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{43} } type UpdateVolumeRequest struct { @@ -2009,7 +2514,7 @@ type UpdateVolumeRequest struct { func (x *UpdateVolumeRequest) Reset() { *x = UpdateVolumeRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[34] + mi := &file_machine_v1alpha1_api_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2021,7 +2526,7 @@ func (x *UpdateVolumeRequest) String() string { func (*UpdateVolumeRequest) ProtoMessage() {} func (x *UpdateVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[34] + mi := &file_machine_v1alpha1_api_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2034,7 +2539,7 @@ func (x *UpdateVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateVolumeRequest.ProtoReflect.Descriptor instead. func (*UpdateVolumeRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{34} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{44} } func (x *UpdateVolumeRequest) GetMachineId() string { @@ -2059,7 +2564,7 @@ type UpdateVolumeResponse struct { func (x *UpdateVolumeResponse) Reset() { *x = UpdateVolumeResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[35] + mi := &file_machine_v1alpha1_api_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2071,7 +2576,7 @@ func (x *UpdateVolumeResponse) String() string { func (*UpdateVolumeResponse) ProtoMessage() {} func (x *UpdateVolumeResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[35] + mi := &file_machine_v1alpha1_api_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2084,7 +2589,7 @@ func (x *UpdateVolumeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateVolumeResponse.ProtoReflect.Descriptor instead. func (*UpdateVolumeResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{35} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{45} } type AttachNetworkInterfaceRequest struct { @@ -2097,7 +2602,7 @@ type AttachNetworkInterfaceRequest struct { func (x *AttachNetworkInterfaceRequest) Reset() { *x = AttachNetworkInterfaceRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[36] + mi := &file_machine_v1alpha1_api_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2109,7 +2614,7 @@ func (x *AttachNetworkInterfaceRequest) String() string { func (*AttachNetworkInterfaceRequest) ProtoMessage() {} func (x *AttachNetworkInterfaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[36] + mi := &file_machine_v1alpha1_api_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2122,7 +2627,7 @@ func (x *AttachNetworkInterfaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachNetworkInterfaceRequest.ProtoReflect.Descriptor instead. func (*AttachNetworkInterfaceRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{36} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{46} } func (x *AttachNetworkInterfaceRequest) GetMachineId() string { @@ -2147,7 +2652,7 @@ type AttachNetworkInterfaceResponse struct { func (x *AttachNetworkInterfaceResponse) Reset() { *x = AttachNetworkInterfaceResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[37] + mi := &file_machine_v1alpha1_api_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2159,7 +2664,7 @@ func (x *AttachNetworkInterfaceResponse) String() string { func (*AttachNetworkInterfaceResponse) ProtoMessage() {} func (x *AttachNetworkInterfaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[37] + mi := &file_machine_v1alpha1_api_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2172,7 +2677,7 @@ func (x *AttachNetworkInterfaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AttachNetworkInterfaceResponse.ProtoReflect.Descriptor instead. func (*AttachNetworkInterfaceResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{37} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{47} } type DetachNetworkInterfaceRequest struct { @@ -2185,7 +2690,7 @@ type DetachNetworkInterfaceRequest struct { func (x *DetachNetworkInterfaceRequest) Reset() { *x = DetachNetworkInterfaceRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[38] + mi := &file_machine_v1alpha1_api_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2197,7 +2702,7 @@ func (x *DetachNetworkInterfaceRequest) String() string { func (*DetachNetworkInterfaceRequest) ProtoMessage() {} func (x *DetachNetworkInterfaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[38] + mi := &file_machine_v1alpha1_api_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2210,7 +2715,7 @@ func (x *DetachNetworkInterfaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachNetworkInterfaceRequest.ProtoReflect.Descriptor instead. func (*DetachNetworkInterfaceRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{38} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{48} } func (x *DetachNetworkInterfaceRequest) GetMachineId() string { @@ -2235,7 +2740,7 @@ type DetachNetworkInterfaceResponse struct { func (x *DetachNetworkInterfaceResponse) Reset() { *x = DetachNetworkInterfaceResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[39] + mi := &file_machine_v1alpha1_api_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2247,7 +2752,7 @@ func (x *DetachNetworkInterfaceResponse) String() string { func (*DetachNetworkInterfaceResponse) ProtoMessage() {} func (x *DetachNetworkInterfaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[39] + mi := &file_machine_v1alpha1_api_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2260,7 +2765,7 @@ func (x *DetachNetworkInterfaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DetachNetworkInterfaceResponse.ProtoReflect.Descriptor instead. func (*DetachNetworkInterfaceResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{39} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{49} } type StatusRequest struct { @@ -2271,7 +2776,7 @@ type StatusRequest struct { func (x *StatusRequest) Reset() { *x = StatusRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[40] + mi := &file_machine_v1alpha1_api_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2283,7 +2788,7 @@ func (x *StatusRequest) String() string { func (*StatusRequest) ProtoMessage() {} func (x *StatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[40] + mi := &file_machine_v1alpha1_api_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2296,7 +2801,7 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead. func (*StatusRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{40} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{50} } type StatusResponse struct { @@ -2308,7 +2813,7 @@ type StatusResponse struct { func (x *StatusResponse) Reset() { *x = StatusResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[41] + mi := &file_machine_v1alpha1_api_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2320,7 +2825,7 @@ func (x *StatusResponse) String() string { func (*StatusResponse) ProtoMessage() {} func (x *StatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[41] + mi := &file_machine_v1alpha1_api_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2333,7 +2838,7 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead. func (*StatusResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{41} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{51} } func (x *StatusResponse) GetMachineClassStatus() []*MachineClassStatus { @@ -2352,7 +2857,7 @@ type ExecRequest struct { func (x *ExecRequest) Reset() { *x = ExecRequest{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[42] + mi := &file_machine_v1alpha1_api_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2364,7 +2869,7 @@ func (x *ExecRequest) String() string { func (*ExecRequest) ProtoMessage() {} func (x *ExecRequest) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[42] + mi := &file_machine_v1alpha1_api_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2377,7 +2882,7 @@ func (x *ExecRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecRequest.ProtoReflect.Descriptor instead. func (*ExecRequest) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{42} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{52} } func (x *ExecRequest) GetMachineId() string { @@ -2396,7 +2901,7 @@ type ExecResponse struct { func (x *ExecResponse) Reset() { *x = ExecResponse{} - mi := &file_machine_v1alpha1_api_proto_msgTypes[43] + mi := &file_machine_v1alpha1_api_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2408,7 +2913,7 @@ func (x *ExecResponse) String() string { func (*ExecResponse) ProtoMessage() {} func (x *ExecResponse) ProtoReflect() protoreflect.Message { - mi := &file_machine_v1alpha1_api_proto_msgTypes[43] + mi := &file_machine_v1alpha1_api_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2421,7 +2926,7 @@ func (x *ExecResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecResponse.ProtoReflect.Descriptor instead. func (*ExecResponse) Descriptor() ([]byte, []int) { - return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{43} + return file_machine_v1alpha1_api_proto_rawDescGZIP(), []int{53} } func (x *ExecResponse) GetUrl() string { @@ -2473,7 +2978,35 @@ const file_machine_v1alpha1_api_proto_rawDesc = "" + "\aMachine\x129\n" + "\bmetadata\x18\x01 \x01(\v2\x1d.meta.v1alpha1.ObjectMetadataR\bmetadata\x121\n" + "\x04spec\x18\x02 \x01(\v2\x1d.machine.v1alpha1.MachineSpecR\x04spec\x127\n" + - "\x06status\x18\x03 \x01(\v2\x1f.machine.v1alpha1.MachineStatusR\x06status\"!\n" + + "\x06status\x18\x03 \x01(\v2\x1f.machine.v1alpha1.MachineStatusR\x06status\"V\n" + + "\x17ListReservationsRequest\x12;\n" + + "\x06filter\x18\x01 \x01(\v2#.machine.v1alpha1.ReservationFilterR\x06filter\"]\n" + + "\x18ListReservationsResponse\x12A\n" + + "\freservations\x18\x01 \x03(\v2\x1d.machine.v1alpha1.ReservationR\freservations\"[\n" + + "\x18CreateReservationRequest\x12?\n" + + "\vreservation\x18\x01 \x01(\v2\x1d.machine.v1alpha1.ReservationR\vreservation\"\\\n" + + "\x19CreateReservationResponse\x12?\n" + + "\vreservation\x18\x01 \x01(\v2\x1d.machine.v1alpha1.ReservationR\vreservation\"A\n" + + "\x18DeleteReservationRequest\x12%\n" + + "\x0ereservation_id\x18\x01 \x01(\tR\rreservationId\"\x1b\n" + + "\x19DeleteReservationResponse\"\xc4\x01\n" + + "\x11ReservationFilter\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12]\n" + + "\x0elabel_selector\x18\x02 \x03(\v26.machine.v1alpha1.ReservationFilter.LabelSelectorEntryR\rlabelSelector\x1a@\n" + + "\x12LabelSelectorEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xbc\x01\n" + + "\vReservation\x129\n" + + "\bmetadata\x18\x01 \x01(\v2\x1d.meta.v1alpha1.ObjectMetadataR\bmetadata\x125\n" + + "\x04spec\x18\x02 \x01(\v2!.machine.v1alpha1.ReservationSpecR\x04spec\x12;\n" + + "\x06status\x18\x03 \x01(\v2#.machine.v1alpha1.ReservationStatusR\x06status\"\x9f\x01\n" + + "\x0fReservationSpec\x12N\n" + + "\tresources\x18\x01 \x03(\v20.machine.v1alpha1.ReservationSpec.ResourcesEntryR\tresources\x1a<\n" + + "\x0eResourcesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\"M\n" + + "\x11ReservationStatus\x128\n" + + "\x05state\x18\x01 \x01(\x0e2\".machine.v1alpha1.ReservationStateR\x05state\"!\n" + "\tImageSpec\x12\x14\n" + "\x05image\x18\x01 \x01(\tR\x05image\"*\n" + "\tEmptyDisk\x12\x1d\n" + @@ -2610,7 +3143,11 @@ const file_machine_v1alpha1_api_proto_rawDesc = "" + "\n" + "machine_id\x18\x01 \x01(\tR\tmachineId\" \n" + "\fExecResponse\x12\x10\n" + - "\x03url\x18\x01 \x01(\tR\x03url*$\n" + + "\x03url\x18\x01 \x01(\tR\x03url*q\n" + + "\x10ReservationState\x12\x1d\n" + + "\x19RESERVATION_STATE_PENDING\x10\x00\x12\x1e\n" + + "\x1aRESERVATION_STATE_ACCEPTED\x10\x01\x12\x1e\n" + + "\x1aRESERVATION_STATE_REJECTED\x10\x02*$\n" + "\x05Power\x12\f\n" + "\bPOWER_ON\x10\x00\x12\r\n" + "\tPOWER_OFF\x10\x01*6\n" + @@ -2626,7 +3163,7 @@ const file_machine_v1alpha1_api_proto_rawDesc = "" + "\x11MACHINE_SUSPENDED\x10\x02\x12\x16\n" + "\x12MACHINE_TERMINATED\x10\x03\x12\x17\n" + "\x13MACHINE_TERMINATING\x10\x04\x12\x13\n" + - "\x0fMACHINE_STOPPED\x10\x052\x8c\v\n" + + "\x0fMACHINE_STOPPED\x10\x052\xd9\r\n" + "\x0eMachineRuntime\x12P\n" + "\aVersion\x12 .machine.v1alpha1.VersionRequest\x1a!.machine.v1alpha1.VersionResponse\"\x00\x12Y\n" + "\n" + @@ -2640,7 +3177,10 @@ const file_machine_v1alpha1_api_proto_rawDesc = "" + "\fDetachVolume\x12%.machine.v1alpha1.DetachVolumeRequest\x1a&.machine.v1alpha1.DetachVolumeResponse\"\x00\x12_\n" + "\fUpdateVolume\x12%.machine.v1alpha1.UpdateVolumeRequest\x1a&.machine.v1alpha1.UpdateVolumeResponse\"\x00\x12{\n" + "\x16AttachNetworkInterface\x12/.machine.v1alpha1.AttachNetworkInterfaceRequest\x1a0.machine.v1alpha1.AttachNetworkInterfaceResponse\x12{\n" + - "\x16DetachNetworkInterface\x12/.machine.v1alpha1.DetachNetworkInterfaceRequest\x1a0.machine.v1alpha1.DetachNetworkInterfaceResponse\x12K\n" + + "\x16DetachNetworkInterface\x12/.machine.v1alpha1.DetachNetworkInterfaceRequest\x1a0.machine.v1alpha1.DetachNetworkInterfaceResponse\x12k\n" + + "\x10ListReservations\x12).machine.v1alpha1.ListReservationsRequest\x1a*.machine.v1alpha1.ListReservationsResponse\"\x00\x12n\n" + + "\x11CreateReservation\x12*.machine.v1alpha1.CreateReservationRequest\x1a+.machine.v1alpha1.CreateReservationResponse\"\x00\x12n\n" + + "\x11DeleteReservation\x12*.machine.v1alpha1.DeleteReservationRequest\x1a+.machine.v1alpha1.DeleteReservationResponse\"\x00\x12K\n" + "\x06Status\x12\x1f.machine.v1alpha1.StatusRequest\x1a .machine.v1alpha1.StatusResponse\x12E\n" + "\x04Exec\x12\x1d.machine.v1alpha1.ExecRequest\x1a\x1e.machine.v1alpha1.ExecResponseB machine.v1alpha1.VolumeSpec.AttributesEntry - 49, // 1: machine.v1alpha1.VolumeSpec.secret_data:type_name -> machine.v1alpha1.VolumeSpec.SecretDataEntry - 50, // 2: machine.v1alpha1.MachineFilter.label_selector:type_name -> machine.v1alpha1.MachineFilter.LabelSelectorEntry - 51, // 3: machine.v1alpha1.EventFilter.label_selector:type_name -> machine.v1alpha1.EventFilter.LabelSelectorEntry - 52, // 4: machine.v1alpha1.MachineClassCapabilities.resources:type_name -> machine.v1alpha1.MachineClassCapabilities.ResourcesEntry - 58, // 5: machine.v1alpha1.Machine.metadata:type_name -> meta.v1alpha1.ObjectMetadata - 14, // 6: machine.v1alpha1.Machine.spec:type_name -> machine.v1alpha1.MachineSpec - 15, // 7: machine.v1alpha1.Machine.status:type_name -> machine.v1alpha1.MachineStatus - 53, // 8: machine.v1alpha1.VolumeConnection.attributes:type_name -> machine.v1alpha1.VolumeConnection.AttributesEntry - 54, // 9: machine.v1alpha1.VolumeConnection.secret_data:type_name -> machine.v1alpha1.VolumeConnection.SecretDataEntry - 55, // 10: machine.v1alpha1.VolumeConnection.encryption_data:type_name -> machine.v1alpha1.VolumeConnection.EncryptionDataEntry - 10, // 11: machine.v1alpha1.Volume.empty_disk:type_name -> machine.v1alpha1.EmptyDisk - 11, // 12: machine.v1alpha1.Volume.connection:type_name -> machine.v1alpha1.VolumeConnection - 56, // 13: machine.v1alpha1.NetworkInterface.attributes:type_name -> machine.v1alpha1.NetworkInterface.AttributesEntry - 0, // 14: machine.v1alpha1.MachineSpec.power:type_name -> machine.v1alpha1.Power - 9, // 15: machine.v1alpha1.MachineSpec.image:type_name -> machine.v1alpha1.ImageSpec - 12, // 16: machine.v1alpha1.MachineSpec.volumes:type_name -> machine.v1alpha1.Volume - 13, // 17: machine.v1alpha1.MachineSpec.network_interfaces:type_name -> machine.v1alpha1.NetworkInterface - 3, // 18: machine.v1alpha1.MachineStatus.state:type_name -> machine.v1alpha1.MachineState - 16, // 19: machine.v1alpha1.MachineStatus.volumes:type_name -> machine.v1alpha1.VolumeStatus - 17, // 20: machine.v1alpha1.MachineStatus.network_interfaces:type_name -> machine.v1alpha1.NetworkInterfaceStatus - 1, // 21: machine.v1alpha1.VolumeStatus.state:type_name -> machine.v1alpha1.VolumeState - 2, // 22: machine.v1alpha1.NetworkInterfaceStatus.state:type_name -> machine.v1alpha1.NetworkInterfaceState - 7, // 23: machine.v1alpha1.MachineClass.capabilities:type_name -> machine.v1alpha1.MachineClassCapabilities - 18, // 24: machine.v1alpha1.MachineClassStatus.machine_class:type_name -> machine.v1alpha1.MachineClass - 5, // 25: machine.v1alpha1.ListMachinesRequest.filter:type_name -> machine.v1alpha1.MachineFilter - 8, // 26: machine.v1alpha1.ListMachinesResponse.machines:type_name -> machine.v1alpha1.Machine - 6, // 27: machine.v1alpha1.ListEventsRequest.filter:type_name -> machine.v1alpha1.EventFilter - 59, // 28: machine.v1alpha1.ListEventsResponse.events:type_name -> event.v1alpha1.Event - 8, // 29: machine.v1alpha1.CreateMachineRequest.machine:type_name -> machine.v1alpha1.Machine - 8, // 30: machine.v1alpha1.CreateMachineResponse.machine:type_name -> machine.v1alpha1.Machine - 57, // 31: machine.v1alpha1.UpdateMachineAnnotationsRequest.annotations:type_name -> machine.v1alpha1.UpdateMachineAnnotationsRequest.AnnotationsEntry - 0, // 32: machine.v1alpha1.UpdateMachinePowerRequest.power:type_name -> machine.v1alpha1.Power - 12, // 33: machine.v1alpha1.AttachVolumeRequest.volume:type_name -> machine.v1alpha1.Volume - 12, // 34: machine.v1alpha1.UpdateVolumeRequest.volume:type_name -> machine.v1alpha1.Volume - 13, // 35: machine.v1alpha1.AttachNetworkInterfaceRequest.network_interface:type_name -> machine.v1alpha1.NetworkInterface - 19, // 36: machine.v1alpha1.StatusResponse.machine_class_status:type_name -> machine.v1alpha1.MachineClassStatus - 20, // 37: machine.v1alpha1.MachineRuntime.Version:input_type -> machine.v1alpha1.VersionRequest - 24, // 38: machine.v1alpha1.MachineRuntime.ListEvents:input_type -> machine.v1alpha1.ListEventsRequest - 22, // 39: machine.v1alpha1.MachineRuntime.ListMachines:input_type -> machine.v1alpha1.ListMachinesRequest - 26, // 40: machine.v1alpha1.MachineRuntime.CreateMachine:input_type -> machine.v1alpha1.CreateMachineRequest - 28, // 41: machine.v1alpha1.MachineRuntime.DeleteMachine:input_type -> machine.v1alpha1.DeleteMachineRequest - 30, // 42: machine.v1alpha1.MachineRuntime.UpdateMachineAnnotations:input_type -> machine.v1alpha1.UpdateMachineAnnotationsRequest - 32, // 43: machine.v1alpha1.MachineRuntime.UpdateMachinePower:input_type -> machine.v1alpha1.UpdateMachinePowerRequest - 34, // 44: machine.v1alpha1.MachineRuntime.AttachVolume:input_type -> machine.v1alpha1.AttachVolumeRequest - 36, // 45: machine.v1alpha1.MachineRuntime.DetachVolume:input_type -> machine.v1alpha1.DetachVolumeRequest - 38, // 46: machine.v1alpha1.MachineRuntime.UpdateVolume:input_type -> machine.v1alpha1.UpdateVolumeRequest - 40, // 47: machine.v1alpha1.MachineRuntime.AttachNetworkInterface:input_type -> machine.v1alpha1.AttachNetworkInterfaceRequest - 42, // 48: machine.v1alpha1.MachineRuntime.DetachNetworkInterface:input_type -> machine.v1alpha1.DetachNetworkInterfaceRequest - 44, // 49: machine.v1alpha1.MachineRuntime.Status:input_type -> machine.v1alpha1.StatusRequest - 46, // 50: machine.v1alpha1.MachineRuntime.Exec:input_type -> machine.v1alpha1.ExecRequest - 21, // 51: machine.v1alpha1.MachineRuntime.Version:output_type -> machine.v1alpha1.VersionResponse - 25, // 52: machine.v1alpha1.MachineRuntime.ListEvents:output_type -> machine.v1alpha1.ListEventsResponse - 23, // 53: machine.v1alpha1.MachineRuntime.ListMachines:output_type -> machine.v1alpha1.ListMachinesResponse - 27, // 54: machine.v1alpha1.MachineRuntime.CreateMachine:output_type -> machine.v1alpha1.CreateMachineResponse - 29, // 55: machine.v1alpha1.MachineRuntime.DeleteMachine:output_type -> machine.v1alpha1.DeleteMachineResponse - 31, // 56: machine.v1alpha1.MachineRuntime.UpdateMachineAnnotations:output_type -> machine.v1alpha1.UpdateMachineAnnotationsResponse - 33, // 57: machine.v1alpha1.MachineRuntime.UpdateMachinePower:output_type -> machine.v1alpha1.UpdateMachinePowerResponse - 35, // 58: machine.v1alpha1.MachineRuntime.AttachVolume:output_type -> machine.v1alpha1.AttachVolumeResponse - 37, // 59: machine.v1alpha1.MachineRuntime.DetachVolume:output_type -> machine.v1alpha1.DetachVolumeResponse - 39, // 60: machine.v1alpha1.MachineRuntime.UpdateVolume:output_type -> machine.v1alpha1.UpdateVolumeResponse - 41, // 61: machine.v1alpha1.MachineRuntime.AttachNetworkInterface:output_type -> machine.v1alpha1.AttachNetworkInterfaceResponse - 43, // 62: machine.v1alpha1.MachineRuntime.DetachNetworkInterface:output_type -> machine.v1alpha1.DetachNetworkInterfaceResponse - 45, // 63: machine.v1alpha1.MachineRuntime.Status:output_type -> machine.v1alpha1.StatusResponse - 47, // 64: machine.v1alpha1.MachineRuntime.Exec:output_type -> machine.v1alpha1.ExecResponse - 51, // [51:65] is the sub-list for method output_type - 37, // [37:51] is the sub-list for method input_type - 37, // [37:37] is the sub-list for extension type_name - 37, // [37:37] is the sub-list for extension extendee - 0, // [0:37] is the sub-list for field type_name + 59, // 0: machine.v1alpha1.VolumeSpec.attributes:type_name -> machine.v1alpha1.VolumeSpec.AttributesEntry + 60, // 1: machine.v1alpha1.VolumeSpec.secret_data:type_name -> machine.v1alpha1.VolumeSpec.SecretDataEntry + 61, // 2: machine.v1alpha1.MachineFilter.label_selector:type_name -> machine.v1alpha1.MachineFilter.LabelSelectorEntry + 62, // 3: machine.v1alpha1.EventFilter.label_selector:type_name -> machine.v1alpha1.EventFilter.LabelSelectorEntry + 63, // 4: machine.v1alpha1.MachineClassCapabilities.resources:type_name -> machine.v1alpha1.MachineClassCapabilities.ResourcesEntry + 71, // 5: machine.v1alpha1.Machine.metadata:type_name -> meta.v1alpha1.ObjectMetadata + 25, // 6: machine.v1alpha1.Machine.spec:type_name -> machine.v1alpha1.MachineSpec + 26, // 7: machine.v1alpha1.Machine.status:type_name -> machine.v1alpha1.MachineStatus + 16, // 8: machine.v1alpha1.ListReservationsRequest.filter:type_name -> machine.v1alpha1.ReservationFilter + 17, // 9: machine.v1alpha1.ListReservationsResponse.reservations:type_name -> machine.v1alpha1.Reservation + 17, // 10: machine.v1alpha1.CreateReservationRequest.reservation:type_name -> machine.v1alpha1.Reservation + 17, // 11: machine.v1alpha1.CreateReservationResponse.reservation:type_name -> machine.v1alpha1.Reservation + 64, // 12: machine.v1alpha1.ReservationFilter.label_selector:type_name -> machine.v1alpha1.ReservationFilter.LabelSelectorEntry + 71, // 13: machine.v1alpha1.Reservation.metadata:type_name -> meta.v1alpha1.ObjectMetadata + 18, // 14: machine.v1alpha1.Reservation.spec:type_name -> machine.v1alpha1.ReservationSpec + 19, // 15: machine.v1alpha1.Reservation.status:type_name -> machine.v1alpha1.ReservationStatus + 65, // 16: machine.v1alpha1.ReservationSpec.resources:type_name -> machine.v1alpha1.ReservationSpec.ResourcesEntry + 0, // 17: machine.v1alpha1.ReservationStatus.state:type_name -> machine.v1alpha1.ReservationState + 66, // 18: machine.v1alpha1.VolumeConnection.attributes:type_name -> machine.v1alpha1.VolumeConnection.AttributesEntry + 67, // 19: machine.v1alpha1.VolumeConnection.secret_data:type_name -> machine.v1alpha1.VolumeConnection.SecretDataEntry + 68, // 20: machine.v1alpha1.VolumeConnection.encryption_data:type_name -> machine.v1alpha1.VolumeConnection.EncryptionDataEntry + 21, // 21: machine.v1alpha1.Volume.empty_disk:type_name -> machine.v1alpha1.EmptyDisk + 22, // 22: machine.v1alpha1.Volume.connection:type_name -> machine.v1alpha1.VolumeConnection + 69, // 23: machine.v1alpha1.NetworkInterface.attributes:type_name -> machine.v1alpha1.NetworkInterface.AttributesEntry + 1, // 24: machine.v1alpha1.MachineSpec.power:type_name -> machine.v1alpha1.Power + 20, // 25: machine.v1alpha1.MachineSpec.image:type_name -> machine.v1alpha1.ImageSpec + 23, // 26: machine.v1alpha1.MachineSpec.volumes:type_name -> machine.v1alpha1.Volume + 24, // 27: machine.v1alpha1.MachineSpec.network_interfaces:type_name -> machine.v1alpha1.NetworkInterface + 4, // 28: machine.v1alpha1.MachineStatus.state:type_name -> machine.v1alpha1.MachineState + 27, // 29: machine.v1alpha1.MachineStatus.volumes:type_name -> machine.v1alpha1.VolumeStatus + 28, // 30: machine.v1alpha1.MachineStatus.network_interfaces:type_name -> machine.v1alpha1.NetworkInterfaceStatus + 2, // 31: machine.v1alpha1.VolumeStatus.state:type_name -> machine.v1alpha1.VolumeState + 3, // 32: machine.v1alpha1.NetworkInterfaceStatus.state:type_name -> machine.v1alpha1.NetworkInterfaceState + 8, // 33: machine.v1alpha1.MachineClass.capabilities:type_name -> machine.v1alpha1.MachineClassCapabilities + 29, // 34: machine.v1alpha1.MachineClassStatus.machine_class:type_name -> machine.v1alpha1.MachineClass + 6, // 35: machine.v1alpha1.ListMachinesRequest.filter:type_name -> machine.v1alpha1.MachineFilter + 9, // 36: machine.v1alpha1.ListMachinesResponse.machines:type_name -> machine.v1alpha1.Machine + 7, // 37: machine.v1alpha1.ListEventsRequest.filter:type_name -> machine.v1alpha1.EventFilter + 72, // 38: machine.v1alpha1.ListEventsResponse.events:type_name -> event.v1alpha1.Event + 9, // 39: machine.v1alpha1.CreateMachineRequest.machine:type_name -> machine.v1alpha1.Machine + 9, // 40: machine.v1alpha1.CreateMachineResponse.machine:type_name -> machine.v1alpha1.Machine + 70, // 41: machine.v1alpha1.UpdateMachineAnnotationsRequest.annotations:type_name -> machine.v1alpha1.UpdateMachineAnnotationsRequest.AnnotationsEntry + 1, // 42: machine.v1alpha1.UpdateMachinePowerRequest.power:type_name -> machine.v1alpha1.Power + 23, // 43: machine.v1alpha1.AttachVolumeRequest.volume:type_name -> machine.v1alpha1.Volume + 23, // 44: machine.v1alpha1.UpdateVolumeRequest.volume:type_name -> machine.v1alpha1.Volume + 24, // 45: machine.v1alpha1.AttachNetworkInterfaceRequest.network_interface:type_name -> machine.v1alpha1.NetworkInterface + 30, // 46: machine.v1alpha1.StatusResponse.machine_class_status:type_name -> machine.v1alpha1.MachineClassStatus + 31, // 47: machine.v1alpha1.MachineRuntime.Version:input_type -> machine.v1alpha1.VersionRequest + 35, // 48: machine.v1alpha1.MachineRuntime.ListEvents:input_type -> machine.v1alpha1.ListEventsRequest + 33, // 49: machine.v1alpha1.MachineRuntime.ListMachines:input_type -> machine.v1alpha1.ListMachinesRequest + 37, // 50: machine.v1alpha1.MachineRuntime.CreateMachine:input_type -> machine.v1alpha1.CreateMachineRequest + 39, // 51: machine.v1alpha1.MachineRuntime.DeleteMachine:input_type -> machine.v1alpha1.DeleteMachineRequest + 41, // 52: machine.v1alpha1.MachineRuntime.UpdateMachineAnnotations:input_type -> machine.v1alpha1.UpdateMachineAnnotationsRequest + 43, // 53: machine.v1alpha1.MachineRuntime.UpdateMachinePower:input_type -> machine.v1alpha1.UpdateMachinePowerRequest + 45, // 54: machine.v1alpha1.MachineRuntime.AttachVolume:input_type -> machine.v1alpha1.AttachVolumeRequest + 47, // 55: machine.v1alpha1.MachineRuntime.DetachVolume:input_type -> machine.v1alpha1.DetachVolumeRequest + 49, // 56: machine.v1alpha1.MachineRuntime.UpdateVolume:input_type -> machine.v1alpha1.UpdateVolumeRequest + 51, // 57: machine.v1alpha1.MachineRuntime.AttachNetworkInterface:input_type -> machine.v1alpha1.AttachNetworkInterfaceRequest + 53, // 58: machine.v1alpha1.MachineRuntime.DetachNetworkInterface:input_type -> machine.v1alpha1.DetachNetworkInterfaceRequest + 10, // 59: machine.v1alpha1.MachineRuntime.ListReservations:input_type -> machine.v1alpha1.ListReservationsRequest + 12, // 60: machine.v1alpha1.MachineRuntime.CreateReservation:input_type -> machine.v1alpha1.CreateReservationRequest + 14, // 61: machine.v1alpha1.MachineRuntime.DeleteReservation:input_type -> machine.v1alpha1.DeleteReservationRequest + 55, // 62: machine.v1alpha1.MachineRuntime.Status:input_type -> machine.v1alpha1.StatusRequest + 57, // 63: machine.v1alpha1.MachineRuntime.Exec:input_type -> machine.v1alpha1.ExecRequest + 32, // 64: machine.v1alpha1.MachineRuntime.Version:output_type -> machine.v1alpha1.VersionResponse + 36, // 65: machine.v1alpha1.MachineRuntime.ListEvents:output_type -> machine.v1alpha1.ListEventsResponse + 34, // 66: machine.v1alpha1.MachineRuntime.ListMachines:output_type -> machine.v1alpha1.ListMachinesResponse + 38, // 67: machine.v1alpha1.MachineRuntime.CreateMachine:output_type -> machine.v1alpha1.CreateMachineResponse + 40, // 68: machine.v1alpha1.MachineRuntime.DeleteMachine:output_type -> machine.v1alpha1.DeleteMachineResponse + 42, // 69: machine.v1alpha1.MachineRuntime.UpdateMachineAnnotations:output_type -> machine.v1alpha1.UpdateMachineAnnotationsResponse + 44, // 70: machine.v1alpha1.MachineRuntime.UpdateMachinePower:output_type -> machine.v1alpha1.UpdateMachinePowerResponse + 46, // 71: machine.v1alpha1.MachineRuntime.AttachVolume:output_type -> machine.v1alpha1.AttachVolumeResponse + 48, // 72: machine.v1alpha1.MachineRuntime.DetachVolume:output_type -> machine.v1alpha1.DetachVolumeResponse + 50, // 73: machine.v1alpha1.MachineRuntime.UpdateVolume:output_type -> machine.v1alpha1.UpdateVolumeResponse + 52, // 74: machine.v1alpha1.MachineRuntime.AttachNetworkInterface:output_type -> machine.v1alpha1.AttachNetworkInterfaceResponse + 54, // 75: machine.v1alpha1.MachineRuntime.DetachNetworkInterface:output_type -> machine.v1alpha1.DetachNetworkInterfaceResponse + 11, // 76: machine.v1alpha1.MachineRuntime.ListReservations:output_type -> machine.v1alpha1.ListReservationsResponse + 13, // 77: machine.v1alpha1.MachineRuntime.CreateReservation:output_type -> machine.v1alpha1.CreateReservationResponse + 15, // 78: machine.v1alpha1.MachineRuntime.DeleteReservation:output_type -> machine.v1alpha1.DeleteReservationResponse + 56, // 79: machine.v1alpha1.MachineRuntime.Status:output_type -> machine.v1alpha1.StatusResponse + 58, // 80: machine.v1alpha1.MachineRuntime.Exec:output_type -> machine.v1alpha1.ExecResponse + 64, // [64:81] is the sub-list for method output_type + 47, // [47:64] is the sub-list for method input_type + 47, // [47:47] is the sub-list for extension type_name + 47, // [47:47] is the sub-list for extension extendee + 0, // [0:47] is the sub-list for field type_name } func init() { file_machine_v1alpha1_api_proto_init() } @@ -2803,8 +3372,8 @@ func file_machine_v1alpha1_api_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_machine_v1alpha1_api_proto_rawDesc), len(file_machine_v1alpha1_api_proto_rawDesc)), - NumEnums: 4, - NumMessages: 54, + NumEnums: 5, + NumMessages: 66, NumExtensions: 0, NumServices: 1, }, diff --git a/iri/apis/machine/v1alpha1/api.proto b/iri/apis/machine/v1alpha1/api.proto index 4e1fc95e6..7c3d83ac5 100644 --- a/iri/apis/machine/v1alpha1/api.proto +++ b/iri/apis/machine/v1alpha1/api.proto @@ -21,6 +21,10 @@ service MachineRuntime { rpc AttachNetworkInterface(AttachNetworkInterfaceRequest) returns (AttachNetworkInterfaceResponse); rpc DetachNetworkInterface(DetachNetworkInterfaceRequest) returns (DetachNetworkInterfaceResponse); + rpc ListReservations(ListReservationsRequest) returns (ListReservationsResponse) {}; + rpc CreateReservation(CreateReservationRequest) returns (CreateReservationResponse) {}; + rpc DeleteReservation(DeleteReservationRequest) returns (DeleteReservationResponse) {}; + rpc Status(StatusRequest) returns (StatusResponse); rpc Exec(ExecRequest) returns (ExecResponse); @@ -55,6 +59,54 @@ message Machine { MachineStatus status = 3; } +message ListReservationsRequest { + ReservationFilter filter = 1; +} + +message ListReservationsResponse { + repeated Reservation reservations = 1; +} + +message CreateReservationRequest { + Reservation reservation = 1; +} + +message CreateReservationResponse { + Reservation reservation = 1; +} + +message DeleteReservationRequest { + string reservation_id = 1; +} + +message DeleteReservationResponse { +} + +message ReservationFilter { + string id = 1; + map label_selector = 2; +} + +message Reservation { + meta.v1alpha1.ObjectMetadata metadata = 1; + ReservationSpec spec = 2; + ReservationStatus status = 3; +} + +message ReservationSpec { + map resources = 1; +} + +message ReservationStatus { + ReservationState state = 1; +} + +enum ReservationState { + RESERVATION_STATE_PENDING = 0; + RESERVATION_STATE_ACCEPTED = 1; + RESERVATION_STATE_REJECTED = 2; +} + message ImageSpec { string image = 1; } diff --git a/iri/apis/machine/v1alpha1/api_grpc.pb.go b/iri/apis/machine/v1alpha1/api_grpc.pb.go index 3a1836870..f9417bc8c 100644 --- a/iri/apis/machine/v1alpha1/api_grpc.pb.go +++ b/iri/apis/machine/v1alpha1/api_grpc.pb.go @@ -32,6 +32,9 @@ const ( MachineRuntime_UpdateVolume_FullMethodName = "/machine.v1alpha1.MachineRuntime/UpdateVolume" MachineRuntime_AttachNetworkInterface_FullMethodName = "/machine.v1alpha1.MachineRuntime/AttachNetworkInterface" MachineRuntime_DetachNetworkInterface_FullMethodName = "/machine.v1alpha1.MachineRuntime/DetachNetworkInterface" + MachineRuntime_ListReservations_FullMethodName = "/machine.v1alpha1.MachineRuntime/ListReservations" + MachineRuntime_CreateReservation_FullMethodName = "/machine.v1alpha1.MachineRuntime/CreateReservation" + MachineRuntime_DeleteReservation_FullMethodName = "/machine.v1alpha1.MachineRuntime/DeleteReservation" MachineRuntime_Status_FullMethodName = "/machine.v1alpha1.MachineRuntime/Status" MachineRuntime_Exec_FullMethodName = "/machine.v1alpha1.MachineRuntime/Exec" ) @@ -52,6 +55,9 @@ type MachineRuntimeClient interface { UpdateVolume(ctx context.Context, in *UpdateVolumeRequest, opts ...grpc.CallOption) (*UpdateVolumeResponse, error) AttachNetworkInterface(ctx context.Context, in *AttachNetworkInterfaceRequest, opts ...grpc.CallOption) (*AttachNetworkInterfaceResponse, error) DetachNetworkInterface(ctx context.Context, in *DetachNetworkInterfaceRequest, opts ...grpc.CallOption) (*DetachNetworkInterfaceResponse, error) + ListReservations(ctx context.Context, in *ListReservationsRequest, opts ...grpc.CallOption) (*ListReservationsResponse, error) + CreateReservation(ctx context.Context, in *CreateReservationRequest, opts ...grpc.CallOption) (*CreateReservationResponse, error) + DeleteReservation(ctx context.Context, in *DeleteReservationRequest, opts ...grpc.CallOption) (*DeleteReservationResponse, error) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (*ExecResponse, error) } @@ -184,6 +190,36 @@ func (c *machineRuntimeClient) DetachNetworkInterface(ctx context.Context, in *D return out, nil } +func (c *machineRuntimeClient) ListReservations(ctx context.Context, in *ListReservationsRequest, opts ...grpc.CallOption) (*ListReservationsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListReservationsResponse) + err := c.cc.Invoke(ctx, MachineRuntime_ListReservations_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *machineRuntimeClient) CreateReservation(ctx context.Context, in *CreateReservationRequest, opts ...grpc.CallOption) (*CreateReservationResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateReservationResponse) + err := c.cc.Invoke(ctx, MachineRuntime_CreateReservation_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *machineRuntimeClient) DeleteReservation(ctx context.Context, in *DeleteReservationRequest, opts ...grpc.CallOption) (*DeleteReservationResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteReservationResponse) + err := c.cc.Invoke(ctx, MachineRuntime_DeleteReservation_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *machineRuntimeClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StatusResponse) @@ -220,6 +256,9 @@ type MachineRuntimeServer interface { UpdateVolume(context.Context, *UpdateVolumeRequest) (*UpdateVolumeResponse, error) AttachNetworkInterface(context.Context, *AttachNetworkInterfaceRequest) (*AttachNetworkInterfaceResponse, error) DetachNetworkInterface(context.Context, *DetachNetworkInterfaceRequest) (*DetachNetworkInterfaceResponse, error) + ListReservations(context.Context, *ListReservationsRequest) (*ListReservationsResponse, error) + CreateReservation(context.Context, *CreateReservationRequest) (*CreateReservationResponse, error) + DeleteReservation(context.Context, *DeleteReservationRequest) (*DeleteReservationResponse, error) Status(context.Context, *StatusRequest) (*StatusResponse, error) Exec(context.Context, *ExecRequest) (*ExecResponse, error) mustEmbedUnimplementedMachineRuntimeServer() @@ -268,6 +307,15 @@ func (UnimplementedMachineRuntimeServer) AttachNetworkInterface(context.Context, func (UnimplementedMachineRuntimeServer) DetachNetworkInterface(context.Context, *DetachNetworkInterfaceRequest) (*DetachNetworkInterfaceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DetachNetworkInterface not implemented") } +func (UnimplementedMachineRuntimeServer) ListReservations(context.Context, *ListReservationsRequest) (*ListReservationsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListReservations not implemented") +} +func (UnimplementedMachineRuntimeServer) CreateReservation(context.Context, *CreateReservationRequest) (*CreateReservationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateReservation not implemented") +} +func (UnimplementedMachineRuntimeServer) DeleteReservation(context.Context, *DeleteReservationRequest) (*DeleteReservationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteReservation not implemented") +} func (UnimplementedMachineRuntimeServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") } @@ -511,6 +559,60 @@ func _MachineRuntime_DetachNetworkInterface_Handler(srv interface{}, ctx context return interceptor(ctx, in, info, handler) } +func _MachineRuntime_ListReservations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListReservationsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MachineRuntimeServer).ListReservations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MachineRuntime_ListReservations_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MachineRuntimeServer).ListReservations(ctx, req.(*ListReservationsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MachineRuntime_CreateReservation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateReservationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MachineRuntimeServer).CreateReservation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MachineRuntime_CreateReservation_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MachineRuntimeServer).CreateReservation(ctx, req.(*CreateReservationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MachineRuntime_DeleteReservation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteReservationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MachineRuntimeServer).DeleteReservation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MachineRuntime_DeleteReservation_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MachineRuntimeServer).DeleteReservation(ctx, req.(*DeleteReservationRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _MachineRuntime_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(StatusRequest) if err := dec(in); err != nil { @@ -602,6 +704,18 @@ var MachineRuntime_ServiceDesc = grpc.ServiceDesc{ MethodName: "DetachNetworkInterface", Handler: _MachineRuntime_DetachNetworkInterface_Handler, }, + { + MethodName: "ListReservations", + Handler: _MachineRuntime_ListReservations_Handler, + }, + { + MethodName: "CreateReservation", + Handler: _MachineRuntime_CreateReservation_Handler, + }, + { + MethodName: "DeleteReservation", + Handler: _MachineRuntime_DeleteReservation_Handler, + }, { MethodName: "Status", Handler: _MachineRuntime_Status_Handler, diff --git a/iri/remote/machine/runtime.go b/iri/remote/machine/runtime.go index 7d193aecd..7abad430f 100644 --- a/iri/remote/machine/runtime.go +++ b/iri/remote/machine/runtime.go @@ -78,6 +78,18 @@ func (r *remoteRuntime) DetachNetworkInterface(ctx context.Context, req *iri.Det return r.client.DetachNetworkInterface(ctx, req) } +func (r *remoteRuntime) ListReservations(ctx context.Context, req *iri.ListReservationsRequest) (*iri.ListReservationsResponse, error) { + return r.client.ListReservations(ctx, req) +} + +func (r *remoteRuntime) CreateReservation(ctx context.Context, req *iri.CreateReservationRequest) (*iri.CreateReservationResponse, error) { + return r.client.CreateReservation(ctx, req) +} + +func (r *remoteRuntime) DeleteReservation(ctx context.Context, req *iri.DeleteReservationRequest) (*iri.DeleteReservationResponse, error) { + return r.client.DeleteReservation(ctx, req) +} + func (r *remoteRuntime) Status(ctx context.Context, req *iri.StatusRequest) (*iri.StatusResponse, error) { return r.client.Status(ctx, req) } diff --git a/iri/testing/machine/fake.go b/iri/testing/machine/fake.go index 67ec5862a..6dfb98d2c 100644 --- a/iri/testing/machine/fake.go +++ b/iri/testing/machine/fake.go @@ -51,6 +51,10 @@ type FakeMachine struct { *iri.Machine } +type FakeReservation struct { + *iri.Reservation +} + type FakeVolume struct { iri.Volume } @@ -71,6 +75,7 @@ type FakeRuntimeService struct { sync.Mutex Machines map[string]*FakeMachine + Reservations map[string]*FakeReservation MachineClassStatus map[string]*FakeMachineClassStatus GetExecURL func(req *iri.ExecRequest) string Events []*FakeEvent @@ -92,6 +97,7 @@ func (r *FakeRuntimeService) ListEvents(ctx context.Context, req *iri.ListEvents func NewFakeRuntimeService() *FakeRuntimeService { return &FakeRuntimeService{ Machines: make(map[string]*FakeMachine), + Reservations: make(map[string]*FakeReservation), MachineClassStatus: make(map[string]*FakeMachineClassStatus), Events: []*FakeEvent{}, } @@ -330,6 +336,71 @@ func (r *FakeRuntimeService) DetachNetworkInterface(ctx context.Context, req *ir return &iri.DetachNetworkInterfaceResponse{}, nil } +func (r *FakeRuntimeService) ListReservations(ctx context.Context, req *iri.ListReservationsRequest) (*iri.ListReservationsResponse, error) { + r.Lock() + defer r.Unlock() + + filter := req.Filter + + var res []*iri.Reservation + for _, m := range r.Reservations { + if filter != nil { + if filter.Id != "" && filter.Id != m.Metadata.Id { + continue + } + if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, m.Metadata.Labels) { + continue + } + } + + res = append(res, m.Reservation) + } + return &iri.ListReservationsResponse{Reservations: res}, nil +} + +func (r *FakeRuntimeService) SetReservations(reservations []*FakeReservation) { + r.Lock() + defer r.Unlock() + + r.Reservations = make(map[string]*FakeReservation) + for _, reservation := range reservations { + r.Reservations[reservation.Metadata.Id] = reservation + } +} + +func (r *FakeRuntimeService) CreateReservation(ctx context.Context, req *iri.CreateReservationRequest) (*iri.CreateReservationResponse, error) { + r.Lock() + defer r.Unlock() + + reservation := req.Reservation + reservation.Metadata.Id = generateID(defaultIDLength) + reservation.Metadata.CreatedAt = time.Now().UnixNano() + reservation.Status = &iri.ReservationStatus{ + State: 0, + } + + r.Reservations[reservation.Metadata.Id] = &FakeReservation{ + Reservation: reservation, + } + + return &iri.CreateReservationResponse{ + Reservation: reservation, + }, nil +} + +func (r *FakeRuntimeService) DeleteReservation(ctx context.Context, req *iri.DeleteReservationRequest) (*iri.DeleteReservationResponse, error) { + r.Lock() + defer r.Unlock() + + reservationID := req.ReservationId + if _, ok := r.Reservations[reservationID]; !ok { + return nil, status.Errorf(codes.NotFound, "reservation %q not found", reservationID) + } + + delete(r.Reservations, reservationID) + return &iri.DeleteReservationResponse{}, nil +} + func (r *FakeRuntimeService) Status(ctx context.Context, req *iri.StatusRequest) (*iri.StatusResponse, error) { r.Lock() defer r.Unlock() diff --git a/poollet/common/utils/utils.go b/poollet/common/utils/utils.go index 67c1fd2b7..bc81293a7 100644 --- a/poollet/common/utils/utils.go +++ b/poollet/common/utils/utils.go @@ -72,6 +72,8 @@ func PrepareDownwardAPILabels( switch o := obj.(type) { case *computev1alpha1.Machine: value, err = fieldpath.ExtractFieldPathAsString(o, fieldPath) + case *computev1alpha1.Reservation: + value, err = fieldpath.ExtractFieldPathAsString(o, fieldPath) case *networkingv1alpha1.Network: value, err = fieldpath.ExtractFieldPathAsString(o, fieldPath) case *networkingv1alpha1.NetworkInterface: diff --git a/poollet/machinepoollet/api/v1alpha1/common_types.go b/poollet/machinepoollet/api/v1alpha1/common_types.go index 6853f315d..d4e3c839c 100644 --- a/poollet/machinepoollet/api/v1alpha1/common_types.go +++ b/poollet/machinepoollet/api/v1alpha1/common_types.go @@ -34,10 +34,23 @@ const ( FieldOwner = "machinepoollet.ironcore.dev/field-owner" MachineFinalizer = "machinepoollet.ironcore.dev/machine" + ReservationUIDLabel = "machinepoollet.ironcore.dev/reservation-uid" + ReservationNamespaceLabel = "machinepoollet.ironcore.dev/reservation-namespace" + ReservationNameLabel = "machinepoollet.ironcore.dev/reservation-name" + + ReservationFinalizerBase = "machinepoollet.ironcore.dev/reservation-" + + ReservationGenerationAnnotation = "machinepoollet.ironcore.dev/reservation-generation" + IRIReservationGenerationAnnotation = "machinepoollet.ironcore.dev/irireservation-generation" + // MachineDownwardAPIPrefix is the prefix for any downward label. MachineDownwardAPIPrefix = "downward-api.machinepoollet.ironcore.dev/" ) +func ReservationFinalizer(poolName string) string { + return ReservationFinalizerBase + poolName +} + // EncodeNetworkInterfaceMapping encodes the given network interface mapping to be used as an annotation. func EncodeNetworkInterfaceMapping(nicMapping map[string]ObjectUIDRef) (string, error) { data, err := json.Marshal(nicMapping) diff --git a/poollet/machinepoollet/controllers/controllers_suite_test.go b/poollet/machinepoollet/controllers/controllers_suite_test.go index 36df4615b..10a5e8e2b 100644 --- a/poollet/machinepoollet/controllers/controllers_suite_test.go +++ b/poollet/machinepoollet/controllers/controllers_suite_test.go @@ -57,7 +57,7 @@ var ( ) const ( - eventuallyTimeout = 3 * time.Second + eventuallyTimeout = 30 * time.Second pollingInterval = 50 * time.Millisecond consistentlyDuration = 3 * time.Second apiServiceTimeout = 5 * time.Minute @@ -273,6 +273,33 @@ func SetupTest() (*corev1.Namespace, *computev1alpha1.MachinePool, *computev1alp MachinePoolName: mp.Name, }).SetupWithManager(k8sManager)).To(Succeed()) + reservationEvents := irievent.NewGenerator(func(ctx context.Context) ([]*iri.Reservation, error) { + res, err := srv.ListReservations(ctx, &iri.ListReservationsRequest{}) + if err != nil { + return nil, err + } + return res.Reservations, nil + }, irievent.GeneratorOptions{}) + + Expect(k8sManager.Add(reservationEvents)).To(Succeed()) + + Expect((&controllers.ReservationAnnotatorReconciler{ + Client: k8sManager.GetClient(), + ReservationEvents: reservationEvents, + }).SetupWithManager(k8sManager)).To(Succeed()) + + Expect((&controllers.ReservationReconciler{ + EventRecorder: &record.FakeRecorder{}, + Client: k8sManager.GetClient(), + MachineRuntime: srv, + MachineRuntimeName: machine.FakeRuntimeName, + MachineRuntimeVersion: machine.FakeVersion, + MachinePoolName: mp.Name, + DownwardAPILabels: map[string]string{ + fooDownwardAPILabel: fmt.Sprintf("metadata.annotations['%s']", fooAnnotation), + }, + }).SetupWithManager(k8sManager)).To(Succeed()) + go func() { defer GinkgoRecover() Expect(k8sManager.Start(mgrCtx)).To(Succeed(), "failed to start manager") diff --git a/poollet/machinepoollet/controllers/reservation_controller.go b/poollet/machinepoollet/controllers/reservation_controller.go new file mode 100644 index 000000000..9ec4d057e --- /dev/null +++ b/poollet/machinepoollet/controllers/reservation_controller.go @@ -0,0 +1,494 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + "context" + "errors" + "fmt" + + "github.com/go-logr/logr" + "github.com/ironcore-dev/controller-utils/clientutils" + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + irimachine "github.com/ironcore-dev/ironcore/iri/apis/machine" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + poolletutils "github.com/ironcore-dev/ironcore/poollet/common/utils" + "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + utilclient "github.com/ironcore-dev/ironcore/utils/client" + utilsmaps "github.com/ironcore-dev/ironcore/utils/maps" + "github.com/ironcore-dev/ironcore/utils/predicates" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + "k8s.io/kubectl/pkg/util/fieldpath" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +type ReservationReconciler struct { + record.EventRecorder + client.Client + + MachineRuntime irimachine.RuntimeService + MachineRuntimeName string + MachineRuntimeVersion string + + MachinePoolName string + + DownwardAPILabels map[string]string + DownwardAPIAnnotations map[string]string + + WatchFilterValue string +} + +func (r *ReservationReconciler) reservationKeyLabelSelector(reservationKey client.ObjectKey) map[string]string { + return map[string]string{ + v1alpha1.ReservationNamespaceLabel: reservationKey.Namespace, + v1alpha1.ReservationNameLabel: reservationKey.Name, + } +} + +func (r *ReservationReconciler) reservationUIDLabelSelector(reservationUID types.UID) map[string]string { + return map[string]string{ + v1alpha1.ReservationUIDLabel: string(reservationUID), + } +} + +//+kubebuilder:rbac:groups="",resources=events,verbs=create;patch +//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch +//+kubebuilder:rbac:groups=compute.ironcore.dev,resources=reservations,verbs=get;list;watch;update;patch +//+kubebuilder:rbac:groups=compute.ironcore.dev,resources=reservations/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=compute.ironcore.dev,resources=reservations/finalizers,verbs=update + +func (r *ReservationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + reservation := &computev1alpha1.Reservation{} + if err := r.Get(ctx, req.NamespacedName, reservation); err != nil { + if !apierrors.IsNotFound(err) { + return ctrl.Result{}, fmt.Errorf("error getting reservation %s: %w", req.NamespacedName, err) + } + return r.deleteGone(ctx, log, req.NamespacedName) + } + return r.reconcileExists(ctx, log, reservation) +} + +func (r *ReservationReconciler) getIRIReservationsForReservation(ctx context.Context, reservation *computev1alpha1.Reservation) ([]*iri.Reservation, error) { + res, err := r.MachineRuntime.ListReservations(ctx, &iri.ListReservationsRequest{ + Filter: &iri.ReservationFilter{LabelSelector: r.reservationUIDLabelSelector(reservation.UID)}, + }) + if err != nil { + return nil, fmt.Errorf("error listing reservations by reservation uid: %w", err) + } + return res.Reservations, nil +} + +func (r *ReservationReconciler) listReservationsByReservationKey(ctx context.Context, reservationKey client.ObjectKey) ([]*iri.Reservation, error) { + res, err := r.MachineRuntime.ListReservations(ctx, &iri.ListReservationsRequest{ + Filter: &iri.ReservationFilter{LabelSelector: r.reservationKeyLabelSelector(reservationKey)}, + }) + if err != nil { + return nil, fmt.Errorf("error listing reservations by reservation key: %w", err) + } + return res.Reservations, nil +} + +func (r *ReservationReconciler) deleteReservations(ctx context.Context, log logr.Logger, reservations []*iri.Reservation) (bool, error) { + var ( + errs []error + deletingIDs []string + ) + for _, reservation := range reservations { + reservationID := reservation.Metadata.Id + log := log.WithValues("ReservationID", reservationID) + log.V(1).Info("Deleting matching reservation") + if _, err := r.MachineRuntime.DeleteReservation(ctx, &iri.DeleteReservationRequest{ + ReservationId: reservationID, + }); err != nil { + if status.Code(err) != codes.NotFound { + errs = append(errs, fmt.Errorf("error deleting reservation %s: %w", reservationID, err)) + } else { + log.V(1).Info("Reservation is already gone") + } + } else { + log.V(1).Info("Issued reservation deletion") + deletingIDs = append(deletingIDs, reservationID) + } + } + + switch { + case len(errs) > 0: + return false, fmt.Errorf("error(s) deleting matching reservation(s): %v", errs) + case len(deletingIDs) > 0: + log.V(1).Info("Reservations are still deleting", "DeletingIDs", deletingIDs) + return false, nil + default: + log.V(1).Info("No reservation present") + return true, nil + } +} + +func (r *ReservationReconciler) deleteGone(ctx context.Context, log logr.Logger, reservationKey client.ObjectKey) (ctrl.Result, error) { + log.V(1).Info("Delete gone") + + log.V(1).Info("Listing reservations by reservation key") + reservations, err := r.listReservationsByReservationKey(ctx, reservationKey) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error listing reservations: %w", err) + } + + ok, err := r.deleteReservations(ctx, log, reservations) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error deleting reservations: %w", err) + } + if !ok { + log.V(1).Info("Not all reservations are gone yet, requeueing") + return ctrl.Result{Requeue: true}, nil + } + log.V(1).Info("Deleted gone") + return ctrl.Result{}, nil +} + +func (r *ReservationReconciler) reconcileExists(ctx context.Context, log logr.Logger, reservation *computev1alpha1.Reservation) (ctrl.Result, error) { + if !reservation.DeletionTimestamp.IsZero() { + return r.delete(ctx, log, reservation) + } + return r.reconcile(ctx, log, reservation) +} + +func (r *ReservationReconciler) delete(ctx context.Context, log logr.Logger, reservation *computev1alpha1.Reservation) (ctrl.Result, error) { + log.V(1).Info("Delete") + + if !controllerutil.ContainsFinalizer(reservation, v1alpha1.ReservationFinalizer(r.MachinePoolName)) { + log.V(1).Info("No finalizer present, nothing to do") + return ctrl.Result{}, nil + } + + log.V(1).Info("Finalizer present") + + log.V(1).Info("Deleting reservations by UID") + ok, err := r.deleteReservationsByReservationUID(ctx, log, reservation.UID) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error deleting reservations: %w", err) + } + if !ok { + log.V(1).Info("Not all reservations are gone, requeueing") + return ctrl.Result{Requeue: true}, nil + } + + log.V(1).Info("Deleted iri reservations by UID, removing finalizer") + if err := clientutils.PatchRemoveFinalizer(ctx, r.Client, reservation, v1alpha1.ReservationFinalizer(r.MachinePoolName)); err != nil { + return ctrl.Result{}, fmt.Errorf("error removing finalizer: %w", err) + } + + log.V(1).Info("Deleted") + return ctrl.Result{}, nil +} + +func (r *ReservationReconciler) deleteReservationsByReservationUID(ctx context.Context, log logr.Logger, reservationUID types.UID) (bool, error) { + log.V(1).Info("Listing reservations") + res, err := r.MachineRuntime.ListReservations(ctx, &iri.ListReservationsRequest{ + Filter: &iri.ReservationFilter{ + LabelSelector: map[string]string{ + v1alpha1.ReservationUIDLabel: string(reservationUID), + }, + }, + }) + if err != nil { + return false, fmt.Errorf("error listing reservations: %w", err) + } + + log.V(1).Info("Listed reservations", "NoOfReservations", len(res.Reservations)) + var ( + errs []error + deletingReservationIDs []string + ) + for _, reservation := range res.Reservations { + reservationID := reservation.Metadata.Id + log := log.WithValues("ReservationID", reservationID) + log.V(1).Info("Deleting reservation") + _, err := r.MachineRuntime.DeleteReservation(ctx, &iri.DeleteReservationRequest{ + ReservationId: reservationID, + }) + if err != nil { + if status.Code(err) != codes.NotFound { + errs = append(errs, fmt.Errorf("error deleting reservation %s: %w", reservationID, err)) + } else { + log.V(1).Info("Reservation is already gone") + } + } else { + log.V(1).Info("Issued reservation deletion") + deletingReservationIDs = append(deletingReservationIDs, reservationID) + } + } + + switch { + case len(errs) > 0: + return false, fmt.Errorf("error(s) deleting reservation(s): %v", errs) + case len(deletingReservationIDs) > 0: + log.V(1).Info("Reservations are in deletion", "DeletingReservationIDs", deletingReservationIDs) + return false, nil + default: + log.V(1).Info("All reservations are gone") + return true, nil + } +} + +func (r *ReservationReconciler) reconcile(ctx context.Context, log logr.Logger, reservation *computev1alpha1.Reservation) (ctrl.Result, error) { + log.V(1).Info("Reconcile") + + log.V(1).Info("Ensuring finalizer") + modified, err := clientutils.PatchEnsureFinalizer(ctx, r.Client, reservation, v1alpha1.ReservationFinalizer(r.MachinePoolName)) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error ensuring finalizer: %w", err) + } + if modified { + log.V(1).Info("Added finalizer, requeueing") + return ctrl.Result{Requeue: true}, nil + } + log.V(1).Info("Finalizer is present") + + log.V(1).Info("Ensuring no reconcile annotation") + modified, err = utilclient.PatchEnsureNoReconcileAnnotation(ctx, r.Client, reservation) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error ensuring no reconcile annotation: %w", err) + } + if modified { + log.V(1).Info("Removed reconcile annotation, requeueing") + return ctrl.Result{Requeue: true}, nil + } + + iriReservations, err := r.getIRIReservationsForReservation(ctx, reservation) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error getting IRI reservations for reservation: %w", err) + } + + switch len(iriReservations) { + case 0: + return r.create(ctx, log, reservation) + case 1: + iriReservation := iriReservations[0] + return r.update(ctx, log, reservation, iriReservation) + default: + panic("unhandled: multiple IRI reservations") + } +} + +func (r *ReservationReconciler) iriReservationLabels(reservation *computev1alpha1.Reservation) (map[string]string, error) { + labels := map[string]string{ + v1alpha1.ReservationUIDLabel: string(reservation.UID), + v1alpha1.ReservationNamespaceLabel: reservation.Namespace, + v1alpha1.ReservationNameLabel: reservation.Name, + } + + apiLabels, err := poolletutils.PrepareDownwardAPILabels(reservation, r.DownwardAPILabels, v1alpha1.MachineDownwardAPIPrefix) + if err != nil { + return nil, err + } + labels = utilsmaps.AppendMap(labels, apiLabels) + return labels, nil +} + +func (r *ReservationReconciler) iriReservationAnnotations( + reservation *computev1alpha1.Reservation, +) (map[string]string, error) { + + annotations := map[string]string{} + + for name, fieldPath := range r.DownwardAPIAnnotations { + value, err := fieldpath.ExtractFieldPathAsString(reservation, fieldPath) + if err != nil { + return nil, fmt.Errorf("error extracting downward api annotation %q: %w", name, err) + } + + annotations[poolletutils.DownwardAPIAnnotation(v1alpha1.MachineDownwardAPIPrefix, name)] = value + } + + return annotations, nil +} + +func (r *ReservationReconciler) create( + ctx context.Context, + log logr.Logger, + reservation *computev1alpha1.Reservation, +) (ctrl.Result, error) { + log.V(1).Info("Create") + + log.V(1).Info("Getting reservation config") + iriReservation, ok, err := r.prepareIRIReservation(ctx, reservation) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error preparing iri reservation: %w", err) + } + if !ok { + log.V(1).Info("Reservation is not yet ready") + return ctrl.Result{}, nil + } + + log.V(1).Info("Creating reservation") + res, err := r.MachineRuntime.CreateReservation(ctx, &iri.CreateReservationRequest{ + Reservation: iriReservation, + }) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error creating reservation: %w", err) + } + log.V(1).Info("Created", "ReservationID", res.Reservation.Metadata.Id) + + log.V(1).Info("Updating status") + if err := r.updateStatus(ctx, log, reservation, res.Reservation); err != nil { + return ctrl.Result{}, fmt.Errorf("error updating reservation status: %w", err) + } + + log.V(1).Info("Created") + return ctrl.Result{}, nil +} + +func (r *ReservationReconciler) updateStatus( + ctx context.Context, + log logr.Logger, + reservation *computev1alpha1.Reservation, + iriReservation *iri.Reservation, +) error { + var errs []error + if err := r.updateReservationStatus(ctx, log, reservation, iriReservation); err != nil { + errs = append(errs, err) + } + + return errors.Join(errs...) +} + +var iriReservationStateToReservationState = map[iri.ReservationState]computev1alpha1.ReservationState{ + iri.ReservationState_RESERVATION_STATE_PENDING: computev1alpha1.ReservationStatePending, + iri.ReservationState_RESERVATION_STATE_ACCEPTED: computev1alpha1.ReservationStateAccepted, + iri.ReservationState_RESERVATION_STATE_REJECTED: computev1alpha1.ReservationStateRejected, +} + +func (r *ReservationReconciler) convertIRIReservationState(state iri.ReservationState) (computev1alpha1.ReservationState, error) { + if res, ok := iriReservationStateToReservationState[state]; ok { + return res, nil + } + return "", fmt.Errorf("unknown reservation state %v", state) +} + +func (r *ReservationReconciler) updateReservationStatus(ctx context.Context, log logr.Logger, reservation *computev1alpha1.Reservation, iriReservation *iri.Reservation) error { + + state, err := r.convertIRIReservationState(iriReservation.Status.State) + if err != nil { + return err + } + + availablePools := []computev1alpha1.ReservationPoolStatus{{ + Name: r.MachinePoolName, + State: state, + }} + + for _, poolState := range reservation.Status.Pools { + if poolState.Name != r.MachinePoolName { + availablePools = append(availablePools, poolState) + } + } + + base := reservation.DeepCopy() + reservation.Status.Pools = availablePools + + if err := r.Status().Patch(ctx, reservation, client.MergeFrom(base)); err != nil { + return fmt.Errorf("error patching status: %w", err) + } + return nil +} + +func (r *ReservationReconciler) update( + ctx context.Context, + log logr.Logger, + reservation *computev1alpha1.Reservation, + iriReservation *iri.Reservation, +) (ctrl.Result, error) { + + log.V(1).Info("Updating reservation status") + if err := r.updateStatus(ctx, log, reservation, iriReservation); err != nil { + return ctrl.Result{}, fmt.Errorf("error updating status: %w", err) + } + + return ctrl.Result{}, nil +} + +func (r *ReservationReconciler) prepareIRIReservation( + ctx context.Context, + reservation *computev1alpha1.Reservation, +) (*iri.Reservation, bool, error) { + var ( + errs []error + ) + + labels, err := r.iriReservationLabels(reservation) + if err != nil { + errs = append(errs, fmt.Errorf("error preparing iri reservation labels: %w", err)) + } + + annotations, err := r.iriReservationAnnotations(reservation) + if err != nil { + errs = append(errs, fmt.Errorf("error preparing iri reservation annotations: %w", err)) + } + + var resources = map[string][]byte{} + for resource, quantity := range reservation.Spec.Resources { + if data, err := quantity.Marshal(); err != nil { + errs = append(errs, fmt.Errorf("error marshaling quantity (%s): %w", resource, err)) + } else { + resources[string(resource)] = data + } + + } + + switch { + case len(errs) > 0: + return nil, false, fmt.Errorf("error(s) preparing reservation: %v", errs) + default: + return &iri.Reservation{ + Metadata: &irimeta.ObjectMetadata{ + Labels: labels, + Annotations: annotations, + }, + Spec: &iri.ReservationSpec{ + Resources: resources, + }, + }, true, nil + } +} + +func ReservationAssignedToMachinePool(reservation *computev1alpha1.Reservation, machinePoolName string) bool { + for _, pool := range reservation.Spec.Pools { + if pool.Name == machinePoolName { + return true + } + } + + return false +} + +func ReservationAssignedToMachinePoolPredicate(machinePoolName string) predicate.Predicate { + return predicate.NewPredicateFuncs(func(object client.Object) bool { + reservation := object.(*computev1alpha1.Reservation) + return ReservationAssignedToMachinePool(reservation, machinePoolName) + }) +} + +func (r *ReservationReconciler) SetupWithManager(mgr ctrl.Manager) error { + log := ctrl.Log.WithName("reservationpoollet") + + return ctrl.NewControllerManagedBy(mgr). + For( + &computev1alpha1.Reservation{}, + builder.WithPredicates( + ReservationAssignedToMachinePoolPredicate(r.MachinePoolName), + predicates.ResourceHasFilterLabel(log, r.WatchFilterValue), + predicates.ResourceIsNotExternallyManaged(log), + ), + ). + Complete(r) +} diff --git a/poollet/machinepoollet/controllers/reservation_controller_test.go b/poollet/machinepoollet/controllers/reservation_controller_test.go new file mode 100644 index 000000000..ed413cdae --- /dev/null +++ b/poollet/machinepoollet/controllers/reservation_controller_test.go @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package controllers_test + +import ( + "fmt" + + _ "github.com/ironcore-dev/ironcore/api/common/v1alpha1" + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1" + _ "github.com/ironcore-dev/ironcore/api/networking/v1alpha1" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + testingmachine "github.com/ironcore-dev/ironcore/iri/testing/machine" + machinepoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "google.golang.org/protobuf/proto" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + . "sigs.k8s.io/controller-runtime/pkg/envtest/komega" +) + +var _ = Describe("MachineController", func() { + ns, mp, _, srv := SetupTest() + + It("Should create a reservation on a matching pool", func(ctx SpecContext) { + + By("creating a reservation") + const fooAnnotationValue = "bar" + reservation := &computev1alpha1.Reservation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + GenerateName: "reservation-", + Annotations: map[string]string{ + fooAnnotation: fooAnnotationValue, + }, + }, + Spec: computev1alpha1.ReservationSpec{ + Pools: []corev1.LocalObjectReference{ + {Name: mp.Name}, + }, + Resources: corev1alpha1.ResourceList{ + corev1alpha1.ResourceCPU: resource.MustParse("1"), + }, + }, + } + Expect(k8sClient.Create(ctx, reservation)).To(Succeed()) + + By("ensuring the ironcore reservation status is pending") + Eventually(Object(reservation)).Should(HaveField("Status.Pools", ConsistOf(computev1alpha1.ReservationPoolStatus{ + Name: mp.Name, + State: computev1alpha1.ReservationStatePending, + }))) + + By("waiting for the runtime to report the reservation") + Eventually(srv).Should(SatisfyAll( + HaveField("Reservations", HaveLen(1)), + )) + + _, iriReservation := GetSingleMapEntry(srv.Reservations) + + By("inspecting the iri reservation") + Expect(iriReservation.Metadata.Labels).To(HaveKeyWithValue(fmt.Sprintf("%s%s", machinepoolletv1alpha1.MachineDownwardAPIPrefix, fooDownwardAPILabel), fooAnnotationValue)) + + By("setting the reservation state to accepted") + iriReservation = &testingmachine.FakeReservation{Reservation: proto.Clone(iriReservation.Reservation).(*iri.Reservation)} + iriReservation.Status.State = iri.ReservationState_RESERVATION_STATE_ACCEPTED + srv.SetReservations([]*testingmachine.FakeReservation{iriReservation}) + + //By("ensuring the ironcore reservation status is pending accepted") + //Eventually(Object(reservation)).Should(HaveField("Status.Pools", ConsistOf(computev1alpha1.ReservationPoolStatus{ + // Name: mp.Name, + // State: computev1alpha1.ReservationStatePending, + //}))) + }) +}) diff --git a/poollet/machinepoollet/controllers/reservationannotator_controller.go b/poollet/machinepoollet/controllers/reservationannotator_controller.go new file mode 100644 index 000000000..9bdcda9bf --- /dev/null +++ b/poollet/machinepoollet/controllers/reservationannotator_controller.go @@ -0,0 +1,147 @@ +// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package controllers + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1" + iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + "github.com/ironcore-dev/ironcore/poollet/irievent" + machinepoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/machinepoollet/api/v1alpha1" + ironcoreclient "github.com/ironcore-dev/ironcore/utils/client" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +type ReservationAnnotatorReconciler struct { + client.Client + + ReservationEvents irievent.Source[*iri.Reservation] +} + +func (r *ReservationAnnotatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + reservation := &computev1alpha1.Reservation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: req.Namespace, + Name: req.Name, + }, + } + + if err := ironcoreclient.PatchAddReconcileAnnotation(ctx, r.Client, reservation); client.IgnoreNotFound(err) != nil { + return ctrl.Result{}, fmt.Errorf("error patching reservation: %w", err) + } + return ctrl.Result{}, nil +} + +func reservationAnnotatorEventHandler[O irimeta.Object](log logr.Logger, c chan<- event.GenericEvent) irievent.HandlerFuncs[O] { + handleEvent := func(obj irimeta.Object) { + namespace, ok := obj.GetMetadata().Labels[machinepoolletv1alpha1.ReservationNamespaceLabel] + if !ok { + return + } + + name, ok := obj.GetMetadata().Labels[machinepoolletv1alpha1.ReservationNameLabel] + if !ok { + return + } + + reservation := &computev1alpha1.Reservation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + } + + select { + case c <- event.GenericEvent{Object: reservation}: + default: + log.V(5).Info("Channel full, discarding event") + } + } + + return irievent.HandlerFuncs[O]{ + CreateFunc: func(event irievent.CreateEvent[O]) { + handleEvent(event.Object) + }, + UpdateFunc: func(event irievent.UpdateEvent[O]) { + handleEvent(event.ObjectNew) + }, + DeleteFunc: func(event irievent.DeleteEvent[O]) { + handleEvent(event.Object) + }, + GenericFunc: func(event irievent.GenericEvent[O]) { + handleEvent(event.Object) + }, + } +} + +func (r *ReservationAnnotatorReconciler) SetupWithManager(mgr ctrl.Manager) error { + c, err := controller.New("reservationannotator", mgr, controller.Options{ + Reconciler: r, + }) + if err != nil { + return err + } + + src, err := r.iriMachineEventSource(mgr) + if err != nil { + return err + } + + if err := c.Watch(src); err != nil { + return err + } + + return nil +} + +func (r *ReservationAnnotatorReconciler) iriMachineEventSource(mgr ctrl.Manager) (source.Source, error) { + ch := make(chan event.GenericEvent, 1024) + + if err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { + log := ctrl.LoggerFrom(ctx).WithName("reservationannotator").WithName("irieventhandlers") + + registrationFuncs := []func() (irievent.HandlerRegistration, error){ + func() (irievent.HandlerRegistration, error) { + return r.ReservationEvents.AddHandler(reservationAnnotatorEventHandler[*iri.Reservation](log, ch)) + }, + } + + var handles []irievent.HandlerRegistration + defer func() { + log.V(1).Info("Removing handles") + for _, handle := range handles { + if err := handle.Remove(); err != nil { + log.Error(err, "Error removing handle") + } + } + }() + + for _, registrationFunc := range registrationFuncs { + handle, err := registrationFunc() + if err != nil { + return err + } + + handles = append(handles, handle) + } + + <-ctx.Done() + return nil + })); err != nil { + return nil, err + } + + return source.Channel(ch, &handler.EnqueueRequestForObject{}), nil +}