octopus-serverspec-extensions 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,29 +1,29 @@
1
- require 'serverspec'
2
- require 'serverspec/type/base'
3
-
4
- module Serverspec::Type
5
- class JavaPropertyFile < Base
6
-
7
- def initialize(name)
8
- @name = name
9
- @runner = Specinfra::Runner
10
- end
11
-
12
- def has_property?(propertyName, propertyValue)
13
- properties = {}
14
- IO.foreach(@name) do |line|
15
- if (!line.start_with?('#'))
16
- properties[$1.strip] = $2 if line =~ /([^=]*)=(.*)/
17
- end
18
- end
19
-
20
- properties[propertyName] == propertyValue
21
- end
22
- end
23
-
24
- def java_property_file(name)
25
- JavaPropertyFile.new(name)
26
- end
27
- end
28
-
1
+ require 'serverspec'
2
+ require 'serverspec/type/base'
3
+
4
+ module Serverspec::Type
5
+ class JavaPropertyFile < Base
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @runner = Specinfra::Runner
10
+ end
11
+
12
+ def has_property?(propertyName, propertyValue)
13
+ properties = {}
14
+ IO.foreach(@name) do |line|
15
+ if (!line.start_with?('#'))
16
+ properties[$1.strip] = $2 if line =~ /([^=]*)=(.*)/
17
+ end
18
+ end
19
+
20
+ properties[propertyName] == propertyValue
21
+ end
22
+ end
23
+
24
+ def java_property_file(name)
25
+ JavaPropertyFile.new(name)
26
+ end
27
+ end
28
+
29
29
  include Serverspec::Type
@@ -1,37 +1,37 @@
1
- require 'serverspec'
2
- require 'serverspec/type/base'
3
-
4
- module Serverspec::Type
5
- class NpmPackage < Base
6
-
7
- def initialize(name)
8
- @name = name
9
- @runner = Specinfra::Runner
10
- end
11
-
12
- def installed?(provider, version)
13
- command_result = @runner.run_command("npm list -g #{name}")
14
-
15
- software = command_result.stdout.split("\n").each_with_object({}) do |s, h|
16
- if s.include? "@"
17
- package_name, package_version = s.split('@')
18
- package_name = package_name.gsub(/.*? /, '')
19
- h[String(package_name).strip.downcase] = String(package_version).strip.downcase
20
- end
21
- h
22
- end
23
-
24
- if (version.nil?)
25
- !software[name.downcase].nil?
26
- else
27
- software[name.downcase] == version
28
- end
29
- end
30
- end
31
-
32
- def npm_package(name)
33
- NpmPackage.new(name)
34
- end
35
- end
36
-
1
+ require 'serverspec'
2
+ require 'serverspec/type/base'
3
+
4
+ module Serverspec::Type
5
+ class NpmPackage < Base
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @runner = Specinfra::Runner
10
+ end
11
+
12
+ def installed?(provider, version)
13
+ command_result = @runner.run_command("npm list -g #{name}")
14
+
15
+ software = command_result.stdout.split("\n").each_with_object({}) do |s, h|
16
+ if s.include? "@"
17
+ package_name, package_version = s.split('@')
18
+ package_name = package_name.gsub(/.*? /, '')
19
+ h[String(package_name).strip.downcase] = String(package_version).strip.downcase
20
+ end
21
+ h
22
+ end
23
+
24
+ if (version.nil?)
25
+ !software[name.downcase].nil?
26
+ else
27
+ software[name.downcase] == version
28
+ end
29
+ end
30
+ end
31
+
32
+ def npm_package(name)
33
+ NpmPackage.new(name)
34
+ end
35
+ end
36
+
37
37
  include Serverspec::Type
