본문 바로가기

Automation Tools/Ansible

ansible | [AWX] Local Script 실행 및 결과값 slack webhook 전송하기

반응형

개요


ssh를 이용한 VMware ESXi VM 생성 및 삭제 Script를 AWX를 이용하여 실행하고 결과 값을 Slack Webhook을 통해 전송 할 수 있다.

 

 

 

설정


awx_task Docker Container 수정

  • awx 관련 docker container 확인
> docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED       STATUS      PORTS                                   NAMES
9b5665c67d98   ansible/awx:17.1.0   "/usr/bin/tini -- /u…"   5 weeks ago   Up 3 days   8052/tcp                                awx_task
f708e1f818fa   ansible/awx:17.1.0   "/usr/bin/tini -- /b…"   5 weeks ago   Up 3 days   0.0.0.0:80->8052/tcp, :::80->8052/tcp   awx_web
7fb8ab51a84b   redis                "docker-entrypoint.s…"   5 weeks ago   Up 3 days   6379/tcp                                awx_redis
1a57eb1638a2   postgres:12          "docker-entrypoint.s…"   5 weeks ago   Up 3 days   5432/tcp                                awx_postgres

 

> docker exec -it awx_task bash

 

  • pip 설치
> pip3 install scp

# cryptography는 2.3이 기본 설치 되어 있다.
# 3.1.1 에서도 이상없이 돌아가는것을 확인하였으므로 설치해 주어도 상관없다.
> pip3 install cryptography==3.1.1

 

 

 

VMware ESXi VM 스크립트 수정

  • python 2.7 -> python 3.6 으로 변경 됨에 따라 변경 되는 print 문법을 수정하여 준다.
# 03.esxi-vm-create2 파일 수정
#!/usr/bin/python -> /usr/bin/python3

# print 문 수정
# 아래 예로 모두 수정
print 'ERROR: Missing required option --name'
->
print('ERROR: Missing required option --name')
...

 

  • esxi_vm_functions.py 에 setup_config 함수내 ESXi ssh PORT 추가
# esxi_vm_functions.py 파일에 PORT 추가

