ServerspecExtraTypes
serverspec-extra-types is a set of addition resource types and matchers for ServerSpec, providing types for technologies such as docker swarm, consul, and rabbitmq.
All checks run on the target, which can be useful when executing via a bastion host
Requirements
- rabbitmq and consul checks requires curl to be installed on the target
Installation
Add this line to your application's Gemfile:
gem 'serverspec-extra-types'
And then execute:
$ bundle
Or install it yourself as:
$ gem install serverspec-extra-types
Usage
Add the following to your spec_helper.rb
require 'serverspec-extra-types'
Resource types
curl | consul_node | consul_node_list | consul_service | consul_service_list | docker_config | docker_container | docker_network | docker_node | docker_secret | docker_service | jenkins_credential |jenkins_job | jenkins_plugin | nfs_export | rabbitmq_node_list | rabbitmq_user_permission | rabbitmq_vhost_list | rabbitmq_vhost_policy | sudo_user
curl
Please note: This type requires curl to be installed on the target host
The curl resource allow for check against remote url. Addition parameters are avaliable to allow for insecure certifactes and follow redirects
Example:
describe curl("https://example.org") do
it { should respond_with_OK }
end
#Without certificate verification
describe curl("https://example.org", insecure: true) do
it { should respond_with_OK }
end
#Following redirects
describe curl("https://example.org", follow_redirects: true) do
it { should respond_with_OK }
end
For a full list of HTTP matchers see HTTP Matchers
consul_node
Please note: This type requires curl to be installed on the target host
have_datacenter
describe consul_node('consul') do
it { should have_datacenter 'dc1'}
end
have_service
describe consul_node('consul') do
it { should have_datacenter 'dc1'}
end
Supports the same additional parameters as the curl matcher
consul_node_list
Please note: This type requires curl to be installed on the target host
have_node
describe consul_node_list() do
it { should have_node 'consul' }
end
Supports the same additional parameters as the curl matcher
consul_service
Please note: This type requires curl to be installed on the target host
have_id
describe consul_service('consul') do
it { should have_id('7ba9a647-0adb-8c92-b0c9-5b011b3530a8') }
end
have_node
describe consul_service('consul') do
it { should have_node('consul') }
end
have_address
describe consul_service('consul') do
it { should have_address('127.0.0.1') }
end
have_datacenter
describe consul_service('consul') do
it { should have_datacenter('dc1') }
end
have_tagged_addresses
describe consul_service('consul') do
it { should have_tagged_addresses({"lan"=>"127.0.0.1", "wan"=>"127.0.0.1"}) }
end
have_node_meta
describe consul_service('consul') do
it { should ({"consul-network-segment"=>""}) }
end
have_service_kind
describe consul_service('consul') do
it { should have_service_kind('') }
end
have_service_id
describe consul_service('consul') do
it { should have_service_id('consul') }
end
have_service_name
describe consul_service('consul') do
it { should have_service_name('consul') }
end
have_service_tags
describe consul_service('consul') do
it { should ([]) }
end
have_service_address
describe consul_service('consul') do
it { should have_service_address('') }
end
have_service_weights
describe consul_service('consul') do
it { should have_service_weights({"Passing"=>1, "Warning"=>1}) }
end
have_service_meta
describe consul_service('consul') do
it { should ({}) }
end
have_service_port
describe consul_service('consul') do
it { should have_service_port(8300) }
end
have_service_enable_tag_override
describe consul_service('consul') do
it { should have_service_enable_tag_override(false) }
end
have_service_proxy_destination
describe consul_service('consul') do
it { should have_service_proxy_destination('') }
end
have_service_proxy
describe consul_service('consul') do
it { should have_service_proxy({}) }
end
have_service_connect
describe consul_service('consul') do
it { should have_service_connect({}) }
end
have_create_index
describe consul_service('consul') do
it { should have_create_index(9) }
end
have_modify_index
describe consul_service('consul') do
it { should have_modify_index(9) }
end
Supports the same additional parameters as the curl matcher
consul_service_list
Please note: This type requires curl to be installed on the target host
have_service
describe consul_service_list() do
it { should have_service 'consul' }
end
Supports the same additional parameters as the curl matcher
docker_config
exists
Check if config exists
describe docker_config('test.conf') do
it { should exist }
end
have_name
Check if config has a specific name
describe docker_config('test.conf') do
it { should have_name 'test.conf' }
end
have_data
Check if config data matches a string
describe docker_config('test.conf') do
it { should have_data 'Some config data' }
end
have_data64
Check if config base64 encoded data matches a string
describe docker_config('test.conf') do
it { should have_data64 'U29tZSBjb25maWcgZGF0YQ=='}
end
be_labeled /be_labelled
Check if config has a specific label
describe docker_config('test.conf') do
it { should have_label('some.label.key') }
# Check for value
it { should have_label('some.label.key').with_value('value') }
end
docker_container
Extension of the serverspec docker container type, and provides the following matchers:
this type now supports selecting the container via a filter or by name
exist
Check if a container exists by name
describe docker_container('focused_currie') do
it { should exist }
end
# Using a filter (useful for containers launch via docker swarm)
describe docker_container('name=focused_currie') do
it { should exist }
end
Check if a container exists by filter
# Look for a container publishing port 80
describe docker_container('publish=80') do
it { should exist }
end
be_running
Check if a container is running (from serverspec)
describe docker_container('focused_curie') do
it { should be_running }
end
have_image
Check if container is running a specfic image
describe docker_container('focused_currie') do
it { should have_image('jenkins/jenkins:lts') }
end
have_hostname / has_host_name
Check container hostname
describe docker_container('focused_currie') do
it { should have_hostname('container1') }
end
have_domainname / have_domain_name
Check container domain name
describe docker_container('focused_currie') do
it { should have_domainname('leek.com') }
end
have_user / run_as_user
Check if container is running as the specified user
describe docker_container('focused_currie') do
it { should run_as_user('jenkins') }
end
map_port
Check if host port is mapped to container port
describe docker_container('focused_currie') do
it { should map_port('80','8080') }
end
Check if host port is mapped to container port using a specific protocol
describe docker_container('focused_currie') do
it { should map_port('80','8080').using_protocol('tcp') }
end
have_volume
Check the for a volume (from serverspec)
describe docker_container('focused_currie') do
it { it { should have_volume('/tmp','/data') }}
end
have_mount
Check the for mounted volume
describe docker_container('focused_currie') do
it { should have_mount('/var/run/docker.sock', '/var/run/docker.sock') }
end
have_restart_policy
Check the containers restart policy
describe docker_container('focused_currie') do
it { should have_restart_policy('always') }
end
have_restart_limit
Check the containers restart limit
describe docker_container('focused_currie') do
it { should have_restart_limit(1) }
end
have_host
Check for additional /etc/hosts entries
describe docker_container('focused_currie') do
it { should have_host('8.8.8.8 dns') }
end
have_environment_variable
Check if the container has an specific environment variable
describe docker_container('focused_currie') do
it { should have_environment_variable('CONSUL_VERSION') }
end
# check its value
describe docker_container('focused_currie') do
it { should have_environment_variable('CONSUL_VERSION').with_value('1.2.0') }
end
be_privileged
Check if the container runs in privileged mode
describe docker_container('focused_currie') do
it { should be_privileged }
end
publishes_all_ports
Check if the container publishes all exposed ports
describe docker_container('focused_currie') do
it { should publishes_all_ports }
end
docker_node
exist
Check if docker node exists
describe docker_node('somehost') do
it { should exist }
end
be_manager / be_a_manager
Check if docker node is a manager node
describe docker_node(`hostname -f`.chomp) do
it { should be_a_manager }
end
be_worker / be_a_worker
Check if docker node exists
describe docker_node('somehost') do
it { should be_a_worker }
end
have_engine_version
Check engine version
describe docker_node('somehost') do
it { should have_engine_version '18.09.1' }
end
be_active
Check if node is active
describe docker_node('somehost') do
it { should be_active }
end
be_draining
Check if node is draining
describe docker_node('somehost') do
it { should be_draining }
end
be_paused
Check if node is paused
describe docker_node('somehost') do
it { should be_paused }
end
docker_network
exist
Check if network exists
describe docker_network('test_network') do
it { should exist }
end
be_attachable
Check if network is attachable
describe docker_network('test_network') do
it { should be_attachable }
end
be_swarm_scoped
Check if network is swarm scoped
describe docker_network('test_network') do
it { should be_swarm_scoped }
end
have_driver
Check if network uses a specific driver
describe docker_network('test_network') do
it { should have_driver('overlay') }
end
be_overlay
Check if network is an overlay network
describe docker_network('test_network') do
it { should }
end
be_internal
Check if network is internal
describe docker_network('test_network') do
it { should_not be_internal }
end
be_ingress
Check if network is an ingress network
describe docker_network('test_network') do
it { should_not be_ingress }
end
be_IPv6_enabled
Check if network is IPv6 enabled
describe docker_network('test_network') do
it { should_not be_IPv6_enabled }
end
docker_secret
exists
Check if secret exists
describe docker_secret('secret.key') do
it { should exist }
end
have_name
Check if secret has a specific name
describe docker_secret('secret.key') do
it { should have_name 'secret.key' }
end
be_labeled /be_labelled
Check if secret has a specific label
describe docker_secret('secret.key') do
it { should have_label('some.label.key') }
# Check for value
it { should have_label('some.label.key').with_value('value') }
end
docker_service
exist
Check if a service exists by name
describe docker_service('my_service') do
it { should exist }
end
have_image
Check if service is running a specfic image
describe docker_service('my-awesome-service') do
it { should have_image('jenkins/jenkins:lts') }
end
have_user / run_as_user
Check if service is running as the specified user
describe docker_service('my-awesome-service') do
it { should run_as_user('jenkins') }
end
map_port
Check if host port is mapped to service port
describe docker_service('my-awesome-service') do
it { should map_port('80','8080') }
end
Check if host port is mapped to service port using a specific protocol
describe docker_service('my-awesome-service') do
it { should map_port('80','8080').using_protocol('tcp') }
end
have_volume
Check the for a volume (from serverspec)
describe docker_service('my-awesome-service') do
it { it { should have_volume('/tmp','/data') }}
end
have_mount
Check the for mounted volume
describe docker_service('my-awesome-service') do
it { should have_mount('/var/run/docker.sock', '/var/run/docker.sock') }
end
have_restart_policy
Check the services restart policy
describe docker_service('my-awesome-service') do
it { should have_restart_policy('any') }
end
have_restart_limit
Check the services restart limit
describe docker_service('my-awesome-service') do
it { should have_restart_limit(1) }
end
have_host
Check for additional /etc/hosts entries
describe docker_service('my-awesome-service') do
it { should have_host('8.8.8.8 dns') }
end
have_environment_variable
Check if the service has an specific environment variable
describe docker_service('my-awesome-service') do
it { should have_environment_variable('CONSUL_VERSION') }
end
# check its value
describe docker_service('my-awesome-service') do
it { should have_environment_variable('CONSUL_VERSION').with_value('1.2.0') }
end
be_labeled/be_labelled
Check if the service has an specific label
describe docker_service('my-awesome-service') do
it { should be_labeled('CONSUL_VERSION') }
end
# check its value
describe docker_service('my-awesome-service') do
it { should be_labeled('CONSUL_VERSION').with_value('1.2.0') }
end
This matcher supports both the UK and US spelling of labelled and also has have_label as an alias but this may conflict with dockerspec's have_lable matcher if using along side
have_config
Check the service has a particular config
describe docker_service('my-awesome-service') do
# Check that it uses a config
it { should have_config('nginx.conf') }
# Check that it places the config in a particular location
it { should have_config('nginx.conf', '/some/target/path') }
end
have_secret
Check the service has a particular secret
describe docker_service('my-awesome-service') do
# Check that it uses a secret
it { should have_secret('secret.crt') }
# Check that it places the secret in a particular location
it { should have_secret('secret.crt', '/some/target/path') }
end
be_global
Check the service is running in global mode
describe docker_service('my-awesome-service') do
it { should be_global }
end
be_replicated
Check the service is running in replicated mode
describe docker_service('my-awesome-service') do
it { should be_replicated }
end
have_replica_count
Check the number of replicas the service has
describe docker_service('my-awesome-service') do
it { should have_replica_count 2 }
end
have_placement_constraint
Check the number of replicas the service has
describe docker_service('my-awesome-service') do
it { should have_placement_constraint('node.role == manager') }
end
jenkins_credential
Please note: This type requires curl to be installed on the target host
TODO Supports the same additional parameters as the curl matcher
jenkins_job
Please note: This type requires curl to be installed on the target host
TODO
jenkins_plugin
Please note: This type requires curl to be installed on the target host
TODO Supports the same additional parameters as the curl matcher
nfs_export
TODO
rabbitmq_node_list
Please note: This type requires curl to be installed on the target host
TODO Supports the same additional parameters as the curl matcher
rabbitmq_user_permission
Please note: This type requires curl to be installed on the target host
TODO Supports the same additional parameters as the curl matcher
rabbitmq_vhost_list
Please note: This type requires curl to be installed on the target host
TODO Supports the same additional parameters as the curl matcher
rabbitmq_vhost_policy
Please note: This type requires curl to be installed on the target host
TODO Supports the same additional parameters as the curl matcher
sudo_user
Check the sudo permissions of a given user
exist
Checks if the user exists and is in the sudoers file
describe sudo_user('someuser') do
it { should exist }
end
have_sudo_disabled
Ensures the user has no sudo permssions
describe sudo_user('someuser') do
it { should have_sudo_disabled }
end
be_allowed_to_run_command
Ensures the user can run a command
describe sudo_user('someuser') do
it { should be_allowed_run_anything }
# Without password
it { should be_allowed_run_anything.without_a_password }
#As a particular user
it { should be_allowed_run_anything.as('someotheruser') }
#As a particular user with out a password
it { should be_allowed_run_anything.as('someotheruser').without_a_password }
#As any user
it { should be_allowed_run_anything.as_anybody }
#As Any user without a password
it { should be_allowed_run_anything.as_anybody.without_password }
end
be_allowed_to_run_anything
Ensures the user can run a anything
describe sudo_user('someuser') do
it { should be_allowed_run_anything }
# Without password
it { should be_allowed_run_anything.without_a_password }
#As a particular user
it { should be_allowed_run_anything.as('someotheruser') }
#As a particular user with out a password
it { should be_allowed_run_anything.as('someotheruser').without_a_password }
#As any user
it { should be_allowed_run_anything.as_anybody }
#As Any user without a password
it { should be_allowed_run_anything.as_anybody.without_password }
end
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/andrewwardrobe/serverspec-extra-types. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the Serverspec::Extra::Types project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.