blob: 1eccf59bcad684f897912d7504d2ac373edd95cd [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
import sys
import json
import glob
import tempfile
import subprocess
import shutil
SLIDER_DIR = os.getenv('SLIDER_HOME', None)
if SLIDER_DIR == None or (not os.path.exists(SLIDER_DIR)):
print "Unable to find SLIDER_HOME. Please configure SLIDER_HOME before running accumulo-slider"
sys.exit(1)
SLIDER_CMD = os.path.join(SLIDER_DIR, 'bin', 'slider.py')
TMP_DIR = os.path.join(tempfile.gettempdir(), "accumulo-slider-tmp."+str(os.getpid()))
CMD_OPTS = {}
def call(cmd):
print "Running: " + " ".join(cmd)
retcode = subprocess.call(cmd)
if retcode != 0:
raise Exception("return code from running %s was %d" % (cmd[0], retcode))
def exec_accumulo_command(command, args=[]):
ACCUMULO_DIR = os.getenv('ACCUMULO_HOME', None)
if ACCUMULO_DIR == None or (not os.path.exists(ACCUMULO_DIR)):
print "Unable to find ACCUMULO_HOME. Please configure ACCUMULO_HOME before running accumulo-slider " + command
sys.exit(1)
ACCUMULO_CMD = os.path.join(ACCUMULO_DIR, 'bin', 'accumulo')
confdir = get_all_conf()
if command == 'shell' or command == 'admin':
cmd = [ACCUMULO_CMD, command, '--config-file', os.path.join(confdir, 'client.conf')] + list(args)
else:
cmd = [ACCUMULO_CMD, command] + list(args)
print "Setting ACCUMULO_CONF_DIR=" + confdir
os.putenv("ACCUMULO_CONF_DIR", confdir)
call(cmd)
def exec_tool_command(jarfile, mainclass, args=[]):
ACCUMULO_DIR = os.getenv('ACCUMULO_HOME', None)
if ACCUMULO_DIR == None or (not os.path.exists(ACCUMULO_DIR)):
print "Unable to find ACCUMULO_HOME. Please configure ACCUMULO_HOME before running accumulo-slider tool"
sys.exit(1)
TOOL_CMD = os.path.join(ACCUMULO_DIR, 'bin', 'tool.sh')
confdir = get_all_conf()
cmd = [TOOL_CMD, jarfile, mainclass] + list(args)
print "Setting ACCUMULO_CONF_DIR=" + confdir
os.putenv("ACCUMULO_CONF_DIR", confdir)
call(cmd)
def jar(jarfile, *args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] jar jarfile [mainclass]]
OR: [accumulo-slider --appconf confdir jar jarfile [mainclass]]
Runs a class from a specified jar
"""
exec_accumulo_command("jar", jarfile, args=args)
def classname(mainclass, *args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] classname mainclass]
OR: [accumulo-slider --appconf confdir classname mainclass]
Runs a specified class on the existing accumulo classpath
"""
exec_accumulo_command(mainclass, args=args)
def shell(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] shell]
OR: [accumulo-slider --appconf confdir shell]
Runs an accumulo shell
"""
exec_accumulo_command("shell", args=args)
def admin(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] admin cmd]
OR: [accumulo-slider --appconf confdir admin cmd]
Executes an admin command (run without cmd argument for a list of commands)
"""
exec_accumulo_command("admin", args=args)
def classpath(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] classpath]
OR: [accumulo-slider --appconf confdir classpath]
Prints the classpath of the accumulo client install
"""
exec_accumulo_command("classpath", args=args)
def info(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] info]
OR: [accumulo-slider --appconf confdir info]
Prints information about an accumulo instance (monitor, masters, and zookeepers)
"""
exec_accumulo_command("info", args=args)
def rfileinfo(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] rfile-info rfilename]
OR: [accumulo-slider --appconf confdir rfile-info rfilename]
Prints information about a specified RFile
"""
exec_accumulo_command("rfile-info", args=args)
def logininfo(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] login-info]
OR: [accumulo-slider --appconf confdir login-info]
Prints the supported authentication token types for the accumulo instance
"""
exec_accumulo_command("login-info", args=args)
def createtoken(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] create-token]
OR: [accumulo-slider --appconf confdir create-token]
Saves a given accumulo authentication token to a file
"""
exec_accumulo_command("create-token", args=args)
def version(*args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] version]
OR: [accumulo-slider --appconf confdir version]
Prints the version of the accumulo client install
"""
exec_accumulo_command("version", args=args)
def tool(jarfile, mainclass, *args):
"""Syntax: [accumulo-slider --app appname[ --appconf confdir] tool jarfile classname]
OR: [accumulo-slider --appconf confdir tool jarfile classname]
Runs a mapreduce job using accumulo's tool.sh
"""
exec_tool_command(jarfile, mainclass, args=args)
def quicklinks():
"""Syntax: [accumulo-slider --app appname quicklinks]
Prints the quicklinks information of accumulo-slider registry
"""
global CMD_OPTS
if not 'app_name' in CMD_OPTS.keys():
print_usage()
sys.exit(1)
cmd = [SLIDER_CMD, "registry", "--getconf", "quicklinks", "--format", "json",
"--name", CMD_OPTS['app_name']]
if 'user' in CMD_OPTS.keys():
cmd.append( "--user "+CMD_OPTS['user'])
call(cmd)
def proxies():
"""Syntax: [accumulo-slider --app appname proxies]
Prints the componentinstancedata information of accumulo-slider registry
"""
global CMD_OPTS
if not 'app_name' in CMD_OPTS.keys():
print_usage()
sys.exit(1)
cmd = [SLIDER_CMD, "registry", "--getconf", "componentinstancedata",
"--format", "json", "--name", CMD_OPTS['app_name']]
if 'user' in CMD_OPTS.keys():
cmd.append( "--user "+CMD_OPTS['user'])
call(cmd)
def install(dir):
"""Syntax: [accumulo-slider --app appname install dir]
Installs a fully configured accumulo client in the specified dir
The resulting client may be used on its own without accumulo-slider
"""
global CMD_OPTS
if not 'app_name' in CMD_OPTS.keys():
print_usage()
sys.exit(1)
if os.path.exists(dir):
raise Exception("Install dir must not exist: " + dir)
global TMP_DIR
workdir = os.path.join(TMP_DIR, 'install-work-dir')
statusfile = os.path.join(workdir, 'status.json')
cmd = [SLIDER_CMD, "status", CMD_OPTS['app_name'], "--out", statusfile]
call(cmd)
infile = open(statusfile)
try:
content = json.load(infile)
finally:
infile.close()
appdef = content['options']['application.def']
appdeffile = appdef[appdef.rfind('/')+1:]
cmd = ["hadoop", "fs", "-copyToLocal", appdef, workdir]
call(cmd)
cmd = ["unzip", os.path.join(workdir, appdeffile), "-d", workdir]
call(cmd)
gzfile = glob.glob(os.path.join(workdir, 'package', 'files', 'accumulo*gz'))
if len(gzfile) != 1:
raise Exception("got " + gzfile + " from glob")
cmd = ["tar", "xvzf", gzfile[0], '-C', workdir]
call(cmd)
tmp_accumulo = glob.glob(os.path.join(workdir, 'accumulo-[0-9]*'))
if len(tmp_accumulo) != 1:
raise Exception("got " + tmp_accumulo + " from glob")
tmp_accumulo = tmp_accumulo[0]
confdir = os.path.join(tmp_accumulo, 'conf')
tmpconf = os.path.join(workdir, 'conf-tmp')
shutil.move(confdir, tmpconf)
make_conf(os.path.join(tmpconf, 'templates'), confdir)
libdir = os.path.join(tmp_accumulo, 'lib')
for jar in glob.glob(os.path.join(workdir, 'package', 'files', '*jar')):
shutil.move(jar, libdir)
shutil.move(tmp_accumulo, dir)
def get_all_conf():
"""Syntax: [accumulo-slider --app appname [--appconf confdir] getconf]
Downloads configuration for an accumulo instance
If --appconf is specified, creates the specified conf dir and populates it
"""
ACCUMULO_CONF_DIR = os.getenv('ACCUMULO_CONF_DIR', None)
if ACCUMULO_CONF_DIR == None or (not os.path.exists(ACCUMULO_CONF_DIR)):
ACCUMULO_DIR = os.getenv('ACCUMULO_HOME', None)
if ACCUMULO_DIR == None or (not os.path.exists(ACCUMULO_DIR)):
print "Unable to find ACCUMULO_HOME. Please configure ACCUMULO_HOME before running this command"
sys.exit(1)
ACCUMULO_CONF_DIR = os.path.join(ACCUMULO_DIR, 'conf')
global CMD_OPTS
global TMP_DIR
confdir = os.path.join(TMP_DIR, 'conf')
if 'app_conf' in CMD_OPTS.keys():
confdir = CMD_OPTS['app_conf']
if os.path.exists(confdir):
print "Using existing app conf instead of downloading it again: " + confdir
return confdir
if not 'app_name' in CMD_OPTS.keys():
print_usage()
sys.exit(1)
make_conf(ACCUMULO_CONF_DIR, confdir)
return confdir
def make_conf(oldconf, newconf):
client_file = os.path.join(newconf, 'client.conf')
site_file = os.path.join(newconf, 'accumulo-site.xml')
env_file = os.path.join(newconf, 'accumulo-env.sh')
env_json = os.path.join(newconf, 'accumulo-env.json')
print "Copying base conf from " + oldconf + " to " + newconf
shutil.copytree(oldconf, newconf)
try_remove(client_file)
try_remove(site_file)
try_remove(env_file)
try_remove(env_json)
get_conf("client", "properties", client_file)
get_conf("accumulo-site", "xml", site_file)
get_conf("accumulo-env", "json", env_json)
infile = open(env_json)
outfile = open(env_file, 'w')
try:
content = json.load(infile)
outfile.write(content['content'])
finally:
outfile.close()
infile.close()
def try_remove(path):
try:
os.remove(path)
except:
if os.path.exists(path):
raise
def get_conf(confname, fileformat, destfile):
if os.path.exists(destfile):
print "Conf file " + destfile + " already exists, remove it to re-download"
return
cmd = [SLIDER_CMD, "registry", "--getconf", confname, "--format",
fileformat, "--dest", destfile, "--name", CMD_OPTS['app_name']]
if 'user' in CMD_OPTS.keys():
cmd.append("--user " + CMD_OPTS['user'])
call(cmd)
if not os.path.exists(destfile):
raise Exception("Failed to read slider deployed accumulo config " + confname)
def print_commands():
"""Print all client commands and link to documentation"""
print "Commands:\n\t", "\n\t".join(sorted(COMMANDS.keys()))
print "\nHelp:", "\n\thelp", "\n\thelp <command>"
def print_usage(command=None):
"""Print one help message or list of available commands"""
if command != None:
if COMMANDS.has_key(command):
print (COMMANDS[command].__doc__ or
"No documentation provided for <%s>" % command)
else:
print "<%s> is not a valid command" % command
else:
print "Usage:"
print "accumulo-slider --app <name>[ --appconf <confdir> --user <username>] <command>"
print " The option --appconf creates a conf dir that can be reused;"
print " on subsequent calls to accumulo-slider, --app can be left off if"
print " --appconf is specified. If --appconf is not specified, a"
print " temporary conf dir is created each time accumulo-slider is run."
print_commands()
def unknown_command(*args):
print "Unknown command: [accumulo-slider %s]" % ' '.join(sys.argv[1:])
print_usage()
COMMANDS = {"shell": shell, "tool": tool, "admin": admin, "classpath": classpath,
"info": info, "version": version, "jar": jar, "classname": classname,
"quicklinks" : quicklinks, "proxies": proxies, "getconf": get_all_conf,
"rfile-info": rfileinfo, "login-info": logininfo, "create-token": createtoken,
"install": install, "help": print_usage}
def parse_config_opts(args):
curr = args[:]
curr.reverse()
global CMD_OPTS
args_list = []
while len(curr) > 0:
token = curr.pop()
if token == "--app":
CMD_OPTS['app_name'] = curr.pop() if (len(curr) != 0) else None
elif token == "--user":
CMD_OPTS['user'] = curr.pop() if (len(curr) != 0) else None
elif token == "--appconf":
CMD_OPTS['app_conf'] = curr.pop() if (len(curr) != 0) else None
else:
args_list.append(token)
return args_list
def main():
args = parse_config_opts(sys.argv[1:])
if len(args) < 1:
print_usage()
sys.exit(-1)
COMMAND = args[0]
ARGS = args[1:]
try:
(COMMANDS.get(COMMAND, unknown_command))(*ARGS)
finally:
global CMD_OPTS
if os.path.exists(TMP_DIR):
print "Cleaning up tmp dir " + TMP_DIR
shutil.rmtree(TMP_DIR)
if __name__ == "__main__":
main()