serverspec-extra-types 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +191 -0
- data/Rakefile +7 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/serverspec_extra_types.rb +3 -0
- data/lib/serverspec_extra_types/helpers/properties.rb +11 -0
- data/lib/serverspec_extra_types/matchers.rb +34 -0
- data/lib/serverspec_extra_types/matchers/be_a_manager_node.rb +15 -0
- data/lib/serverspec_extra_types/matchers/be_a_worker_node.rb +14 -0
- data/lib/serverspec_extra_types/matchers/be_active.rb +11 -0
- data/lib/serverspec_extra_types/matchers/configure_queue.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_count.rb +11 -0
- data/lib/serverspec_extra_types/matchers/have_domain_name.rb +10 -0
- data/lib/serverspec_extra_types/matchers/have_engine_version.rb +11 -0
- data/lib/serverspec_extra_types/matchers/have_environment_variable.rb +21 -0
- data/lib/serverspec_extra_types/matchers/have_ha_mode.rb +5 -0
- data/lib/serverspec_extra_types/matchers/have_ha_nodes.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_ha_sync_mode.rb +5 -0
- data/lib/serverspec_extra_types/matchers/have_host.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_hostname.rb +6 -0
- data/lib/serverspec_extra_types/matchers/have_image.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_image_sha.rb +5 -0
- data/lib/serverspec_extra_types/matchers/have_label.rb +20 -0
- data/lib/serverspec_extra_types/matchers/have_mount.rb +11 -0
- data/lib/serverspec_extra_types/matchers/have_network.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_placement_constraint.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_replica_count.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_restart_limit.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_restart_policy.rb +8 -0
- data/lib/serverspec_extra_types/matchers/have_user.rb +10 -0
- data/lib/serverspec_extra_types/matchers/have_vhost.rb +5 -0
- data/lib/serverspec_extra_types/matchers/include_regex.rb +5 -0
- data/lib/serverspec_extra_types/matchers/map_port.rb +25 -0
- data/lib/serverspec_extra_types/matchers/mirror_all.rb +5 -0
- data/lib/serverspec_extra_types/matchers/publish_all_ports.rb +3 -0
- data/lib/serverspec_extra_types/matchers/read_from_queue.rb +8 -0
- data/lib/serverspec_extra_types/matchers/write_to_queue.rb +8 -0
- data/lib/serverspec_extra_types/types.rb +18 -0
- data/lib/serverspec_extra_types/types/api_base.rb +36 -0
- data/lib/serverspec_extra_types/types/consul_base.rb +40 -0
- data/lib/serverspec_extra_types/types/consul_node.rb +20 -0
- data/lib/serverspec_extra_types/types/consul_node_list.rb +32 -0
- data/lib/serverspec_extra_types/types/consul_service.rb +24 -0
- data/lib/serverspec_extra_types/types/consul_service_list.rb +32 -0
- data/lib/serverspec_extra_types/types/docker_container.rb +124 -0
- data/lib/serverspec_extra_types/types/docker_node.rb +41 -0
- data/lib/serverspec_extra_types/types/docker_service.rb +121 -0
- data/lib/serverspec_extra_types/types/rabbitmq_base.rb +38 -0
- data/lib/serverspec_extra_types/types/rabbitmq_node_list.rb +18 -0
- data/lib/serverspec_extra_types/types/rabbitmq_user_permission.rb +39 -0
- data/lib/serverspec_extra_types/types/rabbitmq_vhost_list.rb +22 -0
- data/lib/serverspec_extra_types/types/rabbitmq_vhost_policy.rb +57 -0
- data/lib/serverspec_extra_types/version.rb +3 -0
- data/properties.yml +23 -0
- data/serverspec-extra-types.gemspec +36 -0
- metadata +232 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'serverspec_extra_types/types/consul_base'
|
2
|
+
|
3
|
+
|
4
|
+
# TODO: List and singular
|
5
|
+
module Serverspec::Type
|
6
|
+
class ConsulNodeList < ConsulBase
|
7
|
+
|
8
|
+
def url
|
9
|
+
"#{@url_base}/v1/catalog/nodes"
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
msg = "Consul Node List"
|
14
|
+
msg << %( with acl token: "#{@token}") if @token
|
15
|
+
msg
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_node?(node)
|
19
|
+
nodes.include? node
|
20
|
+
end
|
21
|
+
|
22
|
+
def nodes
|
23
|
+
inspection.keys
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspection
|
27
|
+
@inspection ||= ::MultiJson.load(get_inspection.stdout)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'serverspec_extra_types/types/consul_base'
|
2
|
+
|
3
|
+
|
4
|
+
# TODO: List and singular
|
5
|
+
module Serverspec::Type
|
6
|
+
class ConsulService < ConsulBase
|
7
|
+
|
8
|
+
def url
|
9
|
+
"#{@url_base}/v1/catalog/service/#{@name}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
msg = "Consul Service #{@name}"
|
14
|
+
msg << %( with acl token: "#{@token}") if @token
|
15
|
+
msg
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspection
|
19
|
+
@inspection ||= ::MultiJson.load(get_inspection.stdout)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'serverspec_extra_types/types/consul_base'
|
2
|
+
|
3
|
+
|
4
|
+
# TODO: List and singular
|
5
|
+
module Serverspec::Type
|
6
|
+
class ConsulServiceList < ConsulBase
|
7
|
+
|
8
|
+
def url
|
9
|
+
"#{@url_base}/v1/catalog/services"
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
msg = "Consul Service List"
|
14
|
+
msg << %( with acl token: "#{@token}") if @token
|
15
|
+
msg
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_service?(service)
|
19
|
+
services.include? service
|
20
|
+
end
|
21
|
+
|
22
|
+
def services
|
23
|
+
inspection.keys
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspection
|
27
|
+
@inspection ||= ::MultiJson.load(get_inspection.stdout)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'serverspec'
|
2
|
+
|
3
|
+
module Serverspec::Type
|
4
|
+
# This class monkey patches serverspec's docker container type with some more method to be used in matchers
|
5
|
+
class DockerContainer
|
6
|
+
def include_regex?
|
7
|
+
inspection.find { |str| str =~ regex }
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_image?(image)
|
11
|
+
self.image == image
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_image_sha?(image)
|
15
|
+
self.image_sha == image
|
16
|
+
end
|
17
|
+
|
18
|
+
def image
|
19
|
+
inspection['Config']['Image'].split('@')[0]
|
20
|
+
end
|
21
|
+
|
22
|
+
def image_sha
|
23
|
+
inspection['Config']['Image'].split('@')[1]
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_environment_variable?(regex, value = nil)
|
27
|
+
if value
|
28
|
+
environment_variable(regex) == value
|
29
|
+
else
|
30
|
+
environment_variable(regex)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def environment_variable(regex)
|
36
|
+
environment_variables.find { |str| str =~ /^#{regex}=/ }.split('=')[1]
|
37
|
+
end
|
38
|
+
|
39
|
+
def environment_variables
|
40
|
+
inspection['Config']['Env']
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_user?(user)
|
44
|
+
self.user == user
|
45
|
+
end
|
46
|
+
|
47
|
+
def user
|
48
|
+
inspection['Config']['User']
|
49
|
+
end
|
50
|
+
|
51
|
+
def has_hostname?(hostname)
|
52
|
+
self.hostname == hostname
|
53
|
+
end
|
54
|
+
|
55
|
+
def hostname
|
56
|
+
inspection['Config']['Hostname']
|
57
|
+
end
|
58
|
+
|
59
|
+
def has_domainname?(domain)
|
60
|
+
self.domain_name == domain
|
61
|
+
end
|
62
|
+
|
63
|
+
def domain_name
|
64
|
+
inspection['Config']['Domainname']
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_restart_limit?(limit)
|
68
|
+
restart_limit == limit
|
69
|
+
end
|
70
|
+
|
71
|
+
def restart_limit
|
72
|
+
inspection['HostConfig']['RestartPolicy']['MaximumRetryCount']
|
73
|
+
end
|
74
|
+
|
75
|
+
def has_restart_policy?(policy)
|
76
|
+
restart_policy == policy
|
77
|
+
end
|
78
|
+
|
79
|
+
def restart_policy
|
80
|
+
inspection['HostConfig']['RestartPolicy']['Name']
|
81
|
+
end
|
82
|
+
def has_host?(host)
|
83
|
+
hosts.include? host
|
84
|
+
end
|
85
|
+
def hosts
|
86
|
+
inspection['HostConfig']['ExtraHosts'].map {|itm| itm.split(':')[1] + ' ' + itm.split(':')[0]}
|
87
|
+
end
|
88
|
+
|
89
|
+
def privileged?
|
90
|
+
inspection['HostConfig']['Privileged']
|
91
|
+
end
|
92
|
+
|
93
|
+
# TODO: matcher for this
|
94
|
+
def publishes_all_ports?
|
95
|
+
inspection['HostConfig']['PublishAllPorts']
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def map_port?(host, container, protocol = 'tcp')
|
100
|
+
inspection['NetworkSettings']['Ports']["#{container}/#{protocol}"][0]['HostPort'] == host
|
101
|
+
end
|
102
|
+
|
103
|
+
def port_map
|
104
|
+
inspection['HostConfig']['PortBindings']
|
105
|
+
end
|
106
|
+
|
107
|
+
def has_mount?(source, target, type)
|
108
|
+
mounts.find { |mount| mount['Source'] == source && mount['Destination'] == target && mount['Type'] == type }
|
109
|
+
end
|
110
|
+
|
111
|
+
def mounts
|
112
|
+
inspection['Mounts']
|
113
|
+
end
|
114
|
+
|
115
|
+
# TODO: matcher for volumes
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def get_inspection
|
120
|
+
@containers ||= @name.include?('=') ? @runner.run_command("docker ps -qa -f #{@name}").stdout : @name
|
121
|
+
@get_inspection ||= @runner.run_command("docker inspect #{@containers}")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Serverspec::Type
|
2
|
+
class DockerNode < DockerBase
|
3
|
+
|
4
|
+
def active?
|
5
|
+
availability == 'active'
|
6
|
+
end
|
7
|
+
|
8
|
+
def availability
|
9
|
+
inspection['Spec']['Availability']
|
10
|
+
end
|
11
|
+
|
12
|
+
def role
|
13
|
+
inspection['Spec']['Role']
|
14
|
+
end
|
15
|
+
|
16
|
+
def manager?
|
17
|
+
role == 'manager'
|
18
|
+
end
|
19
|
+
|
20
|
+
def worker?
|
21
|
+
role == 'worker'
|
22
|
+
end
|
23
|
+
|
24
|
+
def labels
|
25
|
+
inspection['Spec']['Labels']
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_engine_version?(version)
|
29
|
+
engine_version == version
|
30
|
+
end
|
31
|
+
|
32
|
+
def engine_version
|
33
|
+
inspection['Description']['Engine']['EngineVersion']
|
34
|
+
end
|
35
|
+
private
|
36
|
+
|
37
|
+
def get_inspection
|
38
|
+
@get_inspection ||= @runner.run_command("docker service inspect #{@name}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'serverspec'
|
2
|
+
require 'serverspec/type/base'
|
3
|
+
require 'serverspec/type/docker_base'
|
4
|
+
|
5
|
+
module Serverspec::Type
|
6
|
+
class DockerService < DockerBase
|
7
|
+
def exist?
|
8
|
+
get_inspection.success?
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_restart_policy?(policy)
|
12
|
+
restart_policy == policy
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_restart_limit?(limit)
|
16
|
+
restart_limit == limit
|
17
|
+
end
|
18
|
+
|
19
|
+
def restart_policy
|
20
|
+
inspection['Spec']['TaskTemplate']['RestartPolicy']['Condition']
|
21
|
+
end
|
22
|
+
|
23
|
+
def restart_limit
|
24
|
+
inspection['Spec']['TaskTemplate']['RestartPolicy']['MaxAttempts']
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_image?(image)
|
28
|
+
self.image == image
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_image_sha?(image)
|
32
|
+
self.image == image
|
33
|
+
end
|
34
|
+
|
35
|
+
def image
|
36
|
+
inspection['Spec']['TaskTemplate']['ContainerSpec']['Image'].split('@')[0]
|
37
|
+
end
|
38
|
+
|
39
|
+
def image_sha
|
40
|
+
inspection['Spec']['TaskTemplate']['ContainerSpec']['Image'].split('@')[1]
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_user?(user)
|
44
|
+
self.user == user
|
45
|
+
end
|
46
|
+
|
47
|
+
def user
|
48
|
+
inspection['Spec']['TaskTemplate']['ContainerSpec']['User']
|
49
|
+
end
|
50
|
+
|
51
|
+
def has_mount?(source, target, type)
|
52
|
+
mounts.find do |mount|
|
53
|
+
mount['Source'] == source && mount['Target'] == target && mount['Type'] == type
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def mounts
|
58
|
+
inspection['Spec']['TaskTemplate']['ContainerSpec']['Mounts']
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_host?(host)
|
62
|
+
hosts.include? host
|
63
|
+
end
|
64
|
+
|
65
|
+
def hosts
|
66
|
+
inspection['Spec']['TaskTemplate']['ContainerSpec']['Hosts']
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_placement_constraint?(constraint)
|
70
|
+
placement_constraints.include? constraint
|
71
|
+
end
|
72
|
+
|
73
|
+
def placement_constraints
|
74
|
+
inspection['Spec']['TaskTemplate']['Placement']['Constraints']
|
75
|
+
end
|
76
|
+
|
77
|
+
def replicated?
|
78
|
+
inspection['Spec']['Mode']['Replicated']
|
79
|
+
end
|
80
|
+
|
81
|
+
def replicas
|
82
|
+
['Spec']['Mode']['Replicated']['Replicas']
|
83
|
+
end
|
84
|
+
def global?
|
85
|
+
inspection['Spec']['Mode']['Global']
|
86
|
+
end
|
87
|
+
|
88
|
+
def replicas
|
89
|
+
inspection['Spec']['Mode']['Replicated']['Replicas']
|
90
|
+
end
|
91
|
+
|
92
|
+
def networks
|
93
|
+
inspection['Spec']['TaskTemplate']['Networks']
|
94
|
+
end
|
95
|
+
|
96
|
+
def has_network?(name)
|
97
|
+
networks.find { |network| network['Aliases'].include? name }
|
98
|
+
end
|
99
|
+
|
100
|
+
def port_map
|
101
|
+
inspection['Spec']['EndpointSpec']['Ports']
|
102
|
+
end
|
103
|
+
|
104
|
+
def map_port?(published, target, protocol = 'tcp',mode = 'ingress')
|
105
|
+
port_map.find do |port|
|
106
|
+
port['PublishedPort'] == published.to_i &&
|
107
|
+
port['TargetPort'] == target.to_i && port['PublishMode'] == mode &&
|
108
|
+
port['Protocol'] == protocol
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def get_inspection
|
116
|
+
@get_inspection ||= @runner.run_command("docker service inspect #{@name}")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
include Serverspec::Type
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'serverspec'
|
2
|
+
require 'serverspec/type/base'
|
3
|
+
require 'multi_json'
|
4
|
+
require 'serverspec_extra_types/helpers/properties'
|
5
|
+
require 'serverspec_extra_types/types/api_base'
|
6
|
+
|
7
|
+
module Serverspec::Type
|
8
|
+
class RabbitmqBase < ApiBase
|
9
|
+
def initialize(name = nil, options = {})
|
10
|
+
super(name, options)
|
11
|
+
@user = ENV['RABBITMQ_USER'] || 'guest'
|
12
|
+
@password = ENV['RABBITMQ_PASSWORD'] || 'guest'
|
13
|
+
@url_base = property[:variables][:rabbitmq_url] || 'http://localhost:15672'
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def inspection
|
18
|
+
@inspection ||= ::MultiJson.load(get_inspection.stdout)[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
def length
|
22
|
+
if inspection.is_a? String
|
23
|
+
inspection.length
|
24
|
+
elsif inspection.kind_of? Array
|
25
|
+
inspection.length
|
26
|
+
else
|
27
|
+
1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def get_inspection
|
34
|
+
command = "curl -s -u #{@user}:#{@password} #{url}"
|
35
|
+
@get_inspection ||= @runner.run_command(command)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'serverspec_extra_types/types/rabbitmq_base'
|
2
|
+
|
3
|
+
module Serverspec::Type
|
4
|
+
class RabbitmqNodeList < RabbitmqBase
|
5
|
+
|
6
|
+
def url
|
7
|
+
"#{@url_base}/api/vhosts"
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
def inspection
|
13
|
+
@inspection ||= ::MultiJson.load(get_inspection.stdout)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'serverspec_extra_types/types/rabbitmq_base'
|
2
|
+
|
3
|
+
module Serverspec::Type
|
4
|
+
class RabbitmqUserPermission < RabbitmqBase
|
5
|
+
|
6
|
+
def url
|
7
|
+
"#{@url_base}/api/users/#{name}/permissions"
|
8
|
+
end
|
9
|
+
|
10
|
+
def read_from_queue?(vhost, queue)
|
11
|
+
queue.match read_permissions(vhost)
|
12
|
+
end
|
13
|
+
|
14
|
+
def write_to_queue?(vhost, queue)
|
15
|
+
queue.match write_permissions(vhost)
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure_queue?(vhost, queue)
|
19
|
+
queue.match configure_permissions(vhost)
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_permissions(vhost)
|
23
|
+
inspection.find { |item| item['vhost'] == vhost}['read']
|
24
|
+
end
|
25
|
+
|
26
|
+
def write_permissions(vhost)
|
27
|
+
inspection.find { |item| item['vhost'] == vhost}['write']
|
28
|
+
end
|
29
|
+
|
30
|
+
def configure_permissions(vhost)
|
31
|
+
inspection.find { |item| item['vhost'] == vhost}['configure']
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspection
|
35
|
+
@inspection ||= ::MultiJson.load(get_inspection.stdout)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|