前言:公司為優(yōu)化資源占用和節(jié)約服務(wù)器成本蛙讥,考慮自建私有云平臺(tái)坎藐,最初領(lǐng)導(dǎo)有考慮用當(dāng)下最火的docker完成候醒,后來(lái)為保持穩(wěn)定性和可維護(hù)性(實(shí)際情況是對(duì)docker不熟能颁,怕出問(wèn)題搞不定,而cloudstack之前略有接觸)倒淫,最終決定用cloudstack來(lái)搭建云平臺(tái)伙菊,因?yàn)闄C(jī)房網(wǎng)絡(luò)環(huán)境特殊,以及cloudstack的版本問(wèn)題敌土,前后折騰一個(gè)多星期镜硕,才把這個(gè)私有云環(huán)境搭好,對(duì)著界面擼了一陣后返干,發(fā)現(xiàn)他沒(méi)有批量化操作兴枯,以及回收主機(jī)不回收磁盤等等毛病,于是想利用調(diào)官方提供的api來(lái)對(duì)它進(jìn)行批量化操作矩欠,于是并有了這篇文章财剖。
官方api地址:http://cloudstack.apache.org/docs/api/apidocs-4.2/TOC_Root_Admin.html
api腳本
cloud_api.py
#coding:utf-8
import urllib, urllib2
import hashlib
import hmac
import base64
import json
import sys
import argparse
from time import sleep
# 設(shè)置全局代理
#import socket, socks
#socks.set_default_proxy(socks.SOCKS5, "127.0.0.1", 1090)
#socket.socket = socks.socksocket
# 設(shè)置默認(rèn)字符編碼
reload(sys)
sys.setdefaultencoding('utf-8')
class CloudAPI():
def __init__(self):
# 配置 cloudstack api
self.config = {
'api_url': 'http://10.10.252.116:8080/client/api?',
'api_response_type': 'json',
#key
'api_key': 'FkZxPdLWvMVYJBZW82NZvXWPwG7NSE0f8i6OgqS2XYUt-cd4uKZbfaAC94oDa9lf6HqbCvw2u-hYTBVCvZCDjg',
'api_secretkey': 'l2WyVLtjVEv1Eb8jYWW9GF6t1U-xciwQagQUwkDEa77CtNmn7hvI_CMdouCsX5VBXXiWnQjZ3C9zUORU2ijUVA',
'zoneid': '6f30bf67-7342-4025-977f-0e989a772e25' # weimob_sub11
}
def apiresult(self,params):
params['apikey'] = self.config['api_key']
params['response'] = self.config['api_response_type']
request_str = '&'.join(['='.join([k, urllib.quote_plus(params[k])]) for k in params.keys()])
sig_str = '&'.join(['='.join([k.lower(), urllib.quote_plus(params[k].lower().replace('+', '%20'))]) for k in
sorted(params.iterkeys())])
signature = urllib.quote_plus(
base64.encodestring(hmac.new(self.config['api_secretkey'], sig_str, hashlib.sha1).digest()).strip())
request_url = self.config['api_url'] + request_str + '&signature=' + signature
result = urllib2.urlopen(request_url)
response = json.loads(result.read())
return response
# 列出虛擬機(jī)實(shí)例
def listVirtualMachines(self,hostname=''):
print "查詢主機(jī)信息"
params = {
'command':'listVirtualMachines',
'name':hostname
}
response = self.apiresult(params)
instances = []
if not response['listvirtualmachinesresponse']:
print "VirtualMachine is \033[31mnot exist\033[0m!"
return False
elif hostname:
for instance in response['listvirtualmachinesresponse']['virtualmachine']:
try:
if hostname == instance['name']:
instance_info = [instance['id'],instance['name'],instance['nic'][0]['ipaddress'],instance['hostname'],instance['templatename'],instance['serviceofferingname'],instance['state']]
print "HostName:\033[32m%s\033[0m HostIp:\033[32m%s\033[0m PhysicalHost:\033[32m%s\033[0m Template:\033[32m%s\033[0m Spec:\033[32m%s\033[0m Status:\033[32m%s\033[0m" \
% (instance_info[1],instance_info[2],instance_info[3],instance_info[4],instance_info[5],instance_info[6])
return [instance['id'],instance['state']]
except KeyError as e:
print "\033[35m%s\033[0m status is \033[31merror\033[0m !" % instance['name']
return [instance['id'],instance['state']]
else:
for instance in response['listvirtualmachinesresponse']['virtualmachine']:
try:
instance_info = [instance['id'],instance['name'],instance['nic'][0]['ipaddress'],instance['hostname'],instance['templatename'],instance['serviceofferingname'],instance['state']]
print "HostName:\033[32m%s\033[0m HostIp:\033[32m%s\033[0m PhysicalHost:\033[32m%s\033[0m Template:\033[32m%s\033[0m Spec:\033[32m%s\033[0m Status:\033[32m%s\033[0m" \
% (instance_info[1],instance_info[2],instance_info[3],instance_info[4],instance_info[5],instance_info[6])
instances.append(instance_info)
except KeyError as e:
print "\033[35m%s status is error\033[0m !" % instance['name']
return [instance['id'],instance['state']]
print "統(tǒng)計(jì): %s" % len(instances)
return instances
return response
# 列出模板
def listTemplates(self,templatename=''):
params = {
'command':'listTemplates',
'templatefilter':'all'
}
response = self.apiresult(params)
instances = []
if not response['listtemplatesresponse']:
print "Template is not exist!"
return False
elif templatename:
for instance in response['listtemplatesresponse']['template']:
if templatename == instance['name']:
instance_info = [instance['id'], instance['name']]
print "TemplateId:\033[32m%s\033[0m TemplateName:\033[32m%s\033[0m" % (instance_info[0],instance_info[1])
return instance['id']
else:
for instance in response['listtemplatesresponse']['template']:
instance_info = [instance['id'],instance['name']]
print "TemplateId:\033[32m%s\033[0m TemplateName:\033[32m%s\033[0m" % (instance_info[0],instance_info[1])
instances.append(instance_info)
print "統(tǒng)計(jì): %s" % len(instances)
return instances
return response
# 列出計(jì)算方案
def listServiceOfferings(self,serviceoffername=''):
params = {
'command':'listServiceOfferings'
}
response = self.apiresult(params)
instances = []
if not response['listserviceofferingsresponse']:
print "ServiceOffer is not exist!"
return False
elif serviceoffername:
for instance in response['listserviceofferingsresponse']['serviceoffering']:
if serviceoffername == instance['name']:
instance_info = [instance['id'], instance['name'], instance['storagetype']]
print "ServiceOfferId:\033[32m%s\033[0m ServiceOfferName:\033[32m%s\033[0m StorageType:\033[32m%s\033[0m" % (instance_info[0],instance_info[1],instance_info[2])
return instance['id']
else:
for instance in response['listserviceofferingsresponse']['serviceoffering']:
instance_info = [instance['id'], instance['name'], instance['storagetype']]
print "ServiceOfferId:\033[32m%s\033[0m ServiceOfferName:\033[32m%s\033[0m StorageType:\033[32m%s\033[0m" % (instance_info[0],instance_info[1],instance_info[2])
instances.append(instance_info)
print "統(tǒng)計(jì): %s" % len(instances)
return instances
return response
# 列出磁盤方案
def listDiskOfferings(self,diskoffername=''):
params = {
'command':'listDiskOfferings'
}
response = self.apiresult(params)
instances = []
if not response['listdiskofferingsresponse']:
print "DiskOffer is not exist!"
return False
elif diskoffername:
for instance in response['listdiskofferingsresponse']['diskoffering']:
if diskoffername == instance['name']:
instance_info = [instance['id'], instance['name'], instance['disksize'], instance['storagetype']]
print "DiskOfferId:\033[32m%s\033[0m DiskOfferName:\033[32m%s\033[0m DiskSize:\033[32m%s\033[0m StorageType:\033[32m%s\033[0m" % (instance_info[0],instance_info[1],instance_info[2],instance_info[3])
return instance['id']
else:
for instance in response['listdiskofferingsresponse']['diskoffering']:
instance_info = [instance['id'], instance['name'], instance['disksize'], instance['storagetype']]
print "DiskOfferId:\033[32m%s\033[0m DiskOfferName:\033[32m%s\033[0m DiskSize:\033[32m%s\033[0m StorageType:\033[32m%s\033[0m" % (instance_info[0],instance_info[1],instance_info[2],instance_info[3])
instances.append(instance_info)
print "統(tǒng)計(jì): %s" % len(instances)
return instances
return response
# 列出數(shù)據(jù)磁盤
def listVolumes(self, hostname=''):
params = {
'command':'listVolumes'
}
response = self.apiresult(params)
instances = []
if not response['listvolumesresponse']:
print "listVolumes is not exist!"
return False
elif hostname:
for instance in response['listvolumesresponse']['volume']:
try:
if instance['type'] == 'DATADISK' and hostname == instance['vmname']:
instance_info = [instance['id'], instance['name'], instance['type'], instance['diskofferingdisplaytext'], instance['vmstate'], instance['vmname']]
print "VolumeId:\033[32m%s\033[0m VolumeName:\033[32m%s\033[0m VolumeType:\033[32m%s\033[0m VolumeSize:\033[32m%s\033[0m VolumeStatus:\033[32m%s\033[0m VolumeHost:\033[32m%s\033[0m" % (instance_info[0],instance_info[1],instance_info[2],instance_info[3], instance_info[4], instance_info[5])
return [instance['id'], instance['name']]
except KeyError as e:
print "\033[35m%s status is error\033[0m !" % instance['name']
return response['listvolumesresponse']['volume']
else:
for instance in response['listvolumesresponse']['volume']:
try:
if instance['type'] == 'DATADISK':
instance_info = [instance['id'], instance['name'], instance['type'], instance['diskofferingdisplaytext'], instance['vmstate'], instance['vmname']]
print "VolumeId:\033[32m%s\033[0m VolumeName:\033[32m%s\033[0m VolumeType:\033[32m%s\033[0m VolumeSize:\033[32m%s\033[0m VolumeStatus:\033[32m%s\033[0m VolumeHost:\033[32m%s\033[0m" % (instance_info[0],instance_info[1],instance_info[2],instance_info[3], instance_info[4], instance_info[5])
instances.append(instance_info)
except KeyError as e:
print "\033[35m%s status is error\033[0m !" % instance['name']
return response['listvolumesresponse']['volume']
print "統(tǒng)計(jì): %s" % len(instances)
return instances
return response
# 部署虛擬機(jī)實(shí)例
def deployVirtualMachine(self, hostname='',templatename='',serviceoffername='',diskoffername=''):
if self.listVirtualMachines(hostname=hostname) or not (hostname and serviceoffername and templatename and diskoffername):
print "you need four args,or the hostname is exist!"
sys.exit()
serviceofferingid = self.listServiceOfferings(serviceoffername=serviceoffername)
templateid = self.listTemplates(templatename=templatename)
diskofferingid = self.listDiskOfferings(diskoffername=diskoffername)
params = {
'command': 'deployVirtualMachine',
'zoneid': self.config['zoneid'],
'name':hostname,
'displayname':hostname,
'serviceofferingid': serviceofferingid,
'templateid':templateid,
'diskofferingid':diskofferingid
}
response = self.apiresult(params)
print "The \033[32m%s\033[0 mis will be \033[32mDeploy\033[0m...!" % hostname
return response
# 操作虛擬機(jī)實(shí)例,包括啟動(dòng)癌淮、停止躺坟、重啟、銷毀乳蓄、重置密碼
def actionVirtualMachine(self, hostname='', action=''):
status = {
'start':'Running',
'stop':'Stopped',
'reboot':'',
'destroy':''
}
hostinfo = self.listVirtualMachines(hostname=hostname)
if not (hostname and action and hostinfo):
print "You need \033[36mtwo args\033[0m!"
sys.exit()
if hostinfo[1] == status[action]:
print "The \033[36m%s\033[0m Status is \033[33m%s\033[0m !" % (hostname,hostinfo[1])
sys.exit()
params = {
'command': action + 'VirtualMachine',
'id': hostinfo[0]
}
response = self.apiresult(params)
sleep(3)
# 回收機(jī)器時(shí)咪橙,刪除掛載數(shù)據(jù)盤, 這個(gè)有點(diǎn)問(wèn)題,因?yàn)闄C(jī)器刪掉時(shí)還沒(méi)關(guān)機(jī)虚倒,直接刪磁盤會(huì)報(bào)錯(cuò), 暫時(shí)注釋掉
# 我想的是先把掛載的磁盤name寫(xiě)入到一個(gè)文件美侦,之后在根據(jù)這個(gè)文件刪除數(shù)據(jù)磁盤
# if action == 'destroy':
# volumeid = self.listVolumes(hostname=hostname)[0]
# params = {
# 'command': 'deleteVolume',
# 'id': volumeid
# }
# response = self.apiresult(params)
print "the %s now is \033[32m%s\033[0m , it will be \033[31m%s\033[0m...!" % (hostname,hostinfo[1],action)
return response
if __name__ == '__main__':
cloudapi=CloudAPI()
parser=argparse.ArgumentParser(description='cloudstack api ',usage='%(prog)s [options]')
parser.add_argument('-l','--host',nargs='?',dest='listhost',default='host',help='查詢主機(jī)')
parser.add_argument('-s','--serviceoffer',nargs='?',dest='serviceoffer',default='serviceoffer',help='查詢計(jì)算方案')
parser.add_argument('-d','--diskoffer',nargs='?',dest='diskoffer',default='diskoffer',help='查詢磁盤方案')
parser.add_argument('-t','--template',nargs='?',dest='template',default='template',help='查詢模板信息')
parser.add_argument('-vd', '--volume', nargs='?', dest='volume', default='volume', help='查詢掛載的數(shù)據(jù)磁盤')
parser.add_argument('-A','--add-host',dest='addhost',nargs=4,metavar=('sh-aa-01','centos_6.5','S1-2c-2g-local','disk_10G'),help='部署主機(jī),填寫(xiě)主機(jī)名、模板魂奥、計(jì)算方案菠剩、磁盤方案')
parser.add_argument('-S','--start-host',dest='starthost',nargs=1,metavar=('sh-aa-01'),help='啟動(dòng)主機(jī),填寫(xiě)主機(jī)名')
parser.add_argument('-P','--stop-host',dest='stophost',nargs=1,metavar=('sh-aa-01'),help='停掉主機(jī),填寫(xiě)主機(jī)名')
parser.add_argument('-R','--reboot-host',dest='reboothost',nargs=1,metavar=('sh-aa-01'),help='重啟主機(jī),填寫(xiě)主機(jī)名')
parser.add_argument('-D','--destroy-host',dest='destroyhost',nargs=1,metavar=('sh-aa-01'),help='銷毀主機(jī),填寫(xiě)主機(jī)名')
parser.add_argument('-v','--version', action='version', version='%(prog)s 1.0')
if len(sys.argv) == 1:
#html = parser.print_help()
html = cloudapi.listVolumes(hostname='sh-ops-cloud-test-online-01')
#html = cloudapi.listVirtualMachines(hostname='sh-ops-cloud-test-online-01')
#html = cloudapi.deployVirtualMachine(hostname='sh-ops-cloud-test-online-03',serviceoffername='S1-2c-2g-local',templatename='centos_6.5',diskoffername='disk_10G')
print html
else:
args = parser.parse_args()
if args.listhost != 'host':
if args.listhost:
cloudapi.listVirtualMachines(args.listhost)
else:
cloudapi.listVirtualMachines()
if args.serviceoffer != 'serviceoffer':
if args.serviceoffer:
cloudapi.listServiceOfferings(args.serviceoffer)
else:
cloudapi.listServiceOfferings()
if args.diskoffer != 'diskoffer':
if args.diskoffer:
cloudapi.listDiskOfferings(args.diskoffer)
else:
cloudapi.listDiskOfferings()
if args.template != 'template':
if args.template:
cloudapi.listTemplates(args.template)
else:
cloudapi.listTemplates()
if args.volume != 'volume':
if args.volume:
cloudapi.listVolumes(args.volume)
else:
cloudapi.listVolumes()
if args.addhost:
cloudapi.deployVirtualMachine(args.addhost[0], args.addhost[1], args.addhost[2], args.addhost[3])
if args.starthost:
cloudapi.actionVirtualMachine(args.starthost[0],'start')
if args.stophost:
cloudapi.actionVirtualMachine(args.stophost[0],'stop')
if args.reboothost:
cloudapi.actionVirtualMachine(args.reboothost[0],'reboot')
if args.destroyhost:
cloudapi.actionVirtualMachine(args.destroyhost[0],'destroy')
查看執(zhí)行效果
python cloud_api.py -l
python cloud_api.py -h
對(duì)主機(jī)進(jìn)行操作
python cloud_api.py -S sh-ops-cloud-test-online-02
批量執(zhí)行腳本
cloud_cli.py
# -*- coding: utf-8 -*-
import os
import sys
import argparse
from cloud_api import CloudAPI
reload(sys)
sys.setdefaultencoding('utf-8')
host_file = 'target'
s_template = 'centos-6.5-templete' # 這里是默認(rèn)系統(tǒng)模板
s_diskoffer = '' # 這里是默認(rèn)規(guī)格磁盤
cmd = 'python cloud_api.py'
def deploy_hosts():
# 實(shí)例化cloud_api
cloudstack = CloudAPI()
cloudstack.listServiceOfferings()
s_serviceoffer = raw_input("Please Input ServiceOffer Name: ")
# s_diskoffer = raw_input("Please Input DiskOffer Name: ")
with open(host_file) as fb:
host_info = list(line.strip() for line in fb)
for s_hostname in host_info:
cmd1 = ' '.join([cmd, sys.argv[1], s_hostname, s_template, s_serviceoffer])
#cmd1 = ' '.join([cmd, sys.argv[1], s_hostname, s_template, s_serviceoffer, s_diskoffer])
os.system(cmd1)
def action_hosts():
with open(host_file) as fb:
host_info = list(line.strip() for line in fb)
for s_hostname in host_info:
cmd1 = ' '.join([cmd, sys.argv[1], s_hostname])
os.system(cmd1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='cloudstack api ', usage='%(prog)s [options]')
parser.add_argument('-l', '--listhost', nargs='?', dest='listhost', default='listhost', help='批量查詢主機(jī)')
parser.add_argument('-A', '--addhost', nargs='?', dest='addhost', default='addhost', help='批量部署主機(jī)')
parser.add_argument('-S', '--starthost', nargs='?', dest='starthost', default='starthost', help='批量啟動(dòng)主機(jī)')
parser.add_argument('-P', '--stophost', nargs='?', dest='stophost', default='stophost', help='批量關(guān)掉主機(jī)')
parser.add_argument('-R', '--reboothost', nargs='?', dest='reboothost', default='reboothost', help='批量重啟主機(jī)')
parser.add_argument('-D', '--destroyhost', nargs='?', dest='destroyhost', default='destroyhost', help='批量銷毀主機(jī)')
if len(sys.argv) == 1:
html = parser.print_help()
print html
elif sys.argv[1] == '-A':
deploy_hosts()
else:
action_hosts()
查看執(zhí)行效果
python cloud_cli.py -h
批量部署主機(jī)
填寫(xiě)target文件(被操作主機(jī)名)
> cat target
sh-ops-cloud-test-online-07
sh-ops-cloud-test-online-08
執(zhí)行
python cloud_cli.py -A
批量查看主機(jī)
python cloud_cli.py -l
批量啟動(dòng)主機(jī)
python cloud_cli.py -S
- 好了,關(guān)于cloudstack的api操作到此為止捧弃,有其它需求的朋友可參考官方api介紹自行修改腳本赠叼。
- 近日在github上搜到一個(gè)寫(xiě)的很全的cloudapi項(xiàng)目,cloudstack-python-client违霞,這個(gè)寫(xiě)的非常全嘴办,之后會(huì)以它為模板寫(xiě)。