Skip to content

Commit d6b42e9

Browse files
committed
feat(liqoctl): specify non-standard resources with liqoctl
This patch introduces the `--resource` flag to the `peer` `create virtualnode` and `create resourceslice` commands, to allow the user to directly specify custom resources without the needs to manually edit the manifests.
1 parent de96cea commit d6b42e9

File tree

10 files changed

+92
-35
lines changed

10 files changed

+92
-35
lines changed

cmd/liqoctl/cmd/peer.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Examples:
5252
$ {{ .Executable }} peer --remote-kubeconfig <provider>
5353
$ {{ .Executable }} peer --remote-kubeconfig <provider> --gw-server-service-type NodePort
5454
$ {{ .Executable }} peer --remote-kubeconfig <provider> --cpu 2 --memory 4Gi --pods 10
55+
$ {{ .Executable }} peer --remote-kubeconfig <provider> --cpu 2 --memory 4Gi --pods 10 --resource nvidia.com/gpu=2
5556
$ {{ .Executable }} peer --remote-kubeconfig <provider> --create-resource-slice false
5657
$ {{ .Executable }} peer --remote-kubeconfig <provider> --create-virtual-node false
5758
`
@@ -129,6 +130,8 @@ func newPeerCommand(ctx context.Context, f *factory.Factory) *cobra.Command {
129130
cmd.Flags().StringVar(&options.CPU, "cpu", "", "The amount of CPU requested for the VirtualNode")
130131
cmd.Flags().StringVar(&options.Memory, "memory", "", "The amount of memory requested for the VirtualNode")
131132
cmd.Flags().StringVar(&options.Pods, "pods", "", "The amount of pods requested for the VirtualNode")
133+
cmd.Flags().StringToStringVar(
134+
&options.OtherResources, "resource", nil, "Other resources requested for the VirtualNode (e.g., 'resource=nvidia.com/gpu=2')")
132135

133136
return cmd
134137
}

docs/advanced/peering/offloading-in-depth.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ You can specify the resources you want to acquire by adding:
6161
* `--cpu` to specify the amount of CPU.
6262
* `--memory` to specify the amount of memory.
6363
* `--pods` to specify the number of pods.
64+
* `--resource` other resources can be specified with this flag, which can be even repeated multiple times. (e.g: `--resource=nvidia.com/gpu=2 --resource=my.custom/resource=2Gi`)
6465

6566
To add other resources like `ephemeral-storage`, `gpu`, or any other custom resources, you can use the `-o yaml` flag for the `liqoctl create resourceslice` command and edit the `ResourceSlice` spec manifest before applying it.
6667

docs/usage/liqoctl/liqoctl_create.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,8 @@ liqoctl create resourceslice [flags]
500500
```bash
501501
$ liqoctl create resourceslice my-slice --remote-cluster-id remote-cluster-id \
502502
--cpu 4 --memory 8Gi --pods 30
503+
$ liqoctl create resourceslice my-slice --remote-cluster-id remote-cluster-id \
504+
--cpu 4 --memory 8Gi --pods 30 --resource nvidia.com/gpu=2
503505
```
504506

505507

@@ -532,6 +534,10 @@ liqoctl create resourceslice [flags]
532534

533535
>The cluster ID of the remote cluster
534536
537+
`--resource` _stringToString_:
538+
539+
>Other resources requested in the resource slice (e.g., 'resource=nvidia.com/gpu=2')
540+
535541

536542
### Global options
537543

@@ -656,6 +662,10 @@ liqoctl create virtualnode [flags]
656662

657663
>The cluster ID of the remote cluster
658664
665+
`--resource` _stringToString_:
666+
667+
>Other resources available in the virtual node (e.g., 'resource=nvidia.com/gpu=2')
668+
659669
`--resource-slice-name` _string_:
660670

661671
>The name of the resourceslice to be used to create the virtual node. Mutually exclusive with --kubeconfig-secret-name

docs/usage/liqoctl/liqoctl_peer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ liqoctl peer [flags]
3737
$ liqoctl peer --remote-kubeconfig <provider>
3838
$ liqoctl peer --remote-kubeconfig <provider> --gw-server-service-type NodePort
3939
$ liqoctl peer --remote-kubeconfig <provider> --cpu 2 --memory 4Gi --pods 10
40+
$ liqoctl peer --remote-kubeconfig <provider> --cpu 2 --memory 4Gi --pods 10 --resource nvidia.com/gpu=2
4041
$ liqoctl peer --remote-kubeconfig <provider> --create-resource-slice false
4142
$ liqoctl peer --remote-kubeconfig <provider> --create-virtual-node false
4243
```
@@ -146,6 +147,10 @@ liqoctl peer [flags]
146147

