使用 CloudStack API 进行监控(附监控脚本)

如同 AWS API 一样,CloudStack API 也是基于 Web Service,可以使用任何一种支持 HTTP 调用的语言(例如 Java,PHP)编写代码。
目前 CloudStack 采用以下两种认证方式:

  1. Session 认证
    通过 login API,获得一个 JSESSIONID cookie 和一个 SESSIONKEY token。
  2. API Key 认证

一 、session认证方式

详细请参考
curl 访问 CloudStack API 的用法

二、API Key 认证

和监控有关的command有:

  • listSystemVms
  • listHosts

我们以CloudStack管理员的身份(admin)为例, 可以先在CloudStack UI上生成用户的apikey和secretkey, 只有管理员权限可以生成这两个key。

key的获取位置

首页》帐户》admin》用户》admin》点击相应key右侧的小图标生成如下

  • apikey
    YOESnQc05-sc_PtnLpAP0fqKSKIR4ZYgFqCeFMPF3Sljr9V-Z_QaX6snnsIM_kRA8Md_5iky9-xxxxxxxxxxxx
  • secretkey
    xYdBHdYabSheGg9jy7ajjqQRjihDpdcb10J_09RqqfvGj5OAE5GXJdC7AMBhotrHpcnsyhajVzftjrxxxxxxxxxx

下面是python的测试过程与最终的脚本

  1. python2.7安装
首先下载源tar包
可利用linux自带下载工具wget下载,如下所示:
wget http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz
下载完成后到下载目录下,解压
tar -zxvf Python-2.7.3.tgz
进入解压缩后的文件夹
cd Python-2.7.3
在编译前先在/usr/local建一个文件夹python27(作为python的安装路径,以免覆盖老的版本)
mkdir /usr/local/python2.7.3
在解压缩后的目录下编译安装
./configure --prefix=/usr/local/python2.7.3
make
make install
此时没有覆盖老版本,再将原来/usr/bin/python链接改为别的名字
mv /usr/bin/python /usr/bin/python2.6.6
再建立新版本python的链接
ln -s /usr/local/python2.7.3/bin/python2.7 /usr/bin/python
这个时候输入
python
就会显示出python的新版本信息
Python 2.7.3 (default, Sep 29 2013, 11:05:02)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
  1. py测试脚本
CloudStack Documentation, Release 4.8.0
You will see an API Key and Secret Key field being generated. The keys will be of the form:
API Key : rtmap
Secret Key: TJyVDr17nNjvEuxTzga1QzkRLztNCKItaeY-h3hYCnmMXPkQe4Ic5q8hOeQOCGbT-jm3GcHXVFTWn6-ZYH-PnQ
Open a Python shell and import the basic modules necessary to make the request.  Do note that this request could be
made many different ways, this is just a low level example. Theurllib* modules are used to make the http request
and do url encoding.  Thehashlib module gives us the sha1 hash function.  It used to geenrate the hmac
(Keyed Hashing for Message Authentication) using the secretkey. The result is encoded using the base64 module.
$python
Python 2.7.3 (default, Nov 17 2012, 19:54:34)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib2
>>> import urllib
>>> import hashlib
>>> import hmac
>>> import base64
Define the endpoint of the Cloud, the command that you want to execute, the type of the response (i.e XML or JSON)
and the keys of the user.  Note that we do not put the secretkey in our request dictionary because it is only used to
compute the hmac.
>>>baseurl='http://localhost:8080/client/api?'
>>>request={}
>>>request['command']='listUsers'
>>>request['response']='json'
>>>request['apikey']='rtmap'
>>>secretkey='TJyVDr17nNjvEuxTzga1QzkRLztNCKItaeY-h3hYCnmMXPkQe4Ic5q8hOeQOCGbT-jm3GcHXVFTWn6-ZYH-PnQ'
Build the base request string, the combination of all the key/pairs of the request, url encoded and joined with amper-
sand.
>>>request_str='&'.join(['='.join([k,urllib.quote_plus(request[k])]) for k in request.keys()])
>>>request_str
'apikey=plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg&command=listUsers&response=json'
Compute the signature with hmac, do a 64 bit encoding and a url encoding, the string used for the signature is similar
to the base request string shown above but the keys/values are lower cased and joined in a sorted order
>>>sig_str='&'.join(['='.join([k.lower(),urllib.quote_plus(request[k].lower().replace('+','%20'))])
for
k
in
sorted(request.iterkeys())])
>>>sig_str
'apikey=plgwjfzk4gys3momtvmjuvg-x-jlwlnfauj9gabbbf9edm-kaymmailqzzq1elzlyq_u38zcm0bewzgudp66mg&command=listusers&response=json'
>>>sig=hmac.new(secretkey,sig_str,hashlib.sha1).digest()
>>>sig
'M:]\x0e\xaf\xfb\x8f\xf2y\xf1p\x91\x1e\x89\x8a\xa1\x05\xc4A\xdb'
>>>sig=base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest())
>>>sig
'TTpdDq/7j/J58XCRHomKoQXEQds=\n'
>>>sig=base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest()).strip()
>>>sig
'TTpdDq/7j/J58XCRHomKoQXEQds='
>>>
>>>sig=urllib.quote_plus(base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest()).strip())

