chef-lxc 0.0.4 → 0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f890ea63de01f32c7c8a710d723a7c83b5ed6796
4
- data.tar.gz: d85c40a3a99d140b66ca4af1d9dde58b8549699d
3
+ metadata.gz: 52e49fcc3e5851ef433948b2fee48854b397f6c6
4
+ data.tar.gz: 25871d209911354fa53cf0b7b2ee75cbe0d535df
5
5
  SHA512:
6
- metadata.gz: 245e5cd1d45de534e1b7bde4f02a69cff15967cd39922e6b01025a36050a86a5921c4338a9c333748df4e0c738bdc3180a03fc30fb71a5623ac4011f5f0f59a4
7
- data.tar.gz: 2f8eddf6d36d0fffe04de50e372abee43650b45c9e8bccaba204ef36c9ef5f76e6073e49c764f58bf1659b199ff97caf931f63eccc6a280a4c237b4dce59097d
6
+ metadata.gz: 6bd7b09dc78662584ec3859a518fa5c96e4866f093811e29da3a8b7c31373d3fbe9360573c2605a9e45a0dd5035f9274566127a2bbe39944fecd65e7485ab91c
7
+ data.tar.gz: 58489515a34b1d6f50960d1fccfd676a009ab8aa1aa035b8e0226d606996ffa7e916af918dae3f115bbc451e368531c874a12a5d75583a96b6aa3da54aea12d5
data/Gemfile CHANGED
@@ -1,7 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
- gem 'serverspec'
5
- gem 'specinfra', github: 'ranjib/specinfra', branch: 'lxc'
6
- gem 'ruby-lxc'
7
- gem 'pry'
data/README.md CHANGED
@@ -77,6 +77,91 @@ A more elaborate example,
77
77
  end
