Enfoque para analizar archivos y crear una estructura de datos dinámica para que la use otro progtwig

Todos,

Antecedentes: tengo un cliente que tiene algunos scripts de comstackción para su centro de datos basados ​​en Python que he heredado. No trabajé en el diseño original, así que estoy limitado en cierta medida a lo que puedo y no puedo cambiar. Dicho esto, mi cliente tiene un archivo de propiedades que utiliza en su centro de datos. Algunos de los valores se usan para construir sus servidores y, lamentablemente, tienen otras aplicaciones que también usan estos valores, por lo que no puedo cambiarlos para que sea más fácil para mí.

Lo que quiero hacer es hacer que los scripts sean más dynamics para distribuir más hosts, de modo que no tenga que seguir actualizando los scripts en el futuro y solo pueda agregar más hosts al archivo de propiedades. Desafortunadamente no puedo cambiar el archivo de propiedades actual y tengo que trabajar con él.

El archivo de propiedades se ve algo como esto:

projectName.ClusterNameServer1.sslport=443 projectName.ClusterNameServer1.port=80 projectName.ClusterNameServer1.host=myHostA projectName.ClusterNameServer2.sslport=443 projectName.ClusterNameServer2.port=80 projectName.ClusterNameServer2.host=myHostB 

Básicamente, en sus scripts de implementación tienen una gran cantidad de if projectName.ClusterNameServerX donde X es un número de entradas definido y luego do something , por ejemplo:

 if projectName.ClusterNameServer1.host != "" do X if projectName.ClusterNameServer2.host != "" do X if projectName.ClusterNameServer3.host != "" do X 

Luego, cuando agregan otro host (por ejemplo, Serve4), han agregado otra sentencia if.

Pregunta: Lo que me gustaría hacer es hacer que los scripts sean más dynamics y analizar el archivo de propiedades y poner lo que necesito en alguna estructura de datos para pasar a los scripts de implementación y luego iterar sobre la estructura y hacer mi implementación de esa manera para no hacerlo. No tengo que agregar constantemente un montón de si algún host # hace algo. Solo tengo curiosidad por aportar algunas sugerencias sobre lo que otros harían para analizar el archivo y qué tipo de estructura de datos usarían y cómo agruparían las cosas por ClusterNameServer # o algo más.

Gracias

  1. Cree una base de datos sqlite para representar los datos en el archivo de propiedades.

  2. Escriba un script para volcar los datos del archivo de propiedades en la base de datos sqlite.

  3. Escriba un script que pueda regenerar el archivo de propiedades basándose en los datos de la base de datos sqlite. Ahora se pueden agregar nuevos hosts insertando filas en la base de datos sqlite. Cada vez que se realiza una actualización o inserción, ejecute este script para mantener los scripts antiguos a la altura, hasta que se complete el paso 5.

  4. Haga que todos los scripts nuevos interactúen con la base de datos sqlite en lugar del archivo de propiedades.

  5. Reescriba los scripts antiguos para usar la base de datos sqlite. Por ejemplo, repasar los resultados de las consultas de SQL en lugar de agregar más declaraciones if .

Dado que los nombres de sus propiedades tienen alguna estructura interna, puede intentar usar el uso de pyparsing para procesar su archivo de propiedades:

 from pyparsing import Word, alphas, alphanums, delimitedList, restOfLine props = """ projectName.ClusterNameServer1.sslport=443 projectName.ClusterNameServer1.port=80 projectName.ClusterNameServer1.host=myHostA projectName.ClusterNameServer2.sslport=443 projectName.ClusterNameServer2.port=80 projectName.ClusterNameServer2.host=myHostB """ # define format of a single property definition line ident = Word(alphas, alphanums+'_') propertyName = delimitedList(ident,'.') propertyDefn = propertyName("name") + '=' + restOfLine("value") # sample code that parses the properties and accesses the # name and value fields for prop in propertyDefn.searchString(props): print '.'.join(prop.name), '->', prop.value 

Huellas dactilares:

 projectName.ClusterNameServer1.sslport -> 443 projectName.ClusterNameServer1.port -> 80 projectName.ClusterNameServer1.host -> myHostA projectName.ClusterNameServer2.sslport -> 443 projectName.ClusterNameServer2.port -> 80 projectName.ClusterNameServer2.host -> myHostB 

Si puede confiar en la estructura del proyecto-servidor-parámetro de las propiedades, puede construir un objeto jerárquico usando defaultdicts (desde el módulo de colecciones):

 # use defaultdicts to accumulate these values into a nested structure from collections import defaultdict properties = defaultdict(lambda:defaultdict(dict)) # build hierarchical property structure # (assumes very rigid project-server-parameter naming) for prop in propertyDefn.searchString(props): properties[prop.name[0]][prop.name[1]][prop.name[2]] = prop.value # show data in nice outline form for project in properties: print '-', project for cluster in properties[project]: print ' -', cluster for param in properties[project][cluster]: print ' -', param, properties[project][cluster][param] 

Huellas dactilares:

 - projectName - ClusterNameServer1 - host myHostA - sslport 443 - port 80 - ClusterNameServer2 - host myHostB - sslport 443 - port 80 

La ejecución del siguiente código crea un diccionario cuyas claves son el número del servidor y los valores son (sslport, port, host)

 import re RE = ('projectName.ClusterNameServer(\d+)\.sslport=(\d+)\s+' 'projectName.ClusterNameServer\\1\.port=(\d+)\s+' 'projectName.ClusterNameServer\\1\.host=(\S+)(?:\s+|\Z)') propertyfile_name = 'servers.txt' with open(propertyfile_name) as f: dico = dict( (server,(s,p,h)) for (server,s,p,h) in re.findall(RE,f.read()) ) print dico 

resultado

 dico== {'1': ('443', '80', 'myHostA'), '2': ('443', '80', 'myHostB')} 

Luego, los datos de dico se pueden pasar ” a los scripts de implementación “; No sé cuáles son tus posibilidades para pasar estos datos. Se puede hacer como un archivo plano, o, mejor, un archivo pickle.

La solución más simple sería incluir las líneas del código anterior directamente en los “scripts de implementación” para que tengan los datos sin la necesidad de recibirlos desde el exterior.

. EDITAR

Otra solución, que encuentro mejor:

 import csv from itertools import ifilter propertyfile_name = 'servers.txt' with open(propertyfile_name,'rb') as f: dico = dict( ifilter(None,csv.reader(f,delimiter='=')) ) print dico 

La función ifilter() es necesaria debido a las líneas en blanco en el archivo.

resultado

{‘projectName.ClusterNameServer2.host’: ‘myHostB’, ‘projectName.ClusterNameServer2.port’: ’80’, ‘projectName.ClusterNameServer1.host’: ‘myHostA’, ‘projectName.ClusterNameServer1.port’: ’80’, ‘ projectName.ClusterNameServer2.sslport ‘:’ 443 ‘,’ projectName.ClusterNameServer1.sslport ‘:’ 443 ‘}

.

EDITAR

 RE = ('(projectName.ClusterNameServer\d+\.(?:sslport|port|host))=(\S+)(?:\s+|\Z)') propertyfile_name = 'servers.txt' with open(propertyfile_name) as f: dico = dict( re.findall(RE,f.read()) ) print dico 

Mismo resultado

Si quieres resultado

 dico== {'1': ('443', '80', 'myHostA'), '2': ('443', '80', 'myHostB')} 

Lo hare mañana