dev-lxc 1.7.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +230 -452
- data/dev-lxc.gemspec +2 -1
- data/lib/dev-lxc/cli.rb +174 -309
- data/lib/dev-lxc/cluster.rb +772 -113
- data/lib/dev-lxc/container.rb +1 -107
- data/lib/dev-lxc/server.rb +107 -420
- data/lib/dev-lxc/version.rb +1 -1
- data/lib/dev-lxc.rb +72 -76
- metadata +18 -4
data/dev-lxc.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = DevLXC::VERSION
|
9
9
|
spec.authors = ["Jeremiah Snapp"]
|
10
10
|
spec.email = ["jeremiah@getchef.com"]
|
11
|
-
spec.description = %q{A tool for
|
11
|
+
spec.description = %q{A tool for building Chef server clusters using LXC containers}
|
12
12
|
spec.summary = spec.description
|
13
13
|
spec.licenses = "Apache2"
|
14
14
|
spec.homepage = "https://github.com/jeremiahsnapp/dev-lxc"
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake", "~> 0"
|
23
|
+
spec.add_runtime_dependency "mixlib-install", "~> 0"
|
23
24
|
spec.add_runtime_dependency "thor", "~> 0"
|
24
25
|
spec.add_runtime_dependency "ruby-lxc", "~> 1.2.0"
|
25
26
|
end
|
data/lib/dev-lxc/cli.rb
CHANGED
@@ -6,59 +6,6 @@ module DevLXC::CLI
|
|
6
6
|
class DevLXC < Thor
|
7
7
|
|
8
8
|
no_commands{
|
9
|
-
def validate_cluster_config(cluster_config)
|
10
|
-
hostnames = Array.new
|
11
|
-
mounts = Array.new
|
12
|
-
packages = Array.new
|
13
|
-
ssh_keys = Array.new
|
14
|
-
|
15
|
-
mounts.concat(cluster_config['mounts']) unless cluster_config['mounts'].nil?
|
16
|
-
ssh_keys.concat(cluster_config['ssh-keys']) unless cluster_config['ssh-keys'].nil?
|
17
|
-
|
18
|
-
%w(chef-server analytics compliance supermarket adhoc).each do |server_type|
|
19
|
-
unless cluster_config[server_type].nil?
|
20
|
-
hostnames << cluster_config[server_type]['api_fqdn'] unless cluster_config[server_type]['api_fqdn'].nil?
|
21
|
-
hostnames << cluster_config[server_type]['analytics_fqdn'] unless cluster_config[server_type]['analytics_fqdn'].nil?
|
22
|
-
hostnames.concat(cluster_config[server_type]['servers'].keys) unless cluster_config[server_type]['servers'].nil?
|
23
|
-
mounts.concat(cluster_config[server_type]['mounts']) unless cluster_config[server_type]['mounts'].nil?
|
24
|
-
packages.concat(cluster_config[server_type]['packages'].values) unless cluster_config[server_type]['packages'].nil?
|
25
|
-
ssh_keys.concat(cluster_config[server_type]['ssh-keys']) unless cluster_config[server_type]['ssh-keys'].nil?
|
26
|
-
end
|
27
|
-
end
|
28
|
-
unless hostnames.empty?
|
29
|
-
hostnames.each do |hostname|
|
30
|
-
unless hostname.end_with?(".lxc")
|
31
|
-
puts "ERROR: Hostname #{hostname} does not end with '.lxc'."
|
32
|
-
exit 1
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
unless mounts.empty?
|
37
|
-
mounts.each do |mount|
|
38
|
-
unless File.exists?(mount.split.first)
|
39
|
-
puts "ERROR: Mount source #{mount.split.first} does not exist."
|
40
|
-
exit 1
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
unless packages.empty?
|
45
|
-
packages.each do |package|
|
46
|
-
unless File.exists?(package)
|
47
|
-
puts "ERROR: Package #{package} does not exist."
|
48
|
-
exit 1
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
unless ssh_keys.empty?
|
53
|
-
ssh_keys.each do |ssh_key|
|
54
|
-
unless File.exists?(ssh_key)
|
55
|
-
puts "ERROR: SSH key #{ssh_key} does not exist."
|
56
|
-
exit 1
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
9
|
def get_cluster(config_file=nil)
|
63
10
|
config_file ||= "dev-lxc.yml"
|
64
11
|
if ! File.exists?(config_file)
|
@@ -67,162 +14,57 @@ module DevLXC::CLI
|
|
67
14
|
exit 1
|
68
15
|
end
|
69
16
|
cluster_config = YAML.load(IO.read(config_file))
|
70
|
-
validate_cluster_config(cluster_config)
|
71
17
|
::DevLXC::Cluster.new(cluster_config)
|
72
18
|
end
|
73
19
|
|
74
|
-
def match_server_name_regex(server_name_regex)
|
75
|
-
get_cluster(options[:config]).servers.select { |s| s.server.name =~ /#{server_name_regex}/ }
|
76
|
-
end
|
77
|
-
|
78
20
|
def print_elapsed_time(elapsed_time)
|
79
21
|
printf "dev-lxc is finished. (%im %.2fs)\n", elapsed_time / 60, elapsed_time % 60
|
80
22
|
end
|
81
23
|
}
|
82
24
|
|
83
|
-
desc "create [
|
25
|
+
desc "create-base-container [BASE_CONTAINER_NAME]", "Create a base container"
|
84
26
|
option :options, :aliases => "-o", :desc => "Specify additional options for the lxc create"
|
85
|
-
def
|
27
|
+
def create_base_container(base_container_name=nil)
|
86
28
|
start_time = Time.now
|
87
|
-
|
88
|
-
if
|
89
|
-
|
90
|
-
print_table
|
91
|
-
selection = ask("Which
|
92
|
-
|
29
|
+
base_container_names = %w(b-ubuntu-1204 b-ubuntu-1404 b-ubuntu-1604 b-centos-5 b-centos-6 b-centos-7)
|
30
|
+
if base_container_name.nil? || ! base_container_names.include?(base_container_name)
|
31
|
+
base_container_names_with_index = base_container_names.map.with_index{ |a, i| [i+1, *a]}
|
32
|
+
print_table base_container_names_with_index
|
33
|
+
selection = ask("Which base container do you want to create?", :limited_to => base_container_names_with_index.map{|c| c[0].to_s})
|
34
|
+
base_container_name = base_container_names[selection.to_i - 1]
|
93
35
|
end
|
94
|
-
::DevLXC.
|
95
|
-
puts
|
96
|
-
print_elapsed_time(Time.now - start_time)
|
97
|
-
end
|
98
|
-
|
99
|
-
desc "install-chef-client [CONTAINER_NAME]", "Install Chef Client in container"
|
100
|
-
option :version, :aliases => "-v", :desc => "Specify the version of Chef Client to install"
|
101
|
-
def install_chef_client(container_name)
|
102
|
-
start_time = Time.now
|
103
|
-
container = ::DevLXC::Container.new(container_name)
|
104
|
-
container.install_chef_client(options[:version])
|
36
|
+
::DevLXC.create_base_container(base_container_name, options[:options])
|
105
37
|
puts
|
106
38
|
print_elapsed_time(Time.now - start_time)
|
107
39
|
end
|
108
40
|
|
109
|
-
desc "
|
110
|
-
option :chef_server_url, :aliases => "-s", :desc => "Specify the URL of the Chef Server"
|
111
|
-
option :validation_client_name, :aliases => "-u", :desc => "Specify the name of the validation client"
|
112
|
-
option :validation_key, :aliases => "-k", :desc => "Specify the path to the validation key"
|
113
|
-
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
114
|
-
def configure_chef_client(container_name)
|
115
|
-
start_time = Time.now
|
116
|
-
chef_server_url = options[:chef_server_url]
|
117
|
-
validation_client_name = options[:validation_client_name]
|
118
|
-
validation_key = options[:validation_key]
|
119
|
-
if chef_server_url.nil? && validation_client_name.nil? && validation_key.nil?
|
120
|
-
cluster = get_cluster(options[:config])
|
121
|
-
chef_server_bootstrap_backend = ::DevLXC::Container.new(cluster.chef_server_bootstrap_backend, cluster.lxc_config_path)
|
122
|
-
unless chef_server_bootstrap_backend.defined?
|
123
|
-
puts "ERROR: Can not copy validation key because Chef Server '#{chef_server_bootstrap_backend.name}' is not created."
|
124
|
-
exit 1
|
125
|
-
end
|
126
|
-
chef_server_url = "https://#{cluster.api_fqdn}/organizations/demo"
|
127
|
-
validation_client_name = 'demo-validator'
|
128
|
-
validation_key = "#{chef_server_bootstrap_backend.config_item('lxc.rootfs')}/root/chef-repo/.chef/demo-validator.pem"
|
129
|
-
elsif chef_server_url.nil? || validation_client_name.nil? || validation_key.nil?
|
130
|
-
puts "ERROR: All of the --chef-server-url, --validation-client-name and --validation-key options must be set or left unset. Do not set only some of these options."
|
131
|
-
exit 1
|
132
|
-
end
|
133
|
-
container = ::DevLXC::Container.new(container_name)
|
134
|
-
container.configure_chef_client(chef_server_url, validation_client_name, validation_key)
|
135
|
-
puts
|
136
|
-
print_elapsed_time(Time.now - start_time)
|
137
|
-
end
|
138
|
-
|
139
|
-
desc "bootstrap-container [BASE_CONTAINER_NAME] [CONTAINER_NAME]", "Bootstrap Chef Client in container"
|
140
|
-
option :version, :aliases => "-v", :desc => "Specify the version of Chef Client to install"
|
141
|
-
option :run_list, :aliases => "-r", :desc => "Specify the Chef Client run_list"
|
142
|
-
option :chef_server_url, :aliases => "-s", :desc => "Specify the URL of the Chef Server"
|
143
|
-
option :validation_client_name, :aliases => "-u", :desc => "Specify the name of the validation client"
|
144
|
-
option :validation_key, :aliases => "-k", :desc => "Specify the path to the validation key"
|
145
|
-
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
146
|
-
def bootstrap_container(base_container_name=nil, container_name)
|
147
|
-
start_time = Time.now
|
148
|
-
chef_server_url = options[:chef_server_url]
|
149
|
-
validation_client_name = options[:validation_client_name]
|
150
|
-
validation_key = options[:validation_key]
|
151
|
-
if chef_server_url.nil? && validation_client_name.nil? && validation_key.nil?
|
152
|
-
cluster = get_cluster(options[:config])
|
153
|
-
chef_server_bootstrap_backend = ::DevLXC::Container.new(cluster.chef_server_bootstrap_backend, cluster.lxc_config_path)
|
154
|
-
unless chef_server_bootstrap_backend.defined?
|
155
|
-
puts "ERROR: Can not copy validation key because Chef Server '#{chef_server_bootstrap_backend.name}' is not created."
|
156
|
-
exit 1
|
157
|
-
end
|
158
|
-
chef_server_url = "https://#{cluster.api_fqdn}/organizations/demo"
|
159
|
-
validation_client_name = 'demo-validator'
|
160
|
-
validation_key = "#{chef_server_bootstrap_backend.config_item('lxc.rootfs')}/root/chef-repo/.chef/demo-validator.pem"
|
161
|
-
elsif chef_server_url.nil? || validation_client_name.nil? || validation_key.nil?
|
162
|
-
puts "ERROR: All of the --chef-server-url, --validation-client-name and --validation-key options must be set or left unset. Do not set only some of these options."
|
163
|
-
exit 1
|
164
|
-
end
|
165
|
-
container = ::DevLXC::Container.new(container_name)
|
166
|
-
container.bootstrap_container(base_container_name, options[:version], options[:run_list], chef_server_url, validation_client_name, validation_key)
|
167
|
-
puts
|
168
|
-
print_elapsed_time(Time.now - start_time)
|
169
|
-
end
|
170
|
-
|
171
|
-
desc "init [UNIQUE_STRING]", "Provide a cluster config file with optional uniqueness in server names and FQDNs"
|
172
|
-
option :open_source, :type => :boolean, :desc => "Standalone Old Open Source Chef Server"
|
173
|
-
option :tiered_chef, :type => :boolean, :desc => "Tiered Chef Server"
|
41
|
+
desc "init", "Provide a cluster config file"
|
174
42
|
option :chef, :type => :boolean, :desc => "Standalone Chef Server"
|
43
|
+
option :chef_tier, :type => :boolean, :desc => "Chef Server using Tier topology with one backend"
|
44
|
+
option :chef_backend, :type => :boolean, :desc => "Chef Server using Chef Backend HA topology with three backends"
|
45
|
+
option :nodes, :type => :boolean, :desc => "Node Servers"
|
175
46
|
option :analytics, :type => :boolean, :desc => "Analytics Server"
|
176
47
|
option :compliance, :type => :boolean, :desc => "Compliance Server"
|
177
48
|
option :supermarket, :type => :boolean, :desc => "Supermarket Server"
|
178
49
|
option :adhoc, :type => :boolean, :desc => "Adhoc Servers"
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
## platform_image_options can be set to provide additional arguments to the LXC create command
|
185
|
-
## reference arg examples: https://github.com/lxc/lxc/blob/lxc-2.0.0/templates/lxc-download.in#L200-L207
|
186
|
-
#platform_image_options: --no-validate
|
50
|
+
option :append, :aliases => "-a", :type => :boolean, :desc => "Do not generate the global config header"
|
51
|
+
option :filename, :aliases => "-f", :desc => "Write generated content to FILE rather than standard output."
|
52
|
+
def init
|
53
|
+
header = %Q(# base_container must be the name of an existing container
|
54
|
+
base_container: b-ubuntu-1404
|
187
55
|
|
188
|
-
|
189
|
-
mounts:
|
190
|
-
- /root/dev root/dev
|
56
|
+
# list any host directories you want mounted into the servers
|
57
|
+
#mounts:
|
58
|
+
# - /root/dev root/dev
|
191
59
|
|
192
|
-
|
60
|
+
# list any SSH public keys you want added to /home/dev-lxc/.ssh/authorized_keys
|
193
61
|
#ssh-keys:
|
194
62
|
# - /root/dev/clusters/id_rsa.pub
|
195
63
|
|
196
|
-
|
197
|
-
)
|
198
|
-
|
199
|
-
chef_packages_path = "/root/dev/chef-packages"
|
200
|
-
open_source_package = "server: #{chef_packages_path}/osc/chef-server_11.1.6-1_amd64.deb"
|
201
|
-
chef_server_package = "server: #{chef_packages_path}/cs/chef-server-core_12.6.0-1_amd64.deb"
|
202
|
-
manage_package = "manage: #{chef_packages_path}/manage/chef-manage_2.3.0-1_amd64.deb"
|
203
|
-
reporting_package = "reporting: #{chef_packages_path}/reporting/opscode-reporting_1.5.6-1_amd64.deb"
|
204
|
-
push_jobs_server_package = "push-jobs-server: #{chef_packages_path}/push-jobs-server/opscode-push-jobs-server_1.1.6-1_amd64.deb"
|
205
|
-
analytics_package = "analytics: #{chef_packages_path}/analytics/opscode-analytics_1.4.0-1_amd64.deb"
|
206
|
-
compliance_package = "compliance: #{chef_packages_path}/compliance/chef-compliance_1.1.9-1_amd64.deb"
|
207
|
-
supermarket_package = "supermarket: #{chef_packages_path}/supermarket/supermarket_2.5.2-1_amd64.deb"
|
208
|
-
|
209
|
-
open_source_config = %Q(
|
210
|
-
chef-server:
|
211
|
-
packages:
|
212
|
-
#{open_source_package}
|
213
|
-
api_fqdn: chef.lxc
|
214
|
-
topology: open-source
|
215
|
-
servers:
|
216
|
-
osc-chef.lxc:
|
217
|
-
ipaddress: 10.0.3.200
|
64
|
+
# DHCP reserved (static) IPs must be selected from the IP range 10.0.3.150 - 254
|
218
65
|
)
|
219
|
-
|
66
|
+
chef_tier_config = %Q(
|
220
67
|
chef-server:
|
221
|
-
packages:
|
222
|
-
#{chef_server_package}
|
223
|
-
#{manage_package}
|
224
|
-
#{reporting_package}
|
225
|
-
#{push_jobs_server_package}
|
226
68
|
topology: tier
|
227
69
|
api_fqdn: chef.lxc
|
228
70
|
servers:
|
@@ -230,44 +72,53 @@ chef-server:
|
|
230
72
|
ipaddress: 10.0.3.201
|
231
73
|
role: backend
|
232
74
|
bootstrap: true
|
75
|
+
products:
|
76
|
+
chef-server:
|
77
|
+
push-jobs-server:
|
78
|
+
reporting:
|
233
79
|
chef-fe1.lxc:
|
234
80
|
ipaddress: 10.0.3.202
|
235
81
|
role: frontend
|
82
|
+
products:
|
83
|
+
chef-server:
|
84
|
+
manage:
|
85
|
+
push-jobs-server:
|
86
|
+
reporting:
|
236
87
|
)
|
237
88
|
chef_config = %Q(
|
238
89
|
chef-server:
|
239
|
-
packages:
|
240
|
-
#{chef_server_package}
|
241
|
-
#{manage_package}
|
242
|
-
#{reporting_package}
|
243
|
-
#{push_jobs_server_package}
|
244
90
|
servers:
|
245
91
|
chef.lxc:
|
246
92
|
ipaddress: 10.0.3.203
|
93
|
+
products:
|
94
|
+
chef-server:
|
95
|
+
manage:
|
96
|
+
push-jobs-server:
|
97
|
+
reporting:
|
247
98
|
)
|
248
99
|
analytics_config = %Q(
|
249
100
|
analytics:
|
250
|
-
packages:
|
251
|
-
#{analytics_package}
|
252
101
|
servers:
|
253
102
|
analytics.lxc:
|
254
103
|
ipaddress: 10.0.3.204
|
104
|
+
products:
|
105
|
+
analytics:
|
255
106
|
)
|
256
107
|
compliance_config = %Q(
|
257
108
|
compliance:
|
258
|
-
packages:
|
259
|
-
#{compliance_package}
|
260
109
|
servers:
|
261
110
|
compliance.lxc:
|
262
111
|
ipaddress: 10.0.3.205
|
112
|
+
products:
|
113
|
+
compliance:
|
263
114
|
)
|
264
115
|
supermarket_config = %Q(
|
265
116
|
supermarket:
|
266
|
-
packages:
|
267
|
-
#{supermarket_package}
|
268
117
|
servers:
|
269
118
|
supermarket.lxc:
|
270
119
|
ipaddress: 10.0.3.206
|
120
|
+
products:
|
121
|
+
supermarket:
|
271
122
|
)
|
272
123
|
adhoc_config = %Q(
|
273
124
|
adhoc:
|
@@ -275,67 +126,95 @@ adhoc:
|
|
275
126
|
adhoc.lxc:
|
276
127
|
ipaddress: 10.0.3.207
|
277
128
|
)
|
278
|
-
|
279
|
-
|
129
|
+
chef_backend_config = %Q(
|
130
|
+
chef-backend:
|
131
|
+
api_fqdn: chef.lxc
|
132
|
+
servers:
|
133
|
+
chef-backend1.lxc:
|
134
|
+
ipaddress: 10.0.3.208
|
135
|
+
role: backend
|
136
|
+
leader: true
|
137
|
+
products:
|
138
|
+
chef-backend:
|
139
|
+
channel: current
|
140
|
+
chef-backend2.lxc:
|
141
|
+
ipaddress: 10.0.3.209
|
142
|
+
role: backend
|
143
|
+
products:
|
144
|
+
chef-backend:
|
145
|
+
channel: current
|
146
|
+
chef-backend3.lxc:
|
147
|
+
ipaddress: 10.0.3.210
|
148
|
+
role: backend
|
149
|
+
products:
|
150
|
+
chef-backend:
|
151
|
+
channel: current
|
152
|
+
chef-frontend1.lxc:
|
153
|
+
ipaddress: 10.0.3.211
|
154
|
+
role: frontend
|
155
|
+
bootstrap: true
|
156
|
+
products:
|
157
|
+
chef-server:
|
158
|
+
manage:
|
159
|
+
)
|
160
|
+
nodes_config = %Q(
|
161
|
+
nodes:
|
162
|
+
servers:
|
163
|
+
node-1.lxc:
|
164
|
+
products:
|
165
|
+
chef:
|
166
|
+
)
|
167
|
+
config = ""
|
168
|
+
config += header unless options[:append]
|
280
169
|
config += chef_config if options[:chef]
|
281
|
-
config +=
|
170
|
+
config += chef_tier_config if options[:chef_tier]
|
282
171
|
config += analytics_config if options[:analytics]
|
283
172
|
config += compliance_config if options[:compliance]
|
284
173
|
config += supermarket_config if options[:supermarket]
|
285
174
|
config += adhoc_config if options[:adhoc]
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
config.gsub!(/ #{server_name}:/, " #{unique_string}#{server_name}:")
|
294
|
-
end
|
295
|
-
end
|
296
|
-
end
|
175
|
+
config += chef_backend_config if options[:chef_backend]
|
176
|
+
config += nodes_config if options[:nodes]
|
177
|
+
if options[:filename]
|
178
|
+
mode = options[:append] ? 'a' : 'w'
|
179
|
+
IO.write(options[:filename], config, mode: mode)
|
180
|
+
else
|
181
|
+
puts config
|
297
182
|
end
|
298
|
-
puts config
|
299
|
-
end
|
300
|
-
|
301
|
-
desc "global-status", "Show status of all dev-lxc images and servers"
|
302
|
-
def global_status
|
303
|
-
containers = Array.new
|
304
|
-
LXC::list_containers({config_path: '/var/lib/dev-lxc'}).map { |c| containers << ::DevLXC::Container.new(c, '/var/lib/dev-lxc').status }
|
305
|
-
max_container_name_length = containers.max_by { |c| c['name'].length }['name'].length unless containers.empty?
|
306
|
-
containers.each { |c| printf "%#{max_container_name_length}s %-15s %s\n", c['name'], c['state'], c['ip_addresses'] }
|
307
183
|
end
|
308
184
|
|
309
185
|
desc "status [SERVER_NAME_REGEX]", "Show status of servers"
|
310
186
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
311
187
|
def status(server_name_regex=nil)
|
312
188
|
cluster = get_cluster(options[:config])
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
189
|
+
if cluster.config['chef-server'][:topology] == "tier" && cluster.config['chef-server'][:fqdn]
|
190
|
+
printf "Chef Server FQDN: %s\n\n", cluster.config['chef-server'][:fqdn]
|
191
|
+
end
|
192
|
+
if cluster.config['chef-backend'][:fqdn]
|
193
|
+
printf "Chef Server FQDN: %s\n\n", cluster.config['chef-backend'][:fqdn]
|
194
|
+
end
|
195
|
+
if cluster.config['analytics'][:topology] == "tier" && cluster.config['analytics'][:fqdn]
|
196
|
+
printf "Analytics FQDN: %s\n\n", cluster.config['analytics'][:fqdn]
|
197
|
+
end
|
318
198
|
servers = Array.new
|
319
|
-
|
199
|
+
cluster.get_sorted_servers(server_name_regex).map { |s| servers << s.status }
|
320
200
|
max_server_name_length = servers.max_by { |s| s['name'].length }['name'].length unless servers.empty?
|
321
|
-
servers.
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
puts realpath.compact
|
201
|
+
servers.each_with_index do |s, server_index|
|
202
|
+
printf "%-#{max_server_name_length}s %-15s %s\n", s['name'], s['state'].upcase, s['ip_addresses']
|
203
|
+
server = cluster.get_server(s['name'])
|
204
|
+
server.snapshot_list.each do |snapname, snaptime, snap_comment|
|
205
|
+
printf " |_ %s %s %s\n", snapname, snaptime, snap_comment
|
206
|
+
end
|
207
|
+
puts if server_index + 1 < servers.length
|
208
|
+
end
|
330
209
|
end
|
331
210
|
|
332
211
|
desc "attach [SERVER_NAME_REGEX]", "Attach the terminal to a single server"
|
333
212
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
334
213
|
def attach(server_name_regex)
|
335
|
-
servers =
|
214
|
+
servers = get_cluster(options[:config]).get_sorted_servers(server_name_regex)
|
336
215
|
if servers.length > 1
|
337
216
|
puts "ERROR: The following servers matched '#{server_name_regex}'"
|
338
|
-
servers.map { |s| puts " #{s.
|
217
|
+
servers.map { |s| puts " #{s.name}" }
|
339
218
|
puts " Please specify a single server to attach to"
|
340
219
|
exit 1
|
341
220
|
elsif servers.empty?
|
@@ -343,9 +222,9 @@ adhoc:
|
|
343
222
|
puts " Please specify a single server to attach to"
|
344
223
|
exit 1
|
345
224
|
end
|
346
|
-
|
347
|
-
|
348
|
-
puts "ERROR: Server '#{
|
225
|
+
container = servers.first.container
|
226
|
+
if !container.defined? || !container.running?
|
227
|
+
puts "ERROR: Server '#{container.name}' is not running"
|
349
228
|
exit 1
|
350
229
|
end
|
351
230
|
attach_opts = {
|
@@ -354,7 +233,7 @@ adhoc:
|
|
354
233
|
extra_env_vars: ["LANG=en_US.UTF-8", "TERM=linux", "HOME=#{ENV['HOME']}"]
|
355
234
|
}
|
356
235
|
shell = ENV['SHELL']
|
357
|
-
|
236
|
+
container.attach(attach_opts) { system(shell) }
|
358
237
|
end
|
359
238
|
|
360
239
|
desc "chef-repo", "Creates a chef-repo in the current directory using files from the cluster's backend /root/chef-repo"
|
@@ -365,48 +244,11 @@ adhoc:
|
|
365
244
|
get_cluster(options[:config]).chef_repo(options[:force], options[:pivotal])
|
366
245
|
end
|
367
246
|
|
368
|
-
desc "list-images [SERVER_NAME_REGEX]", "List of each servers' images created during the build process"
|
369
|
-
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
370
|
-
def list_images(server_name_regex=nil)
|
371
|
-
lxc_config_path = get_cluster(options[:config]).lxc_config_path
|
372
|
-
images = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Array.new } }
|
373
|
-
match_server_name_regex(server_name_regex).each do |s|
|
374
|
-
images[s.platform_image_name][s.shared_image_name] << s.server.name
|
375
|
-
end
|
376
|
-
images.each_with_index do |(platform_name, shared), images_index|
|
377
|
-
shared.each_with_index do |(shared_name, final), shared_index|
|
378
|
-
printf "Platform: %27s %s\n", (LXC::Container.new(platform_name, lxc_config_path).defined? ? "Created" : "Not Created"), platform_name
|
379
|
-
unless shared_name.empty?
|
380
|
-
puts "|"
|
381
|
-
printf "\\_ Shared: %26s %s\n", (LXC::Container.new(shared_name, lxc_config_path).defined? ? "Created" : "Not Created"), shared_name
|
382
|
-
end
|
383
|
-
final.each_with_index do |final_name, final_index|
|
384
|
-
puts " |"
|
385
|
-
unique_name = "u-#{final_name}"
|
386
|
-
printf " \\_ Unique: %23s %s\n", (LXC::Container.new(unique_name, lxc_config_path).defined? ? "Created" : "Not Created"), unique_name
|
387
|
-
|
388
|
-
shared_connector = (final_index + 1 < final.length ? "|" : " ")
|
389
|
-
|
390
|
-
custom_name = "c-#{final_name}"
|
391
|
-
if LXC::Container.new(custom_name, lxc_config_path).defined?
|
392
|
-
printf " #{shared_connector} \\_ Custom: %20s %s\n", "Created", custom_name
|
393
|
-
custom_spacing = " "
|
394
|
-
final_width = 11
|
395
|
-
else
|
396
|
-
final_width = 14
|
397
|
-
end
|
398
|
-
printf " #{shared_connector} #{custom_spacing}\\_ Final Server: %#{final_width}s %s\n", (LXC::Container.new(final_name, lxc_config_path).defined? ? "Created" : "Not Created"), final_name
|
399
|
-
end
|
400
|
-
puts if (shared_index + 1 < shared.length) || (images_index + 1 < images.length)
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
247
|
desc "run-command [SERVER_NAME_REGEX] [COMMAND]", "Runs a command in each server"
|
406
248
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
407
249
|
def run_command(server_name_regex=nil, command)
|
408
250
|
start_time = Time.now
|
409
|
-
|
251
|
+
get_cluster(options[:config]).get_sorted_servers(server_name_regex).each { |s| s.run_command(command); puts }
|
410
252
|
print_elapsed_time(Time.now - start_time)
|
411
253
|
end
|
412
254
|
|
@@ -414,7 +256,8 @@ adhoc:
|
|
414
256
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
415
257
|
def up(server_name_regex=nil)
|
416
258
|
start_time = Time.now
|
417
|
-
|
259
|
+
get_cluster(options[:config]).up(server_name_regex)
|
260
|
+
puts
|
418
261
|
print_elapsed_time(Time.now - start_time)
|
419
262
|
end
|
420
263
|
|
@@ -422,53 +265,75 @@ adhoc:
|
|
422
265
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
423
266
|
def halt(server_name_regex=nil)
|
424
267
|
start_time = Time.now
|
425
|
-
|
268
|
+
get_cluster(options[:config]).get_sorted_servers(server_name_regex).reverse_each { |s| s.stop; puts }
|
426
269
|
print_elapsed_time(Time.now - start_time)
|
427
270
|
end
|
428
271
|
|
429
|
-
desc "snapshot [SERVER_NAME_REGEX]", "
|
272
|
+
desc "snapshot [SERVER_NAME_REGEX]", "Manage a cluster's snapshots"
|
273
|
+
option :comment, :aliases => "-c", :desc => "Add snapshot comment"
|
430
274
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
431
|
-
option :
|
275
|
+
option :destroy, :aliases => "-d", :desc => "Destroy snapshot - use ALL to destroy all snapshots"
|
276
|
+
option :list, :aliases => "-l", :type => :boolean, :desc => "List snapshots"
|
277
|
+
option :restore, :aliases => "-r", :desc => "Restore snapshots"
|
432
278
|
def snapshot(server_name_regex=nil)
|
433
279
|
start_time = Time.now
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
280
|
+
servers = get_cluster(options[:config]).get_sorted_servers(server_name_regex)
|
281
|
+
if options[:list]
|
282
|
+
servers.each_with_index do |s, server_index|
|
283
|
+
puts s.name
|
284
|
+
s.snapshot_list.each do |snapname, snaptime, snap_comment|
|
285
|
+
printf " |_ %s %s %s\n", snapname, snaptime, snap_comment
|
286
|
+
end
|
287
|
+
puts if server_index + 1 < servers.length
|
288
|
+
end
|
289
|
+
return
|
290
|
+
elsif options[:destroy]
|
291
|
+
snapname = options[:destroy] == 'destroy' ? "LAST" : options[:destroy]
|
292
|
+
servers.each { |s| s.snapshot_destroy(snapname); puts }
|
293
|
+
elsif options[:restore]
|
294
|
+
running_servers = Array.new
|
295
|
+
servers.each do |s|
|
296
|
+
running_servers << s.name if s.container.running?
|
297
|
+
end
|
298
|
+
unless running_servers.empty?
|
299
|
+
puts "ERROR: Aborting snapshot restore because the following servers are running"
|
300
|
+
puts running_servers
|
301
|
+
exit 1
|
302
|
+
end
|
303
|
+
snapname = options[:restore] == 'restore' ? "LAST" : options[:restore]
|
304
|
+
servers.each { |s| s.snapshot_restore(snapname); puts }
|
305
|
+
else
|
306
|
+
running_servers = Array.new
|
307
|
+
servers.each do |s|
|
308
|
+
running_servers << s.name if s.container.running?
|
309
|
+
end
|
310
|
+
unless running_servers.empty?
|
311
|
+
puts "ERROR: Aborting snapshot because the following servers are running"
|
312
|
+
puts running_servers
|
313
|
+
exit 1
|
314
|
+
end
|
315
|
+
servers.each { |s| s.snapshot(options[:comment]); puts }
|
451
316
|
end
|
452
|
-
match_server_name_regex(server_name_regex).each { |s| s.snapshot(options[:force]); puts }
|
453
317
|
print_elapsed_time(Time.now - start_time)
|
454
318
|
end
|
455
319
|
|
456
320
|
desc "destroy [SERVER_NAME_REGEX]", "Destroy servers"
|
457
321
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
458
|
-
option :
|
459
|
-
option :unique, :aliases => "-u", :type => :boolean, :desc => "Also destroy the unique images"
|
460
|
-
option :shared, :aliases => "-s", :type => :boolean, :desc => "Also destroy the shared images"
|
461
|
-
option :platform, :aliases => "-p", :type => :boolean, :desc => "Also destroy the platform images"
|
322
|
+
option :force, :aliases => "-f", :type => :boolean, :desc => "Destroy servers without confirmation"
|
462
323
|
def destroy(server_name_regex=nil)
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
324
|
+
servers = get_cluster(options[:config]).get_sorted_servers(server_name_regex)
|
325
|
+
if servers.empty?
|
326
|
+
puts "No matching server names were found"
|
327
|
+
exit
|
328
|
+
end
|
329
|
+
unless options[:force]
|
330
|
+
confirmation_string = String.new
|
331
|
+
servers.reverse_each { |s| confirmation_string += "#{s.name}\n" }
|
332
|
+
confirmation_string += "Are you sure you want to destroy these servers? (y/N)\n"
|
333
|
+
return unless yes?(confirmation_string)
|
471
334
|
end
|
335
|
+
start_time = Time.now
|
336
|
+
servers.reverse_each { |s| s.destroy; puts }
|
472
337
|
print_elapsed_time(Time.now - start_time)
|
473
338
|
end
|
474
339
|
|