jisota 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +21 -0
- data/README.md +106 -2
- data/Rakefile +10 -0
- data/jisota.gemspec +1 -0
- data/lib/jisota.rb +4 -2
- data/lib/jisota/collection.rb +2 -4
- data/lib/jisota/command_script.rb +3 -2
- data/lib/jisota/composite_script.rb +2 -2
- data/lib/jisota/configuration.rb +3 -3
- data/lib/jisota/dsl_base.rb +12 -0
- data/lib/jisota/file_script.rb +107 -9
- data/lib/jisota/nil_output.rb +14 -0
- data/lib/jisota/{logger.rb → output.rb} +16 -35
- data/lib/jisota/package.rb +2 -2
- data/lib/jisota/package_script.rb +28 -20
- data/lib/jisota/packages/gem_install.rb +17 -0
- data/lib/jisota/packages/nginx_passenger.rb +34 -0
- data/lib/jisota/packages/ruby.rb +2 -2
- data/lib/jisota/param_parser.rb +30 -19
- data/lib/jisota/provisioner.rb +7 -3
- data/lib/jisota/script_block.rb +13 -14
- data/lib/jisota/script_context.rb +24 -0
- data/lib/jisota/server.rb +2 -1
- data/lib/jisota/ssh_engine.rb +6 -2
- data/lib/jisota/ssh_session.rb +10 -15
- data/lib/jisota/version.rb +1 -1
- data/package_files/nginx_passenger/nginx_service +65 -0
- data/spec/acceptance/ruby_passenger_nginx_spec.rb +24 -0
- data/spec/acceptance/simple_script_spec.rb +8 -24
- data/spec/acceptance/upload_blocks_spec.rb +34 -0
- data/spec/lib/jisota/collection_spec.rb +10 -0
- data/spec/lib/jisota/command_script_spec.rb +4 -3
- data/spec/lib/jisota/composite_script_spec.rb +8 -6
- data/spec/lib/jisota/configuration_spec.rb +1 -3
- data/spec/lib/jisota/dsl_base_spec.rb +37 -0
- data/spec/lib/jisota/file_script_spec.rb +63 -8
- data/spec/lib/jisota/output_spec.rb +84 -0
- data/spec/lib/jisota/package_script_spec.rb +20 -8
- data/spec/lib/jisota/package_spec.rb +2 -6
- data/spec/lib/jisota/packages/apt_spec.rb +7 -4
- data/spec/lib/jisota/packages/gem_install_spec.rb +18 -0
- data/spec/lib/jisota/packages/nginx_passenger_spec.rb +17 -0
- data/spec/lib/jisota/packages/ruby_spec.rb +6 -3
- data/spec/lib/jisota/param_parser_spec.rb +105 -0
- data/spec/lib/jisota/provisioner_spec.rb +30 -0
- data/spec/lib/jisota/role_spec.rb +1 -3
- data/spec/lib/jisota/script_block_spec.rb +7 -4
- data/spec/lib/jisota/ssh_engine_spec.rb +26 -0
- data/spec/lib/jisota/ssh_session_spec.rb +53 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/support/acceptance_helpers.rb +45 -0
- data/spec/test_files/nginx_default.conf +121 -0
- data/spec/vagrant/Vagrantfile +118 -0
- data/spec/vagrant/ssh_key +27 -0
- metadata +55 -7
- data/lib/jisota/upload_file.rb +0 -3
- data/spec/lib/jisota/logger_spec.rb +0 -34
@@ -4,7 +4,7 @@ module Jisota
|
|
4
4
|
#
|
5
5
|
# Will default to use STDOUT and STDERR, but that can be overwritten in the
|
6
6
|
# initializer
|
7
|
-
class
|
7
|
+
class Output
|
8
8
|
attr_accessor :stdout, :stderr, :verbose, :prefix, :indent_level
|
9
9
|
|
10
10
|
def initialize(options = {})
|
@@ -15,60 +15,41 @@ module Jisota
|
|
15
15
|
@indent_level = 0
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
prefixed_message "Uploading #{from} -> #{to}"
|
24
|
-
end
|
25
|
-
|
26
|
-
def package(package_script)
|
27
|
-
prefixed_message "Package #{package_script}"
|
28
|
-
end
|
29
|
-
|
30
|
-
def package_cancelled_by_verify(package_script)
|
31
|
-
prefixed_message "Package #{package_script} already installed"
|
32
|
-
end
|
33
|
-
|
34
|
-
def prefixed_message(message)
|
35
|
-
stdout.write(create_message(message, true, true))
|
18
|
+
def system_message(message, &block)
|
19
|
+
result = ["", prefix, " " * indent_level, message, "\n"].join
|
20
|
+
stdout.write(result)
|
21
|
+
stdout.flush
|
22
|
+
indent(&block) if block_given?
|
36
23
|
end
|
37
24
|
|
38
25
|
def info(message)
|
39
26
|
stdout.write(message) if verbose
|
27
|
+
stdout.flush
|
40
28
|
end
|
41
29
|
|
42
30
|
def warn(message)
|
43
31
|
stderr.write(message) if verbose
|
32
|
+
stderr.flush
|
44
33
|
end
|
45
34
|
|
46
35
|
def error(message)
|
47
36
|
stderr.write(message)
|
37
|
+
stderr.flush
|
48
38
|
end
|
49
39
|
|
50
40
|
def indent
|
51
41
|
self.indent_level += 1
|
42
|
+
if block_given?
|
43
|
+
begin
|
44
|
+
yield
|
45
|
+
ensure
|
46
|
+
outdent
|
47
|
+
end
|
48
|
+
end
|
52
49
|
end
|
53
50
|
|
54
51
|
def outdent
|
55
52
|
self.indent_level -= 1
|
56
53
|
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def create_message(message, newline, use_prefix)
|
61
|
-
result = ""
|
62
|
-
if use_prefix
|
63
|
-
result << prefix
|
64
|
-
else
|
65
|
-
result << " " * prefix.size
|
66
|
-
end
|
67
|
-
result << " " * indent_level
|
68
|
-
result << message
|
69
|
-
result << "\n" if newline
|
70
|
-
result
|
71
|
-
end
|
72
|
-
|
73
54
|
end
|
74
55
|
end
|
data/lib/jisota/package.rb
CHANGED
@@ -5,12 +5,12 @@ module Jisota
|
|
5
5
|
def initialize(name = nil, &block)
|
6
6
|
@params = []
|
7
7
|
@name = name
|
8
|
-
DSL.new(self).
|
8
|
+
DSL.new(self).evaluate(&block) if block_given?
|
9
9
|
end
|
10
10
|
|
11
11
|
alias_method :key, :name
|
12
12
|
|
13
|
-
class DSL
|
13
|
+
class DSL < DSLBase
|
14
14
|
def initialize(target)
|
15
15
|
@target = target
|
16
16
|
end
|
@@ -8,47 +8,55 @@ module Jisota
|
|
8
8
|
# If the package has a `verify_block`, that will be executed first. If the
|
9
9
|
# result of verify is success, the `run_block` will not be executed.
|
10
10
|
class PackageScript
|
11
|
-
attr_accessor :package, :args
|
11
|
+
attr_accessor :package, :args
|
12
12
|
|
13
|
-
def initialize(package, args = []
|
13
|
+
def initialize(package, args = [])
|
14
14
|
@package = package
|
15
15
|
@args = args
|
16
|
-
@packages = packages
|
17
16
|
end
|
18
17
|
|
19
|
-
def execute(
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def execute(context)
|
19
|
+
context.param_scope(parse_params) do
|
20
|
+
context.logger.system_message("Package #{self}") do
|
21
|
+
execute_verify_and_run(context)
|
22
|
+
end
|
23
|
+
end
|
25
24
|
end
|
26
25
|
|
27
26
|
def to_s
|
28
|
-
|
27
|
+
result = ""
|
28
|
+
result << package.name.to_s
|
29
|
+
if args.any?
|
30
|
+
result << " "
|
31
|
+
result << args.map(&:inspect).join(", ")
|
32
|
+
end
|
33
|
+
result
|
29
34
|
end
|
30
35
|
|
31
36
|
private
|
32
37
|
|
33
|
-
def
|
34
|
-
|
38
|
+
def parse_params
|
39
|
+
ParamParser.new(package.params, args).parse
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute_verify_and_run(context)
|
35
43
|
if package.verify_block
|
36
|
-
verify_script = package.verify_block.evaluate(
|
37
|
-
result = verify_script.execute(
|
44
|
+
verify_script = package.verify_block.evaluate(context)
|
45
|
+
result = verify_script.execute(context)
|
38
46
|
if result
|
39
|
-
logger.
|
47
|
+
context.logger.system_message("Package #{self} already installed")
|
40
48
|
true
|
41
49
|
else
|
42
|
-
execute_run(
|
50
|
+
execute_run(context)
|
43
51
|
end
|
44
52
|
else
|
45
|
-
execute_run(
|
53
|
+
execute_run(context)
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
def execute_run(
|
50
|
-
run_script = package.run_block.evaluate(
|
51
|
-
run_script.execute(
|
57
|
+
def execute_run(context)
|
58
|
+
run_script = package.run_block.evaluate(context)
|
59
|
+
run_script.execute(context)
|
52
60
|
end
|
53
61
|
end
|
54
62
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'jisota'
|
2
|
+
|
3
|
+
Jisota.global_config do
|
4
|
+
package :gem_install do
|
5
|
+
description "Installs a gem"
|
6
|
+
param :gem_name, required: true
|
7
|
+
param :sudo, default: true
|
8
|
+
|
9
|
+
run do
|
10
|
+
cmd "#{sudo ? "sudo " : ""}gem install #{gem_name} --no-document"
|
11
|
+
end
|
12
|
+
|
13
|
+
verify do
|
14
|
+
cmd "#{sudo ? "sudo " : ""}gem list #{gem_name} --installed"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'jisota'
|
2
|
+
|
3
|
+
Jisota.global_config do
|
4
|
+
package :nginx_passenger do
|
5
|
+
description "Install nginx with passenger module"
|
6
|
+
param :config_file, required: true
|
7
|
+
|
8
|
+
run do
|
9
|
+
gem_install :passenger
|
10
|
+
apt "libcurl4-openssl-dev"
|
11
|
+
nginx_passenger_install
|
12
|
+
|
13
|
+
upload from: config_file, to: '/opt/nginx/conf/nginx.conf' do
|
14
|
+
update { cmd "sudo service nginx restart" }
|
15
|
+
end
|
16
|
+
|
17
|
+
upload from: "package_files/nginx_passenger/nginx_service", to: "/etc/init.d/nginx" do
|
18
|
+
create { cmd 'sudo update-rc.d nginx defaults 99' }
|
19
|
+
end
|
20
|
+
|
21
|
+
nginx_passenger_start
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
package :nginx_passenger_install do
|
26
|
+
run { cmd 'sudo passenger-install-nginx-module --auto --auto-download --prefix=/opt/nginx' }
|
27
|
+
verify { cmd 'which /opt/nginx/sbin/nginx' }
|
28
|
+
end
|
29
|
+
|
30
|
+
package :nginx_passenger_start do
|
31
|
+
run { cmd "sudo service nginx start" }
|
32
|
+
verify { cmd "ps -C nginx" }
|
33
|
+
end
|
34
|
+
end
|
data/lib/jisota/packages/ruby.rb
CHANGED
@@ -9,7 +9,7 @@ Jisota.global_config do
|
|
9
9
|
run do
|
10
10
|
minor_version = version.match(/\d+\.\d+/)[0]
|
11
11
|
|
12
|
-
apt *%w(libffi-dev libssl-dev zlib1g-dev libreadline-dev)
|
12
|
+
apt *%w(libffi-dev libssl-dev zlib1g-dev libreadline-dev build-essential)
|
13
13
|
cmd %Q{
|
14
14
|
mkdir -p #{tmp_dir} &&
|
15
15
|
cd #{tmp_dir} &&
|
@@ -18,7 +18,7 @@ Jisota.global_config do
|
|
18
18
|
cd ruby-#{version} &&
|
19
19
|
./configure &&
|
20
20
|
make &&
|
21
|
-
sudo make install
|
21
|
+
sudo make install
|
22
22
|
}
|
23
23
|
end
|
24
24
|
|
data/lib/jisota/param_parser.rb
CHANGED
@@ -3,17 +3,17 @@ module Jisota
|
|
3
3
|
attr_reader :params, :args
|
4
4
|
|
5
5
|
def initialize(params, args)
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@args = args.dup
|
6
|
+
@params = params
|
7
|
+
@args = args
|
9
8
|
end
|
10
9
|
|
11
10
|
def parse
|
11
|
+
params_work_list = params.dup
|
12
12
|
Hash.new.tap do |result|
|
13
13
|
init_splat_params(result)
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
add_unnamed_args(result, params_work_list)
|
15
|
+
add_named_args(result)
|
16
|
+
handle_remaining_params(result, params_work_list)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -25,12 +25,11 @@ module Jisota
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def add_unnamed_args(result, params_work_list)
|
29
29
|
param = nil
|
30
|
-
|
31
|
-
param =
|
32
|
-
arg
|
33
|
-
raise ParameterError, "No parameter for implicit argument #{arg}" unless param
|
30
|
+
unnamed_args.each do |arg|
|
31
|
+
param = params_work_list.shift unless param && param.splat?
|
32
|
+
raise ParameterError, "No parameter for unnamed argument #{arg}" unless param
|
34
33
|
if param.splat?
|
35
34
|
result[param.name] << arg
|
36
35
|
else
|
@@ -39,25 +38,37 @@ module Jisota
|
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
args.first.each do |key, value|
|
46
|
-
param = @original_params.select { |p| p.name == key }.first
|
41
|
+
def add_named_args(result)
|
42
|
+
named_args.each do |key, value|
|
43
|
+
param = params.select { |p| p.name == key }.first
|
47
44
|
raise ParameterError, "No parameter with name #{key.inspect}" unless param
|
48
45
|
if result.has_key?(key)
|
49
46
|
if param.splat?
|
50
47
|
raise ParameterError, "Splat parameter #{key.inspect} only accepts unnamed arguments"
|
51
48
|
else
|
52
|
-
raise ParameterError, "Parameter #{key.inspect} already set with an
|
49
|
+
raise ParameterError, "Parameter #{key.inspect} already set with an unnamed argument"
|
53
50
|
end
|
54
51
|
end
|
55
52
|
result[key] = value
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
59
|
-
def
|
60
|
-
|
56
|
+
def unnamed_args
|
57
|
+
args.dup.tap do |result|
|
58
|
+
result.pop if named_args?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def named_args
|
63
|
+
named_args? ? args.last : {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def named_args?
|
67
|
+
args.last.is_a?(Hash)
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_remaining_params(result, params_work_list)
|
71
|
+
params_work_list.each do |param|
|
61
72
|
unless result.has_key?(param.name)
|
62
73
|
if param.required? && !param.default?
|
63
74
|
raise ParameterError, "Parameter #{param.name.inspect} is required"
|
data/lib/jisota/provisioner.rb
CHANGED
@@ -12,11 +12,15 @@ module Jisota
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def run_server(server, ssh, roles, packages, logger)
|
15
|
-
|
15
|
+
ssh_options = { user: server.user, host: server.host }
|
16
|
+
ssh_options[:keys] = [server.key] if server.key
|
17
|
+
|
18
|
+
ssh.start(ssh_options) do |ssh_session|
|
16
19
|
server.roles.each do |role_name|
|
17
20
|
role = roles[role_name]
|
18
|
-
|
19
|
-
script.
|
21
|
+
context = ScriptContext.new(ssh_session: ssh_session, logger: logger, packages: packages)
|
22
|
+
script = role.script_block.evaluate(context)
|
23
|
+
script.execute(context)
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
data/lib/jisota/script_block.rb
CHANGED
@@ -15,26 +15,25 @@ module Jisota
|
|
15
15
|
@block = block
|
16
16
|
end
|
17
17
|
|
18
|
-
def evaluate(
|
18
|
+
def evaluate(context = ScriptContext.new)
|
19
19
|
CompositeScript.new.tap do |script|
|
20
|
-
dsl = DSL.new(script,
|
21
|
-
dsl.
|
20
|
+
dsl = DSL.new(script, context)
|
21
|
+
dsl.evaluate(&block)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
class DSL
|
26
|
-
def initialize(script,
|
25
|
+
class DSL < DSLBase
|
26
|
+
def initialize(script, context)
|
27
27
|
@script = script
|
28
|
-
@
|
29
|
-
@packages = packages
|
28
|
+
@context = context
|
30
29
|
end
|
31
30
|
|
32
31
|
def cmd(command)
|
33
32
|
@script.scripts << CommandScript.new(command)
|
34
33
|
end
|
35
34
|
|
36
|
-
def upload(
|
37
|
-
@script.scripts << FileScript.new(
|
35
|
+
def upload(**options, &block)
|
36
|
+
@script.scripts << FileScript.new(**options, &block)
|
38
37
|
end
|
39
38
|
|
40
39
|
def method_missing(method, *args, &block)
|
@@ -48,17 +47,17 @@ module Jisota
|
|
48
47
|
private
|
49
48
|
|
50
49
|
def has_argument?(name)
|
51
|
-
@
|
50
|
+
@context.params.has_key?(name)
|
52
51
|
end
|
53
52
|
|
54
53
|
def get_argument(name)
|
55
|
-
@
|
54
|
+
@context.params.fetch(name)
|
56
55
|
end
|
57
56
|
|
58
57
|
def add_package_script(name, args)
|
59
|
-
if @packages.has_key?(name)
|
60
|
-
package = @packages[name]
|
61
|
-
@script.scripts << PackageScript.new(package, args
|
58
|
+
if @context.packages.has_key?(name)
|
59
|
+
package = @context.packages[name]
|
60
|
+
@script.scripts << PackageScript.new(package, args)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Jisota
|
2
|
+
class ScriptContext
|
3
|
+
attr_accessor :ssh_session, :logger, :params, :packages
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@ssh_session = options.fetch(:ssh_session) { nil }
|
7
|
+
@logger = options.fetch(:logger) { NilOutput.new }
|
8
|
+
@params = options.fetch(:params) { Hash.new }
|
9
|
+
@packages = options.fetch(:packages) { Collection.new }
|
10
|
+
end
|
11
|
+
|
12
|
+
def command(cmd)
|
13
|
+
ssh_session.command(cmd, logger)
|
14
|
+
end
|
15
|
+
|
16
|
+
def param_scope(scope_params)
|
17
|
+
old_params = params
|
18
|
+
self.params = scope_params
|
19
|
+
result = yield if block_given?
|
20
|
+
self.params = old_params
|
21
|
+
result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|