dev-lxc 1.7.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|