콘텐츠로 이동

Alibaba Cloud API 서명 문제 해결을 통한 청구 분석 구현


여러 퍼블릭 클라우드 리소스를 구매하는 것과 프라이빗 호스트를 조달하는 것은 비용 측면에서 인식이 크게 다릅니다. 프라이빗 호스트를 조달하는 것은 일회성 투자로, 구매 후 사용 여부나 사용 성과가后续 투자에 지속적인 영향을 미치지 않습니다. 반면 퍼블릭 클라우드 리소스를 구매할 때는 항상 상기해야 합니다: 초기 투자는 적지만, 하루가 지날 때마다 그만큼의 비용이 발생합니다. 따라서 여러 클라우드 리소스에 대한 비용 지출 내역과 청구 분석을 한눈에 파악할 수 있는 방법이 절실히 필요합니다.

Alibaba Cloud 비용 API 수집

먼저 Alibaba Cloud 청구서를 예로 들어, Alibaba Cloud의 비용 청구서 정보를 수집하여 분석하려면 거래 및 청구 관리 API에 대한 충분한 이해가 필요합니다. Alibaba Cloud API를 호출할 때 가장 골치 아픈 부분은 API의 서명(Signature) 메커니즘입니다. Alibaba Cloud는 일반 문서에도 별도 설명이 있지만, 서명 메커니즘에 대한 설명 문서만 제공되어 경험이 부족한 개발자에게는 어려움을 줍니다. 그렇다면 이 불완전한 설명 문서를 바탕으로 어떻게 청구 비용을 수집할 수 있을까요?

API 요청 원리

간단히 말해 Alibaba Cloud API를 호출하는 것은 HTTP 요청(대부분 GET, 여기서도 GET 요청 기준)이며, 뒤에 여러 매개변수가 붙습니다. 예를 들어 스냅샷을 조회하는 요청은 다음과 같습니다:

http://ecs.aliyuncs.com/?SignatureVersion=1.0&Format=JSON&Timestamp=2017-08-07T05%3A50%3A57Z&RegionId=cn-hongkong&AccessKeyId=xxxxxxxxx&SignatureMethod=HMAC-SHA1&Version=2017-12-14&Signature=%2FeGgFfxxxxxtZ2w1FLt8%3D&Action=DescribeSnapshots&SignatureNonce=b5046ef2-7b2b-11e7-a3c5-00163e001831&ZoneId=cn-hongkong-b

요청에 필요한 공통 매개변수(API 호출 시 항상 필요한 매개변수)는 다음과 같습니다:

SignatureVersion # 서명 알고리즘 버전, 현재 1.0
Format # 응답 메시지 형식, JSON 또는 XML, 기본값은 XML
Timestamp # 요청 타임스탬프, UTC 시간, 예: 2021-12-16T12:00:00Z
AccessKeyId # 계정 키 ID
SignatureMethod # 서명 방식, 현재 HMAC-SHA1
Version # 버전 번호, 날짜 형식, 예: 2017-12-14, 제품마다 다름
Signature # 가장 까다로운 서명
SignatureNonce # 고유 난수, 네트워크 공격 방지. 요청 간에 서로 다른 난수 사용

Signature 외에는 다른 매개변수는 비교적 쉽게 얻을 수 있으며, 일부는 고정된 값입니다. 자세한 내용은 Alibaba Cloud 문서를 참조하세요.
공통 매개변수 외에도 특정 인터페이스(Action)의 요청 매개변수가 필요합니다. 각 Action 인터페이스의 매개변수는 해당 제품의 인터페이스 문서를 참조하세요. 예: QuerySettleBill
Signature는 공통 매개변수와 인터페이스 매개변수를 기반으로 하므로 더 복잡합니다.

표준화된 요청 문자열 구성

  • dict 구성
    Python에서 매개변수의 일대일 대응을 나타내는 것은 dict입니다. dict를 생성하고 요청 매개변수를 입력합니다.
