#!/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. # Script to check if hcat_server is reachable. # Checks if databases can be enumerated, and databases can be created/dropped. import sys, os, random, string, logging, logging.handlers from optparse import OptionParser from decimal import * def generate_random_id( length=8, charset=(string.ascii_lowercase + string.digits) ): return ''.join(random.choice(charset) for i in range(length)) # PING-DB related "constants". HCAT_CHECK_DATABASE_NAME = 'hcat_ping_' + generate_random_id() HCAT_CHECK_DATABASE_LOCATION = '/tmp/hcat_ping/' + HCAT_CHECK_DATABASE_NAME ATTEMPT_CLEANUP=False logger = logging.getLogger() logLevels = [ logging.ERROR, logging.INFO, logging.DEBUG ] THE_CHECK_COMMAND = "" def check_unique_database_name(): global HCAT_CHECK_DATABASE_NAME global HCAT_CHECK_DATABASE_LOCATION # If directory already exists, pick a new database-name/location. while run_command_quietly("hadoop dfs -ls " + HCAT_CHECK_DATABASE_LOCATION) == 0: HCAT_CHECK_DATABASENAME = 'hcat_ping_' + generate_random_id() HCAT_CHECK_DATABASE_LOCATION = '/tmp/hcat_ping/' + HCAT_CHECK_DATABASE_NAME def run_command_quietly(command): global logger os.putenv("HADOOP_HOME_WARN_SUPPRESS", "true") return_code = os.system(command + " >/dev/null 2>&1") logger.debug("Running command: " + command + " ... returned " + str(return_code)) return return_code def run_hcat_command(command): return run_command_quietly(THE_CHECK_COMMAND + " -e \"" + command + "\" ") def init_ping_command(): global THE_CHECK_COMMAND if is_command_in_path("hcat"): THE_CHECK_COMMAND = "hcat" elif is_command_in_path("hive"): THE_CHECK_COMMAND = "hive" else: logger.error("Could not find hcat or hive in $PATH. Can't connect to \ HCatalog Server.") sys.exit(2) def is_command_in_path(command): return run_command_quietly("which " + command) == 0 def list_databases(): global logger return_code = run_hcat_command("SHOW DATABASES") if return_code != 0: logger.debug("Could not list-databases.") return False return True def create_database(): check_unique_database_name() global ATTEMPT_CLEANUP global logger ATTEMPT_CLEANUP = True # State is changing. Must attempt cleanup. create_db = "CREATE DATABASE " + HCAT_CHECK_DATABASE_NAME + " LOCATION '"+ HCAT_CHECK_DATABASE_LOCATION + "'" list_db_dir = "hadoop dfs -ls " + HCAT_CHECK_DATABASE_LOCATION if run_hcat_command(create_db) !=0 or run_command_quietly(list_db_dir) != 0: logger.debug("Creating database failed.") return False return True def drop_database(suppressError): global logger drop_db = "DROP DATABASE " + HCAT_CHECK_DATABASE_NAME list_db_dir = "hadoop dfs -ls " + HCAT_CHECK_DATABASE_LOCATION if run_hcat_command(drop_db) != 0 or run_command_quietly(list_db_dir) == 0: if not suppressError: logger.debug("Dropping database failed.") return False return True def cleanup(): drop_database(True) run_command_quietly( "hadoop dfs -rmr -skipTrash " + HCAT_CHECK_DATABASE_LOCATION ) def parse_options(): global logger global logLevels streamHandler = logging.StreamHandler() logger.addHandler(streamHandler) parser = OptionParser() parser.add_option("-v", "--verbose", dest="verbosity_level", help="Controls verbosity of output to LEVEL (0-2)", metavar="LEVEL", default="1") parser.add_option("-f", "--file", dest="filename", help="Write output to FILE", metavar="FILE") (options, args) = parser.parse_args() level = int(Decimal(options.verbosity_level)) if not level in range(0,3): print "Invalid verbosity level. Should be in range [0, 2]." sys.exit(3) if options.filename: logger.removeHandler(streamHandler) handler = logging.handlers.RotatingFileHandler(options.filename, maxBytes=1024*1024, backupCount=3) logger.addHandler(handler) else: handler = streamHandler formatter = logging.Formatter("%(asctime)s %(filename)s:%(lineno)d %(levelname)s - %(message)s") handler.setFormatter( formatter ) logger.setLevel( logLevels[level] ) def main(*args): global logger try: try: parse_options() init_ping_command() # Not making assumptions on availability of ternary. if list_databases() and create_database() and drop_database(False): logger.info("HCatalog Server is running fine.") return 0 # OK! else: logger.critical("HCatalog Server could not be contacted.") return 2 # Critical! except SystemExit, sysExit: return sysExit except Exception, e: logger.exception("Could not determine if HCatalog Server is running.") return 3 # Unknown Error. finally: # Nested try. Pre-2.5 Python won't allow try-except-finally. if ATTEMPT_CLEANUP: cleanup() if __name__ == '__main__': sys.exit( main(*sys.argv) )