A Test Kitchen driver for Apache CloudStack and Citrix CloudPlatform. It deploys and destroys CloudStack virtual machines so you can test your cookbooks and infrastructure code against them.
This documentation uses Cinc Workstation and the
cinccommands throughout. Everything here works identically with Chef Workstation — see Using with Chef.
- An Apache CloudStack or Citrix CloudPlatform deployment
- API credentials for it: an API key, a secret key, and the API URL
- Test Kitchen 3.0 or newer, including the version bundled with current Cinc Workstation and Chef Workstation
fog-cloudstack, installed automatically as a dependency
Install the driver alongside Test Kitchen:
gem install kitchen-cloudstackOr, for a project-local bundle:
# Gemfile
source "https://rubygems.org"
gem "test-kitchen"
gem "kitchen-cloudstack"bundle installIf you installed into a bundle, run the commands below through bundle exec.
The driver needs three values, which you can find in the CloudStack UI under your account's API keys:
driver:
name: cloudstack
cloudstack_api_key: <%= ENV['CLOUDSTACK_API_KEY'] %>
cloudstack_secret_key: <%= ENV['CLOUDSTACK_SECRET_KEY'] %>
cloudstack_api_url: https://cloudstack.example.com/client/apiKeep the keys out of kitchen.yml by reading them from the environment as
shown above.
---
driver:
name: cloudstack
cloudstack_api_key: <%= ENV['CLOUDSTACK_API_KEY'] %>
cloudstack_secret_key: <%= ENV['CLOUDSTACK_SECRET_KEY'] %>
cloudstack_api_url: https://cloudstack.example.com/client/api
provisioner:
name: cinc_infra
platforms:
- name: ubuntu-22.04
driver:
cloudstack_template_id: 8a4e1c1f-1234-4b8b-9c2f-77b6c9f0e111
cloudstack_serviceoffering_id: b1d2f3a4-5678-4c9d-8e1f-99a7b6c5d4e3
cloudstack_zone_id: c2e3f4b5-9012-4d0e-9f2a-11b3c5d7e9f1
suites:
- name: default
run_list:
- recipe[my_cookbook::default]Then run the full test cycle:
bundle exec cinc kitchen testOr step through it:
bundle exec cinc kitchen create # deploy the CloudStack VM
bundle exec cinc kitchen converge # apply your cookbook
bundle exec cinc kitchen verify # run your tests
bundle exec cinc kitchen destroy # destroy the VMTemplate, service offering, and zone are usually set per platform, since they
are what differs between operating systems. Everything else usually belongs in
the top-level driver: block.
Options can be set under the top-level driver: key, or per platform under
platforms[].driver:.
| Option | Default | Description |
|---|---|---|
cloudstack_api_key |
none | CloudStack API key. Required. |
cloudstack_secret_key |
none | CloudStack secret key. Required. |
cloudstack_api_url |
none | Full URL of the CloudStack API endpoint, e.g. https://cloudstack.example.com/client/api. Required. |
disable_ssl_validation |
false |
Skip TLS certificate validation. Only use this against a deployment with an invalid certificate, and only if you understand the risk. |
| Option | Default | Description |
|---|---|---|
cloudstack_template_id |
none | ID of the template (OS image) to deploy. Required, normally set per platform. |
cloudstack_serviceoffering_id |
none | ID of the service offering, which determines CPU and memory. Required, normally set per platform. |
cloudstack_zone_id |
none | ID of the zone to deploy into. Required, normally set per platform. |
cloudstack_project_id |
unset | ID of a project to deploy the VM into. |
cloudstack_affinity_group_id |
unset | ID of an affinity group, for pinning to a dedicated cluster. |
cloudstack_expunge |
false |
Expunge the VM on destroy rather than leaving it in the Destroyed state. |
These apply only when the service offering itself does not specify CPU or memory.
| Option | Default | Description |
|---|---|---|
cloudstack_serviceoffering_cpu |
from offering | Number of CPUs. |
cloudstack_serviceoffering_cpuspeed |
from offering | Speed of each CPU, in MHz. |
cloudstack_serviceoffering_memory |
from offering | Memory, in MB. |
| Option | Default | Description |
|---|---|---|
cloudstack_diskoffering_id |
unset | ID of a disk offering to attach a data disk from. |
cloudstack_diskoffering_size |
from offering | Size of the data disk in GB, for a custom disk offering. |
| Option | Default | Description |
|---|---|---|
cloudstack_network_id |
unset | Network ID, for isolated or VPC networks. |
cloudstack_security_group_id |
unset | Security group ID, for shared networks. |
associate_public_ip |
false |
Acquire a public IP and set up static NAT automatically. |
cloudstack_vm_public_ip |
unset | Public IP to connect to, when you configure advanced networking and static NAT yourself. |
cloudstack_create_firewall_rule |
false |
Create a firewall rule opening the transport's port to the public IP. |
cloudstack_firewall_cidr |
0.0.0.0/0 |
Source range the firewall rule allows. Narrow this to your own network rather than leaving it open to the internet. |
| Option | Default | Description |
|---|---|---|
username |
transport default | User to connect as. Leave unset to use the transport: setting. |
port |
transport default | Port to connect on. Leave unset to use the transport: setting. |
password |
generated by CloudStack | Password to connect with. By default the driver uses the password CloudStack generates. |
cloudstack_ssh_keypair_name |
unset | Name of a CloudStack SSH keypair to deploy with. See SSH keypairs. |
keypair_search_directory |
see below | Extra directory to search for the keypair's .pem file. |
cloudstack_sync_time |
0 |
Seconds to wait before connecting, to let cloud-set-guest-password or cloud-set-guest-sshkey finish. Raise this if logins fail intermittently just after boot. |
| Option | Default | Description |
|---|---|---|
server_name |
generated | Display name of the VM in CloudStack. |
host_name |
generated | Hostname set on the VM itself. Useful when long generated hostnames cause ENAMETOOLONG errors during a converge. |
| Option | Default | Description |
|---|---|---|
cloudstack_userdata |
unset | User data passed to the VM. Must be a double-quoted string, so escapes such as \n are interpreted. |
cloudstack_job_poll_interval |
10 |
Seconds between checks on a running CloudStack job. |
cloudstack_job_timeout |
600 |
Seconds to wait for a CloudStack job before giving up. Raise this if deploys legitimately take longer. |
disable_ssl_validation |
false |
Skip SSL certificate validation against the API. Only for a deployment without valid certificates. |
To use a CloudStack SSH keypair, set cloudstack_ssh_keypair_name and make the
matching private key available as a .pem file. The driver looks for a file
named after the keypair with a .pem suffix — a keypair called TestKey needs
TestKey.pem — in these locations:
- the directory given by
keypair_search_directory, specified without a trailing slash - the directory containing your
kitchen.yml - your home directory (
~) - your
~/.sshdirectory
Note that this file must be the private key, not the public key.
driver:
name: cloudstack
cloudstack_ssh_keypair_name: TestKey
keypair_search_directory: /home/me/cloudstack-keysThe driver does not connect to the instance itself. It works out an address and a set of credentials, hands them to the configured Test Kitchen transport, and waits for that transport to become ready. This is what lets the same driver serve both Linux and Windows instances.
Credentials are chosen in this order:
- a CloudStack SSH keypair, if
cloudstack_ssh_keypair_nameis set and the matching.pemis found - the password CloudStack generates, for a password-enabled template
- the
passwordyou configured on the driver
username and port are only sent to the transport when you set them on the
driver. Leave them unset and your transport: configuration applies, which is
usually what you want:
driver:
name: cloudstack
# no username here
transport:
username: ubuntu # honoured, because the driver does not override itSet the transport to WinRM and the driver follows it. Port forwarding and firewall rules use the transport's port (5985, or 5986 for SSL) instead of SSH's 22, and the password CloudStack generates for a password-enabled Windows template is handed to WinRM automatically:
driver:
name: cloudstack
cloudstack_api_key: <%= ENV['CLOUDSTACK_API_KEY'] %>
cloudstack_secret_key: <%= ENV['CLOUDSTACK_SECRET_KEY'] %>
cloudstack_api_url: https://cloudstack.example.com/client/api
associate_public_ip: true
cloudstack_create_firewall_rule: true
transport:
name: winrm
platforms:
- name: windows-2022
driver:
cloudstack_template_id: <windows template id>
cloudstack_serviceoffering_id: <offering id>
cloudstack_zone_id: <zone id>The template must have password management enabled so CloudStack can set and report the administrator password, and WinRM must be listening in the image.
kitchen list asks the driver whether each instance is still alive, and this
driver answers from CloudStack rather than guessing, so an instance destroyed
out from under Test Kitchen is reported accurately.
The value must be double-quoted so the escape sequences are interpreted:
driver:
name: cloudstack
cloudstack_userdata: "#cloud-config\npackages:\n - htop\n"driver:
name: cloudstack
cloudstack_network_id: d3f4a5b6-3456-4e1f-8a2b-33c5d7e9f1a2
associate_public_ip: true
cloudstack_create_firewall_rule: truedriver:
name: cloudstack
cloudstack_network_id: d3f4a5b6-3456-4e1f-8a2b-33c5d7e9f1a2
cloudstack_vm_public_ip: 203.0.113.25driver:
name: cloudstack
cloudstack_security_group_id: e4a5b6c7-7890-4f2a-9b3c-44d6e8f0a2b3driver:
name: cloudstack
cloudstack_serviceoffering_id: f5b6c7d8-1234-4a3b-8c4d-55e7f9a1b3c4
cloudstack_serviceoffering_cpu: 4
cloudstack_serviceoffering_cpuspeed: 2000
cloudstack_serviceoffering_memory: 8192
cloudstack_diskoffering_id: a6c7d8e9-5678-4b4c-9d5e-66f8a0b2c4d5
cloudstack_diskoffering_size: 100driver:
name: cloudstack
host_name: kitchen-testdriver:
name: cloudstack
cloudstack_expunge: trueNameError: uninitialized constant Kitchen::Driver::SSHBase. You are running
kitchen-cloudstack 0.24.0 or older, which was built on a class Test Kitchen
removed in 4.0. Upgrade to 1.0.0 or newer.
A CloudStack job times out. Deploys on a busy or large template can exceed
the ten minute default. Raise cloudstack_job_timeout.
WinRM never becomes ready. Check that the template has password management
enabled, that WinRM is listening in the image, and — if you are forwarding a
public IP — that cloudstack_create_firewall_rule is set so the WinRM port is
actually open.
Login fails immediately after the VM boots. CloudStack's
cloud-set-guest-password and cloud-set-guest-sshkey scripts may not have run
yet. Increase cloudstack_sync_time.
Converge fails with ENAMETOOLONG. The generated hostname is too long for
the run. Set host_name to something short.
This driver is not tied to Cinc. The examples above use Cinc Workstation and the cinc_infra provisioner, but the driver works exactly the same with Chef Workstation — run kitchen instead of cinc kitchen, and use chef_infra instead of cinc_infra:
provisioner:
name: chef_infraEverything else works identically.
Bug reports and pull requests are welcome on GitHub. Porting the driver off the removed SSHBase class would be especially valuable. See CONTRIBUTING.md for development setup and the state of the test tooling.
Created and maintained by Jeff Moody (fifthecho@gmail.com).
Licensed under the Apache License, Version 2.0. See LICENSE for details.