Repository: ambari
Updated Branches:
  refs/heads/trunk e90fb2807 -> d90fd2b8b


AMBARI-18241 A wrapper util to validate blueprint by submitting it via 
blueprint REST API (dili)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d90fd2b8
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d90fd2b8
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d90fd2b8

Branch: refs/heads/trunk
Commit: d90fd2b8b3c5c11b46423f4deef395a25d3e88a5
Parents: e90fb28
Author: Di Li <[email protected]>
Authored: Wed Aug 24 10:52:19 2016 -0400
Committer: Di Li <[email protected]>
Committed: Wed Aug 24 10:52:19 2016 -0400

----------------------------------------------------------------------
 .../src/main/python/preinstall_checker.py       | 138 ++++++++++++++++---
 1 file changed, 121 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d90fd2b8/contrib/utils/preinstall-check/src/main/python/preinstall_checker.py
----------------------------------------------------------------------
diff --git 
a/contrib/utils/preinstall-check/src/main/python/preinstall_checker.py 
b/contrib/utils/preinstall-check/src/main/python/preinstall_checker.py
index 5d512b7..5da3772 100644
--- a/contrib/utils/preinstall-check/src/main/python/preinstall_checker.py
+++ b/contrib/utils/preinstall-check/src/main/python/preinstall_checker.py
@@ -18,6 +18,7 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 '''
 
+import uuid
 import datetime
 import time
 import json
@@ -36,6 +37,14 @@ has_errors=False
 #request types
 HTTP_REQUEST_GET='GET'
 HTTP_REQUEST_POST='POST'
+HTTP_REQUEST_DELETE='DELETE'
+
+#HTTP CODE
+HTTP_OK=200
+HTTP_CREATED=201
+HTTP_BAD_REQUEST=400
+HTTP_FORBIDDEN=403
+HTTP_CONFLICT=409
 
 #defaults
 EXIT_MESSAGE = "Make sure to provide correct cluster information including 
port, admin user name and password. Default values will be used if you omit the 
command parameters.";
@@ -52,15 +61,15 @@ DEFAULT_MINDISKSPACE=2.0 #in GB
 DEFAULT_MINDISKSPACEUSRLIB=1.0 #in GB
 
 #ops
-OPERATION_CHECK='check'
-OPERATIONS=[OPERATION_CHECK]
+OPERATION_HOST_CHECK='host_check'
+OPERATION_VALIDATE_BLUEPRINT='validate_blueprint'
+OPERATIONS=[OPERATION_HOST_CHECK, OPERATION_VALIDATE_BLUEPRINT]
 
 #codes
 CODE_SUCCESS=0
 CODE_ERROR=1
 CODE_WARNING=2
 CODE_CONNECTION_REFUSED=7
-HTTP_FORBIDDEN=403
 
 #labels
 LABEL_OK='[   OK  ]'
@@ -94,8 +103,13 @@ def init_parser_options(parser):
                     default=DEFAULT_LOG_DIR,
                     help="The log file home location. Default log file home is 
{0}.".format(DEFAULT_LOG_DIR),
                     metavar="DIR")
+  parser.add_option('--blueprint',
+                    dest="blueprint",
+                    default=None,
+                    help="Blueprint to validate",
+                    metavar="FILE")
   parser.add_option('--operation',
-                    dest='operation', default=OPERATION_CHECK,
+                    dest='operation', default=OPERATION_HOST_CHECK,
                     help='Operation can one of the following {0}'.format(', 
'.join(OPERATIONS)))
   parser.add_option("-v", "--verbose", dest="verbose", action="store_true", 
default=False, help="Output verbosity.")
 
@@ -120,7 +134,10 @@ def validate_options(options):
   if not options.operation:
     errors.append('No operation provided')
   elif not options.operation in OPERATIONS:
-      errors.append('Unknow operation {0}. Specify one of the following 
operations: {1}'.format(options.operation, ', '.join(OPERATIONS)))
+    errors.append('Unknow operation {0}. Specify one of the following 
operations: {1}'.format(options.operation, ', '.join(OPERATIONS)))
+  elif options.operation == OPERATION_VALIDATE_BLUEPRINT:
+    if not options.blueprint:
+      errors.append('No blueprint file provided')
 
   if not errors:
     return 'Parameters validation finished successfully', CODE_SUCCESS
@@ -297,6 +314,21 @@ def execute_curl_command(url, headers=[], 
request_type=DEFAULT_HTTP_REQUEST_TYPE
   exit_code = exeProcess.returncode
   return out, err, exit_code
 
+def get_http_response_code(out):
+  for a_line in out.split('\n'):
+    a_line = a_line.strip()
+    if a_line.endswith('HTTP/1.1 200 OK'):
+      return HTTP_OK
+    elif a_line.endswith('HTTP/1.1 201 Created'):
+      return HTTP_CREATED
+    elif a_line.endswith('HTTP/1.1 400 Bad Request'):
+      return HTTP_BAD_REQUEST
+    elif a_line.endswith('HTTP/1.1 409 Conflict'):
+      return HTTP_CONFLICT
+    elif a_line.endswith('HTTP/1.1 400 Forbidden'):
+      return HTTP_FORBIDDEN
+  return -1
+
 """
 Determine if Ambari Server responded with an error message for the REST API 
call
 """
@@ -894,10 +926,80 @@ def run_agent_checks(options, agents, server_url):
     reverse_lookup_checks_parser(task_results_by_host, results_to_print)
     print_check_results(results_to_print)
 
+def run_validate_blueprint(options, server_url):
+  results_to_print = []
+  blueprint_file = options.blueprint
+  label_check = 'Blueprint validation'
+  step(label_check)
+  logger.debug('Blueprint file to check {0}'.format(blueprint_file))
+  if os.path.isfile(blueprint_file):
+    """Validate blueprint file is a valid json file"""
+    valid_json_file = False
+    try:
+      with open(blueprint_file) as data_file:
+        data = json.load(data_file)
+        valid_json_file = True
+    except ValueError as value_error:
+      results_to_print.append({'key':label_check, 'status':STATUS_FAILED, 
'error':[str(value_error)]})
+
+    if valid_json_file:
+      """Either a timestamp based name or the name defined in the blueprint"""
+      blueprint_metadata = data.get('Blueprints', {})
+      blueprint_name = blueprint_metadata.get('blueprint_name', None)
+      if not blueprint_name:
+        blueprint_name = 'blueprint_validation_{0}'.format(str(uuid.uuid4()))
+      logger.debug('Blueprint name used for server side validation: 
{0}'.format(blueprint_name))
+      url = '{0}/api/v1/blueprints/{1}'.format(server_url, blueprint_name)
+      out, err, ec = execute_curl_command(url, request_type=HTTP_REQUEST_POST, 
request_body="@{0}".format(blueprint_file), user=options.user, 
password=options.password)
+      logger.debug(out)
+      logger.debug(err)
+      if CODE_ERROR == ec:
+        results_to_print.append({'key':label_check, 'status':STATUS_FAILED, 
'error':[err]})
+      else:
+        http_response_code = get_http_response_code(err)
+        logger.debug('HTTP response from the Ambari server: 
{0}'.format(http_response_code))
+        if http_response_code == HTTP_CREATED and not out :
+          results_to_print.append({'key':label_check, 'status':STATUS_PASSED})
+        else:
+          is_erroneous_response, http_ec, http_err = 
is_erroneous_response_by_server(out)
+          if is_erroneous_response:
+            results_to_print.append({'key':label_check, 
'status':STATUS_FAILED, 'error':[http_err]})
+          else:
+            results_to_print.append({'key':label_check, 
'status':STATUS_FAILED, 'error':[err]})
+  else:
+    results_to_print.append({'key':label_check, 'status':STATUS_FAILED, 
'error':['{0} does not exist'.format(blueprint_file)]})
+  print_check_results(results_to_print)
+  deregister_temporary_blueprint(options, server_url, blueprint_name)
+
+def deregister_temporary_blueprint(options, server_url, blueprint_name):
+  url = '{0}/api/v1/blueprints/{1}'.format(server_url, blueprint_name)
+  out, err, ec = execute_curl_command(url, request_type=HTTP_REQUEST_DELETE, 
user=options.user, password=options.password)
+  if CODE_ERROR == ec:
+    logger.error(out)
+    logger.error(err)
+  else:
+    logger.debug(out)
+    logger.debug(err)
+    http_response_code = get_http_response_code(err)
+    logger.debug('HTTP response from the Ambari server: 
{0}'.format(http_response_code))
+    if http_response_code == HTTP_OK and not out :
+      logger.debug("{0} deregistered".format(blueprint_name))
+    else:
+      is_erroneous_response, http_ec, http_err = 
is_erroneous_response_by_server(out)
+      if is_erroneous_response:
+        logger.error(http_err)
+      else:
+        logger.info(out)
+        if err:
+          logger.error(err)
+
 """
 Execute the operation passed in from the command line
 """
 def run(options):
+  global has_warnings
+  global has_errors
+
   server_url = get_server_url(options.port)
   label_check = 'Ambari server reachable by user credentials'
   step(label_check)
@@ -916,23 +1018,25 @@ def run(options):
     logger.error('No Ambari Agent registered to the Ambari Server. Install 
Ambari Agent first.')
     return CODE_ERROR
 
-  if OPERATION_CHECK == options.operation:
+  if OPERATION_HOST_CHECK == options.operation:
     run_host_checks(options, agents, server_url)
     run_java_home_checks(options, agents, server_url)
     run_agent_checks(options, agents, server_url)
+  elif OPERATION_VALIDATE_BLUEPRINT == options.operation:
+    run_validate_blueprint(options, server_url)
+
+  if has_errors:
     logger.info('')
-    global has_warnings
-    global has_errors
-    if has_errors:
-      logger.error('Checks finished with errors')
-    elif has_warnings:
-      logger.warning('Checks finished with warnings')
-    else:
-      logger.info('Checks finished')
-    return CODE_SUCCESS
-  else:
-    logger.error('Unknown operation {0}'.options.operation)
+    logger.error('Checks finished with errors')
     return CODE_ERROR
+  elif has_warnings:
+    logger.info('')
+    logger.warning('Checks finished with warnings')
+    return CODE_WARNING
+  else:
+    logger.info('')
+    logger.info('Checks finished')
+    return CODE_SUCCESS
 
 def main():
   parser = optparse.OptionParser(usage="usage: %prog [option] arg ... [option] 
arg",)

Reply via email to