Cloud Insight API 사용하여 서버의 평균 자원 사용량 응답 데이터 Excel 저장 후 메일 전송 #4

728x90

2024.04.29 - [네이버클라우드] - Cloud Insight API 사용하여 서버의 평균 자원 사용량 응답 데이터 Excel 저장 #3

 

Cloud Insight API 사용하여 서버의 평균 자원 사용량 응답 데이터 Excel 저장 #3

2024.04.23 - [네이버클라우드 API 사용 활용 사례] - Cloud Insight API 사용하여 서버의 평균 CPU 사용량 출력 #2-2 지난 포스팅에서는 Cloud Insight API를 통하여 생성된 서버의 CPU/MEM/FileSystem 사용량을 확인

burst.tistory.com

 

이전 포스팅 내용은 네이버클라우드 Cloud Insight API를 이용하여 사용중인 Instance의 자원 사용량 데이터를 Excel에 저장하는 내용까지 실습해 보았다.

이번 포스팅에서는 저장 된 Excel 파일을 메일에 첨부하여 보내는 방법을 알아 보자!

 

Python 메일 라이브러리

 

이번 포스팅에서는 메일 프로토콜 인 SMTP를 지원하는 smtplib 라이브러리를 사용 할 예정이다.

smtplib라이브러리는 파이썬에서 기본적으로 제공해주는 라이브러리로 import를 하여 바로 사용 할 수 있다.

import smtplib

 

또한 메일 형식(보내는 사람 / 받는 사람 / 제목 / 내용) 및 첨부파일 전송을 위해 MIME(Multipurpose Internet Main Extensions)를 사용 할 예정이다.

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
  • 메일 제목, 보내는 사람, 받는 사람등을 작성하기 위해 MIMEMultipart import
  • 메일 본문의 내용을 작성하기 위해 MIMEText import
  • 메일에 첨부파일을 추가하기 위해 MIMEApplication import

간단한 메일 전송 Test

  • Sample test.xlsx를 첨부하여 메일 전송하기
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

#메일에 첨부하려는 excel파일(Python 코드와 같은 위치에 있으면 파일 이름만 저장하며 되지만, 다른 경로에 파일이 있다면 경로 전체 + 파일 이름 입력
file_name = 'test.xlsx'

# 다수 MIME를 사용하기 위한 MIMEMultipart객체 생성
msg = MIMEMultipart()

# msg객체에 "From": 보내는 사람 메일 주소, "To": 받는 사람 메일 주소, "Subject": 메일제목 저장
msg['From'] = '보내는 사람 메일 주소'
msg['To'] = '받는 사람 메일 주소'
msg['Subject'] = '파이썬 메일 전송 Test 메일'

# 메일 내용을 MIMEText 객체에 저장 
body = MIMEText('안녕하세요! Test 메일입니다.', _charset='utf-8')

# 작성한 메일 내용을 msg객체에 추가
msg.attach(body)

# 현재까지 메일 송신자/수신자/제목/본문 내용이 msg객체에 저장(기본 메일 형식)

# Excel 파일 첨부
# 첨부하려는 파일을 r=read mode, b=바이너리 파일 모드로 열고, MIMEApplication객체에 read()함수를 사용하여 내용 저장
with open(file_name, 'rb') as excel_file : 
    excel_attachment = MIMEApplication( excel_file.read() )
    #첨부파일의 정보를 헤더로 추가
    excel_attachment.add_header('Content-Disposition','attachment', filename=file_name) 
    # msg 객체에 첨부파일 내용 추가
    msg.attach(excel_attachment)

# smtp라이브러리를 사용하여 메일 전송

# Test 메일 발송을 위하여 네이버 메일 사용(네이버 메일에서 별도 설정 필요)
# 사용하려는 메일의 smtp주소 지정
mailServer = smtplib.SMTP_SSL('smtp.naver.com')

#메일 서버 로그인(아이디 / 계정)
mailServer.login('메일 주소', '비밀 번호')

# 위에 만든 msg객체를 send_message()함수를 통해 발송
mailServer.send_message(msg)
# 메일 발송 후 메일 서버 접속 종료
mailServer.quit()

 

