itamae 1.10.0 → 1.12.5
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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +203 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +144 -1
- data/README.md +2 -3
- data/Rakefile +50 -42
- data/bin/itamae +0 -1
- data/itamae.gemspec +2 -2
- data/lib/itamae/backend.rb +20 -5
- data/lib/itamae/cli.rb +14 -9
- data/lib/itamae/definition.rb +0 -2
- data/lib/itamae/logger.rb +5 -1
- data/lib/itamae/mash.rb +7 -0
- data/lib/itamae/node.rb +4 -4
- data/lib/itamae/notification.rb +0 -2
- data/lib/itamae/recipe.rb +20 -3
- data/lib/itamae/resource/base.rb +3 -3
- data/lib/itamae/resource/directory.rb +0 -2
- data/lib/itamae/resource/execute.rb +0 -2
- data/lib/itamae/resource/file.rb +43 -6
- data/lib/itamae/resource/gem_package.rb +0 -2
- data/lib/itamae/resource/git.rb +5 -7
- data/lib/itamae/resource/group.rb +0 -2
- data/lib/itamae/resource/http_request.rb +12 -3
- data/lib/itamae/resource/link.rb +0 -2
- data/lib/itamae/resource/local_ruby_block.rb +0 -2
- data/lib/itamae/resource/package.rb +3 -3
- data/lib/itamae/resource/remote_directory.rb +1 -3
- data/lib/itamae/resource/remote_file.rb +0 -2
- data/lib/itamae/resource/service.rb +0 -2
- data/lib/itamae/resource/template.rb +8 -4
- data/lib/itamae/resource/user.rb +0 -2
- data/lib/itamae/resource.rb +0 -1
- data/lib/itamae/runner.rb +3 -4
- data/lib/itamae/version.rb +1 -1
- data/lib/itamae.rb +1 -1
- data/spec/integration/default_spec.rb +26 -32
- data/spec/integration/docker_spec.rb +29 -0
- data/spec/integration/local_spec.rb +6 -0
- data/spec/integration/ordinary_user_spec.rb +108 -0
- data/spec/integration/recipes/default.rb +10 -48
- data/spec/integration/recipes/docker.rb +44 -0
- data/spec/integration/recipes/local.rb +19 -0
- data/spec/integration/recipes/ordinary_user.rb +109 -0
- data/spec/integration/recipes/toplevel_module.rb +6 -0
- data/spec/integration/recipes/variables.rb +14 -0
- data/spec/unit/lib/itamae/backend_spec.rb +10 -10
- data/tasks/integration_local_spec.rb +117 -0
- metadata +26 -9
- data/.travis.yml +0 -39
data/lib/itamae/mash.rb
ADDED
data/lib/itamae/node.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'itamae'
|
2
1
|
require 'hashie'
|
3
2
|
require 'json'
|
4
3
|
require 'schash'
|
4
|
+
require 'itamae/mash'
|
5
5
|
|
6
6
|
module Itamae
|
7
7
|
class Node
|
@@ -10,7 +10,7 @@ module Itamae
|
|
10
10
|
attr_reader :mash
|
11
11
|
|
12
12
|
def initialize(hash, backend)
|
13
|
-
@mash =
|
13
|
+
@mash = Itamae::Mash.new(hash)
|
14
14
|
@backend = backend
|
15
15
|
end
|
16
16
|
|
@@ -43,7 +43,7 @@ module Itamae
|
|
43
43
|
private
|
44
44
|
|
45
45
|
def _reverse_merge(other_hash)
|
46
|
-
|
46
|
+
Itamae::Mash.new(other_hash).merge(@mash)
|
47
47
|
end
|
48
48
|
|
49
49
|
def method_missing(method, *args)
|
@@ -63,7 +63,7 @@ module Itamae
|
|
63
63
|
def fetch_inventory_value(key)
|
64
64
|
value = @backend.host_inventory[key]
|
65
65
|
if value.is_a?(Hash)
|
66
|
-
value =
|
66
|
+
value = Itamae::Mash.new(value)
|
67
67
|
end
|
68
68
|
|
69
69
|
value
|
data/lib/itamae/notification.rb
CHANGED
data/lib/itamae/recipe.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
|
-
|
3
1
|
module Itamae
|
4
2
|
class Recipe
|
5
3
|
NotFoundError = Class.new(StandardError)
|
@@ -55,7 +53,7 @@ module Itamae
|
|
55
53
|
|
56
54
|
def load(vars = {})
|
57
55
|
context = EvalContext.new(self, vars)
|
58
|
-
|
56
|
+
InstanceEval.new(File.read(path), path, 1, context: context).call
|
59
57
|
end
|
60
58
|
|
61
59
|
def run
|
@@ -153,6 +151,25 @@ module Itamae
|
|
153
151
|
end
|
154
152
|
end
|
155
153
|
|
154
|
+
class InstanceEval
|
155
|
+
def initialize(src, path, lineno, context:)
|
156
|
+
# Using instance_eval + eval to allow top-level class/module definition without `::`.
|
157
|
+
# To pass args without introducing any local/instance variables, this code is also eval-ed.
|
158
|
+
@code = <<-RUBY
|
159
|
+
@context.instance_eval do
|
160
|
+
eval(#{src.dump}, nil, #{path.dump}, #{lineno})
|
161
|
+
end
|
162
|
+
RUBY
|
163
|
+
@context = context
|
164
|
+
end
|
165
|
+
|
166
|
+
# This method has no local variables to avoid spilling them to recipes.
|
167
|
+
def call
|
168
|
+
eval(@code)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
private_constant :InstanceEval
|
172
|
+
|
156
173
|
class RecipeFromDefinition < Recipe
|
157
174
|
attr_accessor :definition
|
158
175
|
|
data/lib/itamae/resource/base.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
1
|
require 'shellwords'
|
3
2
|
require 'hashie'
|
4
3
|
|
@@ -16,7 +15,7 @@ module Itamae
|
|
16
15
|
def initialize(resource)
|
17
16
|
@resource = resource
|
18
17
|
|
19
|
-
@attributes =
|
18
|
+
@attributes = Itamae::Mash.new
|
20
19
|
@notifications = []
|
21
20
|
@subscriptions = []
|
22
21
|
@verify_commands = []
|
@@ -196,6 +195,7 @@ module Itamae
|
|
196
195
|
show_differences
|
197
196
|
|
198
197
|
method_name = "action_#{action}"
|
198
|
+
Itamae.logger.debug "(in #{method_name})"
|
199
199
|
if runner.dry_run?
|
200
200
|
unless respond_to?(method_name)
|
201
201
|
Itamae.logger.error "action #{action.inspect} is unavailable"
|
@@ -222,7 +222,7 @@ module Itamae
|
|
222
222
|
end
|
223
223
|
|
224
224
|
def clear_current_attributes
|
225
|
-
@current_attributes =
|
225
|
+
@current_attributes = Itamae::Mash.new
|
226
226
|
end
|
227
227
|
|
228
228
|
def pre_action
|
data/lib/itamae/resource/file.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
require 'itamae'
|
2
|
-
|
3
1
|
module Itamae
|
4
2
|
module Resource
|
5
3
|
class File < Base
|
6
4
|
define_attribute :action, default: :create
|
7
5
|
define_attribute :path, type: String, default_name: true
|
8
6
|
define_attribute :content, type: String, default: nil
|
7
|
+
define_attribute :sensitive, default: false
|
9
8
|
define_attribute :mode, type: String
|
10
9
|
define_attribute :owner, type: String
|
11
10
|
define_attribute :group, type: String
|
12
11
|
define_attribute :block, type: Proc, default: proc {}
|
13
12
|
|
13
|
+
class << self
|
14
|
+
attr_accessor :sha256sum_available
|
15
|
+
end
|
16
|
+
|
14
17
|
def pre_action
|
15
18
|
current.exist = run_specinfra(:check_file_is_file, attributes.path)
|
16
19
|
|
@@ -29,6 +32,11 @@ module Itamae
|
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
35
|
+
if exists_and_not_modified?
|
36
|
+
attributes.modified = false
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
32
40
|
send_tempfile
|
33
41
|
compare_file
|
34
42
|
end
|
@@ -135,10 +143,28 @@ module Itamae
|
|
135
143
|
end
|
136
144
|
end
|
137
145
|
|
146
|
+
def exists_and_not_modified?
|
147
|
+
return false unless current.exist && sha256sum_available?
|
148
|
+
|
149
|
+
current_digest = run_command(["sha256sum", attributes.path]).stdout.split(/\s/, 2).first
|
150
|
+
digest = if content_file
|
151
|
+
Digest::SHA256.file(content_file).hexdigest
|
152
|
+
else
|
153
|
+
Digest::SHA256.hexdigest(attributes.content.to_s)
|
154
|
+
end
|
155
|
+
|
156
|
+
current_digest == digest
|
157
|
+
end
|
158
|
+
|
138
159
|
def show_content_diff
|
160
|
+
if attributes.sensitive
|
161
|
+
Itamae.logger.info("diff exists, but not displaying sensitive content")
|
162
|
+
return
|
163
|
+
end
|
164
|
+
|
139
165
|
if attributes.modified
|
140
166
|
Itamae.logger.info "diff:"
|
141
|
-
diff = run_command(["diff", "-u", compare_to, @temppath], error: false)
|
167
|
+
diff = run_command(["diff", "-u", "--label=#{attributes.path} (BEFORE)", compare_to, "--label=#{attributes.path} (AFTER)", @temppath], error: false)
|
142
168
|
diff.stdout.each_line do |line|
|
143
169
|
color = if line.start_with?('+')
|
144
170
|
:green
|
@@ -173,7 +199,12 @@ module Itamae
|
|
173
199
|
src = if content_file
|
174
200
|
content_file
|
175
201
|
else
|
176
|
-
f =
|
202
|
+
f =
|
203
|
+
if Gem.win_platform?
|
204
|
+
Tempfile.open('itamae', :mode=>IO::BINARY)
|
205
|
+
else
|
206
|
+
Tempfile.open('itamae')
|
207
|
+
end
|
177
208
|
f.write(attributes.content)
|
178
209
|
f.close
|
179
210
|
f.path
|
@@ -183,12 +214,12 @@ module Itamae
|
|
183
214
|
|
184
215
|
if backend.is_a?(Itamae::Backend::Docker)
|
185
216
|
run_command(["mkdir", @temppath])
|
186
|
-
backend.send_file(src, @temppath)
|
217
|
+
backend.send_file(src, @temppath, user: attributes.user)
|
187
218
|
@temppath = ::File.join(@temppath, ::File.basename(src))
|
188
219
|
else
|
189
220
|
run_command(["touch", @temppath])
|
190
221
|
run_specinfra(:change_file_mode, @temppath, '0600')
|
191
|
-
backend.send_file(src, @temppath)
|
222
|
+
backend.send_file(src, @temppath, user: attributes.user)
|
192
223
|
end
|
193
224
|
|
194
225
|
run_specinfra(:change_file_mode, @temppath, '0600')
|
@@ -196,6 +227,12 @@ module Itamae
|
|
196
227
|
f.unlink if f
|
197
228
|
end
|
198
229
|
end
|
230
|
+
|
231
|
+
def sha256sum_available?
|
232
|
+
return self.class.sha256sum_available unless self.class.sha256sum_available.nil?
|
233
|
+
|
234
|
+
self.class.sha256sum_available = run_command(["sha256sum", "--version"], error: false).exit_status == 0
|
235
|
+
end
|
199
236
|
end
|
200
237
|
end
|
201
238
|
end
|
data/lib/itamae/resource/git.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
|
-
|
3
1
|
module Itamae
|
4
2
|
module Resource
|
5
3
|
class Git < Base
|
@@ -86,11 +84,11 @@ module Itamae
|
|
86
84
|
end
|
87
85
|
|
88
86
|
def get_revision(branch)
|
89
|
-
result = run_command_in_repo("git rev-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
run_command_in_repo("git rev-
|
87
|
+
result = run_command_in_repo("git rev-parse #{shell_escape(branch)}", error: false)
|
88
|
+
return result.stdout.strip if result.exit_status == 0
|
89
|
+
|
90
|
+
fetch_origin!
|
91
|
+
run_command_in_repo("git rev-parse #{shell_escape(branch)}").stdout.strip
|
94
92
|
end
|
95
93
|
|
96
94
|
def fetch_origin!
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
1
|
require 'uri'
|
3
2
|
require 'net/https'
|
4
3
|
|
@@ -6,6 +5,9 @@ module Itamae
|
|
6
5
|
module Resource
|
7
6
|
class HttpRequest < File
|
8
7
|
RedirectLimitExceeded = Class.new(StandardError)
|
8
|
+
HTTPClientError = Class.new(StandardError)
|
9
|
+
HTTPServerError = Class.new(StandardError)
|
10
|
+
HTTPUnknownError = Class.new(StandardError)
|
9
11
|
|
10
12
|
alias_method :_action_create, :action_create
|
11
13
|
undef_method :action_create, :action_delete, :action_edit
|
@@ -49,7 +51,10 @@ module Itamae
|
|
49
51
|
response = http.method(attributes.action).call(uri.request_uri, attributes.message, attributes.headers)
|
50
52
|
end
|
51
53
|
|
52
|
-
|
54
|
+
case response
|
55
|
+
when Net::HTTPSuccess
|
56
|
+
break
|
57
|
+
when Net::HTTPRedirection
|
53
58
|
if redirects_followed < attributes.redirect_limit
|
54
59
|
uri = URI.parse(response["location"])
|
55
60
|
redirects_followed += 1
|
@@ -57,8 +62,12 @@ module Itamae
|
|
57
62
|
else
|
58
63
|
raise RedirectLimitExceeded
|
59
64
|
end
|
65
|
+
when Net::HTTPClientError
|
66
|
+
raise HTTPClientError
|
67
|
+
when Net::HTTPServerError
|
68
|
+
raise HTTPServerError
|
60
69
|
else
|
61
|
-
|
70
|
+
raise HTTPUnknownError
|
62
71
|
end
|
63
72
|
end
|
64
73
|
|
data/lib/itamae/resource/link.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
|
-
|
3
1
|
module Itamae
|
4
2
|
module Resource
|
5
3
|
class Package < Base
|
@@ -26,6 +24,8 @@ module Itamae
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def action_install(action_options)
|
27
|
+
return if !attributes.version && current.installed
|
28
|
+
|
29
29
|
unless run_specinfra(:check_package_is_installed, attributes.name, attributes.version)
|
30
30
|
run_specinfra(:install_package, attributes.name, attributes.version, attributes.options)
|
31
31
|
updated!
|
@@ -33,7 +33,7 @@ module Itamae
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def action_remove(action_options)
|
36
|
-
if
|
36
|
+
if current.installed
|
37
37
|
run_specinfra(:remove_package, attributes.name, attributes.options)
|
38
38
|
updated!
|
39
39
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
|
-
|
3
1
|
module Itamae
|
4
2
|
module Resource
|
5
3
|
class RemoteDirectory < Base
|
@@ -41,7 +39,7 @@ module Itamae
|
|
41
39
|
super
|
42
40
|
|
43
41
|
if current.exist
|
44
|
-
diff = run_command(["diff", "-u", attributes.path, @temppath], error: false)
|
42
|
+
diff = run_command(["diff", "-u", "-r", attributes.path, @temppath], error: false)
|
45
43
|
if diff.exit_status == 0
|
46
44
|
# no change
|
47
45
|
Itamae.logger.debug "directory content will not change"
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
1
|
require 'erb'
|
3
2
|
require 'tempfile'
|
4
3
|
|
@@ -38,9 +37,14 @@ module Itamae
|
|
38
37
|
|
39
38
|
def render_file(src)
|
40
39
|
template = ::File.read(src)
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
erb =
|
41
|
+
if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
|
42
|
+
ERB.new(template, trim_mode: '-')
|
43
|
+
else
|
44
|
+
ERB.new(template, nil, '-')
|
45
|
+
end
|
46
|
+
erb.filename = src
|
47
|
+
erb.result(binding)
|
44
48
|
end
|
45
49
|
|
46
50
|
def node
|
data/lib/itamae/resource/user.rb
CHANGED
data/lib/itamae/resource.rb
CHANGED
data/lib/itamae/runner.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'itamae'
|
2
1
|
require 'json'
|
3
2
|
require 'yaml'
|
4
3
|
|
@@ -31,7 +30,7 @@ module Itamae
|
|
31
30
|
prepare_handler
|
32
31
|
|
33
32
|
@node = create_node
|
34
|
-
@tmpdir =
|
33
|
+
@tmpdir = options[:tmp_dir] || '/tmp/itamae_tmp'
|
35
34
|
@children = RecipeChildren.new
|
36
35
|
@diff = false
|
37
36
|
|
@@ -99,11 +98,11 @@ module Itamae
|
|
99
98
|
unless @backend.run_command("which ohai", error: false).exit_status == 0
|
100
99
|
# install Ohai
|
101
100
|
Itamae.logger.info "Installing Chef package... (to use Ohai)"
|
102
|
-
@backend.run_command("curl -L https://
|
101
|
+
@backend.run_command("curl -L https://omnitruck.chef.io/install.sh | bash")
|
103
102
|
end
|
104
103
|
|
105
104
|
Itamae.logger.info "Loading node data via ohai..."
|
106
|
-
hash.merge!(JSON.parse(@backend.run_command("ohai").stdout))
|
105
|
+
hash.merge!(JSON.parse(@backend.run_command("ohai 2>/dev/null").stdout))
|
107
106
|
end
|
108
107
|
|
109
108
|
if @options[:node_json]
|
data/lib/itamae/version.rb
CHANGED
data/lib/itamae.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "itamae/version"
|
2
2
|
require "itamae/runner"
|
3
|
-
require "itamae/cli"
|
4
3
|
require "itamae/recipe"
|
5
4
|
require "itamae/resource"
|
6
5
|
require "itamae/handler"
|
@@ -13,6 +12,7 @@ require "itamae/notification"
|
|
13
12
|
require "itamae/definition"
|
14
13
|
require "itamae/ext"
|
15
14
|
require "itamae/generators"
|
15
|
+
require "itamae/mash"
|
16
16
|
|
17
17
|
module Itamae
|
18
18
|
# Your code goes here...
|
@@ -104,7 +104,7 @@ describe file('/tmp/http_request_headers.html') do
|
|
104
104
|
its(:content) { should match(/"User-Agent":\s*"Itamae"/) }
|
105
105
|
end
|
106
106
|
|
107
|
-
|
107
|
+
xdescribe file('/tmp/http_request_redirect.html') do
|
108
108
|
it { should be_file }
|
109
109
|
its(:content) { should match(/"from":\s*"itamae"/) }
|
110
110
|
end
|
@@ -119,34 +119,6 @@ describe file('/tmp/subscribes') do
|
|
119
119
|
its(:content) { should eq("2431") }
|
120
120
|
end
|
121
121
|
|
122
|
-
describe file('/tmp/cron_stopped') do
|
123
|
-
it { should be_file }
|
124
|
-
its(:content) do
|
125
|
-
expect(subject.content.lines.size).to eq 1
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
# FIXME: cron service is not running in docker...
|
130
|
-
#
|
131
|
-
# root@3450c6da6ea5:/# ps -C cron
|
132
|
-
# PID TTY TIME CMD
|
133
|
-
# root@3450c6da6ea5:/# service cron start
|
134
|
-
# Rather than invoking init scripts through /etc/init.d, use the service(8)
|
135
|
-
# utility, e.g. service cron start
|
136
|
-
#
|
137
|
-
# Since the script you are attempting to invoke has been converted to an
|
138
|
-
# Upstart job, you may also use the start(8) utility, e.g. start cron
|
139
|
-
# root@3450c6da6ea5:/# ps -C cron
|
140
|
-
# PID TTY TIME CMD
|
141
|
-
# root@3450c6da6ea5:/#
|
142
|
-
|
143
|
-
# describe file('/tmp/cron_running') do
|
144
|
-
# it { should be_file }
|
145
|
-
# its(:content) do
|
146
|
-
# expect(subject.content.lines.size).to eq 2
|
147
|
-
# end
|
148
|
-
# end
|
149
|
-
|
150
122
|
describe file('/tmp-link') do
|
151
123
|
it { should be_linked_to '/tmp' }
|
152
124
|
its(:content) do
|
@@ -206,15 +178,19 @@ describe command('gem list') do
|
|
206
178
|
end
|
207
179
|
|
208
180
|
describe command('gem list') do
|
209
|
-
its(:stdout) { should
|
181
|
+
its(:stdout) { should match(/^rake \(.*11.1.0.*\)/) }
|
210
182
|
end
|
211
183
|
|
212
184
|
describe command('gem list') do
|
213
185
|
its(:stdout) { should_not include('test-unit') }
|
214
186
|
end
|
215
187
|
|
216
|
-
describe command('
|
217
|
-
its(:
|
188
|
+
describe command('gem list') do
|
189
|
+
its(:stdout) { should include('ast (2.0.0)') }
|
190
|
+
end
|
191
|
+
|
192
|
+
describe command('ri AST') do
|
193
|
+
its(:stderr) { should eq("Nothing known about AST\n") }
|
218
194
|
end
|
219
195
|
|
220
196
|
describe file('/tmp/created_by_definition') do
|
@@ -357,3 +333,21 @@ describe file('/tmp/empty_file3') do
|
|
357
333
|
it { should be_file }
|
358
334
|
its(:content) { should eq "" }
|
359
335
|
end
|
336
|
+
|
337
|
+
describe file('/tmp/toplevel_module') do
|
338
|
+
it { should exist }
|
339
|
+
it { should be_file }
|
340
|
+
its(:content) { should eq "helper" }
|
341
|
+
end
|
342
|
+
|
343
|
+
describe file('/tmp/local_variables') do
|
344
|
+
it { should exist }
|
345
|
+
it { should be_file }
|
346
|
+
its(:content) { should eq "[]" }
|
347
|
+
end
|
348
|
+
|
349
|
+
describe file('/tmp/instance_variables') do
|
350
|
+
it { should exist }
|
351
|
+
it { should be_file }
|
352
|
+
its(:content) { should eq "[:@recipe]" } # backward compatibility
|
353
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe file('/tmp/cron_stopped') do
|
4
|
+
it { should be_file }
|
5
|
+
its(:content) do
|
6
|
+
expect(subject.content.lines.size).to eq 1
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# FIXME: cron service is not running in docker...
|
11
|
+
#
|
12
|
+
# root@3450c6da6ea5:/# ps -C cron
|
13
|
+
# PID TTY TIME CMD
|
14
|
+
# root@3450c6da6ea5:/# service cron start
|
15
|
+
# Rather than invoking init scripts through /etc/init.d, use the service(8)
|
16
|
+
# utility, e.g. service cron start
|
17
|
+
#
|
18
|
+
# Since the script you are attempting to invoke has been converted to an
|
19
|
+
# Upstart job, you may also use the start(8) utility, e.g. start cron
|
20
|
+
# root@3450c6da6ea5:/# ps -C cron
|
21
|
+
# PID TTY TIME CMD
|
22
|
+
# root@3450c6da6ea5:/#
|
23
|
+
|
24
|
+
# describe file('/tmp/cron_running') do
|
25
|
+
# it { should be_file }
|
26
|
+
# its(:content) do
|
27
|
+
# expect(subject.content.lines.size).to eq 2
|
28
|
+
# end
|
29
|
+
# end
|