147148
>The name of the kubeconfig user to use (in the remote cluster)
148149
150+
`--resource` _stringToString_:
151+
152+
>Other resources requested for the VirtualNode (e.g., 'resource=nvidia.com/gpu=2')
153+
149154
`--resource-slice-class` _string_:
150155

151156
>The class of the ResourceSlice **(default "default")**

docs/usage/peer.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ To perform a peering without having access to both clusters, you need to manuall
3636
The peering command enables all 3 liqo modules and performs the following steps:
3737

3838
1. **enables networking**.
39-
Exchanges network configurations and creates the two **gateways** (one acting as _server_ and located in the provider cluster, another acting as _client_ in the consumer cluster) to let the two clusters communicate over a secure tunnel.
40-
The location of the client/server gateway can be customized when creating the peering using the `--gw-server-service-location` flag in `liqoctl`.
39+
Exchanges network configurations and creates the two **gateways** (one acting as _server_ and located in the provider cluster, another acting as _client_ in the consumer cluster) to let the two clusters communicate over a secure tunnel.
40+
The location of the client/server gateway can be customized when creating the peering using the `--gw-server-service-location` flag in `liqoctl`.
4141
2. **enables authentication**.
4242
Authenticates the consumer with the provider.
4343
In this step, the consumer obtains an `Identity` (*kubeconfig*) to replicate resources to the provider cluster.
@@ -237,6 +237,18 @@ liqoctl peer \
237237
--memory=2Gi
238238
```
239239

240+
Other non-standard resources can be defined via the `--resource` flag:
241+
242+
```bash
243+
liqoctl peer \
244+
--kubeconfig=$CONSUMER_KUBECONFIG_PATH \
245+
--remote-kubeconfig=$PROVIDER_KUBECONFIG_PATH \
246+
--cpu=2 \
247+
--memory=2Gi \
248+
--resource=nvidia.com/gpu=2 \
249+
--resource=custom=2Gi
250+
```
251+
240252
```{warning}
241253
To make sure the consumer cluster does not exceed the quota of shared resources, the offloaded pods need to be created with the resources `limits` set.
242254

pkg/liqoctl/peer/handler.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ type Options struct {
6161
CPU string
6262
Memory string
6363
Pods string
64+
OtherResources map[string]string
6465
}
6566

6667
// NewOptions returns a new Options struct.
@@ -195,9 +196,10 @@ func ensureOffloading(ctx context.Context, o *Options) error {
195196
Class: o.ResourceSliceClass,
196197
DisableVirtualNodeCreation: !o.CreateVirtualNode,
197198

198-
CPU: o.CPU,
199-
Memory: o.Memory,
200-
Pods: o.Pods,
199+
CPU: o.CPU,
200+
Memory: o.Memory,
201+
Pods: o.Pods,
202+
OtherResources: o.OtherResources,
201203
}
202204