D = {
    'BillingCycle':str(time.strftime("%Y-%m", time.gmtime())),
    'Action':'QuerySettleBill',
    # 'PageNum':'5',
    'Format':'JSON',
    'Version':'2017-12-14',
    'AccessKeyId':'LTAI5tLumx55Vui4WJwZJneK',
    'SignatureMethod':'HMAC-SHA1',
    'MaxResults' : '300',
    # 'NextToken':"", #?
    'Timestamp':str(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())),
    'SignatureVersion':'1.0'
    # 'SignatureNonce':str_seed
}
  • 정렬
    서명은 순서를 포함한 고유성을 요구하므로 매개변수 이름별로 정렬해야 합니다.
  # 서명은 순서를 포함한 고유성을 요구하므로 매개변수 이름별로 정렬
        sortedD = sorted(D.items(),key=lambda x: x[0])
  • URL 인코딩
    표준 요청 문자열에서 UTF-8 문자 집합을 사용해야 하므로, 요청 매개변수 이름과 값에 규격에 맞지 않는 문자가 있으면 URL 인코딩을 수행해야 합니다. 구체적인 규칙은 다음과 같습니다:

문자 AZ, az, 0~9 및 문자 "-", "_", ".", "~"는 인코딩하지 않음;
기타 문자는 %XY 형식으로 인코딩하며, XY는 문자에 해당하는 ASCII 코드의 16진수 표현입니다. 예를 들어 영어 큰따옴표(")의 인코딩은 %22입니다.
확장 UTF-8 문자의 경우 %XY%ZA… 형식으로 인코딩합니다.
영어 공백( )은 %20으로 인코딩하며, 더하기(+)가 아닙니다.

참고: 일반적으로 URL 인코딩을 지원하는 라이브러리(예: Java의 java.net.URLEncoder)는 "application/x-www-form-urlencoded" MIME 유형 규칙에 따라 인코딩합니다. 구현 시 이러한 방식을 직접 사용하여 인코딩한 후, 인코딩된 문자열에서 더하기(+)를 %20으로, 별표(*)를 %2A로, %7E를 물결표(~)로 바꾸면 위 규칙에 설명된 인코딩 문자열을 얻을 수 있습니다.

여기서는 Python의 urllib 라이브러리를 사용하여 인코딩합니다:

# Python의 urllib 라이브러리를 사용하여 인코딩
def percentEncode(str):
    res = urllib.parse.quote(str.encode('utf8'), '')
    res = res.replace('+', '%20')
    res = res.replace('*', '%2A')
    res = res.replace('%7E', '~')
    return res
  • 표준화된 요청 문자열 생성
# 표준화된 요청 문자열 생성
canstring = ''
for k,v in sortedD:
    canstring += '&' + percentEncode(k) + '=' + percentEncode(v)

서명 대상 문자열 StringToSign 구성

규칙은 다음과 같습니다:

StringToSign=
HTTPMethod + "&" +
percentEncode("/") + "&" +
percentEncode(CanonicalizedQueryString)

따라서 이 예제에서는:

        # 표준화된 요청 문자열 생성
        stringToSign = 'GET&%2F&' + percentEncode(canstring[1:])

HMAC 값 계산

# access_key_secret
access_key_secret = '<access_key_secret>'
# HMAC 값 계산
h = hmac.new((access_key_secret + "&").encode('utf8'), stringToSign.encode('utf8'), sha1)

서명 값 계산

# 서명 값 계산하여 signature 서명 생성
signature = base64.encodestring(h.digest()).strip()
여기까지 signature 서명이 생성되었습니다.

서명 추가

# 서명 추가
D['Signature'] = signature

따라서 이 예제에서 최종 요청 URL은 다음과 같습니다:

# 최종 API 호출
url = 'http://business.aliyuncs.com/?' + urllib.parse.urlencode(D)
http://business.aliyuncs.com/?BillingCycle=2021-12&Action=QuerySettleBill&Format=JSON&Version=2017-12-14&AccessKeyId=LTAI5tLumx55Vui4WJwZJneK&SignatureMethod=HMAC-SHA1&MaxResults=300&Timestamp=2021-12-16T12%3A27%3A58Z&SignatureVersion=1.0&SignatureNonce=0.30196531140307337&NextToken=&Signature=zFb4631sSGONvAeWD3xCIovMeoM%3D

브라우저에서 직접 접속하면 결과를 얻을 수 있습니다:

image.png

전체 예제

import sys, datetime
import time
import json
import urllib
import hmac
from hashlib import sha1
import base64
import random
import requests


# 요청에 필요한 공통 매개변수(API 호출 시 항상 필요한 매개변수)
D = {
    'BillingCycle':str(time.strftime("%Y-%m", time.gmtime())),
    'Action':'QuerySettleBill',
    # 'PageNum':'5',
    'Format':'JSON',
    'Version':'2017-12-14',
    'AccessKeyId':'<AccessKeyId>',
    'SignatureMethod':'HMAC-SHA1',
    'MaxResults' : '300',
    # 'NextToken':"", #?
    'Timestamp':str(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())),
    'SignatureVersion':'1.0'
    # 'SignatureNonce':str_seed
}
# 현재 시간
now_time = str(time.strftime("%Y-%m-%d", time.gmtime()))

