diff --git a/cloud-cli/bindir/cloud-tool b/cloud-cli/bindir/cloud-tool deleted file mode 100755 index 4fcc8342228..00000000000 --- a/cloud-cli/bindir/cloud-tool +++ /dev/null @@ -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) diff --git a/cloud-cli/bindir/cloudvoladm b/cloud-cli/bindir/cloudvoladm deleted file mode 100755 index 16f31bde89f..00000000000 --- a/cloud-cli/bindir/cloudvoladm +++ /dev/null @@ -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 @ @ 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) diff --git a/cloud-cli/cloudapis/__init__.py b/cloud-cli/cloudapis/__init__.py deleted file mode 100644 index f23b2ce2fbf..00000000000 --- a/cloud-cli/cloudapis/__init__.py +++ /dev/null @@ -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 - diff --git a/cloud-cli/cloudapis/cloud.py b/cloud-cli/cloudapis/cloud.py deleted file mode 100644 index a0e88805c82..00000000000 --- a/cloud-cli/cloudapis/cloud.py +++ /dev/null @@ -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("", "\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 - - diff --git a/cloud-cli/cloudtool/__init__.py b/cloud-cli/cloudtool/__init__.py deleted file mode 100644 index c4b479eb790..00000000000 --- a/cloud-cli/cloudtool/__init__.py +++ /dev/null @@ -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) diff --git a/cloud-cli/cloudtool/utils.py b/cloud-cli/cloudtool/utils.py deleted file mode 100644 index e123434614a..00000000000 --- a/cloud-cli/cloudtool/utils.py +++ /dev/null @@ -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 = "" - cmd_name = "" - 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