chef-metal-lxc 0.4 → 0.5
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/lib/chef_metal/driver_init/lxc.rb +3 -0
- data/lib/chef_metal_lxc.rb +1 -1
- data/lib/chef_metal_lxc/lxc_driver.rb +166 -0
- data/lib/chef_metal_lxc/lxc_transport.rb +32 -26
- data/lib/chef_metal_lxc/version.rb +1 -1
- metadata +27 -32
- data/lib/chef_metal_lxc/lxc_provisioner.rb +0 -164
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 222f247414cedb23359fd5b9925b15a4264c8571
|
|
4
|
+
data.tar.gz: 3b857d0edcb88781b6106b467622d125d8d9c524
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 25cb466ac9b171b94dd9c13502000616298a7293557f6f4666ab06f0612b14647fac06c79b8e1650577b090ac9e70ff471972450022f400204562192e6126151
|
|
7
|
+
data.tar.gz: 6c43f9e2d61768220c81d9c74f0215a86b51eaf24c9ac0f26478eea35f259d892fcab0bca7552124b0d71cfb9c8bb1078cc31c456d54c3a4d37b52cad9280cb5
|
data/lib/chef_metal_lxc.rb
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
require 'chef_metal'
|
|
2
|
-
require 'chef_metal_lxc/
|
|
2
|
+
require 'chef_metal_lxc/lxc_driver'
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
require 'chef/mixin/shell_out'
|
|
2
|
+
require 'chef_metal/driver'
|
|
3
|
+
require 'chef_metal/machine/unix_machine'
|
|
4
|
+
require 'chef_metal/convergence_strategy/install_cached'
|
|
5
|
+
require 'chef_metal_lxc/lxc_transport'
|
|
6
|
+
require 'chef_metal_lxc/version'
|
|
7
|
+
require 'lxc'
|
|
8
|
+
require 'shellwords'
|
|
9
|
+
|
|
10
|
+
module ChefMetalLXC
|
|
11
|
+
# Provisions machines in lxc.
|
|
12
|
+
class LXCDriver < ChefMetal::Driver
|
|
13
|
+
|
|
14
|
+
include Chef::Mixin::ShellOut
|
|
15
|
+
|
|
16
|
+
# URL scheme:
|
|
17
|
+
# lxc:<path>
|
|
18
|
+
# <path> defaults to LXC config 'lxc.lxcpath'
|
|
19
|
+
# canonical URL calls realpath on <path>
|
|
20
|
+
def self.from_url(driver_url, config)
|
|
21
|
+
LXCDriver.new(driver_url, config)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.canonicalize_url(driver_url, config)
|
|
25
|
+
scheme, lxc_path = driver_url.split(':', 2)
|
|
26
|
+
if lxc_path.nil? || lxc_path == ':'
|
|
27
|
+
lxc_path = LXC.global_config_item('lxc.lxcpath')
|
|
28
|
+
end
|
|
29
|
+
lxc_path = File.realpath(lxc_path)
|
|
30
|
+
[ "lxc:#{lxc_path}", config ]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def initialize(driver_url, config)
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def lxc_path
|
|
38
|
+
scheme, lxc_path = driver_url.split(':', 2)
|
|
39
|
+
lxc_path
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Valid machine options:
|
|
43
|
+
# :template - template name
|
|
44
|
+
# :template_options - additional arguments for templates
|
|
45
|
+
# :backingstore - backing storage (lvm, thinpools, btrfs etc)
|
|
46
|
+
# :config_file - <path> path to LXC file a la https://wiki.archlinux.org/index.php/Linux_Containers#Configuration_file
|
|
47
|
+
# :extra_config - { 'key' => 'value', ... } a set of LXC config key/value pairs to individually set. Merges with, and overrides any values in config_file.
|
|
48
|
+
def allocate_machine(action_handler, machine_spec, machine_options)
|
|
49
|
+
# Create the container if it does not exist
|
|
50
|
+
if machine_spec.location
|
|
51
|
+
ct = LXC::Container.new(machine_spec.location['name'], lxc_path)
|
|
52
|
+
else
|
|
53
|
+
ct = LXC::Container.new(machine_spec.name, lxc_path)
|
|
54
|
+
if ct.defined?
|
|
55
|
+
# Should this be a warning? Configurable, at least.
|
|
56
|
+
raise "container #{machine_spec.name} already exists and is not managed by this LXC driver."
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
unless ct.defined?
|
|
61
|
+
action_handler.perform_action "create lxc container #{ct.name}" do
|
|
62
|
+
#
|
|
63
|
+
# Set config
|
|
64
|
+
#
|
|
65
|
+
# TODO if config file changes, reload container?
|
|
66
|
+
if machine_options[:config_file]
|
|
67
|
+
ct.load_config(machine_options[:config_file])
|
|
68
|
+
end
|
|
69
|
+
if machine_options[:extra_config]
|
|
70
|
+
machine_options[:extra_config].each_pair do |key, value|
|
|
71
|
+
ct.set_config_item(key, value)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Create the machine
|
|
77
|
+
#
|
|
78
|
+
ct.create(machine_options[:template], machine_options[:backingstore], machine_options[:devspecs], 0, machine_options[:template_options])
|
|
79
|
+
|
|
80
|
+
machine_spec.location = {
|
|
81
|
+
'driver_url' => driver_url,
|
|
82
|
+
'driver_version' => ChefMetalLXC::VERSION,
|
|
83
|
+
'name' => machine_spec.name,
|
|
84
|
+
'host_node' => action_handler.host_node,
|
|
85
|
+
'allocated_at' => Time.now.utc.to_s
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def ready_machine(action_handler, machine_spec, machine_options)
|
|
92
|
+
ct = LXC::Container.new(machine_spec.location['name'], lxc_path)
|
|
93
|
+
|
|
94
|
+
# Unfreeze the frozen
|
|
95
|
+
if ct.state == :frozen
|
|
96
|
+
action_handler.perform_action "unfreeze lxc container #{machine_spec.location['name']} (state is #{ct.state})" do
|
|
97
|
+
ct.unfreeze
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Get stopped containers running
|
|
102
|
+
unless ct.running?
|
|
103
|
+
action_handler.perform_action "start lxc container #{machine_spec.location['name']} (state is #{ct.state})" do
|
|
104
|
+
# Have to shell out to lxc-start for now, ct.start holds server sockets open!
|
|
105
|
+
lxc_start = "lxc-start -d -n #{Shellwords.escape(machine_spec.location['name'])}"
|
|
106
|
+
# TODO add ability to change options on start
|
|
107
|
+
# if machine_options[:config_file]
|
|
108
|
+
# lxc_start << " -f #{Shellwords.escape(machine_options[:config_file])}"
|
|
109
|
+
# end
|
|
110
|
+
# if machine_options[:extra_config]
|
|
111
|
+
# machine_options[:extra_config].each_pair do |key,value|
|
|
112
|
+
# lxc_start << " -s #{Shellwords.escape("#{key}=#{value}")}"
|
|
113
|
+
# end
|
|
114
|
+
# end
|
|
115
|
+
shell_out!(lxc_start)
|
|
116
|
+
# ct.start
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Create machine object for callers to use
|
|
121
|
+
machine_for(machine_spec, machine_options)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Connect to machine without acquiring it
|
|
125
|
+
def connect_to_machine(machine_spec, machine_options)
|
|
126
|
+
machine_for(machine_spec, machine_options)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def destroy_machine(action_handler, machine_spec, machine_options)
|
|
130
|
+
if machine_spec.location
|
|
131
|
+
ct = LXC::Container.new(machine_spec.location['name'], lxc_path)
|
|
132
|
+
if ct.defined?
|
|
133
|
+
action_handler.perform_action "delete lxc container #{machine_spec.location['name']}" do
|
|
134
|
+
ct.destroy
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
convergence_strategy_for(machine_spec, machine_options).cleanup_convergence(action_handler, machine_spec)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def stop_machine(action_handler, node)
|
|
142
|
+
if machine_spec.location
|
|
143
|
+
ct = LXC::Container.new(machine_spec.location['name'], lxc_path)
|
|
144
|
+
if ct.running?
|
|
145
|
+
action_handler.perform_action "delete lxc container #{machine_spec.location['name']}" do
|
|
146
|
+
ct.stop
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
protected
|
|
153
|
+
|
|
154
|
+
def machine_for(machine_spec, machine_options)
|
|
155
|
+
ChefMetal::Machine::UnixMachine.new(machine_spec, transport_for(machine_spec), convergence_strategy_for(machine_spec, machine_options))
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def convergence_strategy_for(machine_spec, machine_options)
|
|
159
|
+
ChefMetal::ConvergenceStrategy::InstallCached.new(machine_options[:convergence_options], config)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def transport_for(machine_spec)
|
|
163
|
+
ChefMetalLXC::LXCTransport.new(machine_spec.location['name'], lxc_path)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -25,7 +25,7 @@ module ChefMetalLXC
|
|
|
25
25
|
@options = options
|
|
26
26
|
@name = name
|
|
27
27
|
@lxc_path = lxc_path
|
|
28
|
-
@port_forwards =
|
|
28
|
+
@port_forwards = {}
|
|
29
29
|
@@active_transports << self
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -43,7 +43,7 @@ module ChefMetalLXC
|
|
|
43
43
|
|
|
44
44
|
def execute(command, options = {})
|
|
45
45
|
Chef::Log.info("Executing #{command} on #{name}")
|
|
46
|
-
container.execute do
|
|
46
|
+
container.execute(:timeout => (execute_timeout(options) || 0)) do
|
|
47
47
|
begin
|
|
48
48
|
# TODO support streaming (shell out needs work)
|
|
49
49
|
out = shell_out(command)
|
|
@@ -57,33 +57,37 @@ module ChefMetalLXC
|
|
|
57
57
|
def make_url_available_to_remote(local_url)
|
|
58
58
|
uri = URI(local_url)
|
|
59
59
|
host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3]
|
|
60
|
-
if host == '127.0.0.1' || host == '
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
if host == '127.0.0.1' || host == '::1'
|
|
61
|
+
unless @port_forwards[uri.port]
|
|
62
|
+
|
|
63
|
+
Chef::Log.debug("Forwarding container port #{uri.port} to local port #{uri.port}")
|
|
64
|
+
# Create the channel that will let the container and the host talk to each other
|
|
65
|
+
channel = LXC::Extra::Channel.new
|
|
66
|
+
|
|
67
|
+
# Start the container side of the proxy, listening for client connections
|
|
68
|
+
pid = container.attach do
|
|
69
|
+
begin
|
|
70
|
+
server = TCPServer.new(host, uri.port)
|
|
71
|
+
proxy = LXC::Extra::ProxyClientSide.new(channel, server)
|
|
72
|
+
proxy.start
|
|
73
|
+
rescue
|
|
74
|
+
Chef::Log.error("ERROR in proxy (container side): #{$!}\n#{$!.backtrace.join("\n")}")
|
|
75
|
+
raise
|
|
76
|
+
end
|
|
77
|
+
end
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
# Start the host side of the proxy, which contacts the real server
|
|
80
|
+
thread = Thread.new do
|
|
81
|
+
proxy = LXC::Extra::ProxyServerSide.new(channel) do
|
|
82
|
+
TCPSocket.new(host, uri.port)
|
|
83
|
+
end
|
|
71
84
|
proxy.start
|
|
72
|
-
rescue
|
|
73
|
-
Chef::Log.error("ERROR in proxy (container side): #{$!}\n#{$!.backtrace.join("\n")}")
|
|
74
|
-
raise
|
|
75
85
|
end
|
|
76
|
-
end
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
thread = Thread.new do
|
|
80
|
-
proxy = LXC::Extra::ProxyServerSide.new(channel) do
|
|
81
|
-
TCPSocket.new('127.0.0.1', uri.port)
|
|
82
|
-
end
|
|
83
|
-
proxy.start
|
|
84
|
-
end
|
|
87
|
+
Chef::Log.debug("Forwarded #{uri.port} on container #{name} to local port #{uri.port}. Container listener id PID #{pid}")
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
@port_forwards[uri.port] = [ pid, thread, channel ]
|
|
90
|
+
end
|
|
87
91
|
|
|
88
92
|
end
|
|
89
93
|
local_url
|
|
@@ -111,8 +115,10 @@ module ChefMetalLXC
|
|
|
111
115
|
end
|
|
112
116
|
|
|
113
117
|
def disconnect
|
|
114
|
-
@port_forwards.
|
|
118
|
+
@port_forwards.each_pair do |port, (pid, thread, channel)|
|
|
119
|
+
Chef::Log.debug("stopping port forward #{port} for container #{name}")
|
|
115
120
|
begin
|
|
121
|
+
Chef::Log.debug("Killing PID #{pid}")
|
|
116
122
|
Process.kill('KILL', pid)
|
|
117
123
|
rescue
|
|
118
124
|
end
|
|
@@ -121,7 +127,7 @@ module ChefMetalLXC
|
|
|
121
127
|
rescue
|
|
122
128
|
end
|
|
123
129
|
end
|
|
124
|
-
@port_forwards =
|
|
130
|
+
@port_forwards = {}
|
|
125
131
|
@@active_transports.delete(self)
|
|
126
132
|
end
|
|
127
133
|
|
metadata
CHANGED
|
@@ -1,109 +1,103 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chef-metal-lxc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.5'
|
|
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-
|
|
11
|
+
date: 2014-06-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: chef
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: chef-metal
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - ~>
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0.
|
|
33
|
+
version: '0.11'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - ~>
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0.
|
|
40
|
+
version: '0.11'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: ruby-lxc
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - ~>
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '1.
|
|
48
|
-
- - '>='
|
|
49
|
-
- !ruby/object:Gem::Version
|
|
50
|
-
version: 1.0.2
|
|
47
|
+
version: '1.1'
|
|
51
48
|
type: :runtime
|
|
52
49
|
prerelease: false
|
|
53
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
54
51
|
requirements:
|
|
55
|
-
- - ~>
|
|
56
|
-
- !ruby/object:Gem::Version
|
|
57
|
-
version: '1.0'
|
|
58
|
-
- - '>='
|
|
52
|
+
- - "~>"
|
|
59
53
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 1.
|
|
54
|
+
version: '1.1'
|
|
61
55
|
- !ruby/object:Gem::Dependency
|
|
62
56
|
name: lxc-extra
|
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
|
64
58
|
requirements:
|
|
65
|
-
- - ~>
|
|
59
|
+
- - "~>"
|
|
66
60
|
- !ruby/object:Gem::Version
|
|
67
61
|
version: '0.0'
|
|
68
|
-
- -
|
|
62
|
+
- - ">="
|
|
69
63
|
- !ruby/object:Gem::Version
|
|
70
64
|
version: 0.0.3
|
|
71
65
|
type: :runtime
|
|
72
66
|
prerelease: false
|
|
73
67
|
version_requirements: !ruby/object:Gem::Requirement
|
|
74
68
|
requirements:
|
|
75
|
-
- - ~>
|
|
69
|
+
- - "~>"
|
|
76
70
|
- !ruby/object:Gem::Version
|
|
77
71
|
version: '0.0'
|
|
78
|
-
- -
|
|
72
|
+
- - ">="
|
|
79
73
|
- !ruby/object:Gem::Version
|
|
80
74
|
version: 0.0.3
|
|
81
75
|
- !ruby/object:Gem::Dependency
|
|
82
76
|
name: rspec
|
|
83
77
|
requirement: !ruby/object:Gem::Requirement
|
|
84
78
|
requirements:
|
|
85
|
-
- -
|
|
79
|
+
- - ">="
|
|
86
80
|
- !ruby/object:Gem::Version
|
|
87
81
|
version: '0'
|
|
88
82
|
type: :development
|
|
89
83
|
prerelease: false
|
|
90
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
91
85
|
requirements:
|
|
92
|
-
- -
|
|
86
|
+
- - ">="
|
|
93
87
|
- !ruby/object:Gem::Version
|
|
94
88
|
version: '0'
|
|
95
89
|
- !ruby/object:Gem::Dependency
|
|
96
90
|
name: rake
|
|
97
91
|
requirement: !ruby/object:Gem::Requirement
|
|
98
92
|
requirements:
|
|
99
|
-
- -
|
|
93
|
+
- - ">="
|
|
100
94
|
- !ruby/object:Gem::Version
|
|
101
95
|
version: '0'
|
|
102
96
|
type: :development
|
|
103
97
|
prerelease: false
|
|
104
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
105
99
|
requirements:
|
|
106
|
-
- -
|
|
100
|
+
- - ">="
|
|
107
101
|
- !ruby/object:Gem::Version
|
|
108
102
|
version: '0'
|
|
109
103
|
description: Provisioner for creating LXC containers in Chef Metal.
|
|
@@ -114,13 +108,14 @@ extra_rdoc_files:
|
|
|
114
108
|
- README.md
|
|
115
109
|
- LICENSE
|
|
116
110
|
files:
|
|
117
|
-
- Rakefile
|
|
118
111
|
- LICENSE
|
|
119
112
|
- README.md
|
|
120
|
-
-
|
|
113
|
+
- Rakefile
|
|
114
|
+
- lib/chef_metal/driver_init/lxc.rb
|
|
115
|
+
- lib/chef_metal_lxc.rb
|
|
116
|
+
- lib/chef_metal_lxc/lxc_driver.rb
|
|
121
117
|
- lib/chef_metal_lxc/lxc_transport.rb
|
|
122
118
|
- lib/chef_metal_lxc/version.rb
|
|
123
|
-
- lib/chef_metal_lxc.rb
|
|
124
119
|
homepage: https://github.com/opscode/chef-metal-lxc
|
|
125
120
|
licenses: []
|
|
126
121
|
metadata: {}
|
|
@@ -130,17 +125,17 @@ require_paths:
|
|
|
130
125
|
- lib
|
|
131
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
127
|
requirements:
|
|
133
|
-
- -
|
|
128
|
+
- - ">="
|
|
134
129
|
- !ruby/object:Gem::Version
|
|
135
130
|
version: '0'
|
|
136
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
132
|
requirements:
|
|
138
|
-
- -
|
|
133
|
+
- - ">="
|
|
139
134
|
- !ruby/object:Gem::Version
|
|
140
135
|
version: '0'
|
|
141
136
|
requirements: []
|
|
142
137
|
rubyforge_project:
|
|
143
|
-
rubygems_version: 2.
|
|
138
|
+
rubygems_version: 2.2.2
|
|
144
139
|
signing_key:
|
|
145
140
|
specification_version: 4
|
|
146
141
|
summary: Provisioner for creating LXC containers in Chef Metal.
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
require 'chef/mixin/shell_out'
|
|
2
|
-
require 'chef_metal/provisioner'
|
|
3
|
-
require 'chef_metal/machine/unix_machine'
|
|
4
|
-
require 'chef_metal/convergence_strategy/install_cached'
|
|
5
|
-
require 'chef_metal_lxc/lxc_transport'
|
|
6
|
-
require 'lxc'
|
|
7
|
-
require 'shellwords'
|
|
8
|
-
|
|
9
|
-
module ChefMetalLXC
|
|
10
|
-
# Provisions machines in lxc.
|
|
11
|
-
class LXCProvisioner < ChefMetal::Provisioner
|
|
12
|
-
|
|
13
|
-
include Chef::Mixin::ShellOut
|
|
14
|
-
|
|
15
|
-
def initialize(lxc_path = nil)
|
|
16
|
-
@lxc_path = lxc_path || LXC.global_config_item('lxc.lxcpath')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
attr_reader :lxc_path
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
# Acquire a machine, generally by provisioning it. Returns a Machine
|
|
23
|
-
# object pointing at the machine, allowing useful actions like setup,
|
|
24
|
-
# converge, execute, file and directory. The Machine object will have a
|
|
25
|
-
# "node" property which must be saved to the server (if it is any
|
|
26
|
-
# different from the original node object).
|
|
27
|
-
#
|
|
28
|
-
# ## Parameters
|
|
29
|
-
# action_handler - the action_handler object that provides context.
|
|
30
|
-
# node - node object (deserialized json) representing this machine. If
|
|
31
|
-
# the node has a provisioner_options hash in it, these will be used
|
|
32
|
-
# instead of options provided by the provisioner. TODO compare and
|
|
33
|
-
# fail if different?
|
|
34
|
-
# node will have node['normal']['provisioner_options'] in it with any options.
|
|
35
|
-
# It is a hash with this format:
|
|
36
|
-
#
|
|
37
|
-
# -- provisioner_url: lxc:<lxc_path>
|
|
38
|
-
# -- template: template name
|
|
39
|
-
# -- template_options: additional arguments for templates
|
|
40
|
-
# -- backingstore: backing storage (lvm, thinpools, btrfs etc)
|
|
41
|
-
# -- config_file: <path> path to LXC file a la https://wiki.archlinux.org/index.php/Linux_Containers#Configuration_file
|
|
42
|
-
# -- extra_config: { 'key' => 'value', ... } a set of LXC config key/value pairs to individually set. Merges with, and overrides any values in config_file.
|
|
43
|
-
#
|
|
44
|
-
# node['normal']['provisioner_output'] will be populated with information
|
|
45
|
-
# about the created machine. For lxc, it is a hash with this
|
|
46
|
-
# format:
|
|
47
|
-
#
|
|
48
|
-
# -- provisioner_url: lxc:<lxc_path>
|
|
49
|
-
# -- name: container name
|
|
50
|
-
#
|
|
51
|
-
def acquire_machine(action_handler, node)
|
|
52
|
-
# TODO verify that the existing provisioner_url in the node is the same as ours
|
|
53
|
-
|
|
54
|
-
# Set up the modified node data
|
|
55
|
-
provisioner_options = node['normal']['provisioner_options']
|
|
56
|
-
provisioner_output = node['normal']['provisioner_output'] || {
|
|
57
|
-
'provisioner_url' => "lxc:#{lxc_path}",
|
|
58
|
-
'name' => node['name']
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
# Create the container if it does not exist
|
|
62
|
-
ct = LXC::Container.new(provisioner_output['name'], lxc_path)
|
|
63
|
-
unless ct.defined?
|
|
64
|
-
action_handler.perform_action "create lxc container #{provisioner_output['name']}" do
|
|
65
|
-
#
|
|
66
|
-
# Set config
|
|
67
|
-
#
|
|
68
|
-
# TODO if config file changes, reload container?
|
|
69
|
-
if provisioner_options['config_file']
|
|
70
|
-
ct.load_config(provisioner_options['config_file'])
|
|
71
|
-
end
|
|
72
|
-
if provisioner_options['extra_config']
|
|
73
|
-
provisioner_options['extra_config'].each_pair do |key, value|
|
|
74
|
-
ct.set_config_item(key, value)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
#
|
|
79
|
-
# Create the machine
|
|
80
|
-
#
|
|
81
|
-
ct.create(provisioner_options['template'], provisioner_options['backingstore'], 0, provisioner_options['template_options'])
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Unfreeze the frozen
|
|
86
|
-
if ct.state == :frozen
|
|
87
|
-
action_handler.perform_action "unfreeze lxc container #{provisioner_output['name']} (state is #{ct.state})" do
|
|
88
|
-
ct.unfreeze
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Get stopped containers running
|
|
93
|
-
unless ct.running?
|
|
94
|
-
action_handler.perform_action "start lxc container #{provisioner_output['name']} (state is #{ct.state})" do
|
|
95
|
-
# Have to shell out to lxc-start for now, ct.start holds server sockets open!
|
|
96
|
-
lxc_start = "lxc-start -d -n #{Shellwords.escape(provisioner_output['name'])}"
|
|
97
|
-
# TODO add ability to change options on start
|
|
98
|
-
# if provisioner_options['config_file']
|
|
99
|
-
# lxc_start << " -f #{Shellwords.escape(provisioner_options['config_file'])}"
|
|
100
|
-
# end
|
|
101
|
-
# if provisioner_options['extra_config']
|
|
102
|
-
# provisioner_options['extra_config'].each_pair do |key,value|
|
|
103
|
-
# lxc_start << " -s #{Shellwords.escape("#{key}=#{value}")}"
|
|
104
|
-
# end
|
|
105
|
-
# end
|
|
106
|
-
shell_out!(lxc_start)
|
|
107
|
-
# ct.start
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
node['normal']['provisioner_output'] = provisioner_output
|
|
112
|
-
# Create machine object for callers to use
|
|
113
|
-
machine_for(node)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# Connect to machine without acquiring it
|
|
117
|
-
def connect_to_machine(node)
|
|
118
|
-
machine_for(node)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def delete_machine(action_handler, node)
|
|
122
|
-
if node['normal'] && node['normal']['provisioner_output']
|
|
123
|
-
provisioner_output = node['normal']['provisioner_output']
|
|
124
|
-
ct = LXC::Container.new(provisioner_output['name'], lxc_path)
|
|
125
|
-
if ct.defined?
|
|
126
|
-
action_handler.perform_action "delete lxc container #{provisioner_output['name']}" do
|
|
127
|
-
ct.destroy
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
convergence_strategy_for(node).delete_chef_objects(action_handler, node)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def stop_machine(action_handler, node)
|
|
135
|
-
provisioner_options = node['normal']['provisioner_options']
|
|
136
|
-
if node['normal'] && node['normal']['provisioner_output']
|
|
137
|
-
provisioner_output = node['normal']['provisioner_output']
|
|
138
|
-
ct = LXC::Container.new(provisioner_output['name'], lxc_path)
|
|
139
|
-
if ct.running?
|
|
140
|
-
action_handler.perform_action "delete lxc container #{provisioner_output['name']}" do
|
|
141
|
-
ct.stop
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
protected
|
|
148
|
-
|
|
149
|
-
def machine_for(node)
|
|
150
|
-
ChefMetal::Machine::UnixMachine.new(node, transport_for(node), convergence_strategy_for(node))
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def convergence_strategy_for(node)
|
|
154
|
-
@convergence_strategy ||= begin
|
|
155
|
-
ChefMetal::ConvergenceStrategy::InstallCached.new
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def transport_for(node)
|
|
160
|
-
provisioner_output = node['normal']['provisioner_output']
|
|
161
|
-
ChefMetalLXC::LXCTransport.new(provisioner_output['name'], lxc_path)
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|