# 로컬 DataKit 연결
datakit = DFF.SRC('datakit')

# Python의 urllib 라이브러리를 사용하여 인코딩
def percentEncode(str):
        res = urllib.parse.quote(str.encode('utf8'), '')
        res = res.replace('+', '%20')
        res = res.replace('*', '%2A')
        res = res.replace('%7E', '~')
        return res


# 청구서 가져오기
def getBill():
    # 청구서 현재 레코드 위치
    next_token = ""
    # 반복하여 청구서를 DataKit에 쓰기
    for i in range(10000):
        random.seed()
        # 고유 난수, 네트워크 재전송 공격 방지. 요청 간에 서로 다른 난수 값 사용
        D["SignatureNonce"] = str(random.random())
        D["NextToken"] = next_token
        # 서명은 순서를 포함한 고유성을 요구하므로 매개변수 이름별로 정렬
        sortedD = sorted(D.items(),key=lambda x: x[0])
        # 표준화된 요청 문자열 생성
        canstring = ''
        for k,v in sortedD:
            canstring += '&' + percentEncode(k) + '=' + percentEncode(v)
        # 표준화된 요청 문자열 생성
        stringToSign = 'GET&%2F&' + percentEncode(canstring[1:])
        # access_key_secret
        access_key_secret = '<access_key_secret>'
        # HMAC 값 계산
        h = hmac.new((access_key_secret + "&").encode('utf8'), stringToSign.encode('utf8'), sha1)
        # 서명 값 계산하여 signature 서명 생성
        signature = base64.encodestring(h.digest()).strip()
        # 서명 추가
        D['Signature'] = signature
        # 최종 API 호출
        url = 'http://business.aliyuncs.com/?' + urllib.parse.urlencode(D)
        # Alibaba Cloud 청구 비용 요청
        print(url)

기술 경로 선택

아키텍처 구상

image.png

Crontab으로 Python 스크립트를 정기적으로 스케줄링하여 Alibaba Cloud 청구 데이터를 가져와 MySQL 스토리지 엔진에 쓰고, Grafana를 통해 청구 분석 데이터를 표시하는 방식을 채택합니다. Grafana Dashboards에서 적절한 Bills 템플릿을 가져와 작업을 간소화할 수 있습니다. 아래에서는 이 아키텍처 구상을 바탕으로 기술 조사를 진행합니다.

기술 조사

현재 오픈소스 시각화 분야에서 가장 인기 있고 시각화 템플릿이 많은 것은 Grafana입니다. Kibana도 훌륭한 시각화 플랫폼이지만, Grafana에 비해 Kibana는 ELK 아키텍처에 더 적합합니다. 우리의 요구 사항을 고려하면 Kibana는 적합하지 않습니다. Grafana는 다양한 데이터 스토리지에서 사용할 수 있는 오픈소스 시각화 도구로, Graphite-web의 풍부한 기능을 대체하며 대시보드를 쉽게 생성하고 편집할 수 있습니다. 고유한 Graphite 대상 파서를 포함하여 메트릭 및 기능 편집을 쉽게 수행할 수 있습니다. 사용자는 스마트 축 형식(예: 선 및 점)을 사용하여 종합적인 차트를 만들 수 있습니다. 또한 Grafana에는 내장 알림 엔진이 있어 대시보드 패널에 조건 규칙을 연결하고 선택한 알림 엔드포인트(예: 이메일, Slack, PagerDuty, 사용자 정의 Webhooks)로 알림을 보낼 수 있습니다. 이는 Alibaba Cloud 비용에 대한 경보 요구 사항을 충족하지만, Grafana는 CPU, 메모리, 디스크 및 I/O 사용률과 같은 메트릭을 분석 및 시각화하도록 설계되었습니다. Grafana는 전문 데이터 쿼리를 허용하지 않아 사용자 경험이 좋지 않습니다. 오픈소스 커뮤니티를 탐색하던 중 “Guance” 제품이 이 요구 사항을 충족하며, Grafana와 Kibana의 모든 장점을 포함할 뿐만 아니라 많은 고유 기능과 Serverless 온라인 프로그래밍 스케줄링 기능을 제공하여 Python 스크립트로 Alibaba Cloud 청구 데이터를 가져올 때 스케줄링 관리 문제를 해결한다는 것을 발견했습니다. 또한 오픈소스 상용 제품으로서 UI의 미적 측면에서 Grafana를 훨씬 능가하며, 제공하는 무료 할당량이 우리의 요구를 충족시키고 문제 발생 시 공식 제품 지원을 받을 수 있습니다.

