Ultra Tesla: Crear redes distribuidas de servicios, fácil, rápido y seguro

Iniciado por DtxdF, Junio 15, 2020, 04:49:38 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Ultra Tesla es un proyecto de código abierto para crear redes distribuidas de servicios fácil, rápido y seguro, usando el poder de computo de múltiples ordenadores. El proyecto permite unificar los distintos servidores en una única interfaz que es proporcionada para el mismo usuario creando una sensación de transparencia.


Mi primer "Hello World":

Ultra Tesla utiliza servicios, que son básicamente mini-programas que se adhieren a la ejecución del servidor, siguiendo una sintaxis en HTTP como la siguiente: <scheme>://<netloc>/<Service>/<Sub-Service>/<...>

Donde <scheme> es 'http' o 'https' según la configuración del servidor; <netloc> es básicamente la dirección del servidor; <Service> es el nombre del servicio, que para este ejemplo será "hello_world" y los demás que son <Sub-Service> y <...> son básicamente otros mini-programas que se tendrán que usar anteponiendo el nombre del servicio anterior, por ejemplo, <Service>/<Sub-Service>/<Sub-Service 1>/<Sub-Service 2>/<...> y así según lo que el administrador haya propuesto.


Código: python
class Handler:
    async def get(self):
    await self.write('Hello World!')


Un ejemplo real con el servicio nombrado como complements/hello_world.py en una URL se vería como lo siguiente (suponiendo que la dirección del servidor sea localhost): No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Contactando al servidor:

Lo siguiente es un script simple para poder contactarse con el servidor y obtener la salida del servicio 'hello_world'

Código: python
import asyncio

from modules.Infrastructure import client

async def main():
    UTeslaClient = client.UTeslaClient('<Nombre de usuario>')
    await UTeslaClient.set_server_key('<Clave pública del servidor>')
    await UTeslaClient.set_user_keys('<Clave pública del usuario>', '<Clave privada del usuario>')

    cmd = {
        'token' : '<Token de acceso>'

    }

    Response = await UTeslaClient.fetch(
        'http://localhost:17000/hello_world',
        cmd,
        method='GET'

    )

    dec_body = UTeslaClient.get_message(Response.body)

    print(dec_body)

if __name__ == '__main__':
    asyncio.run(main())


Deberíamos obtener la siguiente respuesta:

Código: text
Hello World!


Creando un usuario:

El administrador será el encargado de crear los usuarios, aunque perfectamente se podría automatizar como un sistema de registro cualquiera con una interfaz de usuario cualquiera, para este ejemplo se usará el plugin 'add' de UTeslaCLI.

Código: bash
# Para requerir ayuda
./UTeslaCLI add --help
# Creamos el usuario
./UTeslaCLI add -u <Nombre de usuario> -p <Contraseña> -i <Ruta de la clave pública>


Creación del par de claves:

Tanto el servidor como el usuario deben tener sus par de claves para que la comunicación sea satisfactoria. Esto es un proceso inicial que deben hacer antes de hacer cualquier cosa (independientemente de si es un usuario o el administrador del servidor).

En el cliente:

El cliente va a requerir usar el plugin 'generate_keys' para la creación del par de claves

Código: bash
# Para requerir ayuda
./UTeslaCLI generate_keys --help
# Generamos el par de claves
./UTeslaCLI generate_keys -bit_size <Tamaño del par de claves en bits> -out-public-key <Nombre del archivo de la clave pública> -out-private-key <Nombre del archivo de la clave privada>


Si se ejecuta sin parámetros se generará con un tamaño de claves por defecto de 3072 bit's y las claves se mostrarán en la salida. Lo recomendable sería dejar el tamaño de claves pre-determinado y guardar el par de claves en un lugar seguro.

Ahora lo que tendría que hacer el usuario que desea registrarse es enviar la clave pública al administrador del servidor para que éste lo registre satisfactoriamente.


En el servidor:

El proceso para generar el par de claves en el lado del servidor será mucho más simple; se hará automáticamente cuando se ejecute.

Código: bash
./UTesla


El tamaño del par de claves estará definido en UTesla.ini, en la sección 'Crypt Limits' y en la clave 'rsa_key_length'.


Lo recomendable es dejar el tamaño de claves pre-determinado tanto del lado del cliente y del servidor, y se debe tener en cuenta que el tamaño de claves debe ser igual o equivalente en las dos partes.

Creación del token de acceso:

UTesla requiere de un token de acceso para realizar la mayoría de acciones, en este caso el cliente deseoso por obtener su token tiene que usar el plugin 'generate_token'

