chef 0.7.10
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of chef might be problematic. Click here for more details.
- data/LICENSE +201 -0
- data/README.rdoc +135 -0
- data/bin/chef-client +26 -0
- data/bin/chef-solo +26 -0
- data/lib/chef.rb +49 -0
- data/lib/chef/application.rb +98 -0
- data/lib/chef/application/agent.rb +18 -0
- data/lib/chef/application/client.rb +209 -0
- data/lib/chef/application/indexer.rb +141 -0
- data/lib/chef/application/server.rb +18 -0
- data/lib/chef/application/solo.rb +214 -0
- data/lib/chef/client.rb +396 -0
- data/lib/chef/compile.rb +138 -0
- data/lib/chef/config.rb +141 -0
- data/lib/chef/cookbook.rb +144 -0
- data/lib/chef/cookbook/metadata.rb +407 -0
- data/lib/chef/cookbook/metadata/version.rb +87 -0
- data/lib/chef/cookbook_loader.rb +168 -0
- data/lib/chef/couchdb.rb +172 -0
- data/lib/chef/daemon.rb +170 -0
- data/lib/chef/exceptions.rb +36 -0
- data/lib/chef/file_cache.rb +205 -0
- data/lib/chef/log.rb +39 -0
- data/lib/chef/mixin/check_helper.rb +31 -0
- data/lib/chef/mixin/checksum.rb +37 -0
- data/lib/chef/mixin/command.rb +351 -0
- data/lib/chef/mixin/create_path.rb +56 -0
- data/lib/chef/mixin/deep_merge.rb +36 -0
- data/lib/chef/mixin/find_preferred_file.rb +99 -0
- data/lib/chef/mixin/from_file.rb +36 -0
- data/lib/chef/mixin/generate_url.rb +48 -0
- data/lib/chef/mixin/language.rb +79 -0
- data/lib/chef/mixin/params_validate.rb +197 -0
- data/lib/chef/mixin/template.rb +84 -0
- data/lib/chef/node.rb +406 -0
- data/lib/chef/node/attribute.rb +412 -0
- data/lib/chef/openid_registration.rb +181 -0
- data/lib/chef/platform.rb +253 -0
- data/lib/chef/provider.rb +40 -0
- data/lib/chef/provider/cron.rb +137 -0
- data/lib/chef/provider/directory.rb +72 -0
- data/lib/chef/provider/execute.rb +58 -0
- data/lib/chef/provider/file.rb +191 -0
- data/lib/chef/provider/group.rb +120 -0
- data/lib/chef/provider/group/groupadd.rb +92 -0
- data/lib/chef/provider/group/pw.rb +88 -0
- data/lib/chef/provider/http_request.rb +102 -0
- data/lib/chef/provider/ifconfig.rb +131 -0
- data/lib/chef/provider/link.rb +157 -0
- data/lib/chef/provider/mount.rb +121 -0
- data/lib/chef/provider/mount/mount.rb +208 -0
- data/lib/chef/provider/package.rb +160 -0
- data/lib/chef/provider/package/apt.rb +110 -0
- data/lib/chef/provider/package/dpkg.rb +113 -0
- data/lib/chef/provider/package/freebsd.rb +153 -0
- data/lib/chef/provider/package/macports.rb +105 -0
- data/lib/chef/provider/package/portage.rb +124 -0
- data/lib/chef/provider/package/rpm.rb +99 -0
- data/lib/chef/provider/package/rubygems.rb +130 -0
- data/lib/chef/provider/package/yum-dump.py +104 -0
- data/lib/chef/provider/package/yum.rb +175 -0
- data/lib/chef/provider/remote_directory.rb +126 -0
- data/lib/chef/provider/remote_file.rb +134 -0
- data/lib/chef/provider/route.rb +118 -0
- data/lib/chef/provider/ruby_block.rb +15 -0
- data/lib/chef/provider/script.rb +42 -0
- data/lib/chef/provider/service.rb +129 -0
- data/lib/chef/provider/service/debian.rb +64 -0
- data/lib/chef/provider/service/freebsd.rb +157 -0
- data/lib/chef/provider/service/gentoo.rb +54 -0
- data/lib/chef/provider/service/init.rb +126 -0
- data/lib/chef/provider/service/redhat.rb +62 -0
- data/lib/chef/provider/template.rb +141 -0
- data/lib/chef/provider/user.rb +170 -0
- data/lib/chef/provider/user/pw.rb +113 -0
- data/lib/chef/provider/user/useradd.rb +107 -0
- data/lib/chef/queue.rb +145 -0
- data/lib/chef/recipe.rb +210 -0
- data/lib/chef/resource.rb +256 -0
- data/lib/chef/resource/apt_package.rb +34 -0
- data/lib/chef/resource/bash.rb +33 -0
- data/lib/chef/resource/cron.rb +143 -0
- data/lib/chef/resource/csh.rb +33 -0
- data/lib/chef/resource/directory.rb +76 -0
- data/lib/chef/resource/dpkg_package.rb +34 -0
- data/lib/chef/resource/execute.rb +127 -0
- data/lib/chef/resource/file.rb +84 -0
- data/lib/chef/resource/gem_package.rb +41 -0
- data/lib/chef/resource/group.rb +68 -0
- data/lib/chef/resource/http_request.rb +52 -0
- data/lib/chef/resource/ifconfig.rb +134 -0
- data/lib/chef/resource/link.rb +78 -0
- data/lib/chef/resource/macports_package.rb +29 -0
- data/lib/chef/resource/mount.rb +135 -0
- data/lib/chef/resource/package.rb +80 -0
- data/lib/chef/resource/perl.rb +33 -0
- data/lib/chef/resource/portage_package.rb +33 -0
- data/lib/chef/resource/python.rb +33 -0
- data/lib/chef/resource/remote_directory.rb +91 -0
- data/lib/chef/resource/remote_file.rb +60 -0
- data/lib/chef/resource/route.rb +135 -0
- data/lib/chef/resource/ruby.rb +33 -0
- data/lib/chef/resource/ruby_block.rb +20 -0
- data/lib/chef/resource/script.rb +51 -0
- data/lib/chef/resource/service.rb +134 -0
- data/lib/chef/resource/template.rb +60 -0
- data/lib/chef/resource/user.rb +98 -0
- data/lib/chef/resource_collection.rb +176 -0
- data/lib/chef/resource_definition.rb +67 -0
- data/lib/chef/rest.rb +238 -0
- data/lib/chef/role.rb +231 -0
- data/lib/chef/run_list.rb +156 -0
- data/lib/chef/runner.rb +123 -0
- data/lib/chef/search.rb +88 -0
- data/lib/chef/search/result.rb +64 -0
- data/lib/chef/search_index.rb +77 -0
- data/lib/chef/tasks/chef_repo.rake +345 -0
- data/lib/chef/util/file_edit.rb +125 -0
- data/lib/chef/util/fileedit.rb +121 -0
- metadata +262 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
class Chef
|
19
|
+
class Exceptions
|
20
|
+
class Application < RuntimeError; end
|
21
|
+
class Cron < RuntimeError; end
|
22
|
+
class Exec < RuntimeError; end
|
23
|
+
class FileNotFound < RuntimeError; end
|
24
|
+
class Package < RuntimeError; end
|
25
|
+
class Service < RuntimeError; end
|
26
|
+
class Route < RuntimeError; end
|
27
|
+
class SearchIndex < RuntimeError; end
|
28
|
+
class Override < RuntimeError; end
|
29
|
+
class UnsupportedAction < RuntimeError; end
|
30
|
+
class MissingLibrary < RuntimeError; end
|
31
|
+
class User < RuntimeError; end
|
32
|
+
class Group < RuntimeError; end
|
33
|
+
class Link < RuntimeError; end
|
34
|
+
class Mount < RuntimeError; end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'chef/mixin/params_validate'
|
19
|
+
require 'chef/mixin/create_path'
|
20
|
+
require 'chef/exceptions'
|
21
|
+
require 'json'
|
22
|
+
require 'fileutils'
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class FileCache
|
26
|
+
class << self
|
27
|
+
include Chef::Mixin::ParamsValidate
|
28
|
+
include Chef::Mixin::CreatePath
|
29
|
+
|
30
|
+
# Write a file to the File Cache.
|
31
|
+
#
|
32
|
+
# === Parameters
|
33
|
+
# path<String>:: The path to the file you want to put in the cache - should
|
34
|
+
# be relative to Chef::Config[:file_cache_path]
|
35
|
+
# contents<String>:: A string with the contents you want written to the file
|
36
|
+
#
|
37
|
+
# === Returns
|
38
|
+
# true
|
39
|
+
def store(path, contents)
|
40
|
+
validate(
|
41
|
+
{
|
42
|
+
:path => path,
|
43
|
+
:contents => contents
|
44
|
+
},
|
45
|
+
{
|
46
|
+
:path => { :kind_of => String },
|
47
|
+
:contents => { :kind_of => String },
|
48
|
+
}
|
49
|
+
)
|
50
|
+
|
51
|
+
file_path_array = File.split(path)
|
52
|
+
file_name = file_path_array.pop
|
53
|
+
cache_path = create_cache_path(File.join(file_path_array))
|
54
|
+
io = File.open(File.join(cache_path, file_name), "w")
|
55
|
+
io.print(contents)
|
56
|
+
io.close
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
# Move a file in to the cache. Useful with the REST raw file output.
|
61
|
+
#
|
62
|
+
# === Parameteres
|
63
|
+
# file<String>:: The path to the file you want in the cache
|
64
|
+
# path<String>:: The relative name you want the new file to use
|
65
|
+
def move_to(file, path)
|
66
|
+
validate(
|
67
|
+
{
|
68
|
+
:file => file,
|
69
|
+
:path => path
|
70
|
+
},
|
71
|
+
{
|
72
|
+
:file => { :kind_of => String },
|
73
|
+
:path => { :kind_of => String },
|
74
|
+
}
|
75
|
+
)
|
76
|
+
|
77
|
+
file_path_array = File.split(path)
|
78
|
+
file_name = file_path_array.pop
|
79
|
+
if File.exists?(file) && File.writable?(file)
|
80
|
+
FileUtils.mv(
|
81
|
+
file,
|
82
|
+
File.join(create_cache_path(File.join(file_path_array), true), file_name)
|
83
|
+
)
|
84
|
+
else
|
85
|
+
raise RuntimeError, "Cannot move #{file} to #{path}!"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Read a file from the File Cache
|
90
|
+
#
|
91
|
+
# === Parameters
|
92
|
+
# path<String>:: The path to the file you want to load - should
|
93
|
+
# be relative to Chef::Config[:file_cache_path]
|
94
|
+
# read<True/False>:: Whether to return the file contents, or the path.
|
95
|
+
# Defaults to true.
|
96
|
+
#
|
97
|
+
# === Returns
|
98
|
+
# String:: A string with the file contents, or the path to the file.
|
99
|
+
#
|
100
|
+
# === Raises
|
101
|
+
# Chef::Exceptions::FileNotFound:: If it cannot find the file in the cache
|
102
|
+
def load(path, read=true)
|
103
|
+
validate(
|
104
|
+
{
|
105
|
+
:path => path
|
106
|
+
},
|
107
|
+
{
|
108
|
+
:path => { :kind_of => String }
|
109
|
+
}
|
110
|
+
)
|
111
|
+
cache_path = create_cache_path(path, false)
|
112
|
+
raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exists?(cache_path)
|
113
|
+
if read
|
114
|
+
File.read(cache_path)
|
115
|
+
else
|
116
|
+
cache_path
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Delete a file from the File Cache
|
121
|
+
#
|
122
|
+
# === Parameters
|
123
|
+
# path<String>:: The path to the file you want to delete - should
|
124
|
+
# be relative to Chef::Config[:file_cache_path]
|
125
|
+
#
|
126
|
+
# === Returns
|
127
|
+
# true
|
128
|
+
def delete(path)
|
129
|
+
validate(
|
130
|
+
{
|
131
|
+
:path => path
|
132
|
+
},
|
133
|
+
{
|
134
|
+
:path => { :kind_of => String },
|
135
|
+
}
|
136
|
+
)
|
137
|
+
cache_path = create_cache_path(path, false)
|
138
|
+
if File.exists?(cache_path)
|
139
|
+
File.unlink(cache_path)
|
140
|
+
end
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
# List all the files in the Cache
|
145
|
+
#
|
146
|
+
# === Returns
|
147
|
+
# Array:: An array of files in the cache, suitable for use with load, delete and store
|
148
|
+
def list()
|
149
|
+
keys = Array.new
|
150
|
+
Dir[File.join(Chef::Config[:file_cache_path], '**', '*')].each do |f|
|
151
|
+
if File.file?(f)
|
152
|
+
path = f.match("^#{Chef::Config[:file_cache_path]}\/(.+)")[1]
|
153
|
+
keys << path
|
154
|
+
end
|
155
|
+
end
|
156
|
+
keys
|
157
|
+
end
|
158
|
+
|
159
|
+
# Whether or not this file exists in the Cache
|
160
|
+
#
|
161
|
+
# === Parameters
|
162
|
+
# path:: The path to the file you want to check - is relative
|
163
|
+
# to Chef::Config[:file_cache_path]
|
164
|
+
#
|
165
|
+
# === Returns
|
166
|
+
# True:: If the file exists
|
167
|
+
# False:: If it does not
|
168
|
+
def has_key?(path)
|
169
|
+
validate(
|
170
|
+
{
|
171
|
+
:path => path
|
172
|
+
},
|
173
|
+
{
|
174
|
+
:path => { :kind_of => String },
|
175
|
+
}
|
176
|
+
)
|
177
|
+
full_path = create_cache_path(path, false)
|
178
|
+
if File.exists?(full_path)
|
179
|
+
true
|
180
|
+
else
|
181
|
+
false
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Create a full path to a given file in the cache. By default,
|
186
|
+
# also creates the path if it does not exist.
|
187
|
+
#
|
188
|
+
# === Parameters
|
189
|
+
# path:: The path to create, relative to Chef::Config[:file_cache_path]
|
190
|
+
# create_if_missing:: True by default - whether to create the path if it does not exist
|
191
|
+
#
|
192
|
+
# === Returns
|
193
|
+
# String:: The fully expanded path
|
194
|
+
def create_cache_path(path, create_if_missing=true)
|
195
|
+
cache_dir = File.expand_path(File.join(Chef::Config[:file_cache_path], path))
|
196
|
+
if create_if_missing
|
197
|
+
create_path(cache_dir)
|
198
|
+
else
|
199
|
+
cache_dir
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
data/lib/chef/log.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Author:: AJ Christensen (<@aj@opsocde.com>)
|
4
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'chef'
|
20
|
+
require 'mixlib/log'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Log
|
24
|
+
extend Mixlib::Log
|
25
|
+
|
26
|
+
# This is here for compatability, before we moved to
|
27
|
+
# Mixlib::Log.
|
28
|
+
class Formatter
|
29
|
+
def self.show_time=(arg)
|
30
|
+
Mixlib::Log::Formatter.show_time = arg
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.show_time
|
34
|
+
Mixlib::Log::Formatter.show_time
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
class Chef
|
19
|
+
module Mixin
|
20
|
+
module CheckHelper
|
21
|
+
def set_if_args(thing, arguments)
|
22
|
+
raise ArgumentError, "Must call set_if_args with a block!" unless Kernel.block_given?
|
23
|
+
if arguments != nil
|
24
|
+
yield(arguments)
|
25
|
+
else
|
26
|
+
thing
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'digest/sha2'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
module Mixin
|
23
|
+
module Checksum
|
24
|
+
|
25
|
+
def checksum(file)
|
26
|
+
digest = Digest::SHA256.new
|
27
|
+
fh = ::File.open(file)
|
28
|
+
fh.each do |line|
|
29
|
+
digest.update(line)
|
30
|
+
end
|
31
|
+
fh.close
|
32
|
+
digest.hexdigest
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/log'
|
20
|
+
require 'chef/exceptions'
|
21
|
+
require 'tmpdir'
|
22
|
+
require 'fcntl'
|
23
|
+
require 'etc'
|
24
|
+
require 'io/wait'
|
25
|
+
|
26
|
+
class Chef
|
27
|
+
module Mixin
|
28
|
+
module Command
|
29
|
+
|
30
|
+
# If command is a block, returns true if the block returns true, false if it returns false.
|
31
|
+
# ("Only run this resource if the block is true")
|
32
|
+
#
|
33
|
+
# If the command is not a block, executes the command. If it returns any status other than
|
34
|
+
# 0, it returns false (clearly, a 0 status code is true)
|
35
|
+
#
|
36
|
+
# === Parameters
|
37
|
+
# command<Block>, <String>:: A block to check, or a string to execute
|
38
|
+
#
|
39
|
+
# === Returns
|
40
|
+
# true:: Returns true if the block is true, or if the command returns 0
|
41
|
+
# false:: Returns false if the block is false, or if the command returns a non-zero exit code.
|
42
|
+
def only_if(command)
|
43
|
+
if command.kind_of?(Proc)
|
44
|
+
res = command.call
|
45
|
+
unless res
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
else
|
49
|
+
status = run_command(:command => command, :ignore_failure => true)
|
50
|
+
if status.exitstatus != 0
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
module_function :only_if
|
58
|
+
|
59
|
+
# If command is a block, returns false if the block returns true, true if it returns false.
|
60
|
+
# ("Do not run this resource if the block is true")
|
61
|
+
#
|
62
|
+
# If the command is not a block, executes the command. If it returns a 0 exitstatus, returns false.
|
63
|
+
# ("Do not run this resource if the command returns 0")
|
64
|
+
#
|
65
|
+
# === Parameters
|
66
|
+
# command<Block>, <String>:: A block to check, or a string to execute
|
67
|
+
#
|
68
|
+
# === Returns
|
69
|
+
# true:: Returns true if the block is false, or if the command returns a non-zero exit status.
|
70
|
+
# false:: Returns false if the block is true, or if the command returns a 0 exit status.
|
71
|
+
def not_if(command)
|
72
|
+
if command.kind_of?(Proc)
|
73
|
+
res = command.call
|
74
|
+
if res
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
else
|
78
|
+
status = run_command(:command => command, :ignore_failure => true)
|
79
|
+
if status.exitstatus == 0
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
module_function :not_if
|
87
|
+
|
88
|
+
# === Parameters
|
89
|
+
# args<Hash>: A number of required and optional arguments
|
90
|
+
# command<String>, <Array>: A complete command with options to execute or a command and options as an Array
|
91
|
+
# creates<String>: The absolute path to a file that prevents the command from running if it exists
|
92
|
+
# cwd<String>: Working directory to execute command in, defaults to Dir.tmpdir
|
93
|
+
# timeout<String>: How many seconds to wait for the command to execute before timing out
|
94
|
+
# returns<String>: The single exit value command is expected to return, otherwise causes an exception
|
95
|
+
# ignore_failure<Boolean>: Whether to raise an exception on failure, or just return the status
|
96
|
+
#
|
97
|
+
# user<String>: The UID or user name of the user to execute the command as
|
98
|
+
# group<String>: The GID or group name of the group to execute the command as
|
99
|
+
# environment<Hash>: Pairs of environment variable names and their values to set before execution
|
100
|
+
#
|
101
|
+
# === Returns
|
102
|
+
# Returns the exit status of args[:command]
|
103
|
+
def run_command(args={})
|
104
|
+
command_output = ""
|
105
|
+
|
106
|
+
args[:ignore_failure] ||= false
|
107
|
+
|
108
|
+
if args.has_key?(:creates)
|
109
|
+
if File.exists?(args[:creates])
|
110
|
+
Chef::Log.debug("Skipping #{args[:command]} - creates #{args[:creates]} exists.")
|
111
|
+
return false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
exec_processing_block = lambda do |pid, stdin, stdout, stderr|
|
116
|
+
Chef::Log.debug("---- Begin output of #{args[:command]} ----")
|
117
|
+
Chef::Log.debug("STDOUT: #{stdout.string.chomp}")
|
118
|
+
Chef::Log.debug("STDERR: #{stderr.string.chomp}")
|
119
|
+
command_output << "STDOUT: #{stdout.string.chomp}"
|
120
|
+
command_output << "STDERR: #{stderr.string.chomp}"
|
121
|
+
Chef::Log.debug("---- End output of #{args[:command]} ----")
|
122
|
+
end
|
123
|
+
|
124
|
+
args[:cwd] ||= Dir.tmpdir
|
125
|
+
unless File.directory?(args[:cwd])
|
126
|
+
raise Chef::Exceptions::Exec, "#{args[:cwd]} does not exist or is not a directory"
|
127
|
+
end
|
128
|
+
|
129
|
+
Chef::Log.debug("Executing #{args[:command]}")
|
130
|
+
|
131
|
+
status = nil
|
132
|
+
|
133
|
+
Dir.chdir(args[:cwd]) do
|
134
|
+
if args[:timeout]
|
135
|
+
begin
|
136
|
+
Timeout.timeout(args[:timeout]) do
|
137
|
+
status = popen4(args[:command], args, &exec_processing_block)
|
138
|
+
end
|
139
|
+
rescue Timeout::Error => e
|
140
|
+
Chef::Log.error("#{args[:command]} exceeded timeout #{args[:timeout]}")
|
141
|
+
raise(e)
|
142
|
+
end
|
143
|
+
else
|
144
|
+
status = popen4(args[:command], args, &exec_processing_block)
|
145
|
+
end
|
146
|
+
|
147
|
+
unless args[:ignore_failure]
|
148
|
+
args[:returns] ||= 0
|
149
|
+
if status.exitstatus != args[:returns]
|
150
|
+
# if the log level is not debug, through output of command when we fail
|
151
|
+
output = ""
|
152
|
+
if Chef::Log.logger.level > 0
|
153
|
+
output << "\n---- Begin output of #{args[:command]} ----\n"
|
154
|
+
output << "#{command_output}"
|
155
|
+
output << "---- End output of #{args[:command]} ----\n"
|
156
|
+
end
|
157
|
+
raise Chef::Exceptions::Exec, "#{args[:command]} returned #{status.exitstatus}, expected #{args[:returns]}#{output}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
Chef::Log.debug("Ran #{args[:command]} returned #{status.exitstatus}")
|
161
|
+
end
|
162
|
+
status
|
163
|
+
end
|
164
|
+
|
165
|
+
module_function :run_command
|
166
|
+
|
167
|
+
# This is taken directly from Ara T Howard's Open4 library, and then
|
168
|
+
# modified to suit the needs of Chef. Any bugs here are most likely
|
169
|
+
# my own, and not Ara's.
|
170
|
+
#
|
171
|
+
# The original appears in external/open4.rb in its unmodified form.
|
172
|
+
#
|
173
|
+
# Thanks Ara!
|
174
|
+
def popen4(cmd, args={}, &b)
|
175
|
+
|
176
|
+
# Waitlast - this is magic.
|
177
|
+
#
|
178
|
+
# Do we wait for the child process to die before we yield
|
179
|
+
# to the block, or after? That is the magic of waitlast.
|
180
|
+
#
|
181
|
+
# By default, we are waiting before we yield the block.
|
182
|
+
args[:waitlast] ||= false
|
183
|
+
|
184
|
+
args[:user] ||= nil
|
185
|
+
unless args[:user].kind_of?(Integer)
|
186
|
+
args[:user] = Etc.getpwnam(args[:user]).uid if args[:user]
|
187
|
+
end
|
188
|
+
args[:group] ||= nil
|
189
|
+
unless args[:group].kind_of?(Integer)
|
190
|
+
args[:group] = Etc.getgrnam(args[:group]).gid if args[:group]
|
191
|
+
end
|
192
|
+
args[:environment] ||= nil
|
193
|
+
|
194
|
+
pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
|
195
|
+
|
196
|
+
verbose = $VERBOSE
|
197
|
+
begin
|
198
|
+
$VERBOSE = nil
|
199
|
+
ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
200
|
+
|
201
|
+
cid = fork {
|
202
|
+
pw.last.close
|
203
|
+
STDIN.reopen pw.first
|
204
|
+
pw.first.close
|
205
|
+
|
206
|
+
pr.first.close
|
207
|
+
STDOUT.reopen pr.last
|
208
|
+
pr.last.close
|
209
|
+
|
210
|
+
pe.first.close
|
211
|
+
STDERR.reopen pe.last
|
212
|
+
pe.last.close
|
213
|
+
|
214
|
+
STDOUT.sync = STDERR.sync = true
|
215
|
+
|
216
|
+
if args[:group]
|
217
|
+
Process.egid = args[:group]
|
218
|
+
Process.gid = args[:group]
|
219
|
+
end
|
220
|
+
|
221
|
+
if args[:user]
|
222
|
+
Process.euid = args[:user]
|
223
|
+
Process.uid = args[:user]
|
224
|
+
end
|
225
|
+
|
226
|
+
if args[:environment]
|
227
|
+
args[:environment].each do |key,value|
|
228
|
+
ENV[key] = value
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
if args[:umask]
|
233
|
+
umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777)
|
234
|
+
File.umask(umask)
|
235
|
+
end
|
236
|
+
|
237
|
+
begin
|
238
|
+
if cmd.kind_of?(Array)
|
239
|
+
exec(*cmd)
|
240
|
+
else
|
241
|
+
exec(cmd)
|
242
|
+
end
|
243
|
+
raise 'forty-two'
|
244
|
+
rescue Exception => e
|
245
|
+
Marshal.dump(e, ps.last)
|
246
|
+
ps.last.flush
|
247
|
+
end
|
248
|
+
ps.last.close unless (ps.last.closed?)
|
249
|
+
exit!
|
250
|
+
}
|
251
|
+
ensure
|
252
|
+
$VERBOSE = verbose
|
253
|
+
end
|
254
|
+
|
255
|
+
[pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
|
256
|
+
|
257
|
+
begin
|
258
|
+
e = Marshal.load ps.first
|
259
|
+
raise(Exception === e ? e : "unknown failure!")
|
260
|
+
rescue EOFError # If we get an EOF error, then the exec was successful
|
261
|
+
42
|
262
|
+
ensure
|
263
|
+
ps.first.close
|
264
|
+
end
|
265
|
+
|
266
|
+
pw.last.sync = true
|
267
|
+
|
268
|
+
pi = [pw.last, pr.first, pe.first]
|
269
|
+
|
270
|
+
if b
|
271
|
+
begin
|
272
|
+
if args[:waitlast]
|
273
|
+
b[cid, *pi]
|
274
|
+
Process.waitpid2(cid).last
|
275
|
+
else
|
276
|
+
# This took some doing.
|
277
|
+
# The trick here is to close STDIN
|
278
|
+
# Then set our end of the childs pipes to be O_NONBLOCK
|
279
|
+
# Then wait for the child to die, which means any IO it
|
280
|
+
# wants to do must be done - it's dead. If it isn't,
|
281
|
+
# it's because something totally skanky is happening,
|
282
|
+
# and we don't care.
|
283
|
+
o = StringIO.new
|
284
|
+
e = StringIO.new
|
285
|
+
|
286
|
+
pi[0].close
|
287
|
+
|
288
|
+
stdout = pi[1]
|
289
|
+
stderr = pi[2]
|
290
|
+
|
291
|
+
stdout.sync = true
|
292
|
+
stderr.sync = true
|
293
|
+
|
294
|
+
stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
|
295
|
+
stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK)
|
296
|
+
|
297
|
+
stdout_finished = false
|
298
|
+
stderr_finished = false
|
299
|
+
|
300
|
+
results = nil
|
301
|
+
|
302
|
+
while !stdout_finished || !stderr_finished
|
303
|
+
begin
|
304
|
+
channels_to_watch = []
|
305
|
+
channels_to_watch << stdout if !stdout_finished
|
306
|
+
channels_to_watch << stderr if !stderr_finished
|
307
|
+
ready = IO.select(channels_to_watch, nil, nil, 1.0)
|
308
|
+
rescue Errno::EAGAIN
|
309
|
+
results = Process.waitpid2(cid, Process::WNOHANG)
|
310
|
+
if results
|
311
|
+
stdout_finished = true
|
312
|
+
stderr_finished = true
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
if ready && ready.first.include?(stdout)
|
317
|
+
line = results ? stdout.gets(nil) : stdout.gets
|
318
|
+
if line
|
319
|
+
o.write(line)
|
320
|
+
else
|
321
|
+
stdout_finished = true
|
322
|
+
end
|
323
|
+
end
|
324
|
+
if ready && ready.first.include?(stderr)
|
325
|
+
line = results ? stderr.gets(nil) : stderr.gets
|
326
|
+
if line
|
327
|
+
e.write(line)
|
328
|
+
else
|
329
|
+
stderr_finished = true
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
results = Process.waitpid2(cid).last unless results
|
334
|
+
o.rewind
|
335
|
+
e.rewind
|
336
|
+
b[cid, pi[0], o, e]
|
337
|
+
results
|
338
|
+
end
|
339
|
+
ensure
|
340
|
+
pi.each{|fd| fd.close unless fd.closed?}
|
341
|
+
end
|
342
|
+
else
|
343
|
+
[cid, pw.last, pr.first, pe.first]
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
module_function :popen4
|
348
|
+
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|