Proyecto

General

Perfil

#!/usr/bin/python -tt
# -*- coding: utf-8 -*-

""" Programa para generar los archivos necesarios para permitir
que los portátiles de los alumnos puedan unirse al punto de acceso
hostapd del profesor, según el horario del propio profesor, y los
alumnos que tienen clase con él a esa hora.

Partiremos de los archivos de datos generados por Rayuela, el formato
de estos archivos es: por cada centro hay un directorio con cinco archivos
uno por cada día de la semana, llamados Lunes.txt, Martes.txt, Miercoles.txt,
Jueves.txt y Viernes.txt. Cada uno de estos archivos de texto contienen
la siguiente información:

D.N.I. del docente|N.I.A. del alumno|Hora de inicio|Hora de fin
08848648L|3251023|815|870|
08848648L|3383767|815|870|
08848648L|3383770|815|870|

la primera línea indica la estructura y a partir de ésta están los datos
que son: dni del profesor, nie del alumno y horas de inicio y fin expresadas
como minutos transcurridos desde las 00:00 horas.

Los ficheros que se generan, deben copiarse al directorio de destino
especificado como parámetro, y que en caso de no darse será por defecto
"/var/www/wifi/(lunes.txt|martex.txt|miercoles.txt|jueves.txt|viernes.txt)"
si la ruta no existe, ésta se creará. Para escribir en el destino debemos
tener los privilegios adecuados.

Los archivos que generaremos, tendrán el mismo nombre, sin mayúsculas, pero
el formato será el siguiente:

login_profesor|mac_alumno|inicio|fin|

no tenemos línea descriptora de estructura, y los datos se obtienen de
realizar consulta al directorio ldap del centro, para lo cual es necesario
que tengamos instalado el paquete python-ldap, además de python, claro está.
El dato de login_profesor es directo en la consulta a ldap, así como la
generación de las horas y minutos, pero el dato de mac_alumno, se realiza
consultando ldap para obtener el login del alumno, que concuerda con el
nombre del portátil asignado al alumno. A partir de este dato accederemos
a la información recogida por puppet de cada ordenador, que se encuentra
en /var/lib/puppet/yaml/node/(login_del_alumno.dominiodelcentro).yaml,
para obtener la mac de la interfaz wifi asociada a ese portátil. Las
líneas importantes son: macaddress_wlan0 o macaddress_eth1 que se
establece en algunos modelos de portátiles.

Uso: crearemos una carpeta donde copiaremos este programa y además
pondremos los txts obtenidos por Rayuela, ejecutaremos el script pasando
como parámetros el lugar donde están los archivos con el parámetro
--datosrayuela rutarayuela, y tambien el lugar donde queremos depositar los
archivos generados, con el parámetros --datosservidor rutaservidor.
Si --datosrayuela no se establece, asumiremos el directorio actual, si
--datosservidor no está establecido, se establecerá internamente en
/var/www/wifi, creando la estructura de directorios mencionada si es que
no existe, además comprobaremos que disponemos de privilegios para escribir
en el directorio de destino.

Francisco Mora Sánchez
IES Maestro Juan Calero
adminies.maestrojuancalero@edu.juntaextremadura.net


"""

import sys,os,ldap,time,errno,re
import ldap

# Expresiones Regulares.
_re_mode = (re.I | re.M | re.S)
macwlan0_pattern = re.compile('.*macaddress_wlan0: (.*?)\n', _re_mode)
maceth1_pattern = re.compile('.*macaddress_eth1: (.*?)\n', _re_mode)

def EjecutaRegex(regex, cadena):
""" ejecuta búsqueda de expresión regular en una cadena """
m = regex.search(cadena)
if m:
return m.groups()[0]
else:
return None

def lee_parametros(lista,params):
"""Funcion que crea un diccionario para leer el valor de los
parametros que se pasan en la linea de comandos."""
for i in range(1,len(lista)):
if lista[i][:2] == "--":
#veamos si tiene valor
if i+1 < len(lista) and lista[i+1] <> "--":
#estamos en un parametro y valor
params[lista[i][2:]] = lista[i+1]

def dameDatosLineaRayuela(linea):
"""Funcion que trocea la linea de datos de rayuela y
devuelve un diccionario cuyas claves son login_profesor
login_alumno, inicio y final
"""
datos = linea.split("|")
return { "dni_profesor" : datos[0], "nie_alumno" : datos[1], "inicio" : datos[2], "final" : datos[3]}

def consultaLdap(identificador):
"""Función que consulta el servidor ldap, con el atributo
employeeNumber. Devuelve el login asociado al profesor o al alumno
"""
try:
l = ldap.open("ldap")
except ldap.LDAPError, e:
print e
return "ERRORLDAP"
base_dn='ou=People,dc=instituto,dc=extremadura,dc=es'
searchFilter = '(employeeNumber='+identificador+')'
searchScope = ldap.SCOPE_SUBTREE
retrieveAttributes = ['uid']
try:
ldap_result_id = l.search(base_dn, searchScope, searchFilter, retrieveAttributes)
result_type, result_data = l.result(ldap_result_id, 0)
if len(result_data)==0:
#print "la búsqueda no da ningún resultado"
return "NO ENCONTRADO"
elif len(result_data)>1:
#print "La búsqueda da más de un resultado"
resultado= result_data[0]
else:
resultado=result_data[0]
#print resultado[1]['uid'][0]
except ldap.LDAPError, e:
print e
print "ERRORLDAP"