Código: bash
./UTeslaCLI generate_token <La URL del servidor> -u <El nombre de usuario> -p <La contraseña del usuario> -s <La clave pública del servidor> -i <La clave pública del usuario> -I <La clave privada del usuario>


Una vez hecho lo anterior y la petición haya sido satisfactoria, se mostrará el token de acceso, el cual debe ser almacenado en un lugar seguro para su posterior uso.

Uso de la distribución de servicios:

Supongamos que en el mundo haya dos servidores y los administradores se conozcan, uno de éstos contiene uno o más servicios que otro no tiene, pero un cliente que requiera el uso de ese servicio usando la URL del primer servidor (por ejemplo) no tendría ningún inconveniente, ya que si el servicio deseado no se encuentra en el primer servidor, éste hará una búsqueda en la red y determinará qué servidor es el que contiene ese servicio, posteriormente obtendría una respuesta como si fuera el mismo cliente y luego la redirige hacia el cliente mismo, por lo que todo sería transparente.

Lo anterior es muy útil si se desea separar ciertos servicios entre servidores, por cuestiones económicas, de recursos, una mejoría en la implementación o cualquier cosa que se desee, al fin y al cabo, el usuario es el que lo decide.

Para estos ejemplos el primer servidor será 'No tienes permitido ver los links. Registrarse o Entrar a mi cuenta' y el segundo 'No tienes permitido ver los links. Registrarse o Entrar a mi cuenta'. El segundo tiene un servicio llamado 'hello_friend', pero nosotros "los clientes" vamos a creer que el servicio está en el primer servidor, por lo cual lo usaremos para interactuar con éste.


complements/hello_friend.py:
Código: python
class handler:
    async def get(self):
        await self.write('hello friend!')


Por diseño, el administrador del segundo servidor debe crear un usuario como si fuera cualquier otro. Por lo que debe saber cómo crearlo, cosa que ya se hablo en anteriores secciones. En este caso nosotros lo llamaremos 'utesla'.

Además, como ya se aclaró en anteriores secciones, la mayoría de operaciones requieren de un token de acceso, por lo se va a suponer que se tiene hecho este paso para el nuevo usuario utesla.

Una vez aclarado todo lo que se tiene que hacer, vamos un paso más allá y obtengamos los servicios del segundo servidor (No tienes permitido ver los links. Registrarse o Entrar a mi cuenta) para el primer servidor (No tienes permitido ver los links. Registrarse o Entrar a mi cuenta)


Código: bash
./UTeslaCLI add_network http://localhost:17001 -s <Clave pública del segundo servidor> -p keys/key.pub -P keys/key.priv -u utesla -t <Token de acceso>


Como esto es un ejemplo, se usan las claves que por defecto se almacenan en la carpeta 'keys' del primer servidor; se usa el usuario 'utesla' que ya debe estar creado en el segundo servidor y nos contactamos con el servidor 'No tienes permitido ver los links. Registrarse o Entrar a mi cuenta' para obtener sus servicios.

Como paso final, el cliente desea obtener el servicio 'hello_friend' y si todo ha salido bien, obtendrá su posterior salida, aunque lo peculiar de todo esto es que el cliente hará una petición al primer servidor en vez de al segundo.

Lo siguiente será muy parecido a lo que se observó en anteriores secciones, pero lo único que cambió es el nombre del servicio:


Código: python
import asyncio

from modules.Infrastructure import client

async def main():
    UTeslaClient = client.UTeslaClient('<Nombre de usuario>')
    await UTeslaClient.set_server_key('<Clave pública del servidor>')
    await UTeslaClient.set_user_keys('<Clave pública del usuario>', '<Clave privada del usuario>')

    cmd = {
        'token' : '<Token de acceso>'

    }

    Response = await UTeslaClient.fetch(
        'http://localhost:17000/hello_friend',
        cmd,
        method='GET'

    )

    dec_body = UTeslaClient.get_message(Response.body)

    print(dec_body)

if __name__ == '__main__':
    asyncio.run(main())


Deberíamos obtener la siguiente respuesta:

Código: text
Hello Friend!


Como se puede apreciar, es un proceso muy sencillo y lo mejor, es transparente para el usuario.

Sub servicios:

Ya se ha explicado anteriormente qué son los sub servicios, pero no se han explicado cómo crearlos. Al igual que la creación de plugins y servicios es muy sencillo.

Lo primero que hay que hacer es crear un servicio, como 'greeting' (complements/greeting.py).


Código: python
class Handler:
    pass