기술 비교

Grafana Guance
사용 복잡도 설치 및 구성이 번거롭고 추가 스토리지 엔진 필요 한 줄 명령으로 설치, 30분 내 즉시 사용 가능
문서 완성도 Grafana 공식 사이트에 완벽한 문서가 있지만, 중국어 문서가 적어 영어에 익숙하지 않은 사용자에게는 문제가 될 수 있음 매우 완벽한 중국어 문서와 많은 사용 사례 가이드 및 강좌 제공
커뮤니티 활동성 커뮤니티 활발, 개발 및 유지보수 팀 강력, 버전 업그레이드 및 반복 빠름 상용 제품, 커뮤니티 매우 활발, 개발 및 유지보수 팀 강력, 문제 해결 빠름, 버전 업그레이드 및 반복 빠름
기능 완성도 54개 데이터 소스, 173+ 대시보드, 히트맵, 라인 차트, 그래프 등 다양한 표시 방식을 갖춘 풍부한 대시보드 플러그인, 간단한 알림 지원 200+ 데이터 소스, 200+ 대시보드, 다양한 운영 체제 지원, 표준 통합 DQL 쿼리로 다양한 데이터 유형 지원, 메트릭 데이터, 로그 데이터, APM 데이터, 인프라, 컨테이너, 미들웨어, 네트워크 성능을 통합 관리, 강력한 이상 탐지 기능 및 고급 권한 기능, 복잡한 알림 규칙 구성 지원
발전 추세 시장 점유율 상승 추세, 자체 발전 및 개선 중 성숙한 상용 제품, 관측 가능성 분야 선두주자, 시장 점유율 상승 추세, 자체 발전 및 개선 중
성능 리소스 사용량 낮음 통합 관리, 리소스 사용량 낮음, 데이터가 바이너리 파일로 전송 효율 높고 대역폭 사용량 낮음
Serverless 프로그래밍 없음 Python 3.x 기반 샌드박스 환경
비용 무료 무료
서비스 커뮤니티 지원 전문 기술 팀 지원 제공

요구 사항 매칭

위 비교를 통해 “Guance”을 사용하면 사용 비용을 크게 낮출 수 있고 설치 및 구성 관리가 매우 편리하다는 것을 알 수 있습니다. Grafana가 단순히 표시 플랫폼으로서 외부 스토리지 엔진을 데이터 소스로 의존해야 하는 반면, “Guance”은 메트릭 데이터, 로그 데이터, APM 데이터, 인프라, 컨테이너, 미들웨어, 네트워크 성능 등 다양한 데이터를 통합 수집 및 관리하여 스토리지 엔진 설치 및 유지보수의 번거로운 단계를 줄여줍니다. Grafana는 완벽한 중국어 문서가 없어 영어에 능숙하지 않은 사용자에게는 어려움이 있을 수 있지만, Guance은 완벽한 중국어 문서와 많은 사용 사례 가이드 비디오를 제공하여 제품 사용을 더 쉽게 시작할 수 있고 요구 사항 자체에 집중할 수 있습니다. “Guance”은 상용 제품으로서 무료로 사용하더라도 전문 기술 팀의 지원을 받을 수 있으며, 방대한 커뮤니티를 통해 많은 제품 사용자와 경험을 공유할 수 있습니다. 기능적으로는 Grafana보다 이상 탐지 기능이 강력하고, 고급 권한 기능 및 복잡한 알림 규칙 구성을 지원하여 비용 분석 외 다른 요구 사항도 잘 구현할 수 있습니다. 또한 “Guance”은 구성 요소를 시각적으로 통합 관리할 수 있으며, 리소스 사용량이 낮고 데이터가 바이너리 파일로 전송 효율이 높으며 대역폭 사용량이 낮습니다. 또한 UI 디자인 측면에서 “Guance”은 눈에 띄는 미니멀리즘 스타일을 제공하므로, 우리의 요구 사항에 맞게 “Guance”을 통해 구축하는 것이 적합합니다.

