server-blender 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/.braids ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+ vendor/server-blender-manifests:
3
+ squashed: true
4
+ url: git@github.com:astrails/server-blender-manifest.git
5
+ branch: master
6
+ type: git
7
+ revision: f6e00941b78856305d9769882dc8920557e2ed35
8
+ remote: braid/vendor/server-blender-manifests
data/.document ADDED
@@ -0,0 +1,6 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ vendor/server-blender-manifests/**/*.rb
6
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,27 @@
1
+ ## MISC
2
+ pkg
3
+ tags
4
+ .yardoc
5
+
6
+ ## MAC OS
7
+ .DS_Store
8
+
9
+ ## TEXTMATE
10
+ *.tmproj
11
+ tmtags
12
+
13
+ ## EMACS
14
+ *~
15
+ \#*
16
+ .\#*
17
+
18
+ ## VIM
19
+ *.swp
20
+
21
+ ## PROJECT::GENERAL
22
+ coverage
23
+ rdoc
24
+ pkg
25
+
26
+ ## PROJECT::SPECIFIC
27
+ doc
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Vitaly Kushner
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/PLAN ADDED
@@ -0,0 +1,13 @@
1
+
2
+ - extrace generic parts from recipes into blender
3
+ - need concept to handle cloud and client-side processing
4
+ - creating instances
5
+ - creating volumes
6
+ - passing data to the instances
7
+ - passing data between instances
8
+
9
+
10
+
11
+
12
+
13
+
data/README.markdown ADDED
@@ -0,0 +1,65 @@
1
+ # Server Blender
2
+
3
+ IMPORTANT: this is pre-alpha. interface is not near being stable. I'm still
4
+ working on making it not-a-hack :)
5
+
6
+ (Note to self: write the tests already you lazy bastard! ;)
7
+
8
+ * Home: [http://astrails.com/opensource/server-blender](http://astrails.com/opensource/server-blender)
9
+ * Code: [http://github.com/astrails/server-blender](http://github.com/astrails/server-blender)
10
+ * Blog: [http://blog.astrails.com/server-blender](http://blog.astrails.com/server-blender)
11
+
12
+ ## Introduction
13
+
14
+ Boostrap and manage servers with shadow\_puppet
15
+
16
+ Blender tries to be a fairly minimal wrapper around [shadow\_puppet](http://github.com/railsmachine/shadow\_puppet)
17
+
18
+ shadow\_puppet is a Ruby interface to [Puppet](http://reductivelabs.com/products/puppet/) manifests.
19
+
20
+ During 'mixing' blender will transfer ALL files in the source directory to the
21
+ remote server and then execute the designated 'recipe' with shadow\_puppet.
22
+
23
+ ## Quick Start
24
+
25
+ The intended usage workflow is as follows:
26
+
27
+ * (optional) blender start - to start a new server instance (currently only EC2 is supported)
28
+ * blender init root@HOSTNAME - install minimal system required to run blender recipes
29
+ * blender mix [-r RECIPE] [DIR] root@HOSTNAME
30
+
31
+ Note: root access through ssh is required for blender to work. There are no
32
+ current plans to support sudo or some other method of privilege elevation (but I will consider it if there is a popular demand. I'm definitely will accept patched for such support ;)
33
+
34
+ ## Examples
35
+
36
+ initialize blender
37
+
38
+ $ blender init root@foobar.com
39
+
40
+ mix default recipe (default.rb) from directory my\_recipes
41
+
42
+ $ blender mix my_recipes root@foobar.com
43
+
44
+ mix recipe extra.rb from directory my\_recipes
45
+
46
+ $ blender mix my_recipes -r extra root@foobar.com # will run my_recipes/extra.rb
47
+
48
+ mix recipe extra.rb from the current directory
49
+
50
+ $ blender mix -r extra root@foobar.com # will run ./extra.rb
51
+
52
+
53
+ ## Note on Patches/Pull Requests
54
+
55
+ * Fork the project.
56
+ * Make your feature addition or bug fix.
57
+ * Add tests for it. This is important so I don't break it in a
58
+ future version unintentionally.
59
+ * Commit, do not mess with rakefile, version, or history.
60
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
61
+ * Send me a pull request. Bonus points for topic branches.
62
+
63
+ ## Copyright
64
+
65
+ Copyright (c) 2009 Vitaly Kushner. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "server-blender"
8
+ gem.summary = %Q{Server provisioning and configuration management tool}
9
+ gem.description = <<-DESC
10
+ Boostrap and manage servers with shadow\_puppet
11
+
12
+ Server Blender tries to be a fairly minimal wrapper around shadow\_puppet
13
+ http://github.com/railsmachine/shadow\_puppet
14
+
15
+ shadow\_puppet is a Ruby interface to Puppet's manifests.
16
+ http://reductivelabs.com/products/puppet/
17
+ DESC
18
+ gem.email = "vitaly@astrails.com"
19
+ gem.homepage = "http://astrails.com/opensource/server-blender"
20
+ gem.authors = ["Vitaly Kushner"]
21
+ gem.add_development_dependency "rspec", ">= 1.2.9"
22
+ gem.add_development_dependency "yard", ">= 0"
23
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
24
+ end
25
+ Jeweler::GemcutterTasks.new
26
+ rescue LoadError
27
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
28
+ end
29
+
30
+ require 'spec/rake/spectask'
31
+ Spec::Rake::SpecTask.new(:spec) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.spec_files = FileList['spec/**/*_spec.rb']
34
+ end
35
+
36
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
37
+ spec.libs << 'lib' << 'spec'
38
+ spec.pattern = 'spec/**/*_spec.rb'
39
+ spec.rcov = true
40
+ end
41
+
42
+ task :spec => :check_dependencies
43
+
44
+ task :default => :spec
45
+
46
+ begin
47
+ require 'yard'
48
+ YARD::Rake::YardocTask.new
49
+ rescue LoadError
50
+ task :yardoc do
51
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
52
+ end
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.8
data/bin/blender ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(File.join(__FILE__, "../../lib/blender"))
4
+ include Blender
5
+
6
+ # commands are just ruby scripts in lib/blender/cli
7
+ COMMANDS_DIR = File.expand_path("lib/blender/cli", Blender::ROOT)
8
+ COMMANDS = Dir["#{COMMANDS_DIR}/*rb"].map {|f| File.basename(f).split(".").first}
9
+
10
+ command = ARGV.shift
11
+ unless command && COMMANDS.include?(command)
12
+ abort <<-USAGE
13
+ Usage: blender COMMAND [OPTIONS]
14
+
15
+ Available commands: #{COMMANDS * " "}
16
+ Run "blender COMMAND -h" to get help about a command
17
+ USAGE
18
+ end
19
+
20
+ require 'optparse'
21
+ require File.expand_path(File.join(__FILE__, "../../lib/blender/cli/", command))
@@ -0,0 +1,240 @@
1
+ #!/bin/bash -eu
2
+
3
+ # log both to the 'real' stdout and into the log
4
+ function log()
5
+ {
6
+ echo "************* $@"
7
+ echo "************* $@" >&3
8
+ }
9
+
10
+ trap "log FAILED" EXIT
11
+
12
+ function banner()
13
+ {
14
+ cat <<_
15
+ Bootstraping blender...
16
+ Date: `date`
17
+ Hostname: `hostname`
18
+ System: `uname -a`
19
+ _
20
+ }
21
+
22
+ function setup_node()
23
+ {
24
+ if [ -n "${NODE:-}" ]; then
25
+ echo SET NODE: $NODE
26
+ echo $NODE > /etc/node
27
+ fi
28
+ }
29
+
30
+ function setup_hostname()
31
+ {
32
+ if [ -n "${HOSTNAME:-}" ]; then
33
+ echo SET HOSTNAME: $HOSTNAME
34
+ echo $HOSTNAME > /etc/hostname
35
+ hostname $HOSTNAME
36
+ fi
37
+ }
38
+
39
+ # initialize blender directory and redirect output to the log file
40
+ function blender_init()
41
+ {
42
+ mkdir -p /var/lib/blender/{recipes,logs,tmp}
43
+ chmod 0700 /var/lib/blender/
44
+
45
+ # save stdout into fd 3
46
+ exec 3>&1
47
+
48
+ # redirect stdout/error to the log
49
+ if [ -n "${TRACE:-}" ]; then
50
+ exec 1 | tee -a /var/lib/blender/logs/blender-bootstrap.log
51
+ else
52
+ exec 1>> /var/lib/blender/logs/blender-bootstrap.log
53
+ fi
54
+ exec 2>&1
55
+
56
+ cd /tmp
57
+ # lets log everything
58
+ set -x
59
+ }
60
+
61
+
62
+ function distribution()
63
+ {
64
+ echo "$DISTRIB_ID $DISTRIB_RELEASE"
65
+ }
66
+
67
+ function supported_version()
68
+ {
69
+ . /etc/lsb-release
70
+
71
+ case "`distribution`" in
72
+ "Ubuntu 10.04") true;;
73
+ *) false;;
74
+ esac
75
+ }
76
+
77
+ function check_version()
78
+ {
79
+ if ! supported_version; then
80
+ log "`distribution` is not supported"
81
+ exit
82
+ fi
83
+ }
84
+
85
+ export DEBIAN_FRONTEND=noninteractive
86
+ export DEBIAN_PRIORITY=critical
87
+
88
+ APT_OPTS="-qy -o DPkg::Options::=--force-confdef -o DPkg::Options::=--force-confnew"
89
+
90
+ # protect ec2-ami-tools from downgrade
91
+ function pin_ami_version()
92
+ {
93
+ cat <<-PREFS >/etc/apt/preferences
94
+ Package: ec2-ami-tools
95
+ Pin: version 1.3-34545
96
+ Pin-Priority: 500
97
+ PREFS
98
+ }
99
+
100
+ function apt_upgrade()
101
+ {
102
+ log "apt upgrade"
103
+ apt-get update
104
+ apt-get upgrade $APT_OPTS
105
+ apt-get autoremove $APT_OPTS
106
+ }
107
+
108
+ function apt_install()
109
+ {
110
+ apt-get install $APT_OPTS "$@"
111
+ }
112
+
113
+ function setup_etckeeper()
114
+ {
115
+ log "installing etckeeper"
116
+ apt_install git-core etckeeper
117
+ cp /etc/etckeeper/etckeeper.conf /etc/etckeeper/etckeeper.conf.orig
118
+ # etckeeper comes configured for bazr. use git instead.
119
+ (rm /etc/etckeeper/etckeeper.conf; awk "/^\s*VCS=/{sub(/.*/, \"VCS=git\")};{print}" > /etc/etckeeper/etckeeper.conf) < /etc/etckeeper/etckeeper.conf
120
+ etckeeper init
121
+ etckeeper commit "import during bootstrap" || true
122
+ }
123
+
124
+
125
+
126
+ function install_stuff()
127
+ {
128
+ log "installing required packages"
129
+ apt_install rsync build-essential zlib1g-dev libssl-dev libreadline5-dev wget bind9-host
130
+ }
131
+
132
+ function install_system_ruby()
133
+ {
134
+ log "installing system ruby"
135
+ apt_install ruby irb ruby-dev libopenssl-ruby
136
+ }
137
+
138
+ function install_system_rubygems()
139
+ {
140
+ log "installing system rubygems"
141
+ apt_install rubygems
142
+ }
143
+
144
+ function upgrade_rubygems()
145
+ {
146
+ log "upgrading rubygems"
147
+ gem install --no-rdoc --no-ri rubygems-update
148
+ update_rubygems
149
+ }
150
+
151
+ UPSTREAM_GEMS_VERSION=1.3.6
152
+ function install_custom_rubygems()
153
+ {
154
+ log "installing custom rubygems"
155
+ # remove system rubygems if exist
156
+ apt-get remove -qy --purge rubygems
157
+ apt-get autoremove -qy
158
+
159
+ # download and install gems
160
+ cd /tmp
161
+ wget http://production.cf.rubygems.org/rubygems/rubygems-$UPSTREAM_GEMS_VERSION.tgz
162
+ tar xfz rubygems-$UPSTREAM_GEMS_VERSION.tgz
163
+ pushd rubygems-$UPSTREAM_GEMS_VERSION
164
+ ruby setup.rb --no-rdoc --no-ri
165
+ ln -sfn /usr/bin/gem1.8 /usr/bin/gem
166
+ }
167
+
168
+ function install_puppet()
169
+ {
170
+ log "installing puppet"
171
+ gem install --no-rdoc --no-ri shadow_puppet -v 0.3.2
172
+ gem install --no-rdoc --no-ri ruby-debug
173
+ }
174
+
175
+ # adds /var/lib/gems/1.8/bin to paths. only needed with the system (debian) braindead gems
176
+
177
+ function add_gems_to_system_path()
178
+ {
179
+ log "fixing system path"
180
+ ## # default /etc/login.defs
181
+ ## ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
182
+ ## ENV_PATH PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
183
+ ## # default /etc/environment
184
+ ## PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
185
+ ##
186
+ ## When loggin-in over SSH /etc/environment path is active
187
+ ## When doing "su - xxx" - /etc/login.defs path is active
188
+
189
+ etckeeper commit "before PATH update" || true
190
+
191
+ ENV_PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/var/lib/gems/1.8/bin
192
+ USER_PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/var/lib/gems/1.8/bin
193
+ ROOT_PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/gems/1.8/bin
194
+
195
+ cat <<-ENV >/etc/environment
196
+ PATH="$ENV_PATH"
197
+ ENV
198
+
199
+ ( rm /etc/login.defs; awk "/^\s*ENV_SUPATH/{sub(/.*/, \"ENV_SUPATH PATH=$ROOT_PATH\")};/^\s*ENV_PATH/{sub(/.*/, \"ENV_PATH PATH=$USER_PATH\")};{print}" > /etc/login.defs ) < /etc/login.defs
200
+
201
+ etckeeper commit "after PATH update"
202
+ }
203
+
204
+ #########################################################
205
+ #########################################################
206
+
207
+ banner
208
+
209
+ blender_init
210
+
211
+ setup_node
212
+ setup_hostname
213
+
214
+ check_version
215
+ pin_ami_version
216
+ apt_upgrade
217
+ setup_etckeeper
218
+ install_stuff
219
+ install_system_ruby
220
+
221
+ if [[ "${USE_SYSTEM_GEMS:-y}" == "y" ]]; then
222
+ install_system_rubygems
223
+ add_gems_to_system_path
224
+ else
225
+ install_custom_rubygems
226
+ upgrade_rubygems
227
+ # upstream rubygems install executables into /usr/bin so no need to fix the path
228
+ fi
229
+
230
+
231
+ gem install rdoc # needed by most gems
232
+
233
+ install_puppet
234
+
235
+ date > /etc/bootstraped_at
236
+ etckeeper commit "bootstrapped"
237
+
238
+ trap - EXIT
239
+
240
+ echo COMPLETED
@@ -0,0 +1,44 @@
1
+ options = {
2
+ :system_gems => 'y'
3
+ }
4
+ OptionParser.new do |opts|
5
+ opts.banner = "Usage: blender init [OPTIONS] HOST"
6
+ opts.separator ""
7
+ opts.separator "Common options:"
8
+
9
+ opts.on("-u", "--upstream-gems", "don't use the system gems, download and install upstream version instead") do
10
+ options[:system_gems] = 'n'
11
+ end
12
+
13
+ opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
14
+ options[:node] = val
15
+ end
16
+
17
+ opts.on("-t", "--trace", "dump trace to the stdout") do |val|
18
+ options[:trace] = true
19
+ end
20
+
21
+ opts.on("-H", "--hostname HOSTNAME", "set HOSTNAME") do |val|
22
+ options[:hostname] = val
23
+ end
24
+
25
+ opts.on("-h", "--help", "Show this message") do
26
+ puts opts
27
+ exit
28
+ end
29
+
30
+ end.parse!
31
+
32
+ abort("please provide a hostname") unless host = ARGV.shift
33
+
34
+ extra=""
35
+ extra << " TRACE=1" if options[:trace]
36
+ extra << " HOSTNAME=#{options[:hostname]}" if options[:hostname]
37
+ extra << " NODE=#{options[:node]}" if options[:node]
38
+
39
+ def run(*cmd)
40
+ puts ">> #{cmd * ' '}"
41
+ system(*cmd)
42
+ end
43
+
44
+ run "cat files/bootstrap.sh | ssh #{host} USE_SYSTEM_GEMS=#{options[:system_gems]}#{extra} /bin/bash -eu"
@@ -0,0 +1,71 @@
1
+ options = {
2
+ :recipe => 'default'
3
+ }
4
+ opts = OptionParser.new do |opts|
5
+ opts.banner = "Usage: blender mix [OPTIONS] [DIR] HOST"
6
+ opts.separator "Options:"
7
+
8
+ opts.on("-r", "--recipe RECIPE", "('default' will be used if RECIPE not specified") do |val|
9
+ options[:recipe] = val
10
+ end
11
+
12
+ opts.on("-N", "--node NODE", "force NODE as the current nodename") do |val|
13
+ options[:node] = val
14
+ end
15
+
16
+ opts.on("-R", "--roles ROLES", "comma delimited list of roles that should execute") do |val|
17
+ options[:roles] = val
18
+ end
19
+
20
+ opts.separator ""
21
+ opts.separator "Common options:"
22
+
23
+ opts.on("-h", "--help", "Show this message") do
24
+ puts opts
25
+ exit
26
+ end
27
+
28
+ opts.separator ""
29
+ opts.separator "Notes:"
30
+ opts.separator ' "." used if DIR not specified'
31
+
32
+ end
33
+ opts.parse!
34
+
35
+ dir = ARGV.shift
36
+ host = ARGV.shift
37
+ abort("unexpected: #{ARGV*" "}\n#{opts}") unless ARGV.empty?
38
+ if host.nil?
39
+ host = dir
40
+ dir = "."
41
+ end
42
+
43
+ abort(opts.to_s) unless dir && host
44
+
45
+ unless File.directory?(dir)
46
+ puts "#{dir} is not a directory"
47
+ abort(opts.to_s)
48
+ end
49
+
50
+ File.file?(File.join(dir, recipe = options[:recipe])) ||
51
+ File.file?(File.join(dir, recipe = "#{options[:recipe]}.rb")) ||
52
+ abort("recipe #{recipe} not found\n#{opts}")
53
+
54
+ WORK_DIR = "/var/lib/blender/recipes"
55
+ LOCAL_MANIFEST_DIR = File.expand_path("../../manifest", __FILE__)
56
+ REMOTE_MANIFEST_DIR = "/var/lib/blender/manifest"
57
+ ROOT_MANIFEST = File.join(REMOTE_MANIFEST_DIR, "root.rb")
58
+
59
+ def run(*cmd)
60
+ puts ">> #{cmd * ' '}"
61
+ system(*cmd)
62
+ end
63
+
64
+ run("rsync -azP --delete --exclude '.*' #{LOCAL_MANIFEST_DIR}/ #{host}:#{REMOTE_MANIFEST_DIR}") &&
65
+ run("rsync -azP --delete --exclude '.*' --exclude other #{dir}/ #{host}:#{WORK_DIR}") &&
66
+
67
+ extra=""
68
+ extra << " NODE=#{options[:node]}" if options[:node]
69
+ extra << " ROLES=#{options[:roles]}" if options[:roles]
70
+
71
+ run("ssh", host, "echo 'Running Puppet [recipe: #{recipe}]...';cd #{WORK_DIR} && RECIPE=#{recipe} #{extra} shadow_puppet #{ROOT_MANIFEST}")
@@ -0,0 +1,82 @@
1
+ require 'pp'
2
+ options = {}
3
+
4
+ AMI_64 = "ami-55739e3c"
5
+ AMI_32 = "ami-bb709dd2"
6
+
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: blender start [OPTIONS] [-- [ec2run options]]"
9
+ opts.separator "Options:"
10
+
11
+ opts.on("--ami AMI",
12
+ "use specified AMI instead of the default one.",
13
+ "If you don't specify your own AMI blender will choose a defaule one:",
14
+ "* #{AMI_32} for 32 bits",
15
+ "* #{AMI_64} for 64 bits",
16
+ "You can change the defaults by writing your own AMIs",
17
+ "into ~/.blender/ami and ~/.blender/ami64 files",
18
+ " "
19
+ ) do |val|
20
+ options[:ami] = val
21
+ end
22
+ opts.on("--key KEY",
23
+ "use KEY when starting instance. KEY should already be generated.",
24
+ "If you don't specify a KEY blender will try to use the key from your EC2 account",
25
+ "Note: There must be only ONE key on the account for it to work. ",
26
+ " "
27
+ ) do |val|
28
+ options[:key] = val
29
+ end
30
+
31
+ opts.on("--64", "use 64 bit default AMI. This does nothing if you specify your own AMI") do
32
+ options[64] = true
33
+ end
34
+
35
+ opts.on("-n", "--dry-run", "Don't do anything, just print the command line to be executed") do |val|
36
+ options[:dry] = true
37
+ end
38
+
39
+ opts.separator "\nCommon options:"
40
+
41
+ opts.on("-h", "--help", "Show this message") do
42
+ puts opts
43
+ exit
44
+ end
45
+
46
+ opts.on_tail <<-EXAMPLE
47
+
48
+ Example:
49
+
50
+ # start a 64bit instance with default options
51
+ blender start -64
52
+
53
+ # start with a custom ami
54
+ blender start --ami ami-2d4aa444
55
+
56
+ # start with passing arguments to ec2run: use security group default+test
57
+ blender start -- -g default -g test
58
+ EXAMPLE
59
+
60
+
61
+ end.parse!
62
+
63
+ def default_ami(options)
64
+ name = options[64] ? "~/.blender/ami64" : "~/.blender/ami"
65
+ ami = File.read(File.expand_path(name)) rescue nil
66
+ ami = options[64] ? AMI_64 : AMI_32 if ami.nil? || ami.empty?
67
+ ami
68
+ end
69
+
70
+ def default_key(options)
71
+ keys = `ec2dkey`.strip.split("\n")
72
+ abort("too many keys") if keys.length > 1
73
+ abort("can't find any keys") if keys.length != 1
74
+ keys.first.split("\t")[1] || raise("invalid key")
75
+ end
76
+
77
+ ami = options[:ami] || default_ami(options)
78
+ key = options[:key] || default_key(options)
79
+
80
+ cmd = ["ec2run", ami, "-k", key, *ARGV]
81
+ puts cmd * " "
82
+ system(*cmd) unless options[:dry]
data/lib/blender.rb ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby -rrubygems
2
+
3
+ module Blender
4
+ ROOT = File.expand_path("../..", __FILE__)
5
+ end
@@ -0,0 +1,87 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{server-blender}
8
+ s.version = "0.0.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Vitaly Kushner"]
12
+ s.date = %q{2010-06-15}
13
+ s.default_executable = %q{blender}
14
+ s.description = %q{Boostrap and manage servers with shadow_puppet
15
+
16
+ Server Blender tries to be a fairly minimal wrapper around shadow_puppet
17
+ http://github.com/railsmachine/shadow_puppet
18
+
19
+ shadow_puppet is a Ruby interface to Puppet's manifests.
20
+ http://reductivelabs.com/products/puppet/
21
+ }
22
+ s.email = %q{vitaly@astrails.com}
23
+ s.executables = ["blender"]
24
+ s.extra_rdoc_files = [
25
+ "LICENSE",
26
+ "README.markdown"
27
+ ]
28
+ s.files = [
29
+ ".braids",
30
+ ".document",
31
+ ".gitignore",
32
+ "LICENSE",
33
+ "PLAN",
34
+ "README.markdown",
35
+ "Rakefile",
36
+ "VERSION",
37
+ "bin/blender",
38
+ "files/bootstrap.sh",
39
+ "lib/blender.rb",
40
+ "lib/blender/cli/init.rb",
41
+ "lib/blender/cli/mix.rb",
42
+ "lib/blender/cli/start.rb",
43
+ "server-blender.gemspec",
44
+ "spec/server-blender_spec.rb",
45
+ "spec/spec.opts",
46
+ "spec/spec_helper.rb",
47
+ "vendor/server-blender-manifests/.gitignore",
48
+ "vendor/server-blender-manifests/LICENSE",
49
+ "vendor/server-blender-manifests/README.markdown",
50
+ "vendor/server-blender-manifests/Rakefile",
51
+ "vendor/server-blender-manifests/VERSION",
52
+ "vendor/server-blender-manifests/lib/blender/manifest/init.rb",
53
+ "vendor/server-blender-manifests/lib/blender/manifest/mixer.rb",
54
+ "vendor/server-blender-manifests/lib/blender/manifest/nodes.rb",
55
+ "vendor/server-blender-manifests/lib/blender/manifest/roles.rb",
56
+ "vendor/server-blender-manifests/lib/blender/manifest/root.rb",
57
+ "vendor/server-blender-manifests/server-blender-manifest.gemspec",
58
+ "vendor/server-blender-manifests/spec/spec.opts",
59
+ "vendor/server-blender-manifests/spec/spec_helper.rb"
60
+ ]
61
+ s.homepage = %q{http://astrails.com/opensource/server-blender}
62
+ s.rdoc_options = ["--charset=UTF-8"]
63
+ s.require_paths = ["lib"]
64
+ s.rubygems_version = %q{1.3.6}
65
+ s.summary = %q{Server provisioning and configuration management tool}
66
+ s.test_files = [
67
+ "spec/server-blender_spec.rb",
68
+ "spec/spec_helper.rb"
69
+ ]
70
+
71
+ if s.respond_to? :specification_version then
72
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
73
+ s.specification_version = 3
74
+
75
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
76
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
77
+ s.add_development_dependency(%q<yard>, [">= 0"])
78
+ else
79
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
80
+ s.add_dependency(%q<yard>, [">= 0"])
81
+ end
82
+ else
83
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
84
+ s.add_dependency(%q<yard>, [">= 0"])
85
+ end
86
+ end
87
+
@@ -0,0 +1,7 @@
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
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'server-blender'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,26 @@
1
+ ## MISC
2
+ pkg
3
+ tags
4
+ .yardoc
5
+
6
+ ## MAC OS
7
+ .DS_Store
8
+
9
+ ## TEXTMATE
10
+ *.tmproj
11
+ tmtags
12
+
13
+ ## EMACS
14
+ *~
15
+ \#*
16
+ .\#*
17
+
18
+ ## VIM
19
+ *.swp
20
+
21
+ ## PROJECT::GENERAL
22
+ coverage
23
+ rdoc
24
+ pkg
25
+
26
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Vitaly Kushner
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ # server-blender-manifest
2
+
3
+ This gem is part of the [server-blender](http://astrails.com/opensource/server-blender) family.
4
+
5
+ It contains server-side root manifest implementation for blender recipes. See server-blender for more information.
6
+
7
+ * Home: [http://astrails.com/opensource/server-blender](http://astrails.com/opensource/server-blender)
8
+ * Code: [http://github.com/astrails/server-blender-manifest](http://github.com/astrails/server-blender-manifest)
9
+ * Blog: [http://blog.astrails.com/server-blender](http://blog.astrails.com/server-blender)
10
+
11
+ ## Note on Patches/Pull Requests
12
+
13
+ * Fork the project.
14
+ * Make your feature addition or bug fix.
15
+ * Add tests for it. This is important so I don't break it in a
16
+ future version unintentionally.
17
+ * Commit, do not mess with rakefile, version, or history.
18
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
19
+ * Send me a pull request. Bonus points for topic branches.
20
+
21
+ ## Copyright
22
+
23
+ Copyright (c) 2010 Vitaly Kushner. See LICENSE for details.
@@ -0,0 +1,40 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "server-blender-manifest"
8
+ gem.summary = %Q{server-side root manifest implementation for server-blender}
9
+ gem.description = <<-DESC
10
+ This gem is part of the server-blender family (http://astrails.com/opensource/server-blender)
11
+ It contains server-side root manifest implementation for blender recipes. See server-blender for more information.
12
+ DESC
13
+ gem.email = "vitaly@astrails.com"
14
+ gem.homepage = "http://astrails.com/opensource/server-blender"
15
+ gem.authors = ["Vitaly Kushner"]
16
+ gem.add_development_dependency "rspec", ">= 1.2.9"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :spec => :check_dependencies
37
+
38
+ task :default => :spec
39
+
40
+ # documentaion is included in the parent server-blender gem
@@ -0,0 +1 @@
1
+ 0.0.8
@@ -0,0 +1,23 @@
1
+ module Blender::Manifest::Init
2
+ def self.included(base)
3
+ base.class_eval do
4
+ recipe :create_blender_directories
5
+ end
6
+ end
7
+
8
+ # create blender directories
9
+ # @return dependency ref for the direcotires creation
10
+ def create_blender_directories
11
+ @create_blender_directories ||=
12
+ begin
13
+ dep = directory "/var/lib/blender", :mode => 0700
14
+ dep = directory "/var/lib/blender/logs", :require => dep
15
+ dep = directory "/var/lib/blender/tmp", :require => dep
16
+ end
17
+ end
18
+
19
+ # @return dependency for blender directories
20
+ def builder_deps
21
+ create_blender_directories
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ module Blender::Manifest::Mixer
2
+ # mixes recipe module
3
+ #
4
+ # The purpose is to make the mixing of recipes cleaner and easier on the eyes :)
5
+ # i.e. instead of
6
+ # require 'foo'
7
+ # include Blender::Recipes::Foo
8
+ # require 'bar'
9
+ # include Blender::Recipes::Bar
10
+ # you can just
11
+ # mix :foo, :bar
12
+ # @param [[String, Symbol, Module]] recipes to mix
13
+ def mix(*recipes)
14
+
15
+ recipes.each do |recipe|
16
+
17
+ next if Root.mixed_recipes.include?(recipe)
18
+ Root.mixed_recipes << recipe
19
+
20
+ case recipe
21
+ when String, Symbol
22
+ require recipe.to_s
23
+ mixin = "Blender::Recipes::#{recipe.to_s.camelize}".constantize
24
+ when Module
25
+ mixin = recipe
26
+ else
27
+ raise "Expecting String, Symbol or Module. don't know what do do with #{recipe.inspect}"
28
+ end
29
+
30
+ puts "MIX: #{mixin}"
31
+ ::Root.send :include, mixin
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,94 @@
1
+ # This module encapsulates nodes handeling
2
+ # Nodes can be declared both on a class level and inside a recipe
3
+ # When defining a node an 'id' is associated with its hostname
4
+ # and the node can later be reffered by this id (for example
5
+ # to get its ip)
6
+ module Blender::Manifest::Nodes
7
+
8
+ def self.included(base)
9
+ base.send :extend, self
10
+ end
11
+
12
+ # this holds the map from host ids to hostnames
13
+ @@internal_hostnames = {}
14
+ @@external_hostnames = {}
15
+
16
+ # returns hostname by id or local host's name if the id is nil
17
+ def hostname(id = nil, external = false)
18
+ if id
19
+ (external ? @@external_hostnames : @@internal_hostnames)[id]
20
+ else
21
+ external ? Facter.fqdn : Facter.hostname
22
+ end
23
+ end
24
+
25
+ # returns id of the node we are running at
26
+ # Note: will ONLY return non-nil value after (or during) node definition
27
+ # unless node is forced by environment NODE variable or /etc/node file
28
+ def current_node
29
+ node = ENV['NODE'] ||
30
+ (File.exists?("/etc/node") && File.read("/etc/node").strip) ||
31
+ @@internal_hostnames.index(hostname) ||
32
+ @@external_hostnames.index(hostname(nil, true))
33
+ node && node.to_sym
34
+ end
35
+
36
+ # @return true if we are running on the node with the given `id`
37
+ def current_node?(id)
38
+ current_node == id.to_sym
39
+ end
40
+
41
+ # resolves host name using 'host' executable
42
+ # @return host's IP by its name or nil if not found
43
+ def host_ip(name)
44
+ res = `host #{name}`.split("\n").grep(/has address/).first
45
+ res && res.split.last
46
+ end
47
+
48
+ # define node and conditionally execute code block only on the specific node
49
+ # Note: can be called multiple times without internal_name and external_name parameters
50
+ # in which case will only do the conditional execution
51
+ # @param [Symbol, String] id of the host to define or test for
52
+ # @param [String] internal_name short hostname for the host
53
+ # @param [String] external_name full dns hostname for the host
54
+ # @example
55
+ # node :app, "host5", "host5.serverfarm2.localdomain" do
56
+ # ...
57
+ # end
58
+ #
59
+ # node :app do
60
+ # ...
61
+ # end
62
+ #
63
+ def node(id, internal_name = nil, external_name = internal_name)
64
+ return if false == internal_name # can be used to temporary 'disable' host's definition
65
+ # like:
66
+ # host :app2, false do .. end
67
+ @@internal_hostnames[id] = internal_name if internal_name
68
+ @@external_hostnames[id] = external_name if external_name
69
+
70
+ if block_given? && current_node?(id)
71
+ puts "NODE: #{id} / #{current_node}"
72
+ @node = id
73
+ yield
74
+ end
75
+ end
76
+
77
+ # find out node addr. try to use external, then internal, then the host id to determine ip
78
+ # @param [Symbol, String] id id of the host to resolve
79
+ def addr(id)
80
+ [hostname(id, true).to_s, hostname(id).to_s, id.to_s].each do |name|
81
+ ip = host_ip(name)
82
+ return ip if ip
83
+ end
84
+
85
+ # if all else fails, we should still be able to address the current node
86
+ current_node?(id) ? "127.0.0.1" : nil
87
+ end
88
+
89
+ # same as addr but throws exception if IP can't be found
90
+ def addr!(id)
91
+ addr(id) or raise "Can't find address for '#{id}'"
92
+ end
93
+
94
+ end
@@ -0,0 +1,40 @@
1
+ module Blender::Manifest::Roles
2
+
3
+ def self.included(base)
4
+ base.send :extend, self
5
+ end
6
+
7
+ # A very simple mechanism to define roles
8
+ #
9
+ # Roles to accept can be defined from environment, /etc/roles file
10
+ # or can be explicitly defined like 'roles xxx, yyy'
11
+ # usually the 'roles a,b,c' call will come inside of
12
+ # a `node` block and so will be conditionally executed depending on the
13
+ # running host
14
+
15
+ def current_roles
16
+ @current_roles ||=
17
+ if ENV['ROLES']
18
+ ENV['ROLES'].split(",")
19
+ elsif File.exists?("/etc/roles")
20
+ File.read("/etc/roles").strip.split
21
+ else
22
+ []
23
+ end
24
+ end
25
+
26
+ # ADDS roles to the currently defined roles
27
+ def roles *roles
28
+ current_roles.concat(roles.map {|r| r.to_s})
29
+ end
30
+
31
+ # conditionally runs the code block if the role 'r' is
32
+ # currently defined
33
+ def role r
34
+ if block_given? && current_roles.include?(r.to_s)
35
+ puts "ROLE: #{r}"
36
+ yield
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,38 @@
1
+ require 'ruby-debug'
2
+ $: << File.dirname(__FILE__) # FIXME: remove?
3
+
4
+ module Blender
5
+ module Manifest; end
6
+ module Recipes; end
7
+ end
8
+ require 'init'
9
+ require 'nodes'
10
+ require 'roles'
11
+ require 'mixer'
12
+
13
+ class Root < ::ShadowPuppet::Manifest
14
+ include Blender::Manifest::Init
15
+ include Blender::Manifest::Nodes
16
+ include Blender::Manifest::Roles
17
+
18
+ @@mixed_recipes = []
19
+ def self.mixed_recipes
20
+ @@mixed_recipes
21
+ end
22
+
23
+ def execute_user_recipe
24
+ raise "no RECIPE to execute" unless recipe = ENV['RECIPE']
25
+
26
+ code = open(recipe).read
27
+ instance_eval(code, recipe)
28
+ end
29
+ recipe :execute_user_recipe
30
+ end
31
+
32
+ include Blender::Manifest::Mixer
33
+
34
+ # "standard" recipe directories
35
+ $: << "recipes" << "recipes/astrails" << "lib/astrails/blender/recipes"
36
+
37
+ # add all libs in the ./vendor directory to the path
38
+ $:.concat Dir["vendor/*/"]
@@ -0,0 +1,58 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{server-blender-manifest}
8
+ s.version = "0.0.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Vitaly Kushner"]
12
+ s.date = %q{2010-06-15}
13
+ s.description = %q{This gem is part of the server-blender family (http://astrails.com/opensource/server-blender)
14
+ It contains server-side root manifest implementation for blender recipes. See server-blender for more information.
15
+ }
16
+ s.email = %q{vitaly@astrails.com}
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.markdown"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "LICENSE",
24
+ "README.markdown",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/blender/manifest/init.rb",
28
+ "lib/blender/manifest/mixer.rb",
29
+ "lib/blender/manifest/nodes.rb",
30
+ "lib/blender/manifest/roles.rb",
31
+ "lib/blender/manifest/root.rb",
32
+ "server-blender-manifest.gemspec",
33
+ "spec/spec.opts",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://astrails.com/opensource/server-blender}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.6}
40
+ s.summary = %q{server-side root manifest implementation for server-blender}
41
+ s.test_files = [
42
+ "spec/spec_helper.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
51
+ else
52
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
53
+ end
54
+ else
55
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
56
+ end
57
+ end
58
+
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'server-blender-manifest'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: server-blender
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 8
9
+ version: 0.0.8
10
+ platform: ruby
11
+ authors:
12
+ - Vitaly Kushner
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-15 00:00:00 +03:00
18
+ default_executable: blender
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 9
31
+ version: 1.2.9
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: yard
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ description: |
47
+ Boostrap and manage servers with shadow_puppet
48
+
49
+ Server Blender tries to be a fairly minimal wrapper around shadow_puppet
50
+ http://github.com/railsmachine/shadow_puppet
51
+
52
+ shadow_puppet is a Ruby interface to Puppet's manifests.
53
+ http://reductivelabs.com/products/puppet/
54
+
55
+ email: vitaly@astrails.com
56
+ executables:
57
+ - blender
58
+ extensions: []
59
+
60
+ extra_rdoc_files:
61
+ - LICENSE
62
+ - README.markdown
63
+ files:
64
+ - .braids
65
+ - .document
66
+ - .gitignore
67
+ - LICENSE
68
+ - PLAN
69
+ - README.markdown
70
+ - Rakefile
71
+ - VERSION
72
+ - bin/blender
73
+ - files/bootstrap.sh
74
+ - lib/blender.rb
75
+ - lib/blender/cli/init.rb
76
+ - lib/blender/cli/mix.rb
77
+ - lib/blender/cli/start.rb
78
+ - server-blender.gemspec
79
+ - spec/server-blender_spec.rb
80
+ - spec/spec.opts
81
+ - spec/spec_helper.rb
82
+ - vendor/server-blender-manifests/.gitignore
83
+ - vendor/server-blender-manifests/LICENSE
84
+ - vendor/server-blender-manifests/README.markdown
85
+ - vendor/server-blender-manifests/Rakefile
86
+ - vendor/server-blender-manifests/VERSION
87
+ - vendor/server-blender-manifests/lib/blender/manifest/init.rb
88
+ - vendor/server-blender-manifests/lib/blender/manifest/mixer.rb
89
+ - vendor/server-blender-manifests/lib/blender/manifest/nodes.rb
90
+ - vendor/server-blender-manifests/lib/blender/manifest/roles.rb
91
+ - vendor/server-blender-manifests/lib/blender/manifest/root.rb
92
+ - vendor/server-blender-manifests/server-blender-manifest.gemspec
93
+ - vendor/server-blender-manifests/spec/spec.opts
94
+ - vendor/server-blender-manifests/spec/spec_helper.rb
95
+ has_rdoc: true
96
+ homepage: http://astrails.com/opensource/server-blender
97
+ licenses: []
98
+
99
+ post_install_message:
100
+ rdoc_options:
101
+ - --charset=UTF-8
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ segments:
116
+ - 0
117
+ version: "0"
118
+ requirements: []
119
+
120
+ rubyforge_project:
121
+ rubygems_version: 1.3.6
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: Server provisioning and configuration management tool
125
+ test_files:
126
+ - spec/server-blender_spec.rb
127
+ - spec/spec_helper.rb