Removed cloud-cli folder and contents, as it is not maintained or used anymore.

This commit is contained in:
Boris Schrijver 2015-12-12 14:57:51 +01:00
parent bdaa60fd6c
commit 7f2bbcbfff
6 changed files with 0 additions and 1116 deletions

View File

@ -1,28 +0,0 @@
#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import cloudtool
ret = cloudtool.main()
if ret: sys.exit(ret)

View File

@ -1,607 +0,0 @@
#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import sys
import os
import subprocess
import cloudtool
import urllib2
from optparse import OptionParser, OptionGroup, OptParseError, BadOptionError, OptionError, OptionConflictError, OptionValueError
import xml.dom.minidom
NetAppServerIP=None
NetAppUserName=None
NetAppPassword=None
CloudStackSvrIP=None
CloudStackSvrPort=8096
cmds=["createvol","deletevol", "listvol", "createlun", "listlun", "destroylun", "assoclun", "disassoclun", "createpool", "modifypool", "destroypool", "listpools"]
header = "Volume Manager CLI, the available COMMANDS are:"
def cmd_help():
print header
print
print "createpool add a new pool to the system"
print "modifypool change the allocation algorithm for a pool"
print "destroypool destroy a pool"
print "listpools list all the pools"
print "createvol add volume to a storage server"
print "deletevol delete volume on a storage server"
print "listvol list volume on a storage server"
print "createlun create LUN on a storage server"
print "listlun list LUN on a storage server"
print "destroylun destroy LUN on a storage server"
print "assoclun assoc LUN on a storage server"
print "disassoclun disassoc LUN on a storage server"
print
print "\"cloudvoladm COMMAND --help\" for more information on a specific command"
print
print "Global Options:"
print "--cloudStackMgtSvrIP the IP address of CloudStack Management Server"
print
print "Config file is ~/.cloudvoladmrc, Config options including: "
print "cloudStackMgtSvrIP=Cloudstack Management Server Address, which can be overriden by --cloudStackMgtSvrIP. If neither is provided, localhost is used."
usage="Volume Manager CLI: add a new volume to a storage pool"
addvolParser= OptionParser(usage)
addvolParser.add_option("-i", metavar="server ip", dest="server_ip", help="The IP address of the storage server")
addvolParser.add_option("-u", metavar="username", dest="username", help="username to access the storage server with")
addvolParser.add_option("-w", metavar="password", dest="password", help="the password to access the storage server with")
addvolParser.add_option("-p", dest="pool_name", help="the name of the pool to allocate from")
addvolParser.add_option("-a", dest="aggregate_name", help="the name of aggregate")
addvolParser.add_option("-v", dest="vol_name", help="the name of volume")
addvolParser.add_option("-s", dest="size", help="size in GB eg.1")
optionalGroup = OptionGroup(addvolParser, "Optional")
optionalGroup.add_option("-r", dest="percentage", help="Percentage used for snapshot reserve")
optionalGroup.add_option("-S", dest="snapshots", help="Snapshot schedule in <weeks> <days> <hours>@<which-hours> <minutes>@<which-minutes> e.g. \"2 4 5@1,4 6@2,5\"")
addvolParser.add_option_group(optionalGroup)
usage="Volume Manager CLI: remove a volume from a pool"
delvolParser= OptionParser(usage)
delvolParser.add_option("-i", metavar="server ip", dest="server_ip", help="The IP address of the storage server")
delvolParser.add_option("-a", dest="aggregate_name", help="The name of aggregate")
delvolParser.add_option("-v", dest="vol_name", help="The name of volume")
usage="Volume Manager CLI: list all volumes known to exist in a pool"
listvolParser= OptionParser(usage)
listvolParser.add_option("-p", dest="pool_name", help="The name of the pool to list volumes from")
usage="Volume Manager CLI: create a LUN on a pool"
createlunParser = OptionParser(usage)
createlunParser.add_option("-p", dest="pool_name", help="The name of the pool to add the volume to")
createlunParser.add_option("-s", dest="size", help="The size in GB e.g. 100")
usage="Volume Manager CLI: list LUN on a pool"
listlunParser = OptionParser(usage)
listlunParser.add_option("-p", dest="pool_name", help="The pool name")
usage="Volume Manager CLI: destroy a LUN "
destroylunParser = OptionParser(usage)
destroylunParser.add_option("-l", dest="lun_name", help="The LUN name")
usage="Volume Manager CLI: Add a new pool to the system"
createPoolParser = OptionParser(usage)
createPoolParser.add_option("-p", dest="pool_name", help="The pool name")
createPoolParser.add_option("-A", dest="algorithm", help="roundrobin or leastfull")
usage="Volume Manager CLI: change the allocation algorithm for a pool"
modifyPoolParser = OptionParser(usage)
modifyPoolParser.add_option("-p", dest="pool_name", help="The pool name")
modifyPoolParser.add_option("-A", dest="algorithm", help="roundrobin or leastfull")
usage="Volume Manager CLI: destroy a pool"
destroyPoolParser = OptionParser(usage)
destroyPoolParser.add_option("-p", dest="pool_name", help="The pool name")
usage="Volume Manager CLI: list pools"
listPoolParser = OptionParser(usage)
usage="Volume Manager CLI: associate a LUN with a guest that uses the stated IQN as client"
assocLunParser = OptionParser(usage)
assocLunParser.add_option("-g", dest="guest_iqn", help="the guest IQN. By default, it reads from /etc/iscsi/initiatorname.iscsi")
assocLunParser.add_option("-l", dest="lun_name", help="The LUN name")
usage="Volume Manager CLI: disassociate a LUN with a guest that uses the stated IQN as client"
disassocLunParser = OptionParser(usage)
disassocLunParser.add_option("-g", dest="guest_iqn", help="the guest IQN. By default, it reads from /etc/iscsi/initiatorname.iscsi")
disassocLunParser.add_option("-l", dest="lun_name", help="The LUN name")
cmdParsers = {cmds[0]:addvolParser, cmds[1]:delvolParser, cmds[2]:listvolParser, cmds[3]:createlunParser, cmds[4]:listlunParser,
cmds[5]:destroylunParser, cmds[6]:assocLunParser, cmds[7]:disassocLunParser, cmds[8]:createPoolParser, cmds[9]:modifyPoolParser, cmds[10]:destroyPoolParser, cmds[11]:listPoolParser}
def validate_parameter(input, signature):
(options, args) = signature.parse_args([])
inputDict = input.__dict__
sigDict = options.__dict__
for k,v in sigDict.iteritems():
inputValue = inputDict[k]
if inputValue == None:
print "Volume Manager CLI: missing operand "
print
signature.parse_args(["--help"])
def help_callback(option, opt, value, parser):
argv = sys.argv[1:]
try:
argv.remove(opt)
except:
argv.remove("--h")
if len(argv) == 0:
cmd_help()
return
(options, args) = parser.parse_args(argv)
for cmd in cmds:
if cmd == args[0]:
cmdParsers[cmd].parse_args(["--help"])
def Help():
usage = "usage: %prog cmd[createpool|listpools|modifypool|destroypool|createvol|deletevol|listvol|createlun|listlun|destroylun|assoclun|disassoclun] arg1 arg2 [--help, -h]"
parser = OptionParser(usage=usage, add_help_option=False)
parser.add_option("-h", "--help", action="callback", callback=help_callback);
parser.add_option("-i", metavar="server ip", dest="server_ip", help="The IP address of the storage server")
parser.add_option("--cloudstackSvr", dest="cloudstackSvr", help="cloudStack Server IP")
parser.add_option("-u", metavar="username", dest="username", help="username to access the storage server with")
parser.add_option("-w", metavar="password", dest="password", help="the password to access the storage server with")
parser.add_option("-p", dest="pool_name", help="the name of the pool to allocate from")
parser.add_option("-v", dest="vol_name", help="the name of volume")
parser.add_option("-A", dest="algorithm", help="roundrobin or leastfull")
parser.add_option("-a", dest="aggregate_name", help="The name of aggregate")
parser.add_option("-o", dest="options", help="requested option string for the NFS export or attach")
parser.add_option("-S", dest="snapshots", help="Snapshot schedule e.g.2 4 5@1,4 6@2,5")
parser.add_option("-r", dest="percentage", help="Percentage used for snapshot reservation")
parser.add_option("-s", dest="size", help="size in GB eg.1")
parser.add_option("-t", dest="target_iqn", help="the target IQN")
parser.add_option("-g", dest="guest_iqn", help="the guest IQN")
parser.add_option("-l", dest="lun_name", help="the LUN name")
return parser
def httpErrorHandler(code, msg):
try:
errtext = xml.dom.minidom.parseString(msg)
if errtext.getElementsByTagName("errortext") is not None:
err = getText(errtext.getElementsByTagName("errortext")[0].childNodes).strip()
print err
except:
print "Internal Error %s"%msg
def getText(nodelist):
rc = []
for node in nodelist:
if node.nodeType == node.TEXT_NODE: rc.append(node.data)
return ''.join(rc)
def createvol(options):
args = []
if options.pool_name == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
if options.aggregate_name == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
if options.vol_name == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
if options.snapshots != None:
args += ['--snapshotpolicy=' + options.snapshots]
if options.size == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
if options.percentage != None:
args += ['--snapshotreservation=' + options.percentage]
if NetAppServerIP == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
if NetAppUserName == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
if NetAppPassword == None:
print "Volume Manager CLI: missing operand "
print
addvolParser.parse_args(["--help"])
'''
snapshot = options.snapshots
tokens = snapshot.split(" ")
print tokens
pos = 0;
for token in tokens:
if pos == 0:
#week
try:
week = int(token)
if week < 0:
raise
except:
print "Pls input correct week"
sys.exit(1)
elif pos == 1:
try:
day = int(token)
if day < 0:
raise
except:
print "Pls input correct day"
sys.exit(1)
elif pos == 2:
try:
hours = token.split("@")
if int(hours[0]) < 0:
raise
hourlists = hours[1].split(",")
for hour in hourlists:
if int(hour) < 0 or int(hour) > 24:
raise
except:
print "Pls input correct hour"
sys.exit(1)
elif pos == 3:
try:
minutes = token.split("@")
if int(minutes[0]) < 0:
raise
minuteslist = minutes[1].split(",")
for minute in minuteslist:
if int(minute) < 0 or int(minute) > 60:
raise
except:
print "Pls input correct hour"
sys.exit(1)
'''
try:
output = cloudtool.main(['cloud-tool', 'createVolumeOnFiler', '--ipaddress=' + NetAppServerIP , '--aggregatename=' + options.aggregate_name,
'--poolname=' + options.pool_name, '--volumename=' + options.vol_name,
'--size=' + options.size,
'--username=' + NetAppUserName, '--password=' + NetAppPassword, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"] + args)
print "Successfully added volume"
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing createvol cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing createvol cmd failed: %s" % (err.reason)
sys.exit(1)
def deletevol(options):
validate_parameter(options, delvolParser)
try:
output = cloudtool.main(['cloud-tool', 'destroyVolumeOnFiler', '--ipaddress=' + NetAppServerIP, '--aggregatename=' + options.aggregate_name,
'--volumename=' + options.vol_name, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
print "Successfully deleted volume"
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing deletevol cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing deletevol cmd failed: %s" % (err.reason)
sys.exit(1)
def listvol(options):
validate_parameter(options, listvolParser)
try:
output = cloudtool.main(['cloud-tool', 'listVolumesOnFiler', '--poolname=' + options.pool_name, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"]).strip("\n")
xmlResult = xml.dom.minidom.parseString(output)
print "%-10s %-20s %-20s %-40s %-20s %-30s "%('Id', 'Address', 'Aggregate', 'Volume', 'Size(GB)', 'snapshotPolicy', )
for volume in xmlResult.getElementsByTagName("volume"):
aggregatename = getText(volume.getElementsByTagName('aggregatename')[0].childNodes).strip()
id = getText(volume.getElementsByTagName('id')[0].childNodes).strip()
volumeName = getText(volume.getElementsByTagName('volumename')[0].childNodes).strip()
snapshotPolicy = getText(volume.getElementsByTagName('snapshotpolicy')[0].childNodes).strip()
ipaddress = getText(volume.getElementsByTagName('ipaddress')[0].childNodes).strip()
volSize = getText(volume.getElementsByTagName('size')[0].childNodes).strip()
print "%-10s %-20s %-20s %-40s %-20s %-30s "%(id, ipaddress, aggregatename, volumeName, volSize, snapshotPolicy)
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing listvol cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing listvol cmd failed: %s" % (err.reason)
sys.exit(1)
def createlun(options):
validate_parameter(options, createlunParser)
try:
output = cloudtool.main(['cloud-tool', 'createLunOnFiler', '--name=' + options.pool_name,
'--size=' + options.size, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
xmlResult = xml.dom.minidom.parseString(output.strip("\n"))
path = getText(xmlResult.getElementsByTagName("path")[0].childNodes).strip()
iqn = getText(xmlResult.getElementsByTagName("iqn")[0].childNodes).strip()
ipAddr = getText(xmlResult.getElementsByTagName('ipaddress')[0].childNodes).strip()
print "%-30s %-30s %-50s "%('LUN Name', 'Address', 'Target IQN')
print "%-30s %-30s %-50s "%(path, ipAddr, iqn)
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing createlun cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing createlun cmd failed: %s" % (err.reason)
sys.exit(1)
def listlun(options):
validate_parameter(options, listlunParser)
args = ["--poolname=" + options.pool_name, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"]
try:
output = cloudtool.main(['cloud-tool', 'listLunsOnFiler'] + args).strip("\n")
xmlResult = xml.dom.minidom.parseString(output)
print "%-10s %-10s %-50s %-30s "%('LUN Id', 'Volume Id', 'Target IQN', 'LUN Name')
for volume in xmlResult.getElementsByTagName("lun"):
uuid = getText(volume.getElementsByTagName('id')[0].childNodes).strip()
path = getText(volume.getElementsByTagName('name')[0].childNodes).strip()
targetiqn = getText(volume.getElementsByTagName('iqn')[0].childNodes).strip()
volumeId = getText(volume.getElementsByTagName('volumeid')[0].childNodes).strip()
print "%-10s %-10s %-50s %-30s "%(uuid, volumeId, targetiqn, path)
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing listlun cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing listlun cmd failed: %s" % (err.reason)
sys.exit(1)
def destroylun(options):
validate_parameter(options, destroylunParser)
try:
output = cloudtool.main(['cloud-tool', 'destroyLunOnFiler', '--path=' + options.lun_name,
"--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
print "Successfully destroyed LUN"
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing destroylun cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing destroylun failed: %s" % (err.reason)
sys.exit(1)
def assoclun(options):
validate_parameter(options, assocLunParser)
try:
output = cloudtool.main(['cloud-tool', 'associateLun', '--name=' + options.lun_name,
'--iqn=' + options.guest_iqn, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
xmlResult = xml.dom.minidom.parseString(output.strip("\n"))
lunid = getText(xmlResult.getElementsByTagName("id")[0].childNodes).strip()
iqn = getText(xmlResult.getElementsByTagName("targetiqn")[0].childNodes).strip()
ipAddr = getText(xmlResult.getElementsByTagName('ipaddress')[0].childNodes).strip()
print "%-30s %-30s %-50s "%('LUN Id', 'Address', 'Target IQN')
print "%-30s %-30s %-50s" % (lunid, ipAddr, iqn)
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing assoclun cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing assoclun failed: %s" % (err.reason)
sys.exit(1)
def disassoclun(options):
validate_parameter(options, disassocLunParser)
try:
output = cloudtool.main(['cloud-tool', 'dissociateLun', '--path=' + options.lun_name,
'--iqn=' + options.guest_iqn, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
print "Successfully dissociated LUN"
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing disassoclun cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing disassoclun failed: %s" % (err.reason)
sys.exit(1)
def createpool(options):
validate_parameter(options, createPoolParser)
if not (options.algorithm == "roundrobin" or options.algorithm == "leastfull"):
print "Only roundrobin or leastfull algorithm is supported"
sys.exit(1)
try:
output = cloudtool.main(['cloud-tool', 'createPool', '--name=' + options.pool_name,
'--algorithm=' + options.algorithm, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
print "Successfully created pool"
except urllib2.HTTPError, err:
code = err.code
print "executing createpool cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, err.read())
sys.exit(1)
except urllib2.URLError, err:
print "executing createpool failed: %s" % (err.reason)
sys.exit(1)
def listpools(options):
try:
output = cloudtool.main(['cloud-tool', 'listPools',
"--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
output = output.strip("\n")
xmlResult = xml.dom.minidom.parseString(output)
print "%-10s %-40s %-10s" %('Id', 'Pool Name', 'Algorithm')
for volume in xmlResult.getElementsByTagName("pool"):
id = getText(volume.getElementsByTagName('id')[0].childNodes).strip()
poolname = getText(volume.getElementsByTagName('name')[0].childNodes).strip()
alg = getText(volume.getElementsByTagName('algorithm')[0].childNodes).strip()
print "%-10s %-40s %-10s"%(id, poolname, alg)
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing listpools cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing listpools failed, due to: %s" % (err.reason)
sys.exit(1)
def modifypool(options):
validate_parameter(options, modifyPoolParser)
try:
output = cloudtool.main(['cloud-tool', 'modifyPool', '--poolname=' + options.pool_name,
'--algorithm=' + options.algorithm, "--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
print "Successfully modified pool"
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing modifypool cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing modifypool failed, due to: %s" % (err.reason)
sys.exit(1)
def destroypool(options):
validate_parameter(options, destroyPoolParser)
try:
output = cloudtool.main(['cloud-tool', 'deletePool', '--poolname=' + options.pool_name,
"--server=" + CloudStackSvrIP + ":" + str(CloudStackSvrPort), "--stripxml=false"])
print "Successfully destroyed pool: " + options.pool_name
except urllib2.HTTPError, err:
code = err.code
msg = err.read()
print "executing destroypool cmd failed, http returning error code: %s" % (code)
httpErrorHandler(code, msg)
sys.exit(1)
except urllib2.URLError, err:
print "executing destroypool failed, due to: %s" % (err.reason)
sys.exit(1)
def loadCfgFile():
options = dict()
try:
cfgFile = open(os.environ['HOME'] + "/.cloudvoladmrc")
for line in cfgFile:
option = line.split("=")
if option[0] == "cloudStackMgtSvrIP":
options["cloudStackMgtSvrIP"] = option[1].strip("\n")
except:
return None
return options
def getGuestIQN():
try:
initialFile = open("/etc/iscsi/initiatorname.iscsi")
for line in initialFile:
iqn = line.split("=")
if iqn[0] == "InitiatorName":
return iqn[1].strip("\n")
except:
return None
return None
if __name__ == '__main__':
parser = Help()
(options, args) = parser.parse_args()
globalCfg = loadCfgFile()
NetAppServerIP= options.server_ip
NetAppUserName = options.username
NetAppPassword = options.password
CloudStackSvrIP = options.cloudstackSvr
if CloudStackSvrIP == None:
if globalCfg != None and "cloudStackMgtSvrIP" in globalCfg:
CloudStackSvrIP = globalCfg["cloudStackMgtSvrIP"]
if CloudStackSvrIP == None:
CloudStackSvrIP = "127.0.0.1"
if options.guest_iqn == None:
GuestIQN = getGuestIQN()
options.__dict__["guest_iqn"] = GuestIQN
if len(args) == 0:
sys.exit(1)
cmd = args[0]
if cmd == "createvol":
createvol(options)
elif cmd == "deletevol":
deletevol(options)
elif cmd == "listvol":
listvol(options)
elif cmd == "createlun":
createlun(options)
elif cmd == "listlun":
listlun(options)
elif cmd == "destroylun":
destroylun(options)
elif cmd == "assoclun":
assoclun(options)
elif cmd == "disassoclun":
disassoclun(options)
elif cmd == "createpool":
createpool(options)
elif cmd == "modifypool":
modifypool(options)
elif cmd == "destroypool":
destroypool(options)
elif cmd == "listpools":
listpools(options)
else:
print "Unrecoginzied command"
cmd_help()
sys.exit(1)

View File

@ -1,43 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
'''
Created on Aug 2, 2010
'''
import os,pkgutil
def get_all_apis():
apis = []
for x in pkgutil.walk_packages([os.path.dirname(__file__)]):
loader = x[0].find_module(x[1])
try: module = loader.load_module("cloudapis." + x[1])
except ImportError: continue
apis.append(module)
return apis
def lookup_api(api_name):
api = None
matchingapi = [ x for x in get_all_apis() if api_name.replace("-","_") == x.__name__.split(".")[-1] ]
if not matchingapi: api = None
else: api = matchingapi[0]
if api: api = getattr(api,"implementor")
return api

View File

@ -1,198 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
'''Implements the CloudStack API'''
from cloudtool.utils import describe
import urllib
import urllib2
import os
import xml.dom.minidom
import re
import base64
import hmac
import hashlib
import httplib
class CloudAPI:
@describe("server", "Management Server host name or address")
@describe("apikey", "Management Server apiKey")
@describe("securitykey", "Management Server securityKey")
@describe("responseformat", "Response format: xml or json")
@describe("stripxml", "True if xml tags have to be stripped in the output, false otherwise")
def __init__(self,
server="127.0.0.1:8096",
responseformat="xml",
stripxml="true",
apiKey=None,
securityKey=None
):
self.__dict__.update(locals())
def _make_request_with_keys(self,command,requests={}):
requests["command"] = command
requests["apiKey"] = self.apiKey
requests["response"] = "xml"
requests = zip(requests.keys(), requests.values())
requests.sort(key=lambda x: str.lower(x[0]))
requestUrl = "&".join(["=".join([request[0], urllib.quote_plus(str(request[1]))]) for request in requests])
hashStr = "&".join(["=".join([str.lower(request[0]), urllib.quote_plus(str.lower(str(request[1])))]) for request in requests])
sig = urllib.quote_plus(base64.encodestring(hmac.new(self.securityKey, hashStr, hashlib.sha1).digest()).strip())
requestUrl += "&signature=%s"%sig
return requestUrl
def _make_request_with_auth(self, command, requests):
self.connection = httplib.HTTPConnection("%s"%(self.server))
requests["command"] = command
requests["apiKey"] = self.apiKey
requests["response"] = self.responseformat
requests = zip(requests.keys(), requests.values())
requests.sort(key=lambda x: str.lower(x[0]))
requestUrl = "&".join(["=".join([request[0], urllib.quote(str(request[1],""))]) for request in requests])
hashStr = "&".join(["=".join([str.lower(request[0]), urllib.quote(str.lower(str(request[1])),"")]) for request in requests])
sig = urllib.quote_plus(base64.encodestring(hmac.new(self.securityKey, str.lower(hashStr), hashlib.sha1).digest()).strip())
requestUrl += "&signature=%s"%sig
self.connection.request("GET", "/client/api?%s"%requestUrl)
return self.connection.getresponse().read()
def _make_request(self,command,parameters=None):
'''Command is a string, parameters is a dictionary'''
if ":" in self.server:
host,port = self.server.split(":")
port = int(port)
else:
host = self.server
port = 8096
url = "http://" + self.server + "/client/api?"
if not parameters: parameters = {}
if self.apiKey is not None and self.securityKey is not None:
return self._make_request_with_auth(command, parameters)
else:
parameters["command"] = command
parameters["response"] = self.responseformat
querystring = urllib.urlencode(parameters)
url += querystring
f = urllib2.urlopen(url)
data = f.read()
if self.stripxml == "true":
data=re.sub("<\?.*\?>", "\n", data);
data=re.sub("</[a-z]*>", "\n", data);
data=data.replace(">", "=");
data=data.replace("=<", "\n");
data=data.replace("\n<", "\n");
data=re.sub("\n.*cloud-stack-version=.*", "", data);
data=data.replace("\n\n\n", "\n");
return data
def load_dynamic_methods():
'''creates smart function objects for every method in the commands.xml file'''
def getText(nodelist):
rc = []
for node in nodelist:
if node.nodeType == node.TEXT_NODE: rc.append(node.data)
return ''.join(rc)
# FIXME figure out installation and packaging
xmlfile = os.path.join("/etc/cloud/cli/","commands.xml")
dom = xml.dom.minidom.parse(xmlfile)
for cmd in dom.getElementsByTagName("command"):
name = getText(cmd.getElementsByTagName('name')[0].childNodes).strip()
assert name
description = getText(cmd.getElementsByTagName('description')[0].childNodes).strip()
if description:
description = '"""%s"""' % description
else: description = ''
arguments = []
options = []
descriptions = []
for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"):
argname = getText(param.getElementsByTagName('name')[0].childNodes).strip()
assert argname
required = getText(param.getElementsByTagName('required')[0].childNodes).strip()
if required == 'true': required = True
elif required == 'false': required = False
else: raise AssertionError, "Not reached"
if required: arguments.append(argname)
options.append(argname)
#import ipdb; ipdb.set_trace()
requestDescription = param.getElementsByTagName('description')
if requestDescription:
descriptionParam = getText(requestDescription[0].childNodes)
else:
descriptionParam = ''
if descriptionParam: descriptions.append( (argname,descriptionParam) )
funcparams = ["self"] + [ "%s=None"%o for o in options ]
funcparams = ", ".join(funcparams)
code = """
def %s(%s):
%s
parms = dict(locals())
del parms["self"]
for arg in %r:
if locals()[arg] is None:
raise TypeError, "%%s is a required option"%%arg
for k,v in parms.items():
if v is None: del parms[k]
output = self._make_request("%s",parms)
return output
"""%(name,funcparams,description,arguments,name)
namespace = {}
exec code.strip() in namespace
func = namespace[name]
for argname,description in descriptions:
func = describe(argname,description)(func)
yield (name,func)
for name,meth in load_dynamic_methods():
setattr(CloudAPI, name, meth)
implementor = CloudAPI
del name,meth,describe,load_dynamic_methods

View File

@ -1,71 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
'''
Created on Aug 2, 2010
'''
import sys
import cloudapis as apis
import cloudtool.utils as utils
def main(argv=None):
#import ipdb; ipdb.set_trace()
if argv == None:
argv = sys.argv
prelim_args = [ x for x in argv[0:] if not x.startswith('-') ]
parser = utils.get_parser()
api = __import__("cloudapis")
apis = getattr(api, "implementor")
if len(prelim_args) == 1:
commandlist = utils.get_command_list(apis)
parser.error("you need to specify a command name as the first argument\n\nCommands supported by the %s API:\n"%prelim_args[0] + "\n".join(commandlist))
command = utils.lookup_command_in_api(apis,prelim_args[1])
if not command: parser.error("command %r not supported by the %s API"%(prelim_args[1],prelim_args[0]))
argv = argv[1:]
if len(argv) == 1:
argv.append("--help")
parser = utils.get_parser(apis.__init__,command)
opts,args,api_optionsdict,cmd_optionsdict = parser.parse_args(argv)
try:
api = apis(**api_optionsdict)
except utils.OptParseError,e:
parser.error(str(e))
command = utils.lookup_command_in_api(api,args[0])
# we now discard the first two arguments as those necessarily are the api and command names
args = args[2:]
try: return command(*args,**cmd_optionsdict)
except TypeError,e: parser.error(str(e))
if __name__ == '__main__':
main(argv)

View File

@ -1,169 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
'''
Created on Aug 2, 2010
'''
import sys
import os
import inspect
from optparse import OptionParser, OptParseError, BadOptionError, OptionError, OptionConflictError, OptionValueError
import cloudapis as apis
def describe(name,desc):
def inner(decoratee):
if not hasattr(decoratee,"descriptions"): decoratee.descriptions = {}
decoratee.descriptions[name] = desc
return decoratee
return inner
def error(msg):
sys.stderr.write(msg)
sys.stderr.write("\n")
class MyOptionParser(OptionParser):
def error(self, msg):
error("%s: %s\n" % (self.get_prog_name(),msg))
self.print_usage(sys.stderr)
self.exit(os.EX_USAGE)
def parse_args(self,*args,**kwargs):
options,arguments = OptionParser.parse_args(self,*args,**kwargs)
def prune_options(options,alist):
"""Given 'options' -- a list of arguments to OptionParser.add_option,
and a set of optparse Values, return a dictionary of only those values
that apply exclusively to 'options'"""
return dict( [ (k,getattr(options,k)) for k in dir(options) if k in alist ] )
api_options = prune_options(options,self.api_dests)
cmd_options = prune_options(options,self.cmd_dests)
return options,arguments,api_options,cmd_options
def get_parser(api_callable=None,cmd_callable=None): # this should probably be the __init__ method of myoptionparser
def getdefaulttag(default):
if default is not None: return " [Default: %default]"
return ''
def get_arguments_and_options(callable):
"""Infers and returns arguments and options based on a callable's signature.
Cooperates with decorator @describe"""
try:
funcargs = inspect.getargspec(callable).args
defaults = inspect.getargspec(callable).defaults
except:
funcargs = inspect.getargspec(callable)[0]
defaults = inspect.getargspec(callable)[3]
if not defaults: defaults = []
args = funcargs[1:len(funcargs)-len(defaults)] # this assumes self, so assumes methods
opts = funcargs[len(funcargs)-len(defaults):]
try: descriptions = callable.descriptions
except AttributeError: descriptions = {}
arguments = [ (argname, descriptions.get(argname,'') ) for argname in args ]
options = [ [
("--%s"%argname.replace("_","-"),),
{
"dest":argname,
"help":descriptions.get(argname,'') + getdefaulttag(default),
"default":default,
}
] for argname,default in zip(opts,defaults) ]
return arguments,options
basic_usage = "usage: %prog [options...] "
api_name = "<api>"
cmd_name = "<command>"
description = "%prog is a command-line tool to access several cloud APIs."
arguments = ''
argexp = ""
if api_callable:
api_name = api_callable.__module__.split(".")[-1].replace("_","-")
api_arguments,api_options = get_arguments_and_options(api_callable)
assert len(api_arguments) is 0 # no mandatory arguments for class initializers
if cmd_callable:
cmd_name = cmd_callable.func_name.replace("_","-")
cmd_arguments,cmd_options = get_arguments_and_options(cmd_callable)
if cmd_arguments:
arguments = " " + " ".join( [ s[0].upper() for s in cmd_arguments ] )
argexp = "\n\nArguments:\n" + "\n".join ( " %s\n %s"%(s.upper(),u) for s,u in cmd_arguments )
description = cmd_callable.__doc__
api_command = "%s %s"%(api_name,cmd_name)
if description: description = "\n\n" + description
else: description = ''
usage = basic_usage + api_command + arguments + description + argexp
parser = MyOptionParser(usage=usage, add_help_option=False)
parser.add_option('--help', action="help")
group = parser.add_option_group("General options")
group.add_option('-v', '--verbose', dest="verbose", help="Print extra output")
parser.api_dests = []
if api_callable and api_options:
group = parser.add_option_group("Options for the %s API"%api_name)
for a in api_options:
group.add_option(a[0][0],**a[1])
parser.api_dests.append(a[1]["dest"])
parser.cmd_dests = []
if cmd_callable and cmd_options:
group = parser.add_option_group("Options for the %s command"%cmd_name)
for a in cmd_options:
group.add_option(a[0][0],**a[1])
parser.cmd_dests.append(a[1]["dest"])
return parser
def lookup_command_in_api(api,command_name):
command = getattr(api,command_name.replace("-","_"),None)
return command
def get_api_list(api):
apilist = []
for cmd_name in dir(api):
cmd = getattr(api,cmd_name)
if callable(cmd) and not cmd_name.startswith("_"):
apilist.append(cmd_name)
return apilist
def get_command_list(api):
cmds = []
for cmd_name in dir(api):
cmd = getattr(api,cmd_name)
if callable(cmd) and not cmd_name.startswith("_"):
if cmd.__doc__:docstring = cmd.__doc__
else:docstring = ''
cmds.append( " %s" % (cmd_name.replace('_','-')) )
return cmds