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 CHANGED
@@ -25,3 +25,4 @@ pkg
25
25
 
26
26
  ## PROJECT::SPECIFIC
27
27
  doc
28
+ log/
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.14
1
+ 0.0.15
data/bin/blender CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.expand_path(File.join(__FILE__, "../../lib/blender"))
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 File.expand_path(File.join(__FILE__, "../../lib/blender/cli/", command))
22
- main
22
+ require "blender/cli/#{command}"
23
+ Blender::Cli.const_get(command.capitalize).new(ARGV).execute
data/files/bootstrap.sh CHANGED
@@ -70,6 +70,7 @@ function supported_version()
70
70
 
71
71
  case "`distribution`" in
72
72
  "Ubuntu 10.04") true;;
73
+ "Ubuntu 10.10") true;;
73
74
  *) false;;
74
75
  esac
75
76
  }
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.15"
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 ServerShake is ready. Have fun!"
57
+ echo "Your mix is ready. Have fun!"
58
58
  else
59
59
  echo
60
- echo "Failed to mix your ServerShake. Check error messages above for details"
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
@@ -0,0 +1,13 @@
1
+ module Blender
2
+ class Cli
3
+ def initialize(args)
4
+ @args = args
5
+ end
6
+
7
+ def run(*cmd)
8
+ STDERR.puts ">> #{cmd * ' '}"
9
+ system(*cmd) unless @dry
10
+ end
11
+
12
+ end
13
+ end
@@ -1,57 +1,59 @@
1
- def parse_options
2
- options = {
3
- :system_gems => 'y'
4
- }
5
- OptionParser.new do |opts|
6
- opts.banner = "Usage: blender init [OPTIONS] HOST"
7
- opts.separator ""
8
- opts.separator "Common options:"
9
-
10
- opts.on("-u", "--upstream-gems", "don't use the system gems, download and install upstream version instead") do
11
- options[:system_gems] = 'n'
12
- end
13
-
14
- opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
15
- options[:node] = val
16
- end
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
- opts.on("-H", "--hostname HOSTNAME", "set HOSTNAME") do |val|
23
- options[:hostname] = val
24
- end
36
+ raise("please provide a hostname\n#{opts}") unless host = args.shift
25
37
 
26
- opts.on("-h", "--help", "Show this message") do
27
- raise(opts.to_s)
28
- end
38
+ raise("unexpected: #{args*" "}\n#{opts}") unless args.empty?
29
39
 
30
- end.parse!
40
+ options.merge(:host => host)
41
+ end
31
42
 
32
- raise("please provide a hostname\n#{opts}") unless host = ARGV.shift
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
- options.merge(:host => host)
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 main
52
- options = parse_options
53
- bootstrap(options)
52
+ def execute
53
+ options = parse_options(@args)
54
+ bootstrap(options)
54
55
 
55
- rescue => e
56
- abort(e.to_s)
56
+ rescue => e
57
+ abort(e.to_s)
58
+ end
57
59
  end
@@ -1,89 +1,89 @@
1
- def parse_options
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
- opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
12
- options[:node] = val
13
- end
3
+ class Blender::Cli::Mix < Blender::Cli
14
4
 
15
- opts.on("-R", "--roles ROLES", "comma delimited list of roles that should execute") do |val|
16
- options[:roles] = val
17
- end
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
- opts.separator ""
20
- opts.separator "Common options:"
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
- opts.on("-h", "--help", "Show this message") do
23
- raise(opts.to_s)
24
- end
15
+ opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
16
+ options[:node] = val
17
+ end
25
18
 
26
- opts.separator ""
27
- opts.separator "Notes:"
28
- opts.separator ' "." used if DIR not specified'
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
- end
31
- opts.parse!
23
+ opts.separator ""
24
+ opts.separator "Common options:"
32
25
 
33
- options[:usage] = opts.to_s
26
+ opts.on("-h", "--help", "Show this message") do
27
+ raise(opts.to_s)
28
+ end
34
29
 
35
- dir = ARGV.shift
36
- host = ARGV.shift
37
- raise("unexpected: #{ARGV*" "}\n#{opts}") unless ARGV.empty?
30
+ opts.separator ""
31
+ opts.separator "Notes:"
32
+ opts.separator ' "." used if DIR not specified'
38
33
 
39
- if host.nil?
40
- host = dir
41
- dir = "."
42
- end
34
+ end
35
+ opts.parse!(args)
43
36
 
44
- raise(opts.to_s) unless dir && host
37
+ options[:usage] = opts.to_s
45
38
 
46
- raise("#{dir} is not a directory\n#{opts}") unless File.directory?(dir)
39
+ dir = args.shift
40
+ host = args.shift
41
+ raise("unexpected: #{args*" "}\n#{opts}") unless args.empty?
47
42
 
48
- options.merge(:dir => dir, :host => host)
49
- end
43
+ if host.nil?
44
+ host = dir
45
+ dir = "."
46
+ end
50
47
 
48
+ raise(opts.to_s) unless dir && host
51
49
 
