Make Oracle Cloud Machine Great Again

Parte 1: ¿Les sobra un OCM en sus Data Centers?

Luciano Adonis
devsChile
6 min readAug 31, 2018

--

Si tu lo deseas puedes Terraformar.

Este es el primer de un conjunto de posts sobre el proceso de creación de un custom provider de Terraform para un OCM.

“¡Hey! ya existen como ehhhh 2 providers para eso.” -Anon

Pero productos como Oracle Cloud at Customer o de lleno Oracle Cloud tienen el soporte necesario, de no estar en la cobertura de los providers oficiales, puedes optar por leer la docu del proveedor y hacer un custom provider a tu pinta.

Antes de llegar eso, hay que plantearse las siguientes preguntas:

  • ¿En que lo utilizaré? — Para un OCM (de los heavys).
  • ¿Cómo hago el truco? — Pegándole a la API con CURL y luego con Go.
  • ¿Cómo le digo lo que quiero? — Normalmente un request con CURL, junto a la variable de entorno “COMPUTE_COOKIE” obtenida de otro request.
  • Y ¿Cómo esto afecta a Terraform? — Entendiendo lo anterior, pasándolo a Golang y acomodándolo a las definiciones dentro del provider, should be no problem. Ah, bueno, sin mencionar la forma en que maneja las cosas Terraform, pero eso es para otro post.
  • Y la más importante ¿Vale la pena? — Si ahorra tiempo, dinero y puedes meterle Terraform, ¿Por qué no?.

Un poco de explicación y contextualización

Oracle Compute Cloud Service

Mejor conocida como Infrastructure-as-a-Service (IaaS), te permite configurar y administrar maquinas en Oracle Cloud Machine (OCM).

Como la nube pública, pero privada.

¿Qué es Tenant? Y ¿Por qué debe importarme?

Este permite llevar el seguimiento de los usuarios con dos roles específicos:

  • Administrador.
  • Recursos especificos.

Junto a estos se encuentran los objetos Cloud, que pueden ser usuarios, instancias, almacenamiento, red, etc. Lo que implica esto, es que tu usuario vendría siendo algo como:

TL;DR: una bonita forma de decir identificador para tu username y al segmento donde quieras hacer algo. Ahora que sabemos lo que es un tenant, podemos dormir tranquilos.

REST API with CURL

Hay un montón de cosas de Oracle que tal vez te hagan sentido al leer la documentación:

Siguiendo el primer ejemplo para obtener las credenciales, el curl vendría siendo algo así:

Esto nos entrega en el header Set-Cookie un valor que es el cookie, el cual debe ser exportado como variable de entorno para ser utilizado en los request al OCM.

Para ser exportado de la siguiente forma:

Ya realizado lo anterior, podemos utilizar, nuestra variable de entorno en los request que se nos ocurran.

  • Con GET puedes ir tanteando a lo que tienes acceso dentro de un tenant específico.

REST API with Golang

TL;DR: el fin justifica los medios y si puedes rickrollear con los errores, hazlo.

Aquí es donde se pone entretenida la cosa. Para crear un provider es necesario cubrir todas esos request que haríamos con CURL pero con Go, si tienes suerte hay algún package para la comunicación con la API de forma efectiva, lo cual te permitiría enfocarte en el manejo de las credenciales, recursos, errores y otras cosas más específicas.

Como recomendación extra, tener lo siguiente a mano, personalmente, me fue bastante útil:

main

Este cumplirá la función de imitar lo que haría Terraform, ya saben, disponibilizar la información obtenida de los .tf y traspasarla a las funciones correspondientes.

Si no nos ponemos quisquillosos, podemos pasarla de lleno en el mismo request y que todo lo feo quede debajo de la alfombra. Ni hablar de los nombres de las variables.

Volviendo a la explicación, func main representaría de forma espiritual a toda la belleza de Terraform.

Para facilitar la explicación dividiré la explicación en:

  • finalCookie: (Lo sé, soy bueno con los nombres) entregándole los parámetros de user, pass y domain a la función getCookie para regresar el valor del Set-Cookie listo para ser usado por otras funciones. + la función between.
  • getStorage: con un GET basta, con esta forma no creamos recursos no deseados con pruebas.

Pero antes de eso…

¿Por qué GoRequest?

Puedo resumir las razones en:

  • Se ve más lindo y es mucho más simple.
  • Te ahorras la conversión a JSON.
  • Te permite enviar múltiples archivos

Pero el código habla por si solo:

Package http

Package GoRequest

Si, cualquiera comiéndose los if errs != nil hace ver todo más lindo.

Ahora si:

getCookie

La explicación simple es que a esta función se le entregan 3 argumentos de tipo string y esta debe regresar un string.

  • Payload: es el struct para armar el formato de autenticación compuesto de user y password, que nos entrega una definición así:
  • urlAuth: convierte en un string la ruta de autenticación con la dirección IP obtenida de la variable domainOCM. Esta será utilizada en el request:
Okay, mucho para una linea.
  • GoRequest: con la definición de esta obtienen los valores para resp, body y errs los cuales utilizaremos para hacer un debug más bonito (en otro Post). La cual puede ser definida en una sola línea. La explicación de cada argumento está aquí.
  • Errores: al realizar pruebas basta con un errs distinto de nulo, dar una descripción de lo que ocurrió y escupirlo como output.

Siempre puedes hacer un Frankenstein para algo específicio:

Pero, ya entrando en un provider, algo como lo siguiente sería “aceptable”:

TL;DR: never gonna give you up.

  • resp: llegamos al punto donde, si todo salió bien, nos devuelve nuestra cookie. El problema con esto, es que aún contiene otra info que no nos sirve. Con esto en mente, lo ideal, sería aplicar algo así:

Pero en Go la cosa no es así (si hay una mejor forma, díganme). Para sacar nuestra cookie en limpio, se debe hacer el parsing desde el primer valor que será “nimbula” hasta “ max-age” a partir del valor de resp formateado como string, mediante una función que solo sé que hace la magia y esa es between.

y ¿between?

Aquí está:

Lo que hace lo hace y por eso aprecio tal magia. A veces, uno solo necesita creer y nada más.

Al usar la función between, funcionó, tienes lo que querías pero también te agrega un salto, lo cual hace colapsar el request final.

Para solucionar eso, mediante strings.TrimSuffix, que te permite eliminar ese saltito que arruina todo. Ah y ya que se borró (mejor dicho, borré) nimbula y max-age, se le vuelve agregar mediante fmt.Sprintf dando como resultado una linda cookie, limpia, que cumplirá todas nuestros requests.

Si tienen una mejor forma, diganme 😅

Ahora que tenemos la cookie, hay que “consumirla”.

getStorage

Es el equivalente en Go del CURL:

Reflexión espiritual

El provider es el responsable de implementar uno o más recursos mediante la comunicación con la API de dicho elemento, en nombre de Terraform. Por lo tanto, si falla la comunicación con la API, nah que hacer.

En el mejor de los casos te tocará hacer un proveedor con una API que ya se encuentre disponible en Go; en ese caso no será todo color de rosa, pero al menos será mas fluído.

--

--