Se pueden colocar los métodos HTTP si se desea, pero para este caso no lo necesitamos

Ahora para la creación de sub servicios simplemente se crea una carpeta en 'complements' con el mismo nombre del servicio mas '-folder'.


Código: bash
mkdir complements/greeting-folder


En esa carpeta se tienen que agregar más archivos que sigan una estructura similar a la del servicio padre, como por ejemplo:

complements/greeting-folder/hello_friend.py:
Código: python
class Handler:
    async def get(self):
        await self.write('Hello Friend!')


Ahora un cliente puede hacer una petición usando una URL parecida a: <Scheme>://<netloc>/greeting/hello_friend y obtendría:

Código: text
Hello Friend!


Adentro de esa carpeta se crean más carpetas (si se desea), pero lo peculiar de todo esto es que no necesitan usar una sintaxis similar a "<Nombre del servicio>-folder", simplemente creando una carpeta e insertando nuevos servicios que sigan una estructura similar a los anteriores es más que suficiente.

Código: bash
mkdir complements/greeting-folder/farewell


complements/greeting-folder/farewell/bye.py:
Código: python
class Handler:
    async def get(self):
        await self.write('Bye!')


Y el cliente puede usar una estructura similar a: <scheme>://<netloc>/greeting/farewell/bye

Módulos:

Los módulos son muy útiles en caso de que se necesite integrar ficheros de python a los complementos, para que la escritura sea más limpia y siga mejores prácticas.

Para crear un módulo es necesario crear primero un servicio, en este caso 'math' (complements/math.py)


Código: python
class Handler:
    async def post(self):
        sum = self.modules.get('sum')
        num1 = self.get_argument('num1', 0)
        num2 = self.get_argument('num2', 0)

        await self.write('Result:' + str(sum.calculate(num1, num2)))


Ahora se debe crear una carpeta con el nombre del servicio mas '-modules' y ahí se agregan ficheros de python como cualquier otro; siguiendo lo que necesita el código anterior:

complements/math-modules/sum.py:

Código: python
def calculate(x, y):
    return x + y


Eso sería todo, muy sencillo y más modular.

Instalación:

Código: bash
git clone --recursive https://github.com/UltraTesla/UTesla.git
cd UTesla


Arch Linux:

Código: bash
sudo pacman -S mariadb


Debian:

Código: bash
sudo apt-get install mariadb-server libmariadb-dev python3-dev


Red Hat Enterprise Linux 8.2

Código: bash
sudo yum install python3-devel gcc mariadb mariadb-server mariadb-devel


General:

Código: bash
sudo systemctl start mariadb.server
python3 -m pip install -r requirements.txt
./UTesla


Es recomendable configurar primero antes de iniciar UTesla (como el nombre de usuario y la contraseña en MySQL)

Contribuyendo:

Al igual que cada proyecto nuevo creado, soy imperfecto y puedo equivocarme, pero con todo el gusto del mundo aceptaré tu contribución, ya sea por código o no, porque hay que recordar que se trata de abarcar muchos idiomas de distintas regiones del mundo y en éso puede haber múltiples defectos.

Notas:


  • No se ha probado en Windows u otro sistema operativo
  • El proyecto usa un protocolo propio y no uno estándar
  • El proyecto no está definido, de eso se encarga el mismo usuario
  • Todo el proyecto fue probado en la versión 3.8.2 y 3.7.3 de python

~ DtxdF
PGP :: <D82F366940155CB043147178C4E075FC4403BDDC>

~ DtxdF


      @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Muy bueno tu trabajo, claro y limpio.
Una guía útil y documentada para los que deseen adherir a Ultra Tesla.
Gracias por compartirlo a la Comunidad!

Saludos

Gabriela

Tú te enamoraste de mi valentía, yo me enamoré de tu oscuridad; tú aprendiste a vencer tus miedos, yo aprendí a no perderme en tu abismo.

Hola @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta  ;D, muchas gracias a ti por leerlo, y como siempre es un placer compartir estos aportes  ;)

~ DtxdF
PGP :: <D82F366940155CB043147178C4E075FC4403BDDC>

~ DtxdF

Excelente trabajo compañero, se agradece estos grandes aportes y proyectos que haces para la comunidad  ;) ;).

-Kirari

Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta lo que sea para aprender y enseñar  ;D

~ DtxdF
PGP :: <D82F366940155CB043147178C4E075FC4403BDDC>

~ DtxdF


Gracias @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, ya vendrán más al respecto :D

~ DtxdF
PGP :: <D82F366940155CB043147178C4E075FC4403BDDC>

~ DtxdF