def load_configurations( self, reload_without_version_control = False ): d_configurations = {} l_bad_configurations = [] # Obtention d'un resolveur base sur le resolv_conf fouri self._resolver = dns.resolver.Resolver( self._resolver_conf ) self._resolver.query = shared_infrastructure.catch_NoNamesservers( self._resolver.query ) BLOCKSIZE = 65536 def get_hook_server_filehash( filename ): hasher = hashlib.sha1() with closing( open( filename ) ) as f: buf = f.read( BLOCKSIZE ) while len( buf ) > 0: hasher.update( buf ) buf = f.read(BLOCKSIZE) return hasher.hexdigest() # Recherche des serveurs for server in [ s for s in os.listdir( self._root_configuration ) if os.path.isdir( self._root_configuration.rstrip( os.sep ) + os.sep + s ) ]: # Si le nom ne correspond pas a un nom resolvable # la configuration n'est pas prise en compte if not self._resolver.query( server, 'A' ) and not self._resolver.query( server, 'AAAA' ): l_bad_configurations.append( ( '%s not resolvable' % ( server ), self._root_configuration, server, ) ) continue try: if not os.listdir( self._root_configuration.rstrip( os.sep ) + os.sep + server ): l_bad_configurations.append( ( '%s no port definition' % ( server ), self._root_configuration, server, ) ) continue except: # En cas de suppression de la racine # entre le listdir dans la boucle # et l'usage du server dans la cronstrcuion # de chemin, le repertoire server # peut avoir disparu. continue # Recherche des ports for port in os.listdir( self._root_configuration.rstrip( os.sep ) + os.sep + server ): # Si le repertoire ne correspond pas au format d'un nom de port # la configuration n'est pas prise en compte try: if not( re.match( '\d{1,5}', port ) and int( port ) <= 65535 ): raise Exception() except: l_bad_configurations.append( ( '%s unvalid port format' % ( port ), self._root_configuration, server, port ) ) continue d_configurations.setdefault( server, {} ).setdefault( port, dict( [ ( hook_server_name , { 'path': hook_server_filepath , 'hash': get_hook_server_filehash( hook_server_filepath ) } ) for hook_server_name, hook_server_filepath in map( lambda hook_server_name: ( hook_server_name , self._root_configuration.rstrip( os.sep ) + \ os.sep + \ server + \ os.sep + \ port + \ os.sep + \ hook_server_name ) , sorted( self._l_hook_server_filenames ) ) if ( True if os.path.isfile( hook_server_filepath ) else ( l_bad_configurations.append( ( '%s is present but is not a file' % ( hook_server_name, ), self._root_configuration, server, port ) ) if os.path.exists( hook_server_filepath ) else False ) ) ] ) ) if \ reload_without_version_control \ or \ self.get_version_configurations( d_configurations ) <> self.current_version_configurations \ or \ hashlib.sha1( repr( l_bad_configurations ) ).hexdigest() <> hashlib.sha1( repr( self._l_bad_configurations ) ).hexdigest(): self._d_configurations = d_configurations self._l_bad_configurations = l_bad_configurations shared_infrastructure.cache_container_hook_server_configuration.clear() shared_infrastructure.cache_container_nginx_fs.clear() return True return False
def __init__( self, agnostic_configuration, root_nginx_configuration, uid_owner, gid_owner, resolver_conf, mount_filename, unmount_filename, redirect_filename, error_status_filename, restart_nginx, ssl_configuration, url2entity_configuration, url2entity_filename, hook_server_configuration, ): self._agnostic_configuration = agnostic_configuration self._root_nginx_configuration = root_nginx_configuration self._uid_owner = uid_owner self._gid_owner = gid_owner self._resolver_conf = resolver_conf self._resolver = dns.resolver.Resolver( self._resolver_conf ) self._resolver.query = shared_infrastructure.catch_NoNamesservers( self._resolver.query ) self._mount_filename = mount_filename self._unmount_filename = unmount_filename self._redirect_filename = redirect_filename self._error_status_filename = error_status_filename self._restart_nginx = restart_nginx self._ssl_configuration = ssl_configuration self._url2entity_configuration = url2entity_configuration self._url2entity_filename = url2entity_filename self._hook_server_configuration = hook_server_configuration self._extra_from_distrib = \ extra_from_distrib.ExtraFromDistrib( self._restart_nginx ) self._extra_from_distrib.register_cache_to_clear( shared_infrastructure.cache_container_nginx_fs ) self._l_bad_configurations = [] self._l_configurations = \ ( \ self._agnostic_configuration, \ self._url2entity_configuration, \ self._hook_server_configuration, \ ) self._pattern_converted_conf_filenames = \ '^(?P<server>.*)-(?P<port>\d+)\.conf$' self._pattern_converted_map_filenames = \ '^(?P<mapping_type>' + \ '%s|%s|%s|%s' % ( self._mount_filename, self._unmount_filename, self._redirect_filename, self._url2entity_filename, ) + ')-(?P<server>.*)-(?P<port>\d+)\.map$' # Getion des templates de read # Creation de l'nevironement des templates self._env = \ Environment( loader = \ ChoiceLoader( [ PackageLoader( __name__, 'templates' ) , self._hook_server_configuration ] ) ) # Gestion des interactions cross mapping # Les tableaux configuration vers virtuel permettent de calculer # les dependances engendrer par les modificatinos dans les configurations self._d_id_server_configuration_2_virtual = {} self._d_id_port_configuration_2_virtual = {} self._d_id_mapping_type_configuration_2_virtual = { self._mount_filename: [ self._mount_filename, self._redirect_filename ], self._redirect_filename: [ self._redirect_filename, self._mount_filename ], self._unmount_filename: [ self._unmount_filename, self._mount_filename ], self._url2entity_filename: [ self._url2entity_filename, ], } # la gestion cross mapping dnas le sens virtuel a configuration # est plus compliquee # Au premier niveau, elle est contextualisee # NGINXConfigurationFS.__ATTR_CTX__ pour le cross mapping # concernant l'obtention des attributs de fichiers (getattr) # NGINXConfigurationFS.__READ_CTX__ pour le crosss mapping # concernant la lecture (read) # Elle est ensuite categorisee par id (server, port, mapping_ype). # Puis les cross mappings eux-memes sont exprimes self._d_id_virtual_2_configuration = { NGINXConfigurationFS.__ATTR_CTX__: \ { NGINXConfigurationFS.__ID_SERVER__: \ { }, NGINXConfigurationFS.__ID_PORT__: \ { }, NGINXConfigurationFS.__ID_MAPPING_TYPE__: \ { self._mount_filename: \ [ self._mount_filename, self._redirect_filename, self._unmount_filename, ], self._redirect_filename: \ [ self._redirect_filename, self._mount_filename ], self._unmount_filename: \ [ self._unmount_filename ], self._url2entity_filename: \ [ self._url2entity_filename ], }, }, NGINXConfigurationFS.__READ_CTX__: \ { NGINXConfigurationFS.__ID_SERVER__: \ { }, NGINXConfigurationFS.__ID_PORT__: \ { }, NGINXConfigurationFS.__ID_MAPPING_TYPE__: \ { self._mount_filename: \ [ self._mount_filename ], self._redirect_filename: \ [ self._redirect_filename ], self._unmount_filename: \ [ self._unmount_filename ], self._url2entity_filename: \ [ self._url2entity_filename ], }, }, } wm = pyinotify.WatchManager() mask = pyinotify.IN_MODIFY # Gestion du repertoire des templates def get_template_dir( template_name ): try: return \ self._env.get_template( template_name ).filename[ :-len( template_name ) ] except: return None def add_templates_watches(): wm.add_watch( list( set( filter( None, map( get_template_dir, self.list_template_names ) ) ) ), mask, rec=True, auto_add=True ) class TemplateEventHandler( pyinotify.ProcessEvent ): def process_evt( o, event ): if not event.dir and \ not event.pathname[ event.pathname.rfind( os.sep + 'templates' + os.sep ) + len( os.sep + 'templates' + os.sep ): ] in self.list_template_names: return None self._l_bad_configurations = [] self._env.cache.clear() shared_infrastructure.cache_container_nginx_fs.clear() try: subprocess.call( self._restart_nginx, shell = True ) except: self.l_bad_configurations.append( ( '%s error' % ( self._restart_nginx ), ) ) shared_infrastructure.cache_container_agnostic_configuration.clear() shared_infrastructure.cache_container_ssl_configuration.clear() shared_infrastructure.cache_container_url2entity_configuration.clear() shared_infrastructure.cache_container_nginx_fs.clear() process_IN_MODIFY = process_evt self._template_notifier = pyinotify.ThreadedNotifier( wm, TemplateEventHandler() ) self._extra_from_distrib.register_notifier( self._template_notifier ) self._template_notifier.coalesce_events() add_templates_watches() self._template_notifier.start() for configuration in self._l_configurations: configuration.notifier.start() self._ssl_configuration.notifier.start()
def load_configurations( self, reload_without_version_control = False ): d_configurations = {} l_bad_configurations = [] # Obtention d'un resolveur base sur le resolv_conf fouri self._resolver = dns.resolver.Resolver( self._resolver_conf ) self._resolver.query = shared_infrastructure.catch_NoNamesservers( self._resolver.query ) # Recherche des serveurs for server in [ s for s in os.listdir( self._root_configuration ) if os.path.isdir( self._root_configuration.rstrip( os.sep ) + os.sep + s ) ]: # Si le nom ne correspond pas a un nom resolvable # la configuration n'est pas prise en compte if not self._resolver.query( server, 'A' ) and not self._resolver.query( server, 'AAAA' ): l_bad_configurations.append( ( '%s not resolvable' % ( server ), self._root_configuration, server, ) ) continue # Si le repertoire ne contient pas de configuration # de port, la configuration n'est pas prise en compte try: if not os.listdir( self._root_configuration.rstrip( os.sep ) + os.sep + server ): l_bad_configurations.append( ( '%s no port definition' % ( server ), self._root_configuration, server, ) ) continue except: # En cas de suppression de la racine # entre le listdir dans la boucle # et l'usage du server dans la cronstrcuion # de chemin, le repertoire server # peut avoir disparu. continue # Recherche des ports for port in os.listdir( self._root_configuration.rstrip( os.sep ) + os.sep + server ): # Si le repertoire ne correspond pas au format d'un nom de port # la configuration n'est pas prise en compte try: if not( re.match( '\d{1,5}', port ) and int( port ) <= 65535 ): raise Exception() except: l_bad_configurations.append( ( '%s unvalid port format' % ( port ), self._root_configuration, server, port ) ) continue # Si aucun fichier de mapping # n'est present, la configuration n'est # pas prise en compte mount_filepath = \ self._root_configuration.rstrip( os.sep ) + os.sep + \ server + os.sep + \ port + os.sep + \ self._mount_filename unmount_filepath = \ self._root_configuration.rstrip( os.sep ) + os.sep + \ server + os.sep + \ port + os.sep + \ self._unmount_filename redirect_filepath = \ self._root_configuration.rstrip( os.sep ) + os.sep + \ server + os.sep + \ port + os.sep + \ self._redirect_filename def add_to_configuration( mapping_type, filepath, pattern, ): try: with closing( open( filepath ) ) as f: for line in [ l.rstrip() for l in f.readlines() ]: if re.match( AgnosticConfiguration._comment_pattern, line ): continue m = re.match( pattern, line ) if not m: l_bad_configurations.append( ( 'invalid format %s' % ( line ), self._root_configuration, server, port, mapping_type ) ) continue try: self._d_l_process_uri[ mapping_type ]( self, m.groupdict(), filepath, line, server, port, mapping_type, d_configurations, l_bad_configurations, ) except: import traceback traceback.print_exc() continue except: pass try: if \ not os.path.isfile( mount_filepath ) and \ not os.path.isfile( unmount_filepath ) and \ not os.path.isfile( redirect_filepath ): l_bad_configurations.append( ( 'no %s or %s or %s file' % \ ( self._mount_filename, self._unmount_filename, self._redirect_filename ), self._root_configuration, server, port ) ) continue except: # En cas de suppression de la racine # entre le listdir dans la boucle # et l'usage du server dans la cronstrcuion # de chemin, le repertoire server # peut avoir disparu. continue add_to_configuration( self._mount_filename, mount_filepath, AgnosticConfiguration._mount_pattern, ) add_to_configuration( self._unmount_filename, unmount_filepath, AgnosticConfiguration._unmount_pattern, ) add_to_configuration( self._redirect_filename, redirect_filepath, AgnosticConfiguration._redirect_pattern, ) if len( d_configurations ) == 0: l_bad_configurations.append( ( 'no configuration available', self._root_configuration, ) ) if \ reload_without_version_control \ or \ self.get_version_configurations( d_configurations ) <> self.current_version_configurations \ or \ hashlib.sha1( repr( l_bad_configurations ) ).hexdigest() <> hashlib.sha1( repr( self._l_bad_configurations ) ).hexdigest(): self._d_configurations = d_configurations self._l_bad_configurations = l_bad_configurations shared_infrastructure.cache_container_agnostic_configuration.clear() shared_infrastructure.cache_container_nginx_fs.clear() #pprint.pprint( self._d_configurations ) return True return False
def load_configurations( self, reload_without_version_control = False ): d_configurations = {} l_bad_configurations = [] # Obtention d'un resolveur base sur le resolv_conf fouri self._resolver = dns.resolver.Resolver( self._resolver_conf ) self._resolver.query = shared_infrastructure.catch_NoNamesservers( self._resolver.query ) # Recherche des serveurs for server in [ s for s in os.listdir( self._root_ssl_configuration ) if os.path.isdir( self._root_ssl_configuration.rstrip( os.sep ) + os.sep + s ) ]: # Si le nom ne correspond pas a un nom resolvable # la configuration n'est pas prise en compte if not self._resolver.query( server, 'A' ) and not self._resolver.query( server, 'AAAA' ): l_bad_configurations.append( ( '%s not resolvable' % ( server ), self._root_ssl_configuration, server, ) ) continue try: if not os.listdir( self._root_ssl_configuration.rstrip( os.sep ) + os.sep + server ): l_bad_configurations.append( ( '%s no port definition' % ( server ), self._root_ssl_configuration, server, ) ) continue except: # En cas de suppression de la racine # entre le listdir dans la boucle # et l'usage du server dans la cronstrcuion # de chemin, le repertoire server # peut avoir disparu. continue # Recherche des ports for port in os.listdir( self._root_ssl_configuration.rstrip( os.sep ) + os.sep + server ): # Si le repertoire ne correspond pas au format d'un nom de port # la configuration n'est pas prise en compte try: if not( re.match( '\d{1,5}', port ) and int( port ) <= 65535 ): raise Exception() except: l_bad_configurations.append( ( '%s unvalid port format' % ( port ), self._root_ssl_configuration, server, port ) ) continue # Les 3 fichiers de configuration doivent etre present # n'est present, la configuration n'est # pas prise en compte ssl_certificate_filepath = \ self._root_ssl_configuration.rstrip( os.sep ) + os.sep + \ server + os.sep + \ port + os.sep + \ self._ssl_certificate_filename ssl_certificate_key_filepath = \ self._root_ssl_configuration.rstrip( os.sep ) + os.sep + \ server + os.sep + \ port + os.sep + \ self._ssl_certificate_key_filename try: if \ not ( \ os.path.isfile( ssl_certificate_filepath ) and \ os.path.isfile( ssl_certificate_key_filepath ) ): l_bad_configurations.append( ( '%s AND %s must be present' % \ ( self._ssl_certificate_filename, self._ssl_certificate_key_filename, ), self._root_ssl_configuration, server, port ) ) continue except: # En cas de suppression de la racine # entre le listdir dans la boucle # et l'usage du server dans la cronstrcuion # de chemin, le repertoire server # peut avoir disparu. continue st_certificate_key_filepath = os.stat( ssl_certificate_key_filepath ) if \ bool( st_certificate_key_filepath.st_mode & stat.S_IROTH ) or \ bool( st_certificate_key_filepath.st_mode & stat.S_IWOTH ) or \ bool( st_certificate_key_filepath.st_mode & stat.S_IXOTH ) or \ not bool( st_certificate_key_filepath.st_mode & stat.S_IRGRP ) \ : l_bad_configurations.append( ( '%s must be -r--r-----' % \ ( self._ssl_certificate_key_filename, ), self._root_ssl_configuration, server, port ) ) continue digest_ssl_certificate = None digest_ssl_certificate_key = None try: with closing( open( ssl_certificate_filepath ) ) as ssl_certificates: digest_ssl_certificate = \ load_certificate( FILETYPE_PEM, ssl_certificates.read() ).digest( 'sha1' ) except Exception, e: l_bad_configurations.append( ( 'ssl problem with %s (%s)' % \ ( self._ssl_certificate_filename, repr( e ) ), self._root_ssl_configuration, server, port ) ) continue try: with closing( open( ssl_certificate_key_filepath ) ) as ssl_certificate_key: digest_ssl_certificate_key = \ hashlib.sha1( dump_privatekey( FILETYPE_PEM, load_privatekey( FILETYPE_PEM, ssl_certificate_key.read() ) ) ).hexdigest() except Exception, e: l_bad_configurations.append( ( 'problem with %s (%s)' % \ ( self._ssl_certificate_key_filename, repr( e ) ), self._root_ssl_configuration, server, port ) ) continue d_configurations.setdefault( server, {} ).setdefault( port, { 'ssl_certificate_digest' : digest_ssl_certificate, 'ssl_certificate_key_digest' : digest_ssl_certificate_key, 'ssl_certificate_filepath' : ssl_certificate_filepath, 'ssl_certificate_key_filepath' : ssl_certificate_key_filepath, } )