def _collate_container_params(self, containertemplate, commonparams, containerelem, overlays): containerparams = [('lxc.utsname', self.lxc_name)] if containertemplate: containerparams.extend(containertemplate.params) for k, v in commonparams: containerparams.append((k, v)) for paramelem in containerelem.findall('./parameters/parameter'): if (str(paramelem.attrib['name']) == 'lxc.utsname'): # the lxc_name is set by the container element atribute print >>sys.stderr, \ 'Found lxc.utsname in containertemplate. Ignoring' continue containerparams.append((str(paramelem.attrib['name']), str(paramelem.attrib['value']))) for i, parampair in enumerate(containerparams): k, v = parampair containerparams[i] = (k, format_string(v, overlays)) return containerparams
def _createfile(self, publishdir, logdir, index, runtime_overlays, env_overlays, etce_config_overlays): reserved_overlays = {} reserved_overlays['etce_index'] = index # etce_hostname formats are limited to the index and the # overlays specified in the test.xml file. etce_hostname_cm = ChainMap({'etce_index': reserved_overlays['etce_index']}, self._template_local_overlaylists[index], self._template_local_overlays, self._templates_global_overlaylists[index], self._global_overlays) reserved_overlays['etce_hostname'] = format_string(self._hostname_format, etce_hostname_cm) if logdir: reserved_overlays['etce_log_path'] = \ os.path.join(logdir, reserved_overlays['etce_hostname']) publishfile = os.path.join(publishdir, reserved_overlays['etce_hostname'], self._output_file_name) other_keys = set([]) non_reserved_overlays = [ runtime_overlays, env_overlays, self._template_local_overlaylists[index], self._template_local_overlays, self._templates_global_overlaylists[index], self._global_overlays, etce_config_overlays ] map(other_keys.update, non_reserved_overlays) key_clashes = other_keys.intersection(set(reserved_overlays.keys())) if key_clashes: raise ValueError('Overlay keys {%s} are reserved. Quitting.' % \ ','.join(map(str,key_clashes))) overlays = ChainMap(reserved_overlays, *non_reserved_overlays) # format str can add subdirectories, so make those if necessary if not os.path.exists(os.path.dirname(publishfile)): os.makedirs(os.path.dirname(publishfile)) if os.path.exists(publishfile): print 'Warning: %s already exists. Overwriting!' % publishfile format_file(self._absname, publishfile, overlays)
def formatted_hostnames(self): formatted_hostnames = [] for index in self.indices: chainmap = ChainMap({'etce_index':index}, self._template_local_overlaylists[index], self._template_local_overlays, self._templates_global_overlaylists[index], self._global_overlays) formatted_hostnames.append(format_string(self._hostname_format, chainmap)) return formatted_hostnames
def _get_initscript(self, containertemplate, containerelem, overlays): initscript= ('',None) if containertemplate: initscript = containertemplate.initscript for initscriptelem in containerelem.findall('./initscript'): initscript = ('init.sh', initscriptelem.text) if initscript[1]: lines = [] for line in initscript[1].split('\n'): line = line.strip() if len(line) > 0: lines.append(format_string(line.strip(), overlays)) initscript = (initscript[0], '\n'.join(lines)) return initscript
def _parseplan(self, lxcplanfile): lxcplanelem = self.parse(lxcplanfile) kernelparameters = {} containertemplates = {} rootdirectories = {} lxcplanelems = \ lxcplanelem.findall('./containertemplates/containertemplate') for containertemplateelem in lxcplanelems: containertemplate_name = containertemplateelem.attrib['name'] containertemplate_parent_name = \ containertemplateelem.attrib.get('parent', None) containertemplate_parent = None if containertemplate_parent_name: if not containertemplate_parent_name in containertemplates: errmsg = 'parent "%s" of containertemplate "%s" not ' \ 'previously listed. Quitting.' % \ (containertemplate_parent_name, containertemplate_name) raise ValueError(errmsg) containertemplate_parent = \ containertemplates[containertemplate_parent_name] containertemplates[containertemplate_name] = \ ContainerTemplate(containertemplateelem, containertemplate_parent) hostelems = lxcplanelem.findall('./hosts/host') bridges = {} containers = {} hostnames = [] for hostelem in hostelems: hostname = hostelem.attrib.get('hostname') hostnames.append(hostname) # 'localhost' is permitted as a catchall hostname to mean the # local machine only when one host is specified in the file if hostname == 'localhost': if len(hostelems) > 1: error = '"localhost" hostname only permitted when one ' \ 'host is specified. Quitting' raise ValueError(error) # kernel params kernelparameters[hostname] = {} for paramelem in hostelem.findall('./kernelparameters/parameter'): kernelparameters[hostname][paramelem.attrib['name']] = \ paramelem.attrib['value'] # bridges (explicit) bridges[hostname] = {} for bridgeelem in hostelem.findall('./bridges/bridge'): bridge = Bridge(bridgeelem) bridges[hostname][bridge.name] = bridge containers[hostname] = [] params = [] containerselem = hostelem.findall('./containers')[0] root_directory = \ os.path.join(ConfigDictionary().get('etce', 'WORK_DIRECTORY'), 'lxcroot') rootdirectories[hostname] = root_directory # ensure no repeated lxc_indices alllxcids = set([]) for containerelem in hostelem.findall('./containers/container'): containerlxcids = etce.utils.nodestr_to_nodelist( str(containerelem.attrib['lxc_indices'])) repeatedids = alllxcids.intersection(containerlxcids) assert len(repeatedids) == 0, \ 'Found repeated lxcid(s): {%s}. Quitting.' % \ ','.join([ str(nid) for nid in list(repeatedids) ]) alllxcids.update(containerlxcids) # Create containers from container elems for containerelem in hostelem.findall('./containers/container'): templatename = containerelem.attrib.get('template', None) template = containertemplates.get(templatename, None) lxcids = etce.utils.nodestr_to_nodelist( str(containerelem.attrib['lxc_indices'])) # fetch the overlays, use etce file values as default overlays = ConfigDictionary().asdict()['overlays'] for overlayelem in containerelem.findall('./overlays/overlay'): oname = overlayelem.attrib['name'] ovalue = overlayelem.attrib['value'] overlays[oname] = etce.utils.configstrtoval(ovalue) # fetch the overlaylists overlaylists = {} for overlaylistelem in containerelem.findall( './overlays/overlaylist'): oname = overlaylistelem.attrib['name'] separator = overlaylistelem.attrib.get('separator', ',') ovalues = overlaylistelem.attrib['values'].split(separator) overlaylists[oname] = ovalues # treat all values for each name as an int if possible, # else all strings for oname, ovals in overlaylists.items(): converted_vals = [] try: converted_vals = [ etce.utils.configstrtoval(oval) for oval in ovals ] overlaylists[oname] = converted_vals except ValueError: # leave as strings pass # Why must a default value be supplied here when # schema declares this attribute with a default value? for i, lxcid in enumerate(lxcids): # start with overlays lxcoverlays = copy.copy(overlays) # then add list items for this node for oname, ovals in overlaylists.items(): lxcoverlays[oname] = ovals[i] # then lxcindex, lxc_name and lxc_directory (cannot be overwritten) lxcoverlays.update({'lxc_index': lxcid}) lxcoverlays.update({ 'lxc_name': format_string(containerelem.attrib['lxc_name'], lxcoverlays) }) lxcoverlays.update({ 'lxc_directory': os.path.join(root_directory, lxcoverlays['lxc_name']) }) containers[hostname].append( Container(containerelem, lxcoverlays, params, template, bridges[hostname], hostname)) # Roll over containers to get names of implicit bridges added # from the container interface bridge names and augment # the bridges list for container in containers[hostname]: for iname, iparams in container.interfaces.items(): if not iname in bridges[hostname]: bridges[hostname][iname] = BridgeImplicit(iname) return hostnames, kernelparameters, bridges, containers, rootdirectories
def _process_interfaces(self, containertemplate, containerelem, overlays): interfaces = defaultdict(lambda: {}) bridge_entry_ipv4 = {} bridge_entry_ipv6 = {} if containertemplate: for bridgename, paramdict in containertemplate.interfaces.items(): bridgename = format_string(bridgename, overlays) for iname, ival in paramdict.items(): interfaces[bridgename][format_string(iname, overlays)] = \ format_string(ival, overlays) for bridgename, entryname in \ containertemplate.hosts_entries_ipv4.items(): bridgename = format_string(bridgename, overlays) bridge_entry_ipv4[bridgename] = format_string( entryname, overlays) for bridgename, entryname in \ containertemplate.hosts_entries_ipv6.items(): bridgename = format_string(bridgename, overlays) bridge_entry_ipv6[bridgename] = format_string( entryname, overlays) # overwrite with local values from container for interfaceelem in containerelem.findall('./interfaces/interface'): bridgename = format_string(str(interfaceelem.attrib['bridge']), overlays) interfaceparams = interfaces[bridgename] for iparamelem in interfaceelem.findall('./parameter'): iname = format_string(str(iparamelem.attrib['name']), overlays) ival = format_string(str(iparamelem.attrib['value']), overlays) interfaceparams[iname] = ival entry_name_ipv4 = \ interfaceelem.attrib.get( 'hosts_entry_ipv4', bridge_entry_ipv4.get(bridgename, None)) if entry_name_ipv4: bridge_entry_ipv4[bridgename] = \ format_string(entry_name_ipv4, overlays) entry_name_ipv6 = \ interfaceelem.attrib.get( 'hosts_entry_ipv6', bridge_entry_ipv6.get(bridgename, None)) if entry_name_ipv6: bridge_entry_ipv6[bridgename] = \ format_string(entry_name_ipv6, overlays) hosts_entries_ipv4 = [] for bridgename, entry_name_ipv4 in bridge_entry_ipv4.items(): if not 'lxc.network.ipv4' in interfaces[bridgename]: error = 'Found hosts_entry_ipv4 attribute for ' \ 'bridge "%s" for container "%s" but ' \ 'no corresponding "lxc.network.ipv4" ' \ 'value for the interface. Quitting.' \ % (bridgename, self.lxc_name) raise ValueError(error) addr = interfaces[bridgename]['lxc.network.ipv4'] hosts_entries_ipv4.append((entry_name_ipv4, addr.split('/')[0])) hosts_entries_ipv6 = [] for bridgename, entry_name_ipv6 in bridge_entry_ipv6.items(): if not 'lxc.network.ipv6' in interfaces[bridgename]: error = 'Found hosts_entry_ipv6 attribute for ' \ 'bridge "%s" for container "%s" but ' \ 'no corresponding "lxc.network.ipv6" ' \ 'value for the interface. Quitting.' \ % (bridgename, self.lxc_name) raise ValueError(error) addr = interfaces[bridgename]['lxc.network.ipv6'] hosts_entries_ipv6.append((entry_name_ipv6, addr)) return interfaces, hosts_entries_ipv4, hosts_entries_ipv6
def _createdir(self, subdirectory_map, publishdir, logdir, index, runtime_overlays, env_overlays, etce_config_overlays): # assemble the format dictionary from the various overlays # most local value takes precedent reserved_overlays = {} reserved_overlays['etce_index'] = index # etce_hostname formats are limited to the index and the # overlays specified in the test.xml file. etce_hostname_cm = ChainMap({'etce_index': reserved_overlays['etce_index']}, self._template_local_overlaylists[index], self._template_local_overlays, self._templates_global_overlaylists[index], self._global_overlays) reserved_overlays['etce_hostname'] = format_string(self._hostname_format, etce_hostname_cm) if logdir: reserved_overlays['etce_log_path'] = \ os.path.join(logdir, reserved_overlays['etce_hostname']) node_publishdir = os.path.join(publishdir, reserved_overlays['etce_hostname']) non_reserved_overlays = [ runtime_overlays, env_overlays, self._template_local_overlaylists[index], self._template_local_overlays, self._templates_global_overlaylists[index], self._global_overlays, etce_config_overlays ] other_keys = set([]) for some_overlays in non_reserved_overlays: other_keys.update(some_overlays) key_clashes = other_keys.intersection(set(reserved_overlays)) if key_clashes: raise ValueError('Overlay keys {%s} are reserved. Quitting.' % \ ','.join(map(str,key_clashes))) overlays = ChainMap(reserved_overlays, *non_reserved_overlays) print('Processing template directory "%s" for etce_index=%d ' \ 'and destination=%s' % \ (self.template_directory_name, index, node_publishdir)) if not os.path.exists(node_publishdir): os.makedirs(node_publishdir) found = False for relpath,entry in subdirectory_map.items(): # ignore files outside of the template directory pathtoks = relpath.split(os.path.sep) if not pathtoks[0] == self.template_directory_name: continue dstfile = os.path.join(node_publishdir,*pathtoks[1:]) dstdir = os.path.dirname(dstfile) if not os.path.exists(dstdir): os.makedirs(dstdir) format_file(entry.full_name, dstfile, overlays)