python调用cloudstack api批量操作机器

前言:公司为优化资源占用和节约服务器成本,考虑自建私有云平台,最初领导有考虑用当下最火的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调用cloudstack api批量操作机器_第1张图片
查询
python cloud_api.py -h
python调用cloudstack api批量操作机器_第2张图片
help

对主机进行操作

python cloud_api.py -S sh-ops-cloud-test-online-02
python调用cloudstack api批量操作机器_第3张图片
action

批量执行脚本

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
python调用cloudstack api批量操作机器_第4张图片
help

批量部署主机

填写target文件(被操作主机名)

> cat target
sh-ops-cloud-test-online-07
sh-ops-cloud-test-online-08

执行

 python cloud_cli.py -A
python调用cloudstack api批量操作机器_第5张图片
addhosts

批量查看主机

python cloud_cli.py -l
listhosts

批量启动主机

python cloud_cli.py -S
starthosts
  • 好了,关于cloudstack的api操作到此为止,有其它需求的朋友可参考官方api介绍自行修改脚本。
  • 近日在github上搜到一个写的很全的cloudapi项目,cloudstack-python-client,这个写的非常全,之后会以它为模板写。

你可能感兴趣的:(python调用cloudstack api批量操作机器)