def __init__(self,hosttype_id,dist_codename,hwaddr=None,context=None,context_only=False,pretend=False): """ Build the configuration for a certain hosttype or host. It works in a threaded or asynchronious environment by ensuring that a unique temp space is created in /tmp 1. Create temp directory. 2. Fetch system, domain and hosts information. 3. Initiate the configuration parser. """ self.hosttype = hostdef.hosttype_as_text(hosttype_id) self.hwaddr = hostdef.check_hwaddr(hwaddr) self.dist_codename = dist_codename self.context = context self.context_only = context_only # Create a temp directory self.tempdir = tempfile.mkdtemp(prefix='skolesys_') # Collect info about domain and host self.infocollection = InfoCollection(self.hwaddr) # Build the configuration self.build_config(pretend)
class ConfigBuilder: """ ConfigBuilder handles the SkoleSYS configuration template hierarchy. The configuration to be generated is controlled by the parameters given in the constructor. The constructor also calls to the configuration builder method. So when the constructor returns the configuration scripts are build and ready to ship. The ConfigBuilder uses tempfile to create a temporary directory in the system's temp directory. The specific location of the configuration scripts that has been build can be read in the member tempdir. ConfigBuilder also packages the result into the file conf.tgz inside the temporary workspace directory so it can be marshalled easyly through some sort of network protocol - the SkoleSYS SOAP service and client provides automatic fetching of configuration scripts for registered hosts so a client can at any time fetch it's full configuration just by calling ss_getconf as root. NOTE! The temporary workspace usually /tmp/skolesys_<somthing> is really temporary. It is deleted by the destructor. So to fetch the result you must keep the ConfigBuilder instance alive long enough for you to make a copy. The template hierarchi: ---------------------- SkoleSYS ships with default configuration templates, but the resulting configuration scripts can easyly be customized. For instance if a particular organization wishes to customize the /etc/hosts file generated for workstations it is done by copying the default /etc/hosts file into the custom-templates hierarchi and changing it there. This mechanism ensures 2 things: 1. The default-templates remain untouched. 2. SkoleSYS mainserver updates don't overwrite the organization cusomizations. A side from the default templates there are 2 levels of cusomizations: (0. default-templates) 1. custom-templates (general customizations) 2. host-templates (host specific customizations) Inside the default-templates and custom-templates exists a 'common' directory, a directory per hosttype ('mainserver','ltspserver','workstation') and a 'contexts' directory which again holds one directory per hosttype example: /etc/skolesys/default-templates/common /etc/skolesys/default-templates/mainserver /etc/skolesys/default-templates/ltspserver /etc/skolesys/default-templates/workstation /etc/skolesys/default-templates/contexts/mainserver /etc/skolesys/default-templates/contexts/ltspserver The host-templates holds a mac-address folder per host having special configurations example: host-templates/01:02:03:04:05:06 host-templates/01:23:45:67:89:ab Distribution end points are used to target the specific Ubuntu version of the system requesting its configuration. The ss_getconf command on skolesys clients (ltspserver or workstation) will automatically detect the distribution codename. The configuration hierarchi is as follows for host '01:23:45:67:89:ab' with hosttype 'ltspserver' running on Ubuntu codename 'feisty': default-templates/common/all default-templates/common/feisty default-templates/mainserver/all default-templates/mainserver/feisty custom-templates/common/all custom-templates/common/feisty custom-templates/mainserver/all custom-templates/mainserver/feisty host-templates/01:23:45:67:89:ab/all (you could add 'feisty' here too but there is not much point in it) So what happens is that all files files under the each of the directories above are parsed recursively using python cheetah. The data used to parse the files origin partially from skolesys,conf and partially from the hosts registered in the ldap back-end. Contexts: -------- Contexts (context argument) are used for creating specialized configurations used for certain events. When in context mode it is possible to skip the basic hierarchi (from above) and just run through the context alone (context_only argument) in the examples below are shown a context parse with context_only and one in combination with the basic hierarchi. The configuration hierarchi for host '01:23:45:67:89:ab' with hosttype 'mainserver' in the context 'update-hosts' (context_only=True): default-templates/contexts/mainserver/update-hosts custom-templates/contexts/mainserver/update-hosts host-templates/contexts/01:23:45:67:89:ab/mainserver/update-hosts The configuration hierarchi for host '01:23:45:67:89:ab' with hosttype 'mainserver' in the context 'update-hosts' (context_only=False): default-templates/common default-templates/mainserver default-templates/contexts/mainserver/update-hosts custom-templates/common custom-templates/mainserver custom-templates/contexts/mainserver/update-hosts host-templates/01:23:45:67:89:ab host-templates/contexts/01:23:45:67:89:ab/mainserver/update-hosts """ def __init__(self,hosttype_id,dist_codename,hwaddr=None,context=None,context_only=False,pretend=False): """ Build the configuration for a certain hosttype or host. It works in a threaded or asynchronious environment by ensuring that a unique temp space is created in /tmp 1. Create temp directory. 2. Fetch system, domain and hosts information. 3. Initiate the configuration parser. """ self.hosttype = hostdef.hosttype_as_text(hosttype_id) self.hwaddr = hostdef.check_hwaddr(hwaddr) self.dist_codename = dist_codename self.context = context self.context_only = context_only # Create a temp directory self.tempdir = tempfile.mkdtemp(prefix='skolesys_') # Collect info about domain and host self.infocollection = InfoCollection(self.hwaddr) # Build the configuration self.build_config(pretend) def build_config(self,pretend): """ 1. Parse the templates 2. Create a resulting archive file for export """ def store_link(args,dirname,fnames): """ This function is used by os.path.walk to collect which config templates should be used for a certain hosttype, host and context. """ temp_level, file_location = args for f in fnames: if os.path.isfile(os.path.join(dirname,f)): file_location[os.path.join(dirname[len(temp_level):],f)] = os.path.join(dirname,f) level_order = ['default','custom','host'] dist_order = ['all',self.dist_codename] system_order = [] if not self.context or not self.context_only: system_order += ['common'] system_order += [self.hosttype] if self.hwaddr: system_order += [self.hwaddr] if self.context: system_order += ['contexts/%s/%s' % (self.hosttype,self.context)] if self.hwaddr: system_order += ['contexts/%s/%s/%s' % (self.hwaddr,self.hosttype,self.context)] file_location = {} template_basedir = self.infocollection.get_collection()['conf']['cfmachine']['template_basedir'] # Determin the config-files for the specific host type and mac-address for level in level_order: for system in system_order: for dist in dist_order: if os.path.exists("%s/%s-templates/%s/%s" % (template_basedir,level,system,dist)): os.path.walk("%s/%s-templates/%s/%s" % (template_basedir,level,system,dist),\ store_link,("%s/%s-templates/%s/%s/" % (template_basedir,level,system,dist),file_location)) if pretend==True: for fi in file_location.keys(): print fi print " -> %s" % file_location[fi] return # Copy the config files running them through cheetah for k,v in file_location.items(): f_stat = os.stat(v) mod,uid,gid,siz = f_stat.st_mode,f_stat.st_uid,f_stat.st_gid,f_stat.st_size destfile = os.path.join(self.tempdir,k) destdir = os.path.split(destfile)[0] try: os.makedirs(destdir) except: pass if siz > 0: print "Parsing: %s" % v t = Template(file=v, searchList=[self.infocollection.get_collection()]) else: t = '' f=open(destfile,'w') try: f.write(t.__str__()) except Exception, e: print "%s, (while parsing %s)" % (e,v) f.close() return False f.close() os.chmod(destfile,mod) os.chown(destfile,uid,gid) # Finally create a tarball for network export curdir = os.getcwd() os.chdir(self.tempdir) os.system('tar czpf conf.tgz *') os.chdir(curdir) return True