Finally, build the entire string by joining the baseurl, the request str and the signature. Then do an http GET:

4.1.  CloudStack Installation from GIT repo for Developers
CloudStack Documentation, Release 4.8.0
>>>req=baseurl+request_str+'&signature='+sig
>>>req
'http://localhost:8080/client/api?apikey=rtmap&command=listUsers&response=json&signature=TTpdDq%2F7j%2FJ58XCRHomKoQXEQds%3D'
>>>res=urllib2.urlopen(req) #401报错 应该不是代码问题,是url本身的问题,应为401,没有通过
>>>res.read()
{
"listusersresponse" : {
"count":1 ,
"user" : [
{
"id":"7ed6d5da-93b2-4545-a502-23d20b48ef2a",
"username":"admin",
"firstname":"admin",
"lastname":"cloud",
"created":"2012-07-05T12:18:27-0700",
"state":"enabled",
"account":"admin",
"accounttype":1,
"domainid":"8a111e58-e155-4482-93ce-84efff3c7c77",
"domain":"ROOT",
"apikey":"plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg",
"secretkey":"VDaACYb0LV9eNjTetIOElcVQkvJck_J_QljX_FcHRj87ZKiy0z0ty0ZsYBkoXkY9b7eq1EhwJaw7FF3akA3KBQ",
"accountid":"7548ac03-af1d-4c1c-9064-2f3e2c0eda0d"
}
]
}
}
All the clients that you will find on github will implement this signature technique, you should not have to do it by
hand.   Now that you have explored the API through the UI and that you understand how to make low level calls,
pick your favorite client of use CloudMonkey.  CloudMonkey is a sub-project of Apache CloudStack and gives oper-
ators/developers the ability to use any of the API methods. It has nice auto-completion and help feature as well as an
API discovery mechanism since 4.2.

Python 2.7.3 (default, Apr 26 2016, 09:35:32) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib2
import urllib
import hashlib
import hmac
import base64
baseurl='http://localhost:8080/client/api?'
request={}
request['command']='listUsers'
request['response']='json'
request['apikey']='rtmap'
secretkey='TJyVDr17nNjvEuxTzga1QzkRLztNCKItaeY-h3hYCnmMXPkQe4Ic5q8hOeQOCGbT-jm3GcHXVFTWn6-ZYH-PnQ'
request_str='&'.join(['='.join([k,urllib.quote_plus(request[k])]) for k in request.keys()])
request_str
sig_str='&'.join(['='.join([k.lower(),urllib.quote_plus(request[k].lower().replace('+','%20'))]) for k in sorted(request.iterkeys())])
sig_str
sig=hmac.new(secretkey,sig_str,hashlib.sha1).digest()
sig
sig=base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest())
sig
sig=base64.encodestring(hmac.new(secretkey,sig_str,hashlib.sha1).digest()).strip()
sig
sig=urllib.quote_plus(base64.encodestring(hmac.new(secretkey.lower(),sig_str,hashlib.sha1).digest()).strip())
req=baseurl+request_str+'&signature='+sig
req
>>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> 'apikey=rtmap&command=listUsers&response=json'
>>> >>> 'apikey=rtmap&command=listusers&response=json'
>>> >>> "\x1dt6\x9f?T~I\xed#'B0\xa8\xa8\x81$B\xd5\x92"
>>> >>> 'HXQ2nz9UfkntIydCMKiogSRC1ZI=\n'
>>> >>> 'HXQ2nz9UfkntIydCMKiogSRC1ZI='
>>> >>> >>> 'http://localhost:8080/client/api?apikey=rtmap&command=listUsers&response=json&signature=HXQ2nz9UfkntIydCMKiogSRC1ZI%3D'
>>> 
>>> 
  1. 完整的python脚本(自己一直在用这个脚本)
