Skip to content

Commit 1bee33c

Browse files
authored
Merge pull request #5 from jay7x/wip
Add cluster management support
2 parents c46cc4f + 72e5352 commit 1bee33c

File tree

7 files changed

+385
-1
lines changed

7 files changed

+385
-1
lines changed

README.md

+49-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Table of Contents
44

55
1. [Description](#description)
66
2. [Requirements](#requirements)
7-
3. [Usage](#usage)
7+
3. [Inventory plugin usage](#inventory-plugin-usage)
8+
4. [Cluster management plans usage](#cluster-management-plans-usage)
89

910
## Description
1011

@@ -36,6 +37,53 @@ groups:
3637
except_matching_names: '^default'
3738
```
3839
40+
## Cluster management plans usage
41+
42+
This module provides a way to define and manage clusters of Lima VMs. It's expected to define clusters in the [plan_hierarchy of your Bolt project's Hiera](https://www.puppet.com/docs/bolt/latest/hiera.html#outside-apply-blocks).
43+
44+
Below is the example of a Hiera file under `plan_hierarchy`:
45+
46+
```yaml
47+
---
48+
# Leverage YAML features to define templates required
49+
x-ubuntu2004: &ubuntu2004
50+
images:
51+
- location: "https://cloud-images.ubuntu.com/releases/20.04/release-20230117/ubuntu-20.04-server-cloudimg-amd64.img"
52+
arch: "x86_64"
53+
digest: "sha256:3e44e9f886eba6b91662086d24028894bbe320c1de89be5c091019fedf9c5ce6"
54+
- location: "https://cloud-images.ubuntu.com/releases/20.04/release-20230117/ubuntu-20.04-server-cloudimg-arm64.img"
55+
arch: "aarch64"
56+
digest: "sha256:4ea4700f7b1de194a2f6bf760b911ea3071e0309fcea14d3a465a3323d57c60e"
57+
- location: "https://cloud-images.ubuntu.com/releases/20.04/release/ubuntu-20.04-server-cloudimg-amd64.img"
58+
arch: "x86_64"
59+
- location: "https://cloud-images.ubuntu.com/releases/20.04/release/ubuntu-20.04-server-cloudimg-arm64.img"
60+
arch: "aarch64"
61+
mounts:
62+
- location: "~"
63+
64+
# Cluster definitions
65+
lima::clusters:
66+
example: # `example` cluster
67+
nodes:
68+
- example1
69+
template: ubuntu # Use latest ubuntu version on this VM
70+
- example2
71+
- example3
72+
config:
73+
<<: *ubuntu2004
74+
```
75+
76+
Now when you have some clusters defined you can use cluster management plans to start/stop/delete a cluster. E.g.:
77+
78+
```bash
79+
# Start the cluster (create example[123] VMs)
80+
bolt plan run lima::cluster::start name=example
81+
# Stop the cluster (stop example[123] VMs)
82+
bolt plan run lima::cluster::stop name=example
83+
# Delete the cluster (delete example[123] VMs)
84+
bolt plan run lima::cluster::delete name=example
85+
```
86+
3987
## Reference
4088

4189
Reference documentation for the module is generated using

REFERENCE.md

+136
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
* [`start`](#start): Create or start Lima VM
1313
* [`stop`](#stop): Stop Lima VM
1414

15+
### Plans
16+
17+
* [`lima::cluster::delete`](#lima--cluster--delete): Delete the cluster of Lima VMs
18+
* [`lima::cluster::start`](#lima--cluster--start): Create/start the cluster of Lima VMs
19+
* [`lima::cluster::stop`](#lima--cluster--stop): Stop the cluster of Lima VMs
20+
* [`lima::clusters`](#lima--clusters): Return the cluster definition
21+
1522
## Tasks
1623

1724
### <a name="delete"></a>`delete`
@@ -144,3 +151,132 @@ Data type: `String[1]`
144151

145152
VM name
146153

154+
## Plans
155+
156+
### <a name="lima--cluster--delete"></a>`lima::cluster::delete`
157+
158+
Delete the cluster of Lima VMs
159+
160+
#### Parameters
161+
162+
The following parameters are available in the `lima::cluster::delete` plan:
163+
164+
* [`name`](#-lima--cluster--delete--name)
165+
* [`clusters`](#-lima--cluster--delete--clusters)
166+
* [`target`](#-lima--cluster--delete--target)
167+
168+
##### <a name="-lima--cluster--delete--name"></a>`name`
169+
170+
Data type: `String[1]`
171+
172+
Cluster name
173+
174+
##### <a name="-lima--cluster--delete--clusters"></a>`clusters`
175+
176+
Data type: `Optional[Hash]`
177+
178+
Hash of all defined clusters. Populated from Hiera usually.
179+
180+
Default value: `undef`
181+
182+
##### <a name="-lima--cluster--delete--target"></a>`target`
183+
184+
Data type: `TargetSpec`
185+
186+
The host to run the limactl on
187+
188+
Default value: `'localhost'`
189+
190+
### <a name="lima--cluster--start"></a>`lima::cluster::start`
191+
192+
Create/start the cluster of Lima VMs
193+
194+
#### Parameters
195+
196+
The following parameters are available in the `lima::cluster::start` plan:
197+
198+
* [`name`](#-lima--cluster--start--name)
199+
* [`clusters`](#-lima--cluster--start--clusters)
200+
* [`target`](#-lima--cluster--start--target)
201+
202+
##### <a name="-lima--cluster--start--name"></a>`name`
203+
204+
Data type: `String[1]`
205+
206+
Cluster name
207+
208+
##### <a name="-lima--cluster--start--clusters"></a>`clusters`
209+
210+
Data type: `Optional[Hash]`
211+
212+
Hash of all defined clusters. Populated from Hiera usually.
213+
214+
Default value: `undef`
215+
216+
##### <a name="-lima--cluster--start--target"></a>`target`
217+
218+
Data type: `TargetSpec`
219+
220+
The host to run the limactl on
221+
222+
Default value: `'localhost'`
223+
224+
### <a name="lima--cluster--stop"></a>`lima::cluster::stop`
225+
226+
Stop the cluster of Lima VMs
227+
228+
#### Parameters
229+
230+
The following parameters are available in the `lima::cluster::stop` plan:
231+
232+
* [`name`](#-lima--cluster--stop--name)
233+
* [`clusters`](#-lima--cluster--stop--clusters)
234+
* [`target`](#-lima--cluster--stop--target)
235+
236+
##### <a name="-lima--cluster--stop--name"></a>`name`
237+
238+
Data type: `String[1]`
239+
240+
Cluster name
241+
242+
##### <a name="-lima--cluster--stop--clusters"></a>`clusters`
243+
244+
Data type: `Optional[Hash]`
245+
246+
Hash of all defined clusters. Populated from Hiera usually.
247+
248+
Default value: `undef`
249+
250+
##### <a name="-lima--cluster--stop--target"></a>`target`
251+
252+
Data type: `TargetSpec`
253+
254+
The host to run the limactl on
255+
256+
Default value: `'localhost'`
257+
258+
### <a name="lima--clusters"></a>`lima::clusters`
259+
260+
Return the cluster definition
261+
262+
#### Parameters
263+
264+
The following parameters are available in the `lima::clusters` plan:
265+
266+
* [`name`](#-lima--clusters--name)
267+
* [`clusters`](#-lima--clusters--clusters)
268+
269+
##### <a name="-lima--clusters--name"></a>`name`
270+
271+
Data type: `String[1]`
272+
273+
Cluster name
274+
275+
##### <a name="-lima--clusters--clusters"></a>`clusters`
276+
277+
Data type: `Hash`
278+
279+
Hash of all defined clusters. Populated from Hiera usually.
280+
281+
Default value: `lookup('lima::clusters', 'default_value' => {})`
282+

hiera.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ hierarchy:
1919
- "os/%{facts.os.family}.yaml"
2020
- name: 'common'
2121
path: 'common.yaml'
22+
23+
# Define plan lookup hierarchy
24+
# This prevents "Interpolations are not supported in lookups outside of an apply
25+
# block" error when plan with lookup is executed
26+
plan_hierarchy: []

plans/cluster/delete.pp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# @summary Delete the cluster of Lima VMs
2+
# @param name
3+
# Cluster name
4+
# @param clusters
5+
# Hash of all defined clusters. Populated from Hiera usually.
6+
# @param target
7+
# The host to run the limactl on
8+
plan lima::cluster::delete (
9+
String[1] $name,
10+
Optional[Hash] $clusters = undef,
11+
TargetSpec $target = 'localhost',
12+
) {
13+
$cluster = run_plan('lima::clusters', 'clusters' => $clusters, 'name' => $name)
14+
15+
$defined_nodes = $cluster['nodes'].map |$node| {
16+
$node ? {
17+
Hash => $node['name'],
18+
String => $node,
19+
default => undef,
20+
}
21+
}
22+
out::verbose("Nodes to delete: ${defined_nodes}")
23+
24+
$stop_res = parallelize ($defined_nodes) |$node| {
25+
run_task(
26+
'lima::delete',
27+
$target,
28+
'name' => $node,
29+
)
30+
}
31+
32+
return $stop_res
33+
}

plans/cluster/start.pp

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# @summary Create/start the cluster of Lima VMs
2+
# @param name
3+
# Cluster name
4+
# @param clusters
5+
# Hash of all defined clusters. Populated from Hiera usually.
6+
# @param target
7+
# The host to run the limactl on
8+
plan lima::cluster::start (
9+
String[1] $name,
10+
Optional[Hash] $clusters = undef,
11+
TargetSpec $target = 'localhost',
12+
) {
13+
$cluster = run_plan('lima::clusters', 'clusters' => $clusters, 'name' => $name)
14+
$tgt = get_target($target)
15+
16+
$cluster_config = $cluster['nodes'].map |$node| {
17+
$n = $node ? {
18+
Hash => $node,
19+
String => { 'name' => $node },
20+
default => {},
21+
}
22+
23+
# Use per-node configs first. Use cluster-wide configs otherwise.
24+
# Look for explicit config hash first then template then url.
25+
$cfg = [
26+
[$n['config'], 'config'],
27+
[$n['template'], 'template'],
28+
[$n['url'], 'url'],
29+
[$cluster['config'], 'config'],
30+
[$cluster['template'], 'template'],
31+
[$cluster['url'], 'url'],
32+
].filter |$x| { $x[0] } # Delete undefined options
33+
34+
unless $cfg.count >= 1 {
35+
fail("Node ${n['name']} has no config/template/url defined in the cluster configuration")
36+
}
37+
38+
# Use first defined option ($cfg[0])
39+
({ 'name' => $n['name'], $cfg[0][1] => $cfg[0][0] })
40+
}
41+
42+
$defined_nodes = $cluster_config.map |$node| { $node['name'] }
43+
out::verbose("Defined nodes: ${defined_nodes}")
44+
45+
# Collect and set the target's facts
46+
if empty(facts($tgt)) {
47+
without_default_logging() || {
48+
run_plan('facts', $tgt, '_catch_errors' => true)
49+
}
50+
}
51+
$cpus = facts($tgt).get('processors.count')
52+
$start_threads = if $cpus < 4 { 1 } else { $cpus / 2 } # Assume every VM can consume up to 200% of a CPU core on start
53+
54+
# Get existing VMs
55+
$list_res = without_default_logging() || {
56+
run_task(
57+
'lima::list',
58+
$tgt,
59+
{ names => $defined_nodes },
60+
)
61+
}
62+
$lima_config = $list_res.find($target).value['list']
63+
64+
# Create missing nodes
65+
$missing_nodes = $defined_nodes - $lima_config.map |$x| { $x['name'] }
66+
out::verbose("Nodes to create: ${missing_nodes}")
67+
68+
# `limactl start` cannot create multiple images in parallel
69+
# See https://github.com/lima-vm/lima/issues/1354
70+
# So creating VMs sequentially..
71+
$create_res = $missing_nodes.map |$node| {
72+
run_task(
73+
'lima::start',
74+
$tgt,
75+
"Create VM ${node}",
76+
'name' => $node,
77+
'template' => $cluster['template'],
78+
'config' => $cluster['config'],
79+
'url' => $cluster['url'],
80+
)
81+
}
82+
83+
# Start existing but non-running nodes
84+
$stopped_nodes = $lima_config
85+
.filter |$x| { $x['status'] == 'Stopped' }
86+
.map |$x| { $x['name'] }
87+
out::verbose("Nodes to start (${start_threads} nodes per batch): ${stopped_nodes}")
88+
89+
# Run in batches of $start_threads VMs in parallel
90+
$start_res = $stopped_nodes.slice($start_threads).map |$batch| {
91+
$batch.parallelize |$node| {
92+
run_task(
93+
'lima::start',
94+
$tgt,
95+
"Start VM ${node}",
96+
'name' => $node,
97+
)
98+
}
99+
}
100+
101+
return flatten($create_res + $start_res)
102+
}

0 commit comments

Comments
 (0)