chef-metal 0.2.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/chef_metal/convergence_strategy/install_cached.rb +121 -0
- data/lib/chef_metal/convergence_strategy/precreate_chef_objects.rb +10 -8
- data/lib/chef_metal/fog.rb +12 -0
- data/lib/chef_metal/machine.rb +10 -0
- data/lib/chef_metal/machine/basic_machine.rb +1 -1
- data/lib/chef_metal/machine/unix_machine.rb +167 -1
- data/lib/chef_metal/provisioner/fog_provisioner.rb +10 -6
- data/lib/chef_metal/provisioner/vagrant_provisioner.rb +9 -5
- data/lib/chef_metal/recipe_dsl.rb +0 -17
- data/lib/chef_metal/vagrant.rb +12 -0
- data/lib/chef_metal/version.rb +1 -1
- metadata +3 -4
- data/lib/chef_metal/provisioner/lxc_provisioner.rb +0 -135
- data/lib/chef_metal/transport/lxc.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b141298163e702535479301b6c88044960e65cc0
|
4
|
+
data.tar.gz: 64383c31616aa7fce1f7785d41134b6516d9b51d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b86349e657a31e3594823b7036aac2c6fd2e5cf2e629da6d1db58a4069502a494bade45142d19db91533cfa66b698600c78f910955cf18a9d8ea0d5754c0e812
|
7
|
+
data.tar.gz: 2dbcb57bdfac12bea0e67c0da47b05a6f9cdc77415d14169820244f4c1ec3172ddc227e19a91f686ae39cc134394fbe11d82d66db9501a3ddbe5ee2b0b3fcba3
|
data/README.md
CHANGED
@@ -120,10 +120,10 @@ chef-metal also comes with a [Fog](http://fog.io/) provisioner that handles prov
|
|
120
120
|
Once your credentials are in, basic usage looks like this:
|
121
121
|
|
122
122
|
```
|
123
|
-
chef-client -z -o myapp::
|
123
|
+
chef-client -z -o myapp::ec2,myapp::small
|
124
124
|
```
|
125
125
|
|
126
|
-
The provisioner definition in `myapp::
|
126
|
+
The provisioner definition in `myapp::ec2` looks like this:
|
127
127
|
|
128
128
|
```ruby
|
129
129
|
ec2testdir = File.expand_path('~/ec2test')
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'chef_metal/convergence_strategy/precreate_chef_objects'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'thread'
|
6
|
+
|
7
|
+
module ChefMetal
|
8
|
+
class ConvergenceStrategy
|
9
|
+
class InstallCached < PrecreateChefObjects
|
10
|
+
def initialize(options = {})
|
11
|
+
@client_rb_path ||= '/etc/chef/client.rb'
|
12
|
+
@client_pem_path ||= '/etc/chef/client.pem'
|
13
|
+
@chef_version ||= options[:chef_version]
|
14
|
+
@prerelease ||= options[:prerelease]
|
15
|
+
@package_cache_path ||= options[:package_cache_path] || "#{ENV['HOME']}/.chef/package_cache"
|
16
|
+
@package_cache = {}
|
17
|
+
@tmp_dir = '/tmp'
|
18
|
+
FileUtils.mkdir_p(@package_cache_path)
|
19
|
+
@download_lock = Mutex.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def setup_convergence(provider, machine, machine_resource)
|
23
|
+
super
|
24
|
+
|
25
|
+
# Install chef-client. TODO check and update version if not latest / not desired
|
26
|
+
if machine.execute_always('chef-client -v').exitstatus != 0
|
27
|
+
platform, platform_version, machine_architecture = machine.detect_os(provider)
|
28
|
+
package_file = download_package_for_platform(provider, machine, platform, platform_version, machine_architecture)
|
29
|
+
remote_package_file = "#{@tmp_dir}/#{File.basename(package_file)}"
|
30
|
+
machine.upload_file(provider, package_file, remote_package_file)
|
31
|
+
install_package(provider, machine, remote_package_file)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def converge(provider, machine)
|
36
|
+
machine.execute(provider, 'chef-client')
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def download_package_for_platform(provider, machine, platform, platform_version, machine_architecture)
|
42
|
+
@package_cache_lock.synchronize do
|
43
|
+
@package_cache ||= {}
|
44
|
+
@package_cache[platform] ||= {}
|
45
|
+
@package_cache[platform][platform_version] ||= {}
|
46
|
+
@package_cache[platform][platform_version][machine_architecture] ||= { :lock => Mutex.new }
|
47
|
+
end
|
48
|
+
@package_cache[platform][platform_version][machine_architecture][:lock].synchronize do
|
49
|
+
if !@package_cache[platform][platform_version][machine_architecture][:file]
|
50
|
+
#
|
51
|
+
# Grab metadata
|
52
|
+
#
|
53
|
+
metadata = download_metadata_for_platform(machine, platform, platform_version, machine_architecture)
|
54
|
+
|
55
|
+
# Download actual package desired by metadata
|
56
|
+
package_file = "#{@package_cache_path}/#{URI(metadata['url']).path.split('/')[-1]}"
|
57
|
+
|
58
|
+
ChefMetal.inline_resource(provider) do
|
59
|
+
remote_file package_file do
|
60
|
+
source metadata['url']
|
61
|
+
checksum metadata['sha256']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
@package_cache[platform][platform_version][machine_architecture][:file] = package_file
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@package_cache[platform][platform_version][machine_architecture][:file]
|
69
|
+
end
|
70
|
+
|
71
|
+
def download_metadata_for_platform(machine, platform, platform_version, machine_architecture)
|
72
|
+
#
|
73
|
+
# Figure out the URL to the metadata
|
74
|
+
#
|
75
|
+
metadata_url="https://www.opscode.com/chef/metadata"
|
76
|
+
metadata_url << "?v=#{@chef_version}"
|
77
|
+
metadata_url << "&prerelease=#{@prerelease ? 'true' : 'false'}"
|
78
|
+
metadata_url << "&p=#{platform}"
|
79
|
+
metadata_url << "&pv=#{platform_version}"
|
80
|
+
metadata_url << "&m=#{machine_architecture}"
|
81
|
+
|
82
|
+
# solaris 9 lacks openssl, solaris 10 lacks recent enough credentials - your base O/S is completely insecure, please upgrade
|
83
|
+
if platform == 'solaris2' && (platform_version == '5.9' || platform_version == '5.10')
|
84
|
+
metadata_url.sub(/^https/, 'http')
|
85
|
+
end
|
86
|
+
|
87
|
+
# Download and parse the metadata
|
88
|
+
Chef::Log.debug("Getting metadata for machine #{machine.node['name']}: #{metadata_url}")
|
89
|
+
metadata_str = Net::HTTP.get(URI(metadata_url))
|
90
|
+
metadata = {}
|
91
|
+
metadata_str.each_line do |line|
|
92
|
+
key, value = line.split("\t", 2)
|
93
|
+
metadata[key] = value
|
94
|
+
end
|
95
|
+
metadata
|
96
|
+
end
|
97
|
+
|
98
|
+
def install_package(provider, machine, remote_package_file)
|
99
|
+
extension = File.extname(remote_package_file)
|
100
|
+
result = case extension
|
101
|
+
when '.rpm'
|
102
|
+
machine.execute(provider, "rpm -Uvh --oldpackage --replacepkgs \"#{remote_package_file}\"")
|
103
|
+
when '.deb'
|
104
|
+
machine.execute(provider, "dpkg -i \"#{remote_package_file}\"")
|
105
|
+
when '.solaris'
|
106
|
+
machine.write_file(provider, "#{@tmp_dir}/nocheck", <<EOM)
|
107
|
+
conflict=nocheck
|
108
|
+
action=nocheck
|
109
|
+
mail=
|
110
|
+
EOM
|
111
|
+
machine.execute(provider, "pkgrm -a \"#{@tmp_dir}/nocheck\" -n chef")
|
112
|
+
machine.execute(provider, "pkgadd -n -d \"#{remote_package_file}\" -a \"#{@tmp_dir}/nocheck\" chef")
|
113
|
+
when '.sh'
|
114
|
+
machine.execute(provider, "sh \"#{remote_package_file}\"")
|
115
|
+
else
|
116
|
+
raise "Unknown package extension '#{extension}' for file #{remote_package_file}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -68,7 +68,7 @@ module ChefMetal
|
|
68
68
|
end
|
69
69
|
|
70
70
|
else
|
71
|
-
|
71
|
+
|
72
72
|
# If the server does not already have keys, create them and upload
|
73
73
|
Cheffish.inline_resource(provider) do
|
74
74
|
private_key 'in_memory' do
|
@@ -109,13 +109,6 @@ module ChefMetal
|
|
109
109
|
def create_chef_objects(provider, machine, machine_resource, public_key)
|
110
110
|
# Save the node and create the client keys and client.
|
111
111
|
ChefMetal.inline_resource(provider) do
|
112
|
-
# Create node
|
113
|
-
# TODO strip automatic attributes first so we don't race with "current state"
|
114
|
-
chef_node machine.node['name'] do
|
115
|
-
chef_server machine_resource.chef_server
|
116
|
-
raw_json machine.node
|
117
|
-
end
|
118
|
-
|
119
112
|
# Create client
|
120
113
|
chef_client machine.node['name'] do
|
121
114
|
chef_server machine_resource.chef_server
|
@@ -125,6 +118,15 @@ module ChefMetal
|
|
125
118
|
admin machine_resource.admin
|
126
119
|
validator machine_resource.validator
|
127
120
|
end
|
121
|
+
|
122
|
+
# Create node
|
123
|
+
# TODO strip automatic attributes first so we don't race with "current state"
|
124
|
+
chef_node machine.node['name'] do
|
125
|
+
chef_server machine_resource.chef_server
|
126
|
+
raw_json machine.node
|
127
|
+
end
|
128
|
+
|
129
|
+
|
128
130
|
end
|
129
131
|
end
|
130
132
|
|
data/lib/chef_metal/fog.rb
CHANGED
@@ -2,3 +2,15 @@ require 'chef_metal'
|
|
2
2
|
require 'chef/resource/fog_key_pair'
|
3
3
|
require 'chef/provider/fog_key_pair'
|
4
4
|
require 'chef_metal/provisioner/fog_provisioner'
|
5
|
+
|
6
|
+
class Chef
|
7
|
+
class Recipe
|
8
|
+
def with_fog_provisioner(options = {}, &block)
|
9
|
+
ChefMetal.with_provisioner(ChefMetal::Provisioner::FogProvisioner.new(options, &block))
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_fog_ec2_provisioner(options = {}, &block)
|
13
|
+
with_fog_provisioner({ :provider => 'AWS' }.merge(options), &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/chef_metal/machine.rb
CHANGED
@@ -75,5 +75,15 @@ module ChefMetal
|
|
75
75
|
def disconnect
|
76
76
|
raise "disconnect not overridden on #{self.class}"
|
77
77
|
end
|
78
|
+
|
79
|
+
# TODO get rid of the provider attribute, that is ridiculous
|
80
|
+
# Detect the OS on the machine (assumes the machine is up)
|
81
|
+
# Returns a triplet:
|
82
|
+
# platform, platform_version, machine_architecture = machine.detect_os(provider)
|
83
|
+
# This triplet is suitable for passing to the Chef metadata API:
|
84
|
+
# https://www.opscode.com/chef/metadata?p=#{platform}&pv=#{platform_version}&m=#{machine_architecture}
|
85
|
+
def detect_os(provider)
|
86
|
+
raise "detect_os not overridden on #{self.class}"
|
87
|
+
end
|
78
88
|
end
|
79
89
|
end
|
@@ -6,6 +6,8 @@ module ChefMetal
|
|
6
6
|
class UnixMachine < BasicMachine
|
7
7
|
def initialize(node, transport, convergence_strategy)
|
8
8
|
super
|
9
|
+
|
10
|
+
@tmp_dir = '/tmp'
|
9
11
|
end
|
10
12
|
|
11
13
|
# Options include:
|
@@ -104,5 +106,169 @@ module ChefMetal
|
|
104
106
|
path.split('/')[0..-2].join('/')
|
105
107
|
end
|
106
108
|
end
|
109
|
+
|
110
|
+
def detect_os(provider)
|
111
|
+
#
|
112
|
+
# Use detect.sh to detect the operating system of the remote machine
|
113
|
+
#
|
114
|
+
# TODO do this in terms of commands rather than writing a shell script
|
115
|
+
self.write_file(provider, "#{@tmp_dir}/detect.sh", detect_sh)
|
116
|
+
detected = self.execute_always("sh #{@tmp_dir}/detect.sh")
|
117
|
+
if detected.exitstatus != 0
|
118
|
+
raise "detect.sh exited with nonzero exit status: #{detected.exitstatus}"
|
119
|
+
end
|
120
|
+
platform = nil
|
121
|
+
platform_version = nil
|
122
|
+
machine_architecture = nil
|
123
|
+
detected.stdout.each_line do |line|
|
124
|
+
if line =~ /^PLATFORM: (.+)/
|
125
|
+
platform = $1
|
126
|
+
elsif line =~ /^PLATFORM_VERSION: (.+)/
|
127
|
+
platform_version = $1
|
128
|
+
elsif line =~ /^MACHINE: (.+)/
|
129
|
+
machine_architecture = $1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
[ platform, platform_version, machine_architecture ]
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def detect_sh
|
138
|
+
result = <<EOM
|
139
|
+
prerelease="false"
|
140
|
+
|
141
|
+
project="chef"
|
142
|
+
|
143
|
+
report_bug() {
|
144
|
+
echo "Please file a bug report at http://tickets.opscode.com"
|
145
|
+
echo "Project: Chef"
|
146
|
+
echo "Component: Packages"
|
147
|
+
echo "Label: Omnibus"
|
148
|
+
echo "Version: $version"
|
149
|
+
echo " "
|
150
|
+
echo "Please detail your operating system type, version and any other relevant details"
|
151
|
+
}
|
152
|
+
|
153
|
+
|
154
|
+
machine=`uname -m`
|
155
|
+
os=`uname -s`
|
156
|
+
|
157
|
+
# Retrieve Platform and Platform Version
|
158
|
+
if test -f "/etc/lsb-release" && grep -q DISTRIB_ID /etc/lsb-release; then
|
159
|
+
platform=`grep DISTRIB_ID /etc/lsb-release | cut -d "=" -f 2 | tr '[A-Z]' '[a-z]'`
|
160
|
+
platform_version=`grep DISTRIB_RELEASE /etc/lsb-release | cut -d "=" -f 2`
|
161
|
+
elif test -f "/etc/debian_version"; then
|
162
|
+
platform="debian"
|
163
|
+
platform_version=`cat /etc/debian_version`
|
164
|
+
elif test -f "/etc/redhat-release"; then
|
165
|
+
platform=`sed 's/^\(.\+\) release.*/\1/' /etc/redhat-release | tr '[A-Z]' '[a-z]'`
|
166
|
+
platform_version=`sed 's/^.\+ release \([.0-9]\+\).*/\1/' /etc/redhat-release`
|
167
|
+
|
168
|
+
# If /etc/redhat-release exists, we act like RHEL by default
|
169
|
+
if test "$platform" = "fedora"; then
|
170
|
+
# Change platform version for use below.
|
171
|
+
platform_version="6.0"
|
172
|
+
fi
|
173
|
+
platform="el"
|
174
|
+
elif test -f "/etc/system-release"; then
|
175
|
+
platform=`sed 's/^\(.\+\) release.\+/\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
|
176
|
+
platform_version=`sed 's/^.\+ release \([.0-9]\+\).*/\1/' /etc/system-release | tr '[A-Z]' '[a-z]'`
|
177
|
+
# amazon is built off of fedora, so act like RHEL
|
178
|
+
if test "$platform" = "amazon linux ami"; then
|
179
|
+
platform="el"
|
180
|
+
platform_version="6.0"
|
181
|
+
fi
|
182
|
+
# Apple OS X
|
183
|
+
elif test -f "/usr/bin/sw_vers"; then
|
184
|
+
platform="mac_os_x"
|
185
|
+
# Matching the tab-space with sed is error-prone
|
186
|
+
platform_version=`sw_vers | awk '/^ProductVersion:/ { print $2 }'`
|
187
|
+
|
188
|
+
major_version=`echo $platform_version | cut -d. -f1,2`
|
189
|
+
case $major_version in
|
190
|
+
"10.6") platform_version="10.6" ;;
|
191
|
+
"10.7"|"10.8"|"10.9") platform_version="10.7" ;;
|
192
|
+
*) echo "No builds for platform: $major_version"
|
193
|
+
report_bug
|
194
|
+
exit 1
|
195
|
+
;;
|
196
|
+
esac
|
197
|
+
|
198
|
+
# x86_64 Apple hardware often runs 32-bit kernels (see OHAI-63)
|
199
|
+
x86_64=`sysctl -n hw.optional.x86_64`
|
200
|
+
if test $x86_64 -eq 1; then
|
201
|
+
machine="x86_64"
|
202
|
+
fi
|
203
|
+
elif test -f "/etc/release"; then
|
204
|
+
platform="solaris2"
|
205
|
+
machine=`/usr/bin/uname -p`
|
206
|
+
platform_version=`/usr/bin/uname -r`
|
207
|
+
elif test -f "/etc/SuSE-release"; then
|
208
|
+
if grep -q 'Enterprise' /etc/SuSE-release;
|
209
|
+
then
|
210
|
+
platform="sles"
|
211
|
+
platform_version=`awk '/^VERSION/ {V = $3}; /^PATCHLEVEL/ {P = $3}; END {print V "." P}' /etc/SuSE-release`
|
212
|
+
else
|
213
|
+
platform="suse"
|
214
|
+
platform_version=`awk '/^VERSION =/ { print $3 }' /etc/SuSE-release`
|
215
|
+
fi
|
216
|
+
elif test "x$os" = "xFreeBSD"; then
|
217
|
+
platform="freebsd"
|
218
|
+
platform_version=`uname -r | sed 's/-.*//'`
|
219
|
+
elif test "x$os" = "xAIX"; then
|
220
|
+
platform="aix"
|
221
|
+
platform_version=`uname -v`
|
222
|
+
machine="ppc"
|
223
|
+
fi
|
224
|
+
|
225
|
+
if test "x$platform" = "x"; then
|
226
|
+
echo "Unable to determine platform version!"
|
227
|
+
report_bug
|
228
|
+
exit 1
|
229
|
+
fi
|
230
|
+
|
231
|
+
# Mangle $platform_version to pull the correct build
|
232
|
+
# for various platforms
|
233
|
+
major_version=`echo $platform_version | cut -d. -f1`
|
234
|
+
case $platform in
|
235
|
+
"el")
|
236
|
+
platform_version=$major_version
|
237
|
+
;;
|
238
|
+
"debian")
|
239
|
+
case $major_version in
|
240
|
+
"5") platform_version="6";;
|
241
|
+
"6") platform_version="6";;
|
242
|
+
"7") platform_version="6";;
|
243
|
+
esac
|
244
|
+
;;
|
245
|
+
"freebsd")
|
246
|
+
platform_version=$major_version
|
247
|
+
;;
|
248
|
+
"sles")
|
249
|
+
platform_version=$major_version
|
250
|
+
;;
|
251
|
+
"suse")
|
252
|
+
platform_version=$major_version
|
253
|
+
;;
|
254
|
+
esac
|
255
|
+
|
256
|
+
if test "x$platform_version" = "x"; then
|
257
|
+
echo "Unable to determine platform version!"
|
258
|
+
report_bug
|
259
|
+
exit 1
|
260
|
+
fi
|
261
|
+
|
262
|
+
if test "x$platform" = "xsolaris2"; then
|
263
|
+
# hack up the path on Solaris to find wget
|
264
|
+
PATH=/usr/sfw/bin:$PATH
|
265
|
+
export PATH
|
266
|
+
fi
|
267
|
+
|
268
|
+
echo "PLATFORM: $platform"
|
269
|
+
echo "PLATFORM_VERSION: $platform_version"
|
270
|
+
echo "MACHINE: $machine"
|
271
|
+
EOM
|
272
|
+
end
|
107
273
|
end
|
108
|
-
end
|
274
|
+
end
|
@@ -213,7 +213,7 @@ module ChefMetal
|
|
213
213
|
def delete_machine(provider, node)
|
214
214
|
if node['normal']['provisioner_output'] && node['normal']['provisioner_output']['server_id']
|
215
215
|
server = compute.servers.get(node['normal']['provisioner_output']['server_id'])
|
216
|
-
provider.converge_by "destroy machine #{node['name']} (#{
|
216
|
+
provider.converge_by "destroy machine #{node['name']} (#{node['normal']['provisioner_output']['server_id']} at #{provisioner_url})" do
|
217
217
|
server.destroy
|
218
218
|
end
|
219
219
|
convergence_strategy_for(node).delete_chef_objects(provider, node)
|
@@ -345,11 +345,15 @@ module ChefMetal
|
|
345
345
|
|
346
346
|
def convergence_strategy_for(node)
|
347
347
|
if node['normal']['provisioner_options'] && node['normal']['provisioner_options']['is_windows']
|
348
|
-
|
349
|
-
|
348
|
+
@windows_convergence_strategy ||= begin
|
349
|
+
require 'chef_metal/convergence_strategy/install_msi'
|
350
|
+
ChefMetal::ConvergenceStrategy::InstallMsi.new
|
351
|
+
end
|
350
352
|
else
|
351
|
-
|
352
|
-
|
353
|
+
@unix_convergence_strategy ||= begin
|
354
|
+
require 'chef_metal/convergence_strategy/install_cached'
|
355
|
+
ChefMetal::ConvergenceStrategy::InstallCached.new
|
356
|
+
end
|
353
357
|
end
|
354
358
|
end
|
355
359
|
|
@@ -377,7 +381,7 @@ module ChefMetal
|
|
377
381
|
def create_ssh_transport(server)
|
378
382
|
require 'chef_metal/transport/ssh'
|
379
383
|
|
380
|
-
ssh_options
|
384
|
+
ssh_options = ssh_options_for(server)
|
381
385
|
# If we're on AWS, the default is to use ubuntu, not root
|
382
386
|
if compute_options[:provider] == 'AWS'
|
383
387
|
username = compute_options[:ssh_username] || 'ubuntu'
|
@@ -221,11 +221,15 @@ module ChefMetal
|
|
221
221
|
|
222
222
|
def convergence_strategy_for(node)
|
223
223
|
if vagrant_option(node, 'vm.guest').to_s == 'windows'
|
224
|
-
|
225
|
-
|
224
|
+
@windows_convergence_strategy ||= begin
|
225
|
+
require 'chef_metal/convergence_strategy/install_msi'
|
226
|
+
ChefMetal::ConvergenceStrategy::InstallMsi.new
|
227
|
+
end
|
226
228
|
else
|
227
|
-
|
228
|
-
|
229
|
+
@unix_convergence_strategy ||= begin
|
230
|
+
require 'chef_metal/convergence_strategy/install_cached'
|
231
|
+
ChefMetal::ConvergenceStrategy::InstallCached.new
|
232
|
+
end
|
229
233
|
end
|
230
234
|
end
|
231
235
|
|
@@ -324,4 +328,4 @@ module ChefMetal
|
|
324
328
|
end
|
325
329
|
end
|
326
330
|
end
|
327
|
-
end
|
331
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'chef_metal'
|
2
|
-
require 'chef_metal/provisioner/fog_provisioner'
|
3
2
|
|
4
3
|
class Chef
|
5
4
|
class Recipe
|
@@ -10,21 +9,5 @@ class Chef
|
|
10
9
|
def with_provisioner_options(provisioner_options, &block)
|
11
10
|
ChefMetal.with_provisioner_options(provisioner_options, &block)
|
12
11
|
end
|
13
|
-
|
14
|
-
def with_vagrant_cluster(cluster_path, &block)
|
15
|
-
ChefMetal.with_vagrant_cluster(cluster_path, &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def with_vagrant_box(box_name, vagrant_options = {}, &block)
|
19
|
-
ChefMetal.with_vagrant_box(box_name, vagrant_options, &block)
|
20
|
-
end
|
21
|
-
|
22
|
-
def with_fog_provisioner(options = {}, &block)
|
23
|
-
ChefMetal.with_provisioner(ChefMetal::Provisioner::FogProvisioner.new(options, &block))
|
24
|
-
end
|
25
|
-
|
26
|
-
def with_fog_ec2_provisioner(options = {}, &block)
|
27
|
-
with_fog_provisioner({ :provider => 'AWS' }.merge(options), &block)
|
28
|
-
end
|
29
12
|
end
|
30
13
|
end
|
data/lib/chef_metal/vagrant.rb
CHANGED
@@ -25,3 +25,15 @@ module ChefMetal
|
|
25
25
|
with_provisioner_options(provisioner_options, &block)
|
26
26
|
end
|
27
27
|
end
|
28
|
+
|
29
|
+
class Chef
|
30
|
+
class Recipe
|
31
|
+
def with_vagrant_cluster(cluster_path, &block)
|
32
|
+
ChefMetal.with_vagrant_cluster(cluster_path, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_vagrant_box(box_name, vagrant_options = {}, &block)
|
36
|
+
ChefMetal.with_vagrant_box(box_name, vagrant_options, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/chef_metal/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-metal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Keiser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- lib/chef/resource/vagrant_box.rb
|
131
131
|
- lib/chef/resource/vagrant_cluster.rb
|
132
132
|
- lib/chef_metal/aws_credentials.rb
|
133
|
+
- lib/chef_metal/convergence_strategy/install_cached.rb
|
133
134
|
- lib/chef_metal/convergence_strategy/install_msi.rb
|
134
135
|
- lib/chef_metal/convergence_strategy/install_sh.rb
|
135
136
|
- lib/chef_metal/convergence_strategy/precreate_chef_objects.rb
|
@@ -141,11 +142,9 @@ files:
|
|
141
142
|
- lib/chef_metal/machine/windows_machine.rb
|
142
143
|
- lib/chef_metal/machine.rb
|
143
144
|
- lib/chef_metal/provisioner/fog_provisioner.rb
|
144
|
-
- lib/chef_metal/provisioner/lxc_provisioner.rb
|
145
145
|
- lib/chef_metal/provisioner/vagrant_provisioner.rb
|
146
146
|
- lib/chef_metal/provisioner.rb
|
147
147
|
- lib/chef_metal/recipe_dsl.rb
|
148
|
-
- lib/chef_metal/transport/lxc.rb
|
149
148
|
- lib/chef_metal/transport/ssh.rb
|
150
149
|
- lib/chef_metal/transport/winrm.rb
|
151
150
|
- lib/chef_metal/transport.rb
|
@@ -1,135 +0,0 @@
|
|
1
|
-
require 'chef/mixin/shell_out'
|
2
|
-
require 'chef_metal/provisioner'
|
3
|
-
require 'lxc'
|
4
|
-
|
5
|
-
module ChefMetal
|
6
|
-
class Provisioner
|
7
|
-
|
8
|
-
# Provisions machines in lxc.
|
9
|
-
class LXCProvisioner < Provisioner
|
10
|
-
|
11
|
-
include Chef::Mixin::ShellOut
|
12
|
-
|
13
|
-
#
|
14
|
-
# Acquire a machine, generally by provisioning it. Returns a Machine
|
15
|
-
# object pointing at the machine, allowing useful actions like setup,
|
16
|
-
# converge, execute, file and directory. The Machine object will have a
|
17
|
-
# "node" property which must be saved to the server (if it is any
|
18
|
-
# different from the original node object).
|
19
|
-
#
|
20
|
-
# ## Parameters
|
21
|
-
# provider - the provider object that is calling this method.
|
22
|
-
# node - node object (deserialized json) representing this machine. If
|
23
|
-
# the node has a provisioner_options hash in it, these will be used
|
24
|
-
# instead of options provided by the provisioner. TODO compare and
|
25
|
-
# fail if different?
|
26
|
-
# node will have node['normal']['provisioner_options'] in it with any options.
|
27
|
-
# It is a hash with this format:
|
28
|
-
#
|
29
|
-
# -- provisioner_url: lxc:<lxc_path>
|
30
|
-
# -- template: template name
|
31
|
-
# -- template_options: additional arguments for templates
|
32
|
-
# -- backingstore: backing storage (lvm, thinpools, btrfs etc)
|
33
|
-
#
|
34
|
-
# node['normal']['provisioner_output'] will be populated with information
|
35
|
-
# about the created machine. For lxc, it is a hash with this
|
36
|
-
# format:
|
37
|
-
#
|
38
|
-
# -- provisioner_url: lxc://<lxc_path>
|
39
|
-
# -- lxc_path: path to lxc root
|
40
|
-
# -- name: container name
|
41
|
-
#
|
42
|
-
def acquire_machine(provider, node)
|
43
|
-
# TODO verify that the existing provisioner_url in the node is the same as ours
|
44
|
-
|
45
|
-
# Set up the modified node data
|
46
|
-
provisioner_options = node['normal']['provisioner_options']
|
47
|
-
provisioner_output = node['normal']['provisioner_output'] || {
|
48
|
-
'provisioner_url' => "lxc://#{lxc_path_for(node)}",
|
49
|
-
'name' => node['name']
|
50
|
-
}
|
51
|
-
|
52
|
-
|
53
|
-
# Create the container if it does not exist
|
54
|
-
ct = LXC::Container.new(provisioner_output['name'], lxc_path_for(node))
|
55
|
-
unless ct.defined?
|
56
|
-
provider.converge_by "create lxc container #{provisioner_output['name']}" do
|
57
|
-
ct.create(provisioner_options['template'], provisioner_options['backingstore'], 0, provisioner_options['template_options'])
|
58
|
-
end
|
59
|
-
end
|
60
|
-
unless ct.running?
|
61
|
-
provider.converge_by "start lxc container #{provisioner_output['name']}" do
|
62
|
-
ct.start
|
63
|
-
while ct.ip_addresses.empty?
|
64
|
-
sleep 1 # wait till dhcp ip allocation is done
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
if true # do a check on whether sshd is installed. This is idempotency!
|
70
|
-
provider.converge_by "install ssh into container #{provisioner_output['name']}" do
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
node['normal']['provisioner_output'] = provisioner_output
|
75
|
-
|
76
|
-
# Create machine object for callers to use
|
77
|
-
machine_for(node)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Connect to machine without acquiring it
|
81
|
-
def connect_to_machine(node)
|
82
|
-
machine_for(node)
|
83
|
-
end
|
84
|
-
|
85
|
-
def delete_machine(provider, node)
|
86
|
-
if node['normal'] && node['normal']['provisioner_output']
|
87
|
-
provisioner_output = node['normal']['provisioner_output']
|
88
|
-
ct = LXC::Container.new(provisioner_output['name'], lxc_path_for(node))
|
89
|
-
if ct.defined?
|
90
|
-
provider.converge_by "delete lxc container #{provisioner_output['name']}" do
|
91
|
-
ct.destroy
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
convergence_strategy_for(node).delete_chef_objects(provider, node)
|
96
|
-
end
|
97
|
-
|
98
|
-
def stop_machine(provider, node)
|
99
|
-
provisioner_options = node['normal']['provisioner_options']
|
100
|
-
if node['normal'] && node['normal']['provisioner_output']
|
101
|
-
provisioner_output = node['normal']['provisioner_output']
|
102
|
-
ct = LXC::Container.new(provisioner_output['name'], lxc_path_for(node))
|
103
|
-
if ct.running?
|
104
|
-
provider.converge_by "delete lxc container #{provisioner_output['name']}" do
|
105
|
-
ct.stop
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
protected
|
112
|
-
|
113
|
-
def lxc_path_for(node)
|
114
|
-
provisioner_options = node['normal']['provisioner_options']
|
115
|
-
provisioner_options['lxc_path'] || LXC.global_config_item('lxc.lxcpath')
|
116
|
-
end
|
117
|
-
|
118
|
-
def machine_for(node)
|
119
|
-
require 'chef_metal/machine/unix_machine'
|
120
|
-
ChefMetal::Machine::UnixMachine.new(node, transport_for(node), convergence_strategy_for(node))
|
121
|
-
end
|
122
|
-
|
123
|
-
def convergence_strategy_for(node)
|
124
|
-
require 'chef_metal/convergence_strategy/install_sh'
|
125
|
-
ChefMetal::ConvergenceStrategy::InstallSh.new
|
126
|
-
end
|
127
|
-
|
128
|
-
def transport_for(node)
|
129
|
-
require 'chef_metal/transport/lxc'
|
130
|
-
provisioner_output = node['normal']['provisioner_output']
|
131
|
-
ChefMetal::Transport::LXCTransport.new(provisioner_output['name'], lxc_path_for(node))
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'chef_metal/transport'
|
2
|
-
require 'lxc/extra'
|
3
|
-
require 'chef/mixin/shell_out'
|
4
|
-
|
5
|
-
module ChefMetal
|
6
|
-
class Transport
|
7
|
-
class LXCTransport < Transport
|
8
|
-
|
9
|
-
class LXCExecuteResult < Struct.new(:stdout, :stderr, :exitstatus)
|
10
|
-
def error!
|
11
|
-
raise "Error: code #{exitstatus}.\nSTDOUT:#{stdout}\nSTDERR:#{stderr}" if exitstatus != 0
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_reader :name, :options, :lxc_path
|
16
|
-
|
17
|
-
include Chef::Mixin::ShellOut
|
18
|
-
|
19
|
-
def initialize(name, lxc_path, options={})
|
20
|
-
@options = options
|
21
|
-
@name = name
|
22
|
-
@lxc_path = lxc_path
|
23
|
-
end
|
24
|
-
|
25
|
-
def ct
|
26
|
-
@container ||= LXC::Container.new(name, lxc_path)
|
27
|
-
end
|
28
|
-
|
29
|
-
def rootfs
|
30
|
-
ct.config_item('lxc.rootfs')
|
31
|
-
end
|
32
|
-
|
33
|
-
def ct_path(path)
|
34
|
-
File.join(rootfs, path)
|
35
|
-
end
|
36
|
-
|
37
|
-
def execute(command)
|
38
|
-
Chef::Log.info("Executing #{command} on #{name}")
|
39
|
-
res = ct.execute do
|
40
|
-
begin
|
41
|
-
out = shell_out(command)
|
42
|
-
LXCExecuteResult.new(out.stdout,out.stderr, out.exitstatus)
|
43
|
-
rescue Exception => e
|
44
|
-
LXCExecuteResult.new('', e.message, -1)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
res
|
48
|
-
end
|
49
|
-
|
50
|
-
def forward_remote_port_to_local(remote_port, local_port)
|
51
|
-
warn 'Port forwarding is not implemented in lxc transport'
|
52
|
-
warn "You can do this on host using:"
|
53
|
-
warn " 'iptables -t nat -A PREROUTING -p tcp --dport #{remote_port} -j DNAT --to #{ct.ip_addresses.first}:#{local_port}'"
|
54
|
-
end
|
55
|
-
|
56
|
-
def read_file(path)
|
57
|
-
if File.exists?(ct_path(path))
|
58
|
-
File.read(ct_path(path))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def download_file(path, local_path)
|
63
|
-
Chef::Log.debug("Copying file #{path} from #{name} to local #{local_path}")
|
64
|
-
FileUtils.cp_r(ct_path(path), local_path)
|
65
|
-
end
|
66
|
-
|
67
|
-
def write_file(path, content)
|
68
|
-
File.open(ct_path(path), 'w') do |f|
|
69
|
-
f.write(content)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def upload_file(local_path, path)
|
74
|
-
FileUtils.cp_r(local_path, ct_path(path))
|
75
|
-
end
|
76
|
-
|
77
|
-
def disconnect
|
78
|
-
end
|
79
|
-
|
80
|
-
def available?
|
81
|
-
begin
|
82
|
-
execute('pwd')
|
83
|
-
true
|
84
|
-
rescue Exception =>e
|
85
|
-
false
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|