Guance으로 비용 관리 구현

배포 설명

예제 Linux 버전: CentOS Linux release 7.8.2003 (Core)

한 대의 서버를 통해 모든 Alibaba Cloud 청구 비용 데이터 수집

전제 조건

DataKit 설치

“Guance”으로 호스트를 모니터링하려면 먼저 DataKit을 설치해야 합니다. DataKit은 공식 데이터 수집 애플리케이션으로, 수백 가지 데이터 수집을 지원합니다. 수집 소스를 구성하면 호스트, 프로세스, 컨테이너, 로그, 애플리케이션 성능, 사용자 액세스 등 다양한 데이터를 실시간으로 수집할 수 있습니다.

DataKit 설치를 시작하기 전에 먼저 “Guance” 계정을 등록해야 합니다. 등록 완료 후 Guance 워크스페이스에 로그인하면 DataKit 설치 명령어를 확인하고 첫 번째 DataKit을 배포할 수 있습니다.

설치 명령어 가져오기

Guance 워크스페이스에 로그인하여 「통합」-「DataKit」을 차례로 클릭하고 DataKit 설치 방식을 선택한 후, 아래 정보를 확인하고 「설치 명령어」를 복사하여 호스트에서 실행합니다.

  • 설치 시스템: Linux

  • 시스템 유형: X86 amd64

  • DataWay 주소: OpenWay

image.png

호스트에서 설치 명령어 실행

명령줄 터미널을 열고 서버에 로그인한 후 복사한 「설치 명령어」를 실행합니다. 설치가 완료되면 Install Success 메시지가 표시되며, DataKit 설치 결과에서 제공하는 링크를 통해 DataKit의 설치 상태, 매뉴얼 및 업데이트 기록을 확인할 수 있습니다.

2.설치 datakit.png

“Guance” 사용 시작

DataKit이 성공적으로 설치되면 호스트 객체 수집기 hostobject가 기본적으로 활성화됩니다. 그러면 Guance 워크스페이스의 「인프라」-「호스트」에서 방금 DataKit을 설치한 호스트를 확인할 수 있습니다. 호스트 상태, 호스트 이름, 운영 체제, CPU 사용률, MEM 사용률, CPU 단일 코어 부하 등을 확인할 수 있으며, 호스트를 클릭하여 더 많은 세부 정보를 볼 수도 있습니다.

4.호스트 확인.png

Func 휴대용 버전 설치

시스템 및 환경 요구 사항

DataFlux Func를 실행하는 호스트는 다음 조건을 충족해야 합니다:

  • CPU 코어 수 >= 2

  • 메모리 용량 >= 4GB

  • 디스크 공간 >= 20GB

  • 네트워크 대역폭 >= 10 Mbps

  • 운영 체제: Ubuntu 16.04 LTS/CentOS 7.2 이상

  • 깨끗한 시스템(운영 체제 설치 후 네트워크 구성 외에 다른 작업을 수행하지 않은 상태)

  • 8088 포트 개방(본 시스템은 기본적으로 8088 포트 사용, 방화벽, 보안 그룹 등에서 8088 인바운드 액세스를 허용하는지 확인)

  • 외부 MySQL 사용 시 MySQL 버전 5.7 이상

  • 외부 Redis 사용 시 Redis 버전 4.0 이상

참고: DataFlux Func는 MacOS, Windows를 지원하지 않습니다. 가상 머신, 클라우드 호스트에서 DataFlux Func를 설치할 수 있습니다.

참고: DataFlux Func는 클러스터형 Redis를 지원하지 않습니다. 고가용성이 필요하면 마스터-슬레이브 버전을 선택하세요.

참고: Alibaba Cloud ECS에 DataFlux Func를 설치하고 Alibaba Cloud Shield 플러그인이 활성화된 경우, Cloud Shield 자체가 많은 리소스를 사용하므로 시스템 구성을 적절히 높여야 합니다.

휴대용 버전 다운로드 명령어
/bin/bash -c "$(curl -fsSL https://t.guance.com/func-portable-download)"