52
- def find_recipe(options)
53
- # check for recipe, recipe.rb, directory_name.rb, and default.rb
54
- recipes = []
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 run(*cmd)
65
- STDERR.puts ">> #{cmd * ' '}"
66
- system(*cmd)
67
- end
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
- run "cat #{File.expand_path("files/init.sh", Blender::ROOT)} | ssh #{options[:host]} /bin/bash -l" or raise("failed init.sh")
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
- run("rsync -qazP --delete --exclude '.*' #{options[:dir]}/ #{options[:host]}:/var/lib/blender/recipes") or raise("failed rsync")
71
+ run("rsync -qazP --delete --exclude '.*' #{options[:dir]}/ #{options[:host]}:/var/lib/blender/recipes") or raise("failed rsync")
74
72
 
75
- env_config = "RECIPE=#{recipe}"
76
- env_config << " NODE=#{options[:node]}" if options[:node]
77
- env_config << " ROLES=#{options[:roles]}" if options[:roles]
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
- run "cat #{File.expand_path("files/mix.sh", Blender::ROOT)} | ssh #{options[:host]} #{env_config} /bin/bash -l" or raise("failed mix.sh")
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 main
83
- options = parse_options
84
- recipe = find_recipe(options)
85
- run_recipe(recipe, options)
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
@@ -1,103 +1,104 @@
1
- require 'pp'
1
+ require 'blender/cli'
2
2
 
3
- def parse_options
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
- OptionParser.new do |opts|
10
- opts.banner = "Usage: blender start [OPTIONS] [-- [ec2run options]]"
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.on("--64", "use 64 bit default AMI. This does nothing if you specify your own AMI") do
34
- options[64] = true
35
- end
11
+ opts = OptionParser.new do |opts|
12
+ opts.banner = "Usage: blender start [OPTIONS] [-- [ec2run options]]"
13
+ opts.separator "Options:"
36
14
 
37
- opts.on("-n", "--dry-run", "Don't do anything, just print the command line to be executed") do |val|
38
- options[:dry] = true
39
- end
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
- opts.separator "\nCommon options:"
26
+ opts.separator ""
42
27
 
43
- opts.on("-h", "--help", "Show this message") do
44
- puts opts
45
- exit
46
- end
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
- opts.on_tail <<-EXAMPLE
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
- Example:
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
- # start a 64bit instance with default options
53
- blender start -64
45
+ opts.separator "\nCommon options:"
54
46
 
55
- # start with a custom ami
56
- blender start --ami ami-2d4aa444
47
+ opts.on("-h", "--help", "Show this message") do
48
+ raise(opts.to_s)
49
+ end
57
50
 
58
- # start with passing arguments to ec2run: use security group default+test
59
- blender start -- -g default -g test
60
- EXAMPLE
51
+ opts.on_tail <<-EXAMPLE
61
52
 
53
+ Example:
62
54
 
63
- end.parse!
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
- options
67
- end
70
+ options
71
+ end
68
72
 
69
- def default_ami(options)
70
- name = options[64] ? "~/.blender/ami64" : "~/.blender/ami"
71
- ami = File.read(File.expand_path(name)) rescue nil
72
- ami = options[64] ? AMI_64 : AMI_32 if ami.nil? || ami.empty?
73
- ami
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(options)
77
- keys = `ec2dkey`.strip.split("\n")
78
- abort("too many keys") if keys.length > 1
79
- abort("can't find any keys") if keys.length != 1
80
- keys.first.split("\t")[1] || raise("invalid key")
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 run(*cmd)
84
- system(*cmd)
85
- end
87
+ def start_ami(options = {}, args = [])
88
+ ami = options[:ami] || default_ami(options)
89
+ key = options[:key] || default_key
86
90
 
87
- def start_ami(options)
88
- ami = options[:ami] || default_ami(options)
89
- key = options[:key] || default_key(options)
91
+ cmd = ["ec2run", ami, "-k", key, *args]
90
92
 
91
- cmd = ["ec2run", ami, "-k", key, *ARGV]
93
+ run(*cmd) or raise "failed to start ami"
94
+ end
92
95
 
93
- STDERR.puts ">> #{cmd * ' '}"
94
- run(cmd) unless options[:dry]
95
- end
96
+ def execute
97
+ options = parse_options(@args)
98
+ start_ami(options, *@args)
96
99
 
97
- def main
98
- options = parse_options
99
- start_ami(options)
100
+ rescue => e
101
+ abort(e.to_s)
102
+ end
100
103
 
101
- rescue => e
102
- abort(e.to_s)
103
104
  end
@@ -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.14"
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-07-04}
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/server-blender_spec.rb",
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.6}
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/server-blender_spec.rb",
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::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
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
@@ -1 +1,5 @@
1
- --color
1
+ --colour
2
+ --format nested
3
+ --format profile:log/spec-benchmark.log
4
+ --loadby mtime
5
+ --reverse
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 'server-blender'
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
- - 14
9
- version: 0.0.14
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-07-04 00:00:00 +03:00
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/server-blender_spec.rb
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.6
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/server-blender_spec.rb
127
+ - spec/cli/init_spec.rb
128
+ - spec/cli/mix_spec.rb
129
+ - spec/cli/start_spec.rb
116
130
  - spec/spec_helper.rb
@@ -1,7 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "ServerBlender" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
6
- end
7
- end