Skip to content

Commit

Permalink
Allocation controller
Browse files Browse the repository at this point in the history
  • Loading branch information
cannarelladev committed Oct 24, 2023
1 parent 42ae08a commit 187c244
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 29 deletions.
50 changes: 50 additions & 0 deletions apis/nodecore/v1alpha1/allocation_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2022-2023 FLUIDOS Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import "github.com/fluidos-project/node/pkg/utils/tools"

// SetStatus sets the status of the allocation.
func (allocation *Allocation) SetStatus(status Status, msg string) {
allocation.Status.Status = status
allocation.Status.LastUpdateTime = tools.GetTimeNow()
allocation.Status.Message = msg
}

/*
// SetPurchasePhase sets the ReserveAndBuy phase of the solver
func (allocation *Allocation) SetReserveAndBuyStatus(phase Phase) {
solver.Status.ReserveAndBuy = phase
solver.Status.SolverPhase.LastChangeTime = tools.GetTimeNow()
}
// SetFindCandidateStatus sets the FindCandidate phase of the solver
func (allocation *Allocation) SetFindCandidateStatus(phase Phase) {
solver.Status.FindCandidate = phase
solver.Status.SolverPhase.LastChangeTime = tools.GetTimeNow()
}
// SetDiscoveryStatus sets the discovery phase of the solver
func (allocation *Allocation) SetDiscoveryStatus(phase Phase) {
solver.Status.DiscoveryPhase = phase
solver.Status.SolverPhase.LastChangeTime = tools.GetTimeNow()
}
// SetReservationStatus sets the reservation phase of the solver
func (allocation *Allocation) SetReservationStatus(phase Phase) {
solver.Status.ReservationPhase = phase
solver.Status.SolverPhase.LastChangeTime = tools.GetTimeNow()
}
*/
31 changes: 22 additions & 9 deletions apis/nodecore/v1alpha1/allocation_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

type NodeType string
type Status string
type Destination string

Check warning on line 23 in apis/nodecore/v1alpha1/allocation_types.go

View workflow job for this annotation

GitHub Actions / Lint golang files

exported: exported type Destination should have comment or be unexported (revive)