참고: 본 문서의 모든 셸 명령어는 root 사용자에서 직접 실행 가능하며, 비-root 사용자에서는 sudo를 추가하여 실행해야 합니다.

참고: 본 문서는 가장 일반적인 작업 단계만 제공합니다. 자세한 설치 및 배포는 「유지보수 매뉴얼」을 참조하세요.

자동 설치 스크립트로 설치 실행

다운로드한 dataflux-func-portable 디렉토리에서,
다음 명령어를 실행하면 자동으로 구성되고 DataFlux Func 전체가 시작됩니다:

참고: 설치 전 시스템 요구 사항과 서버 구성을 확인하세요.

참고: DataFlux Func는 Mac을 지원하지 않습니다. Linux 시스템에 복사하여 설치를 실행하세요.

sudo /bin/bash run-portable.sh

자동 설치 스크립트를 사용하면 몇 분 내에 빠르게 설치 및 실행할 수 있으며, 자동 구성 내용은 다음과 같습니다:

  • MySQL, Redis, DataFlux Func(Server, Worker, Beat 포함) 실행

  • 모든 데이터를 /usr/local/dataflux-func/ 디렉토리에 자동 생성 및 저장(MySQL 데이터, Redis 데이터, DataFlux Func 구성, 로그 등 파일 포함)

  • MySQL root 사용자 비밀번호, 시스템 Secret을 무작위로 생성하고 DataFlux Func 구성 파일에 저장

  • Redis는 비밀번호 미설정

  • MySQL, Redis는 외부 액세스 미제공

실행 완료 후 브라우저에서 http://{서버 IP 주소/도메인}:8088에 접속하여 초기화 작업 인터페이스를 진행할 수 있습니다.

참고: 실행 환경 성능이 낮은 경우 docker ps 명령어로 모든 구성 요소가 성공적으로 시작되었는지 확인한 후에 접속하세요(아래 목록 참조).

  1. dataflux-func_mysql

  2. dataflux-func_redis

  3. dataflux-func_server

  4. dataflux-func_worker-0

  5. dataflux-func_worker-1-6

  6. dataflux-func_worker-7

  7. dataflux-func_worker-8-9

  8. dataflux-func_beat

RAM 액세스 제어 가져오기

  1. RAM 콘솔에 로그인 https://ram.console.aliyun.com/users

  2. 새 사용자 생성: 인사 관리 - 사용자 - 사용자 생성 image.png

  3. AccessKeyIDAccessKey Secret의 CSV 파일을 저장하거나 다운로드합니다(구성 파일에서 사용됨).

  4. 사용자 권한 부여(청구 권한)

구성 구현

DataFlux Function에 로그인

Func에 로그인, 주소 http://ip:8088(기본 admin/admin)

스크립트 세트 생성

제목/설명 정보 입력

image.png

스크립트 편집

스크립트를 작성하여 청구 데이터를 DataKit에 쓰고 보고서 생성을 준비합니다.

전체 스크립트는 다음과 같습니다:

import sys, datetime
import time
import json
import urllib
import hmac
from hashlib import sha1
import base64
import random
import requests


# 요청에 필요한 공통 매개변수(API 호출 시 항상 필요한 매개변수)
D = {
    'BillingCycle':str(time.strftime("%Y-%m", time.gmtime())),
    'Action':'QuerySettleBill',
    # 'PageNum':'5',
    'Format':'JSON',
    'Version':'2017-12-14',
    'AccessKeyId':'<AccessKeyId>',
    'SignatureMethod':'HMAC-SHA1',
    'MaxResults' : '300',
    # 'NextToken':"", #?
    'Timestamp':str(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())),
    'SignatureVersion':'1.0'
    # 'SignatureNonce':str_seed
}
# 현재 시간
now_time = str(time.strftime("%Y-%m-%d", time.gmtime()))

# 로컬 DataKit 연결
datakit = DFF.SRC('datakit')

# Python의 urllib 라이브러리를 사용하여 인코딩
def percentEncode(str):
        res = urllib.parse.quote(str.encode('utf8'), '')
        res = res.replace('+', '%20')
        res = res.replace('*', '%2A')
        res = res.replace('%7E', '~')
        return res