etc-image-0etc-image-1
etc-image-2

 

Cloud Insight 응답 데이터 저장 Excel파일 첨부하여 Mail 전송하기

 

  • 이전 블로그에서 포스팅한 Cloud Insight 응답 데이터를 Excel에 저장하고 해당 Excel 파일을 고객사 메일에 전송하는 코드
    • Cloud Insight를 통해 CPU, MEM, FileSystem( / )의 사용량을 조회할 서버: Server A, Server B 
    • API 응답 데이터는 test.xlsx에 저장
    • 해당 excel파일을 금일 날짜를 지정하여 다른이름으로 저장 후, 네이버 메일로 구글 메일 계정으로 전송
    • Cloud Insight API를 조회하고 싶은 시간을 코드 실행 시 입력하게 작성

 

etc-image-3etc-image-4

 

import time
import openpyxl
import smtplib
import hashlib
import hmac
import base64
import requests
import json
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

fpath = test.xlsx

wb = openpyxl.load_workbook(fpath)
ws = wb.active

t1 = input("ex)2022-12-07 09:00:00 형식으로 조회하고 싶은 시간을 입력해주세요")

# 입력받은 날짜와 시간 형식의 문자열을 datetime으로 변환
t2 = time.strptime(t1, '%Y-%m-%d %H:%M:%S')

# 입력받은 시간을 timestamp로 변환
input_time = time.mktime(t2)

print("Unix timestamp : ", input_time) 
print("Unix timestamp : ",int(input_time))

end = int(input_time) + 1
start = int(input_time)

# unix timestamp 설정
timestamp = int(time.time() * 1000)
timestamp = str(timestamp)

# Ncloud API Key 설정
ncloud_accesskey = "Access Key"
ncloud_secretkey = "Secert Key"

# 암호화 문자열 생성을 위한 기본값 설정
apicall_method = "POST"
space = " "
new_line = "\n"

# API 서버 정보
api_server = "https://cw.apigw.ntruss.com"

# API URL 서버 목록 조회
api_url = "/cw_fea/real/cw/api/data/query/multiple"


# hmac으로 암호화할 문자열 생성
message = apicall_method + space + api_url + new_line + str(timestamp) + new_line + ncloud_accesskey
message = bytes(message, 'UTF-8')

# hmac_sha256 암호화
ncloud_secretkey = bytes(ncloud_secretkey, 'UTF-8')
signingKey = base64.b64encode(hmac.new(ncloud_secretkey, message, digestmod=hashlib.sha256).digest())


# http 호출 헤더값 설정
http_header = {
    'Content-Type': 'application/json',
    'x-ncp-apigw-timestamp': str(timestamp),
    'x-ncp-iam-access-key': ncloud_accesskey,
    'x-ncp-apigw-signature-v2': signingKey
    }
#avg_cpu_used_rto 정보를 호출하는 payload
#응답을 원하는 서버를 metricInfoList에 인스턴스 번호로 저장

def request_cpu_API(end,start):
    payload_cpu = {
        "metricInfoList": [
            {
                "prodKey": "460438474722512896",
                "metric": "avg_cpu_used_rto",
                "interval": "Min1",
                "aggregation": "avg",
                "dimensions": {
                    "instanceNo": "Server Instance Number" #Server A
                }
            },
            {
            "prodKey": "460438474722512896",
                "metric": "avg_cpu_used_rto",
                "interval": "Min1",
                "aggregation": "avg",
                "dimensions": {
                    "instanceNo": "Server Instance Number" #Server B
                }   
            }
        ],
        "prodName":"System/Server(VPC)",
        "timeEnd": end,                                     #리소스 사용 정보를 시간별로 제공하기 때문에, 원하는 시간을 지정해야 함. 
        "timeStart": start                                     #timeStart, timeEnd로 원하는 시간을 지정하며, 해당 값은 timestamp값을 넣어줘야 함.
        }                                                           #현재 수기로 넣어 주고 있음. 현재 2022.12.06.09.00시로 설정되어 있음
    
    response = requests.post(api_server + api_url, headers=http_header,json=payload_cpu) #API request 호출하여 response 변수에 응답데이터 저장

    #print(type(response))                                              #최초 응답받은 데이터는 json형태로 출력은 해주지만 실제 json데이터는 아님.
    avg_cpu_used = json.loads(response.text)                            #응답 데이터를 별도의 변수에 json파일로 저장
    #print(type(avg_cpu_used))                                          #현재 자료형은 list
    #print(avg_cpu_used)                                                #list자료형에 key:value형태로 데이터 출력 확인
    return avg_cpu_used


