From f28d85137071cadd02f22ca056baf1e01febe6b4 Mon Sep 17 00:00:00 2001 From: Andrea Colli-Vignarelli <48754766+andreacv98@users.noreply.github.com> Date: Wed, 24 Jan 2024 07:25:04 +0100 Subject: [PATCH] Fixed Liqo pods field compatibility (#25) --- apis/nodecore/v1alpha1/common.go | 1 + apis/nodecore/v1alpha1/flavour_types.go | 9 +++++ apis/nodecore/v1alpha1/solver_types.go | 7 ++-- .../v1alpha1/zz_generated.deepcopy.go | 9 ++++- .../advertisement.fluidos.eu_discoveries.yaml | 21 +++++++++-- ...tisement.fluidos.eu_peeringcandidates.yaml | 27 ++++++++++++++ .../crds/nodecore.fluidos.eu_allocations.yaml | 35 +++++++++++++++++++ .../crds/nodecore.fluidos.eu_flavours.yaml | 26 ++++++++++++++ .../crds/nodecore.fluidos.eu_solvers.yaml | 21 +++++++++-- .../reservation.fluidos.eu_contracts.yaml | 34 ++++++++++++++++++ .../reservation.fluidos.eu_reservations.yaml | 7 ++++ .../reservation.fluidos.eu_transactions.yaml | 7 ++++ .../node/samples/nginx-deployment.yaml | 26 ++++++++++++++ deployments/node/samples/solver.yaml | 3 +- pkg/local-resource-manager/node_services.go | 6 ++++ pkg/rear-controller/grpc/service.go | 1 + pkg/utils/common/common.go | 14 ++++++++ pkg/utils/flags/flags.go | 2 ++ pkg/utils/models/local-resource-manager.go | 2 ++ pkg/utils/models/models.go | 6 ++++ pkg/utils/models/reservation.go | 1 + pkg/utils/parseutil/parseutil.go | 10 +++++- pkg/utils/resourceforge/forge.go | 5 +++ testbed/kind/README.md | 19 ++++++++++ .../kind/consumer/cluster-multi-worker.yaml | 6 ++-- .../kind/provider/cluster-multi-worker.yaml | 6 ++-- 26 files changed, 294 insertions(+), 17 deletions(-) create mode 100644 deployments/node/samples/nginx-deployment.yaml diff --git a/apis/nodecore/v1alpha1/common.go b/apis/nodecore/v1alpha1/common.go index abfa044..20bf164 100644 --- a/apis/nodecore/v1alpha1/common.go +++ b/apis/nodecore/v1alpha1/common.go @@ -52,6 +52,7 @@ type Partition struct { Architecture string `json:"architecture"` CPU resource.Quantity `json:"cpu"` Memory resource.Quantity `json:"memory"` + Pods resource.Quantity `json:"pods"` Gpu resource.Quantity `json:"gpu,omitempty"` EphemeralStorage resource.Quantity `json:"ephemeral-storage,omitempty"` Storage resource.Quantity `json:"storage,omitempty"` diff --git a/apis/nodecore/v1alpha1/flavour_types.go b/apis/nodecore/v1alpha1/flavour_types.go index a68b2c0..513f5ed 100644 --- a/apis/nodecore/v1alpha1/flavour_types.go +++ b/apis/nodecore/v1alpha1/flavour_types.go @@ -36,6 +36,9 @@ type Characteristics struct { // Memory is the amount of RAM of the Flavour. Memory resource.Quantity `json:"memory"` + // Pods is the maximum number of pods of the Flavour. + Pods resource.Quantity `json:"pods"` + // GPU is the number of GPU cores of the Flavour. Gpu resource.Quantity `json:"gpu,omitempty"` @@ -63,11 +66,17 @@ type Partitionable struct { // MemoryMin is the minimum requirable amount of RAM of the Flavour. MemoryMin resource.Quantity `json:"memoryMin"` + // PodsMin is the minimum requirable number of pods of the Flavour. + PodsMin resource.Quantity `json:"podsMin"` + // CpuStep is the incremental value of CPU cores of the Flavour. CpuStep resource.Quantity `json:"cpuStep"` // MemoryStep is the incremental value of RAM of the Flavour. MemoryStep resource.Quantity `json:"memoryStep"` + + // PodsStep is the incremental value of pods of the Flavour. + PodsStep resource.Quantity `json:"podsStep"` } // Aggregatable represents the aggregation properties of a Flavour, such as the minimum instance count. diff --git a/apis/nodecore/v1alpha1/solver_types.go b/apis/nodecore/v1alpha1/solver_types.go index e368c45..b50a63c 100644 --- a/apis/nodecore/v1alpha1/solver_types.go +++ b/apis/nodecore/v1alpha1/solver_types.go @@ -54,8 +54,9 @@ type FlavourSelector struct { // MatchSelector represents the criteria for selecting Flavours through a strict match. type MatchSelector struct { - Cpu resource.Quantity `json:"cpu"` - Memory resource.Quantity `json:"memory"` + CPU resource.Quantity `json:"cpu,omitempty"` + Memory resource.Quantity `json:"memory,omitempty"` + Pods resource.Quantity `json:"pods,omitempty"` Storage resource.Quantity `json:"storage,omitempty"` EphemeralStorage resource.Quantity `json:"ephemeralStorage,omitempty"` Gpu resource.Quantity `json:"gpu,omitempty"` @@ -65,11 +66,13 @@ type MatchSelector struct { type RangeSelector struct { MinCpu resource.Quantity `json:"minCpu,omitempty"` MinMemory resource.Quantity `json:"minMemory,omitempty"` + MinPods resource.Quantity `json:"minPods,omitempty"` MinEph resource.Quantity `json:"minEph,omitempty"` MinStorage resource.Quantity `json:"minStorage,omitempty"` MinGpu resource.Quantity `json:"minGpu,omitempty"` MaxCpu resource.Quantity `json:"MaxCpu,omitempty"` MaxMemory resource.Quantity `json:"MaxMemory,omitempty"` + MaxPods resource.Quantity `json:"MaxPods,omitempty"` MaxEph resource.Quantity `json:"MaxEph,omitempty"` MaxStorage resource.Quantity `json:"MaxStorage,omitempty"` MaxGpu resource.Quantity `json:"MaxGpu,omitempty"` diff --git a/apis/nodecore/v1alpha1/zz_generated.deepcopy.go b/apis/nodecore/v1alpha1/zz_generated.deepcopy.go index 9cb9408..8e8de85 100644 --- a/apis/nodecore/v1alpha1/zz_generated.deepcopy.go +++ b/apis/nodecore/v1alpha1/zz_generated.deepcopy.go @@ -133,6 +133,7 @@ func (in *Characteristics) DeepCopyInto(out *Characteristics) { *out = *in out.Cpu = in.Cpu.DeepCopy() out.Memory = in.Memory.DeepCopy() + out.Pods = in.Pods.DeepCopy() out.Gpu = in.Gpu.DeepCopy() out.EphemeralStorage = in.EphemeralStorage.DeepCopy() out.PersistentStorage = in.PersistentStorage.DeepCopy() @@ -300,8 +301,9 @@ func (in *LiqoCredentials) DeepCopy() *LiqoCredentials { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MatchSelector) DeepCopyInto(out *MatchSelector) { *out = *in - out.Cpu = in.Cpu.DeepCopy() + out.CPU = in.CPU.DeepCopy() out.Memory = in.Memory.DeepCopy() + out.Pods = in.Pods.DeepCopy() out.Storage = in.Storage.DeepCopy() out.EphemeralStorage = in.EphemeralStorage.DeepCopy() out.Gpu = in.Gpu.DeepCopy() @@ -352,6 +354,7 @@ func (in *Partition) DeepCopyInto(out *Partition) { *out = *in out.CPU = in.CPU.DeepCopy() out.Memory = in.Memory.DeepCopy() + out.Pods = in.Pods.DeepCopy() out.Gpu = in.Gpu.DeepCopy() out.EphemeralStorage = in.EphemeralStorage.DeepCopy() out.Storage = in.Storage.DeepCopy() @@ -372,8 +375,10 @@ func (in *Partitionable) DeepCopyInto(out *Partitionable) { *out = *in out.CpuMin = in.CpuMin.DeepCopy() out.MemoryMin = in.MemoryMin.DeepCopy() + out.PodsMin = in.PodsMin.DeepCopy() out.CpuStep = in.CpuStep.DeepCopy() out.MemoryStep = in.MemoryStep.DeepCopy() + out.PodsStep = in.PodsStep.DeepCopy() } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Partitionable. @@ -446,11 +451,13 @@ func (in *RangeSelector) DeepCopyInto(out *RangeSelector) { *out = *in out.MinCpu = in.MinCpu.DeepCopy() out.MinMemory = in.MinMemory.DeepCopy() + out.MinPods = in.MinPods.DeepCopy() out.MinEph = in.MinEph.DeepCopy() out.MinStorage = in.MinStorage.DeepCopy() out.MinGpu = in.MinGpu.DeepCopy() out.MaxCpu = in.MaxCpu.DeepCopy() out.MaxMemory = in.MaxMemory.DeepCopy() + out.MaxPods = in.MaxPods.DeepCopy() out.MaxEph = in.MaxEph.DeepCopy() out.MaxStorage = in.MaxStorage.DeepCopy() out.MaxGpu = in.MaxGpu.DeepCopy() diff --git a/deployments/node/crds/advertisement.fluidos.eu_discoveries.yaml b/deployments/node/crds/advertisement.fluidos.eu_discoveries.yaml index 9a1c202..35fce63 100644 --- a/deployments/node/crds/advertisement.fluidos.eu_discoveries.yaml +++ b/deployments/node/crds/advertisement.fluidos.eu_discoveries.yaml @@ -89,15 +89,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true storage: anyOf: - type: integer - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - required: - - cpu - - memory type: object rangeSelector: description: RangeSelector represents the criteria for selecting @@ -127,6 +130,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + MaxPods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true MaxStorage: anyOf: - type: integer @@ -157,6 +166,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + minPods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true minStorage: anyOf: - type: integer diff --git a/deployments/node/crds/advertisement.fluidos.eu_peeringcandidates.yaml b/deployments/node/crds/advertisement.fluidos.eu_peeringcandidates.yaml index eae98db..79bc042 100644 --- a/deployments/node/crds/advertisement.fluidos.eu_peeringcandidates.yaml +++ b/deployments/node/crds/advertisement.fluidos.eu_peeringcandidates.yaml @@ -117,10 +117,19 @@ spec: storage of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + description: Pods is the maximum number of pods of the + Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - architecture - cpu - memory + - pods type: object optionalFields: description: This field is used to specify the optional fields @@ -211,11 +220,29 @@ spec: RAM of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + podsMin: + anyOf: + - type: integer + - type: string + description: PodsMin is the minimum requirable number + of pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + podsStep: + anyOf: + - type: integer + - type: string + description: PodsStep is the incremental value of + pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - cpuMin - cpuStep - memoryMin - memoryStep + - podsMin + - podsStep type: object type: object price: diff --git a/deployments/node/crds/nodecore.fluidos.eu_allocations.yaml b/deployments/node/crds/nodecore.fluidos.eu_allocations.yaml index ee8b792..48dbf8e 100644 --- a/deployments/node/crds/nodecore.fluidos.eu_allocations.yaml +++ b/deployments/node/crds/nodecore.fluidos.eu_allocations.yaml @@ -123,10 +123,19 @@ spec: storage of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + description: Pods is the maximum number of pods of the + Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - architecture - cpu - memory + - pods type: object optionalFields: description: This field is used to specify the optional fields @@ -217,11 +226,29 @@ spec: RAM of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + podsMin: + anyOf: + - type: integer + - type: string + description: PodsMin is the minimum requirable number + of pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + podsStep: + anyOf: + - type: integer + - type: string + description: PodsStep is the incremental value of + pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - cpuMin - cpuStep - memoryMin - memoryStep + - podsMin + - podsStep type: object type: object price: @@ -345,10 +372,18 @@ spec: of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + description: Pods is the maximum number of pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - architecture - cpu - memory + - pods type: object type: description: 'This specifies the type of the node: Node (Physical diff --git a/deployments/node/crds/nodecore.fluidos.eu_flavours.yaml b/deployments/node/crds/nodecore.fluidos.eu_flavours.yaml index a8cc9da..9bcb22e 100644 --- a/deployments/node/crds/nodecore.fluidos.eu_flavours.yaml +++ b/deployments/node/crds/nodecore.fluidos.eu_flavours.yaml @@ -109,10 +109,18 @@ spec: of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + description: Pods is the maximum number of pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - architecture - cpu - memory + - pods type: object optionalFields: description: This field is used to specify the optional fields that @@ -201,11 +209,29 @@ spec: the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + podsMin: + anyOf: + - type: integer + - type: string + description: PodsMin is the minimum requirable number of pods + of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + podsStep: + anyOf: + - type: integer + - type: string + description: PodsStep is the incremental value of pods of + the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - cpuMin - cpuStep - memoryMin - memoryStep + - podsMin + - podsStep type: object type: object price: diff --git a/deployments/node/crds/nodecore.fluidos.eu_solvers.yaml b/deployments/node/crds/nodecore.fluidos.eu_solvers.yaml index 6ff8368..8b5255f 100644 --- a/deployments/node/crds/nodecore.fluidos.eu_solvers.yaml +++ b/deployments/node/crds/nodecore.fluidos.eu_solvers.yaml @@ -118,15 +118,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true storage: anyOf: - type: integer - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - required: - - cpu - - memory type: object rangeSelector: description: RangeSelector represents the criteria for selecting @@ -156,6 +159,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + MaxPods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true MaxStorage: anyOf: - type: integer @@ -186,6 +195,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + minPods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true minStorage: anyOf: - type: integer diff --git a/deployments/node/crds/reservation.fluidos.eu_contracts.yaml b/deployments/node/crds/reservation.fluidos.eu_contracts.yaml index f207890..227680a 100644 --- a/deployments/node/crds/reservation.fluidos.eu_contracts.yaml +++ b/deployments/node/crds/reservation.fluidos.eu_contracts.yaml @@ -178,10 +178,19 @@ spec: storage of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + description: Pods is the maximum number of pods of the + Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - architecture - cpu - memory + - pods type: object optionalFields: description: This field is used to specify the optional fields @@ -272,11 +281,29 @@ spec: RAM of the Flavour. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + podsMin: + anyOf: + - type: integer + - type: string + description: PodsMin is the minimum requirable number + of pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + podsStep: + anyOf: + - type: integer + - type: string + description: PodsStep is the incremental value of + pods of the Flavour. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true required: - cpuMin - cpuStep - memoryMin - memoryStep + - podsMin + - podsStep type: object type: object price: @@ -368,6 +395,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true storage: anyOf: - type: integer @@ -378,6 +411,7 @@ spec: - architecture - cpu - memory + - pods type: object seller: description: This is the Node identity of the seller FLUIDOS Node. diff --git a/deployments/node/crds/reservation.fluidos.eu_reservations.yaml b/deployments/node/crds/reservation.fluidos.eu_reservations.yaml index e026631..b6d1c29 100644 --- a/deployments/node/crds/reservation.fluidos.eu_reservations.yaml +++ b/deployments/node/crds/reservation.fluidos.eu_reservations.yaml @@ -120,6 +120,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true storage: anyOf: - type: integer @@ -130,6 +136,7 @@ spec: - architecture - cpu - memory + - pods type: object peeringCandidate: description: PeeringCandidate is the reference to the PeeringCandidate diff --git a/deployments/node/crds/reservation.fluidos.eu_transactions.yaml b/deployments/node/crds/reservation.fluidos.eu_transactions.yaml index 7f41aa6..7cc7f82 100644 --- a/deployments/node/crds/reservation.fluidos.eu_transactions.yaml +++ b/deployments/node/crds/reservation.fluidos.eu_transactions.yaml @@ -107,6 +107,12 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true + pods: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true storage: anyOf: - type: integer @@ -117,6 +123,7 @@ spec: - architecture - cpu - memory + - pods type: object startTime: description: StartTime is the time at which the reservation should diff --git a/deployments/node/samples/nginx-deployment.yaml b/deployments/node/samples/nginx-deployment.yaml new file mode 100644 index 0000000..c64a180 --- /dev/null +++ b/deployments/node/samples/nginx-deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: 2 # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + resources: + limits: + cpu: "500m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "128Mi" diff --git a/deployments/node/samples/solver.yaml b/deployments/node/samples/solver.yaml index 27373b6..d82fdd3 100644 --- a/deployments/node/samples/solver.yaml +++ b/deployments/node/samples/solver.yaml @@ -9,11 +9,12 @@ spec: # ONLY k8s-fluidos is supported at the moment type: k8s-fluidos # REMEMBER: the architecture is the one of the node, not the one of the container. Change it accordingly - architecture: arm64 + architecture: amd64 # ONLY rangeSelector is supported at the moment rangeSelector: minCpu: "1000m" minMemory: "1Gi" + minPods: "50" intentID: "intent-sample" # This flag is used to indicate that the solver should find a candidate (FLUIDOS node) findCandidate: true diff --git a/pkg/local-resource-manager/node_services.go b/pkg/local-resource-manager/node_services.go index e219418..f813988 100644 --- a/pkg/local-resource-manager/node_services.go +++ b/pkg/local-resource-manager/node_services.go @@ -78,19 +78,25 @@ func forgeResourceMetrics(nodeMetrics *metricsv1beta1.NodeMetrics, node *corev1. cpuUsed := nodeMetrics.Usage.Cpu() memoryTotal := node.Status.Allocatable.Memory() memoryUsed := nodeMetrics.Usage.Memory() + podsTotal := node.Status.Allocatable.Pods() + podsUsed := nodeMetrics.Usage.Pods() ephemeralStorage := nodeMetrics.Usage.StorageEphemeral() // Compute the available resources cpuAvail := cpuTotal.DeepCopy() memAvail := memoryTotal.DeepCopy() + podsAvail := podsTotal.DeepCopy() cpuAvail.Sub(*cpuUsed) memAvail.Sub(*memoryUsed) + podsAvail.Sub(*podsUsed) return &models.ResourceMetrics{ CPUTotal: *cpuTotal, CPUAvailable: cpuAvail, MemoryTotal: *memoryTotal, MemoryAvailable: memAvail, + PodsTotal: *podsTotal, + PodsAvailable: podsAvail, EphemeralStorage: *ephemeralStorage, } } diff --git a/pkg/rear-controller/grpc/service.go b/pkg/rear-controller/grpc/service.go index 05721df..2a05174 100644 --- a/pkg/rear-controller/grpc/service.go +++ b/pkg/rear-controller/grpc/service.go @@ -77,6 +77,7 @@ func mapQuantityToResourceList(partition *nodecorev1alpha1.Partition) map[string resources := make(map[string]*resource.Quantity) resources[corev1.ResourceCPU.String()] = &partition.CPU resources[corev1.ResourceMemory.String()] = &partition.Memory + resources[corev1.ResourcePods.String()] = &partition.Pods resources[corev1.ResourceStorage.String()] = &partition.Storage resources[corev1.ResourceEphemeralStorage.String()] = &partition.EphemeralStorage return resources diff --git a/pkg/utils/common/common.go b/pkg/utils/common/common.go index 58e3439..cd46ea0 100644 --- a/pkg/utils/common/common.go +++ b/pkg/utils/common/common.go @@ -78,6 +78,11 @@ func filterByMatchSelector(selector *models.Selector, f *nodecorev1alpha1.Flavou return false } + if selector.MatchSelector.Pods.CmpInt64(0) == 0 && f.Spec.Characteristics.Pods.Cmp(selector.MatchSelector.Pods) != 0 { + klog.Infof("MatchSelector Pods: %d - Flavour Pods: %d", selector.MatchSelector.Pods, f.Spec.Characteristics.Pods) + return false + } + if selector.MatchSelector.EphemeralStorage.CmpInt64(0) == 0 && f.Spec.Characteristics.EphemeralStorage.Cmp(selector.MatchSelector.EphemeralStorage) != 0 { klog.Infof("MatchSelector EphemeralStorage: %d - Flavour EphemeralStorage: %d", @@ -108,6 +113,11 @@ func filterByRangeSelector(selector *models.Selector, f *nodecorev1alpha1.Flavou return false } + if selector.RangeSelector.MinPods.CmpInt64(0) != 0 && f.Spec.Characteristics.Pods.Cmp(selector.RangeSelector.MinPods) < 0 { + klog.Infof("RangeSelector MinPods: %d - Flavour Pods: %d", selector.RangeSelector.MinPods, f.Spec.Characteristics.Pods) + return false + } + if selector.RangeSelector.MinEph.CmpInt64(0) != 0 && f.Spec.Characteristics.EphemeralStorage.Cmp(selector.RangeSelector.MinEph) < 0 { klog.Infof("RangeSelector MinEph: %d - Flavour EphemeralStorage: %d", selector.RangeSelector.MinEph, f.Spec.Characteristics.EphemeralStorage) return false @@ -130,6 +140,10 @@ func filterByRangeSelector(selector *models.Selector, f *nodecorev1alpha1.Flavou return false } + if selector.RangeSelector.MaxPods.CmpInt64(0) != 0 && f.Spec.Characteristics.Pods.Cmp(selector.RangeSelector.MaxPods) > 0 { + return false + } + if selector.RangeSelector.MaxEph.CmpInt64(0) != 0 && f.Spec.Characteristics.EphemeralStorage.Cmp(selector.RangeSelector.MaxEph) > 0 { return false } diff --git a/pkg/utils/flags/flags.go b/pkg/utils/flags/flags.go index 54bb7aa..87fe970 100644 --- a/pkg/utils/flags/flags.go +++ b/pkg/utils/flags/flags.go @@ -46,8 +46,10 @@ var ( PERIOD string CPUMin string MemoryMin string + PodsMin string CPUStep string MemoryStep string + PodsStep string MinCount int64 MaxCount int64 ) diff --git a/pkg/utils/models/local-resource-manager.go b/pkg/utils/models/local-resource-manager.go index 809064d..8d57453 100644 --- a/pkg/utils/models/local-resource-manager.go +++ b/pkg/utils/models/local-resource-manager.go @@ -33,5 +33,7 @@ type ResourceMetrics struct { CPUAvailable resource.Quantity `json:"availableCPU"` MemoryTotal resource.Quantity `json:"totalMemory"` MemoryAvailable resource.Quantity `json:"availableMemory"` + PodsTotal resource.Quantity `json:"totalPods"` + PodsAvailable resource.Quantity `json:"availablePods"` EphemeralStorage resource.Quantity `json:"ephemeralStorage"` } diff --git a/pkg/utils/models/models.go b/pkg/utils/models/models.go index e48c254..b631ed6 100644 --- a/pkg/utils/models/models.go +++ b/pkg/utils/models/models.go @@ -37,6 +37,7 @@ type Flavour struct { type Characteristics struct { CPU resource.Quantity `json:"cpu,omitempty"` Memory resource.Quantity `json:"memory,omitempty"` + Pods resource.Quantity `json:"pods,omitempty"` PersistentStorage resource.Quantity `json:"storage,omitempty"` EphemeralStorage resource.Quantity `json:"ephemeralStorage,omitempty"` Gpu resource.Quantity `json:"gpu,omitempty"` @@ -53,8 +54,10 @@ type Policy struct { type Partitionable struct { CPUMinimum resource.Quantity `json:"cpuMinimum"` MemoryMinimum resource.Quantity `json:"memoryMinimum"` + PodsMinimum resource.Quantity `json:"podsMinimum"` CPUStep resource.Quantity `json:"cpuStep"` MemoryStep resource.Quantity `json:"memoryStep"` + PodsStep resource.Quantity `json:"podsStep"` } // Aggregatable represents the aggregation properties of a Flavour, such as the minimum instance count. @@ -95,6 +98,7 @@ type Selector struct { type MatchSelector struct { CPU resource.Quantity `json:"cpu,omitempty"` Memory resource.Quantity `json:"memory,omitempty"` + Pods resource.Quantity `json:"pods,omitempty"` Storage resource.Quantity `json:"storage,omitempty"` EphemeralStorage resource.Quantity `json:"ephemeralStorage,omitempty"` Gpu resource.Quantity `json:"gpu,omitempty"` @@ -104,11 +108,13 @@ type MatchSelector struct { type RangeSelector struct { MinCPU resource.Quantity `json:"minCpu,omitempty"` MinMemory resource.Quantity `json:"minMemory,omitempty"` + MinPods resource.Quantity `json:"minPods,omitempty"` MinStorage resource.Quantity `json:"minStorage,omitempty"` MinEph resource.Quantity `json:"minEph,omitempty"` MinGpu resource.Quantity `json:"minGpu,omitempty"` MaxCPU resource.Quantity `json:"maxCpu,omitempty"` MaxMemory resource.Quantity `json:"maxMemory,omitempty"` + MaxPods resource.Quantity `json:"maxPods,omitempty"` MaxStorage resource.Quantity `json:"maxStorage,omitempty"` MaxEph resource.Quantity `json:"maxEph,omitempty"` MaxGpu resource.Quantity `json:"maxGpu,omitempty"` diff --git a/pkg/utils/models/reservation.go b/pkg/utils/models/reservation.go index 192e1fb..18d9577 100644 --- a/pkg/utils/models/reservation.go +++ b/pkg/utils/models/reservation.go @@ -21,6 +21,7 @@ type Partition struct { Architecture string `json:"architecture"` CPU resource.Quantity `json:"cpu"` Memory resource.Quantity `json:"memory"` + Pods resource.Quantity `json:"pods"` EphemeralStorage resource.Quantity `json:"ephemeral-storage,omitempty"` Gpu resource.Quantity `json:"gpu,omitempty"` Storage resource.Quantity `json:"storage,omitempty"` diff --git a/pkg/utils/parseutil/parseutil.go b/pkg/utils/parseutil/parseutil.go index 18ccae4..fae8c7e 100644 --- a/pkg/utils/parseutil/parseutil.go +++ b/pkg/utils/parseutil/parseutil.go @@ -31,8 +31,9 @@ func ParseFlavourSelector(selector *nodecorev1alpha1.FlavourSelector) *models.Se if selector.MatchSelector != nil { s.MatchSelector = &models.MatchSelector{ - CPU: selector.MatchSelector.Cpu, + CPU: selector.MatchSelector.CPU, Memory: selector.MatchSelector.Memory, + Pods: selector.MatchSelector.Pods, EphemeralStorage: selector.MatchSelector.EphemeralStorage, Storage: selector.MatchSelector.Storage, Gpu: selector.MatchSelector.Gpu, @@ -43,11 +44,13 @@ func ParseFlavourSelector(selector *nodecorev1alpha1.FlavourSelector) *models.Se s.RangeSelector = &models.RangeSelector{ MinCPU: selector.RangeSelector.MinCpu, MinMemory: selector.RangeSelector.MinMemory, + MinPods: selector.RangeSelector.MinPods, MinEph: selector.RangeSelector.MinEph, MinStorage: selector.RangeSelector.MinStorage, MinGpu: selector.RangeSelector.MinGpu, MaxCPU: selector.RangeSelector.MaxCpu, MaxMemory: selector.RangeSelector.MaxMemory, + MaxPods: selector.RangeSelector.MaxPods, MaxEph: selector.RangeSelector.MaxEph, MaxStorage: selector.RangeSelector.MaxStorage, MaxGpu: selector.RangeSelector.MaxGpu, @@ -62,6 +65,7 @@ func ParsePartition(partition *nodecorev1alpha1.Partition) *models.Partition { return &models.Partition{ CPU: partition.CPU, Memory: partition.Memory, + Pods: partition.Pods, EphemeralStorage: partition.EphemeralStorage, Storage: partition.Storage, Gpu: partition.Gpu, @@ -74,6 +78,7 @@ func ParsePartitionFromObj(partition *models.Partition) *nodecorev1alpha1.Partit Architecture: partition.Architecture, CPU: partition.CPU, Memory: partition.Memory, + Pods: partition.Pods, Gpu: partition.Gpu, Storage: partition.Storage, EphemeralStorage: partition.EphemeralStorage, @@ -98,6 +103,7 @@ func ParseFlavour(flavour *nodecorev1alpha1.Flavour) *models.Flavour { Characteristics: models.Characteristics{ CPU: flavour.Spec.Characteristics.Cpu, Memory: flavour.Spec.Characteristics.Memory, + Pods: flavour.Spec.Characteristics.Pods, PersistentStorage: flavour.Spec.Characteristics.PersistentStorage, EphemeralStorage: flavour.Spec.Characteristics.EphemeralStorage, Gpu: flavour.Spec.Characteristics.Gpu, @@ -109,8 +115,10 @@ func ParseFlavour(flavour *nodecorev1alpha1.Flavour) *models.Flavour { return &models.Partitionable{ CPUMinimum: flavour.Spec.Policy.Partitionable.CpuMin, MemoryMinimum: flavour.Spec.Policy.Partitionable.MemoryMin, + PodsMinimum: flavour.Spec.Policy.Partitionable.PodsMin, CPUStep: flavour.Spec.Policy.Partitionable.CpuStep, MemoryStep: flavour.Spec.Policy.Partitionable.MemoryStep, + PodsStep: flavour.Spec.Policy.Partitionable.PodsStep, } } return nil diff --git a/pkg/utils/resourceforge/forge.go b/pkg/utils/resourceforge/forge.go index ca04f1a..b6b502a 100644 --- a/pkg/utils/resourceforge/forge.go +++ b/pkg/utils/resourceforge/forge.go @@ -165,6 +165,7 @@ func ForgeFlavourFromMetrics(node *models.NodeInfo, ni nodecorev1alpha1.NodeIden Architecture: node.Architecture, Cpu: node.ResourceMetrics.CPUAvailable, Memory: node.ResourceMetrics.MemoryAvailable, + Pods: node.ResourceMetrics.PodsAvailable, EphemeralStorage: node.ResourceMetrics.EphemeralStorage, PersistentStorage: parseutil.ParseQuantityFromString("0"), Gpu: parseutil.ParseQuantityFromString("0"), @@ -173,6 +174,7 @@ func ForgeFlavourFromMetrics(node *models.NodeInfo, ni nodecorev1alpha1.NodeIden Partitionable: &nodecorev1alpha1.Partitionable{ CpuMin: parseutil.ParseQuantityFromString(flags.CPUMin), MemoryMin: parseutil.ParseQuantityFromString(flags.MemoryMin), + PodsMin: parseutil.ParseQuantityFromString(flags.PodsMin), CpuStep: parseutil.ParseQuantityFromString(flags.CPUStep), MemoryStep: parseutil.ParseQuantityFromString(flags.MemoryStep), }, @@ -365,6 +367,7 @@ func ForgeFlavourFromObj(flavour *models.Flavour) *nodecorev1alpha1.Flavour { Characteristics: nodecorev1alpha1.Characteristics{ Cpu: flavour.Characteristics.CPU, Memory: flavour.Characteristics.Memory, + Pods: flavour.Characteristics.Pods, Architecture: flavour.Characteristics.Architecture, EphemeralStorage: flavour.Characteristics.EphemeralStorage, PersistentStorage: flavour.Characteristics.PersistentStorage, @@ -418,6 +421,7 @@ func ForgePartition(selector *nodecorev1alpha1.FlavourSelector) *nodecorev1alpha Architecture: selector.Architecture, CPU: selector.RangeSelector.MinCpu, Memory: selector.RangeSelector.MinMemory, + Pods: selector.RangeSelector.MinPods, EphemeralStorage: selector.RangeSelector.MinEph, Storage: selector.RangeSelector.MinStorage, Gpu: selector.RangeSelector.MinGpu, @@ -452,6 +456,7 @@ func ForgeAllocation(contract *reservationv1alpha1.Contract, intentID, nodeName Architecture: contract.Spec.Partition.Architecture, Cpu: contract.Spec.Partition.CPU, Memory: contract.Spec.Partition.Memory, + Pods: contract.Spec.Partition.Pods, EphemeralStorage: contract.Spec.Partition.EphemeralStorage, Gpu: contract.Spec.Partition.Gpu, PersistentStorage: contract.Spec.Partition.Storage, diff --git a/testbed/kind/README.md b/testbed/kind/README.md index 58071d5..d0ced76 100644 --- a/testbed/kind/README.md +++ b/testbed/kind/README.md @@ -145,3 +145,22 @@ kubectl get contracts.reservation.fluidos.eu -n fluidos kubectl get peeringcandidates.advertisement.fluidos.eu -n fluidos kubectl get transactions.reservation.fluidos.eu -n fluidos ``` + +6. The infrastructure for the resource sharing has been created. + +You can now create a demo namespace on the `fluidos-consumer` cluster: + +```sh +kubectl create namespace demo +``` +And then offload the namespace to the `fluidos-provider` cluster: + +```sh +liqoctl offload namespace demo --pod-offloading-strategy Remote +``` + +You can now create a workload inside this offloaded namespace through and already provided Kubernetes deployment: + +```sh +kubectl apply -f nginx-deployment.yaml -n demo +``` diff --git a/testbed/kind/consumer/cluster-multi-worker.yaml b/testbed/kind/consumer/cluster-multi-worker.yaml index 60fe086..17517ce 100644 --- a/testbed/kind/consumer/cluster-multi-worker.yaml +++ b/testbed/kind/consumer/cluster-multi-worker.yaml @@ -2,13 +2,13 @@ kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - image: kindest/node:v1.25.0 + image: kindest/node:v1.28.0 - role: worker labels: node-role.fluidos.eu/resources: "true" node-role.fluidos.eu/worker: "true" - image: kindest/node:v1.25.0 + image: kindest/node:v1.28.0 - role: worker - image: kindest/node:v1.25.0 + image: kindest/node:v1.28.0 labels: node-role.fluidos.eu/resources: "true" \ No newline at end of file diff --git a/testbed/kind/provider/cluster-multi-worker.yaml b/testbed/kind/provider/cluster-multi-worker.yaml index 5822274..43a4d7c 100644 --- a/testbed/kind/provider/cluster-multi-worker.yaml +++ b/testbed/kind/provider/cluster-multi-worker.yaml @@ -2,13 +2,13 @@ kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - image: kindest/node:v1.25.0 + image: kindest/node:v1.28.0 - role: worker labels: node-role.fluidos.eu/resources: "true" node-role.fluidos.eu/worker: "true" - image: kindest/node:v1.25.0 + image: kindest/node:v1.28.0 - role: worker - image: kindest/node:v1.25.0 + image: kindest/node:v1.28.0 labels: node-role.fluidos.eu/resources: "true"