const (
Node NodeType = "Node"
Expand All @@ -31,6 +32,12 @@ const (
Reserved Status = "Reserved"
Released Status = "Released"
Inactive Status = "Inactive"
Error Status = "Error"
)

const (
Remote Destination = "Remote"

Check warning on line 39 in apis/nodecore/v1alpha1/allocation_types.go

View workflow job for this annotation

GitHub Actions / Lint golang files

exported: exported const Remote should have comment (or a comment on this block) or be unexported (revive)
Local Destination = "Local"
)

// AllocationSpec defines the desired state of Allocation
Expand All @@ -47,33 +54,39 @@ type AllocationSpec struct {
// This specifies the type of the node: Node (Physical node of the cluster) or VirtualNode (Remote node owned by a different cluster)
Type NodeType `json:"type"`

// This specifies if the destination of the allocation is local or remote so if the allocation will be used locally or from a remote cluster
Destination Destination `json:"destination"`

// This flag indicates if the allocation is a forwarding allocation, if true it represents only a placeholder to undertand that the cluster is just a proxy to another cluster
Forwarding bool `json:"forwarding,omitempty"`

// This Flavour describes the characteristics of the allocation, it is based on the Flavour CRD from which it was created
Flavour Flavour `json:"flavour"`

// This is the dimension of the allocation, it is based on the Flavour CRD from which it was created
Partition *Partition `json:"partition,omitempty"`
// This flags indicates if the Flavour from which the allocation was created was partitioned or not
Partitioned bool `json:"partitioned"`

// This is the dimension of the allocation
Resources *Partition `json:"partition,omitempty"`
}

// AllocationStatus defines the observed state of Allocation
// AllocationStatus defines the observed state of Allocation.
type AllocationStatus struct {

// This allow to know the current status of the allocation
Status Status `json:"status"`

// The creation time of the allocation object
CreationTime metav1.Time `json:"creationTime"`
Status Status `json:"status,omitempty"`

// The last time the allocation was updated
LastUpdateTime metav1.Time `json:"lastUpdateTime"`
LastUpdateTime string `json:"lastUpdateTime,omitempty"`

// Message contains the last message of the allocation
Message string `json:"message,omitempty"`
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

// Allocation is the Schema for the allocations API
// Allocation is the Schema for the allocations API.
type Allocation struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
8 changes: 3 additions & 5 deletions apis/nodecore/v1alpha1/zz_generated.deepcopy.go

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

30 changes: 17 additions & 13 deletions deployments/node/crds/nodecore.fluidos.eu_allocations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: Allocation is the Schema for the allocations API
description: Allocation is the Schema for the allocations API.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
Expand All @@ -34,6 +34,11 @@ spec:
spec:
description: AllocationSpec defines the desired state of Allocation
properties:
destination:
description: This specifies if the destination of the allocation is
local or remote so if the allocation will be used locally or from
a remote cluster
type: string
flavour:
description: This Flavour describes the characteristics of the allocation,
it is based on the Flavour CRD from which it was created
Expand Down Expand Up @@ -291,8 +296,7 @@ spec:
description: This is the corresponding Node or VirtualNode name
type: string
partition:
description: This is the dimension of the allocation, it is based
on the Flavour CRD from which it was created
description: This is the dimension of the allocation
properties:
architecture:
type: string
Expand Down Expand Up @@ -331,35 +335,35 @@ spec:
- cpu
- memory
type: object
partitioned:
description: This flags indicates if the Flavour from which the allocation
was created was partitioned or not
type: boolean
type:
description: 'This specifies the type of the node: Node (Physical
node of the cluster) or VirtualNode (Remote node owned by a different
cluster)'
type: string
required:
- destination
- flavour
- intentID
- nodeName
- partitioned
- type
type: object
status:
description: AllocationStatus defines the observed state of Allocation
description: AllocationStatus defines the observed state of Allocation.
properties:
creationTime:
description: The creation time of the allocation object
format: date-time
type: string
lastUpdateTime:
description: The last time the allocation was updated
format: date-time
type: string
message:
description: Message contains the last message of the allocation
type: string
status:
description: This allow to know the current status of the allocation
type: string
required:
- creationTime
- lastUpdateTime
- status
type: object
type: object
served: true
Expand Down
126 changes: 126 additions & 0 deletions pkg/rear-manager/allocation_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

nodecorev1alpha1 "github.com/fluidos-project/node/apis/nodecore/v1alpha1"
"github.com/fluidos-project/node/pkg/utils/resourceforge"
"github.com/fluidos-project/node/pkg/utils/services"
)

// +kubebuilder:rbac:groups=nodecore.fluidos.eu,resources=allocations,verbs=get;list;watch;create;update;patch;delete
Expand All @@ -48,9 +50,133 @@ func (r *AllocationReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, nil
}