avg_cpu_used_f = request_cpu_API(end, start)

row = 7
print("CPU : avg_cpu_used DATA")
for cpu in avg_cpu_used_f:
    print(cpu['dps'][0][1])
    ws[f'f{row}'] = round(float(cpu['dps'][0][1]), 2)
    row = row + 1

wb.save(fpath)

def request_mem_API(end,start):
    payload = {
        "metricInfoList": [
            {
                "prodKey": "460438474722512896",
                "metric": "mem_usert",
                "interval": "Min1",
                "aggregation": "avg",
                "dimensions": {
                    "instanceNo": "Server Instance Number" #Server A
                }
            },
            {
            "prodKey": "460438474722512896",
                "metric": "mem_usert",
                "interval": "Min1",
                "aggregation": "avg",
                "dimensions": {
                    "instanceNo": "Server Instance Number" #Server B
                }   
            }
        ],
        "prodName":"System/Server(VPC)",
        "timeEnd": end, 
        "timeStart": start
        } 

    response = requests.post(api_server + api_url, headers=http_header,json=payload)

    mem_usert = json.loads(response.text)
    return mem_usert

mem_usert_f = request_mem_API(end, start)

print("Memory : mem_usert DATA")
row = 7
for mem in mem_usert_f:
    print(mem['dps'][0][1])
    ws[f'g{row}'] = round(float(mem['dps'][0][1]), 2)
    row = row + 1

wb.save(fpath)

def request_fs_usert_root_API(end, start):
    payload = {
        "metricInfoList": [
            {
                "prodKey": "460438474722512896",
                "metric": "fs_usert",
                "interval": "Min1",
                "aggregation": "avg",
                "dimensions": {
                    "instanceNo": "Server Instance Number", #Server A
                    "mnt_nm": "/"
                }
            },
            {
            "prodKey": "460438474722512896",
                "metric": "fs_usert",
                "interval": "Min1",
                "aggregation": "avg",
                "dimensions": {
                    "instanceNo": "Server Instance Number", #Server B
                    "mnt_nm": "/"
                }   
            }
        ],
        "prodName":"System/Server(VPC)",
        "timeEnd": end, 
        "timeStart": start
        } 

    response = requests.post(api_server + api_url, headers=http_header,json=payload)

    fs_usert_root = json.loads(response.text)
    return fs_usert_root

fs_usert_root_f = request_fs_usert_root_API(end, start)


print("fs_usert : mnt: /")
row = 7
for fs_usert in fs_usert_root_f:
    print(fs_usert['dps'][0][1])
    ws[f'h{row}'] = round(float(fs_usert['dps'][0][1]), 2)
    row = row + 1

wb.save(fpath)

#저장된 엑셀파일 메일에 첨부하여 보내기.

#엑셀파일 파일명에 현재 날짜를 추가하여 다른이름으로 저장하기 위해 현재 날짜 호출
t3 = time.strftime('%Y%m%d', time.localtime(time.time()))
#엑셀 파일명에 현재 날짜 추가해서 저장
wb.save('test'+ '_' + t3 + '.xlsx')


file_name = 'test'+ '_' + t3 + '.xlsx'

# 다수 MIME를 사용하기 위한 MIMEMultipart객체 생성
msg = MIMEMultipart()
 
