dev-lxc 0.6.4 → 1.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 +179 -48
- data/bin/dev-lxc +4 -1
- data/lib/dev-lxc/cli.rb +154 -24
- data/lib/dev-lxc/cluster.rb +6 -25
- data/lib/dev-lxc/container.rb +143 -13
- data/lib/dev-lxc/server.rb +44 -48
- data/lib/dev-lxc/version.rb +1 -1
- data/lib/dev-lxc.rb +7 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9b7bd69da896ea6a750b5f4ac463fcf23de242e
|
4
|
+
data.tar.gz: 638d5b30c5c74a4983f763614141cb63d4218931
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 107c68008b67e58ac0deca62b502e696dee71d3cfd5984c8a60a2bad3034ba75e821d67a41e9bd5d24efb3c02dc6f313fb105c0ebfa7cca11611aec8386fb7d9
|
7
|
+
data.tar.gz: df9768afa06905a197c75a95c8df997152445f52db38f51b51278d3fb540337719407525f9dc9483eb0049297f67b894fe9fd79cee4d191c24583cfce6d6ed97
|
data/README.md
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
# dev-lxc
|
2
2
|
|
3
|
-
A tool for creating Chef Server clusters
|
3
|
+
A tool for creating Chef Server clusters and Chef Analytics clusters using LXC containers.
|
4
4
|
|
5
5
|
Using [ruby-lxc](https://github.com/lxc/ruby-lxc) it builds a standalone Chef Server or
|
6
6
|
tier Chef Server cluster composed of a backend and multiple frontends with round-robin
|
7
|
-
DNS resolution. It
|
8
|
-
|
7
|
+
DNS resolution. It can also build a standalone or tier Chef Analytics server and connect
|
8
|
+
it with the Chef Server.
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
dev-lxc also has commands to manipulate Chef node containers. For example, dev-lxc can bootstrap a
|
11
|
+
container by installing Chef Client, configuring it for a Chef Server and running a specified run_list.
|
12
|
+
|
13
|
+
The dev-lxc tool is well suited as a tool for support related work, customized cluster builds
|
14
|
+
for demo purposes, as well as general experimentation and exploration of Chef products
|
12
15
|
|
13
16
|
### Features
|
14
17
|
|
@@ -59,6 +62,23 @@ If you aren't familiar with using containers please read this introduction.
|
|
59
62
|
Be sure that you configure the `mounts` and `packages` lists in `dev-lxc.yml` to match your
|
60
63
|
particular environment.
|
61
64
|
|
65
|
+
The package paths in dev-lxc's example configs assume that the packages are stored in the
|
66
|
+
following directory structure in the dev-lxc-platform VM. I recommend creating that
|
67
|
+
directory structure in the physical workstation and configuring dev-lxc-platform's `.knife.yml`
|
68
|
+
to mount the structure into `/dev-shared` in the dev-lxc-platform VM.
|
69
|
+
|
70
|
+
```
|
71
|
+
/dev-shared/chef-packages/
|
72
|
+
├── analytics
|
73
|
+
├── cs
|
74
|
+
├── ec
|
75
|
+
├── manage
|
76
|
+
├── osc
|
77
|
+
├── push-jobs-server
|
78
|
+
├── reporting
|
79
|
+
└── sync
|
80
|
+
```
|
81
|
+
|
62
82
|
## Update dev-lxc gem
|
63
83
|
|
64
84
|
Run `gem update dev-lxc` inside the Vagrant VM platform to ensure you have the latest version.
|
@@ -130,27 +150,9 @@ dev-lxc init tier > dev-lxc.yml
|
|
130
150
|
List of each servers' images created during the build process.
|
131
151
|
|
132
152
|
```
|
133
|
-
dev-lxc
|
134
|
-
```
|
135
|
-
|
136
|
-
#### Start cluster
|
137
|
-
|
138
|
-
Starting the cluster the first time takes awhile since it has a lot to build.
|
139
|
-
|
140
|
-
The tool automatically creates images at appropriate times so future creation of the
|
141
|
-
cluster's servers is very quick.
|
142
|
-
|
143
|
-
```
|
144
|
-
dev-lxc up
|
153
|
+
dev-lxc list-images
|
145
154
|
```
|
146
155
|
|
147
|
-
A test org, user, knife.rb and keys are automatically created in
|
148
|
-
the bootstrap backend server in `/root/chef-repo/.chef` for testing purposes.
|
149
|
-
|
150
|
-
The `knife-opc` plugin is installed in the embedded ruby environment of the
|
151
|
-
Private Chef and Enterprise Chef server to facilitate the creation of the test
|
152
|
-
org and user.
|
153
|
-
|
154
156
|
#### Cluster status
|
155
157
|
|
156
158
|
Run the following command to see the status of the cluster.
|
@@ -172,12 +174,69 @@ Analytics: https://analytics.lxc
|
|
172
174
|
analytics-fe1.lxc running 10.0.3.207
|
173
175
|
```
|
174
176
|
|
177
|
+
#### cluster-view, tks, tls commands
|
178
|
+
|
179
|
+
The dev-lxc-platform comes with some commands that create and manage helpful
|
180
|
+
tmux/byobu sessions to more easily see the state of a cluster.
|
181
|
+
|
182
|
+
Running the `cluster-view` command in the same directory as a `dev-lxc.yml` file
|
183
|
+
creates a tmux/byobu session with the same name as the cluster's directory.
|
184
|
+
`cluster-view` can also be run with the parent directory of a `dev-lxc.yml` file
|
185
|
+
as the first argument and `cluster-view` will change to that directory before
|
186
|
+
creating the tmux/byobu session.
|
187
|
+
|
188
|
+
The session's first window is named "cluster".
|
189
|
+
|
190
|
+
The left side is for running dev-lxc commands.
|
191
|
+
|
192
|
+
The right side is made up of three vertically stacked panes with each pane's content
|
193
|
+
updating every 0.5 seconds.
|
194
|
+
|
195
|
+
* Top - system's memory usage provided by `free -h`
|
196
|
+
* Middle - cluster's status provided by `dev-lxc status`
|
197
|
+
* Bottom - list of the cluster's images provided by `dev-lxc list-images`
|
198
|
+
|
199
|
+
The session's second window is named "shell". It opens in the same directory as the
|
200
|
+
cluster's `dev-lxc.yml` file.
|
201
|
+
|
202
|
+
The `tls` and `tks` commands are really aliases.
|
203
|
+
|
204
|
+
`tls` is an alias for `tmux list-sessions` and is used to see what tmux/byobu sessions
|
205
|
+
are running.
|
206
|
+
|
207
|
+
`tks` is an alias for `tmux kill-session -t` and is used to kill tmux/byobu sessions.
|
208
|
+
When specifying the session to be killed you only need as many characters of the session
|
209
|
+
name that are required to make the name unique among the list of running sessions.
|
210
|
+
|
211
|
+
I recommend switching to a different running tmux/byobu session before killing the current
|
212
|
+
tmux/byobu session. Otherwise you will need to reattach to the remaining tmux/byobu session.
|
213
|
+
Use the keyboard shortcuts Alt-Up/Down to easily switch between tmux/byobu sessions.
|
214
|
+
|
215
|
+
#### Start cluster
|
216
|
+
|
217
|
+
Starting the cluster the first time takes awhile since it has a lot to build.
|
218
|
+
|
219
|
+
The tool automatically creates images at appropriate times so future creation of the
|
220
|
+
cluster's servers is very quick.
|
221
|
+
|
222
|
+
```
|
223
|
+
dev-lxc up
|
224
|
+
```
|
225
|
+
|
226
|
+
A test org, user, knife.rb and keys are automatically created in
|
227
|
+
the bootstrap backend server in `/root/chef-repo/.chef` for testing purposes.
|
228
|
+
|
229
|
+
The `knife-opc` plugin is installed in the embedded ruby environment of the
|
230
|
+
Private Chef and Enterprise Chef server to facilitate the creation of the test
|
231
|
+
org and user.
|
232
|
+
|
175
233
|
#### Create chef-repo
|
176
234
|
|
177
235
|
Create a local chef-repo with appropriate knife.rb and pem files.
|
178
236
|
|
179
|
-
|
180
|
-
|
237
|
+
Use the `-p` option to also get pivotal.pem and pivotal.rb files.
|
238
|
+
|
239
|
+
Use the `-f` option to overwrite existing knife.rb and pivotal.rb files.
|
181
240
|
|
182
241
|
```
|
183
242
|
dev-lxc chef-repo
|
@@ -222,11 +281,19 @@ emacs $(dev-lxc abspath chef /etc/opscode/chef-server.rb)
|
|
222
281
|
|
223
282
|
#### Run arbitrary commands in each server
|
224
283
|
|
225
|
-
After modifying the chef-server.rb you could use the
|
284
|
+
After modifying the chef-server.rb you could use the run-command subcommand to tell the backend and
|
226
285
|
frontend servers to run `chef-server-ctl reconfigure`.
|
227
286
|
|
228
287
|
```
|
229
|
-
dev-lxc
|
288
|
+
dev-lxc run-command chef 'chef-server-ctl reconfigure'
|
289
|
+
```
|
290
|
+
|
291
|
+
#### Attach the terminal to a server
|
292
|
+
|
293
|
+
Attach the terminal to a server in the cluster that matches the REGEX pattern given.
|
294
|
+
|
295
|
+
```
|
296
|
+
dev-lxc attach chef-be
|
230
297
|
```
|
231
298
|
|
232
299
|
#### Make a snapshot of the servers
|
@@ -254,6 +321,15 @@ images if you want to build them from scratch.
|
|
254
321
|
dev-lxc destroy -c -u -s
|
255
322
|
```
|
256
323
|
|
324
|
+
#### Global status of all dev-lxc images and servers
|
325
|
+
|
326
|
+
Use the `global-status` command to see the status of all dev-lxc images and servers stored in dev-lxc's
|
327
|
+
default LXC config_path `/var/lib/dev-lxc`.
|
328
|
+
|
329
|
+
```
|
330
|
+
dev-lxc global-status
|
331
|
+
```
|
332
|
+
|
257
333
|
#### Use commands against specific servers
|
258
334
|
You can also run most of these commands against a set of servers by specifying a regular expression
|
259
335
|
that matches a set of server names.
|
@@ -266,7 +342,73 @@ For example, to only start the Chef Servers named `chef-be.lxc` and `chef-fe1.lx
|
|
266
342
|
you can run the following command.
|
267
343
|
|
268
344
|
```
|
269
|
-
dev-lxc up
|
345
|
+
dev-lxc up chef
|
346
|
+
```
|
347
|
+
|
348
|
+
### Managing Node Containers
|
349
|
+
|
350
|
+
#### Manually Create a Platform Image
|
351
|
+
|
352
|
+
Platform images can be used for purposes other than building clusters. For example, they can
|
353
|
+
be used as Chef nodes for testing purposes.
|
354
|
+
|
355
|
+
You can see a menu of platform images this tool can create by using the following command.
|
356
|
+
|
357
|
+
```
|
358
|
+
dev-lxc create
|
359
|
+
```
|
360
|
+
|
361
|
+
The initial creation of platform images can take awhile so let's go ahead and start creating
|
362
|
+
an Ubuntu 14.04 image now.
|
363
|
+
|
364
|
+
```
|
365
|
+
dev-lxc create p-ubuntu-1404
|
366
|
+
```
|
367
|
+
|
368
|
+
#### Install Chef Client in a Container
|
369
|
+
|
370
|
+
Use the `-v` option to specify a particular version of Chef Client.
|
371
|
+
|
372
|
+
Use `-v latest` or leave out the `-v` option to install the latest version of Chef Client.
|
373
|
+
|
374
|
+
For example, install the latest 11.x version of Chef Client.
|
375
|
+
|
376
|
+
```
|
377
|
+
dev-lxc install-chef-client test-node.lxc -v 11
|
378
|
+
```
|
379
|
+
|
380
|
+
#### Configure Chef Client in a Container
|
381
|
+
|
382
|
+
Use the `-s`, `-u`, `-k` options to set `chef_server_url`, `validation_client_name` and
|
383
|
+
`validation_key` in a container's `/etc/chef/client.rb` and copy the validator's key to
|
384
|
+
`/etc/chef/validation.pem`.
|
385
|
+
|
386
|
+
Or leave the options empty and it will default to using values from the cluster defined
|
387
|
+
in `dev-lxc.yml`.
|
388
|
+
|
389
|
+
```
|
390
|
+
dev-lxc config-chef-client test-node.lxc
|
391
|
+
```
|
392
|
+
|
393
|
+
#### Bootstrap Chef Client in a Container
|
394
|
+
|
395
|
+
Specifying a `BASE_CONTAINER_NAME` will clone the base container into a new container
|
396
|
+
and bootstrap it. If no `BASE_CONTAINER_NAME` is given then the container to be bootstrapped
|
397
|
+
needs to already exist.
|
398
|
+
|
399
|
+
Use the `-v` option to specify a particular version of Chef Client.
|
400
|
+
|
401
|
+
Use the `-s`, `-u`, `-k` options to set `chef_server_url`, `validation_client_name` and
|
402
|
+
`validation_key` in a container's `/etc/chef/client.rb` and copy the validator's key to
|
403
|
+
`/etc/chef/validation.pem`.
|
404
|
+
|
405
|
+
Or leave the options empty and it will default to using values from the cluster defined
|
406
|
+
in `dev-lxc.yml`.
|
407
|
+
|
408
|
+
Use the `-r` option to specify the run_list for chef-client to use.
|
409
|
+
|
410
|
+
```
|
411
|
+
dev-lxc bootstrap-container test-node.lxc -r my_run_list
|
270
412
|
```
|
271
413
|
|
272
414
|
### Using the dev-lxc library
|
@@ -282,7 +424,7 @@ DevLXC::CLI::DevLXC.start
|
|
282
424
|
ARGV = [ 'status' ] # show status of all servers
|
283
425
|
DevLXC::CLI::DevLXC.start
|
284
426
|
|
285
|
-
ARGV = [ '
|
427
|
+
ARGV = [ 'run-command', 'uptime' ] # run `uptime` in all servers
|
286
428
|
DevLXC::CLI::DevLXC.start
|
287
429
|
|
288
430
|
ARGV = [ 'destroy' ] # destroy all servers
|
@@ -302,6 +444,7 @@ server.start # start chef-fe1.lxc
|
|
302
444
|
server.status # show status of chef-fe1.lxc
|
303
445
|
server.run_command("chef-server-ctl reconfigure") # run command in chef-fe1.lxc
|
304
446
|
server.stop # stop chef-fe1.lxc
|
447
|
+
server.destroy # destroy chef-fe1.lxc
|
305
448
|
```
|
306
449
|
|
307
450
|
## Cluster Config Files
|
@@ -471,6 +614,12 @@ Images are then cloned using the btrfs filesystem to very quickly provide a ligh
|
|
471
614
|
of the image. This clone is either used to build the next image in the build process or the final
|
472
615
|
container that will actually be run.
|
473
616
|
|
617
|
+
By default, the cluster's images and final server containers are all stored in `/var/lib/dev-lxc`
|
618
|
+
so they don't clutter the containers stored in the default LXC config_path `/var/lib/lxc`.
|
619
|
+
|
620
|
+
The cluster's LXC config_path can be configured by setting `lxc_config_path` at the top of the
|
621
|
+
`dev-lxc.yml` file to the desired directory.
|
622
|
+
|
474
623
|
There are four image categories.
|
475
624
|
|
476
625
|
1. Platform
|
@@ -555,24 +704,6 @@ Of course, you can also just use the standard LXC commands to destroy any contai
|
|
555
704
|
lxc-destroy -n [NAME]
|
556
705
|
```
|
557
706
|
|
558
|
-
### Manually Create a Platform Image
|
559
|
-
|
560
|
-
Platform images can be used for purposes other than building clusters. For example, they can
|
561
|
-
be used as Chef nodes for testing purposes.
|
562
|
-
|
563
|
-
You can see a menu of platform images this tool can create by using the following command.
|
564
|
-
|
565
|
-
```
|
566
|
-
dev-lxc create
|
567
|
-
```
|
568
|
-
|
569
|
-
The initial creation of platform images can take awhile so let's go ahead and start creating
|
570
|
-
an Ubuntu 14.04 image now.
|
571
|
-
|
572
|
-
```
|
573
|
-
dev-lxc create p-ubuntu-1404
|
574
|
-
```
|
575
|
-
|
576
707
|
## Contributing
|
577
708
|
|
578
709
|
1. Fork it
|
data/bin/dev-lxc
CHANGED
data/lib/dev-lxc/cli.rb
CHANGED
@@ -6,24 +6,28 @@ module DevLXC::CLI
|
|
6
6
|
class DevLXC < Thor
|
7
7
|
|
8
8
|
no_commands{
|
9
|
-
def get_cluster(
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
puts "ERROR: Cluster config file `config` does not exist."
|
9
|
+
def get_cluster(config_file=nil)
|
10
|
+
config_file ||= "dev-lxc.yml"
|
11
|
+
if ! File.exists?(config_file)
|
12
|
+
puts "ERROR: Cluster config file '#{config_file}' does not exist."
|
14
13
|
puts " Create a `./dev-lxc.yml` file or specify the path using `--config`."
|
15
14
|
exit 1
|
16
15
|
end
|
17
|
-
::DevLXC::Cluster.new(YAML.load(IO.read(
|
16
|
+
::DevLXC::Cluster.new(YAML.load(IO.read(config_file)))
|
18
17
|
end
|
19
18
|
|
20
19
|
def match_server_name_regex(server_name_regex)
|
21
20
|
get_cluster(options[:config]).servers.select { |s| s.server.name =~ /#{server_name_regex}/ }
|
22
21
|
end
|
22
|
+
|
23
|
+
def print_elapsed_time(elapsed_time)
|
24
|
+
printf "dev-lxc is finished. (%im %.2fs)\n", elapsed_time / 60, elapsed_time % 60
|
25
|
+
end
|
23
26
|
}
|
24
27
|
|
25
28
|
desc "create [PLATFORM_IMAGE_NAME]", "Create a platform image"
|
26
29
|
def create(platform_image_name=nil)
|
30
|
+
start_time = Time.now
|
27
31
|
platform_image_names = %w(p-ubuntu-1204 p-ubuntu-1404 p-centos-5 p-centos-6)
|
28
32
|
if platform_image_name.nil? || ! platform_image_names.include?(platform_image_name)
|
29
33
|
platform_image_names_with_index = platform_image_names.map.with_index{ |a, i| [i+1, *a]}
|
@@ -32,6 +36,80 @@ module DevLXC::CLI
|
|
32
36
|
platform_image_name = platform_image_names[selection.to_i - 1]
|
33
37
|
end
|
34
38
|
::DevLXC.create_platform_image(platform_image_name)
|
39
|
+
puts
|
40
|
+
print_elapsed_time(Time.now - start_time)
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "install-chef-client [CONTAINER_NAME]", "Install Chef Client in container"
|
44
|
+
option :version, :aliases => "-v", :desc => "Specify the version of Chef Client to install"
|
45
|
+
def install_chef_client(container_name)
|
46
|
+
start_time = Time.now
|
47
|
+
container = ::DevLXC::Container.new(container_name)
|
48
|
+
container.install_chef_client(options[:version])
|
49
|
+
puts
|
50
|
+
print_elapsed_time(Time.now - start_time)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "configure-chef-client [CONTAINER_NAME]", "Configure Chef Client in container"
|
54
|
+
option :chef_server_url, :aliases => "-s", :desc => "Specify the URL of the Chef Server"
|
55
|
+
option :validation_client_name, :aliases => "-u", :desc => "Specify the name of the validation client"
|
56
|
+
option :validation_key, :aliases => "-k", :desc => "Specify the path to the validation key"
|
57
|
+
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
58
|
+
def configure_chef_client(container_name)
|
59
|
+
start_time = Time.now
|
60
|
+
chef_server_url = options[:chef_server_url]
|
61
|
+
validation_client_name = options[:validation_client_name]
|
62
|
+
validation_key = options[:validation_key]
|
63
|
+
if chef_server_url.nil? && validation_client_name.nil? && validation_key.nil?
|
64
|
+
cluster = get_cluster(options[:config])
|
65
|
+
chef_server_bootstrap_backend = ::DevLXC::Container.new(cluster.chef_server_bootstrap_backend, cluster.lxc_config_path)
|
66
|
+
unless chef_server_bootstrap_backend.defined?
|
67
|
+
puts "ERROR: Can not copy validation key because Chef Server '#{chef_server_bootstrap_backend.name}' is not created."
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
chef_server_url = "https://#{cluster.api_fqdn}/organizations/ponyville"
|
71
|
+
validation_client_name = 'ponyville-validator'
|
72
|
+
validation_key = "#{chef_server_bootstrap_backend.config_item('lxc.rootfs')}/root/chef-repo/.chef/ponyville-validator.pem"
|
73
|
+
elsif chef_server_url.nil? || validation_client_name.nil? || validation_key.nil?
|
74
|
+
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."
|
75
|
+
exit 1
|
76
|
+
end
|
77
|
+
container = ::DevLXC::Container.new(container_name)
|
78
|
+
container.configure_chef_client(chef_server_url, validation_client_name, validation_key)
|
79
|
+
puts
|
80
|
+
print_elapsed_time(Time.now - start_time)
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "bootstrap-container [BASE_CONTAINER_NAME] [CONTAINER_NAME]", "Bootstrap Chef Client in container"
|
84
|
+
option :version, :aliases => "-v", :desc => "Specify the version of Chef Client to install"
|
85
|
+
option :run_list, :aliases => "-r", :desc => "Specify the Chef Client run_list"
|
86
|
+
option :chef_server_url, :aliases => "-s", :desc => "Specify the URL of the Chef Server"
|
87
|
+
option :validation_client_name, :aliases => "-u", :desc => "Specify the name of the validation client"
|
88
|
+
option :validation_key, :aliases => "-k", :desc => "Specify the path to the validation key"
|
89
|
+
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
90
|
+
def bootstrap_container(base_container_name=nil, container_name)
|
91
|
+
start_time = Time.now
|
92
|
+
chef_server_url = options[:chef_server_url]
|
93
|
+
validation_client_name = options[:validation_client_name]
|
94
|
+
validation_key = options[:validation_key]
|
95
|
+
if chef_server_url.nil? && validation_client_name.nil? && validation_key.nil?
|
96
|
+
cluster = get_cluster(options[:config])
|
97
|
+
chef_server_bootstrap_backend = ::DevLXC::Container.new(cluster.chef_server_bootstrap_backend, cluster.lxc_config_path)
|
98
|
+
unless chef_server_bootstrap_backend.defined?
|
99
|
+
puts "ERROR: Can not copy validation key because Chef Server '#{chef_server_bootstrap_backend.name}' is not created."
|
100
|
+
exit 1
|
101
|
+
end
|
102
|
+
chef_server_url = "https://#{cluster.api_fqdn}/organizations/ponyville"
|
103
|
+
validation_client_name = 'ponyville-validator'
|
104
|
+
validation_key = "#{chef_server_bootstrap_backend.config_item('lxc.rootfs')}/root/chef-repo/.chef/ponyville-validator.pem"
|
105
|
+
elsif chef_server_url.nil? || validation_client_name.nil? || validation_key.nil?
|
106
|
+
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."
|
107
|
+
exit 1
|
108
|
+
end
|
109
|
+
container = ::DevLXC::Container.new(container_name)
|
110
|
+
container.bootstrap_container(base_container_name, options[:version], options[:run_list], chef_server_url, validation_client_name, validation_key)
|
111
|
+
puts
|
112
|
+
print_elapsed_time(Time.now - start_time)
|
35
113
|
end
|
36
114
|
|
37
115
|
desc "init [TOPOLOGY] [UNIQUE_STRING]", "Provide a cluster config file with optional uniqueness in server names and FQDNs"
|
@@ -58,13 +136,24 @@ module DevLXC::CLI
|
|
58
136
|
puts config
|
59
137
|
end
|
60
138
|
|
139
|
+
desc "global-status", "Show status of all dev-lxc images and servers"
|
140
|
+
def global_status
|
141
|
+
containers = Array.new
|
142
|
+
LXC::list_containers({config_path: '/var/lib/dev-lxc'}).map { |c| containers << ::DevLXC::Container.new(c, '/var/lib/dev-lxc').status }
|
143
|
+
max_container_name_length = containers.max_by { |c| c['name'].length }['name'].length unless containers.empty?
|
144
|
+
containers.each { |c| printf "%#{max_container_name_length}s %-15s %s\n", c['name'], c['state'], c['ip_addresses'] }
|
145
|
+
end
|
146
|
+
|
61
147
|
desc "status [SERVER_NAME_REGEX]", "Show status of servers"
|
62
148
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
63
149
|
def status(server_name_regex=nil)
|
64
150
|
cluster = get_cluster(options[:config])
|
65
151
|
puts "Chef Server: https://#{cluster.api_fqdn}\n\n"
|
66
152
|
puts "Analytics: https://#{cluster.analytics_fqdn}\n\n" if cluster.analytics_fqdn
|
67
|
-
|
153
|
+
servers = Array.new
|
154
|
+
match_server_name_regex(server_name_regex).map { |s| servers << s.server.status }
|
155
|
+
max_server_name_length = servers.max_by { |s| s['name'].length }['name'].length unless servers.empty?
|
156
|
+
servers.each { |s| printf "%#{max_server_name_length}s %-15s %s\n", s['name'], s['state'], s['ip_addresses'] }
|
68
157
|
end
|
69
158
|
|
70
159
|
desc "abspath [SERVER_NAME_REGEX] [ROOTFS_PATH]", "Returns the absolute path to a file in each server"
|
@@ -75,6 +164,34 @@ module DevLXC::CLI
|
|
75
164
|
puts abspath.compact.join(" ")
|
76
165
|
end
|
77
166
|
|
167
|
+
desc "attach [SERVER_NAME_REGEX]", "Attach the terminal to a single server"
|
168
|
+
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
169
|
+
def attach(server_name_regex)
|
170
|
+
servers = match_server_name_regex(server_name_regex)
|
171
|
+
if servers.length > 1
|
172
|
+
puts "ERROR: The following servers matched '#{server_name_regex}'"
|
173
|
+
servers.map { |s| puts " #{s.server.name}" }
|
174
|
+
puts " Please specify a single server to attach to"
|
175
|
+
exit 1
|
176
|
+
elsif servers.empty?
|
177
|
+
puts "ERROR: No servers matched '#{server_name_regex}'"
|
178
|
+
puts " Please specify a single server to attach to"
|
179
|
+
exit 1
|
180
|
+
end
|
181
|
+
server = servers.first.server
|
182
|
+
unless server.defined? && server.running?
|
183
|
+
puts "ERROR: Server '#{server.name}' is not running"
|
184
|
+
exit 1
|
185
|
+
end
|
186
|
+
attach_opts = {
|
187
|
+
wait: true,
|
188
|
+
env_policy: LXC::LXC_ATTACH_CLEAR_ENV,
|
189
|
+
extra_env_vars: ["LANG=en_US.UTF-8", "TERM=linux", "HOME=#{ENV['HOME']}"]
|
190
|
+
}
|
191
|
+
shell = ENV['SHELL']
|
192
|
+
server.attach(attach_opts) { system(shell) }
|
193
|
+
end
|
194
|
+
|
78
195
|
desc "chef-repo", "Creates a `bootstrap-node` script and chef-repo in the current directory using files from the cluster's backend /root/chef-repo"
|
79
196
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
80
197
|
option :force, :aliases => "-f", :type => :boolean, :desc => "Overwrite any existing knife.rb or pivotal.rb files"
|
@@ -83,80 +200,90 @@ module DevLXC::CLI
|
|
83
200
|
get_cluster(options[:config]).chef_repo(options[:force], options[:pivotal])
|
84
201
|
end
|
85
202
|
|
86
|
-
desc "
|
203
|
+
desc "list-images [SERVER_NAME_REGEX]", "List of each servers' images created during the build process"
|
87
204
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
88
205
|
def list_images(server_name_regex=nil)
|
206
|
+
lxc_config_path = get_cluster(options[:config]).lxc_config_path
|
89
207
|
images = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Array.new } }
|
90
208
|
match_server_name_regex(server_name_regex).each do |s|
|
91
209
|
images[s.platform_image_name][s.shared_image_name] << s.server.name
|
92
210
|
end
|
93
211
|
images.each_with_index do |(platform_name, shared), images_index|
|
94
212
|
shared.each_with_index do |(shared_name, final), shared_index|
|
95
|
-
printf "Platform: %
|
213
|
+
printf "Platform: %25s %s\n", (LXC::Container.new(platform_name, lxc_config_path).defined? ? "Created" : "Not Created"), platform_name
|
96
214
|
puts "|"
|
97
|
-
printf "\\_ Shared: %
|
215
|
+
printf "\\_ Shared: %24s %s\n", (LXC::Container.new(shared_name, lxc_config_path).defined? ? "Created" : "Not Created"), shared_name
|
98
216
|
final.each_with_index do |final_name, final_index|
|
99
217
|
puts " |"
|
100
218
|
unique_name = "u-#{final_name}"
|
101
|
-
printf " \\_ Unique: %
|
219
|
+
printf " \\_ Unique: %21s %s\n", (LXC::Container.new(unique_name, lxc_config_path).defined? ? "Created" : "Not Created"), unique_name
|
102
220
|
|
103
221
|
shared_connector = (final_index + 1 < final.length ? "|" : " ")
|
104
222
|
|
105
223
|
custom_name = "c-#{final_name}"
|
106
|
-
if LXC::Container.new(custom_name).defined?
|
107
|
-
printf " #{shared_connector} \\_ Custom: %
|
224
|
+
if LXC::Container.new(custom_name, lxc_config_path).defined?
|
225
|
+
printf " #{shared_connector} \\_ Custom: %18s %s\n", "Created", custom_name
|
108
226
|
custom_spacing = " "
|
109
|
-
final_width =
|
227
|
+
final_width = 9
|
110
228
|
else
|
111
|
-
final_width =
|
229
|
+
final_width = 12
|
112
230
|
end
|
113
|
-
printf " #{shared_connector} #{custom_spacing}\\_ Final: %#{final_width}s %s\n", (LXC::Container.new(final_name).defined? ? "Created" : "Not Created"), final_name
|
231
|
+
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
|
114
232
|
end
|
115
233
|
puts if (shared_index + 1 < shared.length) || (images_index + 1 < images.length)
|
116
234
|
end
|
117
235
|
end
|
118
236
|
end
|
119
237
|
|
120
|
-
desc "
|
238
|
+
desc "run-command [SERVER_NAME_REGEX] [COMMAND]", "Runs a command in each server"
|
121
239
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
122
240
|
def run_command(server_name_regex=nil, command)
|
123
|
-
|
241
|
+
start_time = Time.now
|
242
|
+
match_server_name_regex(server_name_regex).each { |s| s.run_command(command); puts }
|
243
|
+
print_elapsed_time(Time.now - start_time)
|
124
244
|
end
|
125
245
|
|
126
246
|
desc "up [SERVER_NAME_REGEX]", "Start servers - This is the default if no subcommand is given"
|
127
247
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
128
248
|
def up(server_name_regex=nil)
|
129
|
-
|
249
|
+
start_time = Time.now
|
250
|
+
match_server_name_regex(server_name_regex).each { |s| s.start; puts }
|
251
|
+
print_elapsed_time(Time.now - start_time)
|
130
252
|
end
|
131
253
|
|
132
254
|
desc "halt [SERVER_NAME_REGEX]", "Stop servers"
|
133
255
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
134
256
|
def halt(server_name_regex=nil)
|
135
|
-
|
257
|
+
start_time = Time.now
|
258
|
+
match_server_name_regex(server_name_regex).reverse_each { |s| s.stop; puts }
|
259
|
+
print_elapsed_time(Time.now - start_time)
|
136
260
|
end
|
137
261
|
|
138
262
|
desc "snapshot [SERVER_NAME_REGEX]", "Create a snapshot of servers"
|
139
263
|
option :config, :desc => "Specify a cluster's YAML config file. `./dev-lxc.yml` will be used by default"
|
140
264
|
option :force, :aliases => "-f", :type => :boolean, :desc => "Overwrite existing custom images"
|
141
265
|
def snapshot(server_name_regex=nil)
|
266
|
+
start_time = Time.now
|
142
267
|
non_stopped_servers = Array.new
|
143
268
|
existing_custom_images = Array.new
|
269
|
+
lxc_config_path = get_cluster(options[:config]).lxc_config_path
|
144
270
|
match_server_name_regex(server_name_regex).each do |s|
|
145
271
|
non_stopped_servers << s.server.name if s.server.state != :stopped
|
146
|
-
existing_custom_images << s.server.name if LXC::Container.new("c-#{s.server.name}").defined?
|
272
|
+
existing_custom_images << s.server.name if LXC::Container.new("c-#{s.server.name}", lxc_config_path).defined?
|
147
273
|
end
|
148
274
|
unless non_stopped_servers.empty?
|
149
|
-
puts "
|
275
|
+
puts "ERROR: Aborting snapshot because the following servers are not stopped"
|
150
276
|
puts non_stopped_servers
|
151
277
|
exit 1
|
152
278
|
end
|
153
279
|
unless existing_custom_images.empty? || options[:force]
|
154
|
-
puts "
|
280
|
+
puts "ERROR: The following servers already have a custom image"
|
155
281
|
puts " Use the `--force` or `-f` option to overwrite existing custom images"
|
156
282
|
puts existing_custom_images
|
157
283
|
exit 1
|
158
284
|
end
|
159
|
-
match_server_name_regex(server_name_regex).each { |s| s.snapshot(options[:force]) }
|
285
|
+
match_server_name_regex(server_name_regex).each { |s| s.snapshot(options[:force]); puts }
|
286
|
+
print_elapsed_time(Time.now - start_time)
|
160
287
|
end
|
161
288
|
|
162
289
|
desc "destroy [SERVER_NAME_REGEX]", "Destroy servers"
|
@@ -166,13 +293,16 @@ module DevLXC::CLI
|
|
166
293
|
option :shared, :aliases => "-s", :type => :boolean, :desc => "Also destroy the shared images"
|
167
294
|
option :platform, :aliases => "-p", :type => :boolean, :desc => "Also destroy the platform images"
|
168
295
|
def destroy(server_name_regex=nil)
|
296
|
+
start_time = Time.now
|
169
297
|
match_server_name_regex(server_name_regex).reverse_each do |s|
|
170
298
|
s.destroy
|
171
299
|
s.destroy_image(:custom) if options[:custom]
|
172
300
|
s.destroy_image(:unique) if options[:unique]
|
173
301
|
s.destroy_image(:shared) if options[:shared]
|
174
302
|
s.destroy_image(:platform) if options[:platform]
|
303
|
+
puts
|
175
304
|
end
|
305
|
+
print_elapsed_time(Time.now - start_time)
|
176
306
|
end
|
177
307
|
|
178
308
|
end
|
data/lib/dev-lxc/cluster.rb
CHANGED
@@ -2,11 +2,14 @@ require "dev-lxc/server"
|
|
2
2
|
|
3
3
|
module DevLXC
|
4
4
|
class Cluster
|
5
|
-
attr_reader :api_fqdn, :analytics_fqdn, :chef_server_bootstrap_backend, :analytics_bootstrap_backend
|
5
|
+
attr_reader :api_fqdn, :analytics_fqdn, :chef_server_bootstrap_backend, :analytics_bootstrap_backend, :lxc_config_path
|
6
6
|
|
7
7
|
def initialize(cluster_config)
|
8
8
|
@cluster_config = cluster_config
|
9
9
|
|
10
|
+
@lxc_config_path = @cluster_config["lxc_config_path"]
|
11
|
+
@lxc_config_path ||= "/var/lib/dev-lxc"
|
12
|
+
|
10
13
|
if @cluster_config["chef-server"]
|
11
14
|
@chef_server_topology = @cluster_config["chef-server"]["topology"]
|
12
15
|
@api_fqdn = @cluster_config["chef-server"]["api_fqdn"]
|
@@ -60,12 +63,12 @@ module DevLXC
|
|
60
63
|
|
61
64
|
def chef_repo(force=false, pivotal=false)
|
62
65
|
if @chef_server_bootstrap_backend.nil?
|
63
|
-
puts "A bootstrap backend Chef Server is not defined in the cluster's config. Please define it first."
|
66
|
+
puts "ERROR: A bootstrap backend Chef Server is not defined in the cluster's config. Please define it first."
|
64
67
|
exit 1
|
65
68
|
end
|
66
69
|
chef_server = Server.new(@chef_server_bootstrap_backend, 'chef-server', @cluster_config)
|
67
70
|
if ! chef_server.server.defined?
|
68
|
-
puts "The '#{chef_server.server.name}' Chef Server does not exist. Please create it first."
|
71
|
+
puts "ERROR: The '#{chef_server.server.name}' Chef Server does not exist. Please create it first."
|
69
72
|
exit 1
|
70
73
|
end
|
71
74
|
|
@@ -117,28 +120,6 @@ module DevLXC
|
|
117
120
|
puts "The knife.rb file can not be copied because it does not exist in '#{chef_server.server.name}' Chef Server's `/root/chef-repo/.chef` directory"
|
118
121
|
end
|
119
122
|
end
|
120
|
-
|
121
|
-
bootstrap_node = %Q(#!/bin/bash
|
122
|
-
|
123
|
-
if [[ -z $1 ]]; then
|
124
|
-
echo "Please provide the name of the node to be bootstrapped"
|
125
|
-
return 1
|
126
|
-
fi
|
127
|
-
|
128
|
-
xc-start $1
|
129
|
-
|
130
|
-
xc-chef-config -s #{chef_server_url} \\
|
131
|
-
-u #{validator_name} \\
|
132
|
-
-k ./chef-repo/.chef/#{validator_name}.pem
|
133
|
-
|
134
|
-
if [[ -n $2 ]]; then
|
135
|
-
xc-attach chef-client -r $2
|
136
|
-
else
|
137
|
-
xc-attach chef-client
|
138
|
-
fi
|
139
|
-
)
|
140
|
-
IO.write("./bootstrap-node", bootstrap_node)
|
141
|
-
FileUtils.chmod("u+x", "./bootstrap-node")
|
142
123
|
end
|
143
124
|
|
144
125
|
def chef_server_config
|
data/lib/dev-lxc/container.rb
CHANGED
@@ -1,31 +1,46 @@
|
|
1
1
|
module DevLXC
|
2
2
|
class Container < LXC::Container
|
3
|
+
def status
|
4
|
+
if self.defined?
|
5
|
+
state = self.state
|
6
|
+
ip_addresses = self.ip_addresses.join(" ") if self.state == :running
|
7
|
+
else
|
8
|
+
state = "not_created"
|
9
|
+
end
|
10
|
+
{ 'name' => self.name, 'state' => state, 'ip_addresses' => ip_addresses }
|
11
|
+
end
|
12
|
+
|
3
13
|
def start
|
4
|
-
|
5
|
-
|
14
|
+
unless self.defined?
|
15
|
+
puts "ERROR: Container '#{self.name}' does not exist."
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
puts "Starting container '#{self.name}'"
|
6
19
|
super
|
7
20
|
wait(:running, 3)
|
8
|
-
puts "Waiting for #{self.name} container's network"
|
21
|
+
puts "Waiting for '#{self.name}' container's network"
|
9
22
|
ips = nil
|
10
23
|
30.times do
|
11
24
|
ips = self.ip_addresses
|
12
25
|
break unless ips.empty?
|
13
26
|
sleep 1
|
14
27
|
end
|
15
|
-
|
28
|
+
if ips.empty?
|
29
|
+
puts "ERROR: Container '#{self.name}' network is not available."
|
30
|
+
exit 1
|
31
|
+
end
|
16
32
|
end
|
17
33
|
|
18
34
|
def stop
|
19
|
-
puts "Stopping container #{self.name}"
|
35
|
+
puts "Stopping container '#{self.name}'"
|
20
36
|
super
|
21
37
|
wait("STOPPED", 3)
|
22
38
|
end
|
23
39
|
|
24
40
|
def destroy
|
25
|
-
return unless self.defined?
|
26
41
|
stop if running?
|
27
|
-
puts "Destroying container #{self.name}"
|
28
|
-
super
|
42
|
+
puts "Destroying container '#{self.name}'"
|
43
|
+
super if self.defined?
|
29
44
|
end
|
30
45
|
|
31
46
|
def sync_mounts(mounts)
|
@@ -36,7 +51,10 @@ module DevLXC
|
|
36
51
|
self.set_config_item("lxc.mount.entry", preserved_mounts)
|
37
52
|
end
|
38
53
|
mounts.each do |mount|
|
39
|
-
|
54
|
+
unless File.exists?(mount.split.first)
|
55
|
+
puts "ERROR: Mount source #{mount.split.first} does not exist."
|
56
|
+
exit 1
|
57
|
+
end
|
40
58
|
if ! preserved_mounts.nil? && preserved_mounts.any? { |m| m.start_with?("#{mount} ") }
|
41
59
|
puts "Skipping mount entry #{mount}, it already exists"
|
42
60
|
next
|
@@ -49,15 +67,22 @@ module DevLXC
|
|
49
67
|
end
|
50
68
|
|
51
69
|
def run_command(command)
|
52
|
-
|
53
|
-
|
70
|
+
unless running?
|
71
|
+
puts "ERROR: Container '#{self.name}' must be running first"
|
72
|
+
exit 1
|
73
|
+
end
|
74
|
+
attach_opts = { wait: true, env_policy: LXC::LXC_ATTACH_CLEAR_ENV, extra_env_vars: ['HOME=/root'] }
|
75
|
+
attach(attach_opts) do
|
54
76
|
LXC.run_command(command)
|
55
77
|
end
|
56
78
|
end
|
57
79
|
|
58
80
|
def install_package(package_path)
|
59
|
-
|
60
|
-
|
81
|
+
unless run_command("test -e #{package_path}") == 0
|
82
|
+
puts "ERROR: File #{package_path} does not exist in container '#{self.name}'"
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
puts "Installing #{package_path} in container '#{self.name}'"
|
61
86
|
case File.extname(package_path)
|
62
87
|
when ".deb"
|
63
88
|
install_command = "dpkg -D10 -i #{package_path}"
|
@@ -66,5 +91,110 @@ module DevLXC
|
|
66
91
|
end
|
67
92
|
run_command(install_command)
|
68
93
|
end
|
94
|
+
|
95
|
+
def install_chef_client(version=nil)
|
96
|
+
unless self.defined?
|
97
|
+
puts "ERROR: Container '#{self.name}' does not exist."
|
98
|
+
exit 1
|
99
|
+
end
|
100
|
+
unless running?
|
101
|
+
puts "ERROR: Container '#{self.name}' is not running"
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
if self.ip_addresses.empty?
|
105
|
+
puts "ERROR: Container '#{self.name}' network is not available."
|
106
|
+
exit 1
|
107
|
+
end
|
108
|
+
|
109
|
+
require 'tempfile'
|
110
|
+
|
111
|
+
installed_version = nil
|
112
|
+
file = Tempfile.new('installed_chef_client_version')
|
113
|
+
begin
|
114
|
+
attach_opts = { wait: true, env_policy: LXC::LXC_ATTACH_CLEAR_ENV, extra_env_vars: ['HOME=/root'], stdout: file }
|
115
|
+
attach(attach_opts) do
|
116
|
+
puts `chef-client -v`
|
117
|
+
end
|
118
|
+
file.rewind
|
119
|
+
installed_version = Regexp.last_match[1] if file.read.match(/chef:\s*(\d+\.\d+\.\d+)/i)
|
120
|
+
ensure
|
121
|
+
file.close
|
122
|
+
file.unlink
|
123
|
+
end
|
124
|
+
if installed_version.nil? || ( ! version.nil? && ! installed_version.start_with?(version) )
|
125
|
+
require "net/https"
|
126
|
+
require "uri"
|
127
|
+
|
128
|
+
uri = URI.parse("https://www.chef.io/chef/install.sh")
|
129
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
130
|
+
http.use_ssl = true
|
131
|
+
|
132
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
133
|
+
|
134
|
+
response = http.request(request)
|
135
|
+
|
136
|
+
file = Tempfile.new('install_sh', "#{config_item('lxc.rootfs')}/tmp")
|
137
|
+
file.write(response.body)
|
138
|
+
begin
|
139
|
+
version = 'latest' if version.nil?
|
140
|
+
install_command = "bash /tmp/#{File.basename(file.path)} -v #{version}"
|
141
|
+
run_command(install_command)
|
142
|
+
ensure
|
143
|
+
file.close
|
144
|
+
file.unlink
|
145
|
+
end
|
146
|
+
else
|
147
|
+
puts "Chef #{installed_version} is already installed."
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def configure_chef_client(chef_server_url, validation_client_name, validation_key)
|
152
|
+
unless self.defined?
|
153
|
+
puts "ERROR: Container '#{self.name}' does not exist."
|
154
|
+
exit 1
|
155
|
+
end
|
156
|
+
|
157
|
+
puts "Configuring Chef Client in container '#{self.name}' for Chef Server '#{chef_server_url}'"
|
158
|
+
|
159
|
+
FileUtils.mkdir_p("#{config_item('lxc.rootfs')}/etc/chef")
|
160
|
+
|
161
|
+
client_rb = %Q(chef_server_url '#{chef_server_url}'
|
162
|
+
validation_client_name '#{validation_client_name}'
|
163
|
+
ssl_verify_mode :verify_none
|
164
|
+
)
|
165
|
+
IO.write("#{config_item('lxc.rootfs')}/etc/chef/client.rb", client_rb)
|
166
|
+
|
167
|
+
begin
|
168
|
+
FileUtils.cp(validation_key, "#{config_item('lxc.rootfs')}/etc/chef/validation.pem")
|
169
|
+
rescue Errno::ENOENT
|
170
|
+
puts "ERROR: The validation key '#{validation_key}' does not exist."
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def bootstrap_container(base_container_name=nil, version=nil, run_list=nil, chef_server_url, validation_client_name, validation_key)
|
175
|
+
puts "Bootstrapping container '#{self.name}' for Chef Server '#{chef_server_url}'"
|
176
|
+
if base_container_name
|
177
|
+
if self.defined?
|
178
|
+
puts "WARN: Skipping cloning. Container '#{self.name}' already exists"
|
179
|
+
else
|
180
|
+
puts "Cloning base container '#{base_container_name}' into container '#{self.name}'"
|
181
|
+
base_container = DevLXC::Container.new(base_container_name)
|
182
|
+
unless base_container.defined?
|
183
|
+
puts "ERROR: Base container '#{base_container_name} does not exist"
|
184
|
+
exit 1
|
185
|
+
end
|
186
|
+
base_container.clone(self.name, {:flags => LXC::LXC_CLONE_SNAPSHOT})
|
187
|
+
self.load_config
|
188
|
+
end
|
189
|
+
end
|
190
|
+
self.start unless self.running?
|
191
|
+
self.install_chef_client(version)
|
192
|
+
self.configure_chef_client(chef_server_url, validation_client_name, validation_key)
|
193
|
+
|
194
|
+
chef_client_command = "chef-client"
|
195
|
+
chef_client_command += " -r #{run_list}" if run_list
|
196
|
+
self.run_command(chef_client_command)
|
197
|
+
end
|
198
|
+
|
69
199
|
end
|
70
200
|
end
|
data/lib/dev-lxc/server.rb
CHANGED
@@ -7,10 +7,12 @@ module DevLXC
|
|
7
7
|
|
8
8
|
def initialize(name, server_type, cluster_config)
|
9
9
|
unless cluster_config[server_type]["servers"].keys.include?(name)
|
10
|
-
|
10
|
+
puts "ERROR: Server '#{name}' is not defined in the cluster config"
|
11
|
+
exit 1
|
11
12
|
end
|
12
13
|
@server_type = server_type
|
13
14
|
cluster = DevLXC::Cluster.new(cluster_config)
|
15
|
+
@lxc_config_path = cluster.lxc_config_path
|
14
16
|
@api_fqdn = cluster.api_fqdn
|
15
17
|
@analytics_fqdn = cluster.analytics_fqdn
|
16
18
|
@chef_server_bootstrap_backend = cluster.chef_server_bootstrap_backend
|
@@ -18,7 +20,7 @@ module DevLXC
|
|
18
20
|
@chef_server_config = cluster.chef_server_config
|
19
21
|
@analytics_config = cluster.analytics_config
|
20
22
|
|
21
|
-
@server = DevLXC::Container.new(name)
|
23
|
+
@server = DevLXC::Container.new(name, @lxc_config_path)
|
22
24
|
@config = cluster_config[@server_type]["servers"][@server.name]
|
23
25
|
@ipaddress = @config["ipaddress"]
|
24
26
|
@role = @config["role"] ? @config["role"] : cluster_config[@server_type]['topology']
|
@@ -55,26 +57,16 @@ module DevLXC
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
|
-
def status
|
59
|
-
if @server.defined?
|
60
|
-
state = @server.state
|
61
|
-
ip_addresses = @server.ip_addresses.join(" ") if @server.state == :running
|
62
|
-
else
|
63
|
-
state = "not_created"
|
64
|
-
end
|
65
|
-
printf "%25s %-15s %s\n", @server.name, state, ip_addresses
|
66
|
-
end
|
67
|
-
|
68
60
|
def abspath(rootfs_path)
|
69
61
|
"#{@server.config_item('lxc.rootfs')}#{rootfs_path}" if @server.defined?
|
70
62
|
end
|
71
63
|
|
72
64
|
def run_command(command)
|
73
65
|
if @server.running?
|
74
|
-
puts "Running '#{command}' in #{@server.name}"
|
66
|
+
puts "Running '#{command}' in '#{@server.name}'"
|
75
67
|
@server.run_command(command)
|
76
68
|
else
|
77
|
-
puts "#{@server.name} is not running"
|
69
|
+
puts "'#{@server.name}' is not running"
|
78
70
|
end
|
79
71
|
end
|
80
72
|
|
@@ -109,7 +101,7 @@ module DevLXC
|
|
109
101
|
puts "WARNING: Skipping snapshot of '#{@server.name}' because it is not stopped"
|
110
102
|
return
|
111
103
|
end
|
112
|
-
custom_image = DevLXC::Container.new("c-#{@server.name}")
|
104
|
+
custom_image = DevLXC::Container.new("c-#{@server.name}", @lxc_config_path)
|
113
105
|
if custom_image.defined?
|
114
106
|
if force
|
115
107
|
custom_image.destroy
|
@@ -118,7 +110,7 @@ module DevLXC
|
|
118
110
|
return
|
119
111
|
end
|
120
112
|
end
|
121
|
-
puts "Creating snapshot of container #{@server.name} in custom image #{custom_image.name}"
|
113
|
+
puts "Creating snapshot of container '#{@server.name}' in custom image '#{custom_image.name}'"
|
122
114
|
@server.clone("#{custom_image.name}", {:flags => LXC::LXC_CLONE_SNAPSHOT|LXC::LXC_CLONE_KEEPMACADDR})
|
123
115
|
end
|
124
116
|
|
@@ -140,47 +132,51 @@ module DevLXC
|
|
140
132
|
def destroy_image(type)
|
141
133
|
case type
|
142
134
|
when :custom
|
143
|
-
DevLXC::Container.new("c-#{@server.name}").destroy
|
135
|
+
DevLXC::Container.new("c-#{@server.name}", @lxc_config_path).destroy
|
144
136
|
when :unique
|
145
|
-
DevLXC::Container.new("u-#{@server.name}").destroy
|
137
|
+
DevLXC::Container.new("u-#{@server.name}", @lxc_config_path).destroy
|
146
138
|
when :shared
|
147
|
-
DevLXC::Container.new(@shared_image_name).destroy
|
139
|
+
DevLXC::Container.new(@shared_image_name, @lxc_config_path).destroy
|
148
140
|
when :platform
|
149
|
-
DevLXC::Container.new(@platform_image_name).destroy
|
141
|
+
DevLXC::Container.new(@platform_image_name, @lxc_config_path).destroy
|
150
142
|
end
|
151
143
|
end
|
152
144
|
|
153
145
|
def create
|
154
146
|
if @server.defined?
|
155
|
-
puts "Using existing container #{@server.name}"
|
147
|
+
puts "Using existing container '#{@server.name}'"
|
156
148
|
return
|
157
149
|
end
|
158
|
-
custom_image = DevLXC::Container.new("c-#{@server.name}")
|
159
|
-
unique_image = DevLXC::Container.new("u-#{@server.name}")
|
150
|
+
custom_image = DevLXC::Container.new("c-#{@server.name}", @lxc_config_path)
|
151
|
+
unique_image = DevLXC::Container.new("u-#{@server.name}", @lxc_config_path)
|
160
152
|
if custom_image.defined?
|
161
|
-
puts "Cloning custom image #{custom_image.name} into container #{@server.name}"
|
153
|
+
puts "Cloning custom image '#{custom_image.name}' into container '#{@server.name}'"
|
162
154
|
custom_image.clone(@server.name, {:flags => LXC::LXC_CLONE_SNAPSHOT|LXC::LXC_CLONE_KEEPMACADDR})
|
163
|
-
@server = DevLXC::Container.new(@server.name)
|
155
|
+
@server = DevLXC::Container.new(@server.name, @lxc_config_path)
|
164
156
|
return
|
165
157
|
elsif unique_image.defined?
|
166
|
-
puts "Cloning unique image #{unique_image.name} into container #{@server.name}"
|
158
|
+
puts "Cloning unique image '#{unique_image.name}' into container '#{@server.name}'"
|
167
159
|
unique_image.clone(@server.name, {:flags => LXC::LXC_CLONE_SNAPSHOT|LXC::LXC_CLONE_KEEPMACADDR})
|
168
|
-
@server = DevLXC::Container.new(@server.name)
|
160
|
+
@server = DevLXC::Container.new(@server.name, @lxc_config_path)
|
169
161
|
return
|
170
162
|
else
|
171
|
-
puts "Creating container #{@server.name}"
|
172
|
-
unless @server.name == @chef_server_bootstrap_backend || DevLXC::Container.new(@chef_server_bootstrap_backend).defined?
|
173
|
-
|
163
|
+
puts "Creating container '#{@server.name}'"
|
164
|
+
unless @server.name == @chef_server_bootstrap_backend || DevLXC::Container.new(@chef_server_bootstrap_backend, @lxc_config_path).defined?
|
165
|
+
puts "ERROR: The bootstrap backend server '#{@chef_server_bootstrap_backend}' must be created first."
|
166
|
+
exit 1
|
174
167
|
end
|
175
168
|
shared_image = create_shared_image
|
176
|
-
puts "Cloning shared image #{shared_image.name} into container #{@server.name}"
|
169
|
+
puts "Cloning shared image '#{shared_image.name}' into container '#{@server.name}'"
|
177
170
|
shared_image.clone(@server.name, {:flags => LXC::LXC_CLONE_SNAPSHOT})
|
178
|
-
@server = DevLXC::Container.new(@server.name)
|
171
|
+
@server = DevLXC::Container.new(@server.name, @lxc_config_path)
|
179
172
|
puts "Adding lxc.hook.post-stop hook"
|
180
173
|
@server.set_config_item("lxc.hook.post-stop", "/usr/local/share/lxc/hooks/post-stop-dhcp-release")
|
181
174
|
@server.save_config
|
182
175
|
hwaddr = @server.config_item("lxc.network.0.hwaddr")
|
183
|
-
|
176
|
+
if hwaddr.empty?
|
177
|
+
puts "ERROR: '#{@server.name}' needs to have an lxc.network.hwaddr entry"
|
178
|
+
exit 1
|
179
|
+
end
|
184
180
|
DevLXC.assign_ip_address(@ipaddress, @server.name, hwaddr)
|
185
181
|
unless @role == 'backend'
|
186
182
|
case @server_type
|
@@ -214,21 +210,21 @@ module DevLXC
|
|
214
210
|
end
|
215
211
|
end
|
216
212
|
@server.stop
|
217
|
-
puts "Cloning container #{@server.name} into unique image #{unique_image.name}"
|
213
|
+
puts "Cloning container '#{@server.name}' into unique image '#{unique_image.name}'"
|
218
214
|
@server.clone("#{unique_image.name}", {:flags => LXC::LXC_CLONE_SNAPSHOT|LXC::LXC_CLONE_KEEPMACADDR})
|
219
215
|
end
|
220
216
|
end
|
221
217
|
|
222
218
|
def create_shared_image
|
223
|
-
shared_image = DevLXC::Container.new(@shared_image_name)
|
219
|
+
shared_image = DevLXC::Container.new(@shared_image_name, @lxc_config_path)
|
224
220
|
if shared_image.defined?
|
225
|
-
puts "Using existing shared image #{shared_image.name}"
|
221
|
+
puts "Using existing shared image '#{shared_image.name}'"
|
226
222
|
return shared_image
|
227
223
|
end
|
228
|
-
platform_image = DevLXC.create_platform_image(@platform_image_name)
|
229
|
-
puts "Cloning platform image #{platform_image.name} into shared image #{shared_image.name}"
|
224
|
+
platform_image = DevLXC.create_platform_image(@platform_image_name, @lxc_config_path)
|
225
|
+
puts "Cloning platform image '#{platform_image.name}' into shared image '#{shared_image.name}'"
|
230
226
|
platform_image.clone(shared_image.name, {:flags => LXC::LXC_CLONE_SNAPSHOT})
|
231
|
-
shared_image = DevLXC::Container.new(shared_image.name)
|
227
|
+
shared_image = DevLXC::Container.new(shared_image.name, @lxc_config_path)
|
232
228
|
|
233
229
|
# Disable certain sysctl.d files in Ubuntu 10.04, they cause `start procps` to fail
|
234
230
|
# Enterprise Chef server's postgresql recipe expects to be able to `start procps`
|
@@ -275,8 +271,8 @@ module DevLXC
|
|
275
271
|
IO.write("#{@server.config_item('lxc.rootfs')}/etc/opscode/chef-server.rb", @chef_server_config)
|
276
272
|
end
|
277
273
|
when "frontend"
|
278
|
-
puts "Copying /etc/opscode from bootstrap backend"
|
279
|
-
FileUtils.cp_r("#{LXC::Container.new(@chef_server_bootstrap_backend).config_item('lxc.rootfs')}/etc/opscode",
|
274
|
+
puts "Copying /etc/opscode from bootstrap backend '#{@chef_server_bootstrap_backend}'"
|
275
|
+
FileUtils.cp_r("#{LXC::Container.new(@chef_server_bootstrap_backend, @lxc_config_path).config_item('lxc.rootfs')}/etc/opscode",
|
280
276
|
"#{@server.config_item('lxc.rootfs')}/etc")
|
281
277
|
end
|
282
278
|
run_ctl(@server_ctl, "reconfigure")
|
@@ -284,8 +280,8 @@ module DevLXC
|
|
284
280
|
|
285
281
|
def configure_reporting
|
286
282
|
if @role == 'frontend'
|
287
|
-
puts "Copying /etc/opscode-reporting from bootstrap backend"
|
288
|
-
FileUtils.cp_r("#{LXC::Container.new(@chef_server_bootstrap_backend).config_item('lxc.rootfs')}/etc/opscode-reporting",
|
283
|
+
puts "Copying /etc/opscode-reporting from bootstrap backend '#{@chef_server_bootstrap_backend}'"
|
284
|
+
FileUtils.cp_r("#{LXC::Container.new(@chef_server_bootstrap_backend, @lxc_config_path).config_item('lxc.rootfs')}/etc/opscode-reporting",
|
289
285
|
"#{@server.config_item('lxc.rootfs')}/etc")
|
290
286
|
end
|
291
287
|
run_ctl(@server_ctl, "reconfigure")
|
@@ -333,21 +329,21 @@ module DevLXC
|
|
333
329
|
def configure_analytics
|
334
330
|
case @role
|
335
331
|
when "standalone", "backend"
|
336
|
-
puts "Copying /etc/opscode-analytics from Chef Server bootstrap backend"
|
337
|
-
FileUtils.cp_r("#{LXC::Container.new(@chef_server_bootstrap_backend).config_item('lxc.rootfs')}/etc/opscode-analytics",
|
332
|
+
puts "Copying /etc/opscode-analytics from Chef Server bootstrap backend '#{@chef_server_bootstrap_backend}'"
|
333
|
+
FileUtils.cp_r("#{LXC::Container.new(@chef_server_bootstrap_backend, @lxc_config_path).config_item('lxc.rootfs')}/etc/opscode-analytics",
|
338
334
|
"#{@server.config_item('lxc.rootfs')}/etc")
|
339
335
|
|
340
336
|
IO.write("#{@server.config_item('lxc.rootfs')}/etc/opscode-analytics/opscode-analytics.rb", @analytics_config)
|
341
337
|
when "frontend"
|
342
|
-
puts "Copying /etc/opscode-analytics from Analytics bootstrap backend"
|
343
|
-
FileUtils.cp_r("#{LXC::Container.new(@analytics_bootstrap_backend).config_item('lxc.rootfs')}/etc/opscode-analytics",
|
338
|
+
puts "Copying /etc/opscode-analytics from Analytics bootstrap backend '#{@analytics_bootstrap_backend}'"
|
339
|
+
FileUtils.cp_r("#{LXC::Container.new(@analytics_bootstrap_backend, @lxc_config_path).config_item('lxc.rootfs')}/etc/opscode-analytics",
|
344
340
|
"#{@server.config_item('lxc.rootfs')}/etc")
|
345
341
|
end
|
346
342
|
run_ctl("opscode-analytics", "reconfigure")
|
347
343
|
end
|
348
344
|
|
349
345
|
def run_ctl(component, subcommand)
|
350
|
-
puts "Running `#{component}-ctl #{subcommand}` in #{@server.name}"
|
346
|
+
puts "Running `#{component}-ctl #{subcommand}` in '#{@server.name}'"
|
351
347
|
@server.run_command("#{component}-ctl #{subcommand}")
|
352
348
|
end
|
353
349
|
|
data/lib/dev-lxc/version.rb
CHANGED
data/lib/dev-lxc.rb
CHANGED
@@ -6,13 +6,13 @@ require "dev-lxc/server"
|
|
6
6
|
require "dev-lxc/cluster"
|
7
7
|
|
8
8
|
module DevLXC
|
9
|
-
def self.create_platform_image(platform_image_name)
|
10
|
-
platform_image = DevLXC::Container.new(platform_image_name)
|
9
|
+
def self.create_platform_image(platform_image_name, lxc_config_path='/var/lib/lxc')
|
10
|
+
platform_image = DevLXC::Container.new(platform_image_name, lxc_config_path)
|
11
11
|
if platform_image.defined?
|
12
|
-
puts "Using existing platform image #{platform_image.name}"
|
12
|
+
puts "Using existing platform image '#{platform_image.name}'"
|
13
13
|
return platform_image
|
14
14
|
end
|
15
|
-
puts "Creating platform image #{platform_image.name}"
|
15
|
+
puts "Creating platform image '#{platform_image.name}'"
|
16
16
|
case platform_image.name
|
17
17
|
when "p-ubuntu-1004"
|
18
18
|
platform_image.create("download", "btrfs", {}, 0, ["-d", "ubuntu", "-r", "lucid", "-a", "amd64"])
|
@@ -29,11 +29,11 @@ module DevLXC
|
|
29
29
|
platform_image.set_config_item("lxc.mount.auto", "proc:rw sys:rw")
|
30
30
|
end
|
31
31
|
hwaddr = '00:16:3e:' + Digest::SHA1.hexdigest(Time.now.to_s).slice(0..5).unpack('a2a2a2').join(':')
|
32
|
-
puts "Setting #{platform_image.name} platform image's lxc.network.0.hwaddr to #{hwaddr}"
|
32
|
+
puts "Setting '#{platform_image.name}' platform image's lxc.network.0.hwaddr to #{hwaddr}"
|
33
33
|
platform_image.set_config_item("lxc.network.0.hwaddr", hwaddr)
|
34
34
|
platform_image.save_config
|
35
35
|
platform_image.start
|
36
|
-
puts "Installing packages in platform image #{platform_image.name}"
|
36
|
+
puts "Installing packages in platform image '#{platform_image.name}'"
|
37
37
|
case platform_image.name
|
38
38
|
when "p-ubuntu-1004"
|
39
39
|
# Disable certain sysctl.d files in Ubuntu 10.04, they cause `start procps` to fail
|
@@ -59,7 +59,7 @@ module DevLXC
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def self.assign_ip_address(ipaddress, container_name, hwaddr)
|
62
|
-
puts "Assigning IP address #{ipaddress} to #{container_name} container's lxc.network.hwaddr #{hwaddr}"
|
62
|
+
puts "Assigning IP address #{ipaddress} to '#{container_name}' container's lxc.network.hwaddr #{hwaddr}"
|
63
63
|
search_file_delete_line("/etc/lxc/dhcp-hosts.conf", /(^#{hwaddr}|,#{ipaddress}$)/)
|
64
64
|
append_line_to_file("/etc/lxc/dhcp-hosts.conf", "#{hwaddr},#{ipaddress}\n")
|
65
65
|
reload_dnsmasq
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dev-lxc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremiah Snapp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|