|
#!/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)
|