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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 292b5df53d047927c96eb8d73e13739b17c57c99
4
- data.tar.gz: 3e696698a4ab38c75ef4cd428637b8ed95d21a6d
3
+ metadata.gz: a9b7bd69da896ea6a750b5f4ac463fcf23de242e
4
+ data.tar.gz: 638d5b30c5c74a4983f763614141cb63d4218931
5
5
  SHA512:
6
- metadata.gz: 5f7bba6ca362e9f8de32c9702ebb9eca1af73f78f4049c63e39f1dd865423fb059f69ea9e4e67414d473fb35d181c9327a40e59fe38b80c5ced151abb2a24a15
7
- data.tar.gz: 916d5ce93646952a3e69f858471a4dc837b01c3acc16a2e89b4d1c64f593fb2fc08fe2439620be12ab2c804aebb7353260df932711b0845ab194b9a98f853856
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 with a Chef Analytics server using LXC containers.
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 will also optionally build a standalone or tier Chef Analytics server
8
- and connect it with the Chef Server.
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
- The dev-lxc tool is well suited as a tool for support related work, customized
11
- cluster builds for demo purposes, as well as general experimentation and exploration.
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 list_images
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
- Also create a `./bootstrap-node` script to simplify creating and
180
- bootstrapping nodes in the `dev-lxc-platform`.
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 run_command subcommand to tell the backend and
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 run_command chef 'chef-server-ctl reconfigure'
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 'chef'
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 = [ 'run_command', 'uptime' ] # run `uptime` in all servers
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
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'dev-lxc/cli'
3
3
 
4
- raise "Must run as root" unless Process.uid == 0
4
+ unless Process.uid == 0
5
+ puts "ERROR: Must run as root"
6
+ exit 1
7
+ end
5
8
 
6
9
  DevLXC::CLI::DevLXC.start
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(config_option)
10
- config = options[:config]
11
- config ||= "dev-lxc.yml"
12
- if ! File.exists?(config)
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(config)))
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
- match_server_name_regex(server_name_regex).each { |s| s.status }
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 "list_images [SERVER_NAME_REGEX]", "List of each servers' images created during the build process"
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: %21s %s\n", (LXC::Container.new(platform_name).defined? ? "Created" : "Not Created"), platform_name
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: %20s %s\n", (LXC::Container.new(shared_name).defined? ? "Created" : "Not Created"), shared_name
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: %17s %s\n", (LXC::Container.new(unique_name).defined? ? "Created" : "Not Created"), unique_name
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: %14s %s\n", "Created", custom_name
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 = 12
227
+ final_width = 9
110
228
  else
111
- final_width = 15
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 "run_command [SERVER_NAME_REGEX] [COMMAND]", "Runs a command in each server"
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
- match_server_name_regex(server_name_regex).each { |s| s.run_command(command) }
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
- match_server_name_regex(server_name_regex).each { |s| s.start }
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
- match_server_name_regex(server_name_regex).reverse_each { |s| s.stop }
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 "WARNING: Aborting snapshot because the following servers are not stopped"
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 "WARNING: The following servers already have a custom image"
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
@@ -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
@@ -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
- raise "Container #{self.name} does not exist." unless self.defined?
5
- puts "Starting container #{self.name}"
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
- raise "Container #{self.name} network is not available." if ips.empty?
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
- raise "Mount source #{mount.split.first} does not exist." unless File.exists?(mount.split.first)
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
- raise "Container #{self.name} must be running first" unless running?
53
- attach({:wait => true, :stdin => STDIN, :stdout => STDOUT, :stderr => STDERR}) do
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
- raise "File #{package_path} does not exist in container #{self.name}" unless run_command("test -e #{package_path}") == 0
60
- puts "Installing #{package_path} in container #{self.name}"
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
@@ -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
- raise "Server #{name} is not defined in the cluster config"
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
- raise "The bootstrap backend server must be created first."
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
- raise "#{@server.name} needs to have an lxc.network.hwaddr entry" if hwaddr.empty?
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
 
@@ -1,3 +1,3 @@
1
1
  module DevLXC
2
- VERSION = "0.6.4"
2
+ VERSION = "1.0.0"
3
3
  end
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.6.4
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-03-30 00:00:00.000000000 Z
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler