server-blender 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/VERSION +1 -1
- data/bin/blender +4 -3
- data/files/bootstrap.sh +1 -0
- data/files/mix.sh +3 -3
- data/lib/blender.rb +0 -0
- data/lib/blender/cli.rb +13 -0
- data/lib/blender/cli/init.rb +49 -47
- data/lib/blender/cli/mix.rb +64 -64
- data/lib/blender/cli/start.rb +77 -76
- data/server-blender.gemspec +11 -6
- data/spec/cli/init_spec.rb +80 -0
- data/spec/cli/mix_spec.rb +157 -0
- data/spec/cli/start_spec.rb +168 -0
- data/spec/spec.opts +5 -1
- data/spec/spec_helper.rb +6 -2
- metadata +20 -6
- data/spec/server-blender_spec.rb +0 -7
data/.gitignore
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.15
|
data/bin/blender
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
$:.unshift File.expand_path(File.join(__FILE__, "../../lib"))
|
4
|
+
require 'blender'
|
4
5
|
include Blender
|
5
6
|
|
6
7
|
# commands are just ruby scripts in lib/blender/cli
|
@@ -18,5 +19,5 @@ Run "blender COMMAND -h" to get help about a command
|
|
18
19
|
end
|
19
20
|
|
20
21
|
require 'optparse'
|
21
|
-
require
|
22
|
-
|
22
|
+
require "blender/cli/#{command}"
|
23
|
+
Blender::Cli.const_get(command.capitalize).new(ARGV).execute
|
data/files/bootstrap.sh
CHANGED
data/files/mix.sh
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
set -ue
|
2
2
|
|
3
3
|
SHADOW_PUPPET_VERSION="0.3.2"
|
4
|
-
MANIFEST_VERSION="0.0.
|
4
|
+
MANIFEST_VERSION="0.0.17"
|
5
5
|
|
6
6
|
trap "echo FAILED" EXIT
|
7
7
|
|
@@ -54,10 +54,10 @@ ensure_gem ruby-debug
|
|
54
54
|
ensure_gem server-blender-manifest $MANIFEST_VERSION
|
55
55
|
if run_recipe; then
|
56
56
|
echo
|
57
|
-
echo "Your
|
57
|
+
echo "Your mix is ready. Have fun!"
|
58
58
|
else
|
59
59
|
echo
|
60
|
-
echo "
|
60
|
+
echo "Mix failed. Check error messages above for details"
|
61
61
|
fi
|
62
62
|
|
63
63
|
trap - EXIT
|
data/lib/blender.rb
CHANGED
File without changes
|
data/lib/blender/cli.rb
ADDED
data/lib/blender/cli/init.rb
CHANGED
@@ -1,57 +1,59 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
opts.
|
9
|
-
|
10
|
-
|
11
|
-
options
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
require 'blender/cli'
|
2
|
+
|
3
|
+
class Blender::Cli::Init < Blender::Cli
|
4
|
+
def parse_options(args)
|
5
|
+
options = {
|
6
|
+
:system_gems => 'y'
|
7
|
+
}
|
8
|
+
opts = OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: blender init [OPTIONS] HOST"
|
10
|
+
opts.separator ""
|
11
|
+
opts.separator "Common options:"
|
12
|
+
|
13
|
+
opts.on("-u", "--upstream-gems", "don't use the system gems, download and install upstream version instead") do
|
14
|
+
options[:system_gems] = 'n'
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
|
18
|
+
options[:node] = val
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on("-t", "--trace", "dump trace to the stdout") do |val|
|
22
|
+
options[:trace] = true
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("-H", "--hostname HOSTNAME", "set HOSTNAME") do |val|
|
26
|
+
options[:hostname] = val
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on("-h", "--help", "Show this message") do
|
30
|
+
raise(opts.to_s)
|
31
|
+
end
|
17
32
|
|
18
|
-
opts.on("-t", "--trace", "dump trace to the stdout") do |val|
|
19
|
-
options[:trace] = true
|
20
33
|
end
|
34
|
+
opts.parse!(args)
|
21
35
|
|
22
|
-
|
23
|
-
options[:hostname] = val
|
24
|
-
end
|
36
|
+
raise("please provide a hostname\n#{opts}") unless host = args.shift
|
25
37
|
|
26
|
-
|
27
|
-
raise(opts.to_s)
|
28
|
-
end
|
38
|
+
raise("unexpected: #{args*" "}\n#{opts}") unless args.empty?
|
29
39
|
|
30
|
-
|
40
|
+
options.merge(:host => host)
|
41
|
+
end
|
31
42
|
|
32
|
-
|
43
|
+
def bootstrap(options)
|
44
|
+
extra=""
|
45
|
+
extra << " TRACE=1" if options[:trace]
|
46
|
+
extra << " HOSTNAME=#{options[:hostname]}" if options[:hostname]
|
47
|
+
extra << " NODE=#{options[:node]}" if options[:node]
|
33
48
|
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def run(*cmd)
|
38
|
-
STDERR.puts ">> #{cmd * ' '}"
|
39
|
-
system(*cmd)
|
40
|
-
end
|
41
|
-
|
42
|
-
def bootstrap(options)
|
43
|
-
extra=""
|
44
|
-
extra << " TRACE=1" if options[:trace]
|
45
|
-
extra << " HOSTNAME=#{options[:hostname]}" if options[:hostname]
|
46
|
-
extra << " NODE=#{options[:node]}" if options[:node]
|
47
|
-
|
48
|
-
run "cat #{File.expand_path("files/bootstrap.sh", Blender::ROOT)} | ssh #{options[:host]} USE_SYSTEM_GEMS=#{options[:system_gems]}#{extra} /bin/bash -eu"
|
49
|
-
end
|
49
|
+
run "cat #{File.expand_path("files/bootstrap.sh", Blender::ROOT)} | ssh #{options[:host]} USE_SYSTEM_GEMS=#{options[:system_gems]}#{extra} /bin/bash -eu" or raise "failed bootstrap.sh"
|
50
|
+
end
|
50
51
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
52
|
+
def execute
|
53
|
+
options = parse_options(@args)
|
54
|
+
bootstrap(options)
|
54
55
|
|
55
|
-
rescue => e
|
56
|
-
|
56
|
+
rescue => e
|
57
|
+
abort(e.to_s)
|
58
|
+
end
|
57
59
|
end
|
data/lib/blender/cli/mix.rb
CHANGED
@@ -1,89 +1,89 @@
|
|
1
|
-
|
2
|
-
options = {}
|
3
|
-
opts = OptionParser.new do |opts|
|
4
|
-
opts.banner = "Usage: blender mix [OPTIONS] [DIR] HOST"
|
5
|
-
opts.separator "Options:"
|
6
|
-
|
7
|
-
opts.on("-r", "--recipe RECIPE", "if RECIPE is not specified blender will first look for <directory_name>.rb and then for blender-recipe.rb") do |val|
|
8
|
-
options[:recipe] = val
|
9
|
-
end
|
1
|
+
require 'blender/cli'
|
10
2
|
|
11
|
-
|
12
|
-
options[:node] = val
|
13
|
-
end
|
3
|
+
class Blender::Cli::Mix < Blender::Cli
|
14
4
|
|
15
|
-
|
16
|
-
|
17
|
-
|
5
|
+
def parse_options(args)
|
6
|
+
options = {}
|
7
|
+
opts = OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: blender mix [OPTIONS] [DIR] HOST"
|
9
|
+
opts.separator "Options:"
|
18
10
|
|
19
|
-
|
20
|
-
|
11
|
+
opts.on("-r", "--recipe RECIPE", "if RECIPE is not specified blender will first look for <directory_name>.rb and then for blender-recipe.rb") do |val|
|
12
|
+
options[:recipe] = val
|
13
|
+
end
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
|
16
|
+
options[:node] = val
|
17
|
+
end
|
25
18
|
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
opts.on("-R", "--roles ROLES", "comma delimited list of roles that should execute") do |val|
|
20
|
+
options[:roles] = val
|
21
|
+
end
|
29
22
|
|
30
|
-
|
31
|
-
|
23
|
+
opts.separator ""
|
24
|
+
opts.separator "Common options:"
|
32
25
|
|
33
|
-
|
26
|
+
opts.on("-h", "--help", "Show this message") do
|
27
|
+
raise(opts.to_s)
|
28
|
+
end
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
opts.separator ""
|
31
|
+
opts.separator "Notes:"
|
32
|
+
opts.separator ' "." used if DIR not specified'
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
dir = "."
|
42
|
-
end
|
34
|
+
end
|
35
|
+
opts.parse!(args)
|
43
36
|
|
44
|
-
|
37
|
+
options[:usage] = opts.to_s
|
45
38
|
|
46
|
-
|
39
|
+
dir = args.shift
|
40
|
+
host = args.shift
|
41
|
+
raise("unexpected: #{args*" "}\n#{opts}") unless args.empty?
|
47
42
|
|
48
|
-
|
49
|
-
|
43
|
+
if host.nil?
|
44
|
+
host = dir
|
45
|
+
dir = "."
|
46
|
+
end
|
50
47
|
|
48
|
+
raise(opts.to_s) unless dir && host
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if rname = options[:recipe]
|
56
|
-
recipes << rname << "#{rname}.rb"
|
50
|
+
raise("#{dir} is not a directory\n#{opts}") unless File.directory?(dir)
|
51
|
+
|
52
|
+
options.merge(:dir => dir, :host => host)
|
57
53
|
end
|
58
|
-
recipes << "#{File.basename(File.expand_path(options[:dir]))}.rb" << "blender-recipe.rb"
|
59
54
|
|
60
|
-
recipe = recipes.detect {|r| File.file?(File.join(options[:dir], r))} ||
|
61
|
-
raise("recipe not found (looking for #{recipes * ' '})\n#{options[:usage]}")
|
62
|
-
end
|
63
55
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
def find_recipe(options)
|
57
|
+
# check for recipe, recipe.rb, directory_name.rb, and blender-recipe.rb
|
58
|
+
if rname = options[:recipe]
|
59
|
+
recipes = [rname, "#{rname}.rb"]
|
60
|
+
else
|
61
|
+
recipes = ["#{File.basename(File.expand_path(options[:dir]))}.rb", "blender-recipe.rb"]
|
62
|
+
end
|
68
63
|
|
64
|
+
recipe = recipes.detect {|r| File.file?(File.join(options[:dir], r))} ||
|
65
|
+
raise("recipe not found (looking for #{recipes * ' '})\n#{options[:usage]}")
|
66
|
+
end
|
69
67
|
|
70
|
-
def run_recipe(recipe, options)
|
71
|
-
|
68
|
+
def run_recipe(recipe, options)
|
69
|
+
run "cat #{File.expand_path("files/init.sh", Blender::ROOT)} | ssh #{options[:host]} /bin/bash -l" or raise("failed init.sh")
|
72
70
|
|
73
|
-
|
71
|
+
run("rsync -qazP --delete --exclude '.*' #{options[:dir]}/ #{options[:host]}:/var/lib/blender/recipes") or raise("failed rsync")
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
env_config = "RECIPE=#{recipe}"
|
74
|
+
env_config << " NODE=#{options[:node]}" if options[:node]
|
75
|
+
env_config << " ROLES=#{options[:roles]}" if options[:roles]
|
78
76
|
|
79
|
-
|
80
|
-
end
|
77
|
+
run "cat #{File.expand_path("files/mix.sh", Blender::ROOT)} | ssh #{options[:host]} #{env_config} /bin/bash -l" or raise("failed mix.sh")
|
78
|
+
end
|
81
79
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
def execute
|
81
|
+
options = parse_options(@args)
|
82
|
+
recipe = find_recipe(options)
|
83
|
+
run_recipe(recipe, options)
|
84
|
+
|
85
|
+
rescue => e
|
86
|
+
abort(e.to_s)
|
87
|
+
end
|
86
88
|
|
87
|
-
rescue => e
|
88
|
-
abort(e.to_s)
|
89
89
|
end
|
data/lib/blender/cli/start.rb
CHANGED
@@ -1,103 +1,104 @@
|
|
1
|
-
require '
|
1
|
+
require 'blender/cli'
|
2
2
|
|
3
|
-
|
4
|
-
options = {}
|
3
|
+
class Blender::Cli::Start < Blender::Cli
|
5
4
|
|
6
5
|
AMI_64 = "ami-55739e3c"
|
7
6
|
AMI_32 = "ami-bb709dd2"
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
opts.separator "Options:"
|
12
|
-
|
13
|
-
opts.on("--ami AMI",
|
14
|
-
"use specified AMI instead of the default one.",
|
15
|
-
"If you don't specify your own AMI blender will choose a defaule one:",
|
16
|
-
"* #{AMI_32} for 32 bits",
|
17
|
-
"* #{AMI_64} for 64 bits",
|
18
|
-
"You can change the defaults by writing your own AMIs",
|
19
|
-
"into ~/.blender/ami and ~/.blender/ami64 files",
|
20
|
-
" "
|
21
|
-
) do |val|
|
22
|
-
options[:ami] = val
|
23
|
-
end
|
24
|
-
opts.on("--key KEY",
|
25
|
-
"use KEY when starting instance. KEY should already be generated.",
|
26
|
-
"If you don't specify a KEY blender will try to use the key from your EC2 account",
|
27
|
-
"Note: There must be only ONE key on the account for it to work. ",
|
28
|
-
" "
|
29
|
-
) do |val|
|
30
|
-
options[:key] = val
|
31
|
-
end
|
8
|
+
def parse_options(args)
|
9
|
+
options = {}
|
32
10
|
|
33
|
-
opts
|
34
|
-
|
35
|
-
|
11
|
+
opts = OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: blender start [OPTIONS] [-- [ec2run options]]"
|
13
|
+
opts.separator "Options:"
|
36
14
|
|
37
|
-
|
38
|
-
|
39
|
-
|
15
|
+
opts.on("-a", "--ami AMI",
|
16
|
+
"use specified AMI instead of the default one.",
|
17
|
+
"If you don't specify your own AMI blender will choose a defaule one:",
|
18
|
+
"* #{AMI_32} for 32 bits",
|
19
|
+
"* #{AMI_64} for 64 bits",
|
20
|
+
"You can change the defaults by writing your own AMIs",
|
21
|
+
"into ~/.blender/ami and ~/.blender/ami64 files"
|
22
|
+
) do |val|
|
23
|
+
options[:ami] = val
|
24
|
+
end
|
40
25
|
|
41
|
-
|
26
|
+
opts.separator ""
|
42
27
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
28
|
+
opts.on("-k", "--key KEY",
|
29
|
+
"use KEY when starting instance. KEY should already be generated.",
|
30
|
+
"If you don't specify a KEY blender will try to use the key from your EC2 account",
|
31
|
+
"Note: There must be only ONE key on the account for it to work."
|
32
|
+
) do |val|
|
33
|
+
options[:key] = val
|
34
|
+
end
|
35
|
+
opts.separator ""
|
47
36
|
|
48
|
-
|
37
|
+
opts.on("--64", "use 64 bit default AMI. This does nothing if you specify your own AMI") do
|
38
|
+
options[64] = true
|
39
|
+
end
|
49
40
|
|
50
|
-
|
41
|
+
opts.on("-n", "--dry-run", "Don't do anything, just print the command line to be executed") do |val|
|
42
|
+
@dry = options[:dry] = true
|
43
|
+
end
|
51
44
|
|
52
|
-
|
53
|
-
blender start -64
|
45
|
+
opts.separator "\nCommon options:"
|
54
46
|
|
55
|
-
|
56
|
-
|
47
|
+
opts.on("-h", "--help", "Show this message") do
|
48
|
+
raise(opts.to_s)
|
49
|
+
end
|
57
50
|
|
58
|
-
|
59
|
-
blender start -- -g default -g test
|
60
|
-
EXAMPLE
|
51
|
+
opts.on_tail <<-EXAMPLE
|
61
52
|
|
53
|
+
Example:
|
62
54
|
|
63
|
-
|
55
|
+
# start a 64bit instance with default options
|
56
|
+
blender start -64
|
57
|
+
|
58
|
+
# start with a custom ami
|
59
|
+
blender start --ami ami-2d4aa444
|
60
|
+
|
61
|
+
# start with passing arguments to ec2run: use security group default+test
|
62
|
+
blender start -- -g default -g test
|
63
|
+
EXAMPLE
|
64
|
+
|
65
|
+
end
|
66
|
+
opts.parse!(args)
|
64
67
|
|
68
|
+
raise("unexpected: #{args*" "}\n#{opts}") unless args.empty?
|
65
69
|
|
66
|
-
|
67
|
-
end
|
70
|
+
options
|
71
|
+
end
|
68
72
|
|
69
|
-
def default_ami(options)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
73
|
+
def default_ami(options = {})
|
74
|
+
name = options[64] ? "~/.blender/ami64" : "~/.blender/ami"
|
75
|
+
ami = File.read(File.expand_path(name)).strip rescue nil
|
76
|
+
ami = options[64] ? AMI_64 : AMI_32 if ami.nil? || ami.empty?
|
77
|
+
ami
|
78
|
+
end
|
75
79
|
|
76
|
-
def default_key
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
80
|
+
def default_key
|
81
|
+
keys = `ec2dkey`.strip.split("\n")
|
82
|
+
raise("too many keys") if keys.length > 1
|
83
|
+
raise("can't find any keys") if keys.length != 1
|
84
|
+
keys.first.split("\t")[1].strip || raise("invalid key")
|
85
|
+
end
|
82
86
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
87
|
+
def start_ami(options = {}, args = [])
|
88
|
+
ami = options[:ami] || default_ami(options)
|
89
|
+
key = options[:key] || default_key
|
86
90
|
|
87
|
-
|
88
|
-
ami = options[:ami] || default_ami(options)
|
89
|
-
key = options[:key] || default_key(options)
|
91
|
+
cmd = ["ec2run", ami, "-k", key, *args]
|
90
92
|
|
91
|
-
|
93
|
+
run(*cmd) or raise "failed to start ami"
|
94
|
+
end
|
92
95
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
+
def execute
|
97
|
+
options = parse_options(@args)
|
98
|
+
start_ami(options, *@args)
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
+
rescue => e
|
101
|
+
abort(e.to_s)
|
102
|
+
end
|
100
103
|
|
101
|
-
rescue => e
|
102
|
-
abort(e.to_s)
|
103
104
|
end
|
data/server-blender.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{server-blender}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.15"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Vitaly Kushner"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-11-28}
|
13
13
|
s.default_executable = %q{blender}
|
14
14
|
s.description = %q{Boostrap and manage servers with shadow_puppet
|
15
15
|
|
@@ -39,21 +39,26 @@ http://reductivelabs.com/products/puppet/
|
|
39
39
|
"files/init.sh",
|
40
40
|
"files/mix.sh",
|
41
41
|
"lib/blender.rb",
|
42
|
+
"lib/blender/cli.rb",
|
42
43
|
"lib/blender/cli/init.rb",
|
43
44
|
"lib/blender/cli/mix.rb",
|
44
45
|
"lib/blender/cli/start.rb",
|
45
46
|
"server-blender.gemspec",
|
46
|
-
"spec/
|
47
|
+
"spec/cli/init_spec.rb",
|
48
|
+
"spec/cli/mix_spec.rb",
|
49
|
+
"spec/cli/start_spec.rb",
|
47
50
|
"spec/spec.opts",
|
48
51
|
"spec/spec_helper.rb"
|
49
52
|
]
|
50
53
|
s.homepage = %q{http://astrails.com/opensource/server-blender}
|
51
54
|
s.rdoc_options = ["--charset=UTF-8"]
|
52
55
|
s.require_paths = ["lib"]
|
53
|
-
s.rubygems_version = %q{1.3.
|
56
|
+
s.rubygems_version = %q{1.3.7}
|
54
57
|
s.summary = %q{Server provisioning and configuration management tool}
|
55
58
|
s.test_files = [
|
56
|
-
"spec/
|
59
|
+
"spec/cli/init_spec.rb",
|
60
|
+
"spec/cli/mix_spec.rb",
|
61
|
+
"spec/cli/start_spec.rb",
|
57
62
|
"spec/spec_helper.rb"
|
58
63
|
]
|
59
64
|
|
@@ -61,7 +66,7 @@ http://reductivelabs.com/products/puppet/
|
|
61
66
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
62
67
|
s.specification_version = 3
|
63
68
|
|
64
|
-
if Gem::Version.new(Gem::
|
69
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
65
70
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
66
71
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
67
72
|
else
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'blender/cli/init'
|
3
|
+
|
4
|
+
describe Blender::Cli::Init do
|
5
|
+
before(:each) do
|
6
|
+
@init = Blender::Cli::Init.new []
|
7
|
+
end
|
8
|
+
|
9
|
+
describe :parse_options do
|
10
|
+
it "should throw usage on --help" do
|
11
|
+
proc {
|
12
|
+
@init.parse_options(%w/-h/)
|
13
|
+
}.should raise_error(RuntimeError, /\AUsage:/)
|
14
|
+
|
15
|
+
proc {
|
16
|
+
@init.parse_options(%w/--help/)
|
17
|
+
}.should raise_error(RuntimeError, <<-USAGE)
|
18
|
+
Usage: blender init [OPTIONS] HOST
|
19
|
+
|
20
|
+
Common options:
|
21
|
+
-u, --upstream-gems don't use the system gems, download and install upstream version instead
|
22
|
+
-N, --node NODE force NODE as the current nodename
|
23
|
+
-t, --trace dump trace to the stdout
|
24
|
+
-H, --hostname HOSTNAME set HOSTNAME
|
25
|
+
-h, --help Show this message
|
26
|
+
USAGE
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should throw usage on missing parameters" do
|
30
|
+
proc {
|
31
|
+
@init.parse_options(%w//)
|
32
|
+
}.should raise_error(RuntimeError, /\Aplease provide a hostname/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should throw usage on extra args" do
|
36
|
+
proc {
|
37
|
+
@init.parse_options(%w/aaa bbb/)
|
38
|
+
}.should raise_error(RuntimeError, /\Aunexpected: bbb\nUsage:/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should parse host" do
|
42
|
+
opts = @init.parse_options(%w/aaa/)
|
43
|
+
opts[:host].should == "aaa"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should parse -u" do
|
47
|
+
@init.parse_options(%w/-u host/)[:system_gems].should == 'n'
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should parse -N" do
|
51
|
+
@init.parse_options(%w/-N node1 host/)[:node].should == "node1"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should parse -t" do
|
55
|
+
@init.parse_options(%w/-t host/)[:trace].should == true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should parse -H" do
|
59
|
+
@init.parse_options(%w/-H hostname host/)[:hostname].should == "hostname"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe :bootstrap do
|
65
|
+
it "should raise if mix fails" do
|
66
|
+
mock(File).expand_path("files/bootstrap.sh", Blender::ROOT) {"path/to/files/bootstrap.sh"}
|
67
|
+
mock(@init).run("cat path/to/files/bootstrap.sh | ssh host USE_SYSTEM_GEMS= TRACE=1 HOSTNAME=foobar.com NODE=zoo /bin/bash -eu") {false}
|
68
|
+
proc {
|
69
|
+
@init.bootstrap :trace => true, :hostname => "foobar.com", :node => "zoo", :host => "host"
|
70
|
+
}.should raise_error(RuntimeError, "failed bootstrap.sh")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should run bootstrap and return true" do
|
74
|
+
mock(File).expand_path("files/bootstrap.sh", Blender::ROOT) {"path/to/files/bootstrap.sh"}
|
75
|
+
mock(@init).run("cat path/to/files/bootstrap.sh | ssh host USE_SYSTEM_GEMS= TRACE=1 HOSTNAME=foobar.com NODE=zoo /bin/bash -eu") {true}
|
76
|
+
@init.bootstrap(:trace => true, :hostname => "foobar.com", :node => "zoo", :host => "host").should == true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'blender/cli/mix'
|
3
|
+
|
4
|
+
describe Blender::Cli::Mix do
|
5
|
+
before(:each) do
|
6
|
+
@mix = Blender::Cli::Mix.new []
|
7
|
+
end
|
8
|
+
|
9
|
+
describe :parse_options do
|
10
|
+
it "should throw usage on --help" do
|
11
|
+
proc {
|
12
|
+
@mix.parse_options(%w/-h/)
|
13
|
+
}.should raise_error(RuntimeError, <<-USAGE)
|
14
|
+
Usage: blender mix [OPTIONS] [DIR] HOST
|
15
|
+
Options:
|
16
|
+
-r, --recipe RECIPE if RECIPE is not specified blender will first look for <directory_name>.rb and then for blender-recipe.rb
|
17
|
+
-N, --node NODE force NODE as the current nodename
|
18
|
+
-R, --roles ROLES comma delimited list of roles that should execute
|
19
|
+
|
20
|
+
Common options:
|
21
|
+
-h, --help Show this message
|
22
|
+
|
23
|
+
Notes:
|
24
|
+
"." used if DIR not specified
|
25
|
+
USAGE
|
26
|
+
|
27
|
+
proc {
|
28
|
+
@mix.parse_options(%w/--help/)
|
29
|
+
}.should raise_error(RuntimeError, /\AUsage:/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should throw usage on missing parameters" do
|
33
|
+
proc {
|
34
|
+
@mix.parse_options(%w//)
|
35
|
+
}.should raise_error(RuntimeError, /\AUsage:/)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should throw usage on extra args" do
|
39
|
+
proc {
|
40
|
+
@mix.parse_options(%w/aaa bbb ccc/)
|
41
|
+
}.should raise_error(RuntimeError, /\Aunexpected: ccc\nUsage:/)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should only arg as host and dir as ." do
|
45
|
+
opts = @mix.parse_options(%w/aaa/)
|
46
|
+
opts[:host].should == "aaa"
|
47
|
+
opts[:dir].should == "."
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should throw usage if dir doesn't exist" do
|
51
|
+
proc {
|
52
|
+
@mix.parse_options(%w/aaa bbb/)
|
53
|
+
}.should raise_error(RuntimeError, /\Aaaa is not a directory/)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should parse host and dir args" do
|
57
|
+
opts = @mix.parse_options(%w/spec some-host/)
|
58
|
+
opts[:dir].should == "spec"
|
59
|
+
opts[:host].should == "some-host"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should parse -N" do
|
63
|
+
@mix.parse_options(%w/-N node1 host/)[:node].should == "node1"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should parse -R" do
|
67
|
+
@mix.parse_options(%w/-R role1 host/)[:roles].should == "role1"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should parse -r" do
|
71
|
+
@mix.parse_options(%w/-r foo host/)[:recipe].should == "foo"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe :find_recipe do
|
76
|
+
it "should return recipe if exists" do
|
77
|
+
mock(File).file?("path/to/foo/bar") {true}
|
78
|
+
@mix.find_recipe(:dir => "path/to/foo", :recipe => "bar").should == "bar"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return recipe.rb if exists" do
|
82
|
+
mock(File).file?("path/to/foo/bar") {false}
|
83
|
+
mock(File).file?("path/to/foo/bar.rb") {true}
|
84
|
+
@mix.find_recipe(:dir => "path/to/foo", :recipe => "bar").should == "bar.rb"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return dirname.rb if exists" do
|
88
|
+
mock(File).file?("path/to/foo/foo.rb") {true}
|
89
|
+
@mix.find_recipe(:dir => "path/to/foo").should == "foo.rb"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return blender-recipe.rb if exists" do
|
93
|
+
mock(File).file?("path/to/foo/foo.rb") {false}
|
94
|
+
mock(File).file?("path/to/foo/blender-recipe.rb") {true}
|
95
|
+
@mix.find_recipe(:dir => "path/to/foo").should == "blender-recipe.rb"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return raise error if no recipe found" do
|
99
|
+
proc {
|
100
|
+
@mix.find_recipe(:dir => "path/to/foo", :usage => "Usage:")
|
101
|
+
}.should raise_error(
|
102
|
+
RuntimeError,
|
103
|
+
/recipe not found \(looking for foo.rb blender-recipe.rb\)\nUsage:/)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should NOT look for directory.rb if given recipe" do
|
107
|
+
mock(File).file?("path/to/foo/bar") {false}
|
108
|
+
mock(File).file?("path/to/foo/bar.rb") {false}
|
109
|
+
dont_allow(File).file?("path/to/foo/foo.rb") {false}
|
110
|
+
dont_allow(File).file?("path/to/foo/blender-recipe.rb") {false}
|
111
|
+
proc {
|
112
|
+
@mix.find_recipe(:dir => "path/to/foo", :recipe => "bar")
|
113
|
+
}.should raise_error(RuntimeError, /recipe not found \(looking for bar bar.rb\)/)
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
describe :run_recipe do
|
119
|
+
it "should raise if init.sh fails" do
|
120
|
+
mock(File).expand_path("files/init.sh", Blender::ROOT) {"path/to/files/init.sh"}
|
121
|
+
mock(@mix).run("cat path/to/files/init.sh | ssh host /bin/bash -l") {false}
|
122
|
+
proc {
|
123
|
+
@mix.run_recipe "foo.rb", :host => "host"
|
124
|
+
}.should raise_error(RuntimeError, "failed init.sh")
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should raise if rsync fails" do
|
128
|
+
stub(File).expand_path("files/init.sh", Blender::ROOT) {"path/to/files/init.sh"}
|
129
|
+
stub(@mix).run("cat path/to/files/init.sh | ssh host /bin/bash -l") {true}
|
130
|
+
mock(@mix).run("rsync -qazP --delete --exclude '.*' foo/ host:/var/lib/blender/recipes") {false}
|
131
|
+
proc {
|
132
|
+
@mix.run_recipe "foo.rb", :host => "host", :dir => "foo"
|
133
|
+
}.should raise_error(RuntimeError, "failed rsync")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should raise if mix fails" do
|
137
|
+
stub(File).expand_path("files/init.sh", Blender::ROOT) {"path/to/files/init.sh"}
|
138
|
+
stub(@mix).run("cat path/to/files/init.sh | ssh host /bin/bash -l") {true}
|
139
|
+
stub(@mix).run("rsync -qazP --delete --exclude '.*' foo/ host:/var/lib/blender/recipes") {true}
|
140
|
+
mock(File).expand_path("files/mix.sh", Blender::ROOT) {"path/to/files/mix.sh"}
|
141
|
+
mock(@mix).run("cat path/to/files/mix.sh | ssh host RECIPE=foo.rb NODE=zoo ROLES=a,b /bin/bash -l") {false}
|
142
|
+
proc {
|
143
|
+
@mix.run_recipe "foo.rb", :host => "host", :dir => "foo", :roles => "a,b", :node => "zoo"
|
144
|
+
}.should raise_error(RuntimeError, "failed mix.sh")
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should run init, rsync and mix and return true" do
|
148
|
+
mock(File).expand_path("files/init.sh", Blender::ROOT) {"path/to/files/init.sh"}
|
149
|
+
mock(@mix).run("cat path/to/files/init.sh | ssh host /bin/bash -l") {true}
|
150
|
+
mock(@mix).run("rsync -qazP --delete --exclude '.*' foo/ host:/var/lib/blender/recipes") {true}
|
151
|
+
mock(File).expand_path("files/mix.sh", Blender::ROOT) {"path/to/files/mix.sh"}
|
152
|
+
mock(@mix).run("cat path/to/files/mix.sh | ssh host RECIPE=foo.rb NODE=zoo ROLES=a,b /bin/bash -l") {true}
|
153
|
+
@mix.run_recipe("foo.rb", :host => "host", :dir => "foo", :roles => "a,b", :node => "zoo").should == true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'blender/cli/start'
|
3
|
+
|
4
|
+
describe Blender::Cli::Start do
|
5
|
+
before(:each) do
|
6
|
+
@start = Blender::Cli::Start.new []
|
7
|
+
end
|
8
|
+
|
9
|
+
describe :parse_options do
|
10
|
+
it "should throw usage on --help" do
|
11
|
+
proc {
|
12
|
+
@start.parse_options(%w/-h/)
|
13
|
+
}.should raise_error(RuntimeError, /\AUsage:/)
|
14
|
+
|
15
|
+
proc {
|
16
|
+
@start.parse_options(%w/--help/)
|
17
|
+
}.should raise_error(RuntimeError, <<-USAGE)
|
18
|
+
Usage: blender start [OPTIONS] [-- [ec2run options]]
|
19
|
+
Options:
|
20
|
+
-a, --ami AMI use specified AMI instead of the default one.
|
21
|
+
If you don't specify your own AMI blender will choose a defaule one:
|
22
|
+
* ami-bb709dd2 for 32 bits
|
23
|
+
* ami-55739e3c for 64 bits
|
24
|
+
You can change the defaults by writing your own AMIs
|
25
|
+
into ~/.blender/ami and ~/.blender/ami64 files
|
26
|
+
|
27
|
+
-k, --key KEY use KEY when starting instance. KEY should already be generated.
|
28
|
+
If you don't specify a KEY blender will try to use the key from your EC2 account
|
29
|
+
Note: There must be only ONE key on the account for it to work.
|
30
|
+
|
31
|
+
--64 use 64 bit default AMI. This does nothing if you specify your own AMI
|
32
|
+
-n, --dry-run Don't do anything, just print the command line to be executed
|
33
|
+
|
34
|
+
Common options:
|
35
|
+
-h, --help Show this message
|
36
|
+
|
37
|
+
Example:
|
38
|
+
|
39
|
+
# start a 64bit instance with default options
|
40
|
+
blender start -64
|
41
|
+
|
42
|
+
# start with a custom ami
|
43
|
+
blender start --ami ami-2d4aa444
|
44
|
+
|
45
|
+
# start with passing arguments to ec2run: use security group default+test
|
46
|
+
blender start -- -g default -g test
|
47
|
+
USAGE
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not fail with no parameters" do
|
51
|
+
proc {
|
52
|
+
@start.parse_options(%w//)
|
53
|
+
}.should_not raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should throw usage on extra args" do
|
57
|
+
proc {
|
58
|
+
@start.parse_options(%w/aaa/)
|
59
|
+
}.should raise_error(RuntimeError, /\Aunexpected: aaa\nUsage:/)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should parse -a" do
|
63
|
+
@start.parse_options(%w/-a ami123/)[:ami].should == "ami123"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should parse -k" do
|
67
|
+
@start.parse_options(%w/-k mykey/)[:key].should == "mykey"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should parse --64" do
|
71
|
+
@start.parse_options(%w/--64/)[64].should == true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should parse -n" do
|
75
|
+
@start.parse_options(%w/-n/)[:dry].should == true
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe :default_ami do
|
81
|
+
it "should read ~/.blender/ami for 32 bit" do
|
82
|
+
mock(File).expand_path("~/.blender/ami") {"/path/to/home/.blender/ami"}
|
83
|
+
mock(File).read("/path/to/home/.blender/ami") {"foo"}
|
84
|
+
@start.default_ami.should == "foo"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should read ~/.blender/ami64 for 64 bit" do
|
88
|
+
mock(File).expand_path("~/.blender/ami64") {"/path/to/home/.blender/ami64"}
|
89
|
+
mock(File).read("/path/to/home/.blender/ami64") {"foo"}
|
90
|
+
@start.default_ami(64 => true).should == "foo"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return AMI_32 when file fails to read" do
|
94
|
+
mock(File).expand_path("~/.blender/ami") {"/path/to/home/.blender/ami"}
|
95
|
+
mock(File).read("/path/to/home/.blender/ami") {raise "boom"}
|
96
|
+
@start.default_ami.should == Blender::Cli::Start::AMI_32
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should return AMI_32 when file is empty" do
|
100
|
+
mock(File).expand_path("~/.blender/ami") {"/path/to/home/.blender/ami"}
|
101
|
+
mock(File).read("/path/to/home/.blender/ami") {" "}
|
102
|
+
@start.default_ami.should == Blender::Cli::Start::AMI_32
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe :default_key do
|
107
|
+
it "should fail if more then 1 key found" do
|
108
|
+
mock(@start).__double_definition_create__.call(:`, "ec2dkey") {"aaa\nbbb"}
|
109
|
+
|
110
|
+
proc {
|
111
|
+
@start.default_key
|
112
|
+
}.should raise_error(RuntimeError, "too many keys")
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should fail if no keys found" do
|
116
|
+
mock(@start).__double_definition_create__.call(:`, "ec2dkey") {""}
|
117
|
+
|
118
|
+
proc {
|
119
|
+
@start.default_key
|
120
|
+
}.should raise_error(RuntimeError, "can't find any keys")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should parse and return single key" do
|
124
|
+
mock(@start).__double_definition_create__.call(:`, "ec2dkey") {"KEYPAIR keyname 12:34:56:78:90"}
|
125
|
+
@start.default_key.should == "keyname"
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
describe :start_ami do
|
131
|
+
it "should start ami with default params" do
|
132
|
+
mock(@start).default_ami(anything) {"def-ami"}
|
133
|
+
mock(@start).default_key {"def-key"}
|
134
|
+
mock(@start).run(*%w"ec2run def-ami -k def-key") {true}
|
135
|
+
@start.start_ami.should be_true
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should raise error if run fails" do
|
139
|
+
mock(@start).default_ami(anything) {"def-ami"}
|
140
|
+
mock(@start).default_key {"def-key"}
|
141
|
+
mock(@start).run(*%w"ec2run def-ami -k def-key") {false}
|
142
|
+
proc {
|
143
|
+
@start.start_ami.should be_true
|
144
|
+
}.should raise_error(RuntimeError, "failed to start ami")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
#describe :bootstrap do
|
153
|
+
#it "should raise if mix fails" do
|
154
|
+
#mock(File).expand_path("files/bootstrap.sh", Blender::ROOT) {"path/to/files/bootstrap.sh"}
|
155
|
+
#mock(@start).run("cat path/to/files/bootstrap.sh | ssh host USE_SYSTEM_GEMS= TRACE=1 HOSTNAME=foobar.com NODE=zoo /bin/bash -eu") {false}
|
156
|
+
#proc {
|
157
|
+
#@start.bootstrap :trace => true, :hostname => "foobar.com", :node => "zoo", :host => "host"
|
158
|
+
#}.should raise_error(RuntimeError, "failed bootstrap.sh")
|
159
|
+
#end
|
160
|
+
|
161
|
+
#it "should run bootstrap and return true" do
|
162
|
+
#mock(File).expand_path("files/bootstrap.sh", Blender::ROOT) {"path/to/files/bootstrap.sh"}
|
163
|
+
#mock(@start).run("cat path/to/files/bootstrap.sh | ssh host USE_SYSTEM_GEMS= TRACE=1 HOSTNAME=foobar.com NODE=zoo /bin/bash -eu") {true}
|
164
|
+
#@start.bootstrap(:trace => true, :hostname => "foobar.com", :node => "zoo", :host => "host").should == true
|
165
|
+
#end
|
166
|
+
#end
|
167
|
+
|
168
|
+
end
|
data/spec/spec.opts
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruby-debug'
|
1
3
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
-
require '
|
5
|
+
require 'blender'
|
4
6
|
require 'spec'
|
5
7
|
require 'spec/autorun'
|
6
8
|
|
9
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
10
|
+
|
7
11
|
Spec::Runner.configure do |config|
|
8
|
-
|
12
|
+
config.mock_with :rr
|
9
13
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: server-blender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 1
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 15
|
10
|
+
version: 0.0.15
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Vitaly Kushner
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-11-28 00:00:00 +02:00
|
18
19
|
default_executable: blender
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: rspec
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
27
30
|
segments:
|
28
31
|
- 1
|
29
32
|
- 2
|
@@ -35,9 +38,11 @@ dependencies:
|
|
35
38
|
name: yard
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
41
46
|
segments:
|
42
47
|
- 0
|
43
48
|
version: "0"
|
@@ -74,11 +79,14 @@ files:
|
|
74
79
|
- files/init.sh
|
75
80
|
- files/mix.sh
|
76
81
|
- lib/blender.rb
|
82
|
+
- lib/blender/cli.rb
|
77
83
|
- lib/blender/cli/init.rb
|
78
84
|
- lib/blender/cli/mix.rb
|
79
85
|
- lib/blender/cli/start.rb
|
80
86
|
- server-blender.gemspec
|
81
|
-
- spec/
|
87
|
+
- spec/cli/init_spec.rb
|
88
|
+
- spec/cli/mix_spec.rb
|
89
|
+
- spec/cli/start_spec.rb
|
82
90
|
- spec/spec.opts
|
83
91
|
- spec/spec_helper.rb
|
84
92
|
has_rdoc: true
|
@@ -91,26 +99,32 @@ rdoc_options:
|
|
91
99
|
require_paths:
|
92
100
|
- lib
|
93
101
|
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
94
103
|
requirements:
|
95
104
|
- - ">="
|
96
105
|
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
97
107
|
segments:
|
98
108
|
- 0
|
99
109
|
version: "0"
|
100
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
101
112
|
requirements:
|
102
113
|
- - ">="
|
103
114
|
- !ruby/object:Gem::Version
|
115
|
+
hash: 3
|
104
116
|
segments:
|
105
117
|
- 0
|
106
118
|
version: "0"
|
107
119
|
requirements: []
|
108
120
|
|
109
121
|
rubyforge_project:
|
110
|
-
rubygems_version: 1.3.
|
122
|
+
rubygems_version: 1.3.7
|
111
123
|
signing_key:
|
112
124
|
specification_version: 3
|
113
125
|
summary: Server provisioning and configuration management tool
|
114
126
|
test_files:
|
115
|
-
- spec/
|
127
|
+
- spec/cli/init_spec.rb
|
128
|
+
- spec/cli/mix_spec.rb
|
129
|
+
- spec/cli/start_spec.rb
|
116
130
|
- spec/spec_helper.rb
|