ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From swa...@apache.org
Subject git commit: AMBARI-4355. Add relocate resources scripts to the pom file. (swagle)
Date Tue, 21 Jan 2014 18:52:05 GMT
Updated Branches:
  refs/heads/branch-1.4.4 735f0698b -> 9b9a4bab8


AMBARI-4355. Add relocate resources scripts to the pom file. (swagle)


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

Branch: refs/heads/branch-1.4.4
Commit: 9b9a4bab8a7b6a1bd4ef8b0370cace5dd78aa57d
Parents: 735f069
Author: Siddharth Wagle <swagle@hortonworks.com>
Authored: Tue Jan 21 10:50:40 2014 -0800
Committer: Siddharth Wagle <swagle@hortonworks.com>
Committed: Tue Jan 21 10:50:40 2014 -0800

----------------------------------------------------------------------
 ambari-server/pom.xml                           |   3 +
 .../scripts/relocate_host_components.py         | 489 +++++++++++++++++++
 .../resources/scripts/relocate_resources.py     | 489 -------------------
 3 files changed, 492 insertions(+), 489 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9b9a4bab/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 8b16de7..28a9daa 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -352,6 +352,9 @@
                 <source>
                   <location>src/main/python/UpgradeHelper_HDP2.py</location>
                 </source>
+                <source>
+                  <location>src/main/resources/scripts/relocate_host_components.py</location>
+                </source>
               </sources>
             </mapping>
             <mapping>

