summaryrefslogtreecommitdiffstats
path: root/meta-openstack/classes
diff options
context:
space:
mode:
authorMustapha Lansana <Mustapha.Lansana@windriver.com>2014-07-30 19:08:55 -0400
committerBruce Ashfield <bruce.ashfield@windriver.com>2014-09-26 09:09:21 -0400
commitcaf76c8322f247d0829dc9a18009bee0b1195a06 (patch)
tree84751c17810440a9e560d486f57d9dc16074faf1 /meta-openstack/classes
parentef4a3055abee950950c2aac127854eb9e83f2793 (diff)
downloadmeta-cloud-services-caf76c8322f247d0829dc9a18009bee0b1195a06.tar.gz
openstackchef: decentralized openstack-chef class implementation
This class provides a framework for recipes(packages) to register their configuration files with the deploychef package. This class works together with the deploychef package. This implementation makes it possible for the deploychef package, with the help of chef-solo, to recreate registered configuration files at run-time. Only services that inherit this class and register their configuration files are re-configurable at run-time; and by configurable, we mean to make chefsolo templates out of their configuration files and to be aware of the list of daemons that need to be killed/started at run-time. Therefore, openstackchef class requires the recipes/classes inheriting it to advertise their configuration files, list of start/stop daemons and finally a special callback function when necessary. In order to avoid duplication of common placeholders and substitution across the various recipes inheriting this class, we keep a dictionary of common placeholders and substitutions, but rely on the recipes to define the values these placeholders take at run-time. See the description at the top of the class files (openstackchef.bbclass and openstackchef_inc.bbclass ) for more details. This class makes chef-solo template files out of the configuration files exposed to it by the recipes. The resulting templates are stored at /opt/deploychef/cookbooks/openstack/templates/default. on the resulting rootfs. It also creates a file containing a set of chef-solo default template values known as attributes in chef-solo world. The default values are provided by the recipes and classes inheriting this class. The chefsolo attributes file is stored at /opt/deploychef/cookbooks/openstack/attributes/default.rb at the end of rootfs creation process. At run-time, the deploychef package whose package files are stored at '/opt/deploychef', makes a call to chef-solo. Chef-solo in turn uses the attributes and templates files to overwrite the configuration files for services like neutron, nova, swift, etc.. that registered configuration files with openstackchef class at build time. See accompanying documentation for further explanation. Signed-off-by: Mustapha Lansana <Mustapha.Lansana@windriver.com>
Diffstat (limited to 'meta-openstack/classes')
-rw-r--r--meta-openstack/classes/openstackchef.bbclass115
-rw-r--r--meta-openstack/classes/openstackchef_inc.bbclass831
2 files changed, 946 insertions, 0 deletions
diff --git a/meta-openstack/classes/openstackchef.bbclass b/meta-openstack/classes/openstackchef.bbclass
new file mode 100644
index 0000000..c2e4a40
--- /dev/null
+++ b/meta-openstack/classes/openstackchef.bbclass
@@ -0,0 +1,115 @@
1# openstackchef.bbclass
2# Copyright (c) 2014 Wind River Systems, Inc.
3#
4# Permission is hereby granted, free of charge, to any person obtaining a copy
5# of this software and associated documentation files (the "Software"), to
6# deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM,
21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22# THE SOFTWARE.
23#
24#
25# This class provides a framework for openstack services like python-neutron
26# or python-nova to register their configuration files so that they can be
27# recreated at run-time by chef-solo. Inheriting
28# this class involves exposing configuration files from which this class
29# creates chef-solo templates. These template files are later used by chef-solo
30# to recreate the configuration files.
31#
32# For the templates files to be created, the recipes are expected
33# to define the following variables variables:
34#
35# SRCNAME:
36# This is the name of the package, neutron for example for the package
37# python-neutron. It's appended to the names of template files and also
38# used in the creation of package based temporary files. A default value
39# of ${BPN} is assigned to this variable when it's not defined by recipes
40# inheriting class.
41#
42# CHEF_SERVICES_CONF_FILES
43#
44# This variable provides the list of configuration files
45# exposed to this class by the recipes inheriting the class.
46# These files are expected to be in the image( ${D}) directory, though ${D}
47# directory is excluded from the file name. Definition of this variable
48# by recipe files is optional.
49# eg.
50# CHEF_SERVICES_CONF_FILES="\
51# ${sysconfdir}/chef/neutron/plugins/linuxbridge/linuxbridge_conf.ini.rb \
52# ${sysconfdir}/chef/neutron/neutron.conf
53# "
54#
55#INITSCRIPT_PACKAGES
56#This variable provides a mechanism for recipes inheriting this class
57#to provide a list of services to start/stop when their configuration files
58#are recreated on disk.
59#This variable is assumed to be provided by all recipes that register a set
60#of configuration files with this class. Failing to do so will lead to
61#service not reloading the newly created configuration file(s) at run-time.
62#
63#
64#INITSCRIPT_NAME_x or INITSCRIPT_NAME
65#This variable is also assumed to be set by recipes inheriting this class.
66#It specifies the names of the services to start/stop as specified above.
67#Like the variable immediately above, failure to provide this variable will
68#lead to mis-configuration of the service at run-time.
69#
70#
71#INITSCRIPT_PARAMS_x or INITSCRIPT_PARAMS
72#Like the last two variable above, this variable is also assumed to be set
73#by recipes inheriting this class. It is used to extract the run-level
74#priority of the INITSCRIPT_NAME variable(s). Unlike, the previous two
75#variables, a default run-level is assigned to the script when this variable
76#defaults to the string 'default'
77#
78#
79# CHEF_SERVICES_SPECIAL_FUNC
80# This variable is optional, and is the name of a shell callback function.
81# Unlike the placeholder/value substitution which this class does,
82# there are times when recipes need to do more than a simple placeholder/
83# value substitution. This is made possible with the use of the callback
84# function.
85# The callback function should be defined by the recipe(s) inheriting
86# this class. When this variable is defined, this class will call the
87# callback function and pass it the name of the file to manipulate
88# in the form of the variable CHEF_SERVICES_FILE_NAME. This variable
89# is then accessed in the callback function in the recipe file as
90# ${CHEF_SERVICES_FILE_NAME}
91#
92inherit hosts openstackchef_inc
93
94#Call this function after the do_install function have executed in
95#recipes inheriting this class, this ensures that we get configuration
96#files that have been moved to the images directory
97addtask deploychef_install before do_package after do_install
98python do_deploychef_install() {
99 if deploychef_not_rootfs_class(d) and \
100 deploychef_openstackchef_enabled(d):
101 #copy configuration files from packages inheriting class
102 template_files_tuple = deploychef_copy_conf_files(d)
103 #convert configuration files into templates for chefsolo
104 deploychef_make_templates( d, template_files_tuple)
105 #Generate a list of startup/shutdown services
106 deploychef_make_startup_shutdown_list(d)
107}
108
109#Use of ROOTFS_POSTPROCESS_COMMAND enables us to hook into the post
110#rootfs creation process and influence the work of openstack_configure_hosts.
111#However, to ensure that our function deploychef_rootfs_postprocess_commands
112#is called after openstack_configure_hosts and not before it,
113#we add it in front of our callback function here.
114ROOTFS_POSTPROCESS_COMMAND += "openstack_configure_hosts ; deploychef_rootfs_postprocess_commands ; "
115
diff --git a/meta-openstack/classes/openstackchef_inc.bbclass b/meta-openstack/classes/openstackchef_inc.bbclass
new file mode 100644
index 0000000..7795082
--- /dev/null
+++ b/meta-openstack/classes/openstackchef_inc.bbclass
@@ -0,0 +1,831 @@
1# openstackchef_inc.bbclass
2# Copyright (c) 2014 Wind River Systems, Inc.
3#
4# Permission is hereby granted, free of charge, to any person obtaining a copy
5# of this software and associated documentation files (the "Software"), to
6# deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONE INFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM,
21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22# THE SOFTWARE.
23#
24#
25#This class is a helper class for openstackchef.bbclass and should not be be
26#inherited on it's own. It implements the functionalities used in
27#openstackchef.bbclass
28CHEFPN = "openstackchef"
29#This variable is here to support legacy use of recipes that inherit this
30#class. By default these recipes will be built without openstackchef support.
31#Set this variable to 'yes' in your local.conf or similar to enable
32#support for OPENSTACKCHEF.
33OPENSTACKCHEF_ENABLED ?=''
34#This variable is defined in most of the openstack services, however,
35#it defaults to bare package name for packages that do not define it.
36SRCNAME ?= "${BPN}"
37#This is the base directory of where deploychef's templates files
38#reside in the classes that inherit it.
39CHEF_TEMPLATE_BASE="${D}${sysconfdir}/${CHEFPN}"
40CHEF_PACKAGE_BASE="${WORKDIR}/package${sysconfdir}/${CHEFPN}"
41CHEF_IMAGE_BASE="${D}${sysconfdir}"
42CHEF_ROOTFS_BASE="${sysconfdir}/${CHEFPN}"
43#These are the prefixs and suffixs to create chefsolo-like placeholders
44ERB_PREFIX = "<%=node[:"
45ERB_SUFFIX = "]%>"
46#These prefix and suffix are used to create our default values
47ERB_DEFAULT_PREFIX="default["
48ERB_DEFAULT_SUFFIX="]"
49#Chefsolo template file extension
50TEMPLATE_EXTENSION='.erb'
51#Build deploychef package since this class has run-time and buil-time dependency
52#on it
53DEPENDS_${PN} += "deploychef"
54RDEPENDS_${PN} += "deploychef"
55CHEF_VERSION = '1'
56#For classes that define a special substitution function, this variable is
57#set by this class and specifies the file named passed back to these function
58#for any special substitution.
59CHEF_SERVICES_FILE_NAME ?=''
60
61#These are hard coded in the recipes files where they are used.
62ADMIN_TENANT_NAME ?= 'admin'
63DEMO_USER ?= 'demo'
64#This is dafault value used by update-rc.d script at runtime when
65#build-time update-rd.d class specifies INITSCRIPT_PARAMS as 'defaults'
66CHEF_INITSCRIPT_PARAMS='defaults 20 10'
67
68def deploychef_services_default_sub_dict(d):
69 """Provides our placeholder/value substitution dictionary for global use
70
71 This function returns as dictionary containing the default substitution pattern
72 as follows:
73 :<key>: Name of placeholder variable
74 :<value>: A tuple consisting of the place holder variable followed
75 by its default value
76 """
77 sub_dict={}
78 #neutron
79 sub_dict['SERVICE_TENANT_NAME'] = ('%SERVICE_TENANT_NAME%' ,
80 '${SERVICE_TENANT_NAME}')
81 sub_dict['SERVICE_PASSWORD'] = ('%SERVICE_PASSWORD%' , '${SERVICE_PASSWORD}')
82
83 sub_dict['DB_USER'] = ('%DB_USER%', '${DB_USER}')
84 sub_dict['DB_PASSWORD'] = ('%DB_PASSWORD%' , '${DB_PASSWORD}')
85 sub_dict['CONTROLLER_IP'] = ('%CONTROLLER_IP%', '${CONTROLLER_IP}')
86 sub_dict['CONTROLLER_HOST'] = ('%CONTROLLER_HOST%', '${CONTROLLER_HOST}')
87 #nova
88 sub_dict['COMPUTE_IP'] = ('%COMPUTE_IP%', '${COMPUTE_IP}')
89 sub_dict['COMPUTE_HOST'] = ('%COMPUTE_HOST%', '${COMPUTE_HOST}')
90 sub_dict['LIBVIRT_IMAGES_TYPE'] = ('%LIBVIRT_IMAGES_TYPE%' , '${LIBVIRT_IMAGES_TYPE}')
91 sub_dict['OS_PASSWORD'] = ('%OS_PASSWORD%' , '${ADMIN_PASSWORD}')
92 sub_dict['SERVICE_TOKEN'] = ('%SERVICE_TOKEN%' , '${SERVICE_TOKEN}')
93 #swfit
94 sub_dict['ADMIN_TENANT_NAME'] = ('%ADMIN_TENANT_NAME%' , '${ADMIN_TENANT_NAME}')
95 sub_dict['ADMIN_USER'] = ('%ADMIN_USER%' , '${ADMIN_TENANT_NAME}')
96 sub_dict['ADMIN_PASSWORD'] = ('%ADMIN_PASSWORD%' , '${ADMIN_PASSWORD}')
97 sub_dict['DEMO_USER'] = ('%DEMO_USER%' , '${DEMO_USER}')
98 sub_dict['DEMO_PASSWORD'] = ('%DEMO_PASSWORD%' , '${ADMIN_PASSWORD}')
99 #ceilometer
100 sub_dict['CEILOMETER_SECRET'] = ('%CEILOMETER_SECRET%' , '${CEILOMETER_SECRET}')
101
102 #keystone
103 sub_dict['TOKEN_FORMAT'] = ('%TOKEN_FORMAT%' , '${TOKEN_FORMAT}')
104 sub_dict['METADATA_SHARED_SECRET'] = ('%METADATA_SHARED_SECRET%' , '${METADATA_SHARED_SECRET}')
105 #cinder
106 sub_dict['CINDER_BACKUP_BACKEND_DRIVER'] = ('%CINDER_BACKUP_BACKEND_DRIVER%' , '${CINDER_BACKUP_BACKEND_DRIVER}')
107 #cloud-init
108 sub_dict['MANAGE_HOSTS'] = ('%MANAGE_HOSTS%' , '${MANAGE_HOSTS}')
109 sub_dict['HOSTNAME'] = ('%HOSTNAME%' , '${MY_HOST}')
110 #postgresql
111 sub_dict['DB_DATADIR'] = ('%DB_DATADIR%' , '${DB_DATADIR}')
112 #glance
113 sub_dict['GLANCE_DEFAULT_STORE'] = ('%GLANCE_DEFAULT_STORE%' , '${GLANCE_DEFAULT_STORE}')
114
115 #barbican
116 sub_dict['BARBICAN_MAX_PACKET_SIZE'] = ('%BARBICAN_MAX_PACKET_SIZE%' , '${BARBICAN_MAX_PACKET_SIZE}')
117 #ceph
118 sub_dict['PUBLIC_IP'] = ('%PUBLIC_IP%' , '${CONTROLLER_IP}')
119 sub_dict['PRIVATE_IP'] = ('%PRIVATE_IP%' , '${MY_IP}')
120 sub_dict['PUBLIC_DOMAIN'] = ('%PUBLIC_DOMAIN%' , '${PUBLIC_DOMAIN}')
121 sub_dict['HOST_NAME'] = ('%HOST_NAME%' , '${MY_HOST}')
122 sub_dict['CEPH_BACKING_FILE_SIZE'] = ('%CEPH_BACKING_FILE_SIZE%' , '${CEPH_BACKING_FILE_SIZE}')
123
124 #Most of the services have SERVICE_USER define but the values are different
125 service_user = d.getVar('SRCNAME', True)
126 if service_user:
127 service_user = service_user.upper() + '_SERVICE_USER'
128 sub_dict[service_user] = ('%SERVICE_USER%' , '${SRCNAME}')
129 return sub_dict
130
131#This variable is the default sets of substitutions common to most of the
132#services in an openstack installation. It means this package is not completely
133#agnostic but at the same time it gives us the added advantage of not repeating
134#ourselves in the recipe/class files that inherits this class.
135CHEF_SERVICES_DEFAULT_CONF_SUBS := "${@deploychef_services_default_sub_dict(d)}"
136
137
138def deploychef_not_rootfs_class(d):
139 """Filter out rootfs related classes
140
141 This function is used to help us selectively executes the creation of template
142 files and daemon start/stop list. It allows us to executes certain functions
143 when the recipe inheriting this class is related to rootfs creation.
144 """
145 pkg = d.getVar('PN', True) or d.getVar('BPN', True)
146 #Skip test if recipe/class calling this class is related to rootfs image
147 #creation.
148 if 'image-' in pkg:
149 return False
150 else:
151 return True
152
153def deploychef_openstackchef_enabled(d):
154 """Find out if openstackchef class usage is enabled
155
156 The variable OPENSTACKCHEF_ENABLED is use to support legacy functionality
157 by recipes inheriting this class. Assinging it an empty string disables
158 the functionality of this class for that recipe file.
159 This function helps us detect when this variable is set to an empty string.
160 """
161 chef = d.getVar('OPENSTACKCHEF_ENABLED', True)
162 #Skip test if recipe/class calling this class is related to rootfs image
163 #creation.
164 if chef != '' :
165 return True
166 else:
167 return False
168
169def deploychef_make_startup_shutdown_list(d):
170 """Create list of services to start/stop and save them to file
171
172 This function uses the update-rc.d environment variables defined
173 in the recipes/classes inheriting this class to create the
174 startup and shutdown services list as defined in the file.
175 This is important because, when we are replacing the configuration
176 files for the services, the services needs to be shutdown and
177 restarted after their configuration files are edited.
178 Therefore, the following variables must be defined by classes inheriting
179 this class.
180
181 INITSCRIPT_PACKAGES: A list of init scripts
182 INITSCRIPT_PARAMS_x: The default start/stop priority for the above scripts
183 """
184
185 import os
186 if d.getVar('INITSCRIPT_PACKAGES') or d.getVar('INITSCRIPT_NAME'):
187 #script_list = bb.data.getVar('INITSCRIPT_PACKAGES', d , 1)
188 script_list = d.getVar('INITSCRIPT_PACKAGES', True) or \
189 d.getVar('INITSCRIPT_NAME', True) #Some package do not define INITSCRIPT_PACKAGES
190 msg="list of start/stop services: %s" % str(script_list)
191 bb.debug(2, msg)
192 base_dir = bb.data.getVar('CHEF_TEMPLATE_BASE', d, 1 )
193 if not os.path.exists(base_dir):
194 os.mkdir(base_dir)
195 startup_file = os.path.join(base_dir, d.getVar('SRCNAME', True) +'-startup-list')
196 shutdown_file = os.path.join(base_dir, d.getVar('SRCNAME', True) +'-shutdown-list')
197 msg ="Startup and shutdown files %s %s saved to %s" % \
198 ( startup_file, shutdown_file, base_dir)
199 bb.note(msg)
200 try:
201 hStartup = open(startup_file, 'w')
202 hShutdown = open(shutdown_file, 'w')
203 for script_name in script_list.split():
204 #Retrieve the default params for update-rc.d for this script
205 #INITSCRIPT_PARAMS_nova-api="defaults 30 10"
206 init_script_name ="INITSCRIPT_NAME_%s" % script_name
207 init_script_name = d.getVar(init_script_name, True) or \
208 d.getVar('INITSCRIPT_NAME', True)
209
210 script_params ="INITSCRIPT_PARAMS_%s" % script_name
211 script_params = d.getVar(script_params, True) or \
212 d.getVar('INITSCRIPT_PARAMS', True)
213 #If only defaults is provided as parameter, then use our default priority
214 if not script_params or len(script_params.split()) < 3:
215 script_params = d.getVar('CHEF_INITSCRIPT_PARAMS', True)
216 if init_script_name:
217 #eg. start 20 5 3 2 . stop 80 0 1 6 .
218 startup_priority = shutdown_priority = ''
219 if script_params.find('stop') > 0:
220 start, stop = script_params.split('stop')
221 start = start.split()
222 stop = stop.split()
223 startup_priority = start[1]
224 shutdown_priority = stop[0]
225 elif script_params.find('stop') == 0:
226 start, stop = script_params.split('start')
227 start = start.split()
228 stop = stop.split()
229 startup_priority = start[0]
230 shutdown_priority = stop[1]
231 else:
232 #"defaults 20 10"
233 defaults = script_params.split()
234 startup_priority = defaults[1]
235 shutdown_priority = defaults[2]
236 #Arrange the script's startup/shutdown format as in rc.x
237 startup_string = "%s%s%s%s" % ('S', startup_priority, init_script_name, os.linesep)
238 shutdown_string = "%s%s%s%s" % ('K', shutdown_priority, init_script_name, os.linesep)
239 hStartup.write(startup_string)
240 hShutdown.write(shutdown_string)
241 msg = "%s %s registered for startup and shutdown in" % \
242 (startup_string, shutdown_string)
243 bb.debug(2 , msg)
244 else:
245 msg = "The variables INITSCRIPT_PARAMS_%s or INITSCRIPT_PARAMS \
246 are not set in %s, startup/shutdown list not created for %s: %s" \
247 % (script_name, d.getVar('FILE', True), d.getVar('SRCNAME', True), script_params)
248 raise bb.build.FuncFailed(msg)
249 hStartup.close()
250 hShutdown.close()
251 except IOError, e:
252 bb.error("Error opening startup/shutdown files %s %s, %s %s" % \
253 (startup_file, shutdown_file, d.getVar('FILE'), e))
254 else:
255 msg = "The variable INITSCRIPT_PACKAGES is not set in %s, \
256 startup/shutdown script will not be made for %s package" % \
257 (d.getVar('FILE', True), d.getVar('SRCNAME', True))
258 bb.build.FuncFailed(msg)
259
260def deploychef_make_substitutions(d, sub_dict, attr_filename, sed_filename):
261 """Make placeholder/value substitution in a file
262
263 This function makes placeholder substitution into the file named
264 sed_filename and appends the default value for those substitution into
265 the file named attr_filename.
266 The substitution is based on sets of placeholder/value pair in the
267 dictionary called sub_dict.
268 :sub_dict: name, placeholder and value dictionary
269 :attr_filename: chef-solo attributes file name
270 :sed_filename: configuration or template file
271 """
272 if attr_filename and sed_filename:
273 if type(sub_dict) is dict:
274 import os
275 import re
276 sHandle = open(sed_filename, 'r+')
277 lines_in_conf_file = sHandle.read()
278 #We only want to append to the list of defines needed by this class
279 hFile= open(attr_filename,'a+')
280 lines_in_file= hFile.read()
281 for key in sub_dict.keys():
282 placeholder , replacement = sub_dict[key]
283 #Filter by placeholder so that our attribute file only include
284 #defines for class being built
285 if re.search(placeholder,lines_in_conf_file):
286 #Make the substitution to create a template file out of
287 #the configuration file or just replace placeholder in
288 #configuration file
289 if d.getVar('TEMPLATE_EXTENSION', True) in sed_filename:
290 #Format the default attributes as expected by chefsolo
291 #for template file.
292 attr_string = d.getVar('ERB_DEFAULT_PREFIX', True)
293 attr_string += r'"' + key
294 attr_string += r'"' + d.getVar('ERB_DEFAULT_SUFFIX', True)
295 attr_string +=' = ' + r'"' + replacement + r'"'
296 #Only write default values that do not yet exist in file
297 #if key not in lines_in_file:
298 if not re.search(key,lines_in_file):
299 hFile.write("%s%s" % (attr_string, os.linesep))
300 #Replace the placeholders in the current file, with
301 #new_replacement
302 new_replacement = d.getVar('ERB_PREFIX') + key
303 new_replacement += d.getVar('ERB_SUFFIX')
304 lines_in_conf_file = re.sub(placeholder, new_replacement, lines_in_conf_file)
305 #Write template file to disk
306 sHandle.seek(0)
307 sHandle.truncate()
308 sHandle.write(lines_in_conf_file)
309 sHandle.close()
310
311 hFile.close()
312 if False:
313 msg = "Cannot read/write to attributes file %s as expected:%s"\
314 % (attr_filename, bb.data.getVar('FILE', d))
315 bb.build.FuncFailed(msg)
316 else:
317 msg = "The substitution dictionary variable sub_dict is not set %s as expected "\
318 % bb.data.getVar('FILE')
319 bb.error(msg)
320 else:
321 msg = "Null file names passsed to function %s %s "\
322 % (bb.data.getVar('FUNC',d), bb.data.getVar('FILE', d))
323 bb.error(msg)
324
325
326
327def deploychef_make_templates( d, conf_tuple=tuple()):
328 """Create a template file out of a configuration file
329
330 Using substitution placeholders and values in the substitution
331 dictionary declared as CHEF_SERVICES_DEFAULT_CONF_SUBS, this function
332 makes the substitution for all placeholders. If the file is a ruby template file,
333 it replaces the placeholders with a chefsolo expression;
334 thereby creating a chefsolo template file.
335
336 :conf_tuple: List of configuration files
337 """
338
339 if len(conf_tuple):
340 import os, ast
341 base_dir = bb.data.getVar('CHEF_TEMPLATE_BASE', d, 1 )
342 attr_file = os.path.join(base_dir, d.getVar('SRCNAME', True) + '-attributes.rb')
343 msg ="Default attributes saved to %s" % attr_file
344 if os.path.exists(attr_file):
345 os.remove(attr_file)
346 bb.note(msg)
347 try:
348 for file_name in conf_tuple:
349 #If a special substitution function is defined for class
350 #inheriting this class, set the file name expected by special
351 #function before calling the function
352 special_func_name = d.getVar('CHEF_SERVICES_SPECIAL_FUNC')
353 if special_func_name:
354 bb.data.setVar('CHEF_SERVICES_FILE_NAME', file_name,\
355 d)
356 bb.build.exec_func(special_func_name, d)
357
358 #Make the necessary susbstitutions using the default
359 #substitutiin dictionary
360 sub_dict = bb.data.getVar('CHEF_SERVICES_DEFAULT_CONF_SUBS', d , 1)
361 msg = "The variable %s is not set in %s as a dictionary as expected "\
362 % ('CHEF_SERVICES_DEFAULT_CONF_SUBS', bb.data.getVar('FILE', d))
363 if sub_dict:
364 #Safely retrieve our python data structure
365 sub_dict = ast.literal_eval(sub_dict)
366 if type(sub_dict) is dict:
367 deploychef_make_substitutions(d, sub_dict, attr_file, file_name)
368 else:
369 raise bb.build.FuncFailed(msg)
370 else:
371 raise bb.build.FuncFailed(msg)
372 #Make the necessary susbstitutions using auxilliary dictionary
373 #if provided by inheriting class
374 sub_dict = bb.data.getVar('CHEF_SERVICES_CONF_SUBS', d , 1)
375 if sub_dict:
376 sub_dict = ast.literal_eval(sub_dict)
377 msg = "The variable %s is not set in %s as a dictionary as expected "\
378 % ('CHEF_SERVICES_CONF_SUB', bb.data.getVar('FILE', d))
379 if type(sub_dict) is dict:
380 pass
381 deploychef_make_substitutions(d, sub_dict, attr_file, file_name)
382 else:
383 bb.build.FuncFailed(msg)
384 except IOError, e:
385 bb.error("Could not write to attribute file %s: in %s, %s" % \
386 (attr_file, d.getVar('FILE'), e))
387
388def deploychef_copy_single_conf_file(d, dst_base, conf_file):
389 """Create a chef-solo template from an openstack configuration file
390
391 This function copies a single configuration file (conf_file)
392 to destination directory (dst_dir) and return a tuple that contains
393 both the absolute path of the conf_file and the template files it was
394 copied as.
395 """
396 if conf_file:
397 import shutil
398 import os
399 #Create the absolute path to configuration file since it's with relative
400 #to image directory
401 image_base = d.getVar('D', True)
402 if conf_file.startswith(os.sep):
403 conf_file=conf_file[1:]
404 abs_conf_path = os.path.join(image_base, conf_file)
405
406 if os.path.exists(abs_conf_path):
407 dst_base = os.path.join(dst_base, os.path.dirname(conf_file))
408 #make room for the template file about to be created
409 if not os.path.exists(dst_base):
410 os.makedirs(dst_base)
411
412 abs_template_file = os.path.basename(conf_file) + \
413 d.getVar('TEMPLATE_EXTENSION', True) + '.' + d.getVar('SRCNAME', True)
414 abs_template_file = os.path.join(dst_base, abs_template_file)
415 #Copy conf file as template file
416 shutil.copy(abs_conf_path, abs_template_file)
417 msg = "\nConf file: %s\n Copied to: %s \n"\
418 % (abs_conf_path, abs_template_file)
419 bb.debug(2, msg)
420 return (abs_conf_path, abs_template_file)
421 else:
422 msg = "Configuration file: %s in %s does not \
423 exist" % (abs_conf_path, d.getVar('FILE'))
424 raise bb.build.FuncFailed(msg)
425 else:
426 msg = "The specified configuration file destined for %s in %s is an empty string\n" \
427 % (dst_base, d.getVar('FILE'))
428 raise bb.build.FuncFailed(msg)
429
430
431
432def deploychef_copy_conf_files(d):
433 """Copy openstack services' configuration files to be used as chef-solo templates
434
435 Copy the configuration file(s) for the services under
436 ${D}${sysconfdir}/${CHEFPN}/<conf_file>.
437 The file(s) is/are assumed to be located in the images directory; ${D}<conf_file>
438 And evaluate all necessary substitution in the configuration file.
439 """
440 abs_template_list = list()
441 abs_conf_list = list()
442
443 #Retrieve our string of configuration files
444 conf_files = d.getVar('CHEF_SERVICES_CONF_FILES', True )
445 #The template files that will be made from the configuration files will be
446 #copied with reference to this base directory.
447 dst_base = d.getVar('CHEF_TEMPLATE_BASE', True )
448 if conf_files and len(conf_files.strip()):
449 conf_files = conf_files.split()
450 if len(conf_files) != 1:
451 for conf_file in conf_files:
452 abs_conf_path, abs_template_path = deploychef_copy_single_conf_file(d, \
453 dst_base, conf_file)
454 if abs_template_path:
455 #Save the absolute path to the template file
456 abs_template_list.append(abs_template_path)
457 if abs_conf_path:
458 #Save the absolute path to the configuration file
459 abs_conf_list.append(abs_conf_path)
460 else:
461 abs_conf_path, abs_template_path = deploychef_copy_single_conf_file(d,\
462 dst_base, conf_files[0])
463 if abs_template_path:
464 #Save the absolute path to the template file
465 abs_template_list.append(abs_template_path)
466 if abs_conf_path:
467 #Save the absolute path to the template file
468 abs_conf_list.append(abs_conf_path)
469 #Since the recipes no longer do the substitution in the
470 #configuration files, let us do it for the configuration files
471 deploychef_make_templates(d, tuple(abs_conf_list))
472 else:
473 msg = "The variable CHEF_SERVICES_CONF_FILES is not set"
474 msg += " in %s as a list of files as expected" % d.getVar('FILE', True)
475 #raise bb.build.FuncFailed(msg)
476 #No longer a requirement that all recipes inheriting this
477 #class must have a set of configuration files.
478 bb.debug(2,msg)
479 return tuple(abs_template_list)
480
481def deploychef_postinst_substitutions(d, sub_dict, postinst):
482 """Make value substitution in openstack services' postinstall scripts
483
484 This function makes all necessary substitution in the 'setup' related postinsts
485 functions pgk_postinst_${PN}-setup. The substitution is base on entries in a
486 dictionary sub_dict. In addition it also updates the list of defined constansts
487 based on the values specified in dictionary or as specified by the recipe's
488 callback function.
489
490 :sub_dict: name, placeholder and value substitution dictionary
491 :postinst: content of an openstack service's postinstall script
492
493 """
494 if postinst:
495 if type(sub_dict) is dict:
496 import re
497 base_dir = d.getVar('CHEF_PACKAGE_BASE', True)
498 attr_filename = os.path.join(base_dir, d.getVar('SRCNAME', True) + '-attributes.rb')
499 if os.path.exists(attr_filename):
500 hFile= open(attr_filename,'a+')
501 lines_in_file= hFile.read()
502 for key in sub_dict.keys():
503 placeholder , replacement = sub_dict[key]
504 if replacement and ( re.search(placeholder, postinst) or \
505 re.search(replacement, postinst)):
506 #If there is any remaining placeholder in the current string
507 #replace it.
508 new_replacement = d.getVar('ERB_PREFIX') + key
509 new_replacement += d.getVar('ERB_SUFFIX')
510
511 updated_postinst = re.sub(placeholder, new_replacement, postinst)
512 #If the placeholder has been substituted, look for the
513 #substitution and replace it with our template value
514 updated_postinst = re.sub(replacement, new_replacement, updated_postinst)
515 #Update our attributes file with the updated replacement
516 #string
517 attr_string = d.getVar('ERB_DEFAULT_PREFIX', True)
518 attr_string += r'"' + key
519 attr_string += r'"' + d.getVar('ERB_DEFAULT_SUFFIX', True)
520 attr_string +=' = ' + r'"' + replacement + r'"'
521 #Only write default values that do not yet exist in file
522 #if key not in lines_in_file:
523 if not re.search(key,lines_in_file):
524 hFile.write("%s%s" % (attr_string, os.linesep))
525
526 postinst_msg= "placeholder %s \n replacement %s \n updated_postinst :\n %s \n" % \
527 (placeholder, replacement, updated_postinst)
528 bb.debug(2, postinst_msg)
529 postinst = updated_postinst
530 hFile.close()
531 else:
532 msg = "The substitution dictionary variable sub_dict is not set %s as expected "\
533 % bb.data.getVar('FILE')
534 bb.build.FuncFailed(msg)
535 else:
536 msg = "Null string passsed to function %s %s "\
537 % (bb.data.getVar('FUNC',d), bb.data.getVar('FILE', d))
538 bb.build.FuncFailed(msg)
539 return postinst
540
541def deploychef_update_package_postinsts(d):
542 """Make placeholder/value substitution in openstack postinstall scripts
543
544 This function searches all the 'setup' related post-install scripts for
545 references to placeholders of interest; such as %CONTROLLER_IP%.
546 It replaces any such reference when it does find one with a placeholder
547 (<%=node[:CONTROLLER_IP]%>); that essentially converts the post-install
548 script to a chefsolo template.
549 """
550 def update_postinst_package(pkg):
551 bb.debug(1, 'Updating placeholders in postinst for pkg_postinst_%s scripts' % pkg)
552
553 ldata = bb.data.createCopy(d)
554 overrides = ldata.getVar("OVERRIDES", True)
555
556 msg = "%s The override variable is %s" % (pkg, overrides)
557 bb.note(msg)
558 ldata.setVar("OVERRIDES", "%s:%s" % (pkg, overrides))
559
560 bb.data.update_data(ldata)
561 postinst = ldata.getVar('pkg_postinst', True)
562 if postinst:
563 #Make the necessary substitutions using the default
564 #substitution dictionary
565 overrides = d.getVar("OVERRIDES", True)
566 msg = "%s The override variable is %s :\n %s " % (pkg, overrides, postinst)
567 bb.note(msg)
568 sub_dict = bb.data.getVar('CHEF_SERVICES_DEFAULT_CONF_SUBS', d , 1)
569 msg = "The variable %s is not set in %s as a dictionary as expected "\
570 % ('CHEF_SERVICES_DEFAULT_CONF_SUBS', bb.data.getVar('FILE', d))
571 if sub_dict:
572 import ast
573 #Safely retrieve our python data structure
574 sub_dict = ast.literal_eval(sub_dict)
575 if type(sub_dict) is dict:
576 import re
577 updated_postinst = deploychef_postinst_substitutions(d, sub_dict, postinst)
578 #Replace the placeholders in postinst script if any
579 d.setVar('pkg_postinst_%s' % pkg, updated_postinst)
580 else:
581 raise bb.build.FuncFailed(msg)
582 else:
583 raise bb.build.FuncFailed(msg)
584 else:
585 msg= "pkg_postinst_%s does not exist for %s\n" % (pkg, str(ldata))
586 bb.note(msg)
587 bb.build.FuncFailed(msg)
588
589 packages = (d.getVar('PACKAGES', True) or "").split()
590 if packages != []:
591 for pkg in packages:
592 if pkg.endswith('setup'):
593 update_postinst_package(pkg)
594
595python populate_packages_append() {
596
597 deploychef_update_package_postinsts(d)
598}
599
600def deploychef_add_file_to_FILES_PN(d, conf_file=None):
601 """Add all directories under a file name to FILES_${PN} variable
602
603 This function appends the name of the template file to the FILES_${PN}/${BPN}
604 bitbake variable to avoid QA warning about files built but not
605 added to rootfs. $CHEF_TEMPLATE_BASE/conf_file. Note that conf_file
606 is relative to the root filesystem as in /etc/neutron/neutron.conf
607 The template file will be located in /etc/${CHEFPN}/etc/neutron/neutron.conf.rb
608 Thefore, we need to make sure that all directories above the
609 template file are added to FILES_${PN} variable.
610
611 :conf_file: a chef-solo template file
612 """
613 import re
614 import os
615 #Perform an override so that we can update FILES_${PN} variables
616 ldata = bb.data.createCopy(d)
617 overrides = ldata.getVar("OVERRIDES", True)
618 pkg = d.getVar('PN', True) or d.getVar('BPN', True)
619 files = d.getVar('FILES_%s' % pkg, True)
620 pkg_files = "FILES_%s" % pkg
621 ldata.setVar("OVERRIDES", "%s:%s" % (pkg_files, overrides))
622 bb.data.update_data(ldata)
623
624 dest_base = d.getVar('CHEF_TEMPLATE_BASE')
625 pkg_imagedir = d.getVar('CHEF_ROOTFS_BASE', True)
626 #Add the packages image base directory if it does not already exist
627 if re.search(pkg_imagedir, files) == None:
628 #All the directory and all files in it
629 files = "%s %s" % ( files, pkg_imagedir)
630 files = "%s %s%s*" % ( files, pkg_imagedir, os.sep )
631 d.setVar('FILES_%s' % pkg, files)
632 msg= "Updated FILES_%s: %s for base images dir" % (pkg, d.getVar('FILES_%s' % pkg, files))
633 bb.debug(2,msg)
634 #All the files and all sub directory leading up to the package image base directory
635 if conf_file:
636 rel_basedir = os.path.dirname(conf_file)
637 if rel_basedir.startswith(os.sep):
638 rel_basedir = rel_basedir[1:]
639 rel_basedir = os.path.join(pkg_imagedir, rel_basedir)
640 if re.search(rel_basedir, files) == None:
641 files = "%s %s" % ( files, rel_basedir)
642 files = "%s %s%s*" % ( files, rel_basedir, os.sep )
643 while rel_basedir.count(os.sep) > 4:
644 #Must be above /etc/chef/etc/
645 rel_basedir_list = rel_basedir.split(os.sep)
646 rel_basedir = os.sep.join(rel_basedir_list[:-1])
647 if re.search(rel_basedir, files) == None:
648 #All the directory and files in it
649 files = "%s %s" % ( files, rel_basedir)
650 files = "%s %s%s*" % ( files, rel_basedir, os.sep )
651 bb.note(files)
652 bb.debug(2, files)
653 d.setVar('FILES_%s' % pkg, files)
654 msg= "Updated FILES_%s: %s " % (pkg, d.getVar('FILES_%s' % pkg, files))
655 bb.debug(2,msg)
656
657def deploychef_update_FILES_PN_variable(d):
658 """Indicate that the created chef-solo templates should be packaged
659
660 This function ensures that all the templates files which are based off
661 of configuration files exposed to this class are packaged up when they
662 are copied from the images directory to the various packages folders
663 This avoids the QA warning such as:
664 WARNING: For recipe python-neutron, the following files/directories were installed
665 but not shipped in any package:
666 """
667 conf_files = d.getVar('CHEF_SERVICES_CONF_FILES', True )
668 if conf_files and len(conf_files.strip()):
669 import shutil
670 import os
671 for conf_file in conf_files.split():
672 deploychef_add_file_to_FILES_PN(d, conf_file)
673 else:
674 #Add the directory containing the start/stop scripts
675 deploychef_add_file_to_FILES_PN(d)
676
677
678python populate_packages_prepend() {
679
680 deploychef_update_FILES_PN_variable(d)
681}
682
683#The sets of functions below are for post rootfs processing. Preparing files
684#for chefsolo is a two stage process. First we must create the required files
685#in the package's image directory; and this is mostly done by the functions
686#above.
687#And then we aggregate the files from their respective package directories
688#and put them together for the deploychef package in the expected
689#location.
690CHEF_ROOT_DIR="${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}"
691CHEF_CONF_DIR="${CHEF_ROOT_DIR}/${sysconfdir}"
692INITD_DIR="${IMAGE_ROOTFS}/${sysconfdir}/init.d"
693POSTINSTS_DIR="${IMAGE_ROOTFS}/${sysconfdir}/rpm-postinsts"
694DEPLOYCHEF_DIR="${IMAGE_ROOTFS}/opt/deploychef"
695DEPLOYCHEF_TEMPLATES_DIR="${DEPLOYCHEF_DIR}/cookbooks/openstack/templates/default"
696ATTRIBUTES_DIR="${DEPLOYCHEF_DIR}/cookbooks/openstack/attributes"
697ATTRIBUTES_FILE="${ATTRIBUTES_DIR}/default.rb"
698
699deploychef_copy_host_files() {
700 #The /etc/hosts & /etc/hostname files are written during the rootfs
701 #post process, therefore the only way of making templates out of them
702 #is to hook into the rootfs post process command.
703 if [ -f "${IMAGE_ROOTFS}/${sysconfdir}/hosts" ]; then
704 #Convert etc/hosts to chefsolo template
705 cp ${IMAGE_ROOTFS}/${sysconfdir}/hosts ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hosts.erb
706 sed -e "s,${CONTROLLER_IP},${ERB_PREFIX}CONTROLLER_IP${ERB_SUFFIX},g" -i \
707 ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hosts.erb
708 sed -e "s,${CONTROLLER_HOST},${ERB_PREFIX}CONTROLLER_HOST${ERB_SUFFIX},g" -i \
709 ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hosts.erb
710
711 sed -e "s,${COMPUTE_IP},${ERB_PREFIX}COMPUTE_IP${ERB_SUFFIX},g" -i \
712 ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hosts.erb
713 sed -e "s,${COMPUTE_HOST},${ERB_PREFIX}COMPUTE_HOST${ERB_SUFFIX},g" -i \
714 ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hosts.erb
715 #Create an attribute file for /etc/hosts
716 attr_string="${ERB_DEFAULT_PREFIX}\"COMPUTE_IP\"${ERB_DEFAULT_SUFFIX} = \"${COMPUTE_IP}\""
717 echo "$attr_string" > ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/hosts-attributes.rb
718 attr_string="${ERB_DEFAULT_PREFIX}\"COMPUTE_HOST\"${ERB_DEFAULT_SUFFIX} = \"${COMPUTE_HOST}\""
719 echo "$attr_string" >> ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/hosts-attributes.rb
720 attr_string="${ERB_DEFAULT_PREFIX}\"CONTROLLER_IP\"${ERB_DEFAULT_SUFFIX} = \"${CONTROLLER_IP}\""
721 echo "$attr_string" >> ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/hosts-attributes.rb
722 attr_string="${ERB_DEFAULT_PREFIX}\"CONTROLLER_HOST\"${ERB_DEFAULT_SUFFIX} = \"${CONTROLLER_HOST}\""
723 echo "$attr_string" >> ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/hosts-attributes.rb
724 fi
725
726 if [ -f "${IMAGE_ROOTFS}/${sysconfdir}/hostname" ]; then
727 #Convert etc/hostname to chefsolo template
728 cp ${IMAGE_ROOTFS}/${sysconfdir}/hostname ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hostname.erb
729 sed -e "s,${MY_HOST},${ERB_PREFIX}HOSTNAME${ERB_SUFFIX},g" -i \
730 ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/${sysconfdir}/hostname.erb
731 #Create an attribute file for /etc/hostname
732 attr_string="${ERB_DEFAULT_PREFIX}\"HOSTNAME\"${ERB_DEFAULT_SUFFIX} = \"${MY_HOST}\""
733 echo "$attr_string" > ${IMAGE_ROOTFS}/${sysconfdir}/${CHEFPN}/hostname-attributes.rb
734 fi
735}
736
737
738combine_services_daemons(){
739 if [ -n $1 ]; then
740 file_suffix=$1
741 rm -f ${DEPLOYCHEF_DIR}/$file_suffix
742 #combine the list of shutdown/startup scripts
743 find "${CHEF_ROOT_DIR}/" -name "*$file_suffix" 2> /dev/null | while read fname; do
744 service_cont=$(cat $fname)
745 for line in $service_cont; do
746 service=$(echo $line | awk -F"[SK][0-9]+" '{print $2}')
747 if [ -e ${INITD_DIR}/$service ]; then
748 echo $line >> ${DEPLOYCHEF_DIR}/$file_suffix
749 fi
750 done
751 done
752 fi
753}
754
755#This function combines the attributes of all the sevices into
756#a default.rb attributes file.
757combine_services_attributes(){
758 file_suffix='attributes.rb'
759 mkdir -p ${ATTRIBUTES_DIR}; rm -f ${ATTRIBUTES_FILE} 2>/dev/null
760 #combine the list of shutdown/starup scripts
761 find "${CHEF_ROOT_DIR}/" -name "*$file_suffix" 2> /dev/null | \
762 while read fname; do
763 cat $fname | while read line_in_file; do
764 index=$(echo $line_in_file | awk -F'"' '{print $2}')
765 #Only append attributes that are not in the default.rb attributes file
766 if [ ! `grep -l $index ${ATTRIBUTES_FILE}` ]; then
767 echo $line_in_file >> ${ATTRIBUTES_FILE}
768 fi
769 done
770 done
771}
772
773#This function copies the templates to deploychef directory from
774#within the packages directories
775copy_templates_in_place(){
776 #copy rpm-postinsts and config templates into templates directory
777 mkdir -p ${DEPLOYCHEF_TEMPLATES_DIR}
778 #First copy all our configuration template files
779 if [ -d ${CHEF_CONF_DIR} ]; then
780 cp -rf ${CHEF_CONF_DIR} ${DEPLOYCHEF_TEMPLATES_DIR}
781 fi
782 #Now copy the rpm-postinsts files into cookbooks/templates/default/etc/
783 if [ -d ${POSTINSTS_DIR} ]; then
784 cp -rf ${POSTINSTS_DIR} ${DEPLOYCHEF_TEMPLATES_DIR}/${sysconfdir}
785 #Move the files to base of the templates directory, where chef-solo
786 #expects them
787 cp -f ${POSTINSTS_DIR}/* ${DEPLOYCHEF_TEMPLATES_DIR}/.
788 fi
789
790}
791
792filter_node_dependent_templates(){
793 if [ -d ${DEPLOYCHEF_TEMPLATES_DIR} ]; then
794 find "${DEPLOYCHEF_TEMPLATES_DIR}/" -name "*.erb*" 2> /dev/null | \
795 while read fname; do
796 config_file=$(echo $fname | awk -F'/default' '{print $2}' | awk \
797 -F'.erb' '{print $1}')
798 #If the base configuration file does not exist on this node
799 #remove it.
800 if [ ! -f ${IMAGE_ROOTFS}$config_file ]; then
801 rm -f "$fname"
802 else
803 #Move the file to the default template directory where
804 #chefsolo expect them
805 cp "$fname" "${DEPLOYCHEF_TEMPLATES_DIR}"
806 fi
807 done
808 fi
809}
810
811#This function is our post rootfs hook, it enables
812#us to do what we wish to do during rootfs creation process.
813deploychef_rootfs_postprocess_commands() {
814
815 if [ -n "${OPENSTACKCHEF_ENABLED}" ]; then
816 deploychef_copy_host_files
817 combine_services_daemons 'shutdown-list'
818 combine_services_daemons 'startup-list'
819 combine_services_attributes
820 copy_templates_in_place
821 filter_node_dependent_templates
822 else
823 #Let us delete the deploychef init script that runs
824 #chef-solo at boot-up from rootfs
825 rm -f ${INITD_DIR}/deploychef 2> /dev/null
826 fi
827 #We nolonger have need for /etc/${CHEFPN} directory on rootfs
828 #Not even at run-time
829 rm -rf "${CHEF_ROOT_DIR}"
830}
831