#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = '火罐儿'
import time
import re
import urllib2
import urllib
import hashlib
import hmac
import base64
#import requests
import json
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
import getopt,sys
import os


def requestUrl(url,apikey,signature,command):
    request={}
    request['command']=command
    request['apikey']=apikey
    request['response']='json'
    secretkey=signature
    request_url='&'.join(['='.join([r,urllib.quote_plus(request[r])]) for r in request.keys()])
    sig_url='&'.join(['='.join([r.lower(),urllib.quote_plus(request[r]).lower()]) for r in sorted(request.iterkeys())])
    sig=urllib.quote_plus(base64.encodestring(hmac.new(secretkey,sig_url,hashlib.sha1).digest()).strip())
    req=url+'?'+request_url+'&signature='+sig
    return req

def reqresults(request_url):
    try:
        res = urllib2.urlopen(request_url)
    except urllib2.HTTPError, e: 
        sys.exit('invalid signaturekey!')
    except urllib2.URLError, e:
        sys.exit('invalid signaturekey!')

    return res.read()

def api_request(url,params,_method="GET"):#
    if _method == "POST":
        rt = requests.post(url,params)
    else:
        rt = requests.get(url,params)

    return rt

def deploy(AllList,url,apikey,secretkey,command):
    request_url = requestUrl(url,apikey,secretkey,command)
    #print request_url
    if command == 'listHosts':
        resultsNeed=json.loads(reqresults(request_url))
        hostList=resultsNeed['listhostsresponse']['host']
        #print json.dumps(hostList,indent=4)
        for i in hostList:
            name=i.get('name','None')
            state=i.get('state','None')
            disconnected=i.get('disconnected','None')
            ipaddress=i.get('ipaddress','None')
            #print('%s:%s state is %s at %s' %(name,ipaddress,state,disconnected))
            if i['state'] !='Up':
                downListStr='%s:%s state is %s at %s' %(name,ipaddress,state,disconnected)
                #sendmsg(downListStr,'192.168.xx.xx')
                AllList.append(downListStr)
        return AllList

    elif command == 'listCapacity':
        capacity = {
        'memory':0,
        'CPU':1,
        'primary_storage':3,
        'secondary_storage':6,
        'share_network_ip':8,
        'local_storage':9,
        'management_ip':5
        }
        resultsNeed=json.loads(reqresults(request_url))
        capacityList=resultsNeed['listcapacityresponse']['capacity']
        #print json.dumps(capacityList,indent=4)
        for i in capacityList:
            type=i.get('type','None')
            for key,value in capacity.iteritems():
                if type==value:
                    type=key
            percentused=i.get('percentused','None')
            #print('%s capacity is %s' %(type,percentused))
            if i['percentused'] > '80.00':
                downListStr='%s capacity is %s' %(type,percentused)
                AllList.append(downListStr)
        return AllList
    elif command == 'listVirtualMachines':
        command = 'listVirtualMachines&state=started'
        request_url = requestUrl(url,apikey,secretkey,command)
        print request_url
        print 'this procedure is coming soon.'
    elif command == 'resetPasswordForVirtualMachine':
        print 'this procedure is coming soon.'
    elif command == 'rebootVirtualMachine':
        print 'this procedure is coming soon.'
    elif command == 'startVirtualMachine':
        print 'this procedure is coming soon.'
    elif command == 'stopVirtualMachine':
        print 'this procedure is coming soon.'
    else :
        sys.exit('invalid command!')