return resultado[1]['uid'][0]

def obtenerMac(login_alumno, archivosYaml, datosyaml):
"""Función que dado un login de alumno, buscará en el archivo yaml
de puppet asociado a ese login de alumno, la cadena macaddress_wlan0,
o bien macaddress_eth1 en caso que no exista la primera. Esta función
quizá se deba testear bien.
Tenemos disponible la lista archivosYaml con todos los archivos yaml
de puppet, incluyendo sus rutas...
"""
#Primero buscamos el archivo en cuestion, tendrá el login_alumno mas
#un punto, dominio, punto y terminación yaml, busquemos el patrón con dos puntos
#ya que suele haber archivos fantasmas con el nombre solamente.
for a in archivosYaml:
if a.count(".") == 2:
#Estamos en un patrón de archivo correcto.
pos = a.find(".")
sufijo = a[pos:]
break
archivoDatosYaml = login_alumno + sufijo
try:
filearchivoDatosYaml = open(os.path.join(datosyaml,archivoDatosYaml), "r")
except:
pass
return "NO:EN:CO:NT:RA:DA"
contenidoyaml = filearchivoDatosYaml.read()
filearchivoDatosYaml.close()
#print contenidoyaml
mac = EjecutaRegex(macwlan0_pattern, contenidoyaml)
if mac == None:
mac = EjecutaRegex(maceth1_pattern, contenidoyaml)
#print mac
if mac == None:
mac = "NO:EN:CO:NT:RA:DA"
return mac
def transformaHora(datohora):
"""Función que pasado un parámetro numérico que almacena los minutos
desde las 00:00.
Devuelve una cadena en la forma "08:35", con la hora y los minutos.
"""
hora = datohora // 60
minutos = datohora % 60
return "%02d%02d" % (hora,minutos)
def transformaArchivos(datosrayuela, datosservidor, datosyaml, debug = False):
#Comprobemos la existencia del directorio de datos de Rayuela
if not os.path.exists(datosrayuela):
if debug:
print "Directorio para datos de rayuela",datosrayuela,"no existe, abortando ejecución..."
return 1

#Comprobemos que sea un directorio
if not os.path.isdir(datosrayuela):
if debug:
print "Directorio para datos de rayuela",datosrayuela,"no es un directorio, abortando ejecución..."
return 2
#Comprobemos que tengamos permisos de apertura y lectura de archivos
if os.path.isdir(datosrayuela):
try:
archivosRayuela = os.listdir(datosrayuela)
except:
if debug:
print "Directorio para datos de rayuela",datosrayuela,"problemas de permisos en carpeta, abortando ejecución..."
return 3

#Comprobemos que existe el directorio de destino
if not os.path.exists(datosservidor):
#No existe directorio de destino, debemos crearlo
if debug:
print "No existe directorio de destino en servidor",datosservidor,"se intentará crear directorio..."
try:
os.makedirs(datosservidor)
except OSError:
if debug:
print "Hay algún problema con la creación del directorio de destino, abortando ejecución..."
return 4
#Comprobemos que tenemos permisos de escritura
if os.path.exists(datosservidor):
if not os.access(datosservidor, os.W_OK):
if debug:
print "Hay algún problema de permisos para la creación de archivos en el directorio de destino del servidor, abortando ejecución..."
return 5

#Comprobemos la existencia del directorio de datos yaml de puppet
if not os.path.exists(datosyaml):
if debug:
print "Directorio para datos yaml de puppet",datosyaml,"no existe, abortando ejecución..."
return 6

