caterer 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Berksfile +3 -0
- data/Berksfile.lock +0 -0
- data/README.md +138 -2
- data/Vagrantfile +22 -0
- data/bin/cater +9 -0
- data/caterer.gemspec +5 -0
- data/cookbooks/users/recipes/default.rb +18 -0
- data/example/Caterfile +28 -10
- data/example/bootstrap.sh +3 -0
- data/knife.rb +1 -0
- data/lib/caterer/action/base.rb +10 -0
- data/lib/caterer/action/config/validate/image.rb +23 -0
- data/lib/caterer/action/config/validate/provisioner.rb +29 -0
- data/lib/caterer/action/config/validate.rb +10 -0
- data/lib/caterer/action/config.rb +7 -0
- data/lib/caterer/action/provisioner/base.rb +16 -0
- data/lib/caterer/action/provisioner/bootstrap.rb +14 -0
- data/lib/caterer/action/provisioner/cleanup.rb +14 -0
- data/lib/caterer/action/provisioner/prepare.rb +14 -0
- data/lib/caterer/action/provisioner/provision.rb +14 -0
- data/lib/caterer/action/provisioner.rb +11 -0
- data/lib/caterer/action/server/validate/ssh.rb +22 -0
- data/lib/caterer/action/server/validate.rb +9 -0
- data/lib/caterer/action/server.rb +7 -0
- data/lib/caterer/action.rb +9 -0
- data/lib/caterer/actions.rb +48 -0
- data/lib/caterer/command/base.rb +100 -0
- data/lib/caterer/command/bootstrap.rb +28 -0
- data/lib/caterer/command/provision.rb +24 -0
- data/lib/caterer/command/reboot.rb +22 -0
- data/lib/caterer/command/test.rb +9 -2
- data/lib/caterer/command/up.rb +28 -0
- data/lib/caterer/command.rb +6 -1
- data/lib/caterer/commands.rb +6 -1
- data/lib/caterer/communication/rsync.rb +14 -0
- data/lib/caterer/communication/ssh.rb +185 -0
- data/lib/caterer/communication.rb +6 -0
- data/lib/caterer/config/base.rb +24 -11
- data/lib/caterer/config/group.rb +24 -0
- data/lib/caterer/config/image.rb +20 -0
- data/lib/caterer/config/member.rb +14 -0
- data/lib/caterer/config/provision/chef_solo.rb +36 -12
- data/lib/caterer/config/provision.rb +5 -3
- data/lib/caterer/config.rb +5 -1
- data/lib/caterer/environment.rb +38 -12
- data/lib/caterer/provisioner/base.rb +19 -0
- data/lib/caterer/provisioner/chef_solo.rb +150 -0
- data/lib/caterer/provisioner.rb +6 -0
- data/lib/caterer/server.rb +102 -0
- data/lib/caterer/util/ansi_escape_code_remover.rb +34 -0
- data/lib/caterer/util/retryable.rb +25 -0
- data/lib/caterer/util.rb +6 -0
- data/lib/caterer/version.rb +1 -1
- data/lib/caterer.rb +15 -5
- data/lib/templates/provisioner/chef_solo/bootstrap.sh +87 -0
- data/lib/templates/provisioner/chef_solo/solo.erb +3 -0
- metadata +124 -3
- data/lib/caterer/config/role.rb +0 -21
data/.gitignore
CHANGED
data/Berksfile
ADDED
data/Berksfile.lock
ADDED
File without changes
|
data/README.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
# Caterer
|
2
2
|
|
3
|
-
|
3
|
+
Heavily inspired by vagrant, caterer is a remote server configuration tool that caters to your servers using a collaborative, fast, and iterative push model. Caterer supports chef-solo by default.
|
4
|
+
|
5
|
+
## Why?
|
6
|
+
|
7
|
+
Caterer is designed as a workflow-first utility around 3 guiding principles:
|
8
|
+
|
9
|
+
1. Configuration as code.
|
10
|
+
2. Push provisioning.
|
11
|
+
3. Modular provisioner.
|
12
|
+
|
13
|
+
Caterer does not replace chef or puppet, but leverages them to provide a faster iterative approach to live infrastructures. If you're familiar with the vagrant workflow, imagine that your 'boxes' are remote servers and you'll feel right at home.
|
14
|
+
|
15
|
+
The goal of caterer is that an entire infrastructure definition lives within a git repo. An infrastructure developer can open the Caterfile and read the infrastructure like a map. All provisioning recipes or definitions will live within this repo, and infrastructure developers can interate repidly to provide a hot infrastructure.
|
4
16
|
|
5
17
|
## Installation
|
6
18
|
|
@@ -18,7 +30,131 @@ Or install it yourself as:
|
|
18
30
|
|
19
31
|
## Usage
|
20
32
|
|
21
|
-
|
33
|
+
### Caterfile
|
34
|
+
|
35
|
+
Caterer loads a Caterfile from the current directory. A Caterfile defines your infrastructure in a centralized, familiar ruby dsl. A Caterfile essentially creates a library of images that can be aggregated and applied to live servers.
|
36
|
+
|
37
|
+
### Images
|
38
|
+
|
39
|
+
An image is a configuration construct that defines the end state of the machine after that image has been applied. An image requires a provisioner.
|
40
|
+
|
41
|
+
### Provisioner
|
42
|
+
|
43
|
+
A provisioner is the tool that will provision a server to meet the end requirements of an image. Currently only chef-solo is supported.
|
44
|
+
|
45
|
+
### Member
|
46
|
+
|
47
|
+
A member is an optional configuration for servers. Storing live server credentials in a version controlled repo is not suitable for many infrastructures, but is there for your convenience if you want it.
|
48
|
+
|
49
|
+
### Group
|
50
|
+
|
51
|
+
A group is a simply way of grouping images or members to provide agrregate funcionality in a simple, concise way.
|
52
|
+
|
53
|
+
## Example
|
54
|
+
|
55
|
+
### Caterfile
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
Caterer.configure do |config|
|
59
|
+
|
60
|
+
config.image :basic do |image|
|
61
|
+
image.provision :chef_solo do |chef|
|
62
|
+
chef.cookbooks_path = ['cookbooks'] # default
|
63
|
+
chef.add_recipe 'ruby'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
config.image :rails do |image|
|
68
|
+
image.provision :chef_solo do |chef|
|
69
|
+
chef.bootstrap_script = 'script/bootstrap'
|
70
|
+
chef.cookbooks_path = ['cookbooks'] # default
|
71
|
+
chef.add_recipe 'ruby'
|
72
|
+
chef.add_recipe 'mysql::server'
|
73
|
+
chef.add_recipe 'mysql::client'
|
74
|
+
chef.json = {
|
75
|
+
"ruby" => {
|
76
|
+
"gems" => ['mysql2']
|
77
|
+
}
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
config.member :m1 do |member|
|
83
|
+
member.images = [:basic]
|
84
|
+
member.host = "192.168.1.101"
|
85
|
+
member.password = 'samIam'
|
86
|
+
end
|
87
|
+
|
88
|
+
config.group :oven do |group|
|
89
|
+
|
90
|
+
group.images = [:basic, :rails]
|
91
|
+
group.user = 'root' # optional
|
92
|
+
group.password = 'password' # optional
|
93
|
+
|
94
|
+
# optional member configuration
|
95
|
+
group.member :oven1 do |m|
|
96
|
+
m.host = "192.168.1.100"
|
97
|
+
end
|
98
|
+
|
99
|
+
group.member :oven2 do |m|
|
100
|
+
m.host = "192.168.1.101"
|
101
|
+
m.password = 'samIam'
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
### Command Line
|
110
|
+
|
111
|
+
Provision a server with a basic image (image defined in Caterfile)
|
112
|
+
|
113
|
+
```bash
|
114
|
+
cater provision -i basic HOST
|
115
|
+
```
|
116
|
+
|
117
|
+
Provision a server with multiple images (images defined in Caterfile)
|
118
|
+
|
119
|
+
```bash
|
120
|
+
cater provision -i basic,rails HOST
|
121
|
+
```
|
122
|
+
|
123
|
+
Provision a server with a group (group defined in Caterfile)
|
124
|
+
|
125
|
+
```bash
|
126
|
+
cater provision -g oven HOST
|
127
|
+
```
|
128
|
+
|
129
|
+
Provision a server from a member defined in Caterfile
|
130
|
+
|
131
|
+
```bash
|
132
|
+
cater provision m1
|
133
|
+
```
|
134
|
+
|
135
|
+
Provision a server from a group member
|
136
|
+
|
137
|
+
```bash
|
138
|
+
cater provision oven::oven1
|
139
|
+
```
|
140
|
+
|
141
|
+
Provision multiple servers from members defined in Caterfile
|
142
|
+
|
143
|
+
```bash
|
144
|
+
cater provision m1,oven::oven1,oven::oven2
|
145
|
+
```
|
146
|
+
|
147
|
+
Bootstrap a server
|
148
|
+
|
149
|
+
```bash
|
150
|
+
cater bootstrap -i basic HOST
|
151
|
+
```
|
152
|
+
|
153
|
+
Boostrap and provision a server
|
154
|
+
|
155
|
+
```bash
|
156
|
+
cater up -i basic HOST
|
157
|
+
```
|
22
158
|
|
23
159
|
## Contributing
|
24
160
|
|
data/Vagrantfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# require 'berkshelf/vagrant'
|
4
|
+
require 'vagrant-vbguest' unless defined? VagrantVbguest::Config
|
5
|
+
|
6
|
+
Vagrant::Config.run do |config|
|
7
|
+
|
8
|
+
config.berkshelf.config_path = './knife.rb'
|
9
|
+
|
10
|
+
config.vm.box = "precise64"
|
11
|
+
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
|
12
|
+
config.vm.customize ["modifyvm", :id, "--cpus", 1, "--memory", 512]
|
13
|
+
config.vm.network :hostonly, "33.33.33.10"
|
14
|
+
config.vm.share_folder("v-root", "/vagrant", ".")
|
15
|
+
config.vbguest.auto_update = true
|
16
|
+
|
17
|
+
config.vm.provision :chef_solo do |chef|
|
18
|
+
chef.cookbooks_path = ['cookbooks']
|
19
|
+
chef.add_recipe 'users'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/bin/cater
CHANGED
@@ -28,6 +28,15 @@ else
|
|
28
28
|
opts[:ui_class] = Vli::UI::Colored
|
29
29
|
end
|
30
30
|
|
31
|
+
# strip out a custom config file and set it into the env opts
|
32
|
+
if ARGV.include? "-c"
|
33
|
+
index = ARGV.index '-c'
|
34
|
+
value = ARGV[index + 1]
|
35
|
+
opts[:custom_config] = value
|
36
|
+
ARGV.delete('-c')
|
37
|
+
ARGV.delete(value)
|
38
|
+
end
|
39
|
+
|
31
40
|
env = Caterer::Environment.new(opts)
|
32
41
|
|
33
42
|
env.load!
|
data/caterer.gemspec
CHANGED
@@ -15,6 +15,11 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.add_dependency 'log4r'
|
16
16
|
gem.add_dependency 'activesupport'
|
17
17
|
gem.add_dependency 'vli'
|
18
|
+
gem.add_dependency 'net-ssh'
|
19
|
+
gem.add_dependency 'net-scp'
|
20
|
+
gem.add_dependency 'tilt'
|
21
|
+
gem.add_dependency 'oj'
|
22
|
+
gem.add_dependency 'multi_json', '>= 1.3'
|
18
23
|
|
19
24
|
gem.files = `git ls-files`.split($/)
|
20
25
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
package "build-essential" do
|
3
|
+
action :nothing
|
4
|
+
end.run_action(:install)
|
5
|
+
|
6
|
+
package 'whois'
|
7
|
+
chef_gem 'ruby-shadow'
|
8
|
+
|
9
|
+
[['bert', 'password'], ['ernie', 'password'], ['tylerflint', 'password']].each do |u, pass|
|
10
|
+
user u do
|
11
|
+
supports :manage_home => true
|
12
|
+
home "/home/#{u}"
|
13
|
+
gid "admin"
|
14
|
+
shell "/bin/bash"
|
15
|
+
password `echo #{pass} | mkpasswd -s -m sha-512`.chomp
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
data/example/Caterfile
CHANGED
@@ -1,25 +1,43 @@
|
|
1
1
|
Caterer.configure do |config|
|
2
2
|
|
3
|
-
config.
|
3
|
+
config.image :basic do |image|
|
4
|
+
image.provision :chef_solo do |chef|
|
5
|
+
chef.cookbooks_path = ['cookbooks'] # default
|
6
|
+
chef.add_recipe 'ruby'
|
7
|
+
end
|
8
|
+
end
|
4
9
|
|
5
|
-
|
10
|
+
config.image :rails do |image|
|
11
|
+
image.provision :chef_solo do |chef|
|
12
|
+
chef.bootstrap_script = 'script/bootstrap'
|
13
|
+
chef.cookbooks_path = ['cookbooks'] # default
|
6
14
|
chef.add_recipe 'ruby'
|
7
15
|
chef.add_recipe 'mysql::server'
|
8
16
|
chef.add_recipe 'mysql::client'
|
9
17
|
chef.json = {
|
10
18
|
"ruby" => {
|
11
19
|
"gems" => ['args_parser', 'mysql2']
|
12
|
-
},
|
13
|
-
"mysql" => {
|
14
|
-
"server_root_password" => "root",
|
15
|
-
"bind_address" => '127.0.0.1',
|
16
|
-
"client" => {
|
17
|
-
"packages" => ["mysql-client", "libmysqlclient-dev"]
|
18
|
-
}
|
19
20
|
}
|
20
21
|
}
|
21
22
|
end
|
23
|
+
end
|
24
|
+
|
25
|
+
config.group :oven do |group|
|
26
|
+
|
27
|
+
group.images = [:basic, :rails]
|
28
|
+
group.user = 'root'
|
29
|
+
group.password = 'password'
|
30
|
+
|
31
|
+
group.member :oven1 do |m|
|
32
|
+
m.host = "192.168.1.100"
|
33
|
+
end
|
34
|
+
|
35
|
+
group.member :oven2 do |m|
|
36
|
+
m.host = "192.168.1.101"
|
37
|
+
m.password = 'samIam'
|
38
|
+
end
|
22
39
|
|
23
40
|
end
|
24
41
|
|
25
|
-
end
|
42
|
+
end
|
43
|
+
|
data/knife.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
#whatev
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Caterer
|
2
|
+
module Action
|
3
|
+
module Config
|
4
|
+
module Validate
|
5
|
+
class Image < Base
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
# check to ensure the image exists
|
9
|
+
image = env[:config].images[env[:image]]
|
10
|
+
|
11
|
+
if not image
|
12
|
+
env[:ui].error "image ':#{env[:image]}' is not defined"
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Caterer
|
2
|
+
module Action
|
3
|
+
module Config
|
4
|
+
module Validate
|
5
|
+
class Provisioner < Base
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
provisioner = env[:config].images[env[:image]].provisioner
|
9
|
+
|
10
|
+
if not provisioner
|
11
|
+
env[:ui].error "provisioner for image ':#{env[:image]}' is not defined"
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
if errors = provisioner.errors
|
16
|
+
errors.each do |key, val|
|
17
|
+
env[:ui].error "image :#{env[:image]} provisioner error -> #{key} #{val}"
|
18
|
+
end
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
module Caterer
|
4
|
+
module Action
|
5
|
+
module Provisioner
|
6
|
+
class Base < Action::Base
|
7
|
+
|
8
|
+
def provisioner(env)
|
9
|
+
config = env[:config].images[env[:image]].provisioner
|
10
|
+
"Caterer::Provisioner::#{config.name.to_s.classify}".constantize.new(env[:server], config)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Caterer
|
2
|
+
module Action
|
3
|
+
module Provisioner
|
4
|
+
autoload :Base, 'caterer/action/provisioner/base'
|
5
|
+
autoload :Bootstrap, 'caterer/action/provisioner/bootstrap'
|
6
|
+
autoload :Cleanup, 'caterer/action/provisioner/cleanup'
|
7
|
+
autoload :Prepare, 'caterer/action/provisioner/prepare'
|
8
|
+
autoload :Provision, 'caterer/action/provisioner/provision'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Caterer
|
2
|
+
module Action
|
3
|
+
module Server
|
4
|
+
module Validate
|
5
|
+
class SSH < Base
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
ready = env[:server].ssh.ready?
|
9
|
+
|
10
|
+
if not ready
|
11
|
+
env[:ui].error "unable to ssh into #{env[:server].host}"
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Caterer
|
2
|
+
module Action
|
3
|
+
autoload :Base, 'caterer/action/base'
|
4
|
+
autoload :Config, 'caterer/action/config'
|
5
|
+
autoload :Runner, 'caterer/action/runner'
|
6
|
+
autoload :Provisioner, 'caterer/action/provisioner'
|
7
|
+
autoload :Server, 'caterer/action/server'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# actions
|
2
|
+
Caterer.actions.register(:validate) do
|
3
|
+
Vli::Action::Builder.new do
|
4
|
+
use Caterer::Action::Config::Validate::Image
|
5
|
+
use Caterer::Action::Config::Validate::Provisioner
|
6
|
+
use Caterer::Action::Server::Validate::SSH
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
Caterer.actions.register(:prepare) do
|
11
|
+
Vli::Action::Builder.new do
|
12
|
+
use Caterer::Action::Provisioner::Prepare
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Caterer.actions.register(:cleanup) do
|
17
|
+
Vli::Action::Builder.new do
|
18
|
+
use Caterer::Action::Provisioner::Cleanup
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Caterer.actions.register(:bootstrap) do
|
23
|
+
Vli::Action::Builder.new do
|
24
|
+
use Caterer.actions.get(:validate)
|
25
|
+
use Caterer.actions.get(:prepare)
|
26
|
+
use Caterer::Action::Provisioner::Bootstrap
|
27
|
+
use Caterer.actions.get(:cleanup)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Caterer.actions.register(:provision) do
|
32
|
+
Vli::Action::Builder.new do
|
33
|
+
use Caterer.actions.get(:validate)
|
34
|
+
use Caterer.actions.get(:prepare)
|
35
|
+
use Caterer::Action::Provisioner::Provision
|
36
|
+
use Caterer.actions.get(:cleanup)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Caterer.actions.register(:up) do
|
41
|
+
Vli::Action::Builder.new do
|
42
|
+
use Caterer.actions.get(:validate)
|
43
|
+
use Caterer.actions.get(:prepare)
|
44
|
+
use Caterer::Action::Provisioner::Bootstrap
|
45
|
+
use Caterer::Action::Provisioner::Provision
|
46
|
+
use Caterer.actions.get(:cleanup)
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Caterer
|
2
|
+
module Command
|
3
|
+
class Base < Vli::Command::Base
|
4
|
+
|
5
|
+
def parse_options(opts=nil, options={}, force_argv=true)
|
6
|
+
opts ||= OptionParser.new
|
7
|
+
opts.separator ""
|
8
|
+
opts.on("-c CONFIG", 'assumes Caterfile in current directory')
|
9
|
+
opts.separator ""
|
10
|
+
opts.on("-u USER", "--user USER", 'assumes current username') do |u|
|
11
|
+
options[:user] = u
|
12
|
+
end
|
13
|
+
opts.on('-p PASSWORD', '--password PASSWORD', 'assumes key') do |p|
|
14
|
+
options[:pass] = p
|
15
|
+
end
|
16
|
+
opts.on('-P PORT', '--port PORT', 'assumes 22') do |p|
|
17
|
+
options[:port] = p
|
18
|
+
end
|
19
|
+
opts.on('-i IMAGE', '--image IMAGE', 'corresponds to a image in Caterfile') do |i|
|
20
|
+
options[:image] = i
|
21
|
+
end
|
22
|
+
opts.on('-g GROUP', '--group GROUP', 'corresponds to a group in Caterfile') do |g|
|
23
|
+
options[:group] = g
|
24
|
+
end
|
25
|
+
opts.separator ""
|
26
|
+
|
27
|
+
begin
|
28
|
+
argv = super(opts)
|
29
|
+
raise if force_argv and (not argv or argv.length == 0)
|
30
|
+
argv
|
31
|
+
rescue
|
32
|
+
safe_puts(opts.help)
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def with_target_servers(argv, options={})
|
39
|
+
target_servers(argv, options).each do |server|
|
40
|
+
yield server if block_given?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def target_servers(argv, options={})
|
45
|
+
@servers ||= begin
|
46
|
+
servers = []
|
47
|
+
|
48
|
+
argv.first.split(",").each do |host|
|
49
|
+
|
50
|
+
if group = @env.config.groups[host.to_sym]
|
51
|
+
group.members.each do |member|
|
52
|
+
servers << init_server(group, member, options)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
|
56
|
+
if not host.match /::/
|
57
|
+
host = "default::#{host}"
|
58
|
+
end
|
59
|
+
|
60
|
+
g, m = host.split "::"
|
61
|
+
group = nil
|
62
|
+
member = nil
|
63
|
+
|
64
|
+
if group = @env.config.groups[g.to_sym]
|
65
|
+
member = group.members[m.to_sym]
|
66
|
+
end
|
67
|
+
|
68
|
+
servers << init_server(group, member, options.merge(:host => m))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
servers
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def init_server(group=nil, member=nil, options={})
|
77
|
+
|
78
|
+
group ||= Config::Group.new
|
79
|
+
member ||= Config::Member.new
|
80
|
+
|
81
|
+
opts = {}
|
82
|
+
opts[:alias] = member.name
|
83
|
+
opts[:user] = options[:user] || member.user || group.user
|
84
|
+
opts[:pass] = options[:pass] || member.password || group.password
|
85
|
+
opts[:host] = member.host || options[:host]
|
86
|
+
opts[:port] = options[:port] || member.port
|
87
|
+
opts[:images] = image_list(options) || member.images || group.images
|
88
|
+
|
89
|
+
Server.new(@env, opts)
|
90
|
+
end
|
91
|
+
|
92
|
+
def image_list(options={})
|
93
|
+
if images = options[:image]
|
94
|
+
images.split(',').map(&:to_sym)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|