import requests import urllib3 import sys import time import threading import logging import os import errno from concurrent.futures import ThreadPoolExecutor from dotenv import load_dotenv from vmware.vapi.vsphere.client import create_vsphere_client from com.vmware.vcenter_client import VM from com.vmware.vcenter.vm_client import Power as PowerHardware from com.vmware.vcenter.vm.guest_client import Power as PowerGuest # Variables wait_power_on = 60 # Tiempo de espera entre grupos de máquinas wait_power_off = 60 # Tiempo de espera entre grupos de máquinas wait_tools_on = 120 # Tiempo de espera para que las tools esten activas wait_tools_off = 120 # Tiempo de espera para que las tools esten apagadas timeout_on = 1200 # Tiempo de espera para que se de la máquina por encendida timeout_off = 1200 # Tiempo de espera hasta forzar el apagado de la maquina operation = "none" # Modo de operación: encendido o apagado # Grupo de máquinas sobre las que se aplicará el modo de energía (NOMBRE) group_selected = "none" vms = "none" # Máquinas que se van a utilizar en la ejecución del script # TEST vms_test_g1 = ["test1", "test2"] vms_test_g2 = ["test3", "test4", "test5"] vms_test_g3 = ["test6", "test7", "test8", "test9", "test10"] # TEST2 vms_test_g4 = ["test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10"] # PRODUCCIÓN vm_sin_grupo = ["alarmas_ayto", "alarmas_cpd", "cita_previa", "daloradius_biblioteca", "deep_freeze2", "editrans2", "edu_latorre", "gestion_switches", "impresoras_ricoh", "inattend2", "lucia", "micollab-mbg", "micollab9.4", "museo_domus", "ofimatico2007", "ofimatico2019", "pulse_secure", "tarificador", "tc_aplicaciones", "tc_balanceador", "tc_bbdd", "tc_wserver", "untangle_biblioteca", "web_pre", "webdmz", "wifimovi", "tao_consultores1", "tao_consultores2", "tao_consultores3", "temporizador_pleno", "wazuh4.3.6"] vm_apagadas = ["adnperros", "autocad2010", "control_biblio", "gisabsis", "glpi", "gwdmz15", "helpdesk", "inventario_igs", "oes2018_pruebas", "open_erp", "pacmer", "presencia", "severino", "verticales_telefonica_camaras"] vm_grupo_0 = ["datacore-cpd", "datacore-pol", "vcsa7"] vm_grupo_1 = ["sacrista", "paco", "synology", "hp1440"] vm_grupo_2 = ["torero", "oraserver19", "oraserver19_pre", "ndsmaster", "storeonce1", "storeonce2"] vm_grupo_3 = ["ayto_web_int", "documentum2016", "geoserver_lan", "peseta2", "taoactuate", "abaco", "intranet2016", "intranet2_pre", "petrolio2"] vm_grupo_4 = ["ayto_web_ext2", "geoserver_pre", "tao1", "tao1_pre", "tirisiti2"] vm_grupo_5 = ["clasico", "gw01-19", "gw02-19", "geoserver_pro", "otrs", "taoapps1_wildfly", "taoapps2_wildfly", "taoapps3_wildfly", "taoapps_pre_wildfly", "tereseta2", "fortianalyzer", "fortimail", "veeam", "taobalanceador_wildfly", "taosede_9", "taosede_9_pre", "filr4"] vm_grupo_6 = ["datasync_gms15", "gwdmz"] vm_grupo_7 = ["centreon2", "zabbix"] # ORACLE vm_oracle_0 = ["oraserver19", "oraserver19_pre"] vm_oracle_1 = ["ayto_web_int", "documentum2016", "geoserver_lan", "peseta2", "taoactuate", "abaco", "intranet2016", "intranet2_pre"] vm_oracle_2 = ["ayto_web_ext2", "geoserver_pre", "tao1", "tao1_pre"] vm_oracle_3 = ["geoserver_pro", "taoapps1_wildfly", "taoapps2_wildfly", "taoapps3_wildfly", "taoapps_pre_wildfly", "taobalanceador_wildfly", "taosede_9", "taosede_9_pre"] # GEOSERVERS g1 = ["geoserver_lan"] g2 = ["geoserver_pre"] g3 = ["geoserver_pro"] # Orden de encendido de las máquinas de test vms_test1 = [vms_test_g1, vms_test_g2, vms_test_g3] vms_test2 = [vms_test_g4] vms_oracle = [vm_oracle_0, vm_oracle_1, vm_oracle_2, vm_oracle_3] vms_produccion = [vm_grupo_2, vm_grupo_3, vm_grupo_4, vm_grupo_5, vm_grupo_6, vm_sin_grupo, vm_grupo_7] vms_geo = [g1, g2, g3] # Listados con los diferentes grupos de máquinas groups = [vms_test1, vms_test2, vms_oracle, vms_produccion, vms_geo] group_names = ["TEST1", "TEST2", "ORACLE", "PRODUCCION", "GEOSERVERS"] def get_vm(client, vm_name): # Return the identifier of a vm # Note: The method assumes that there is only one vm with the mentioned name. names = set([vm_name]) vms = client.vcenter.VM.list(VM.FilterSpec(names=names)) if len(vms) == 0: return None vm = vms[0].vm return vm def power_off_vm(client, vm, name): # Si la maquina existe if vm != None: # Obtiene el estado (encendida o apagada) status = client.vcenter.vm.Power.get(vm) timeout_shutdown = time.time() + timeout_off # Repite hasta que se apague o se acabe el tiempo while status.state == PowerHardware.State.POWERED_ON: status = client.vcenter.vm.Power.get(vm) guest_status = client.vcenter.vm.guest.Power.get(vm).state # El sistema operativo está funcionando if guest_status == PowerGuest.State.RUNNING: tools = client.vcenter.vm.guest.Power.get(vm).operations_ready # Las tools estan operativas if tools == True: logging.info("%s: Enviada señal de apagado", name) client.vcenter.vm.guest.Power.shutdown(vm) # Espera hasta que las tools ya no esten disponibles o salte el time out timeout_tools = time.time() + wait_tools_off while tools == True: tools = client.vcenter.vm.guest.Power.get( vm).operations_ready time.sleep(1) if time.time() > timeout_tools: logging.info("%s: Timeout tools", name) break logging.info("%s: Apagandose ...", name) time.sleep(5) if time.time() > timeout_shutdown: logging.info("%s: Forzando apagado ...", name) client.vcenter.vm.power.stop(vm) break logging.info("%s: Apagada", name) return True # Si la máquina no existe else: logging.info("%s: No existe", name) return False def power_on_vm(client, vm, name): # Si la maquina existe if vm != None: # Obtiene el estado (encendida o apagada) status = client.vcenter.vm.Power.get(vm) # Repite hasta que se encienda while status.state == PowerHardware.State.POWERED_OFF: client.vcenter.vm.Power.start(vm) logging.info("%s: Enviada señal de encendido", name) # Espera hasta que las tools esten disponibles o salte el time out timeout_tools = time.time() + wait_tools_on tools = client.vcenter.vm.guest.Power.get(vm).operations_ready while tools == False: time.sleep(5) tools = client.vcenter.vm.guest.Power.get(vm).operations_ready logging.info("%s: Encendiendose", name) if time.time() > timeout_tools: logging.info("%s: Timeout tools", name) break # Comprueba el estado status = client.vcenter.vm.Power.get(vm) # La máquina ya está encendida logging.info("%s: Encendida", name) return True # Si la máquina no existe else: logging.warning("%s: no existe", name) return False def printHelp(prog): print("\nFUNCIONAMIENTO") print("\tpython3 " + prog + " OPCIONES\n") print("OPCIONES") print("\t -h, --help:") print("\t\tMuestra esta ayuda\n") print("\t -l, --list:") print("\t\tLista los posibles grupos de maquinas virtuales para operar\n") print("\t -l, --list NOMBRE_GRUPO:") print("\t\tLista los nombres de las máquinas virtuales que pertenecen al grupo NOMBRE_GRUPO\n") print("\t -g, --group NOMBRE_GRUPO:") print("\t\tEstablece el grupo de maquinas virtuales sobre el cual se aplicará el modo de energía\n") print("\t -p, --power on|off:") print("\t\tIndica el modo de operación de energía que se aplicará a las máquians virtuales") print("\t\t--power on: Enciende las máquinas virtuales del grupo seleccionado") print("\t\t--power off: Apaga las máquinas virtuales del grupo seleccionado\n") print("EJEMPLO") print("\tpython3 " + prog + " --power on --group ORACLE\n") def checkArgs(args): global operation operation = "none" global group_selected group_selected = "none" global vms vms = "none" for index in range(0, len(args)): # POWER if args[index] == "--power" or args[index] == "-p": if index < len(args)-1: if args[index+1] == "on": operation = "on" elif args[index+1] == "off": operation = "off" # LIST if args[index] == "--list" or args[index] == "-l": operation = "none" # Comprueba que el argumento list es el último o no contiene un nombre de grupo válido detras if index == len(args)-1 or (index <= len(args)-1 and args[index+1] not in group_names): print("Los grupos de máquinas disponibles son los siguientes:") for group in group_names: print("- "+group) # Comprueba que el argumento posterior pertenece a un grupo if index < len(args)-1: if args[index+1] in group_names: num = group_names.index(args[index+1]) num_group = 1 for group in groups[num]: print("Grupo", num_group) num_group += 1 for mv in group: print("\t" + mv) # GROUP if args[index] == "--group" or args[index] == "-g": group_selected = "none" # Comprueba que el argumento posterior pertenece a un grupo if index < len(args)-1: if args[index+1] in group_names: group_selected = args[index+1] num = group_names.index(group_selected) vms = groups[num] # HELP if args[index] == "--help" or args[index] == "-h": operation = "none" printHelp(args[0]) if len(args) == 1: operation = "none" printHelp(args[0]) def main(): # Comprueba los argumentos checkArgs(sys.argv) print("operation", operation) vms = vms_test1 print("vms", vms) # ~Si no tiene los parametros necesarios, sale del programa if (operation == "none" or vms == "none"): sys.exit() # Crea el directorio para los logs try: os.mkdir('log') except OSError as e: if e.errno != errno.EEXIST: raise # Obtiene la fecha y hora de inicio ini_timestr = time.strftime("%Y%m%d-%H%M%S") # Inicia el log logging.basicConfig(level=logging.INFO, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', encoding='utf-8', datefmt='%m-%d %H:%M', filename='log/' + ini_timestr + '.log', filemode='w') # Define a Handler which writes INFO messages or higher to the sys.stderr console = logging.StreamHandler() console.setLevel(logging.INFO) # Set a format which is simpler for console use formatter = logging.Formatter('%(levelname)-8s>> %(message)s') # Tell the handler to use this format console.setFormatter(formatter) # Add the handler to the root logger logging.getLogger().addHandler(console) # logging.info("Empieza el programa\n") session = requests.session() # Disable cert verification for demo purpose. # This is not recommended in a production environment. session.verify = False # Disable the secure connection warning for demo purpose. # This is not recommended in a production environment. urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Obtiene la información desde el fichero .env load_dotenv() vcenter_server = os.getenv('VCENTER_SERVER') vcenter_username = os.getenv('VCENTER_USERNAME') vcenter_password = os.getenv('VCENTER_PASSWORD') print("vcenter_server", vcenter_server) # Connect to a vCenter Server using username and password client = create_vsphere_client( server=vcenter_server, username=vcenter_username, password=vcenter_password, session=session) # Bucle principal main_loop(client, operation) # logging.info("Acaba el programa") def main_loop(client, operation): # Enciende máquinas if operation == "on": logging.info("Modo de operación: ENCENDER MÁQUINAS\n") group = 0 while group < len(vms): logging.info("Grupo %s: PROCESANDO", group) # Create the thread pool n_threads = len(vms[group]) with ThreadPoolExecutor(n_threads) as executor: _ = [executor.submit(power_on_vm, client, get_vm( client, vm_name), vm_name) for vm_name in vms[group]] # Terminado el grupo de máquinas logging.info("Grupo %s: TERMINADO\n", group) # Resumen logging.info("Grupo %s: RESUMEN", group) num_mv = 0 for vm_name in vms[group]: vm = get_vm(client, vm_name) if power_on_vm(client, vm, vm_name): num_mv += 1 logging.info("%s de %s máquinas encendidas\n", num_mv, len(vms[group])) group += 1 if group < len(vms): logging.info("Esperando %s segundos ...\n", wait_power_on) time.sleep(wait_power_on) # Apaga máquinas if operation == "off": logging.info("Modo de operación: APAGAR MÁQUINAS\n") group = len(vms) - 1 while group >= 0: logging.info("Grupo %s: PROCESANDO", group) # Create the thread pool n_threads = len(vms[group]) with ThreadPoolExecutor(n_threads) as executor: _ = [executor.submit(power_off_vm, client, get_vm( client, vm_name), vm_name) for vm_name in vms[group]] # Terminado el grupo de máquinas logging.info("Grupo %s: TERMINADO\n", group) # Resumen logging.info("Grupo %s: RESUMEN", group) num_mv = 0 for vm_name in vms[group]: vm = get_vm(client, vm_name) if power_off_vm(client, vm, vm_name): num_mv += 1 logging.info("%s de %s máquinas apagadas\n", num_mv, len(vms[group])) group -= 1 if group >= 0: logging.info("Esperando %s segundos ...\n", wait_power_off) time.sleep(wait_power_off) if __name__ == "__main__": main()