#Comprobemos que sea un directorio
if not os.path.isdir(datosyaml):
if debug:
print "Directorio para datos yaml de puppet",datosyaml,"no es un directorio, abortando ejecución..."
return 7
#Comprobemos que tengamos permisos de apertura y lectura de archivos
if os.path.isdir(datosyaml):
try:
#archivosYaml = glob.glob(os.path.join(params["datosyaml"],"*.*.yaml"))
archivosYaml = os.listdir(datosyaml)
except:
if debug:
print "Directorio para datos yaml de puppet",datosyaml,"problemas de permisos en directorio, abortando ejecución..."
return 8
#Limpiemos las listas de archivos
archivosRayuela = [ archivo for archivo in archivosRayuela if archivo in ["Lunes.txt","Martes.txt","Miercoles.txt","Jueves.txt","Viernes.txt"]]
archivosYaml = [ archivo for archivo in archivosYaml if archivo[-5:] == ".yaml"]
#print archivosRayuela
#print archivosYaml
#Para evitar consultar al servidor ldap varias veces para un mismo dni o nie crearemos
#dos diccionarios, uno para profesores y otro para alumnos con los datos que
#recuperaremos del servidor ldap, además otro con los logins de alumnos y
#las macs
#profesores = { "dni" : "login_profesor", ... }
#alumnos = { "nie" : "login_alumno", ... }
#macs = { "login_alumno" : "mac", ... }
profesores = {}
alumnos = {}
macs = {}
#Procesemos cada archivo de Rayuela
for archivoRayuela in archivosRayuela:
if debug:
print "Procesando archivo",os.path.join(datosrayuela,archivoRayuela)
filearchivoRayuela = open(os.path.join(datosrayuela,archivoRayuela), 'r')
archivoServidor = os.path.join(datosservidor,archivoRayuela.lower())
if debug:
print "Generando archivo",archivoServidor
filearchivoServidor = open(archivoServidor, 'w')
while True:
linea = filearchivoRayuela.readline()
if not linea:
break
if linea[:6] == "D.N.I.":
continue
#Procesemos cada linea de Rayuela
#datosLineaRayuela es un diccionario cuyas claves son dni_profesor, nie_alumno, inicio, final
datosLineaRayuela = dameDatosLineaRayuela(linea)
datosLineaServidor = ""
#Consultemos el login del profesor en ldap por su dni y el nie del alumno
#comprobando que no lo hemos encontrado previamente
if profesores.has_key(datosLineaRayuela["dni_profesor"]):
login_profesor = profesores[datosLineaRayuela["dni_profesor"]]
#if debug:
# print "Nooooo se consulta a ldap, profesor dni",datosLineaRayuela["dni_profesor"],"pertenece a",login_profesor
else:
login_profesor = consultaLdap(datosLineaRayuela["dni_profesor"])
profesores[datosLineaRayuela["dni_profesor"]] = login_profesor
if debug:
print "Se consulta a ldap, profesor dni",datosLineaRayuela["dni_profesor"],"pertenece a",login_profesor
if alumnos.has_key(datosLineaRayuela["nie_alumno"]):
login_alumno = alumnos[datosLineaRayuela["nie_alumno"]]
#if debug:
# print "Nooooo se consulta a ldap, alumno nie",datosLineaRayuela["nie_alumno"],"pertenece a",login_alumno
else:
login_alumno = consultaLdap(datosLineaRayuela["nie_alumno"])
alumnos[datosLineaRayuela["nie_alumno"]] = login_alumno
if debug:
print "Se consulta a ldap, alumno nie",datosLineaRayuela["nie_alumno"],"pertenece a",login_alumno

if macs.has_key(login_alumno):
mac_alumno = macs[login_alumno]
#if debug:
# print "Nooooo se consultan datos yaml, alumno login",login_alumno,"tiene mac",mac_alumno
else:
mac_alumno = obtenerMac(login_alumno, archivosYaml, datosyaml)
#mac_alumno = obtenerMac("dmoral01", archivosYaml, datosyaml)
macs[login_alumno] = mac_alumno
if debug:
print "Se consultan datos yaml, alumno login",login_alumno,"tiene mac",mac_alumno
inicio = transformaHora(int(datosLineaRayuela["inicio"]))
final = transformaHora(int(datosLineaRayuela["final"]))
datosLineaServidor = login_profesor+"|"+mac_alumno+"|"+str(inicio)+"|"+str(final)+"|"+"\n"
#datosLineaServidor = login_profesor+"|"+mac_alumno+"|"+datosLineaRayuela["inicio"]+"|"+datosLineaRayuela["final"]+"|"+"\n"
if debug:
print datosLineaServidor
filearchivoServidor.write(datosLineaServidor)
filearchivoRayuela.close()
filearchivoServidor.close()
return 0

if __name__ == '__main__':
params = {}
lista = sys.argv
lee_parametros(lista,params)
#comprobaremos las combinaciones de parametros en linea de comandos
if len(lista) == 2 and lista[1] == "--help":
print 'uso: ./transformaArchivos.py [--datosrayuela rutadatosrayuela] [--datosservidor rutadatosservidor] [--datosyaml rutadatosyaml]'
sys.exit(1)
if not params.has_key("datosrayuela"):
print "No se ha establecido la ruta a la carpeta con los datos de rayuela, usando por defecto '"+os.getcwd()+"'"
params["datosrayuela"] = os.getcwd()
if not params.has_key("datosservidor"):
print "No se ha establecido la ruta dónde depositar los archivos generados, usando por defecto '/var/www/wifi'"
params["datosservidor"] = "/var/www/wifi"
if not params.has_key("datosyaml"):
print "No se ha establecido la ruta dónde se encuentran los datos yaml de puppet, usando por defecto '/var/lib/puppet/yaml/node'"
params["datosyaml"] = "/var/lib/puppet/yaml/node"

print
print "Los valores pasado son los siguientes:"
print "Directorio de datos de Rayuela:",params["datosrayuela"]
print "Directorio de datos de para el servidor:",params["datosservidor"]
print "Directorio de datos yaml de puppet:",params["datosyaml"]

resultado = transformaArchivos(params["datosrayuela"], params["datosservidor"], params["datosyaml"], True)
if resultado > 0:
print "Se ha producido errores en el procesamiento, código de error",resultado
else:
print "Se ha ejecutado correctamente"
exit(resultado)
    (1-1/1)