blob: 1d3cb080a09e6ea49aa9c97c5b6953f87d8c2350 [file] [log] [blame]
#!/usr/bin/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 os.path
import optparse
import random
import sys
import types
from tashi.rpycservices.rpyctypes import NetworkConfiguration,\
DiskConfiguration, HostState, Instance, Host, TashiException
from tashi.utils.config import Config
from tashi import vmStates, hostStates, boolean, stringPartition, createClient
users = {}
networks = {}
def fetchUsers():
if (users == {}):
_users = client.getUsers()
for user in _users:
users[user.id] = user
def fetchNetworks():
if (networks == {}):
_networks = client.getNetworks()
for network in _networks:
networks[network.id] = network
def getUser():
fetchUsers()
if client.username != None:
userStr = client.username
else:
userStr = os.getenv("USER", "unknown")
for user in users:
if (users[user].name == userStr):
return users[user].id
raise TashiException({'msg':"Unknown user %s" % (userStr)})
def checkHid(host):
userId = getUser()
hosts = client.getHosts()
hostId = None
try:
hostId = int(host)
except:
for h in hosts:
if (h.name == host):
hostId = h.id
if (hostId is None):
raise TashiException({'msg':"Unknown host %s" % (str(host))})
# XXXstroucki permissions for host related stuff?
return hostId
def remoteCommand(command, *args):
global client
#print "Doing command %s args %s" % (command, args)
f = getattr(client, command, None)
rv = f(*args)
return rv
def setHostState(args):
global scriptname
parser = optparse.OptionParser()
parser.set_usage("%s setHostState [options]" % scriptname)
parser.add_option("--host", help="Set the state of this host (mandatory)", action="store", type="string", dest="hostname")
parser.add_option("--state", help="Change state to this value, e.g. Normal or Drained (mandatory)", action="store", type="string", dest="state")
(options, arguments) = parser.parse_args(args)
if options.hostname is None or options.state is None:
print "A mandatory option is missing\n"
parser.print_help()
sys.exit(-1)
hostId = checkHid(options.hostname)
rv = remoteCommand("setHostState", hostId, options.state)
print rv
return 0
def setHostNotes(args):
global scriptname
parser = optparse.OptionParser()
parser.set_usage("%s setHostNotes [options]" % scriptname)
parser.add_option("--host", help="Annotate this host with the note (mandatory)", action="store", type="string", dest="hostname")
parser.add_option("--notes", help="Annotate the host with this note (mandatory)", action="store", type="string", dest="notes")
(options, arguments) = parser.parse_args(args)
if options.hostname is None or options.notes is None:
print "A mandatory option is missing\n"
parser.print_help()
sys.exit(-1)
hostId = checkHid(options.hostname)
rv = remoteCommand("setHostNotes", hostId, options.notes)
print rv
return 0
def help(args):
global scriptname
print "Available commands:"
for (command, desc) in cmdsdesc:
print "%s\t\t%s" % (command, desc)
print "See %s <command> -h for help on these commands." % scriptname
return 0
""" Possible functions:
description = (
('addHost', 'Adds a new host to Tashi'),
('delHost', 'Removes a host from Tashi'),
('addUser', 'Adds a user to Tashi'),
('delUser', 'Removes a user from Tashi'),
('addNet', 'Adds a network to Tashi'),
('delNet', 'Removes a network from Tashi'),
('setHostState', 'Set the state of a host, eg. Normal or Drained'),
('setHostNotes', 'Annotate a host record'),
)
# Example use strings
examples = (
('addHost', ('--name <host name>',)),
('delHost', ('--name <host name>',)),
('addUser', ('--name <user name>',)),
('delUser', ('--name <user name>',)),
('addNet', ('--name <network name> --id <VLAN ID>',)),
('delNet', ('--name <network name>','--id <VLAN ID>',)),
('setHostState', ('--host <host name> --state <new state>',)),
('setHostNotes', ('--host <host name> --text <text string>',)),
)
show_hide = []
def usage(func = None):
"""Print program usage"""
if (func == None or func not in argLists):
if (func != None):
print "Unknown function %s" % (func)
print
functions = argLists
print "%s is the administrative tool for Tashi" % (os.path.basename(sys.argv[0]))
print "Tashi, a system for cloud-computing on BigData"
print "Visit http://incubator.apache.org/tashi/ for more information."
print
else:
functions = {func: argLists[func]}
print "Usage:"
for f in functions:
args = argLists[f]
line = "\t" + f
for arg in args:
if (arg[3]):
line += " --%s <value>" % (arg[0])
else:
line += " [--%s <value>]" % (arg[0])
print line
if ("--help" in sys.argv and f in description):
print
print "\t\t" + description[f]
print
if ("--examples" in sys.argv):
if ("--help" not in sys.argv or f not in description):
print
for example in examples.get(f, []):
print "\t\t" + f + " " + example
print
if ("--help" not in sys.argv and "--examples" not in sys.argv):
print
print "Additionally, all functions accept --show-<name> and --hide-<name>, which show and hide columns during table generation"
if ("--examples" not in sys.argv):
print "Use \"--examples\" to see examples"
sys.exit(-1)
def transformState(obj):
if (type(obj) == Instance):
fetchUsers()
try:
obj.state = vmStates[obj.state]
except:
obj.state = 'Unknown'
if (obj.userId in users):
obj.user = users[obj.userId].name
else:
obj.user = None
obj.disk = obj.disks[0].uri
if (obj.disks[0].persistent):
obj.disk += ":True"
elif (type(obj) == Host):
try:
obj.state = hostStates[obj.state]
except:
obj.state = 'Unknown'
def genKeys(_list):
keys = {}
for row in _list:
for item in row.__dict__.keys():
keys[item] = item
if ('id' in keys):
del keys['id']
keys = ['id'] + keys.values()
else:
keys = keys.values()
return keys
def makeTable(_list, keys=None):
(consoleWidth, __consoleHeight) = (9999, 9999)
try:
# XXXpipe: get number of rows and column on current window
stdout = os.popen("stty size")
__r = stdout.read()
stdout.close()
except:
pass
for obj in _list:
transformState(obj)
if (keys == None):
keys = genKeys(_list)
for (show, k) in show_hide:
if (show):
if (k != "all"):
keys.append(k)
else:
keys = genKeys(_list)
else:
if (k in keys):
keys.remove(k)
if (k == "all"):
keys = []
maxWidth = {}
for k in keys:
maxWidth[k] = len(k)
for row in _list:
for k in keys:
if (k in row.__dict__):
maxWidth[k] = max(maxWidth[k], len(str(row.__dict__[k])))
if (keys == []):
return
totalWidth = reduce(lambda x, y: x + y + 1, maxWidth.values(), 0)
while (totalWidth > consoleWidth):
widths = maxWidth.items()
widths.sort(cmp=lambda x, y: cmp(x[1], y[1]))
widths.reverse()
maxWidth[widths[0][0]] = widths[0][1]-1
totalWidth = reduce(lambda x, y: x + y + 1, maxWidth.values(), 0)
line = ""
for k in keys:
if (len(str(k)) > maxWidth[k]):
line += (" %-" + str(maxWidth[k]-3) + "." + str(maxWidth[k]-3) + "s...") % (k)
else:
line += (" %-" + str(maxWidth[k]) + "." + str(maxWidth[k]) + "s") % (k)
print line
line = ""
for k in keys:
line += ("-" * (maxWidth[k]+1))
print line
def sortFunction(a, b):
av = a.__dict__[keys[0]]
bv = b.__dict__[keys[0]]
if (av < bv):
return -1
elif (av > bv):
return 1
else:
return 0
_list.sort(cmp=sortFunction)
for row in _list:
line = ""
for k in keys:
row.__dict__[k] = row.__dict__.get(k, "")
if (len(str(row.__dict__[k])) > maxWidth[k]):
line += (" %-" + str(maxWidth[k]-3) + "." + str(maxWidth[k]-3) + "s...") % (str(row.__dict__[k]))
else:
line += (" %-" + str(maxWidth[k]) + "." + str(maxWidth[k]) + "s") % (str(row.__dict__[k]))
print line
def simpleType(obj):
"""Determines whether an object is a simple type -- used as a helper function to pprint"""
if (type(obj) is not types.ListType):
if (not getattr(obj, "__dict__", None)):
return True
return False
def pprint(obj, depth = 0, key = None):
"""My own version of pprint that prints out a dict in a readable, but slightly more compact format"""
valueManip = lambda x: x
if (key):
keyString = key + ": "
if (key == "state"):
valueManip = lambda x: vmStates[x]
else:
keyString = ""
if (type(obj) is types.ListType):
if (reduce(lambda x, y: x and simpleType(y), obj, True)):
print (" " * (depth * INDENT)) + keyString + str(obj)
else:
print (" " * (depth * INDENT)) + keyString + "["
for o in obj:
pprint(o, depth + 1)
print (" " * (depth * INDENT)) + "]"
elif (getattr(obj, "__dict__", None)):
if (reduce(lambda x, y: x and simpleType(y), obj.__dict__.itervalues(), True)):
print (" " * (depth * INDENT)) + keyString + str(obj)
else:
print (" " * (depth * INDENT)) + keyString + "{"
for (k, v) in obj.__dict__.iteritems():
pprint(v, depth + 1, k)
print (" " * (depth * INDENT)) + "}"
else:
print (" " * (depth * INDENT)) + keyString + str(valueManip(obj))
def matchFunction(func):
if (func == "--help" or func == "--examples"):
usage()
lowerFunc = func.lower()
lowerFuncsList = map(lambda x: (x.lower(), x), argLists.keys())
lowerFuncs = {}
for (l, f) in lowerFuncsList:
lowerFuncs[l] = f
if (lowerFunc in lowerFuncs):
return lowerFuncs[lowerFunc]
usage(func)
def main():
"""Main function for the client program"""
global INDENT, exitCode, client
exitCode = 0
exception = None
INDENT = (os.getenv("INDENT", 4))
if (len(sys.argv) < 2):
usage()
config = Config(["Client"])
# get command name
function = matchFunction(sys.argv[1])
# build a structure of possible arguments
possibleArgs = {}
argList = argLists[function]
for i in range(0, len(argList)):
possibleArgs[argList[i][0]]=argList[i]
args = sys.argv[2:]
vals = {}
try:
# create client handle
client = createClient(config)
# set defaults
for parg in possibleArgs.values():
(parg, conv, default, required) = parg
if (required is False):
vals[parg] = default()
while (len(args) > 0):
arg = args.pop(0)
if (arg == "--help" or arg == "--examples"):
usage(function)
# this exits
if (arg.startswith("--")):
if (arg[2:] in possibleArgs):
(parg, conv, default, required) = possibleArgs[arg[2:]]
try:
val = None
lookahead = args[0]
if not lookahead.startswith("--"):
val = args.pop(0)
except:
pass
val = conv(val)
if (val == None):
val = default()
vals[parg] = val
continue
# somewhat lame, but i don't want to rewrite the fn at this time
exception = ValueError("Unknown argument %s" % (arg))
f = None
try:
f = extraViews[function][0]
except:
pass
if (f is None):
f = getattr(client, function, None)
try:
if exception is not None:
raise exception
if (function in convertArgs):
fargs = eval(convertArgs[function], globals(), vals)
else:
fargs = []
res = f(*fargs)
except TashiException, e:
print "Failed in calling %s: %s" % (function, e.msg)
sys.exit(-1)
except Exception, e:
print "Failed in calling %s: %s" % (function, e)
print "Please run tashi-admin --examples for syntax information"
sys.exit(-1)
if (res != None):
keys = extraViews.get(function, (None, None))[1]
try:
if (type(res) == types.ListType):
makeTable(res, keys)
elif (type(res) == types.StringType):
print res
else:
makeTable([res], keys)
except IOError:
pass
except Exception, e:
print e
except TashiException, e:
print "Tashi could not complete your request:"
print e.msg
exitCode = e.errno
except Exception, e:
print e
print "Please run tashi-admin --examples for syntax information"
sys.exit(exitCode)
if __name__ == "__main__":
main()