gtk+3: fix dependencies for new gnome/accessibility/at-spi2-core
[oi-userland.git] / components / ruby / puppet / files / update_smf.py
blob512c9afb1eab7342a9de9c8efe4aeb852c60f3a1
1 #! /usr/bin/python
3 # CDDL HEADER START
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
20 # CDDL HEADER END
24 # Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
27 '''
28 Utility program for helping with the upgrade of puppet to a newer
29 version. This program will take a puppet configuration file that
30 has been generated via the command sequence
32 puppet agent --genconfig > puppet.conf
34 and use the data in that configuration file to replace the
35 associated Puppet SMF user configuratable properties with the
36 properties that are allowed in the new version of puppet
38 NOTE: This file should not be included with the puppet release
39 '''
41 import os
42 import re
43 import sys
45 from lxml import etree
46 from optparse import OptionParser
49 COMMENT_PATTERN = re.compile(".*# ?(.*)")
50 CONFIG_VALUE_PATTERN = re.compile("([\S]+)\s*=\s*(\S*)")
52 DEFAULT_VALUE_STR = "The default value is "
54 # SMF defined property types. For a list of
55 # all available types see
56 # /usr/share/lib/xml/dtd/service_bundle.dtd.1
57 TYPE_ASTRING = "astring"
58 TYPE_BOOLEAN = "boolean"
59 TYPE_INTEGER = "integer"
60 TYPE_HOST = "host"
61 TYPE_HOSTNAME = "hostname"
62 TYPE_NETADDRESS = "net_address"
63 TYPE_URI = "uri"
66 # Dictionary of currently defined property types to associate
67 # with a specified property. Any property not defined here
68 # is assumed to have a property type of astring, integer,
69 # or boolean
70 PROP_TYPE = {
71 'server': TYPE_HOST,
72 'archive_file_server': TYPE_HOST,
73 'bindaddress': TYPE_NETADDRESS,
74 'ca_server': TYPE_HOST,
75 'certname': TYPE_HOSTNAME,
76 'couchdb_url': TYPE_URI,
77 'dbserver': TYPE_HOST,
78 'dns_alt_names': TYPE_HOST,
79 'http_proxy_host': TYPE_HOST,
80 'inventory_server': TYPE_HOST,
81 'ldapserver': TYPE_HOST,
82 'ldapuser': TYPE_HOSTNAME,
83 'module_repository': TYPE_URI,
84 'queue_source': TYPE_URI,
85 'report_server': TYPE_HOST,
86 'reporturl': TYPE_URI,
87 'smtpserver': TYPE_HOST,
88 'srv_domain': TYPE_HOST,
91 # Dictionary used to hold properites and the resulting xml code
92 PUPPET_CONFIG_DICT = dict()
95 def err(msg):
96 '''Output standard error message'''
97 # Duplicate the syntax of the parser.error
98 sys.stderr.write("%(prog)s: error: %(msg)s\n" %
99 {"prog": os.path.basename(sys.argv[0]), "msg": msg})
102 def create_config_element(key, key_type, desc_text):
103 '''Create a basic xml entry following the basic pattern of
105 <prop_pattern name='${key}' type='${key_type}'
106 required='false'>
107 <description> <loctext xml:lang='C'>
108 ${desc_text}
109 </loctext> </description>
110 </prop_pattern>
112 prop_pattern = etree.Element(
113 "prop_pattern",
114 name=key,
115 type=key_type,
116 required="false")
117 desc = etree.SubElement(prop_pattern, "description")
118 loctext = etree.SubElement(desc, "loctext")
119 loctext.text = "\n%s\n\t " % desc_text
120 loctext.set('{http://www.w3.org/XML/1998/namespace}lang', 'C')
121 return prop_pattern
124 def determine_type(key, value):
125 '''Determine the xml property type to associate with the
126 specified key
129 # Does the key have a specified xml property type
130 # already defined?
131 try:
132 return PROP_TYPE[key]
133 except KeyError:
134 pass
136 # Use the value to determine the xml property type
137 if value.isdigit():
138 return TYPE_INTEGER
139 if value.lower() in ['false', 'true']:
140 return TYPE_BOOLEAN
141 return TYPE_ASTRING
144 def process_grouping(lines):
145 '''Process the lines in the list. The last entry should be
146 a 'key=value' entry
149 # The last field should be a key = value pair
150 # If it's not then the format of the file is not matching
151 # the expected format of
153 # Description
154 # The default value is "xxxx"
155 # key = value
157 key_value = lines.pop()
158 match = CONFIG_VALUE_PATTERN.match(key_value)
159 if not match:
160 raise TypeError("Last line in grouping is not in expected "
161 "format of 'key = value'\n%s" %
162 "\n".join(lines))
163 key = match.group(1)
164 value = match.group(2)
166 default_value_line = lines.pop()
167 if not default_value_line.startswith(DEFAULT_VALUE_STR):
168 # Not a match. Last line was still part of the description
169 lines.append(default_value_line)
171 key_type = determine_type(key, value)
173 # remaining lines are the descriptor field
174 desc = '\n'.join(lines)
175 PUPPET_CONFIG_DICT[key] = (key, key_type, desc)
178 def parse_puppet_config(filename):
179 '''Parse the puppet configuration file that is generated by
180 puppet agent --genconfig
182 parameter_list = []
183 agent_check = True
184 with open(filename, 'r') as f_handle:
185 for line in f_handle:
186 if agent_check:
187 if line.startswith("[agent]"):
188 # Throw away the initial starting block code in the
189 del parameter_list[:]
190 agent_check = False
191 continue
192 line = line.strip().replace("\n", "")
193 if not line:
194 # If parameter_list is not empty, process the data and
195 # generate an xml structure
196 process_grouping(parameter_list)
197 # Done processing, delete all the saved entries
198 del parameter_list[:]
199 continue
201 match = COMMENT_PATTERN.match(line)
202 if match:
203 line = match.group(1)
204 parameter_list.append(line)
205 f_handle.close()
208 def update_smf_file(smf_xml_file, output_file, version):
209 '''Replace the puppet property definitions in the specified SMF
210 file with those that are stored in PUPPET_CONFIG_DICT
213 try:
214 parser = etree.XMLParser(remove_blank_text=True)
215 tree = etree.parse(smf_xml_file, parser)
216 root = tree.getroot()
217 template = root.find("service/template")
218 puppet_desc = template.find("common_name/loctext")
219 puppet_desc.text = "Puppet version %s" % version
221 pg_pattern = template.find("pg_pattern")
222 except IOError as msg:
223 err(msg)
224 return -1
225 except etree.XMLSyntaxError as msg:
226 err(msg)
227 return -1
228 except NameError as msg:
229 err("XML file %s does not match expected formated" % smf_xml_file)
231 # Delete the pg_pattern nodes and it's children
232 # This is the structure that will be rebuilt based
233 # on the genconfig information that was read in
234 if pg_pattern is not None:
235 template.remove(pg_pattern)
237 # <pg_pattern name='config' type='application' required='false'>
238 pg_pattern = etree.SubElement(
239 template,
240 "pg_pattern",
241 name="config",
242 type="application",
243 required="false")
244 for key in sorted(PUPPET_CONFIG_DICT.iterkeys()):
245 values = PUPPET_CONFIG_DICT[key]
246 element = create_config_element(values[0], values[1], values[2])
247 pg_pattern.append(element)
249 # Write out the contents of the updated puppet SMF config file
250 print "Writting out contents of new SMF configuration file to: %s" % \
251 output_file
252 with open(output_file, "w") as f_handle:
253 f_handle.write(etree.tostring(tree, pretty_print=True))
254 f_handle.close()
257 def option_list():
258 '''Build the option list for this utility'''
259 desc = "Utility for assisting in the upgrading of Solaris Puppet SMF file"
260 usage = "usage: %prog -c <puppet_config_file> -s <smf_confilg_file> " \
261 "-v <puppet_version> [-o <output_file>]\n"
262 opt_list = OptionParser(description=desc, usage=usage)
264 opt_list.add_option("-c", "--config", dest="config", default=None,
265 action="store", type="string", nargs=1,
266 metavar="<puppet_config_file>",
267 help="Puppet configuration file generated via"
268 "genconfig option to puppet. i.e. "
269 "puppet agent --genconfig > puppet.conf")
270 opt_list.add_option("-s", "--smf", dest="smf_xml", default=None,
271 action="store", type="string", nargs=1,
272 metavar="<smf_config_file>",
273 help="Current solaris Puppet SMF XML configuration"
274 " file. This file is located in <userland_tree>"
275 "/components/puppet/files/puppet.xml")
276 opt_list.add_option("-o", "--output", dest="output", default=None,
277 action="store", type="string", nargs=1,
278 metavar="<output_file>",
279 help="The name of the new puppet.xml file ")
280 opt_list.add_option("-v", "--version", dest="version", default="None",
281 action="store", type="string", nargs=1,
282 metavar="<puppet_version>",
283 help="Puppet Version of update")
285 return opt_list
288 def main():
289 '''Execute this utility based on the options supplied by the user'''
290 parser = option_list()
292 (options, _args) = parser.parse_args()
294 if not options.output and options.version:
295 options.output = "puppet.%s.xml" % options.version
297 if not options.config or not options.smf_xml or \
298 not options.output or not options.version:
299 err("Required options not specified")
300 parser.print_help()
301 sys.exit(-1)
303 if not os.path.isfile(options.config):
304 err("%s does not exist or is not a regular file\n"
305 % options.config)
306 sys.exit(-1)
307 if not os.path.isfile(options.smf_xml):
308 err("%s does not exist or is not a regular file\n"
309 % options.smf_xml)
310 sys.exit(-1)
311 if os.path.exists(options.output):
312 err("specified file %s already exist\n"
313 % options.output)
314 sys.exit(-1)
316 parse_puppet_config(options.config)
317 update_smf_file(options.smf_xml, options.output, options.version)
319 if __name__ == '__main__':
320 main()