server-blender 0.0.14 → 0.0.15
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.
- 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
|