【阿里云API】 阿里云API调用的若干说明
阿里云API
為了監(jiān)控我們使用的一些阿里云產(chǎn)品,需要些一些腳本,定時(shí)調(diào)用這些腳本來(lái)獲得相關(guān)阿里云產(chǎn)品的信息。
■ 概述
調(diào)用阿里云API大約分成兩類(lèi)方法,一個(gè)是直接從HTTP協(xié)議開(kāi)始,自己根據(jù)阿里云的規(guī)則進(jìn)行URL的編寫(xiě)然后發(fā)起請(qǐng)求,獲得回應(yīng)。這種方法比較繁瑣(阿里云API的校驗(yàn)挺復(fù)雜的,昨天寫(xiě)了一晚上才成功寫(xiě)出對(duì)的URL)。另一種方法是利用阿里云提供的SDK(有多種語(yǔ)言的SDK,比如java,python,php等等),比如之前就有用過(guò)SDK來(lái)編寫(xiě)腳本監(jiān)控RDS。下面從這兩種方法來(lái)分別說(shuō)明阿里云API的使用方法。
貼出阿里云官方API說(shuō)明資料:
總體調(diào)用方式說(shuō)明:【https://help.aliyun.com/document_detail/28616.html?spm=5176.doc51936.6.635.7Gl897】
資源監(jiān)控接口說(shuō)明:【https://help.aliyun.com/document_detail/51936.html?spm=5176.doc28616.6.637.6sm7b1】
預(yù)設(shè)監(jiān)控項(xiàng)說(shuō)明:【https://help.aliyun.com/document_detail/28619.html?spm=5176.doc51936.6.650.rpFTYc】
■ 用SDK調(diào)用API
其實(shí)對(duì)SDK的研究還沒(méi)有很深入,基本上是對(duì)之前的人留下來(lái)的腳本的一個(gè)觀摩分析,然后依葫蘆畫(huà)瓢。這里主要說(shuō)明python的SDK。pythonSDK的使用手冊(cè)【https://help.aliyun.com/document_detail/28622.html?spm=5176.doc28619.6.653.EIfwUD】
其實(shí)官網(wǎng)上說(shuō)得也很清楚了。。
安裝:
pip install aliyun-python-sdk-core pip install aliyun-python-sdk-cms安裝完成之后,來(lái)看一下如何使用;
#!/usr/bin/env python #coding=utf-8from aliyunsdkcore import client #客戶類(lèi),其實(shí)叫account感覺(jué)更加合理,因?yàn)樗蔷S護(hù)accessKeyId和secretKeyId的對(duì)象 from aliyunsdkcms.request.v20170301 import QueryMetricListRequest #QueryMetricList是阿里云方面規(guī)定的一個(gè)名字,意思是要獲取多條監(jiān)控?cái)?shù)據(jù)的請(qǐng)求 import jsonclt = client.AcsClient('access_key_id','secret_key_id','cn-hangzhou')#構(gòu)建客戶對(duì)象時(shí)需要一明一暗兩個(gè)KEY,然后第三個(gè)參數(shù)可以參見(jiàn)“調(diào)用方式”那個(gè)網(wǎng)頁(yè)上上面的各個(gè)物理區(qū)域的代碼,比如cn-hangzhou,cn-hongkong,us-west-1等等 request = QueryMetricListRequest.QueryMetricListRequest()
#===========================================================
#下面就是設(shè)置request中的各種參數(shù),有可能沒(méi)有涵蓋所有的方法,不過(guò)也都大同小異,值得一提的是,可以看到所有參數(shù)都是字符串,即便是dimension本來(lái)是一個(gè)字典,
#period本來(lái)是一個(gè)數(shù)字,兩個(gè)time本來(lái)是時(shí)間對(duì)象,都要轉(zhuǎn)化成相關(guān)的字符串
#=========================================================== request.set_accept_format('JSON') request.set_Project('acs_slb_dashboard') request.set_Metric('ActiveConnection') request.set_StartTime('2017-08-09 11:00:00') request.set_EndTime('2017-08-09 11:10:00') request.set_Dimensions(str({'instanceId':'instance_id','port':'port'})) request.set_Period('60')res = json.loads(clt.do_action_with_exception(request)) #選擇with_exception的話出錯(cuò)是以raise Exception的形式報(bào)出的,否則就是返回的res是錯(cuò)誤碼和錯(cuò)誤信息這樣子。 print json.dumps(res,indent=4)
如果你是第一次接觸阿里云API,很可能會(huì)覺(jué)得一臉懵逼。主要是針對(duì)各個(gè)參數(shù)的意義還不明確,對(duì)各個(gè)參數(shù)意義及格式規(guī)定的解說(shuō)放在下面,直接用HTTP請(qǐng)求來(lái)調(diào)用API的章節(jié)里面。
?
■ 通過(guò)HTTP請(qǐng)求調(diào)用API
其實(shí)用SDK當(dāng)然也是通過(guò)HTTP請(qǐng)求來(lái)調(diào)用的API,這里的通過(guò)HTTP請(qǐng)求是指沒(méi)有任何包裝的,純粹用我們自己的代碼從0開(kāi)始建立起一個(gè)調(diào)用API的URL然后發(fā)出請(qǐng)求。
首先,阿里云似乎支持POST和GET兩種HTTP方法的調(diào)用方式,但是我沒(méi)有試過(guò)POST,現(xiàn)在官網(wǎng)上的說(shuō)明文檔好像也已經(jīng)放棄POST了,所以之后的說(shuō)明都是基于GET方法的。說(shuō)到GET方法,我們的印象就是域名后面一長(zhǎng)串帶著各種百分號(hào)數(shù)字字母的URI(注意URL和URI的區(qū)別,URL是整串,URI是問(wèn)號(hào)后面的一長(zhǎng)串),那么阿里云API調(diào)用時(shí)的那串URI包含了哪些參數(shù)就是關(guān)鍵。
這些參數(shù)基本可以分成三個(gè)部分:
●? 公共參數(shù) 每次請(qǐng)求都要包括的部分
公共參數(shù)在“調(diào)用方式”那張網(wǎng)頁(yè)上有說(shuō)明,包括
Format 要求返回的格式,默認(rèn)是'xml',我們可以設(shè)置為'JSON'
Version 指當(dāng)前API的版本,看官網(wǎng)要求,目前最新的是'2017-03-01'
AccessId 用戶賬號(hào)的明鑰ID
SignatureMethod 簽名使用的算法,目前是只有'HMAC-SHA1'一種選擇,至于什么是簽名下面會(huì)講的
Timestamp 時(shí)間戳,使用的格式是'%Y-%m-%dT%XZ'(帶T和Z的這個(gè)是ISO8601的標(biāo)準(zhǔn)時(shí)間格式),而且一定要用倫敦時(shí)區(qū)的時(shí)間,也就是說(shuō)對(duì)于中國(guó)的使用者我們可以(( datatime.datetime.now - datetime.timedelta(hours=8)).strftime('%Y-%m-%dT%XZ'))
SignatureVersion 算法版本,目前寫(xiě)'1.0'即可
SignatureNonce 為了防止重放攻擊設(shè)置的隨機(jī)數(shù),在python中可以用uuid來(lái)生成這個(gè)隨機(jī)數(shù): str(uuid.uuid1())
?
●? 請(qǐng)求具體參數(shù)? 跟這次請(qǐng)求想要獲得的信息相關(guān),每次請(qǐng)求之間都需要不同的參數(shù)
就監(jiān)控而言,請(qǐng)求具體參數(shù)的說(shuō)明在“查詢監(jiān)控?cái)?shù)據(jù)”那張網(wǎng)頁(yè)上。
Action 請(qǐng)求動(dòng)作,請(qǐng)求監(jiān)控?cái)?shù)據(jù)就寫(xiě)QueryMetricList
Project 指明是監(jiān)控什么產(chǎn)品,比如ECS就寫(xiě)'acs_ecs_dashboard',如果是SLB就寫(xiě)'acs_slb_dashboard',每個(gè)產(chǎn)品的這個(gè)字段信息可以在“預(yù)設(shè)監(jiān)控項(xiàng)”的網(wǎng)頁(yè)中看到
Metric 監(jiān)控項(xiàng)名稱(chēng),也是在“預(yù)設(shè)監(jiān)控項(xiàng)”中查詢
Period 時(shí)間間隔,以秒數(shù)計(jì),說(shuō)明返回的監(jiān)控?cái)?shù)據(jù),兩個(gè)時(shí)間點(diǎn)之間跨度多大。一般默認(rèn)是60。
EndTime 指出查詢的監(jiān)控?cái)?shù)據(jù)截止至什么時(shí)間
StartTime 指出查詢的監(jiān)控?cái)?shù)據(jù)開(kāi)始于什么時(shí)間,這兩個(gè)時(shí)間參數(shù)可以寫(xiě)毫秒時(shí)間戳,也可以寫(xiě)成'%Y-%m-%d %X'的形式,推薦后者,因?yàn)閜ython自帶的時(shí)間戳生成time.time()是以秒為單位而非毫秒
Dimensions 用于過(guò)濾數(shù)據(jù)的k-v對(duì)對(duì)象,在python里的話可以str化一個(gè)字典來(lái)實(shí)現(xiàn)。Dimensions里面可以寫(xiě)哪些字段可以在“預(yù)設(shè)監(jiān)控項(xiàng)”中查詢,一般必然帶有一個(gè)'instanceId'字段
Length 用于查詢結(jié)果的分頁(yè),設(shè)置了Length之后最多只返回一定條數(shù)的結(jié)果
Cursor 游標(biāo)
●? 簽名
Signature 簽名,其實(shí)嚴(yán)格來(lái)說(shuō),簽名是屬于公共參數(shù)的一部分,只不過(guò)簽名每次請(qǐng)求也是不同的,而且簽名的生成要依靠上面兩部分參數(shù)的信息。下面重點(diǎn)講一下如何生成簽名,感覺(jué)官網(wǎng)上講得不是很清楚。。
●? 簽名生成方法
首先,簽名是一串字符串,用于提供給阿里云后臺(tái)校驗(yàn)我們的信息是否正確,有沒(méi)有調(diào)出后臺(tái)信息的權(quán)限。要生成這個(gè)簽名,首先要把上面兩個(gè)參數(shù)集合(在python中就是兩個(gè)字典了)除了整合到一起,然后按照key的順序?qū)ζ渑判?#xff0c;對(duì)排完序的每一對(duì)k-v對(duì),分別將k和v都轉(zhuǎn)化成url形式(python的話可以調(diào)用urllib.quote方法)的字符串,然后用等號(hào)連接這兩個(gè)字符串得到一對(duì)k-v對(duì)的一個(gè)整體字符串。然后用'&'符號(hào)將各個(gè)k-v對(duì)的整體字符串按照之前排序(也就是k的順序)連接起來(lái),獲得一個(gè)長(zhǎng)的,包含了上面兩個(gè)字典中所有鍵值對(duì)的字符串。
拿到這個(gè)長(zhǎng)字符串之后,再用urllib.quote方法對(duì)其轉(zhuǎn)義,此時(shí)可以看到比如冒號(hào)在結(jié)果的字符串中變成了%253A,這就是兩次轉(zhuǎn)義(: -> %3A -> %253A)的結(jié)果。根據(jù)官網(wǎng)上的說(shuō)明我們對(duì)結(jié)果字符串還可以做一些轉(zhuǎn)義上出現(xiàn)誤差后的替換,比如replace('+','%20').replace('*', '%2A').replace('%7E', '~'),最終得到了一個(gè)更長(zhǎng)的字符串。。
再在這個(gè)更長(zhǎng)字符串的開(kāi)頭加上'GET&%2F&',這里注意兩點(diǎn),1.因?yàn)槭荊ET方法所以這里寫(xiě)GET 2.這里的&和%不用再轉(zhuǎn)義的,不要問(wèn)為什么。。阿里云就是這么規(guī)定的。至此,我們得到了所謂的StringToSign,即用于簽名的一個(gè)原料字符串。
接下來(lái),要運(yùn)用hmac-sha1的算法來(lái)對(duì)這個(gè)原料字符串進(jìn)行散列取值,sha1算法還需要一個(gè)秘鑰,這時(shí)候就是用戶秘鑰(secret_key_id)派上用場(chǎng)的時(shí)候,把secret_key_id的末尾加上一個(gè)'&',然后把其作為秘鑰來(lái)進(jìn)行計(jì)算,按照sha1的算法得到結(jié)果后再把它用base64的標(biāo)準(zhǔn)進(jìn)行編碼,編碼完成之后去掉行尾的\n,就得到了最后的簽名了。
下面給出python的實(shí)現(xiàn)代碼:
string_to_sign = ''for k, v in sorted(unsign_param.iteritems(), key=lambda x: x[0]):string_to_sign += urllib.quote(k) + '=' + urllib.quote(v) + '&'string_to_sign = 'GET&%2F&' + urllib.quote(string_to_sign[:-1]).replace('+', '%20').replace('*', '%2A').replace('%7E', '~')# 要[:-1]的原因是因?yàn)樯蓅tring_to_sign的時(shí)候,最后必然會(huì)多出一個(gè)&,這個(gè)是不必要的。如果用的是'&'.join(xxx)這樣的方法就沒(méi)有這個(gè)煩惱了import hashlib,hmaccoder = hmac.new(key=secret, msg=string_to_sign, digestmod=hashlib.sha1)signature = coder.digest().encode('base64').strip() #記得encode出來(lái)行尾有換行符,要去掉●? 發(fā)出請(qǐng)求,接受回復(fù)
在做完簽名之后,可以往之前沒(méi)有Signature這個(gè)字段的公共參數(shù)字典里加上{'Signature':signature},然后整合公共參數(shù)字典和請(qǐng)求參數(shù)字典,得到了一個(gè)大字典,這個(gè)大字典就是我們?cè)谡?qǐng)求阿里云API時(shí)用到的所有參數(shù)了。把這個(gè)參數(shù)按照GET方法要求的樣子整合到基本請(qǐng)求地址'http://metric.cn-hangzhou.aliyuncs.com/'(根據(jù)物理機(jī)房所在區(qū)域不同,基本地址也會(huì)有不同,參見(jiàn)“基本調(diào)用”那張網(wǎng)頁(yè))上面去,然后發(fā)出請(qǐng)求就可以了。
回復(fù)的數(shù)據(jù)如果成功,則是像下面這樣的:
{"Code": "200","Success": true,"Period": "60","RequestId": "8AE2C5AD-7CB3-4B5D-BE21-72AD4F762D8E","Datapoints": [{"instanceId": "instance_id","timestamp": 1502263380000,"Average": 280,"userId": "xxxxxxxxxxxx","Maximum": 280,"vip": "x.x.x.x","Minimum": 280,"port": "443"},{"instanceId": "instance_id","timestamp": 1502263440000,"Average": 2024,"userId": "xxxxxxxxxxxx","Maximum": 2024,"vip": "x.x.x.x","Minimum": 2024,"port": "443"}] }//數(shù)據(jù)已做脫敏處理
可以看到Datapoints字段下面的列表,其中每一項(xiàng)都是一個(gè)時(shí)間點(diǎn)上的監(jiān)控?cái)?shù)值的信息。
如果回復(fù)失敗了,那么得到的可能會(huì)是下面這樣的:
{"Code": "SignatureDoesNotMatch","Message": "Specified signature is not matched with our calculation.","HostId": "metrics.cn-hangzhou.aliyuncs.com","RequestId": "B4086476-2299-45F5-AC99-00AC1769E4D5" }?
■ 完整的python請(qǐng)求實(shí)現(xiàn)
下面是一個(gè)較為完整的實(shí)現(xiàn),用python寫(xiě)成,有些校驗(yàn)什么的主要是考慮到我們自己的業(yè)務(wù)場(chǎng)景, 可以不用管
#!/usr/bin/env python # coding=utf-8 # @author:weiyzimport sys import os import uuid import datetime import urllib import hmactry:import requests except ImportError,e:import urllib2try:import json except ImportError,e:import simplejson as json# 配置文件指定 ACCOUNT_CONF_FILE = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'xxxx.ini') if not os.path.isfile(ACCOUNT_CONF_FILE):raise Exception('Configuration file {0} is not found'.format(ACCOUNT_CONF_FILE))try:instance_id = sys.argv[1]search_key = sys.argv[2]account = sys.argv[3]port = sys.argv[4]search_type = sys.argv[5] except IndexError, e:raise Exception('Invalid arguments. Check there are four arguments for the script.')def get_key_from_account():'''通過(guò)讀文件獲得相關(guān)賬號(hào)的AccessKeyId:return:'''import ConfigParsercf = ConfigParser.ConfigParser()cf.read(ACCOUNT_CONF_FILE)try:return cf.get(account, 'id') , cf.get(account,'secret')except ConfigParser.NoSectionError:raise Exception('Account {0} is not configured in configuration.'.format(account))def get_sign_param():'''進(jìn)行公共參數(shù)字典、請(qǐng)求參數(shù)字典的匯總,并計(jì)算簽名,最終把簽名也加入字典當(dāng)中最終形成的就是完整的請(qǐng)求參數(shù)字典,只要整合成URI就可以發(fā)起請(qǐng)求了:return:'''time_format = '%Y-%m-%dT%XZ'time_stamp = (datetime.datetime.now() - datetime.timedelta(hours=8)).strftime(time_format)access_key_id,secret = get_key_from_account()unsign_public_param = {'Format': 'JSON','Version': '2017-03-01','AccessKeyId': access_key_id,'SignatureMethod': 'HMAC-SHA1','Timestamp': time_stamp, # 時(shí)間戳格式一定是帶T和Z的那個(gè)'SignatureVersion': '1.0','SignatureNonce': str(uuid.uuid1())}secret += '&'req_param = {'Action': 'QueryMetricList','Project': 'acs_slb_dashboard','Metric': search_key,'Period': '60','EndTime': datetime.datetime.now().strftime('%Y-%m-%d %X'),'StartTime': (datetime.datetime.now() - datetime.timedelta(minutes=8)).strftime('%Y-%m-%d %X'),'Dimensions': str({'instanceId': instance_id, 'port': port})# 另外注意Dimensions這個(gè)字典里面的key也是要按照順序排列的 }unsign_param = {}unsign_param.update(unsign_public_param)del (unsign_public_param)unsign_param.update(req_param)del (req_param)string_to_sign = ''for k, v in sorted(unsign_param.iteritems(), key=lambda x: x[0]):string_to_sign += urllib.quote(k) + '=' + urllib.quote(v) + '&'string_to_sign = 'GET&%2F&' + urllib.quote(string_to_sign[:-1]).replace('+', '%20').replace('*', '%2A').replace('%7E', '~')import hashlibcoder = hmac.new(key=secret, msg=string_to_sign, digestmod=hashlib.sha1)signature = coder.digest().encode('base64').strip()unsign_param.update({'Signature': signature})return unsign_paramif __name__ == '__main__':sign_param = get_sign_param()base_url = 'http://metrics.cn-hangzhou.aliyuncs.com/'if 'requests' in locals():res = requests.get(base_url, params=sign_param)result = json.loads(res.content)elif 'urllib2' in locals():req = urllib2.Request(base_url+'?'+urllib.urlencode(sign_param))res = urllib2.urlopen(req)result = res.read()json.loads(result)else:result = {'Message':'Sending Request Failed.'}if result.get('Code') != '200' or result.get('Success') != True:raise Exception('API Call Failed:[Error Message]{0}'.format(result.get('Message')))def filter_result(result):for datapoint in result.get('Datapoints'):yield datapoint.get('Maximum'), datapoint.get('Average')maxlist, avglist = zip(*list(filter_result(result)))max_, avg = max(maxlist), max(avglist)if search_type == 'max':print max_elif search_type == 'avg':print avg■ 其他一些注意點(diǎn)
●? 調(diào)用監(jiān)控?cái)?shù)據(jù)是有時(shí)滯的
不知道其他產(chǎn)品的情況怎么樣,今天我調(diào)用SLB的監(jiān)控?cái)?shù)據(jù)的話始終有7-8分鐘的時(shí)滯。也就是說(shuō)保持調(diào)取當(dāng)前時(shí)間前8分鐘之內(nèi)的監(jiān)控?cái)?shù)據(jù)只能看到一條或兩條數(shù)據(jù),6分鐘前開(kāi)始那個(gè)節(jié)點(diǎn)到當(dāng)前時(shí)間的監(jiān)控?cái)?shù)據(jù)是沒(méi)有的。問(wèn)了下阿里云的工作人員,發(fā)現(xiàn)這是他們內(nèi)部的問(wèn)題,不知道以后是否會(huì)修復(fù)。總之是這樣的。
?
轉(zhuǎn)載于:https://www.cnblogs.com/franknihao/p/7325699.html
總結(jié)
以上是生活随笔為你收集整理的【阿里云API】 阿里云API调用的若干说明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: LibreOJ #2006. 「SCOI
- 下一篇: HDU 4587 TWO NODES(割