78
78
  ```
79
79
 
80
+ ### Automating multi container setup
81
+ Chef-LXC provides `Chef::LXC.create_fleet` method to build chef managed
82
+ multi container system. It offers helper methods to create containers and perform common
83
+ chef administrative operations like creating roles, environments, databags etc.
84
+
85
+ `Chef::LXC::Fleet` can be used with [chef-zero](https://github.com/chef/chef-zero)
86
+ and [berkshelf](http://berkshelf.com/) to test and prototype chef-solo or chef-client/server
87
+ managed infrastructure easily.
88
+
89
+ Following is an example:
90
+
91
+ ```ruby
92
+ require 'chef/lxc'
93
+ require 'chef_zero/server'
94
+ require 'tempfile'
95
+ require 'berkshelf'
96
+
97
+ cookbook_path = File.expand_path('/tmp/cookbooks')
98
+
99
+ # Use berkshelf to venodirze cookbooks
100
+ berksfile = Berkshelf::Berksfile.from_file('/path/to/Berksfile')
101
+ berksfile.vendor('/tmp/cookbooks')
102
+
103
+ # Use chef zero as chef server, tell chef-zero to bind on lxcbr interface
104
+ server = ChefZero::Server.new(host: '10.0.3.1', port: 8889)
105
+ server.start_background
106
+
107
+ # Generate temporary client key for knife operations
108
+ tempfile = Tempfile.new('chef-lxc')
109
+ File.open(tempfile.path, 'w') do |f|
110
+ f.write(server.gen_key_pair.first)
111
+ end
112
+
113
+
114
+ Chef::LXC.create_fleet('memcache') do |fleet|
115
+ # Create base container with chef installed in it
116
+ fleet.create_container('base') do |ct|
117
+ ct.recipe do
118
+ execute 'apt-get update -y'
119
+ remote_file '/opt/chef_12.2.1-1_amd64.deb' do
120
+ source 'http://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/x86_64/chef_12.2.1-1_amd64.deb'
121
+ end
122
+ dpkg_package 'chef' do
123
+ source '/opt/chef_12.2.1-1_amd64.deb'
124
+ end
125
+ directory '/etc/chef'
126
+ file '/etc/chef/client.pem' do
127
+ content ChefZero::Server.new.gen_key_pair.first
128
+ end
129
+ file '/etc/chef/client.rb' do
130
+ content "chef_server_url 'http://10.0.3.1:8889'\n"
131
+ end
132
+ end
133
+ end
134
+
135
+ # configure chef setting for the chef zero server
136
+ fleet.chef_config do |config|
137
+ config[:client_key] = tempfile.path
138
+ config[:node_name] = 'test'
139
+ config[:chef_server_url] = 'http://10.0.3.1:8889'
140
+ end
141
+
142
+ # Upload cookbooks, data bags, create roles
143
+ fleet.upload_cookbooks(cookbook_path)
144
+ fleet.create_environment('sandbox')
145
+ fleet.create_role('memcached', 'recipe[memcached]')
146
+ fleet.create_role('db', 'recipe[mysel::server]')
147
+ fleet.create_role('web', 'recipe[apache]', 'recipe[php]')
148
+
149
+ fleet.create_container('memcached', from: 'base') do |ct|
150
+ ct.command('chef-client -r role[memcached] -E sandbox')
151
+ end
152
+ fleet.create_container('db', from: 'base') do |ct|
153
+ ct.command('chef-client -r role[mysql] -E sandbox')
154
+ end
155
+ fleet.create_container('web', from: 'base') do |ct|
156
+ ct.command('chef-client -r role[web] -E sandbox')
157
+ end
158
+ end
159
+
160
+ tempfile.unlink
161
+ server.stop
162
+ ```
163
+
164
+
80
165
  ## Contributing
81
166
 
82
167
  1. Fork it
data/chef-lxc.gemspec CHANGED
@@ -29,4 +29,5 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency "rspec"
30
30
  spec.add_development_dependency "rake"
31
31
  spec.add_development_dependency "chef-zero"
32
+ spec.add_development_dependency "pry"
32
33
  end
data/lib/chef/lxc.rb CHANGED
@@ -1,3 +1,14 @@
1
1
  require 'chef/lxc_helper'
2
2
  require 'chef/resource/lxc'
3
3
  require 'chef/provider/lxc'
4
+ require 'chef/lxc/fleet'
5
+
6
+ class Chef
7
+ module LXC
8
+ def self.create_fleet(name)
9
+ fleet = Chef::LXC::Fleet.new
10
+ yield fleet if block_given?
11
+ fleet
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ require 'mixlib/shellout'
2
+ require 'chef/lxc_helper'
3
+
4
+ class Chef
5
+ module LXC
6
+ module ContainerHelper
7
+ include Chef::LXCHelper
8
+
9
+ def recipe(path = nil, &block)
10
+ recipe_content = path ? File.read(path) : nil
11
+ recipe_in_container(self, recipe_content, &block)
12
+ end
13
+
14
+ def command(command)
15
+ out = execute(wait: true) do
16
+ cmd = Mixlib::ShellOut.new(command)
17
+ cmd.live_stream = $stdout
18
+ cmd.run_command
19
+ cmd.exitstatus
20
+ end
21
+ out
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ require 'chef'
2
+ require 'chef/environment'
3
+ require 'chef/role'
4
+ require 'chef/knife/cookbook_upload'
5
+ require 'chef/knife/data_bag_from_file'
6
+ require 'chef/knife/data_bag_create'
7
+ require 'chef/lxc/container_helper'
8
+ require 'chef/lxc/knife_helper'
9
+
10
+ class Chef
11
+ module LXC
12
+ class Fleet
13
+ include Chef::LXC::KnifeHelper
14
+
15
+ def create_container(name, opts = {})
16
+ from = opts[:from]
17
+ force = opts[:force]
18
+ ct = container(name)
19
+ if ct.defined? and force
20
+ ct.stop if ct.running?
21
+ ct.destroy
22
+ ct = container(name)
23
+ end
24
+ if from
25
+ base = container(from)
26
+ base.clone(name)
27
+ ct = container(name)
28
+ else
29
+ template = opts[:template] || 'download'
30
+ bdevtype = opts[:bdevtype]
31
+ bdevspecs = opts[:bdevspecs] || {}
32
+ flags = opts[:flags] || 0
33
+ args = opts[:flags] || %w(-d ubuntu -r trusty -a amd64)
34
+ ct.create(template, bdevtype, bdevspecs, flags, args)
35
+ end
36
+ ct.start unless ct.running?
37
+ while ct.ip_addresses.empty?
38
+ sleep 1
39
+ end
40
+ yield ct if block_given?
41
+ ct.stop if opts[:stop_after]
42
+ ct
43
+ end
44
+
45
+ def container(name)
46
+ ct = ::LXC::Container.new(name)
47
+ ct.extend Chef::LXC::ContainerHelper
48
+ ct
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,64 @@
1
+ class Chef
2
+ module LXC
3
+ module KnifeHelper
4
+ def knife(klass, *args)
5
+ klass.load_deps
6
+ plugin = klass.new
7
+ plugin.name_args = args
8
+ yield plugin.config if block_given?
9
+ plugin.run
10
+ plugin
11
+ end
12
+
13
+ def chef_config(config = {})
14
+ config.each do |key, value|
15
+ Chef::Config[key] = value
16
+ end
17
+ yield Chef::Config if block_given?
18
+ Chef::Config
19
+ end
20
+
21
+ def upload_cookbooks(path, *cookbooks)
22
+ cookbook_dirs = Array(path)
23
+ knife Chef::Knife::CookbookUpload, *cookbooks do |config|
24
+ config[:all] = true if cookbooks.empty?
25
+ config[:cookbook_path] = cookbook_dirs
26
+ end
27
+ end
28
+
29
+ def create_data_bag(name)
30
+ knife Chef::Knife::DataBagCreate, name
31
+ end
32
+
33
+ def upload_data_bag(name, path, opts = {})
34
+ items = Dir["#{path}/*"]
35
+ name_args = [name, items].flatten
36
+ plugin = knife(Chef::Knife::DataBagFromFile, *name_args)do |config|
37
+ if opts[:encrypted]
38
+ config[:secret_file] = opts[:secret_file]
39
+ config[:encrypt] = true
40
+ Chef::Config[:knife][:secret_file] = opts[:secret_file]
41
+ end
42
+ end
43
+ end
44
+
45
+ def create_environment(name, opts ={})
46
+ e = Chef::Environment.new
47
+ e.name(name)
48
+ e.default_attributes(opts[:default_attributes])
49
+ e.save
50
+ e
51
+ end
52
+
53
+ def create_role(name, run_list)
54
+ role = Chef::Role.new
55
+ role.name(name)
56
+ Array(run_list).each do |item|
57
+ role.run_list << item
58
+ end
59
+ role.save
60
+ role
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,5 @@
1
1
  class Chef
2
2
  module LXC
3
- VERSION = '0.0.4'
3
+ VERSION = '0.1'
4
4
  end
5
5
  end
@@ -1,5 +1,6 @@
1
1
  require 'lxc'
2
2
  require 'lxc/extra'
3
+ require 'mixlib/shellout'
3
4
 
4
5
  class Chef
5
6
  module LXCHelper
@@ -16,7 +17,7 @@ class Chef
16
17
  client.load_node
17
18
  client.build_node
18
19
  run_context = Chef::RunContext.new(client.node, {}, client.events)
19
- recipe = Chef::Recipe.new("chef-loxc-cookbook", "chef-lxc-recipe", run_context)
20
+ recipe = Chef::Recipe.new('chef-lxc-cookbook', 'chef-lxc-recipe', run_context)
20
21
  recipe.instance_eval(&recipe_block) if recipe_block
21
22
  recipe.instance_eval(recipe_text, __FILE__, __LINE__) if recipe_text
22
23
  runner = Chef::Runner.new(run_context)
@@ -0,0 +1,47 @@
1
+ require 'chef/lxc'
2
+ require 'chef_zero/server'
3
+ require 'tempfile'
4
+
5
+ cookbook_path = File.expand_path('../../../data/cookbooks', __FILE__)
6
+ server = ChefZero::Server.new(host: '10.0.3.1', port: 8889)
7
+ server.start_background unless server.running?
8
+ tempfile = Tempfile.new('chef-lxc')
9
+ File.open(tempfile.path, 'w') do |f|
10
+ f.write(server.gen_key_pair.first)
11
+ end
12
+
13
+ Chef::LXC.create_fleet('memcache') do |fleet|
14
+ # Create base container with chef installed in it
15
+ fleet.create_container('base') do |ct|
16
+ ct.recipe do
17
+ execute 'apt-get update -y'
18
+ remote_file '/opt/chef_12.2.1-1_amd64.deb' do
19
+ source 'http://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/x86_64/chef_12.2.1-1_amd64.deb'
20
+ end
21
+ dpkg_package 'chef' do
22
+ source '/opt/chef_12.2.1-1_amd64.deb'
23
+ end
24
+ directory '/etc/chef'
25
+ file '/etc/chef/client.pem' do
26
+ content ChefZero::Server.new.gen_key_pair.first
27
+ end
28
+ file '/etc/chef/client.rb' do
29
+ content "chef_server_url 'http://10.0.3.1:8889'\n"
30
+ end
31
+ end
32
+ end
33
+
34
+ # configure chef setting for the new chef server
35
+ fleet.chef_config do |config|
36
+ config[:client_key] = tempfile.path
37
+ config[:node_name] = 'test'
38
+ config[:chef_server_url] = 'http://10.0.3.1:8889'
39
+ end
40
+
41
+ # Upload cookbooks, data bags, create roles
42
+ fleet.upload_cookbooks(cookbook_path)
43
+ fleet.create_role('memcached', 'recipe[memcached]')
44
+ fleet.create_container('memcached', from: 'base') do |ct|
45
+ ct.command('chef-client -r role[memcached]')
46
+ end
47
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ require 'chef/lxc/fleet'
3
+
4
+ describe Chef::LXC::Fleet do
5
+ let(:fleet) do
6
+ described_class.new
7
+ end
8
+ context '#create_container' do
9
+ it 'new container' do
10
+ ct = double(::LXC::Container, defined?: false, start: true, stop: true, running?: true)
11
+ expect(ct).to receive(:create).with(
12
+ 'download', nil, {}, 0, %w(-d ubuntu -r trusty -a amd64)
13
+ )
14
+ expect(ct).to receive(:ip_addresses).and_return(['192.168.2.1'])
15
+ allow(::LXC::Container).to receive(:new).and_return(ct)
16
+ fleet.create_container('test-container')
17
+ end
18
+
19
+ it 'clone' do
20
+ ct = double(::LXC::Container, defined?: false, start: true, stop: true, running?: true)
21
+ base = double(::LXC::Container)
22
+ expect(base).to receive(:clone)
23
+ expect(ct).to receive(:ip_addresses).and_return(['192.168.2.1'])
24
+ allow(::LXC::Container).to receive(:new).and_call_original
25
+ allow(::LXC::Container).to receive(:new).with('baz').and_return(base)
26
+ allow(::LXC::Container).to receive(:new).with('test-foo').and_return(ct)
27
+ fleet.create_container('test-foo', from: 'baz')
28
+ end
29
+
30
+ it 'recreate' do
31
+ ct = double(::LXC::Container, defined?: true, start: true, stop: true, running?: true)
32
+ expect(ct).to receive(:destroy)
33
+ expect(ct).to receive(:create).with(
34
+ 'download', nil, {}, 0, %w(-d ubuntu -r trusty -a amd64)
35
+ )
36
+ expect(ct).to receive(:ip_addresses).and_return(['192.168.2.1'])
37
+ allow(::LXC::Container).to receive(:new).with('test-foo').and_return(ct)
38
+ fleet.create_container('test-foo', force: true)
39
+ end
40
+
41
+ it 'clone and recreate' do
42
+ ct = double(::LXC::Container, defined?: true, start: true, stop: true, running?: true)
43
+ expect(ct).to receive(:destroy)
44
+ base = double(::LXC::Container)
45
+ expect(base).to receive(:clone)
46
+ expect(ct).to receive(:ip_addresses).and_return(['192.168.2.1'])
47
+ allow(::LXC::Container).to receive(:new).and_call_original
48
+ allow(::LXC::Container).to receive(:new).with('baz').and_return(base)
49
+ allow(::LXC::Container).to receive(:new).with('test-foo').and_return(ct)
50
+ fleet.create_container('test-foo', force: true, from: 'baz')
51
+ end
52
+ end
53
+
54
+ it '#container' do
55
+ ct = fleet.container('test-container')
56
+ expect(ct).to be_kind_of(::LXC::Container)
57
+ expect(ct.name).to eq('test-container')
58
+ expect(ct).to respond_to(:recipe)
59
+ expect(ct).to respond_to(:command)
60
+ end
61
+
62
+ it '#chef_config' do
63
+ fleet.chef_config(client_key: 'test.pem')
64
+ expect(Chef::Config[:client_key]).to eq('test.pem')
65
+ end
66
+
67
+ it '#upload_cookbooks' do
68
+ expect_any_instance_of(Chef::Knife::CookbookUpload).to receive(:run)
69
+ plugin = fleet.upload_cookbooks('/path/to/cookbooks', 'a', 'b', 'c')
70
+ expect(plugin.name_args).to eq(%w(a b c))
71
+ expect(plugin.config[:cookbook_path]).to eq(['/path/to/cookbooks'])
72
+ expect(plugin.config[:all]).to be_nil
73
+ end
74
+
75
+ it '#create_data_bag' do
76
+ expect_any_instance_of(Chef::Knife::DataBagCreate).to receive(:run)
77
+ plugin = fleet.create_data_bag('test-dbag')
78
+ expect(plugin.name_args).to eq(['test-dbag'])
79
+ end
80
+
81
+ it '#upload_data_bag' do
82
+ allow(Dir).to receive(:[]).with('/path/to/dbag/*').and_return(%w(a b c))
83
+ expect_any_instance_of(Chef::Knife::DataBagFromFile).to receive(:run)
84
+ plugin = fleet.upload_data_bag('foo', '/path/to/dbag')
85
+ expect(plugin.name_args).to eq(%w(foo a b c))
86
+ end
87
+
88
+ it '#create environment' do
89
+ expect_any_instance_of(Chef::Environment).to receive(:save)
90
+ attrs = {a: 1, b: 2}
91
+ env = fleet.create_environment('test-env', default_attributes: attrs)
92
+ expect(env.name).to eq('test-env')
93
+ expect(env.default_attributes).to eq(a: 1, b:2)
94
+ end
95
+
96
+ it '#create role' do
97
+ expect_any_instance_of(Chef::Role).to receive(:save)
98
+ role = fleet.create_role('test-role', 'recipe[bar]')
99
+ expect(role.name).to eq('test-role')
100
+ expect(role.run_list.count).to eq(1)
101
+ expect(role.run_list.first.to_s).to eq('recipe[bar]')
102
+ end
103
+ end
@@ -24,20 +24,4 @@ describe 'inline recipe' do
24
24
  it 'container should be running' do
25
25
  expect(ct.running?).to be(true)
26
26
  end
27
-
28
- it 'should create test directory' do
29
- expect(file('/opt/test')).to be_directory
30
- end
31
-
32
- it 'should install apach2 package' do
33
- expect(package('apache2')).to be_installed
34
- end
35
-
36
- it 'should start apache2 service' do
37
- expect(service('apache2')).to be_running
38
- end
39
-
40
- it 'should enable apache2 service' do
41
- expect(service('apache2')).to be_enabled
42
- end
43
27
  end
@@ -0,0 +1,2 @@
1
+ name 'memcached'
2
+ version '0.0.1'
@@ -0,0 +1,3 @@
1
+ package 'dependency' do
2
+ package_name %w(memcached)
3
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,10 +1,5 @@
1
-
2
1
  require 'chef/lxc'
3
- require 'serverspec'
4
-
5
- include SpecInfra::Helper::Lxc
6
- include SpecInfra::Helper::Debian
7
-
2
+ require 'pry'
8
3
 
9
4
  module LXCSpecHelper
10
5
  def execute_recipe(recipe)
@@ -29,6 +24,5 @@ RSpec.configure do |config|
29
24
  config.filter_run(focus: true)
30
25
  config.include LXCSpecHelper
31
26
  config.run_all_when_everything_filtered = true
32
- config.lxc = "chef"
33
27
  config.backtrace_exclusion_patterns = []
34
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-lxc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: '0.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ranjib Dey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-27 00:00:00.000000000 Z
11
+ date: 2015-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: LXC bindings for Chef
112
126
  email:
113
127
  - ranjib@linux.com
@@ -125,14 +139,21 @@ files:
125
139
  - chef-lxc.gemspec
126
140
  - lib/chef/application/lxc.rb
127
141
  - lib/chef/lxc.rb
142
+ - lib/chef/lxc/container_helper.rb
143
+ - lib/chef/lxc/fleet.rb
144
+ - lib/chef/lxc/knife_helper.rb
128
145
  - lib/chef/lxc/version.rb
129
146
  - lib/chef/lxc_helper.rb
130
147
  - lib/chef/provider/lxc.rb
131
148
  - lib/chef/resource/lxc.rb
149
+ - spec/chef/lxc/fleet_dsl.rb
150
+ - spec/chef/lxc/fleet_spec.rb
132
151
  - spec/chef/recipe_spec.rb
133
152
  - spec/chef/simple_spec.rb
134
153
  - spec/chef/template_spec.rb
135
154
  - spec/chef_lxc_spec.rb
155
+ - spec/data/cookbooks/memcached/metadata.rb
156
+ - spec/data/cookbooks/memcached/recipes/default.rb
136
157
  - spec/data/recipe.rb
137
158
  - spec/data/simple.rb
138
159
  - spec/data/template.rb
@@ -162,10 +183,14 @@ signing_key:
162
183
  specification_version: 4
163
184
  summary: LXC bindings for Chef
164
185
  test_files:
186
+ - spec/chef/lxc/fleet_dsl.rb
187
+ - spec/chef/lxc/fleet_spec.rb
165
188
  - spec/chef/recipe_spec.rb
166
189
  - spec/chef/simple_spec.rb
167
190
  - spec/chef/template_spec.rb
168
191
  - spec/chef_lxc_spec.rb
192
+ - spec/data/cookbooks/memcached/metadata.rb
193
+ - spec/data/cookbooks/memcached/recipes/default.rb
169
194
  - spec/data/recipe.rb
170
195
  - spec/data/simple.rb
171
196
  - spec/data/template.rb