前言:公司为优化资源占用和节约服务器成本,考虑自建私有云平台,最初领导有考虑用当下最火的docker完成,后来为保持稳定性和可维护性(实际情况是对docker不熟,怕出问题搞不定,而cloudstack之前略有接触),最终决定用cloudstack来搭建云平台,因为机房网络环境特殊,以及cloudstack的版本问题,前后折腾一个多星期,才把这个私有云环境搭好,对着界面撸了一阵后,发现他没有批量化操作,以及回收主机不回收磁盘等等毛病,于是想利用调官方提供的api来对它进行批量化操作,于是并有了这篇文章。
官方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
# 设置全局代理
#import socket, socks
#socks.set_default_proxy(socks.SOCKS5, "127.0.0.1", 1090)
#socket.socket = socks.socksocket
# 设置默认字符编码
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
# 列出虚拟机实例
def listVirtualMachines(self,hostname=''):
print "查询主机信息"
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 "统计: %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 "统计: %s" % len(instances)
return instances
return response
# 列出计算方案
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 "统计: %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 "统计: %s" % len(instances)
return instances
return response
# 列出数据磁盘
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 "统计: %s" % len(instances)
return instances
return response
# 部署虚拟机实例
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
# 操作虚拟机实例,包括启动、停止、重启、销毁、重置密码
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)
# 回收机器时,删除挂载数据盘, 这个有点问题,因为机器删掉时还没关机,直接删磁盘会报错, 暂时注释掉
# 我想的是先把挂载的磁盘name写入到一个文件,之后在根据这个文件删除数据磁盘
# 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='查询主机')
parser.add_argument('-s','--serviceoffer',nargs='?',dest='serviceoffer',default='serviceoffer',help='查询计算方案')
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='查询挂载的数据磁盘')
parser.add_argument('-A','--add-host',dest='addhost',nargs=4,metavar=('sh-aa-01','centos_6.5','S1-2c-2g-local','disk_10G'),help='部署主机,填写主机名、模板、计算方案、磁盘方案')
parser.add_argument('-S','--start-host',dest='starthost',nargs=1,metavar=('sh-aa-01'),help='启动主机,填写主机名')
parser.add_argument('-P','--stop-host',dest='stophost',nargs=1,metavar=('sh-aa-01'),help='停掉主机,填写主机名')
parser.add_argument('-R','--reboot-host',dest='reboothost',nargs=1,metavar=('sh-aa-01'),help='重启主机,填写主机名')
parser.add_argument('-D','--destroy-host',dest='destroyhost',nargs=1,metavar=('sh-aa-01'),help='销毁主机,填写主机名')
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')
查看执行效果
python cloud_api.py -l
python cloud_api.py -h
对主机进行操作
python cloud_api.py -S sh-ops-cloud-test-online-02
批量执行脚本
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' # 这里是默认系统模板
s_diskoffer = '' # 这里是默认规格磁盘
cmd = 'python cloud_api.py'
def deploy_hosts():
# 实例化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='批量查询主机')
parser.add_argument('-A', '--addhost', nargs='?', dest='addhost', default='addhost', help='批量部署主机')
parser.add_argument('-S', '--starthost', nargs='?', dest='starthost', default='starthost', help='批量启动主机')
parser.add_argument('-P', '--stophost', nargs='?', dest='stophost', default='stophost', help='批量关掉主机')
parser.add_argument('-R', '--reboothost', nargs='?', dest='reboothost', default='reboothost', help='批量重启主机')
parser.add_argument('-D', '--destroyhost', nargs='?', dest='destroyhost', default='destroyhost', help='批量销毁主机')
if len(sys.argv) == 1:
html = parser.print_help()
print html
elif sys.argv[1] == '-A':
deploy_hosts()
else:
action_hosts()
查看执行效果
python cloud_cli.py -h
批量部署主机
填写target文件(被操作主机名)
> cat target
sh-ops-cloud-test-online-07
sh-ops-cloud-test-online-08
执行
python cloud_cli.py -A
批量查看主机
python cloud_cli.py -l
批量启动主机
python cloud_cli.py -S
- 好了,关于cloudstack的api操作到此为止,有其它需求的朋友可参考官方api介绍自行修改脚本。
- 近日在github上搜到一个写的很全的cloudapi项目,cloudstack-python-client,这个写的非常全,之后会以它为模板写。