dev-lxc 0.6.4 → 1.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 +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
|