Skip to content

Commit

Permalink
Merge pull request #7 from jay7x/wip
Browse files Browse the repository at this point in the history
Fix per-node configuration in lima::cluster::start plan
  • Loading branch information
jay7x authored Feb 21, 2023
2 parents 2350b44 + 21ea66a commit 3e18cdc
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 20 deletions.
1 change: 1 addition & 0 deletions .fixtures.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
fixtures:
forge_modules:
ruby_task_helper: "puppetlabs/ruby_task_helper"
facts: "puppetlabs/facts"
6 changes: 6 additions & 0 deletions .sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ appveyor.yml:
delete: true
'spec/spec_helper.rb':
strict_level: ':error'
spec_overrides:
- "# BoltSpec setup"
- "# https://www.puppet.com/docs/bolt/latest/testing_plans.html"
- "require 'bolt_spec/plans'"
- "include BoltSpec::Plans"
- "BoltSpec::Plans.init"
Rakefile:
changelog_user: jay7x
Gemfile:
Expand Down
2 changes: 1 addition & 1 deletion plans/cluster/delete.pp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Optional[Hash] $clusters = undef,
TargetSpec $target = 'localhost',
) {
$cluster = run_plan('lima::clusters', 'clusters' => $clusters, 'name' => $name)
$cluster = run_plan('lima::clusters', 'name' => $name, 'clusters' => $clusters)

$defined_nodes = $cluster['nodes'].map |$node| {
$node ? {
Expand Down
35 changes: 17 additions & 18 deletions plans/cluster/start.pp
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,37 @@
Optional[Hash] $clusters = undef,
TargetSpec $target = 'localhost',
) {
$cluster = run_plan('lima::clusters', 'clusters' => $clusters, 'name' => $name)
$cluster = run_plan('lima::clusters', 'name' => $name, 'clusters' => $clusters)
$tgt = get_target($target)

$cluster_config = $cluster['nodes'].map |$node| {
$cluster_config = $cluster['nodes'].reduce({}) |$memo, $node| {
$n = $node ? {
Hash => $node,
String => { 'name' => $node },
default => {},
}

# Use per-node configs first. Use cluster-wide configs otherwise.
# Look for explicit config hash first then template then url.
# Look for explicit config hash then template then url.
# Keeping it non-DRY for readability
$cfg = [
[$n['config'], 'config'],
[$n['template'], 'template'],
[$n['url'], 'url'],
[$cluster['config'], 'config'],
[$cluster['template'], 'template'],
[$cluster['url'], 'url'],
].filter |$x| { $x[0] } # Delete undefined options
['config', $n['config']],
['template', $n['template']],
['url', $n['url']],
['config', $cluster['config']],
['template', $cluster['template']],
['url', $cluster['url']],
].filter |$x| { $x[1] } # Delete undefined options

unless $cfg.count >= 1 {
unless $cfg.length >= 1 {
fail("Node ${n['name']} has no config/template/url defined in the cluster configuration")
}

# Use first defined option ($cfg[0])
({ 'name' => $n['name'], $cfg[0][1] => $cfg[0][0] })
$memo + { $n['name'] => { $cfg[0][0] => $cfg[0][1] } }
}

$defined_nodes = $cluster_config.map |$node| { $node['name'] }
$defined_nodes = $cluster_config.keys
out::verbose("Defined nodes: ${defined_nodes}")

# Collect and set the target's facts
Expand Down Expand Up @@ -72,11 +73,10 @@
run_task(
'lima::start',
$tgt,
"Create VM ${node}",
'name' => $node,
'template' => $cluster['template'],
'config' => $cluster['config'],
'url' => $cluster['url'],
'template' => $cluster_config[$node]['template'],
'config' => $cluster_config[$node]['config'],
'url' => $cluster_config[$node]['url'],
)
}

Expand All @@ -92,7 +92,6 @@
run_task(
'lima::start',
$tgt,
"Start VM ${node}",
'name' => $node,
)
}
Expand Down
2 changes: 1 addition & 1 deletion plans/cluster/stop.pp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Optional[Hash] $clusters = undef,
TargetSpec $target = 'localhost',
) {
$cluster = run_plan('lima::clusters', 'clusters' => $clusters, 'name' => $name)
$cluster = run_plan('lima::clusters', 'name' => $name, 'clusters' => $clusters)

$defined_nodes = $cluster['nodes'].map |$node| {
$node ? {
Expand Down
55 changes: 55 additions & 0 deletions spec/plans/cluster/delete_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'lima::cluster::delete' do
let(:plan) { subject }
let(:cluster_name) { 'example' }
let(:nodes) do
[
'example-main',
'example-node1',
'example-node2',
'example-node3',
]
end
let(:clusters) do
{
cluster_name => {
'nodes' => [
nodes[0],
nodes[1],
{
'name' => nodes[2],
},
{
'name' => nodes[3],
},
],
},
}
end
let(:cluster) { clusters[cluster_name] }

it 'fails when wrong name specified' do
result = run_plan(plan, { 'name' => 'nonexistent', 'clusters' => clusters })

expect(result.ok?).to be(false)
expect(result.value.msg).to match(%r{Cluster 'nonexistent' is not defined})
end

it 'deletes all nodes in the cluster' do
expect_plan('lima::clusters').always_return(cluster)

nodes.each do |node|
expect_task('lima::delete').be_called_times(1).with_params({ 'name' => node }).always_return({})
end

expect_out_verbose.with_params("Nodes to delete: [#{nodes.join(', ')}]")

result = run_plan(plan, { 'name' => cluster_name, 'clusters' => clusters })

expect(result.ok?).to be(true)
expect(result.value.count).to eq(nodes.length)
end
end
109 changes: 109 additions & 0 deletions spec/plans/cluster/start_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'lima::cluster::start' do
let(:plan) { subject }
let(:cluster_name) { 'example' }
let(:nodes) do
[
'example-main',
'example-node1',
'example-node2',
'example-node3',
'example-node4',
'example-node5',
]
end
let(:clusters) do
{
cluster_name => {
'nodes' => [
nodes[0],
nodes[1],
{
'name' => nodes[2],
'config' => {
'node_config_specified' => true,
},
},
{
'name' => nodes[3],
'template' => 'superlinuxdistro',
},
{
'name' => nodes[4],
'url' => 'https://example.com/templates/superlinuxdistro.yaml',
},
nodes[5],
],
'template' => 'ubuntu-lts',
'url' => 'https://example.com/templates/ubuntu-lts.yaml',
'config' => {
'cluster_config_specified' => true,
},
},
}
end
let(:cluster) { clusters[cluster_name] }
let(:facts) { { 'processors': { 'count': 1 } } }
let(:lima_list_res) do
{
'list': [
{ 'name': nodes[0], 'status': 'Running' },
{ 'name': nodes[1], 'status': 'Stopped' },
]
}
end

it 'fails when wrong name specified' do
result = run_plan(plan, { 'name' => 'nonexistent', 'clusters' => clusters })

expect(result.ok?).to be(false)
expect(result.value.msg).to match(%r{Cluster 'nonexistent' is not defined})
end

it 'creates and runs the cluster' do
allow_task('facts').always_return(facts)

expect_plan('lima::clusters').always_return(cluster)
expect_task('lima::list').be_called_times(1).always_return(lima_list_res)

# Mock a call to create missing nodes
[
cluster['nodes'][2],
cluster['nodes'][3],
cluster['nodes'][4],
{
'name' => nodes[5],
'config' => {
'cluster_config_specified' => true,
}
},
].each do |node|
params = {
'name' => node['name'],
'template' => node['template'],
'config' => node['config'],
'url' => node['url'],
}

expect_task('lima::start').be_called_times(1).with_params(params).always_return({})
end

# Mock a call to start existing but stopped node (see lima_list_res)
nodes_to_stop = [ nodes[1] ]
nodes_to_stop.each do |node|
expect_task('lima::start').be_called_times(1).with_params({ 'name' => node }).always_return({})
end

expect_out_verbose.with_params("Defined nodes: [#{nodes.join(', ')}]")
expect_out_verbose.with_params("Nodes to create: [#{[ nodes[2], nodes[3], nodes[4], nodes[5] ].join(', ')}]")
expect_out_verbose.with_params("Nodes to start (1 nodes per batch): [#{nodes_to_stop.join(', ')}]")

result = run_plan(plan, { 'name' => cluster_name, 'clusters' => clusters })

expect(result.ok?).to be(true)
expect(result.value.count).to eq(5)
end
end
70 changes: 70 additions & 0 deletions spec/plans/cluster/stop_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'lima::cluster::stop' do
let(:plan) { subject }
let(:cluster_name) { 'example' }
let(:nodes) do
[
'example-main',
'example-node1',
'example-node2',
'example-node3',
]
end
let(:clusters) do
{
cluster_name => {
'nodes' => [
nodes[0],
nodes[1],
{
'name' => nodes[2],
},
{
'name' => nodes[3],
},
],
},
}
end
let(:cluster) { clusters[cluster_name] }
let(:lima_list_res) do
{
'list': [
{ 'name': nodes[0], 'status': 'Running' },
{ 'name': nodes[1], 'status': 'Stopped' },
{ 'name': nodes[2], 'status': 'Running' },
]
}
end

it 'fails when wrong name specified' do
result = run_plan(plan, { 'name' => 'nonexistent', 'clusters' => clusters })

expect(result.ok?).to be(false)
expect(result.value.msg).to match(%r{Cluster 'nonexistent' is not defined})
end

it 'stops all non-running nodes in the cluster' do
expect_plan('lima::clusters').always_return(cluster)
expect_task('lima::list').be_called_times(1).always_return(lima_list_res)

nodes_to_stop = [
nodes[0],
nodes[2],
]
nodes_to_stop.each do |node|
expect_task('lima::stop').be_called_times(1).with_params({ 'name' => node }).always_return({})
end

expect_out_verbose.with_params("Defined nodes: [#{nodes.join(', ')}]")
expect_out_verbose.with_params("Nodes to stop: [#{nodes_to_stop.join(', ')}]")

result = run_plan(plan, { 'name' => cluster_name, 'clusters' => clusters })

expect(result.ok?).to be(true)
expect(result.value.count).to eq(nodes_to_stop.length)
end
end
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,7 @@ def ensure_module_defined(module_name)
end

# 'spec_overrides' from sync.yml will appear below this line
# https://www.puppet.com/docs/bolt/latest/testing_plans.html
require 'bolt_spec/plans'
include BoltSpec::Plans
BoltSpec::Plans.init

0 comments on commit 3e18cdc

Please sign in to comment.