# 청구서 가져오기
@DFF.API('getBill')
def getBill():
    # 청구서 현재 레코드 위치
    next_token = ""
    # 반복하여 청구서를 DataKit에 쓰기
    for i in range(10000):
        random.seed()
        # 고유 난수, 네트워크 재전송 공격 방지. 요청 간에 서로 다른 난수 값 사용
        D["SignatureNonce"] = str(random.random())
        D["NextToken"] = next_token
        # 서명은 순서를 포함한 고유성을 요구하므로 매개변수 이름별로 정렬
        sortedD = sorted(D.items(),key=lambda x: x[0])
        canstring = ''
        for k,v in sortedD:
            canstring += '&' + percentEncode(k) + '=' + percentEncode(v)
        # 표준화된 요청 문자열 생성
        stringToSign = 'GET&%2F&' + percentEncode(canstring[1:])
        # access_key_secret
        access_key_secret = '<access_key_secret>'
        # HMAC 값 계산
        h = hmac.new((access_key_secret + "&").encode('utf8'), stringToSign.encode('utf8'), sha1)
        # 서명 값 계산하여 signature 서명 생성
        signature = base64.encodestring(h.digest()).strip()
        # 서명 추가
        D['Signature'] = signature
        # 최종 API 호출
        url = 'http://business.aliyuncs.com/?' + urllib.parse.urlencode(D)
        # Alibaba Cloud 청구 비용 요청
        response = requests.get(url)
        billing_cycle = response.json()["Data"]["BillingCycle"]
        account_id = response.json()["Data"]["AccountID"]
        next_token = response.json()["Data"]["NextToken"]
        if next_token is not None:
            bill = response.json()["Data"]["Items"]["Item"]
            print(bill)
            # 당일 청구서를 Guance에 쓰기
            for i in bill:
                print(i["UsageEndTime"])
                time = i["UsageEndTime"].split(" ")[0]
                print(time,now_time)
                if time == now_time:
                    measurement = "aliyunSettleBill"
                    tags = {
                        "BillingCycle":billing_cycle,
                        "AccountID":account_id
                    }
                    fields = {
                        "ProductName":i["ProductName"],
                        "SubOrderId":i["SubOrderId"],
                        "BillAccountID":i["BillAccountID"],
                        "DeductedByCashCoupons":i["DeductedByCashCoupons"],
                        "PaymentTime":i["PaymentTime"],
                        "PaymentAmount":i["PaymentAmount"],
                        "DeductedByPrepaidCard":i["DeductedByPrepaidCard"],
                        "InvoiceDiscount":i["InvoiceDiscount"],
                        "UsageEndTime":i["UsageEndTime"],
                        "Item":i["Item"],
                        "SubscriptionType":i["SubscriptionType"],
                        "PretaxGrossAmount":i["PretaxGrossAmount"],
                        "Currency":i["Currency"],
                        "CommodityCode":i["CommodityCode"],
                        "UsageStartTime":i["UsageStartTime"],
                        "AdjustAmount":i["AdjustAmount"],
                        "Status":i["Status"],
                        "DeductedByCoupons":i["DeductedByCoupons"],
                        "RoundDownDiscount":i["RoundDownDiscount"],
                        "ProductDetail":i["ProductDetail"],
                        "ProductCode":i["ProductCode"],
                        "ProductType":i["ProductType"],
                        "OutstandingAmount":i["OutstandingAmount"],
                        "BizType":i["BizType"], 
                        "PipCode":i["PipCode"],
                        "PretaxAmount":i["PretaxAmount"],
                        "OwnerID":i["OwnerID"],
                        "BillAccountName":i["BillAccountName"],
                        "RecordID":i["RecordID"],
                        "CashAmount":i["CashAmount"],
                    }
                    try:
                        status_code, result = datakit.write_logging(measurement=measurement, tags=tags, fields=fields)
                        print(status_code,result)
                    except:
                        print("삽입 실패!")
                else:
                    break
            else:
                continue
            break
        else:
            break

스크립트 게시

저장 후 구성 및 게시

image.png

예약 작업 생성

자동 트리거 작업 추가: 관리 - 자동 트리거 구성 - 새 작업 생성. 청구서는 일일 청구서이므로 수집 빈도는 하루 한 번으로 설정하면 됩니다.

image.png

업로드된 데이터 확인

로그 미리보기

image.png

탐색기 생성

탐색기 가져오기

image.png

문서 평가

이 페이지가 도움이 되었나요?