if allocation.Status.Status != nodecorev1alpha1.Active &&
allocation.Status.Status != nodecorev1alpha1.Reserved &&
allocation.Status.Status != nodecorev1alpha1.Released &&
allocation.Status.Status != nodecorev1alpha1.Inactive {
allocation.SetStatus(nodecorev1alpha1.Inactive, "Allocation has been set to Inactive")

if err := r.updateAllocationStatus(ctx, &allocation); err != nil {
klog.Errorf("Error when updating Allocation %s status: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

klog.Infof("Reconciling Solver %s", req.NamespacedName)

if allocation.Status.Status == nodecorev1alpha1.Error {
klog.Infof("Allocation %s is in error state", req.NamespacedName)
return ctrl.Result{}, nil
}

if allocation.Spec.Type == nodecorev1alpha1.Node {
allocStatus := allocation.Status.Status
switch allocStatus {
case nodecorev1alpha1.Active:
// We need to check if the ForeignCluster is still ready
// If the ForeignCluster is not ready we need to set the Allocation to Released
klog.Infof("Allocation %s is active", req.NamespacedName)
case nodecorev1alpha1.Reserved:
if allocation.Spec.Destination == nodecorev1alpha1.Remote {

Check failure on line 81 in pkg/rear-manager/allocation_controller.go

View workflow job for this annotation

GitHub Actions / Lint golang files

dupBranchBody: both branches in if statement have same body (gocritic)
// We need to check the status of the ForeignCluster
// If the ForeignCluster is Ready the Allocation can be set to Active
// else we need to wait for the ForeignCluster to be Ready
klog.Infof("Allocation %s is reserved", req.NamespacedName)
} else {
// We can set the Allocation to Active
klog.Infof("Allocation %s is reserved", req.NamespacedName)
}
case nodecorev1alpha1.Released:
// The Allocation is released,
klog.Infof("Allocation %s is released", req.NamespacedName)
case nodecorev1alpha1.Inactive:
// Alloction Type is Node, so we need to invalidate the Flavour
// and eventually create a new one detaching the right Partition from the old one
klog.Infof("Allocation %s is inactive", req.NamespacedName)

flavour, err := services.GetFlavourByID(allocation.Spec.Flavour.Name, r.Client)
if err != nil {
klog.Errorf("Error when getting Flavour %s: %v", allocation.Spec.Flavour.Name, err)
allocation.SetStatus(nodecorev1alpha1.Error, "Error when getting Flavour")
if err := r.updateAllocationStatus(ctx, &allocation); err != nil {
klog.Errorf("Error when updating Allocation %s status: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

flavour.Spec.OptionalFields.Availability = false
if err := r.Client.Update(ctx, flavour); err != nil {
klog.Errorf("Error when updating Flavour %s: %v", flavour.Name, err)
allocation.SetStatus(nodecorev1alpha1.Error, "Error when updating Flavour")
if err := r.updateAllocationStatus(ctx, &allocation); err != nil {
klog.Errorf("Error when updating Allocation %s status: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

partitioned := allocation.Spec.Partitioned
if partitioned {
// We need to create a new Flavour with the right Partition
flavourRes := allocation.Spec.Flavour.Spec.Characteristics
allocationRes := allocation.Spec.Resources

newCharacteristics := computeCharacteristics(&flavourRes, allocationRes)
newFlavour := resourceforge.ForgeFlavourFromRef(flavour, newCharacteristics)

if err := r.Client.Create(ctx, newFlavour); err != nil {
klog.Errorf("Error when creating Flavour %s: %v", newFlavour.Name, err)
allocation.SetStatus(nodecorev1alpha1.Error, "Error when creating Flavour")
if err := r.updateAllocationStatus(ctx, &allocation); err != nil {
klog.Errorf("Error when updating Allocation %s status: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
}

allocation.SetStatus(nodecorev1alpha1.Reserved, "Allocation has been set to Reserved")
if err := r.updateAllocationStatus(ctx, &allocation); err != nil {
klog.Errorf("Error when updating Allocation %s status: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
default:
klog.Infof("Allocation %s is in an unknown state", req.NamespacedName)
}
}

return ctrl.Result{}, nil
}

func computeCharacteristics(old *nodecorev1alpha1.Characteristics, p *nodecorev1alpha1.Partition) *nodecorev1alpha1.Characteristics {
newCPU := old.Cpu.DeepCopy()
newMemory := old.Memory.DeepCopy()
newStorage := old.PersistentStorage.DeepCopy()
newGpu := old.Gpu.DeepCopy()
newEphemeralStorage := old.EphemeralStorage.DeepCopy()
newCPU.Sub(p.CPU)
newMemory.Sub(p.Memory)
newStorage.Sub(p.Storage)
newGpu.Sub(p.Gpu)
newEphemeralStorage.Sub(p.EphemeralStorage)
return &nodecorev1alpha1.Characteristics{
Architecture: old.Architecture,
Cpu: newCPU,
Memory: newMemory,
Gpu: newGpu,
PersistentStorage: newStorage,
EphemeralStorage: newEphemeralStorage,
}
}

func (r *AllocationReconciler) updateAllocationStatus(ctx context.Context, allocation *nodecorev1alpha1.Allocation) error {
return r.Status().Update(ctx, allocation)
}

// SetupWithManager sets up the controller with the Manager.
func (r *AllocationReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&nodecorev1alpha1.Allocation{}).
Expand Down
2 changes: 1 addition & 1 deletion pkg/utils/consts/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// package consts contains the constants used in the FLUIDOS and some miscellaneous ones.
// Package consts contains the constants used in the FLUIDOS and some miscellaneous ones.
package consts
Loading

0 comments on commit 187c244

Please sign in to comment.