def setup_config():

    #
    #   System wide defaults
    #
    ConfigData = dict(

        ...
        #  ESXi host/IP, root login & password
        HOST="172.16.10.48",
        PORT="22",
        USER="root",
        PASSWORD="***********",
        ...

 

  • 03.esxi-vm-create2, 02.esxi-vm-destory 파일내에 PORT 변수 추가
# PORT = ConfigData['PORT']
ConfigData = setup_config()
...
HOST = ConfigData['HOST']
USER = ConfigData['USER']
PORT = ConfigData['PORT']
PASSWORD = ConfigData['PASSWORD']
CPU = ConfigData['CPU']
MEM = ConfigData['MEM']
...

 

  • sftp 사용을 위하여 03.esxi-vm-create2 파일 paramiko 설정 수정
# paramiko ssh 설정
...
try:
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(HOST, PORT, USER, PASSWORD)
...

# 맨 마지막줄 추가
ssh.close()


# paramiko sftp 설정
if not isDryRun and not CheckHasErrors:
...
        # Create NAME.vmx
        if isVerbose:
            print("Create " + NAME + ".vmx file")
        (stdin, stdout, stderr) = ssh.exec_command("mkdir " + FullPath )
        type(stdin)
        fp = open('/tmp/'+NAME+'.vmx', 'a')
        for line in VMX:
            fp.write(line)
            fp.write('\n')
        fp.close()

        sftp = ssh.open_sftp()
        sftp.put('/tmp/'+NAME+'.vmx',MyVM+'.vmx')
        sftp.close()

 ...

 

 

  • 03.esxi-vm-create2, 02.esxi-vm-destory 파일에 Slack Webhook 부분 추가
# import json
...
import warnings
import json
import subprocess

from esxi_vm_functions import *
...
# 03.esxi-vm-create2 파일에 LOG 쌓는 부분을 slack webhook payload로 수정
...
#      Print Summary
#
#   The output log string
LogOutput += '"ESXi_Host":"' + HOST + '",'
LogOutput += '"VM_Name":"' + NAME + '",'
LogOutput += '"VM_CPU":"' + str(CPU) + ' Core",'
LogOutput += '"VM_Mem":"' + str(MEM) + ' GB",'
LogOutput += '"VM_DISK_Volume":"' + str(HDISK) + ' GB",'
LogOutput += '"VM_Disk_Provisioning":"' + DISKFORMAT + '",'
LogOutput += '"VM_iSCSI_Controller":"' + VIRTDEV + '",'
LogOutput += '"VM_Storage_Pool":"' + STORE + '",'
#LogOutput += '"VM_Storage_Pool_Path":"' + DSPATH + '",'
LogOutput += '"VM_NIC_Driver":"' + NETDRIVER + '",'
LogOutput += '"VM_Network":"' + NET + '",'
LogOutput += '"VM_ISO":"' + ISOarg + '",'
#LogOutput += '"ISO used":"' + ISO + '",'
LogOutput += '"VM_Guest OS":"' + GUESTOS + '",'
LogOutput += '"VM_MAC":"' + MACarg + '",'
LogOutput += '"VM_MAC Used":"' + GeneratedMAC + '",'
#LogOutput += '"Dry Run":"' + str(isDryRun) + '",'
#LogOutput += '"Verbose":"' + str(isVerbose) + '",'
if ErrorMessages != "":
    slack_color = 'danger'
    slack_title = 'Failed :: The "' + os.path.basename(__file__) + '" Script'
    LogOutput += '"Error Message":"' + ErrorMessages + '",'
else:
    slack_color = 'good'
    slack_title = 'OK :: The "' + os.path.basename(__file__) + '" Script'
LogOutput += '"Result":"' + Result + '",'
LogOutput += '"Completion Time":"' + str(theCurrDateTime()) + '"'
LogOutput += '}'

## slack var
slack_channel = 'test-channel'
slack_user = 'script for ' + os.path.basename(__file__)
slack_emoji = ':slack:'
slack_url = 'https://hooks.slack.com/services/***************'

## slack payload data append
def append_payload(title,value,short,payload):
    append_data = {'title': title, 'value': value, 'short': short}
    payload['attachments'][0]['fields'].append(append_data)
    return(payload)

try:
    log_j = json.loads(LogOutput)
    payload = {}
    payload['channel'] = slack_channel
    payload['username'] = slack_user
    payload['icon_emoji'] = slack_emoji
    payload['attachments'] = [{}]

    payload['attachments'][0]['fallback'] = slack_title
    payload['attachments'][0]['pretext'] = slack_title
    payload['attachments'][0]['title'] = slack_title
    payload['attachments'][0]['color'] = slack_color
    payload['attachments'][0]['fields']=[{}]
    payload['attachments'][0]['fields'][0]['title']='Script Name'
    payload['attachments'][0]['fields'][0]['value']=os.path.basename(__file__)
    payload['attachments'][0]['fields'][0]['short']='true'

    for key, value in log_j.items():
        payload=append_payload(key,value,'true',payload)

    payload_a=json.dumps(payload)

    slack_send = "curl -X POST --data-urlencode 'payload={a}' {b}".format(a=payload_a,b=slack_url)
    subprocess.check_output(slack_send, shell=True, universal_newlines=True)

except:
    print("Error writing to log file: " + LOG)
...

 

# 02.esxi-vm-destroy Log 쌓는 부분을  slack webhook payload로 수정
...
#      Print Summary

#
#   The output log string
LogOutput += '"ESXi_Host":"' + HOST + '",'
LogOutput += '"VM_Name":"' + NAME + '",'
LogOutput += '"VM_Storage_Pool_Path":"' + DSPATH + '",'
LogOutput += '"Verbose":"' + str(isVerbose) + '",'
if ErrorMessages != "":
    slack_color = 'danger'
    slack_title = 'Failed :: The "' + os.path.basename(__file__) + '" Script'
    LogOutput += '"Error Message":"' + ErrorMessages + '",'
else:
    slack_color = 'good'
    slack_title = 'OK :: The "' + os.path.basename(__file__) + '" Script'
LogOutput += '"Result":"' + Result + '",'
LogOutput += '"Completion Time":"' + str(theCurrDateTime()) + '"'
LogOutput += '}'

## slack var
slack_channel = 'test-channel'
slack_user = 'script for ' + os.path.basename(__file__)
slack_emoji = ':slack:'
slack_url = 'https://hooks.slack.com/services/********************'

## slack payload data append
def append_payload(title,value,short,payload):
    append_data = {'title': title, 'value': value, 'short': short}
    payload['attachments'][0]['fields'].append(append_data)
    return(payload)

try:
    log_j = json.loads(LogOutput)
    payload = {}
    payload['channel'] = slack_channel
    payload['username'] = slack_user
    payload['icon_emoji'] = slack_emoji
    payload['attachments'] = [{}]

    payload['attachments'][0]['fallback'] = slack_title
    payload['attachments'][0]['pretext'] = slack_title
    payload['attachments'][0]['title'] = slack_title
    payload['attachments'][0]['color'] = slack_color
    payload['attachments'][0]['fields']=[{}]
    payload['attachments'][0]['fields'][0]['title']='Script Name'
    payload['attachments'][0]['fields'][0]['value']=os.path.basename(__file__)
    payload['attachments'][0]['fields'][0]['short']='true'

    for key, value in log_j.items():
        payload=append_payload(key,value,'true',payload)

    payload_a=json.dumps(payload)

    slack_send = "curl -X POST --data-urlencode 'payload={a}' {b}".format(a=payload_a,b=slack_url)
    result = subprocess.check_output(slack_send, shell=True, universal_newlines=True)
    print(result)

except:
    print("Error writing to log file: " + LOG)
...

 

  • 최종 수정 스크립트 파일

02.esxi-vm-destroy
0.01MB
03.esxi-vm-create2
0.02MB

 

 

 

awx_task container에 ESXi VM 스크립트 넣기

  • awx_task 는 /opt/awx/projects <-> /var/lib/awx/projects 의 볼룸이 마운트 되어 있다.
> docker inspect awx_task
...
        "Mounts": [
			...
            {
                "Type": "bind",
                "Source": "/opt/awx/projects",
                "Destination": "/var/lib/awx/projects",
                "Mode": "rw",
                "RW": true,
                "Propagation": "rprivate"
            },
			...

 

  • 03.esxi-vm-create2, 02.esxi-vm-destory 파일은 /opt/awx/projects에 복사
> cp -arf /opt/esxi-vm-create/03.esxi-vm-create2 /opt/awx/projects/
> cp -arf /opt/esxi-vm-create/02.esxi-vm-destory /opt/awx/projects/
> cp -arf /opt/esxi-vm-create/esxi_VM_functions.py /opt/awx/projects/
  • esxi_vm_functions.py python sys path 경로에 추가
> docker exec -it awx_task bash
> mv /opt/awx/projects/esxi_vm_functions.py /usr/lib/python3.6/site-packages/

 

 

 

inventory 작성

  • inventory host 변수에 VM 생성에 관한 변수값을 정의한다.
> 01.test_win.ini 
[test_win]
172.16.10.131 

[test_win:vars]
# vm 생성 관련
spec_disk=100 
spec_cpu=8 
spec_memory=4 
host_alias=test_win2
iso_image=20220524_auto_w2012x64_ko_clean.ISO
network_alias=ME2ON_Private
guest_os=windows8srv-64
disk_provisioning=zeroedthick
disk_controller=lsisas1068
nic_driver=e1000e

# vm을 생성하고자 하는 esxi host
esxi_server=172.16.10.48

# windows image 백업을 위한 변수
backup_drive=c: 
backup_target_dir="\\\\172.16.10.32\SE_Backup\test_win"
backup_target_host_user=admin
backup_target_host_password=*******

ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
#ansible_user=administrator
#ansible_password="**********"

 

 

 

playbook 작성

  • local_action을 이용하여 local script 를 정의 하고 스크립트와 함께 사용 할 파라미터를 정의 한다.
  • vm 생성
> 08.script_create_esxi_vm.yml 
---
- hosts: all
  gather_facts: no
  ignore_unreachable: yes
  vars:
    esxi_vars: "-H {{esxi_server}} -n {{ host_alias}} -c {{ spec_cpu}} -m {{ spec_memory}} -v {{ spec_disk}} --iso {{ iso_image}} -N {{ network_alias}} -g {{ guest_os}} -f {{ disk_provisioning }} -s {{ disk_controller }} -a {{ nic_driver }}"
  tasks:
  - name: create esxi vm
    local_action : script /var/lib/awx/projects/03.esxi-vm-create2 {{ esxi_vars }}

 

  • vm 삭제
> 09.script_destory_esxi_vm.yml 
---
- hosts: all
  gather_facts: no
  ignore_unreachable: yes
  vars:
    esxi_vars: "-H {{esxi_server}} -n {{host_alias}}"
  tasks:
  - name: destory esxi vm
    local_action : script /var/lib/awx/projects/02.esxi-vm-destroy {{ esxi_vars }}

 

  • git을 이용하여 gitlab에 push
> git add .
> git commit -a
> git status
> git push origin push

 

 

AWX Job Template 작성 및 실행


  • vm 생성

 

  • vm 삭제

 

 

  • Job template 실행 후 slack 메세지 확인

VM 생성
VM 삭제

 

반응형