Abr 01 2021

Inventario dinámico Ansible de Servidores IBM Cloud

Published by at 17:40 under Ansible,Python

IBM Cloud se basa en la API Softlayer – también conocida como IBM Classic Infrastructure – para automatizar acciones. La API está disponible en diferentes lenguajes como Python, Go, Java o PHP.
Voy a generar un inventario dinámico de los servidores recuperados de mi cuenta de IBM Cloud directamente utilizables por Ansible.


Generaré grupos correspondientes a los datacenters. También le gustaría agrupar servidores en todo tipo de categorías como bases de datos, Mysql, Linux, Web, etc… No se preocupe, también podemos hacer esto de una forma muy sencilla.
Esto se puede lograr agregando etiquetas a los hosts en IBM Cloud portal y obviamente, un host puede tener varias etiquetas y pertenecer a los grupos de Ansible correspondientes a estas etiquetas / tags.

Una vez que estos grupos han sido declarados en el archivo inventory, puede ejecutar playbooks de Ansible como instalar paquetes de Apache en servidores que pertenecen al grupo «Web» por ejemplo.


Primero debe agregar su API key en un archivo de shell para ejecutar antes del script. Podría ser parte del script, pero permite que cada usuario use su propia clave.

export SL_USERNAME=nombre_usuario
export SL_API_KEY=a1b2c3[...]3456


Ejecute . ./IBM_SL_env.sh primero para agregar el nombre de usuario y la clave de API en las variables de entorno que leerá el script de Python a continuación.

#!/usr/bin/env python3  
import os
import SoftLayer
 
HOST_VARS_DIR  = "host_vars"
INVENTORY_FILE = "inventory"
 
class Inventory:
   def __init__(self):
      # Variables
      self.categories = {}
      self.datacenter = {}
      self.servers = {}
 
      # Create Softlayer connection
      self.client = SoftLayer.create_client_from_env()
 
      # Init Methods
      self.get_server_list()
      self.write_inventory()
 

   def short_host_name(self, host):
      return host['fullyQualifiedDomainName'][:host['fullyQualifiedDomainName'].find('.mydomain.')]
 

   def add_host_to_cat(self, host, cat):
      if cat == "ibm-kubernetes-service": cat = "kube"
      if cat not in self.categories:
         self.categories[cat] = [host]
      else:
         self.categories[cat].append(host)
 

   def add_server_to_list(self, host):
      try:
         host["primaryBackendIpAddress"]
      except KeyError:
         pass
      else:
         host["ShortHostname"] = self.short_host_name(host)
             
         # Build server Categories list
         if host["tagReferences"] != []:
            for tagRef in host["tagReferences"]:
               self.add_host_to_cat(host["ShortHostname"], tagRef["tag"]["name"].strip())
             
         # Build datacenter lists
         if host["datacenter"]["name"] not in self.datacenter:
            self.datacenter[host["datacenter"]["name"]] = [host["ShortHostname"]]
         else:
            self.datacenter[host["datacenter"]["name"]].append(host["ShortHostname"])
             
         # Build server attribute list
         serverAttributes = {}
         serverAttributes['IP'] = host["primaryBackendIpAddress"]
         self.servers[host["ShortHostname"]] = serverAttributes
     

   def get_server_list(self):
      object_mask = "mask[id,fullyQualifiedDomainName," \
                    "primaryBackendIpAddress," \
                    "tagReferences[tag[name]]," \
                    "datacenter]"
 
      # Get virtual server list
      mgr = SoftLayer.VSManager(self.client)
      for vs in mgr.list_instances(mask=object_mask):
         self.add_server_to_list(vs)
 
      # Get bare metal servers
      hsl = SoftLayer.HardwareManager(self.client)
      for hs in hsl.list_hardware(mask=object_mask):
         self.add_server_to_list(hs)
 

   def write_inventory(self):
      # host_vars structure
      if not os.path.exists(HOST_VARS_DIR):
         os.makedirs(HOST_VARS_DIR)
 
      inventoryFile = open(INVENTORY_FILE,"w")
 
      for cat in self.categories.keys():
         if cat != "kube":
            inventoryFile.write("[" + cat + "]\n")
            for host in self.categories[cat]:
               # write host vars
               inventoryFile.write(host + "\n")
               file = open(HOST_VARS_DIR+"/"+host,"w")
               file.write("ansible_host: " + self.servers[host]['IP'] + "\n")
               file.close()        
            inventoryFile.write("\n")
      for dc in self.datacenter.keys():
         inventoryFile.write("[" + dc + "]\n")
         for host in self.datacenter[dc]:
            if not host.startswith("kube"):
               inventoryFile.write(host + "\n")
         inventoryFile.write("\n")
      inventoryFile.close()

if __name__ == "__main__":
   exit(Inventory())


Algunas notas:

Los nodos de Kubernetes administrado son visibles en la infraestructura clásica de IBM Cloud como cualquier VM (VSI en terminología de IBM) pero no puede conectarse a ellos. Por lo tanto, se agregan a la categoría «Kube» antes de ser ignorados.


Se crea un archivo separado en hosts_var para cada servidor, que contiene su dirección IP. Puede agregar otras variables como parámetros iSCSI, etc…


El script recupera máquinas virtuales en el inventario Ansible, así como máquinas físicas (bare metal). Es posible comentar cualquiera de estas secciones si no es necesario, guardando una llamada a IBM.


No responses yet

Comments RSS

Leave a Reply