203205
if err := rsOptions.HandleCreate(ctx); err != nil {

pkg/liqoctl/rest/resourceslice/create.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ The ResourceSlice resource is used to represent a slice of resources that can be
4444
4545
Examples:
4646
$ {{ .Executable }} create resourceslice my-slice --remote-cluster-id remote-cluster-id \
47-
--cpu 4 --memory 8Gi --pods 30`
47+
--cpu 4 --memory 8Gi --pods 30
48+
$ {{ .Executable }} create resourceslice my-slice --remote-cluster-id remote-cluster-id \
49+
--cpu 4 --memory 8Gi --pods 30 --resource nvidia.com/gpu=2`
4850

4951
// Create implements the create command.
5052
func (o *Options) Create(ctx context.Context, options *rest.CreateOptions) *cobra.Command {
@@ -80,6 +82,8 @@ func (o *Options) Create(ctx context.Context, options *rest.CreateOptions) *cobr
8082
cmd.Flags().StringVar(&o.CPU, "cpu", "", "The amount of CPU requested in the resource slice")
8183
cmd.Flags().StringVar(&o.Memory, "memory", "", "The amount of memory requested in the resource slice")
8284
cmd.Flags().StringVar(&o.Pods, "pods", "", "The amount of pods requested in the resource slice")
85+
cmd.Flags().StringToStringVar(
86+
&o.OtherResources, "resource", nil, "Other resources requested in the resource slice (e.g., 'resource=nvidia.com/gpu=2')")
8387
cmd.Flags().BoolVar(&o.DisableVirtualNodeCreation, "no-virtual-node", false,
8488
"Prevent the automatic creation of a VirtualNode for the ResourceSlice. Default: false")
8589

@@ -111,12 +115,8 @@ func (o *Options) HandleCreate(ctx context.Context) error {
111115
resourceSlice := forge.ResourceSlice(opts.Name, namespace)
112116
_, err = resource.CreateOrUpdate(ctx, opts.CRClient, resourceSlice, func() error {
113117
return forge.MutateResourceSlice(resourceSlice, o.RemoteClusterID.GetClusterID(), &forge.ResourceSliceOptions{
114-
Class: authv1beta1.ResourceSliceClass(o.Class),
115-
Resources: map[corev1.ResourceName]string{
116-
corev1.ResourceCPU: o.CPU,
117-
corev1.ResourceMemory: o.Memory,
118-
corev1.ResourcePods: o.Pods,
119-
},
118+
Class: authv1beta1.ResourceSliceClass(o.Class),
119+
Resources: o.buildResourceMap(),
120120
}, !o.DisableVirtualNodeCreation)
121121
})
122122
if err != nil {
@@ -157,6 +157,21 @@ func (o *Options) getTenantNamespace(ctx context.Context) (string, error) {
157157
}
158158
}
159159

160+
func (o *Options) buildResourceMap() map[corev1.ResourceName]string {
161+
resources := map[corev1.ResourceName]string{
162+
corev1.ResourceCPU: o.CPU,
163+
corev1.ResourceMemory: o.Memory,
164+
corev1.ResourcePods: o.Pods,
165+
}
166+
167+
// Add other resources to the resources map.
168+
for name, quantity := range o.OtherResources {
169+
resources[corev1.ResourceName(name)] = quantity
170+
}
171+
172+
return resources
173+
}
174+
160175
// output implements the logic to output the generated ResourceSlice resource.
161176
func (o *Options) output(ctx context.Context) error {
162177
opts := o.CreateOptions
@@ -177,12 +192,8 @@ func (o *Options) output(ctx context.Context) error {
177192

178193
resourceSlice := forge.ResourceSlice(opts.Name, namespace)
179194
err = forge.MutateResourceSlice(resourceSlice, o.RemoteClusterID.GetClusterID(), &forge.ResourceSliceOptions{
180-
Class: authv1beta1.ResourceSliceClass(o.Class),
181-
Resources: map[corev1.ResourceName]string{
182-
corev1.ResourceCPU: o.CPU,
183-
corev1.ResourceMemory: o.Memory,
184-
corev1.ResourcePods: o.Pods,
185-
},
195+
Class: authv1beta1.ResourceSliceClass(o.Class),
196+
Resources: o.buildResourceMap(),
186197
}, !o.DisableVirtualNodeCreation)
187198
if err != nil {
188199
return err

pkg/liqoctl/rest/resourceslice/types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ type Options struct {
2929
Class string
3030
DisableVirtualNodeCreation bool
3131

32-
CPU string
33-
Memory string
34-
Pods string
32+
CPU string
33+
Memory string
34+
Pods string
35+
OtherResources map[string]string
3536
}
3637

3738
var _ rest.API = &Options{}

pkg/liqoctl/rest/virtualnode/create.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ func (o *Options) Create(ctx context.Context, options *rest.CreateOptions) *cobr
9494
cmd.Flags().StringVar(&o.cpu, "cpu", "2", "The amount of CPU available in the virtual node")
9595
cmd.Flags().StringVar(&o.memory, "memory", "4Gi", "The amount of memory available in the virtual node")
9696
cmd.Flags().StringVar(&o.pods, "pods", "110", "The amount of pods available in the virtual node")
97+
cmd.Flags().StringToStringVar(&o.otherResources, "resource", nil,
98+
"Other resources available in the virtual node (e.g., 'resource=nvidia.com/gpu=2')")
9799
cmd.Flags().StringSliceVar(&o.storageClasses, "storage-classes",
98100
[]string{}, "The storage classes offered by the remote cluster. The first one will be used as default")
99101
cmd.Flags().StringSliceVar(&o.ingressClasses, "ingress-classes",
@@ -225,6 +227,20 @@ func (o *Options) forgeVirtualNodeOptions(vkOptionsTemplateRef *corev1.ObjectRef
225227
return nil, fmt.Errorf("unable to parse pod quantity: %w", err)
226228
}
227229

230+
resourceMap := corev1.ResourceList{
231+
corev1.ResourceCPU: cpuQnt,
232+
corev1.ResourceMemory: memoryQnt,
233+
corev1.ResourcePods: podsQnt,
234+
}
235+
236+
for resourceName, resourceValue := range o.otherResources {
237+
parsedQuantity, err := k8sresource.ParseQuantity(resourceValue)
238+
if err != nil {
239+
return nil, fmt.Errorf("unable to parse quantity for resource %q: %w", resourceName, err)
240+
}
241+
resourceMap[corev1.ResourceName(resourceName)] = parsedQuantity
242+
}
243+
228244
storageClasses := make([]liqov1beta1.StorageType, len(o.storageClasses))
229245
for i, storageClass := range o.storageClasses {
230246
sc := liqov1beta1.StorageType{
@@ -261,17 +277,12 @@ func (o *Options) forgeVirtualNodeOptions(vkOptionsTemplateRef *corev1.ObjectRef
261277
return &forge.VirtualNodeOptions{
262278
KubeconfigSecretRef: corev1.LocalObjectReference{Name: o.kubeconfigSecretName},
263279
VkOptionsTemplateRef: vkOptionsTemplateRef,
264-
265-
ResourceList: corev1.ResourceList{
266-
corev1.ResourceCPU: cpuQnt,
267-
corev1.ResourceMemory: memoryQnt,
268-
corev1.ResourcePods: podsQnt,
269-
},
270-
StorageClasses: storageClasses,
271-
IngressClasses: ingressClasses,
272-
LoadBalancerClasses: loadBalancerClasses,
273-
NodeLabels: o.labels,
274-
NodeSelector: o.nodeSelector,
280+
ResourceList: resourceMap,
281+
StorageClasses: storageClasses,
282+
IngressClasses: ingressClasses,
283+
LoadBalancerClasses: loadBalancerClasses,
284+
NodeLabels: o.labels,
285+
NodeSelector: o.nodeSelector,
275286
}, nil
276287
}
277288

pkg/liqoctl/rest/virtualnode/types.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ type Options struct {
3333
resourceSliceName string
3434
vkOptionsTemplate string
3535

36-
cpu string
37-
memory string
38-
pods string
36+
cpu string
37+
memory string
38+
pods string
39+
otherResources map[string]string
3940

4041
storageClasses []string
4142
ingressClasses []string

0 commit comments

Comments
 (0)