@@ -1,57 +1,58 @@
1
- require 'serverspec'
2
- require 'serverspec/type/base'
3
- require 'net/http'
4
- require 'json'
5
-
6
- module Serverspec::Type
7
- class OctopusDeployEnvironment < Base
8
- @environment = nil
9
- @serverUrl = nil
10
- @apiKey = nil
11
-
12
- def initialize(serverUrl, apiKey, environment_name)
13
- @name = "Octopus Deploy Environment #{environment_name}"
14
- @runner = Specinfra::Runner
15
- @serverUrl = serverUrl
16
- @apiKey = apiKey
17
-
18
- if (serverUrl.nil?)
19
- puts "'serverUrl' was not provided. Unable to connect to Octopus server to validate configuration."
20
- return
21
- end
22
- if (apiKey.nil?)
23
- puts "'apiKey' was not provided. Unable to connect to Octopus server to validate configuration."
24
- return
25
- end
26
-
27
- @environment = get_environment_via_api(serverUrl, apiKey, environment_name)
28
- end
29
-
30
- def exists?
31
- !@environment.nil?
32
- end
33
- end
34
-
35
- def octopus_deploy_environment(serverUrl, apiKey, environment_name)
36
- OctopusDeployEnvironment.new(serverUrl, apiKey, environment_name)
37
- end
38
-
39
- private
40
-
41
- def get_environment_via_api(serverUrl, apiKey, environment_name)
42
- environment = nil
43
- url = "#{serverUrl}/api/environments?name=#{environment_name}&api-key=#{apiKey}"
44
-
45
- begin
46
- resp = Net::HTTP.get_response(URI.parse(url))
47
- body = JSON.parse(resp.body)
48
- environment = body['Items'].first unless body.nil?
49
- rescue => e
50
- puts "Unable to connect to #{url}: #{e}"
51
- end
52
-
53
- environment
54
- end
55
- end
56
-
57
- include Serverspec::Type
1
+ require 'serverspec'
2
+ require 'serverspec/type/base'
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module Serverspec::Type
7
+ class OctopusDeployEnvironment < Base
8
+ @environment = nil
9
+ @serverUrl = nil
10
+ @apiKey = nil
11
+
12
+ def initialize(serverUrl, apiKey, environment_name)
13
+ @name = "Octopus Deploy Environment #{environment_name}"
14
+ @runner = Specinfra::Runner
15
+ @serverUrl = serverUrl
16
+ @apiKey = apiKey
17
+
18
+ if (serverUrl.nil?)
19
+ raise "'serverUrl' was not provided. Unable to connect to Octopus server to validate configuration."
20
+ end
21
+ if (apiKey.nil?)
22
+ raise "'apiKey' was not provided. Unable to connect to Octopus server to validate configuration."
23
+ end
24
+ if (environment_name.nil?)
25
+ raise "'environment_name' was not provided. Unable to connect to Octopus server to validate configuration."
26
+ end
27
+
28
+ @environment = get_environment_via_api(serverUrl, apiKey, environment_name)
29
+ end
30
+
31
+ def exists?
32
+ (!@environment.nil?) && (@environment != [])
33
+ end
34
+ end
35
+
36
+ def octopus_deploy_environment(serverUrl, apiKey, environment_name)
37
+ OctopusDeployEnvironment.new(serverUrl, apiKey, environment_name)
38
+ end
39
+
40
+ private
41
+
42
+ def get_environment_via_api(serverUrl, apiKey, environment_name)
43
+ environment = nil
44
+ url = "#{serverUrl}/api/environments?name=#{environment_name}&api-key=#{apiKey}"
45
+
46
+ begin
47
+ resp = Net::HTTP.get_response(URI.parse(url))
48
+ body = JSON.parse(resp.body)
49
+ environment = body['Items'].first unless body.nil?
50
+ rescue => e
51
+ raise "Unable to connect to #{url}: #{e}"
52
+ end
53
+
54
+ environment
55
+ end
56
+ end
57
+
58
+ include Serverspec::Type
@@ -1,171 +1,204 @@
1
- require 'serverspec'
2
- require 'serverspec/type/base'
3
- require 'net/http'
4
- require 'json'
5
-
6
- module Serverspec::Type
7
- class OctopusDeployTentacle < Base
8
- @machine = nil
9
- @serverUrl = nil
10
- @apiKey = nil
11
-
12
- def initialize(serverUrl, apiKey, instance)
13
- @name = "Octopus Deploy Tentacle #{instance}"
14
- @runner = Specinfra::Runner
15
- @serverUrl = serverUrl
16
- @apiKey = apiKey
17
-
18
- if (serverUrl.nil?)
19
- puts "'serverUrl' was not provided. Unable to connect to Octopus server to validate configuration."
20
- return
21
- end
22
- if (apiKey.nil?)
23
- puts "'apiKey' was not provided. Unable to connect to Octopus server to validate configuration."
24
- return
25
- end
26
-
27
- if (exists?)
28
- thumbprint = `"c:\\program files\\Octopus Deploy\\Tentacle\\Tentacle.exe" show-thumbprint --console --nologo --instance #{instance}`
29
- thumbprint = thumbprint.gsub('==== ShowThumbprintCommand starting ====', '').strip
30
- thumbprint = thumbprint.gsub('The thumbprint of this Tentacle is: ', '').strip
31
- thumbprint = thumbprint.gsub('==== ShowThumbprintCommand completed ====', '').strip
32
- thumbprint = thumbprint.gsub('==== ShowThumbprintCommand ====', '').strip
33
-
34
- @machine = get_machine_via_api(serverUrl, apiKey, thumbprint)
35
- else
36
- puts "tentacle.exe does not exist"
37
- end
38
- end
39
-
40
- def registered_with_the_server?
41
- !@machine.nil?
42
- end
43
-
44
- def online?
45
- return nil if @machine.nil?
46
- @machine = poll_until_machine_has_completed_healthcheck(@serverUrl, @apiKey, @machine["Thumbprint"])
47
- status = @machine['Status']
48
- if ("#{status}" == "")
49
- status = @machine['HealthStatus'] if "#{status}" == ""
50
- puts "Expected status 'Healthy|HasWarnings' for Tentacle #{@name}, but got '#{status}'" if (status != "Healthy" && status != "HasWarnings")
51
- status == "Healthy" || status == "HasWarnings"
52
- else
53
- puts "Expected status 'Online|CalamariNeedsUpgrade|NeedsUpgrade' for Tentacle #{@name}, but got '#{status}'" if (status != "Online" && status != "CalamariNeedsUpgrade" && status != "NeedsUpgrade")
54
- status == "Online" || status == "CalamariNeedsUpgrade" || status == "NeedsUpgrade"
55
- end
56
- end
57
-
58
- def in_environment?(environment_name)
59
- return false if @machine.nil?
60
- url = "#{@serverUrl}/api/environments/all?api-key=#{@apiKey}"
61
- resp = Net::HTTP.get_response(URI.parse(url))
62
- environments = JSON.parse(resp.body)
63
- environment_id = environments.select {|e| e["Name"] == environment_name}.first["Id"]
64
- !@machine["EnvironmentIds"].select {|e| e == environment_id}.empty?
65
- end
66
-
67
- def has_tenant?(tenant_name)
68
- return false if @machine.nil?
69
- url = "#{@serverUrl}/api/tenants/all?api-key=#{@apiKey}"
70
- resp = Net::HTTP.get_response(URI.parse(url))
71
- tenants = JSON.parse(resp.body)
72
- tenant_id = tenants.select {|e| e["Name"] == tenant_name}.first["Id"]
73
- !@machine["TenantIds"].select {|e| e == tenant_id}.empty?
74
- end
75
-
76
- def has_tenant_tag?(tag_set, tag)
77
- return false if @machine.nil?
78
- tenant_tags = @machine["TenantTags"]
79
- !tenant_tags.select {|e| e == "#{tag_set}/#{tag}"}.empty?
80
- end
81
-
82
- def has_policy?(policy_name)
83
- return false if @machine.nil?
84
- url = "#{@serverUrl}/api/machinepolicies/all?api-key=#{@apiKey}"
85
- resp = Net::HTTP.get_response(URI.parse(url))
86
- policies = JSON.parse(resp.body)
87
- policy_id = policies.select {|e| e["Name"] == policy_name}.first["Id"]
88
- @machine["MachinePolicyId"] == policy_id
89
- end
90
-
91
- def has_role?(role_name)
92
- return false if @machine.nil?
93
- roles = @machine["Roles"]
94
- !roles.select {|e| e == role_name}.empty?
95
- end
96
-
97
- def has_display_name?(name)
98
- return false if @machine.nil?
99
- @machine["Name"] == name
100
- end
101
-
102
- def has_endpoint?(uri)
103
- return false if @machine.nil?
104
- puts "Expected uri '#{uri}' for Tentacle #{@name}, but got '#{@machine["Uri"]}'" unless (@machine["Uri"].casecmp(uri) == 0)
105
- @machine["Uri"].casecmp(uri) == 0
106
- end
107
-
108
- def listening_tentacle?
109
- return false if @machine.nil?
110
- puts "Expected CommunicationStyle 'TentaclePassive' for Tentacle #{@name}, but got '#{@machine["Endpoint"]["CommunicationStyle"]}'" if (@machine["Endpoint"]["CommunicationStyle"] != "TentaclePassive")
111
- @machine["Endpoint"]["CommunicationStyle"] == "TentaclePassive"
112
- end
113
-
114
- def polling_tentacle?
115
- return false if @machine.nil?
116
- puts "Expected CommunicationStyle 'TentacleActive' for Tentacle #{@name}, but got '#{@machine["Endpoint"]["CommunicationStyle"]}'" if (@machine["Endpoint"]["CommunicationStyle"] != "TentacleActive")
117
- @machine["Endpoint"]["CommunicationStyle"] == "TentacleActive"
118
- end
119
-
120
- def exists?
121
- ::File.exists?("c:\\program files\\Octopus Deploy\\Tentacle\\Tentacle.exe")
122
- end
123
- end
124
-
125
- def octopus_deploy_tentacle(serverUrl, apiKey, instance)
126
- OctopusDeployTentacle.new(serverUrl, apiKey, instance)
127
- end
128
-
129
- private
130
-
131
- def poll_until_machine_has_completed_healthcheck(serverUrl, apiKey, thumbprint)
132
- machine = nil
133
- url = "#{serverUrl}/api/machines/all?api-key=#{apiKey}"
134
-
135
- now = Time.now
136
- counter = 1
137
- loop do
138
- machine = get_machine_via_api(serverUrl, apiKey, thumbprint)
139
-
140
- break if machine.nil?
141
- break if counter > 10
142
- break if !machine_healthcheck_outstanding(machine)
143
- puts "Machine health check for #{machine["Name"]} has not yet completed. Waiting 5 seconds to try again."
144
- counter += 1
145
- sleep 5
146
- end
147
-
148
- machine
149
- end
150
-
151
- def machine_healthcheck_outstanding(machine)
152
- machine["StatusSummary"] == "This machine was recently added. Please perform a health check."
153
- end
154
-
155
- def get_machine_via_api(serverUrl, apiKey, thumbprint)
156
- machine = nil
157
- url = "#{serverUrl}/api/machines/all?api-key=#{apiKey}"
158
-
159
- begin
160
- resp = Net::HTTP.get_response(URI.parse(url))
161
- body = JSON.parse(resp.body)
162
- machine = body.select {|e| e["Thumbprint"] == thumbprint}.first unless body.nil?
163
- rescue => e
164
- puts "Unable to connect to #{url}: #{e}"
165
- end
166
-
167
- machine
168
- end
169
- end
170
-
171
- include Serverspec::Type
1
+ require 'serverspec'
2
+ require 'serverspec/type/base'
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module Serverspec::Type
7
+ class OctopusDeployTentacle < Base
8
+ @machine = nil
9
+ @serverUrl = nil
10
+ @apiKey = nil
11
+ @serverSupportsSpaces = nil
12
+ @spaceId = nil
13
+ @spaceFragment = ""
14
+
15
+ def initialize(serverUrl, apiKey, instance, spaceId = 'Spaces-1')
16
+ @name = "Octopus Deploy Tentacle #{instance}"
17
+ @runner = Specinfra::Runner
18
+ @serverUrl = serverUrl
19
+ @apiKey = apiKey
20
+ @spaceId = spaceId
21
+
22
+ if (serverUrl.nil?)
23
+ puts "'serverUrl' was not provided. Unable to connect to Octopus server to validate configuration."
24
+ return
25
+ end
26
+ if (apiKey.nil?)
27
+ puts "'apiKey' was not provided. Unable to connect to Octopus server to validate configuration."
28
+ return
29
+ end
30
+
31
+ if (exists?)
32
+ thumbprint = `"c:\\program files\\Octopus Deploy\\Tentacle\\Tentacle.exe" show-thumbprint --console --nologo --instance #{instance}`
33
+ thumbprint = thumbprint.gsub('==== ShowThumbprintCommand starting ====', '').strip
34
+ thumbprint = thumbprint.gsub('The thumbprint of this Tentacle is: ', '').strip
35
+ thumbprint = thumbprint.gsub('==== ShowThumbprintCommand completed ====', '').strip
36
+ thumbprint = thumbprint.gsub('==== ShowThumbprintCommand ====', '').strip
37
+
38
+ @serverSupportsSpaces = check_supports_spaces(serverUrl)
39
+
40
+ if (@serverSupportsSpaces)
41
+ @spaceFragment = "#{@spaceId}/"
42
+ end
43
+
44
+ @machine = get_machine_via_api(serverUrl, apiKey, thumbprint)
45
+ else
46
+ puts "tentacle.exe does not exist"
47
+ end
48
+ end
49
+
50
+ def registered_with_the_server?
51
+ !@machine.nil?
52
+ end
53
+
54
+ def online?
55
+ return nil if @machine.nil?
56
+ @machine = poll_until_machine_has_completed_healthcheck(@serverUrl, @apiKey, @machine["Thumbprint"])
57
+ status = @machine['Status']
58
+ if ("#{status}" == "")
59
+ status = @machine['HealthStatus'] if "#{status}" == ""
60
+ puts "Expected status 'Healthy|HasWarnings' for Tentacle #{@name}, but got '#{status}'" if (status != "Healthy" && status != "HasWarnings")
61
+ status == "Healthy" || status == "HasWarnings"
62
+ else
63
+ puts "Expected status 'Online|CalamariNeedsUpgrade|NeedsUpgrade' for Tentacle #{@name}, but got '#{status}'" if (status != "Online" && status != "CalamariNeedsUpgrade" && status != "NeedsUpgrade")
64
+ status == "Online" || status == "CalamariNeedsUpgrade" || status == "NeedsUpgrade"
65
+ end
66
+ end
67
+
68
+ def in_environment?(environment_name)
69
+ return false if @machine.nil?
70
+ url = "#{@serverUrl}/api/#{spaceFragment}environments/all?api-key=#{@apiKey}"
71
+ resp = Net::HTTP.get_response(URI.parse(url))
72
+ environments = JSON.parse(resp.body)
73
+ environment_id = environments.select {|e| e["Name"] == environment_name}.first["Id"]
74
+ !@machine["EnvironmentIds"].select {|e| e == environment_id}.empty?
75
+ end
76
+
77
+ def in_space?(space_name)
78
+ return false if @machine.nil?
79
+ return false if @serverSupportsSpaces
80
+ url = "#{@serverUrl}/api/#{spaceFragment}spaces/all?api-key=#{@apiKey}"
81
+ resp = Net::HTTP.get_response(URI.parse(url))
82
+ spaces = JSON.parse(resp.body)
83
+ space_id = spaces.select {|e| e["Name"] == space_name}.first["Id"]
84
+ @machine["SpaceId"] == space_id
85
+ end
86
+
87
+ def has_tenant?(tenant_name)
88
+ return false if @machine.nil?
89
+ url = "#{@serverUrl}/api/#{spaceFragment}tenants/all?api-key=#{@apiKey}"
90
+ resp = Net::HTTP.get_response(URI.parse(url))
91
+ tenants = JSON.parse(resp.body)
92
+ tenant_id = tenants.select {|e| e["Name"] == tenant_name}.first["Id"]
93
+ !@machine["TenantIds"].select {|e| e == tenant_id}.empty?
94
+ end
95
+
96
+ def has_tenant_tag?(tag_set, tag)
97
+ return false if @machine.nil?
98
+ tenant_tags = @machine["TenantTags"]
99
+ !tenant_tags.select {|e| e == "#{tag_set}/#{tag}"}.empty?
100
+ end
101
+
102
+ def has_policy?(policy_name)
103
+ return false if @machine.nil?
104
+ url = "#{@serverUrl}/api/#{spaceFragment}machinepolicies/all?api-key=#{@apiKey}"
105
+ resp = Net::HTTP.get_response(URI.parse(url))
106
+ policies = JSON.parse(resp.body)
107
+ policy_id = policies.select {|e| e["Name"] == policy_name}.first["Id"]
108
+ @machine["MachinePolicyId"] == policy_id
109
+ end
110
+
111
+ def has_role?(role_name)
112
+ return false if @machine.nil?
113
+ roles = @machine["Roles"]
114
+ !roles.select {|e| e == role_name}.empty?
115
+ end
116
+
117
+ def has_display_name?(name)
118
+ return false if @machine.nil?
119
+ @machine["Name"] == name
120
+ end
121
+
122
+ def has_endpoint?(uri)
123
+ return false if @machine.nil?
124
+ puts "Expected uri '#{uri}' for Tentacle #{@name}, but got '#{@machine["Uri"]}'" unless (@machine["Uri"].casecmp(uri) == 0)
125
+ @machine["Uri"].casecmp(uri) == 0
126
+ end
127
+
128
+ def listening_tentacle?
129
+ return false if @machine.nil?
130
+ puts "Expected CommunicationStyle 'TentaclePassive' for Tentacle #{@name}, but got '#{@machine["Endpoint"]["CommunicationStyle"]}'" if (@machine["Endpoint"]["CommunicationStyle"] != "TentaclePassive")
131
+ @machine["Endpoint"]["CommunicationStyle"] == "TentaclePassive"
132
+ end
133
+
134
+ def polling_tentacle?
135
+ return false if @machine.nil?
136
+ puts "Expected CommunicationStyle 'TentacleActive' for Tentacle #{@name}, but got '#{@machine["Endpoint"]["CommunicationStyle"]}'" if (@machine["Endpoint"]["CommunicationStyle"] != "TentacleActive")
137
+ @machine["Endpoint"]["CommunicationStyle"] == "TentacleActive"
138
+ end
139
+
140
+ def exists?
141
+ ::File.exists?("c:\\program files\\Octopus Deploy\\Tentacle\\Tentacle.exe")
142
+ end
143
+ end
144
+
145
+ def octopus_deploy_tentacle(serverUrl, apiKey, instance)
146
+ OctopusDeployTentacle.new(serverUrl, apiKey, instance)
147
+ end
148
+
149
+ private
150
+
151
+ def check_supports_spaces(serverUrl)
152
+ begin
153
+ resp = Net::HTTP.get_response(URI.parse("#{serverUrl}/api/"))
154
+ body = JSON.parse(resp.body)
155
+ version = body['Version']
156
+ return Gem::Version.new(version) > Gem::Version.new('2019.0.0')
157
+ rescue => e
158
+ puts "Unable to connect to #{serverUrl}: #{e}"
159
+ end
160
+
161
+ return false
162
+ end
163
+
164
+ def poll_until_machine_has_completed_healthcheck(serverUrl, apiKey, thumbprint)
165
+ machine = nil
166
+ url = "#{serverUrl}/api/#{spaceFragment}machines/all?api-key=#{apiKey}"
167
+
168
+ now = Time.now
169
+ counter = 1
170
+ loop do
171
+ machine = get_machine_via_api(serverUrl, apiKey, thumbprint)
172
+
173
+ break if machine.nil?
174
+ break if counter > 10
175
+ break if !machine_healthcheck_outstanding(machine)
176
+ puts "Machine health check for #{machine["Name"]} has not yet completed. Waiting 5 seconds to try again."
177
+ counter += 1
178
+ sleep 5
179
+ end
180
+
181
+ machine
182
+ end
183
+
184
+ def machine_healthcheck_outstanding(machine)
185
+ machine["StatusSummary"] == "This machine was recently added. Please perform a health check."
186
+ end
187
+
188
+ def get_machine_via_api(serverUrl, apiKey, thumbprint)
189
+ machine = nil
190
+ url = "#{serverUrl}/api/#{spaceFragment}machines/all?api-key=#{apiKey}"
191
+
192
+ begin
193
+ resp = Net::HTTP.get_response(URI.parse(url))
194
+ body = JSON.parse(resp.body)
195
+ machine = body.select {|e| e["Thumbprint"] == thumbprint}.first unless body.nil?
196
+ rescue => e
197
+ puts "Unable to connect to #{url}: #{e}"
198
+ end
199
+
200
+ machine
201
+ end
202
+ end
203
+
204
+ include Serverspec::Type