# msg객체에 "From": 보내는 사람 메일 주소, "To": 받는 사람 메일 주소, "Subject": 메일제목 저장
msg['From'] = '보내는 사람 메일 주소'
msg['To'] = '받는 사람 메일 주소'
msg['Subject'] = '파이썬 메일 전송 Test 메일'
 
# 메일 내용을 MIMEText 객체에 저장 
body = MIMEText('안녕하세요! Test 메일입니다.', _charset='utf-8')
 
# 작성한 메일 내용을 msg객체에 추가
msg.attach(body)
 
# 현재까지 메일 송신자/수신자/제목/본문 내용이 msg객체에 저장(기본 메일 형식)
 
# Excel 파일 첨부
# 첨부하려는 파일을 r=read mode, b=바이너리 파일 모드로 열고, MIMEApplication객체에 read()함수를 사용하여 내용 저장
with open(file_name, 'rb') as excel_file : 
    excel_attachment = MIMEApplication( excel_file.read() )
    #첨부파일의 정보를 헤더로 추가
    excel_attachment.add_header('Content-Disposition','attachment', filename=file_name) 
    # msg 객체에 첨부파일 내용 추가
    msg.attach(excel_attachment)
 
# smtp라이브러리를 사용하여 메일 전송
 
# Test 메일 발송을 위하여 네이버 메일 사용(네이버 메일에서 별도 설정 필요)
# 사용하려는 메일의 smtp주소 지정
mailServer = smtplib.SMTP_SSL('smtp.naver.com')
 
#메일 서버 로그인(아이디 / 계정)
mailServer.login('메일 주소', '비밀 번호')
 
# 위에 만든 msg객체를 send_message()함수를 통해 발송
mailServer.send_message(msg)
# 메일 발송 후 메일 서버 접속 종료
mailServer.quit()

 

 결론

 

요즘 "Python을 통한 업무 자동화"라는 문장을 많이 들어봤다. 처음으로 반복적인 작업에 대해서 자동화 구성을 해봤고 나름 너무 뿌듯했다. 개발은 처음이라 코드 내용이 많이 부족하고 Error 핸들링도 작성하지 못하였다.

 

또한 실제로 작성된 코드는 위에 작성한 코드와는 상이한 부분이 많다.

 

1. Cloud Insight를 통해 조회해야 하는 서버 목록 수 - 15EA

따라서 API를 호출하는 코드의 Body 내용이 너무 길어졌다. 때문에 각 API 호출을 각 각 모듈로 구성하여 Main 함수에서 해당 모듈을 호출하여 사용하는 방식으로 구성하였다.

 

2. 메일 송부 시 개인 메일 계정이 아니라 회사 메일 계정을 사용해야 했다. 일반적으로 사용하는 Naver, Google에 대한 제어는 직접 제어 할 수 있었으나 회사 메일은 관리자가 따로 있기 때문에 어려운 부분이 있었다.

결론적으로 우리 회사 메일 smtp서버의 경우 인증을 아이디/패스워드가 아닌 IP를 통해 진행하고 있엇다.

따라서 해당 코드를 외부에서 실행할 경우 회사 메일을 통한 자동화는 할 수 없었다.

 

3. 위에 작성된 코드는 내가 조회를 원하는 시간을 직접 입력하는 방식이다. 하지만 실제는 매일, 오전 09:00 서버의 자원 사용량을 조회를 해야 한다. 따라서 직접 입력이 아닌, 코드가 실행 될 때 해당 날짜를 불러오고, 오전 09:00를 지정하여 해당 날짜의 지정한 시간을 조회하는 시간으로 설정하게 하였다.

 

4. 사람의 개입 없이 프로그램이 실행되어 조회, 저장, 메일 송부까지 자동화가 되어야 한다. 작성한 코드를 실행파일로 만든 후, Windows 작업 스케줄러에 등록하여 반복적으로 자동으로 프로그램이 실행되게 설정하였다.

 

처음하는 개발이라 많은 시간이 들었고, 어려운 부분이 많았다.

앞으로는 더 많은 네이버 클라우드 API를 사용하고, 자동화하여 효율적인 업무를 할 수 있도록 공부하고 또 공부해야겠다.

 

728x90