def sendmail(infor):
    msg = MIMEText(infor, 'plain', 'utf-8')
    msg['From'] = formataddr(["cloudstack节点告警",'alert@xxx.com'])
    msg['To'] = formataddr(['管理员','xxx@xxx.com'])
    msg['Subject'] = "CloudStack listHosts"
    try:
        server = smtplib.SMTP("smtp.xxx.com", 25)
        server.login("alert@xxx.com", "xxxxxx")
        server.sendmail('alert@xxx.com', \
	['xxx@xxx.com'], \
        msg.as_string())
        server.quit()
        print "Warnning! 邮件发送成功!"
    except smtplib.SMTPException:
        print "Error: 无法发送邮件"

def sendmsg(infor,server):
    p = re.compile('\n')
    infor=re.sub(p,';',infor)
    #略
    try:
        os.system('curl "%s"'%(wxstring))
        print "微信发送成功!"
    except Exception, e:
        print "Error: 无法发送微信"


def usage():
    msg="""
option args: [-i,-p,-k,-s,-c]
usage:
-h,--help   display this help
-i,--ip     set the cloudstack management ip
-p,--port   set the cloudstack port
-k,--apikey     set the cloudstack apikey
-s,--secretkey  set the cloudstack secretkey
-c,--command    set the cloudstack command parameter
"""
    print msg

def main():
    AllList=[]
    try:
        options,args = getopt.getopt(sys.argv[1:],"hi:p:k:s:c:",["help","ip=","port=","apikey=","secretkey=","command="])
    except getopt.GetoptError:
        sys.exit(usage())

    #if options==[]:
    #   sys.exit(usage())

    for name,value in options:
        if name in ("-h","--help"):
            sys.exit(usage())
        elif name in ("-i","--ip"):
            server=value
        elif name in ("-p","--port"):
            apiport=value
        elif name in ("-k","--apikey"):
            apikey=value
        elif name in ("-s","--secretkey"):
            secretkey=value
        elif name in ("-c","--command"):
            command=value
        else:
            sys.exit(usage())

    options,args = getopt.getopt(sys.argv[1:],"hi:p:k:s:c:",["help","ip=","port=","apikey=","secretkey=","command="])

    if 'server' not in locals().keys():
        server = '192.168.100.20'
    if 'apiport' not in locals().keys():
        apiport = '8080'
    if 'command' not in locals().keys():
        command = 'listHosts'
    if 'apikey' not in locals().keys():
        apikey='YOESnQc05-sc_PtnLpAP0fqKSKIR4ZYgFqCeFMPF3Sljr9V-Z_QaX6snnsIM_kRA8Md_5iky9-xxxxxxxxxxxx'
    if 'secretkey' not in locals().keys():
        secretkey = 'xYdBHdYabSheGg9jy7ajjqQRjihDpdcb10J_09RqqfvGj5OAE5GXJdC7AMBhotrHpcnsyhajxxxxxxxxxxxx'

    url = 'http://' + server + ':' + apiport + '/client/api'
    deploy(AllList,url,apikey,secretkey,command)
    if AllList:
        for i in AllList:
	    sendmsg(i,server)
        infor_list='\n'.join(AllList)
        sendmail(infor_list)
        sendmsg(infor_list,server)
        print '***************发送邮件内容:*****************'
        print infor_list
    else:
        print '***************一切正常**********************'

if __name__ == '__main__':
    main()

  1. 脚本的执行
    python cloudstackmonitor.py
    -i 192.168.xx.xx
    -p 8080
    -k 'YOESnQc05-sc_PtnLpAP0fqKSKIR4ZYgFqCeFMPF3Sljr9V-Z_QaX6snnsIM_kRA8Md_5iky9-xxxxxxxxxxxx'
    -s 'xYdBHdYabSheGg9jy7ajjqQRjihDpdcb10J_09RqqfvGj5OAE5GXJdC7AMBhotrHpcnsyhajxxxxxxxxxxxxxxxx'
    -c listVirtualMachines

附件

官方API地址,运维自动化可参考
http://cloudstack.apache.org/docs/api/apidocs-4.5/TOC_Root_Admin.html

posted @ 2018-05-16 15:17  火罐儿  阅读(907)  评论(0编辑  收藏  举报