http://git-wip-us.apache.org/repos/asf/ambari/blob/9b9a4bab/ambari-server/src/main/resources/scripts/relocate_host_components.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/relocate_host_components.py b/ambari-server/src/main/resources/scripts/relocate_host_components.py
new file mode 100644
index 0000000..f9b71a0
--- /dev/null
+++ b/ambari-server/src/main/resources/scripts/relocate_host_components.py
@@ -0,0 +1,489 @@
+#!/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 optparse
+import sys
+import os
+import logging
+import tempfile
+import urllib2
+import socket
+import json
+import base64
+import time
+
+AMBARI_HOSTNAME = None
+AMBARI_PORT = 8080
+CLUSTER_NAME = None
+PROTOCOL = "http"
+USERNAME = "admin"
+PASSWORD = "admin"
+DEFAULT_TIMEOUT = 10 # seconds
+START_ON_RELOCATE = False
+
+# Supported Actions
+RELOCATE_ACTION = 'relocate'
+ALLOWED_ACTUAL_STATES_FOR_RELOCATE = [ 'INIT', 'UNKNOWN', 'MAINTENANCE', 'UNINSTALLED' ]
+ALLOWED_HOST_STATUS_FOR_RELOCATE = [ 'HEALTHY' ]
+STATUS_WAIT_TIMEOUT = 120 # seconds
+STATUS_CHECK_INTERVAL = 10 # seconds
+
+# API calls
+GET_CLUSTERS_URI = "/api/v1/clusters/"
+GET_HOST_COMPONENTS_URI = "/api/v1/clusters/{0}/services/{1}/components/{2}" +\
+                          "?fields=host_components"
+GET_HOST_COMPONENT_DESIRED_STATE_URI = "/api/v1/clusters/{0}/hosts/{1}" +\
+                                       "/host_components/{2}" +\
+                                       "?fields=HostRoles/desired_state"
+GET_HOST_COMPONENT_STATE_URI = "/api/v1/clusters/{0}/hosts/{1}" +\
+                               "/host_components/{2}" +\
+                               "?fields=HostRoles/state"
+GET_HOST_STATE_URL = "/api/v1/clusters/{0}/hosts/{1}?fields=Hosts/host_state"
+HOST_COMPONENT_URI = "/api/v1/clusters/{0}/hosts/{1}/host_components/{2}"
+ADD_HOST_COMPONENT_URI = "/api/v1/clusters/{0}/hosts?Hosts/host_name={1}"
+
+logger = logging.getLogger()
+
+
+
+class PreemptiveBasicAuthHandler(urllib2.BaseHandler):
+
+  def __init__(self):
+    password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
+    password_mgr.add_password(None, getUrl(''), USERNAME, PASSWORD)
+    self.passwd = password_mgr
+    self.add_password = self.passwd.add_password
+
+  def http_request(self, req):
+    uri = req.get_full_url()
+    user = USERNAME
+    pw = PASSWORD
+    raw = "%s:%s" % (user, pw)
+    auth = 'Basic %s' % base64.b64encode(raw).strip()
+    req.add_unredirected_header('Authorization', auth)
+    return req
+
+
+class AmbariResource:
+
+  def __init__(self, serviceName, componentName):
+    self.serviveName = serviceName
+    self.componentName = componentName
+    self.isInitialized = False
+
+  def initializeResource(self):
+    global CLUSTER_NAME
+    if CLUSTER_NAME is None:
+      CLUSTER_NAME = self.findClusterName()
+
+    if self.serviveName is None:
+      raise Exception('Service name undefined')
+
+    if self.componentName is None:
+      raise Exception('Component name undefined')
+
+    handler = PreemptiveBasicAuthHandler()
+    opener = urllib2.build_opener(handler)
+    # Install opener for all requests
+    urllib2.install_opener(opener)
+    self.urlOpener = opener
+
+    self.old_hostname = self.getHostname()
+
+    self.isInitialized = True
+
+
+  def relocate(self, new_hostname):
+    if not self.isInitialized:
+      raise Exception('Resource not initialized')
+
+    # If old and new hostname are the same exit harmlessly
+    if self.old_hostname == new_hostname:
+      logger.error('New hostname is same as existing host name, %s' % self.old_hostname)
+      sys.exit(2)
+    pass
+
+    try:
+      self.verifyHostComponentStatus(self.old_hostname, new_hostname, self.componentName)
+    except Exception, e:
+      logger.error("Exception caught on verify relocate request.")
+      logger.error(e.message)
+      sys.exit(3)
+
+    # Put host component in Maintenance state
+    self.updateHostComponentStatus(self.old_hostname, self.componentName,
+                                   "Maintenance", "MAINTENANCE")
+
+    # Delete current host component
+    self.deleteHostComponent(self.old_hostname, self.componentName)
+
+    # Add component on the new host
+    self.addHostComponent(new_hostname, self.componentName)
+
+    # Install host component
+    self.updateHostComponentStatus(new_hostname, self.componentName,
+                                   "Installing", "INSTALLED")
+
+    # Wait on install
+    self.waitOnHostComponentUpdate(new_hostname, self.componentName,
+                                   "INSTALLED")
+
+    if START_ON_RELOCATE:
+      # Start host component
+      self.updateHostComponentStatus(new_hostname, self.componentName,
+                                     "Starting", "STARTED")
+
+      # Wait on start
+      self.waitOnHostComponentUpdate(new_hostname, self.componentName, "STARTED")
+    pass
+  pass
+
+  def waitOnHostComponentUpdate(self, hostname, componentName, status):
+    logger.info("Waiting for host component status to update ...")
+    sleep_itr = 0
+    state = None
+    while sleep_itr < STATUS_WAIT_TIMEOUT:
+      try:
+        state = self.getHostComponentState(hostname, componentName)
+        if status == state:
+          logger.info("Status update successful. status: %s" % state)
+          return
+        pass
+      except Exception, e:
+        logger.error("Caught an exception waiting for status update.. "
+                     "continuing to wait...")
+      pass
+
+      time.sleep(STATUS_CHECK_INTERVAL)
+      sleep_itr += STATUS_CHECK_INTERVAL
+    pass
+    if state and state != status:
+      logger.error("Timed out on wait, status unchanged. status = %s" % state)
+      sys.exit(1)
+    pass
+  pass
+
+  def addHostComponent(self, hostname, componentName):
+    data = '{"host_components":[{"HostRoles":{"component_name":"%s"}}]}' % self.componentName
+    req = urllib2.Request(getUrl(ADD_HOST_COMPONENT_URI.format(CLUSTER_NAME,
+                          hostname)), data)
+
+    req.add_header("X-Requested-By", "ambari_probe")
+    req.get_method = lambda: 'POST'
+    try:
+      logger.info("Adding host component: %s" % req.get_full_url())
+      resp = self.urlOpener.open(req)
+      self.logResponse('Add host component response: ', resp)
+    except Exception, e:
+      logger.error('Create host component failed, component: {0}, host: {1}'
+                    .format(componentName, hostname))
+      logger.error(e)
+      raise e
+    pass
+
+  def deleteHostComponent(self, hostname, componentName):
+    req = urllib2.Request(getUrl(HOST_COMPONENT_URI.format(CLUSTER_NAME,
+                                hostname, componentName)))
+    req.add_header("X-Requested-By", "ambari_probe")
+    req.get_method = lambda: 'DELETE'
+    try:
+      logger.info("Deleting host component: %s" % req.get_full_url())
+      resp = self.urlOpener.open(req)
+      self.logResponse('Delete component response: ', resp)
+    except Exception, e:
+      logger.error('Delete {0} failed.'.format(componentName))
+      logger.error(e)
+      raise e
+    pass
+
+  def updateHostComponentStatus(self, hostname, componentName, contextStr, status):
+    # Update host component
+    data = '{"RequestInfo":{"context":"%s %s"},"Body":{"HostRoles":{"state":"%s"}}}' % (contextStr,
self.componentName, status)
+    req = urllib2.Request(getUrl(HOST_COMPONENT_URI.format(CLUSTER_NAME,
+                                hostname, componentName)), data)
+    req.add_header("X-Requested-By", "ambari_probe")
+    req.get_method = lambda: 'PUT'
+    try:
+      logger.info("%s host component: %s" % (contextStr, req.get_full_url()))
+      resp = self.urlOpener.open(req)
+      self.logResponse('Update host component response: ', resp)
+    except Exception, e:
+      logger.error('Update Status {0} failed.'.format(componentName))
+      logger.error(e)
+      raise e
+    pass
+
+  def verifyHostComponentStatus(self, old_hostname, new_hostname, componentName):
+    # Check desired state of host component is not STOPPED or host is
+    # unreachable
+    actualState = self.getHostComponentState(old_hostname, componentName)
+
+    if actualState not in ALLOWED_ACTUAL_STATES_FOR_RELOCATE:
+      raise Exception('Aborting relocate action since host component '
+                      'state is %s' % actualState)
+
+    hostState = self.getHostSatus(new_hostname)
+    if hostState not in ALLOWED_HOST_STATUS_FOR_RELOCATE:
+      raise Exception('Aborting relocate action since host state is %s' % hostState)
+
+    pass
+
+  def getHostSatus(self, hostname):
+    hostStateUrl = getUrl(GET_HOST_STATE_URL.format(CLUSTER_NAME, hostname))
+
+    logger.info("Requesting host status: %s " % hostStateUrl)
+    urlResponse = self.urlOpener.open(hostStateUrl)
+    state = None
+
+    if urlResponse:
+      response = urlResponse.read()
+      data = json.loads(response)
+      logger.debug('Response from getHostSatus: %s' % data)
+      if data:
+        try:
+          hostsInfo = data.get('Hosts')
+          if not hostsInfo:
+            raise Exception('Cannot find host state for host: {1}'.format(hostname))
+
+          state = hostsInfo.get('host_state')
+        except Exception, e:
+          logger.error('Unable to parse json data. %s' % data)
+          raise e
+        pass
+
+      else:
+        logger.error("Unable to retrieve host state.")
+      pass
+
+    return state
+
+
+  def getHostComponentState(self, hostname, componentName):
+    hostStatusUrl = getUrl(GET_HOST_COMPONENT_STATE_URI.format(CLUSTER_NAME,
+                                hostname, componentName))
+
+    logger.info("Requesting host component state: %s " % hostStatusUrl)
+    urlResponse = self.urlOpener.open(hostStatusUrl)
+    state = None
+
+    if urlResponse:
+      response = urlResponse.read()
+      data = json.loads(response)
+      logger.debug('Response from getHostComponentState: %s' % data)
+      if data:
+        try:
+          hostRoles = data.get('HostRoles')
+          if not hostRoles:
+            raise Exception('Cannot find host component state for component: ' +\
+                            '{0}, host: {1}'.format(componentName, hostname))
+
+          state = hostRoles.get('state')
+        except Exception, e:
+          logger.error('Unable to parse json data. %s' % data)
+          raise e
+        pass
+
+      else:
+        logger.error("Unable to retrieve host component desired state.")
+      pass
+
+    return state
+
+
+  # Log response for PUT, POST or DELETE
+  def logResponse(self, text=None, response=None):
+    if response is not None:
+      resp = str(response.getcode())
+      if text is None:
+        text = 'Logging response from server: '
+      if resp is not None:
+        logger.info(text + resp)
+
+  def findClusterName(self):
+    clusterUrl = getUrl(GET_CLUSTERS_URI)
+    clusterName = None
+
+    logger.info("Requesting clusters: " + clusterUrl)
+    urlResponse = self.urlOpener.open(clusterUrl)
+    if urlResponse is not None:
+      response = urlResponse.read()
+      data = json.loads(response)
+      logger.debug('Response from findClusterName: %s' % data)
+      if data:
+        try:
+          clusters = data.get('items')
+          if len(clusters) > 1:
+            raise Exception('Multiple clusters found. %s' % clusters)
+
+          clusterName = clusters[0].get('Clusters').get('cluster_name')
+        except Exception, e:
+          logger.error('Unable to parse json data. %s' % data)
+          raise e
+        pass
+      else:
+        logger.error("Unable to retrieve clusters data.")
+      pass
+
+    return clusterName
+
+  def getHostname(self):
+    hostsUrl = getUrl(GET_HOST_COMPONENTS_URI.format(CLUSTER_NAME,
+                  self.serviveName, self.componentName))
+
+    logger.info("Requesting host info: " + hostsUrl)
+    urlResponse = self.urlOpener.open(hostsUrl)
+    hostname = None
+
+    if urlResponse is not None:
+      response = urlResponse.read()
+      data = json.loads(response)
+      logger.debug('Response from getHostname: %s' % data)
+      if data:
+        try:
+          hostRoles = data.get('host_components')
+          if not hostRoles:
+            raise Exception('Cannot find host component data for service: ' +\
+                            '{0}, component: {1}'.format(self.serviveName, self.componentName))
+          if len(hostRoles) > 1:
+            raise Exception('More than one hosts found with the same role')
+
+          hostname = hostRoles[0].get('HostRoles').get('host_name')
+        except Exception, e:
+          logger.error('Unable to parse json data. %s' % data)
+          raise e
+        pass
+
+      else:
+        logger.error("Unable to retrieve host component data.")
+      pass
+
+    return hostname
+
+
+def getUrl(partial_url):
+  return PROTOCOL + "://" + AMBARI_HOSTNAME + ":" + AMBARI_PORT + partial_url
+
+def get_supported_actions():
+  return [ RELOCATE_ACTION ]
+
+#
+# Main.
+#
+def main():
+  tempDir = tempfile.gettempdir()
+  outputFile = os.path.join(tempDir, "ambari_reinstall_probe.out")
+
+  parser = optparse.OptionParser(usage="usage: %prog [options]")
+  parser.set_description('This python program is a Ambari thin client and '
+                         'supports relocation of ambari host components on '
+                         'Ambari managed clusters.')
+
+  parser.add_option("-v", "--verbose", dest="verbose", action="store_false",
+                  default=False, help="output verbosity.")
+  parser.add_option("-s", "--host", dest="server_hostname",
+                  help="Ambari server host name.")
+  parser.add_option("-p", "--port", dest="server_port",
+                  default="8080" ,help="Ambari server port. [default: 8080]")
+  parser.add_option("-r", "--protocol", dest="protocol", default = "http",
+                  help="Protocol for communicating with Ambari server ("
+                       "http/https) [default: http].")
+  parser.add_option("-c", "--cluster-name", dest="cluster_name",
+                  help="Ambari cluster to operate on.")
+  parser.add_option("-e", "--service-name", dest="service_name",
+                  help="Ambari Service to which the component belongs to.")
+  parser.add_option("-m", "--component-name", dest="component_name",
+                  help="Ambari Service Component to operate on.")
+  parser.add_option("-n", "--new-host", dest="new_hostname",
+                  help="New host to relocate the component to.")
+  parser.add_option("-a", "--action", dest="action", default = "relocate",
+                  help="Script action. [default: relocate]")
+  parser.add_option("-o", "--output-file", dest="outputfile",
+                  default = outputFile, metavar="FILE",
+                  help="Output file. [default: %s]" % outputFile)
+  parser.add_option("-u", "--username", dest="username",
+                  default="admin" ,help="Ambari server admin user. [default: admin]")
+  parser.add_option("-w", "--password", dest="password",
+                  default="admin" ,help="Ambari server admin password.")
+  parser.add_option("-d", "--start-component", dest="start_component",
+                  action="store_false", default=False,
+                  help="Should the script start the component after relocate.")
+
+  (options, args) = parser.parse_args()
+
+  # set verbose
+  if options.verbose:
+    logging.basicConfig(level=logging.DEBUG)
+  else:
+    logging.basicConfig(level=logging.INFO)
+
+  global AMBARI_HOSTNAME
+  AMBARI_HOSTNAME = options.server_hostname
+
+  global AMBARI_PORT
+  AMBARI_PORT = options.server_port
+
+  global CLUSTER_NAME
+  CLUSTER_NAME = options.cluster_name
+
+  global PROTOCOL
+  PROTOCOL = options.protocol
+
+  global USERNAME
+  USERNAME = options.username
+
+  global PASSWORD
+  PASSWORD = options.password
+
+  global START_ON_RELOCATE
+  START_ON_RELOCATE = options.start_component
+
+  global logger
+  logger = logging.getLogger('AmbariProbe')
+  handler = logging.FileHandler(options.outputfile)
+  formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
+  handler.setFormatter(formatter)
+  logger.addHandler(handler)
+
+  action = RELOCATE_ACTION
+
+  if options.action is not None:
+    if options.action not in get_supported_actions():
+      logger.error("Unsupported action: " + options.action + ", "
+                  "valid actions: " + str(get_supported_actions()))
+      sys.exit(1)
+    else:
+      action = options.action
+
+  socket.setdefaulttimeout(DEFAULT_TIMEOUT)
+
+  ambariResource = AmbariResource(serviceName=options.service_name,
+                                  componentName=options.component_name)
+  ambariResource.initializeResource()
+
+  if action == RELOCATE_ACTION:
+    if options.new_hostname is not None:
+      ambariResource.relocate(options.new_hostname)
+
+if __name__ == "__main__":
+  try:
+    main()
+  except (KeyboardInterrupt, EOFError):
+    print("\nAborting ... Keyboard Interrupt.")
+    sys.exit(1)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9b9a4bab/ambari-server/src/main/resources/scripts/relocate_resources.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/relocate_resources.py b/ambari-server/src/main/resources/scripts/relocate_resources.py
deleted file mode 100644
index f9b71a0..0000000
--- a/ambari-server/src/main/resources/scripts/relocate_resources.py
+++ /dev/null
@@ -1,489 +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 optparse
-import sys
-import os
-import logging
-import tempfile
-import urllib2
-import socket
-import json
-import base64
-import time
-
-AMBARI_HOSTNAME = None
-AMBARI_PORT = 8080
-CLUSTER_NAME = None
-PROTOCOL = "http"
-USERNAME = "admin"
-PASSWORD = "admin"
-DEFAULT_TIMEOUT = 10 # seconds
-START_ON_RELOCATE = False
-
-# Supported Actions
-RELOCATE_ACTION = 'relocate'
-ALLOWED_ACTUAL_STATES_FOR_RELOCATE = [ 'INIT', 'UNKNOWN', 'MAINTENANCE', 'UNINSTALLED' ]
-ALLOWED_HOST_STATUS_FOR_RELOCATE = [ 'HEALTHY' ]
-STATUS_WAIT_TIMEOUT = 120 # seconds
-STATUS_CHECK_INTERVAL = 10 # seconds
-
-# API calls
-GET_CLUSTERS_URI = "/api/v1/clusters/"
-GET_HOST_COMPONENTS_URI = "/api/v1/clusters/{0}/services/{1}/components/{2}" +\
-                          "?fields=host_components"
-GET_HOST_COMPONENT_DESIRED_STATE_URI = "/api/v1/clusters/{0}/hosts/{1}" +\
-                                       "/host_components/{2}" +\
-                                       "?fields=HostRoles/desired_state"
-GET_HOST_COMPONENT_STATE_URI = "/api/v1/clusters/{0}/hosts/{1}" +\
-                               "/host_components/{2}" +\
-                               "?fields=HostRoles/state"
-GET_HOST_STATE_URL = "/api/v1/clusters/{0}/hosts/{1}?fields=Hosts/host_state"
-HOST_COMPONENT_URI = "/api/v1/clusters/{0}/hosts/{1}/host_components/{2}"
-ADD_HOST_COMPONENT_URI = "/api/v1/clusters/{0}/hosts?Hosts/host_name={1}"
-
-logger = logging.getLogger()
-
-
-
-class PreemptiveBasicAuthHandler(urllib2.BaseHandler):
-
-  def __init__(self):
-    password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
-    password_mgr.add_password(None, getUrl(''), USERNAME, PASSWORD)
-    self.passwd = password_mgr
-    self.add_password = self.passwd.add_password
-
-  def http_request(self, req):
-    uri = req.get_full_url()
-    user = USERNAME
-    pw = PASSWORD
-    raw = "%s:%s" % (user, pw)
-    auth = 'Basic %s' % base64.b64encode(raw).strip()
-    req.add_unredirected_header('Authorization', auth)
-    return req
-
-
-class AmbariResource:
-
-  def __init__(self, serviceName, componentName):
-    self.serviveName = serviceName
-    self.componentName = componentName
-    self.isInitialized = False
-
-  def initializeResource(self):
-    global CLUSTER_NAME
-    if CLUSTER_NAME is None:
-      CLUSTER_NAME = self.findClusterName()
-
-    if self.serviveName is None:
-      raise Exception('Service name undefined')
-
-    if self.componentName is None:
-      raise Exception('Component name undefined')
-
-    handler = PreemptiveBasicAuthHandler()
-    opener = urllib2.build_opener(handler)
-    # Install opener for all requests
-    urllib2.install_opener(opener)
-    self.urlOpener = opener
-
-    self.old_hostname = self.getHostname()
-
-    self.isInitialized = True
-
-
-  def relocate(self, new_hostname):
-    if not self.isInitialized:
-      raise Exception('Resource not initialized')
-
-    # If old and new hostname are the same exit harmlessly
-    if self.old_hostname == new_hostname:
-      logger.error('New hostname is same as existing host name, %s' % self.old_hostname)
-      sys.exit(2)
-    pass
-
-    try:
-      self.verifyHostComponentStatus(self.old_hostname, new_hostname, self.componentName)
-    except Exception, e:
-      logger.error("Exception caught on verify relocate request.")
-      logger.error(e.message)
-      sys.exit(3)
-
-    # Put host component in Maintenance state
-    self.updateHostComponentStatus(self.old_hostname, self.componentName,
-                                   "Maintenance", "MAINTENANCE")
-
-    # Delete current host component
-    self.deleteHostComponent(self.old_hostname, self.componentName)
-
-    # Add component on the new host
-    self.addHostComponent(new_hostname, self.componentName)
-
-    # Install host component
-    self.updateHostComponentStatus(new_hostname, self.componentName,
-                                   "Installing", "INSTALLED")
-
-    # Wait on install
-    self.waitOnHostComponentUpdate(new_hostname, self.componentName,
-                                   "INSTALLED")
-
-    if START_ON_RELOCATE:
-      # Start host component
-      self.updateHostComponentStatus(new_hostname, self.componentName,
-                                     "Starting", "STARTED")
-
-      # Wait on start
-      self.waitOnHostComponentUpdate(new_hostname, self.componentName, "STARTED")
-    pass
-  pass
-
-  def waitOnHostComponentUpdate(self, hostname, componentName, status):
-    logger.info("Waiting for host component status to update ...")
-    sleep_itr = 0
-    state = None
-    while sleep_itr < STATUS_WAIT_TIMEOUT:
-      try:
-        state = self.getHostComponentState(hostname, componentName)
-        if status == state:
-          logger.info("Status update successful. status: %s" % state)
-          return
-        pass
-      except Exception, e:
-        logger.error("Caught an exception waiting for status update.. "
-                     "continuing to wait...")
-      pass
-
-      time.sleep(STATUS_CHECK_INTERVAL)
-      sleep_itr += STATUS_CHECK_INTERVAL
-    pass
-    if state and state != status:
-      logger.error("Timed out on wait, status unchanged. status = %s" % state)
-      sys.exit(1)
-    pass
-  pass
-
-  def addHostComponent(self, hostname, componentName):
-    data = '{"host_components":[{"HostRoles":{"component_name":"%s"}}]}' % self.componentName
-    req = urllib2.Request(getUrl(ADD_HOST_COMPONENT_URI.format(CLUSTER_NAME,
-                          hostname)), data)
-
-    req.add_header("X-Requested-By", "ambari_probe")
-    req.get_method = lambda: 'POST'
-    try:
-      logger.info("Adding host component: %s" % req.get_full_url())
-      resp = self.urlOpener.open(req)
-      self.logResponse('Add host component response: ', resp)
-    except Exception, e:
-      logger.error('Create host component failed, component: {0}, host: {1}'
-                    .format(componentName, hostname))
-      logger.error(e)
-      raise e
-    pass
-
-  def deleteHostComponent(self, hostname, componentName):
-    req = urllib2.Request(getUrl(HOST_COMPONENT_URI.format(CLUSTER_NAME,
-                                hostname, componentName)))
-    req.add_header("X-Requested-By", "ambari_probe")
-    req.get_method = lambda: 'DELETE'
-    try:
-      logger.info("Deleting host component: %s" % req.get_full_url())
-      resp = self.urlOpener.open(req)
-      self.logResponse('Delete component response: ', resp)
-    except Exception, e:
-      logger.error('Delete {0} failed.'.format(componentName))
-      logger.error(e)
-      raise e
-    pass
-
-  def updateHostComponentStatus(self, hostname, componentName, contextStr, status):
-    # Update host component
-    data = '{"RequestInfo":{"context":"%s %s"},"Body":{"HostRoles":{"state":"%s"}}}' % (contextStr,
self.componentName, status)
-    req = urllib2.Request(getUrl(HOST_COMPONENT_URI.format(CLUSTER_NAME,
-                                hostname, componentName)), data)
-    req.add_header("X-Requested-By", "ambari_probe")
-    req.get_method = lambda: 'PUT'
-    try:
-      logger.info("%s host component: %s" % (contextStr, req.get_full_url()))
-      resp = self.urlOpener.open(req)
-      self.logResponse('Update host component response: ', resp)
-    except Exception, e:
-      logger.error('Update Status {0} failed.'.format(componentName))
-      logger.error(e)
-      raise e
-    pass
-
-  def verifyHostComponentStatus(self, old_hostname, new_hostname, componentName):
-    # Check desired state of host component is not STOPPED or host is
-    # unreachable
-    actualState = self.getHostComponentState(old_hostname, componentName)
-
-    if actualState not in ALLOWED_ACTUAL_STATES_FOR_RELOCATE:
-      raise Exception('Aborting relocate action since host component '
-                      'state is %s' % actualState)
-
-    hostState = self.getHostSatus(new_hostname)
-    if hostState not in ALLOWED_HOST_STATUS_FOR_RELOCATE:
-      raise Exception('Aborting relocate action since host state is %s' % hostState)
-
-    pass
-
-  def getHostSatus(self, hostname):
-    hostStateUrl = getUrl(GET_HOST_STATE_URL.format(CLUSTER_NAME, hostname))
-
-    logger.info("Requesting host status: %s " % hostStateUrl)
-    urlResponse = self.urlOpener.open(hostStateUrl)
-    state = None
-
-    if urlResponse:
-      response = urlResponse.read()
-      data = json.loads(response)
-      logger.debug('Response from getHostSatus: %s' % data)
-      if data:
-        try:
-          hostsInfo = data.get('Hosts')
-          if not hostsInfo:
-            raise Exception('Cannot find host state for host: {1}'.format(hostname))
-
-          state = hostsInfo.get('host_state')
-        except Exception, e:
-          logger.error('Unable to parse json data. %s' % data)
-          raise e
-        pass
-
-      else:
-        logger.error("Unable to retrieve host state.")
-      pass
-
-    return state
-
-
-  def getHostComponentState(self, hostname, componentName):
-    hostStatusUrl = getUrl(GET_HOST_COMPONENT_STATE_URI.format(CLUSTER_NAME,
-                                hostname, componentName))
-
-    logger.info("Requesting host component state: %s " % hostStatusUrl)
-    urlResponse = self.urlOpener.open(hostStatusUrl)
-    state = None
-
-    if urlResponse:
-      response = urlResponse.read()
-      data = json.loads(response)
-      logger.debug('Response from getHostComponentState: %s' % data)
-      if data:
-        try:
-          hostRoles = data.get('HostRoles')
-          if not hostRoles:
-            raise Exception('Cannot find host component state for component: ' +\
-                            '{0}, host: {1}'.format(componentName, hostname))
-
-          state = hostRoles.get('state')
-        except Exception, e:
-          logger.error('Unable to parse json data. %s' % data)
-          raise e
-        pass
-
-      else:
-        logger.error("Unable to retrieve host component desired state.")
-      pass
-
-    return state
-
-
-  # Log response for PUT, POST or DELETE
-  def logResponse(self, text=None, response=None):
-    if response is not None:
-      resp = str(response.getcode())
-      if text is None:
-        text = 'Logging response from server: '
-      if resp is not None:
-        logger.info(text + resp)
-
-  def findClusterName(self):
-    clusterUrl = getUrl(GET_CLUSTERS_URI)
-    clusterName = None
-
-    logger.info("Requesting clusters: " + clusterUrl)
-    urlResponse = self.urlOpener.open(clusterUrl)
-    if urlResponse is not None:
-      response = urlResponse.read()
-      data = json.loads(response)
-      logger.debug('Response from findClusterName: %s' % data)
-      if data:
-        try:
-          clusters = data.get('items')
-          if len(clusters) > 1:
-            raise Exception('Multiple clusters found. %s' % clusters)
-
-          clusterName = clusters[0].get('Clusters').get('cluster_name')
-        except Exception, e:
-          logger.error('Unable to parse json data. %s' % data)
-          raise e
-        pass
-      else:
-        logger.error("Unable to retrieve clusters data.")
-      pass
-
-    return clusterName
-
-  def getHostname(self):
-    hostsUrl = getUrl(GET_HOST_COMPONENTS_URI.format(CLUSTER_NAME,
-                  self.serviveName, self.componentName))
-
-    logger.info("Requesting host info: " + hostsUrl)
-    urlResponse = self.urlOpener.open(hostsUrl)
-    hostname = None
-
-    if urlResponse is not None:
-      response = urlResponse.read()
-      data = json.loads(response)
-      logger.debug('Response from getHostname: %s' % data)
-      if data:
-        try:
-          hostRoles = data.get('host_components')
-          if not hostRoles:
-            raise Exception('Cannot find host component data for service: ' +\
-                            '{0}, component: {1}'.format(self.serviveName, self.componentName))
-          if len(hostRoles) > 1:
-            raise Exception('More than one hosts found with the same role')
-
-          hostname = hostRoles[0].get('HostRoles').get('host_name')
-        except Exception, e:
-          logger.error('Unable to parse json data. %s' % data)
-          raise e
-        pass
-
-      else:
-        logger.error("Unable to retrieve host component data.")
-      pass
-
-    return hostname
-
-
-def getUrl(partial_url):
-  return PROTOCOL + "://" + AMBARI_HOSTNAME + ":" + AMBARI_PORT + partial_url
-
-def get_supported_actions():
-  return [ RELOCATE_ACTION ]
-
-#
-# Main.
-#
-def main():
-  tempDir = tempfile.gettempdir()
-  outputFile = os.path.join(tempDir, "ambari_reinstall_probe.out")
-
-  parser = optparse.OptionParser(usage="usage: %prog [options]")
-  parser.set_description('This python program is a Ambari thin client and '
-                         'supports relocation of ambari host components on '
-                         'Ambari managed clusters.')
-
-  parser.add_option("-v", "--verbose", dest="verbose", action="store_false",
-                  default=False, help="output verbosity.")
-  parser.add_option("-s", "--host", dest="server_hostname",
-                  help="Ambari server host name.")
-  parser.add_option("-p", "--port", dest="server_port",
-                  default="8080" ,help="Ambari server port. [default: 8080]")
-  parser.add_option("-r", "--protocol", dest="protocol", default = "http",
-                  help="Protocol for communicating with Ambari server ("
-                       "http/https) [default: http].")
-  parser.add_option("-c", "--cluster-name", dest="cluster_name",
-                  help="Ambari cluster to operate on.")
-  parser.add_option("-e", "--service-name", dest="service_name",
-                  help="Ambari Service to which the component belongs to.")
-  parser.add_option("-m", "--component-name", dest="component_name",
-                  help="Ambari Service Component to operate on.")
-  parser.add_option("-n", "--new-host", dest="new_hostname",
-                  help="New host to relocate the component to.")
-  parser.add_option("-a", "--action", dest="action", default = "relocate",
-                  help="Script action. [default: relocate]")
-  parser.add_option("-o", "--output-file", dest="outputfile",
-                  default = outputFile, metavar="FILE",
-                  help="Output file. [default: %s]" % outputFile)
-  parser.add_option("-u", "--username", dest="username",
-                  default="admin" ,help="Ambari server admin user. [default: admin]")
-  parser.add_option("-w", "--password", dest="password",
-                  default="admin" ,help="Ambari server admin password.")
-  parser.add_option("-d", "--start-component", dest="start_component",
-                  action="store_false", default=False,
-                  help="Should the script start the component after relocate.")
-
-  (options, args) = parser.parse_args()
-
-  # set verbose
-  if options.verbose:
-    logging.basicConfig(level=logging.DEBUG)
-  else:
-    logging.basicConfig(level=logging.INFO)
-
-  global AMBARI_HOSTNAME
-  AMBARI_HOSTNAME = options.server_hostname
-
-  global AMBARI_PORT
-  AMBARI_PORT = options.server_port
-
-  global CLUSTER_NAME
-  CLUSTER_NAME = options.cluster_name
-
-  global PROTOCOL
-  PROTOCOL = options.protocol
-
-  global USERNAME
-  USERNAME = options.username
-
-  global PASSWORD
-  PASSWORD = options.password
-
-  global START_ON_RELOCATE
-  START_ON_RELOCATE = options.start_component
-
-  global logger
-  logger = logging.getLogger('AmbariProbe')
-  handler = logging.FileHandler(options.outputfile)
-  formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
-  handler.setFormatter(formatter)
-  logger.addHandler(handler)
-
-  action = RELOCATE_ACTION
-
-  if options.action is not None:
-    if options.action not in get_supported_actions():
-      logger.error("Unsupported action: " + options.action + ", "
-                  "valid actions: " + str(get_supported_actions()))
-      sys.exit(1)
-    else:
-      action = options.action
-
-  socket.setdefaulttimeout(DEFAULT_TIMEOUT)
-
-  ambariResource = AmbariResource(serviceName=options.service_name,
-                                  componentName=options.component_name)
-  ambariResource.initializeResource()
-
-  if action == RELOCATE_ACTION:
-    if options.new_hostname is not None:
-      ambariResource.relocate(options.new_hostname)
-
-if __name__ == "__main__":
-  try:
-    main()
-  except (KeyboardInterrupt, EOFError):
-    print("\nAborting ... Keyboard Interrupt.")
-    sys.exit(1)


Mime
View raw message