producer-core 0.6.1 → 0.6.2
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 +5 -5
- data/README.md +12 -144
- data/bin/producer +1 -1
- data/lib/producer/core/action.rb +4 -3
- data/lib/producer/core/actions/file_writer.rb +1 -7
- data/lib/producer/core/cli.rb +19 -71
- data/lib/producer/core/env.rb +7 -23
- data/lib/producer/core/errors.rb +11 -9
- data/lib/producer/core/remote.rb +7 -1
- data/lib/producer/core/task.rb +0 -1
- data/lib/producer/core/testing/cucumber/etc_steps.rb +1 -1
- data/lib/producer/core/testing/cucumber/recipe_steps.rb +18 -19
- data/lib/producer/core/testing/cucumber/remote_steps.rb +9 -15
- data/lib/producer/core/testing/cucumber/ssh_steps.rb +9 -1
- data/lib/producer/core/testing/cucumber.rb +1 -29
- data/lib/producer/core/version.rb +1 -1
- data/lib/producer/core.rb +1 -1
- metadata +25 -42
- data/lib/producer/core/actions/yaml_writer.rb +0 -22
- data/lib/producer/core/testing/aruba_program_wrapper.rb +0 -24
- data/lib/producer/core/testing/cucumber/execution_steps.rb +0 -3
- data/lib/producer/core/testing/cucumber/output_steps.rb +0 -47
- data/lib/producer/core/testing.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2cad65cc103070c2e168b124dec1d018d3a133cae0a6d8135766c321b1e62898
|
4
|
+
data.tar.gz: a1d7a87ac02475c992a3c448ddd0a1ca6c7b750d2a7d568bd846ec94911390e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 786dbe20ba244351fd32a7f05f2cba1ea947515cf090ea1d9274f55d28ca6bf92e3a8f1e45c091dc75ac69e461303e65c24fb39cc0612652edfc7a6822fcc3e0
|
7
|
+
data.tar.gz: 0c220841cab6fe26cb7261598a945d9b21d99fdb8469c1e3710533421347726d74b22e28c7262b1795393c186a82a980f8760d448fef6f1f5474e603d3a351bf
|
data/README.md
CHANGED
@@ -1,47 +1,23 @@
|
|
1
1
|
producer
|
2
2
|
========
|
3
3
|
|
4
|
-
|
5
|
-
DSL to
|
6
|
-
|
7
|
-
[![Version ][badge-version-img]][badge-version-uri]
|
8
|
-
[![Build status ][badge-build-img]][badge-build-uri]
|
9
|
-
[![Code Climate ][badge-cclimate-img]][badge-cclimate-uri]
|
4
|
+
producer-core is a software configuration management tool providing
|
5
|
+
a DSL to describe infrastructure as code. It helps automating software
|
6
|
+
deployment, configuration and management.
|
10
7
|
|
11
8
|
|
12
9
|
Getting started
|
13
10
|
---------------
|
14
11
|
|
15
|
-
### Installation (requires ruby
|
16
|
-
|
17
|
-
$ gem install producer-core
|
12
|
+
### Installation (requires ruby and rubygems)
|
18
13
|
|
19
|
-
|
20
|
-
### Simple recipe
|
21
|
-
|
22
|
-
Recipes are composed by tasks and a task includes actions. Here we
|
23
|
-
use the `echo` action, which output the given string to standard
|
24
|
-
output. All the power of the Ruby language is available.
|
25
|
-
|
26
|
-
```ruby
|
27
|
-
hello_message = 'hello world!'
|
28
|
-
|
29
|
-
task :hello_world do
|
30
|
-
echo hello_message
|
31
|
-
echo hello_message.upcase
|
32
|
-
end
|
33
|
-
```
|
34
|
-
|
35
|
-
$ producer simple_recipe.rb
|
36
|
-
hello world!
|
37
|
-
HELLO WORLD!
|
14
|
+
gem install producer-core
|
38
15
|
|
39
16
|
|
40
17
|
### Shell command execution on remote host
|
41
18
|
|
42
|
-
The `sh` action will execute a shell command
|
43
|
-
|
44
|
-
CLI option `-t`.
|
19
|
+
The `sh` action will execute a shell command on the targeted remote
|
20
|
+
host. The remote host can be specified with the CLI option `-t`.
|
45
21
|
|
46
22
|
```ruby
|
47
23
|
task :show_zsh_pkg do
|
@@ -49,7 +25,7 @@ task :show_zsh_pkg do
|
|
49
25
|
end
|
50
26
|
```
|
51
27
|
|
52
|
-
|
28
|
+
% producer -t localhost show_zsh_pkg.rb
|
53
29
|
zsh-5.0.7 The Z shell
|
54
30
|
|
55
31
|
When execution fails, recipe processing is stopped and the action
|
@@ -62,9 +38,9 @@ task :sh_fail do
|
|
62
38
|
end
|
63
39
|
```
|
64
40
|
|
65
|
-
|
41
|
+
% producer -t localhost sh_fail.rb
|
66
42
|
RemoteCommandExecutionError: false
|
67
|
-
|
43
|
+
%
|
68
44
|
|
69
45
|
Only the first action is applied.
|
70
46
|
|
@@ -74,8 +50,6 @@ end
|
|
74
50
|
A task can be bound to a condition: when the condition fails actions
|
75
51
|
are skipped, otherwise actions are applied as usual.
|
76
52
|
|
77
|
-
This condition can be a simple ruby expression :
|
78
|
-
|
79
53
|
```ruby
|
80
54
|
task :condition_pass do
|
81
55
|
condition { true }
|
@@ -88,16 +62,13 @@ task :condition_fail do
|
|
88
62
|
end
|
89
63
|
```
|
90
64
|
|
65
|
+
|
91
66
|
#### Built-in tests
|
92
67
|
|
93
68
|
Specific test keywords are also available in the condition block
|
94
69
|
context, `producer-core` ships with a few common tests,
|
95
70
|
`producer-stdlib` provides more, and custom tests can be defined.
|
96
71
|
|
97
|
-
Here we use the `sh` condition keyword which will pass when the
|
98
|
-
execution of the given shell command succeed, and fail when the
|
99
|
-
execution fails.
|
100
|
-
|
101
72
|
```ruby
|
102
73
|
task :condition_sh_pass do
|
103
74
|
condition { sh 'true' }
|
@@ -128,105 +99,11 @@ task :main_task do
|
|
128
99
|
end
|
129
100
|
end
|
130
101
|
```
|
131
|
-
|
102
|
+
% producer nested_tasks.rb
|
132
103
|
do foo
|
133
104
|
do bar
|
134
105
|
|
135
106
|
|
136
|
-
Usage
|
137
|
-
-----
|
138
|
-
|
139
|
-
Usage: producer [options] [recipes] [-- recipe_arguments...]
|
140
|
-
|
141
|
-
options:
|
142
|
-
-v, --verbose enable verbose mode
|
143
|
-
-d, --debug enable debug mode
|
144
|
-
-n, --dry-run enable dry run mode
|
145
|
-
-t, --target HOST target host
|
146
|
-
|
147
|
-
|
148
|
-
Actions
|
149
|
-
-------
|
150
|
-
|
151
|
-
See:
|
152
|
-
https://github.com/tjouan/producer-core/tree/master/features/actions
|
153
|
-
|
154
|
-
|
155
|
-
Tests
|
156
|
-
-----
|
157
|
-
|
158
|
-
See:
|
159
|
-
https://github.com/tjouan/producer-core/tree/master/features/tests
|
160
|
-
|
161
|
-
|
162
|
-
Templates
|
163
|
-
---------
|
164
|
-
|
165
|
-
The following example can setup jails on a FreeBSD host.
|
166
|
-
|
167
|
-
In `templates/freebsd/jail.conf.erb`:
|
168
|
-
|
169
|
-
```erb
|
170
|
-
exec.start = "/bin/sh /etc/rc";
|
171
|
-
exec.stop = "/bin/sh /etc/rc.shutdown";
|
172
|
-
exec.clean;
|
173
|
-
mount.devfs;
|
174
|
-
allow.chflags;
|
175
|
-
|
176
|
-
path = "/var/jails/$name";
|
177
|
-
|
178
|
-
<% @jails.each do |jail| -%>
|
179
|
-
<%= jail[:name] %> {
|
180
|
-
interface "<%= @if %>";
|
181
|
-
ip4.addr = <%= jail[:addr4] %>;
|
182
|
-
}
|
183
|
-
<% end -%>
|
184
|
-
```
|
185
|
-
|
186
|
-
Simple usage:
|
187
|
-
|
188
|
-
```ruby
|
189
|
-
INTERFACE = 're0'.freeze
|
190
|
-
JAILS = [{
|
191
|
-
name: 'freebsd-10r1',
|
192
|
-
src: true,
|
193
|
-
addr4: '10.0.0.1'
|
194
|
-
}].freeze
|
195
|
-
|
196
|
-
task :jails_conf do
|
197
|
-
conf = template 'freebsd/jail.conf', if: INTERFACE, jails: JAILS
|
198
|
-
file_write_once '/etc/jail.conf', conf
|
199
|
-
end
|
200
|
-
```
|
201
|
-
|
202
|
-
|
203
|
-
Macros
|
204
|
-
------
|
205
|
-
|
206
|
-
FIXME
|
207
|
-
|
208
|
-
|
209
|
-
Test macros
|
210
|
-
-----------
|
211
|
-
|
212
|
-
FIXME
|
213
|
-
|
214
|
-
|
215
|
-
Macro composition
|
216
|
-
-----------------
|
217
|
-
|
218
|
-
FIXME
|
219
|
-
|
220
|
-
|
221
|
-
Background
|
222
|
-
----------
|
223
|
-
|
224
|
-
producer started as a collection of heterogeneous scripts (Ruby,
|
225
|
-
POSIX shell, Perl…) in the late '90s. I wanted to experiment with the
|
226
|
-
design and usage of Domain Specific Languages in Ruby, and refactor
|
227
|
-
all my scripts as "recipes" in a common language.
|
228
|
-
|
229
|
-
|
230
107
|
Similar or related code and tools
|
231
108
|
---------------------------------
|
232
109
|
|
@@ -272,12 +149,3 @@ Similar or related code and tools
|
|
272
149
|
* https://github.com/auxesis/cucumber-nagios (Cucumber, Net::SSH,
|
273
150
|
Webrat)
|
274
151
|
* http://larsyencken.github.io/marelle/ (Prolog, babushka inspired)
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
[badge-version-img]: https://img.shields.io/gem/v/producer-core.svg?style=flat-square
|
279
|
-
[badge-version-uri]: https://rubygems.org/gems/producer-core
|
280
|
-
[badge-build-img]: https://img.shields.io/travis/tjouan/producer-core/master.svg?style=flat-square
|
281
|
-
[badge-build-uri]: https://travis-ci.org/tjouan/producer-core
|
282
|
-
[badge-cclimate-img]: https://img.shields.io/codeclimate/github/tjouan/producer-core.svg?style=flat-square
|
283
|
-
[badge-cclimate-uri]: https://codeclimate.com/github/tjouan/producer-core
|
data/bin/producer
CHANGED
data/lib/producer/core/action.rb
CHANGED
@@ -4,15 +4,16 @@ module Producer
|
|
4
4
|
INSPECT_ARGUMENTS_SUM_LEN = 68
|
5
5
|
|
6
6
|
extend Forwardable
|
7
|
-
def_delegators :@env, :input, :output, :
|
7
|
+
def_delegators :@env, :input, :output, :remote
|
8
|
+
def_delegator :@env, :output_error, :error_output
|
8
9
|
def_delegators :remote, :fs
|
9
10
|
|
10
11
|
attr_reader :env, :arguments, :options
|
11
12
|
|
12
|
-
def initialize env, *args
|
13
|
+
def initialize env, *args
|
13
14
|
@env = env
|
14
15
|
@arguments = args
|
15
|
-
@options =
|
16
|
+
@options = @arguments[-1].kind_of?(Hash) ? @arguments.pop : {}
|
16
17
|
setup if respond_to? :setup
|
17
18
|
end
|
18
19
|
|
@@ -3,7 +3,7 @@ module Producer
|
|
3
3
|
module Actions
|
4
4
|
class FileWriter < Action
|
5
5
|
def setup
|
6
|
-
check_arguments_size!
|
6
|
+
check_arguments_size! 2
|
7
7
|
@path, @content = arguments
|
8
8
|
convert_options mode: :permissions, user: :owner
|
9
9
|
end
|
@@ -16,12 +16,6 @@ module Producer
|
|
16
16
|
fs.file_write @path, @content
|
17
17
|
fs.setstat @path, options unless options.empty?
|
18
18
|
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def arguments_size
|
23
|
-
2
|
24
|
-
end
|
25
19
|
end
|
26
20
|
end
|
27
21
|
end
|
data/lib/producer/core/cli.rb
CHANGED
@@ -1,106 +1,54 @@
|
|
1
1
|
module Producer
|
2
2
|
module Core
|
3
|
-
class CLI
|
3
|
+
class CLI < Baf::CLI
|
4
4
|
ArgumentError = Class.new(ArgumentError)
|
5
5
|
|
6
6
|
USAGE =
|
7
7
|
"Usage: #{File.basename $0} [options] [recipes] [-- recipe_argument...]"
|
8
8
|
.freeze
|
9
9
|
|
10
|
-
EX_USAGE = 64
|
11
|
-
EX_SOFTWARE = 70
|
12
|
-
|
13
10
|
ARGUMENTS_SEPARATOR = '--'.freeze
|
14
11
|
|
15
|
-
ENV_VERBOSE_KEY = 'PRODUCER_VERBOSE'.freeze
|
16
|
-
ENV_DEBUG_KEY = 'PRODUCER_DEBUG'.freeze
|
17
|
-
ENV_DRYRUN_KEY = 'PRODUCER_DRYRUN'.freeze
|
18
|
-
|
19
12
|
class << self
|
20
|
-
def
|
21
|
-
|
22
|
-
cli.parse_arguments!
|
23
|
-
cli.run
|
24
|
-
rescue ArgumentError => e
|
25
|
-
stderr.puts e.message
|
26
|
-
exit EX_USAGE
|
27
|
-
rescue StandardError => e
|
28
|
-
stderr.puts ErrorFormatter.new(debug: cli.env.debug?).format e
|
29
|
-
exit EX_SOFTWARE
|
13
|
+
def handle_error env, ex
|
14
|
+
env.puts_error ErrorFormatter.new(debug: env.debug?).format ex
|
30
15
|
end
|
31
16
|
end
|
32
17
|
|
33
|
-
|
18
|
+
def setup
|
19
|
+
banner USAGE
|
34
20
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@stdin = stdin
|
39
|
-
@stdout = stdout
|
40
|
-
@stderr = stderr
|
41
|
-
@env = build_env
|
21
|
+
flag_verbose
|
22
|
+
flag_debug
|
23
|
+
flag_version Producer::Core::VERSION
|
42
24
|
|
43
|
-
|
25
|
+
flag :n, :dry_run, 'enable dry run mode'
|
26
|
+
option :t, :target, 'HOST', 'target host'
|
44
27
|
end
|
45
28
|
|
46
29
|
def parse_arguments!
|
47
|
-
if
|
48
|
-
@arguments,
|
30
|
+
if arguments.include? ARGUMENTS_SEPARATOR
|
31
|
+
@arguments, env.recipe_argv = split_arguments_lists arguments
|
49
32
|
end
|
50
|
-
|
51
|
-
|
52
|
-
rescue OptionParser::InvalidOption
|
53
|
-
raise ArgumentError, option_parser
|
33
|
+
super
|
34
|
+
usage! if arguments.empty?
|
54
35
|
end
|
55
36
|
|
56
|
-
def run worker: Worker.new(
|
37
|
+
def run worker: Worker.new(env)
|
57
38
|
evaluate_recipes.each { |recipe| worker.process recipe.tasks }
|
58
39
|
ensure
|
59
|
-
|
40
|
+
env.cleanup
|
60
41
|
end
|
61
42
|
|
62
43
|
def evaluate_recipes
|
63
|
-
|
44
|
+
arguments.map { |e| Recipe::FileEvaluator.evaluate(e, env) }
|
64
45
|
end
|
65
46
|
|
66
47
|
private
|
67
48
|
|
68
|
-
def build_env
|
69
|
-
Env.new(input: @stdin, output: @stdout, error_output: @stderr)
|
70
|
-
end
|
71
|
-
|
72
|
-
def configure_environment! environment
|
73
|
-
@env.verbose = true if environment.key? ENV_VERBOSE_KEY
|
74
|
-
@env.debug = true if environment.key? ENV_DEBUG_KEY
|
75
|
-
@env.dry_run = true if environment.key? ENV_DRYRUN_KEY
|
76
|
-
end
|
77
|
-
|
78
49
|
def split_arguments_lists arguments
|
79
|
-
arguments
|
80
|
-
|
81
|
-
.reject { |a, _| a }
|
82
|
-
.map &:last
|
83
|
-
end
|
84
|
-
|
85
|
-
def option_parser
|
86
|
-
OptionParser.new do |opts|
|
87
|
-
opts.banner = USAGE
|
88
|
-
opts.separator ''
|
89
|
-
opts.separator 'options:'
|
90
|
-
|
91
|
-
option_parser_add_boolean_options opts
|
92
|
-
opts.on '-t', '--target HOST', 'target host' do |e|
|
93
|
-
env.target = e
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def option_parser_add_boolean_options opts
|
99
|
-
{ v: 'verbose', d: 'debug', n: 'dry run' }.each do |k, v|
|
100
|
-
opts.on "-#{k}", "--#{v.tr ' ', '-'}", "enable #{v} mode" do
|
101
|
-
env.send "#{v.tr ' ', '_'}=", true
|
102
|
-
end
|
103
|
-
end
|
50
|
+
head, tail = arguments.slice_after(ARGUMENTS_SEPARATOR).to_a
|
51
|
+
[head[0..-2], tail]
|
104
52
|
end
|
105
53
|
end
|
106
54
|
end
|
data/lib/producer/core/env.rb
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
module Producer
|
2
2
|
module Core
|
3
|
-
class Env
|
3
|
+
class Env < Baf::Env
|
4
4
|
extend Forwardable
|
5
5
|
def_delegators :@registry, :[]=, :key?
|
6
6
|
|
7
|
-
attr_reader
|
8
|
-
attr_accessor :
|
7
|
+
attr_reader :input, :output, :output_error, :registry, :logger
|
8
|
+
attr_accessor :recipe_argv
|
9
9
|
|
10
|
-
def initialize
|
11
|
-
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@output = output
|
15
|
-
@error_output = error_output
|
16
|
-
@remote = remote
|
17
|
-
@registry = registry
|
10
|
+
def initialize remote: nil, registry: {}, **opts
|
11
|
+
super **opts
|
12
|
+
@remote = remote
|
13
|
+
@registry = registry
|
18
14
|
end
|
19
15
|
|
20
16
|
def remote
|
@@ -39,18 +35,6 @@ module Producer
|
|
39
35
|
logger.send severity, message
|
40
36
|
end
|
41
37
|
|
42
|
-
def verbose?
|
43
|
-
@verbose
|
44
|
-
end
|
45
|
-
|
46
|
-
def debug?
|
47
|
-
@debug
|
48
|
-
end
|
49
|
-
|
50
|
-
def dry_run?
|
51
|
-
@dry_run
|
52
|
-
end
|
53
|
-
|
54
38
|
def cleanup
|
55
39
|
remote.cleanup
|
56
40
|
end
|
data/lib/producer/core/errors.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
module Producer
|
2
2
|
module Core
|
3
|
-
Error
|
4
|
-
RuntimeError
|
3
|
+
Error = Class.new StandardError
|
4
|
+
RuntimeError = Class.new RuntimeError
|
5
5
|
|
6
|
-
ArgumentError
|
7
|
-
ConditionNotMetError
|
8
|
-
RecipeEvaluationError
|
9
|
-
|
10
|
-
|
11
|
-
RemoteInvalidError
|
12
|
-
|
6
|
+
ArgumentError = Class.new Error
|
7
|
+
ConditionNotMetError = Class.new Error
|
8
|
+
RecipeEvaluationError = Class.new RuntimeError
|
9
|
+
RegistryKeyError = Class.new RuntimeError
|
10
|
+
RemoteCommandExecutionError = Class.new RuntimeError
|
11
|
+
RemoteInvalidError = Class.new ArgumentError
|
12
|
+
RemoteMismatchError = Class.new RuntimeError
|
13
|
+
RemoteUnknownError = Class.new RuntimeError
|
14
|
+
TemplateMissingError = Class.new RuntimeError
|
13
15
|
end
|
14
16
|
end
|
data/lib/producer/core/remote.rb
CHANGED
@@ -11,7 +11,13 @@ module Producer
|
|
11
11
|
def session
|
12
12
|
@session ||= begin
|
13
13
|
check_hostname!
|
14
|
-
Net::SSH.start
|
14
|
+
Net::SSH.start @hostname, user_name, verify_host_key: :always
|
15
|
+
rescue Net::SSH::HostKeyError => e
|
16
|
+
error = '`%s\' authenticity can\'t be established' % hostname
|
17
|
+
case e
|
18
|
+
when Net::SSH::HostKeyUnknown then fail RemoteUnknownError, error
|
19
|
+
when Net::SSH::HostKeyMismatch then fail RemoteMismatchError, error
|
20
|
+
end
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
data/lib/producer/core/task.rb
CHANGED
@@ -28,7 +28,6 @@ module Producer
|
|
28
28
|
define_action :file_append, Actions::FileAppend
|
29
29
|
define_action :file_replace_content, Actions::FileReplaceContent
|
30
30
|
define_action :file_write, Actions::FileWriter
|
31
|
-
define_action :yaml_write, Actions::YAMLWriter
|
32
31
|
|
33
32
|
attr_reader :name, :actions, :condition
|
34
33
|
|
@@ -1,34 +1,33 @@
|
|
1
|
-
def run_recipe remote: false, options: nil, check: false, rargv: nil
|
2
|
-
command = %w[
|
1
|
+
def run_recipe remote: false, options: nil, check: false, rargv: nil, wait: true
|
2
|
+
command = $_baf[:program] + %w[recipe.rb]
|
3
3
|
case remote
|
4
4
|
when :unknown then command += %w[-t unknown_host.test]
|
5
5
|
when true then command += %w[-t some_host.test]
|
6
6
|
end
|
7
|
-
command
|
8
|
-
command
|
7
|
+
command += options if options
|
8
|
+
command += %w[--] + rargv if rargv
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
10
|
+
env_allow = Baf::Testing::ENV_WHITELIST + $_baf[:env_allow]
|
11
|
+
$_baf[:process] = Baf::Testing.run command, env_allow: env_allow, wait: wait
|
13
12
|
|
14
|
-
|
15
|
-
|
13
|
+
Baf::Testing.expect_ex $_baf[:process], 0 if check
|
14
|
+
expect($_baf[:process].output).to match /\ASocketError/ if remote == :unknown
|
16
15
|
end
|
17
16
|
|
18
17
|
Given /^a recipe with:$/ do |recipe_body|
|
19
|
-
write_file 'recipe.rb', recipe_body
|
18
|
+
Baf::Testing.write_file 'recipe.rb', recipe_body + $/
|
20
19
|
end
|
21
20
|
|
22
21
|
Given /^a recipe with an error$/ do
|
23
|
-
write_file 'recipe.rb', "fail 'some error'\n"
|
22
|
+
Baf::Testing.write_file 'recipe.rb', "fail 'some error'\n"
|
24
23
|
end
|
25
24
|
|
26
25
|
Given /^a recipe using a remote$/ do
|
27
|
-
write_file 'recipe.rb', "task(:some_task) { sh 'echo hello' }\n"
|
26
|
+
Baf::Testing.write_file 'recipe.rb', "task(:some_task) { sh 'echo hello' }\n"
|
28
27
|
end
|
29
28
|
|
30
29
|
Given /^a recipe named "([^"]+)" with:$/ do |recipe_path, recipe_body|
|
31
|
-
write_file recipe_path, recipe_body
|
30
|
+
Baf::Testing.write_file recipe_path, recipe_body
|
32
31
|
end
|
33
32
|
|
34
33
|
When /^I execute the recipe$/ do
|
@@ -44,11 +43,11 @@ When /^I execute the recipe on unknown remote target$/ do
|
|
44
43
|
end
|
45
44
|
|
46
45
|
When /^I execute the recipe with options? (-.+)$/ do |options|
|
47
|
-
run_recipe options: options
|
46
|
+
run_recipe options: options.split(' ')
|
48
47
|
end
|
49
48
|
|
50
49
|
When /^I execute the recipe on unknown remote target with options? (-.+)$/ do |options|
|
51
|
-
run_recipe remote: :unknown, options: options
|
50
|
+
run_recipe remote: :unknown, options: options.split(' ')
|
52
51
|
end
|
53
52
|
|
54
53
|
When /^I successfully execute the recipe$/ do
|
@@ -60,17 +59,17 @@ When /^I successfully execute the recipe on remote target$/ do
|
|
60
59
|
end
|
61
60
|
|
62
61
|
When /^I successfully execute the recipe on remote target with options? (-.+)$/ do |options|
|
63
|
-
run_recipe remote: true, options: options, check: true
|
62
|
+
run_recipe remote: true, options: options.split(' '), check: true
|
64
63
|
end
|
65
64
|
|
66
65
|
When /^I successfully execute the recipe with options? (-.+)$/ do |options|
|
67
|
-
run_recipe options: options, check: true
|
66
|
+
run_recipe options: options.split(' '), check: true
|
68
67
|
end
|
69
68
|
|
70
69
|
When /^I successfully execute the recipe with arguments "([^"]+)"$/ do |rargv|
|
71
|
-
run_recipe rargv: rargv, check: true
|
70
|
+
run_recipe rargv: rargv.split(' '), check: true
|
72
71
|
end
|
73
72
|
|
74
73
|
When /^I execute the recipe interactively$/ do
|
75
|
-
|
74
|
+
run_recipe remote: true, wait: false
|
76
75
|
end
|
@@ -1,43 +1,37 @@
|
|
1
1
|
def stat_mode path
|
2
|
-
|
3
|
-
('%o' % [File::Stat.new(path).mode])[-4, 4]
|
4
|
-
end
|
2
|
+
('%o' % [File::Stat.new(path).mode])[-4, 4]
|
5
3
|
end
|
6
4
|
|
7
5
|
Given /^a remote directory named "([^"]+)"$/ do |path|
|
8
|
-
|
6
|
+
FileUtils.mkdir_p path
|
9
7
|
end
|
10
8
|
|
11
9
|
Given /^a remote file named "([^"]+)"$/ do |file_name|
|
12
|
-
write_file file_name, ''
|
10
|
+
Baf::Testing.write_file file_name, ''
|
13
11
|
end
|
14
12
|
|
15
13
|
Given /^a remote file named "([^"]+)" with "([^"]+)"$/ do |file_name, content|
|
16
|
-
write_file file_name, content
|
14
|
+
Baf::Testing.write_file file_name, content
|
17
15
|
end
|
18
16
|
|
19
17
|
Then /^the remote directory "([^"]+)" must exist$/ do |path|
|
20
|
-
expect(path).to
|
18
|
+
expect(Dir.exist? path).to be true
|
21
19
|
end
|
22
20
|
|
23
21
|
Then /^the remote file "([^"]+)" must exist$/ do |path|
|
24
|
-
|
22
|
+
expect(File.file? path).to be true
|
25
23
|
end
|
26
24
|
|
27
25
|
Then /^the remote file "([^"]+)" must contain "([^"]+)"$/ do |path, content|
|
28
|
-
expect(path).to
|
26
|
+
expect(IO.read path).to include content
|
29
27
|
end
|
30
28
|
|
31
29
|
Then /^the remote file "([^"]+)" must contain exactly "([^"]+)"$/ do |path, content|
|
32
|
-
expect(path).to
|
30
|
+
expect(IO.read path).to include content
|
33
31
|
end
|
34
32
|
|
35
33
|
Then /^the remote file "([^"]+)" must contain exactly:$/ do |path, content|
|
36
|
-
expect(path).to
|
37
|
-
end
|
38
|
-
|
39
|
-
Then /^the remote file "([^"]+)" must match \/([^\/]+)\/$/ do |path, pattern|
|
40
|
-
expect(path).to have_file_content /#{pattern}/
|
34
|
+
expect(IO.read path).to eq content
|
41
35
|
end
|
42
36
|
|
43
37
|
Then /^the remote file "([^"]+)" must have (\d+) mode$/ do |path, mode|
|
@@ -1,3 +1,11 @@
|
|
1
|
+
Given /^SSH known hosts:$/ do |db|
|
2
|
+
Baf::Testing.write_file '.ssh/known_hosts', db
|
3
|
+
end
|
4
|
+
|
1
5
|
Given /^an SSH config with:$/ do |config|
|
2
|
-
write_file '.ssh/config', config
|
6
|
+
Baf::Testing.write_file '.ssh/config', config
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^no SSH known hosts$/ do
|
10
|
+
Baf::Testing.write_file '.ssh/known_hosts', ''
|
3
11
|
end
|
@@ -1,35 +1,7 @@
|
|
1
|
-
require '
|
2
|
-
require 'aruba/in_process'
|
1
|
+
require 'cucumber/sshd/cucumber'
|
3
2
|
|
4
3
|
require 'producer/core'
|
5
|
-
require 'producer/core/testing/aruba_program_wrapper'
|
6
4
|
require 'producer/core/testing/cucumber/etc_steps'
|
7
|
-
require 'producer/core/testing/cucumber/execution_steps'
|
8
|
-
require 'producer/core/testing/cucumber/output_steps'
|
9
5
|
require 'producer/core/testing/cucumber/recipe_steps'
|
10
6
|
require 'producer/core/testing/cucumber/remote_steps'
|
11
7
|
require 'producer/core/testing/cucumber/ssh_steps'
|
12
|
-
|
13
|
-
# Raise aruba default timeout so test suite can run on a slow machine.
|
14
|
-
Before do
|
15
|
-
@aruba_timeout_seconds = 8
|
16
|
-
end
|
17
|
-
|
18
|
-
# Use aruba "in process" optimization only for scenarios not tagged @exec.
|
19
|
-
# We need a real process in a few cases: real program name, interactive usage…
|
20
|
-
Before('@exec') do
|
21
|
-
aruba.config.command_launcher = :spawn
|
22
|
-
end
|
23
|
-
|
24
|
-
Before('~@exec') do
|
25
|
-
aruba.config.command_launcher = :in_process
|
26
|
-
aruba.config.main_class = Producer::Core::Testing::ArubaProgramWrapper
|
27
|
-
end
|
28
|
-
|
29
|
-
# Enable cucumber-sshd "fast" mode (persists sshd across scenarios), and
|
30
|
-
# register hooks for @sshd tagged scenarios.
|
31
|
-
Before do
|
32
|
-
@_sshd_fast = true
|
33
|
-
@_sshd_wait_ready = true if ENV.key? 'TRAVIS'
|
34
|
-
end
|
35
|
-
require 'cucumber/sshd/cucumber'
|
data/lib/producer/core.rb
CHANGED
@@ -5,6 +5,7 @@ require 'optparse'
|
|
5
5
|
require 'pathname'
|
6
6
|
require 'yaml'
|
7
7
|
|
8
|
+
require 'baf/cli'
|
8
9
|
require 'net/ssh'
|
9
10
|
require 'net/sftp'
|
10
11
|
|
@@ -16,7 +17,6 @@ require 'producer/core/actions/mkdir'
|
|
16
17
|
require 'producer/core/actions/file_append'
|
17
18
|
require 'producer/core/actions/file_replace_content'
|
18
19
|
require 'producer/core/actions/file_writer'
|
19
|
-
require 'producer/core/actions/yaml_writer'
|
20
20
|
|
21
21
|
# condition tests
|
22
22
|
require 'producer/core/test'
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: producer-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thibault Jouan
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ssh
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 4.2.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 4.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: net-sftp
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,25 +39,19 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: baf
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0.
|
48
|
-
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: '0.9'
|
51
|
-
type: :development
|
47
|
+
version: '0.15'
|
48
|
+
type: :runtime
|
52
49
|
prerelease: false
|
53
50
|
version_requirements: !ruby/object:Gem::Requirement
|
54
51
|
requirements:
|
55
52
|
- - "~>"
|
56
53
|
- !ruby/object:Gem::Version
|
57
|
-
version: '0.
|
58
|
-
- - "<"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '0.9'
|
54
|
+
version: '0.15'
|
61
55
|
- !ruby/object:Gem::Dependency
|
62
56
|
name: cucumber
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,34 +72,28 @@ dependencies:
|
|
78
72
|
requirements:
|
79
73
|
- - "~>"
|
80
74
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
82
|
-
- - ">="
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
version: 1.1.1
|
75
|
+
version: '2.0'
|
85
76
|
type: :development
|
86
77
|
prerelease: false
|
87
78
|
version_requirements: !ruby/object:Gem::Requirement
|
88
79
|
requirements:
|
89
80
|
- - "~>"
|
90
81
|
- !ruby/object:Gem::Version
|
91
|
-
version: '
|
92
|
-
- - ">="
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: 1.1.1
|
82
|
+
version: '2.0'
|
95
83
|
- !ruby/object:Gem::Dependency
|
96
84
|
name: rake
|
97
85
|
requirement: !ruby/object:Gem::Requirement
|
98
86
|
requirements:
|
99
|
-
- - "
|
87
|
+
- - ">="
|
100
88
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
89
|
+
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
93
|
requirements:
|
106
|
-
- - "
|
94
|
+
- - ">="
|
107
95
|
- !ruby/object:Gem::Version
|
108
|
-
version: '
|
96
|
+
version: '0'
|
109
97
|
- !ruby/object:Gem::Dependency
|
110
98
|
name: rspec
|
111
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,9 +108,10 @@ dependencies:
|
|
120
108
|
- - "~>"
|
121
109
|
- !ruby/object:Gem::Version
|
122
110
|
version: '3.1'
|
123
|
-
description: |
|
124
|
-
|
125
|
-
|
111
|
+
description: |
|
112
|
+
producer-core is a software configuration management tool providing a DSL
|
113
|
+
to describe infrastructure as code.
|
114
|
+
It helps automating software deployment, configuration and management.
|
126
115
|
email: tj@a13.fr
|
127
116
|
executables:
|
128
117
|
- producer
|
@@ -140,7 +129,6 @@ files:
|
|
140
129
|
- lib/producer/core/actions/file_writer.rb
|
141
130
|
- lib/producer/core/actions/mkdir.rb
|
142
131
|
- lib/producer/core/actions/shell_command.rb
|
143
|
-
- lib/producer/core/actions/yaml_writer.rb
|
144
132
|
- lib/producer/core/cli.rb
|
145
133
|
- lib/producer/core/condition.rb
|
146
134
|
- lib/producer/core/env.rb
|
@@ -159,12 +147,8 @@ files:
|
|
159
147
|
- lib/producer/core/template/raw_renderer.rb
|
160
148
|
- lib/producer/core/template/yaml_renderer.rb
|
161
149
|
- lib/producer/core/test.rb
|
162
|
-
- lib/producer/core/testing.rb
|
163
|
-
- lib/producer/core/testing/aruba_program_wrapper.rb
|
164
150
|
- lib/producer/core/testing/cucumber.rb
|
165
151
|
- lib/producer/core/testing/cucumber/etc_steps.rb
|
166
|
-
- lib/producer/core/testing/cucumber/execution_steps.rb
|
167
|
-
- lib/producer/core/testing/cucumber/output_steps.rb
|
168
152
|
- lib/producer/core/testing/cucumber/recipe_steps.rb
|
169
153
|
- lib/producer/core/testing/cucumber/remote_steps.rb
|
170
154
|
- lib/producer/core/testing/cucumber/ssh_steps.rb
|
@@ -185,7 +169,7 @@ homepage: https://rubygems.org/gems/producer-core
|
|
185
169
|
licenses:
|
186
170
|
- BSD-3-Clause
|
187
171
|
metadata: {}
|
188
|
-
post_install_message:
|
172
|
+
post_install_message:
|
189
173
|
rdoc_options: []
|
190
174
|
require_paths:
|
191
175
|
- lib
|
@@ -200,9 +184,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
184
|
- !ruby/object:Gem::Version
|
201
185
|
version: '0'
|
202
186
|
requirements: []
|
203
|
-
|
204
|
-
|
205
|
-
signing_key:
|
187
|
+
rubygems_version: 3.3.17
|
188
|
+
signing_key:
|
206
189
|
specification_version: 4
|
207
|
-
summary:
|
190
|
+
summary: Software configuration management tool
|
208
191
|
test_files: []
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Producer
|
2
|
-
module Core
|
3
|
-
module Actions
|
4
|
-
class YAMLWriter < FileWriter
|
5
|
-
def setup
|
6
|
-
super
|
7
|
-
@content = options.delete(:data).to_yaml
|
8
|
-
end
|
9
|
-
|
10
|
-
def name
|
11
|
-
'yaml_write'
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def arguments_size
|
17
|
-
1
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Producer
|
2
|
-
module Core
|
3
|
-
module Testing
|
4
|
-
class ArubaProgramWrapper
|
5
|
-
def initialize argv, stdin = $stdin, stdout = $stdout, stderr = $stderr,
|
6
|
-
kernel = Kernel
|
7
|
-
@argv = argv
|
8
|
-
@stdin = stdin
|
9
|
-
@stdout = stdout
|
10
|
-
@stderr = stderr
|
11
|
-
@kernel = kernel
|
12
|
-
end
|
13
|
-
|
14
|
-
def execute!
|
15
|
-
Producer::Core::CLI.run!(
|
16
|
-
@argv.dup, stdin: @stdin, stdout: @stdout, stderr: @stderr
|
17
|
-
)
|
18
|
-
rescue SystemExit => e
|
19
|
-
@kernel.exit e.status
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
Then /^the output must contain exactly the usage$/ do
|
2
|
-
assert_exact_output <<-eoh, all_output
|
3
|
-
Usage: producer [options] [recipes] [-- recipe_argument...]
|
4
|
-
|
5
|
-
options:
|
6
|
-
-v, --verbose enable verbose mode
|
7
|
-
-d, --debug enable debug mode
|
8
|
-
-n, --dry-run enable dry run mode
|
9
|
-
-t, --target HOST target host
|
10
|
-
eoh
|
11
|
-
end
|
12
|
-
|
13
|
-
Then /^the output must match \/([^\/]+)\/$/ do |pattern|
|
14
|
-
assert_matching_output pattern, all_output
|
15
|
-
end
|
16
|
-
|
17
|
-
Then /^the output must contain "([^"]+)"$/ do |content|
|
18
|
-
assert_partial_output content, all_output
|
19
|
-
end
|
20
|
-
|
21
|
-
Then /^the output must contain:$/ do |content|
|
22
|
-
assert_partial_output content, all_output
|
23
|
-
end
|
24
|
-
|
25
|
-
Then /^the output must not contain "([^"]+)"$/ do |content|
|
26
|
-
assert_no_partial_output content, all_output
|
27
|
-
end
|
28
|
-
|
29
|
-
Then /^the output must contain exactly "([^"]+)"$/ do |content|
|
30
|
-
assert_exact_output content, all_output
|
31
|
-
end
|
32
|
-
|
33
|
-
Then /^the output must contain exactly:$/ do |content|
|
34
|
-
assert_exact_output content, all_output
|
35
|
-
end
|
36
|
-
|
37
|
-
Then /^the error output must contain exactly "([^"]+)"$/ do |content|
|
38
|
-
assert_exact_output content, all_stderr
|
39
|
-
end
|
40
|
-
|
41
|
-
Then /^the output must contain ruby lib directory$/ do
|
42
|
-
assert_partial_output RbConfig::CONFIG['rubylibdir'], all_output
|
43
|
-
end
|
44
|
-
|
45
|
-
Then /^the output must not contain ruby lib directory$/ do
|
46
|
-
assert_no_partial_output RbConfig::CONFIG['rubylibdir'], all_output
|
47
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
require 'producer/core/testing/mock_remote'
|