chef-metal 0.2.1 → 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +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
|