]>
git.proxmox.com Git - pve-storage.git/blob - test/rbd_namespace.pl
3 # This script is meant to be run manually on hyperconverged PVE server with a
4 # Ceph cluster. It tests how PVE handles RBD namespaces.
6 # The pool (default: rbd) must already exist. The namespace and VMs will be
9 # Parameters like names for the pool an namespace and the VMID can be
10 # configured. The VMIDs for the clones is $vmid -1 and $vmid -2.
12 # Cleanup is done after a successful run. Cleanup can also be called manually.
16 # * Snapshot rollback can sometimes be racy with stopping the VM and Ceph
17 # recognizing that the disk image is not in use anymore.
26 use PVE
::Tools
qw(run_command);
28 my $pool = "testpool";
29 my $use_existing= undef;
30 my $namespace = "testspace";
36 my $helpstring = "usage: $0 [OPTIONS]
40 --pool <name> pool name, default: ${pool}
41 --use-existing use existing pool, default: 0, needs --pool set
42 --namespace <name> rbd namespace, default: ${namespace}
43 --vmid <id> VMID of the test VM, default: ${vmid}
44 --cleanup Remove the storage definitions, namespaces and VM afterwards
45 -d, --debug Enable debug output
46 -h, --help Print this help message
51 "use-existing" => \
$use_existing,
52 "namespace=s" => \
$namespace,
54 "h|help" => \
$showhelp,
55 "cleanup" => \
$cleanup,
57 ) or die ($helpstring);
64 my $storage_name = "${pool}-${namespace}";
66 my $vmid_clone = int($vmid) - 1;
67 my $vmid_linked_clone = int($vmid) - 2;
70 print to_json
($_[0], { utf8
=> 8, pretty
=> 1, canonical
=> 1 }) . "\n";
77 my ($cmd, $json, $ignore_errors) = @_;
80 my $parser = sub {$raw .= shift;};
83 run_command
($cmd, outfunc
=> $parser);
86 die $err if !$ignore_errors;
93 } elsif ($raw =~ m/^(\[.*\])$/s) { # untaint
94 $result = JSON
::decode_json
($1);
96 die "got unexpected data from command: '$cmd' -> '$raw'\n";
113 run_command
($cmd, outfunc
=> $out);
125 print "Preparing test environment\n";
127 my $pools = run_cmd
("ceph osd pool ls --format json", 1);
129 my %poolnames = map {$_ => 1} @$pools;
130 die "Pool '$pool' does not exist!\n"
131 if !exists($poolnames{$pool}) && $use_existing;
133 run_cmd
(['pveceph', 'pool', 'create', ${pool
}, '--add_storages', 1])
136 my $namespaces = run_cmd
(['rbd', '-p', ${pool
}, 'namespace', 'ls', '--format', 'json'], 1);
139 for my $i (@$namespaces) {
140 $ns_found = 1 if $i->{name
} eq $namespace;
144 print "Create namespace '${namespace}' in pool '${pool}'\n";
145 run_cmd
(['rbd', 'namespace', 'create', "${pool}/${namespace}"]);
148 my $storages = run_cmd
(['pvesh', 'get', 'storage', '--output-format', 'json'], 1);
153 print "Create storage definition\n";
154 for my $stor (@$storages) {
155 $pool_found = 1 if $stor->{storage
} eq $pool;
156 $rbd_found = 1 if $stor->{storage
} eq $storage_name;
159 run_cmd
(['pvesm', 'set', ${storage_name
}, '--krbd', '0']);
160 die "Enable the storage '$stor->{storage}'!" if $stor->{disable
};
164 die "No storage for pool '${pool}' found! Must have same name as pool!\n"
167 run_cmd
(['pvesm', 'add', 'rbd', $pool, '--pool', $pool, '--content', 'images,rootdir']);
169 # create PVE storages (librbd / krbd)
170 run_cmd
(['pvesm', 'add', 'rbd', ${storage_name
}, '--krbd', '0', '--pool', ${pool
}, '--namespace', ${namespace
}, '--content', 'images,rootdir'])
175 print "Create test VM ${vmid}\n";
176 my $vms = run_cmd
(['pvesh', 'get', 'cluster/resources', '--type', 'vm', '--output-format', 'json'], 1);
178 # TODO: introduce a force flag to make this behaviour configurable
180 if ($vm->{vmid
} eq $vmid) {
181 print "Test VM '${vmid}' already exists. It will be removed and recreated!\n";
182 run_cmd
(['qm', 'stop', ${vmid
}], 0, 1);
183 run_cmd
(['qm', 'destroy', ${vmid
}]);
186 run_cmd
(['qm', 'create', ${vmid
}, '--bios', 'ovmf', '--efidisk0', "${storage_name}:1", '--scsi0', "${storage_name}:2"]);
191 print "Cleaning up test environment!\n";
192 print "Removing VMs\n";
193 run_cmd
(['qm', 'stop', ${vmid
}], 0, 1);
194 run_cmd
(['qm', 'stop', ${vmid_linked_clone
}], 0, 1);
195 run_cmd
(['qm', 'stop', ${vmid_clone
}], 0, 1);
196 run_cmd
(['qm', 'destroy', ${vmid_linked_clone
}], 0, 1);
197 run_cmd
(['qm', 'destroy', ${vmid_clone
}], 0, 1);
198 run_cmd
(['for', 'i', 'in', "/dev/rbd/${pool}/${namespace}/*;", 'do', '/usr/bin/rbd', 'unmap', '\$i;', 'done'], 0, 1);
199 run_cmd
(['qm', 'unlock', ${vmid
}], 0, 1);
200 run_cmd
(['qm', 'destroy', ${vmid
}], 0, 1);
202 print "Removing Storage definition for ${storage_name}\n";
203 run_cmd
(['pvesm', 'remove', ${storage_name
}], 0, 1);
205 print "Removing RBD namespace '${pool}/${namespace}'\n";
206 run_cmd
(['rbd', 'namespace', 'remove', "${pool}/${namespace}"], 0, 1);
208 if (!$use_existing) {
209 print "Removing Storage definition for ${pool}\n";
210 run_cmd
(['pvesm', 'remove', ${pool
}], 0, 1);
211 print "Removing test pool\n";
212 run_cmd
(['pveceph', 'pool', 'destroy', $pool]);
217 # Example structure for tests
219 # name => "name of test section",
221 # ['some', 'prep', 'command'],
224 # ['test', 'cmd', $vmid],
225 # ['second', 'step', $vmid],
228 # ['cleanup', 'command'],
232 name
=> 'first VM start',
234 ['qm', 'start', $vmid],
238 name
=> 'snapshot/rollback',
240 ['qm', 'snapshot', $vmid, 'test'],
241 ['qm', 'rollback', $vmid, 'test'],
244 ['qm', 'unlock', $vmid],
248 name
=> 'remove snapshot',
250 ['qm', 'delsnapshot', $vmid, 'test'],
254 name
=> 'moving disk between namespaces',
256 ['qm', 'move_disk', $vmid, 'scsi0', $pool, '--delete', 1],
257 ['qm', 'move_disk', $vmid, 'scsi0', $storage_name, '--delete', 1],
261 name
=> 'switch to krbd',
263 ['qm', 'stop', $vmid],
264 ['pvesm', 'set', $storage_name, '--krbd', 1]
268 name
=> 'start VM with krbd',
270 ['qm', 'start', $vmid],
274 name
=> 'snapshot/rollback with krbd',
276 ['qm', 'snapshot', $vmid, 'test'],
277 ['qm', 'rollback', $vmid, 'test'],
280 ['qm', 'unlock', $vmid],
284 name
=> 'remove snapshot with krbd',
286 ['qm', 'delsnapshot', $vmid, 'test'],
290 name
=> 'moving disk between namespaces with krbd',
292 ['qm', 'move_disk', $vmid, 'scsi0', $pool, '--delete', 1],
293 ['qm', 'move_disk', $vmid, 'scsi0', $storage_name, '--delete', 1],
297 name
=> 'clone VM with krbd',
299 ['qm', 'clone', $vmid, $vmid_clone],
303 name
=> 'switch to non krbd',
305 ['qm', 'stop', $vmid],
306 ['qm', 'stop', $vmid_clone],
307 ['pvesm', 'set', $storage_name, '--krbd', 0]
311 name
=> 'templates and linked clone',
313 ['qm', 'template', $vmid],
314 ['qm', 'clone', $vmid, $vmid_linked_clone],
315 ['qm', 'start', $vmid_linked_clone],
316 ['qm', 'stop', $vmid_linked_clone],
320 name
=> 'start linked clone with krbd',
322 ['pvesm', 'set', $storage_name, '--krbd', 1]
325 ['qm', 'start', $vmid_linked_clone],
326 ['qm', 'stop', $vmid_linked_clone],
331 sub run_prep_cleanup
{
335 print join(' ', @$_). "\n";
344 ok
(run_test_cmd
($_), join(' ', @$_));
349 print "Running tests:\n";
353 $num_tests += scalar(@{$_->{steps
}}) if defined $_->{steps
};
356 print("Tests: $num_tests\n");
357 plan tests
=> $num_tests;
359 for my $test (@$tests) {
360 print "Section: $test->{name}\n";
361 run_prep_cleanup
($test->{preparations
}) if defined $test->{preparations
};
362 run_steps
($test->{steps
}) if defined $test->{steps
};
363 run_prep_cleanup
($test->{cleanup
}) if defined $test->{cleanup
};
368 if (Test
::More-
>builder->is_passing()) {