Jelajahi Sumber

AMBARI-2442. Amabri Client refactoring -1. (Subin M via mahadev)

Mahadev Konar 12 tahun lalu
induk
melakukan
23754e344a

+ 0 - 0
ambari-client/src/main/python/ambari_client/__init__.py


+ 51 - 8
ambari-client/src/main/python/ambari_client/ambari_api.py

@@ -14,15 +14,11 @@
 #  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 logging
-from ambari_client.http_client import HttpClient
-from ambari_client.resources import  clusters
-from ambari_client.rest_resource import RestResource
+from ambari_client.core.http_client import HttpClient
+from ambari_client.resources import  clusters ,hosts
+from ambari_client.core.rest_resource import RestResource
 
 __docformat__ = "epytext"
 
@@ -78,6 +74,9 @@ class AmbariClient(RestResource):
     """
     return clusters.get_all_clusters(self)
 
+
+
+
   def get_cluster(self, cluster_name):
     """
     Get a cluster by cluster_name.
@@ -87,7 +86,51 @@ class AmbariClient(RestResource):
     """
     return clusters.get_cluster(self, cluster_name)
 
-  
+
+
+  def get_all_hosts(self):
+    """
+    Get all hosts
+    @return: A list of HostModel objects.
+    """
+    return hosts.get_all_hosts(self)
+
+
+  def get_request_status(self , request_path):
+    """
+    Get request status
+    @return: A  StatusModel object.
+    """
+    return "TODO"
+
+
+  def bootstrap_hosts(self , hosts_list ,ssh_key):
+    """
+    Bootstrap hosts.
+    @param hosts list of host_names.
+    @return: A  StatusModel object.
+    """
+    return hosts.bootstrap_hosts(self, hosts_list ,ssh_key)
+
+
+  def create_cluster(self, cluster_name, version):
+    """
+    Create a new cluster.
+    @param name Cluster name.
+    @param version HDP version.
+    @return  ClusterModel object.
+    """
+    return clusters.create_cluster(self, cluster_name, version)  
+
+
+
+  def delete_cluster(self ,cluster_name):
+    """
+    Create a cluster
+    @param root_resource: The root Resource.
+    @param cluster_name: Cluster cluster_name
+    """
+    return clusters.delete_cluster(self, cluster_name)
 
 
 

+ 0 - 0
ambari-client/src/main/python/ambari_client/core/__init__.py


+ 49 - 0
ambari-client/src/main/python/ambari_client/core/errors.py

@@ -0,0 +1,49 @@
+#
+#  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.
+
+class ResourceError(Exception):
+
+    def __init__(self, msg=None, code=None, response=None):
+        self.msg = msg or ''
+        self.status_code = code
+        self.response = response
+        Exception.__init__(self)
+        
+    def _get_message(self):
+        return self.msg
+    
+    def __str__(self):
+        if self.msg:
+            return self.msg
+        try:
+            return self._fmt % self.__dict__
+        except (NameError, ValueError, KeyError), e:
+            return 'exception %s: %s' \
+                % (self.__class__.__name__, str(e))
+        
+class ResourceNotFound(ResourceError):
+    """Exception raised when no resource was found. 
+    """
+
+class RequestError(Exception):
+    """Exception for incorrect request """
+    
+class Unauthorized(ResourceError):
+    """Exception when an authorization is required """
+
+class RequestFailed(ResourceError):
+    """Exception for unexpected HTTP error  """

+ 1 - 5
ambari-client/src/main/python/ambari_client/http_client.py → ambari-client/src/main/python/ambari_client/core/http_client.py

@@ -14,11 +14,7 @@
 #  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 logging
 import posixpath
 import sys
@@ -30,7 +26,7 @@ try:
   import json
 except ImportError:
   import simplejson as json
-from ambari_client.http_utils import uri_encoding
+from ambari_client.core.http_utils import uri_encoding
 
 __docformat__ = "epytext"
 

+ 0 - 4
ambari-client/src/main/python/ambari_client/http_utils.py → ambari-client/src/main/python/ambari_client/core/http_utils.py

@@ -14,12 +14,8 @@
 #  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 types
 import urllib
 import urllib2

+ 24 - 7
ambari-client/src/main/python/ambari_client/rest_resource.py → ambari-client/src/main/python/ambari_client/core/rest_resource.py

@@ -14,11 +14,7 @@
 #  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.
-'''
 
-
-
-'''
 try:
   import json
 except ImportError:
@@ -68,10 +64,13 @@ class RestResource(object):
 
     LOG.debug ("RESPONSE from the REST request >>>>>>> \n"+str(resp) )
     LOG.debug ("\n===========================================================")
-    if not resp and code!=200:
-        raise Exception("Command '%s %s' failed" %(http_method, path))
+    #take care of REST calls with no response
+    if not resp and (code!=200 and code!=201):
+        raise Exception("Command '%s %s' failed with error %s" %(http_method, path,code))
+    if resp and (code==404 or code==405):
+        raise Exception("Command '%s %s' failed with error %s" %(http_method, path,code))
     try:
-        if code==200 and not resp:
+        if (code==200 or code==201) and not resp:
           return {}
         json_dict = json.loads(resp)
         return json_dict
@@ -101,4 +100,22 @@ class RestResource(object):
     return self.invoke("PUT", path, payload,self._set_headers(content_type))
 
 
+  def post(self, path=None, payload=None, content_type=None):
+    """
+    Invoke the POST method on a resource.
+    @param path: resource path
+    @param payload: Body of the request.
+    @param content_type: 
+    @return: A dictionary of the REST result.
+    """
+    return self.invoke("POST", path, payload,self._set_headers(content_type))
+
 
+  def delete(self, path=None, payload=None,):
+    """
+    Invoke the DELETE method on a resource.
+    @param path: resource path
+    @param payload: Body of the request.
+    @return: A dictionary of the REST result.
+    """
+    return self.invoke("DELETE", path, payload)

+ 0 - 0
ambari-client/src/main/python/ambari_client/model/__init__.py


+ 2 - 4
ambari-client/src/main/python/ambari_client/model/base_model.py

@@ -14,10 +14,6 @@
 #  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 sys
 import logging
@@ -45,6 +41,8 @@ class BaseModel(object):
 
   
   def __init__(self, resource_root, **rw_attrs):
+    #print" ================== base_model\n"
+    print locals()
     self._resource_root = resource_root
     for k, v in rw_attrs.items():
       if k not in self.RW_ATTR:

+ 38 - 6
ambari-client/src/main/python/ambari_client/model/cluster.py

@@ -14,15 +14,12 @@
 #  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 logging
+import time
 from ambari_client.model.base_model import  BaseModel 
 from ambari_client.model.paths import CLUSTERS_PATH 
-from ambari_client.model import service
+from ambari_client.model import service ,host
 from ambari_client.model.utils import ModelUtils ,retain_self_helper
 
 
@@ -50,8 +47,30 @@ def get_all_clusters(root_resource, details=None):
 
 
 
+def create_cluster(root_resource, cluster_name, version):
+  """
+  Create a cluster
+  @param root_resource: The root Resource.
+  @param cluster_name: Cluster cluster_name
+  @param version: HDP version
+  @return: An ClusterModel object
+  """
+  data={"Clusters":{"version":str(version)}}
+  cluster = ClusterModel(root_resource, cluster_name, version)
+  path = CLUSTERS_PATH+"/%s" % (cluster_name)
+  root_resource.post(path=path , payload=data)
+  return get_cluster(root_resource, cluster_name)
+
+def delete_cluster(root_resource, cluster_name):
+  """
+  Delete a cluster by name
+  @param root_resource: The root Resource object.
+  @param name: Cluster name
+  """
+  root_resource.delete("%s/%s" % (CLUSTERS_PATH, cluster_name))
+  time.sleep(3)
+  return None
 
-    
     
 class ClusterModel(BaseModel):
 
@@ -82,7 +101,20 @@ class ClusterModel(BaseModel):
     """
     return service.get_all_services(self._get_resource_root(), self.cluster_name)
 
+  def get_all_hosts(self, detail = None):
+    """
+    Get all hosts in this cluster.
+    @return: A list of HostModel objects.
+    """
+    return host.get_all_cluster_hosts(self._get_resource_root(), self.cluster_name)
+
 
+  def get_host(self, hostname , detail = None):
+    """
+    Get a specific hosts in this cluster.
+    @return: A HostModel object.
+    """
+    return host.get_host(self._get_resource_root(), self.cluster_name, hostname)
 
 class ClusterModelRef(BaseModel):
   RW_ATTR = ('cluster_name',)

+ 124 - 0
ambari-client/src/main/python/ambari_client/model/host.py

@@ -0,0 +1,124 @@
+#
+#  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.
+
+try:
+  import json
+except ImportError:
+  import simplejson as json
+import logging
+from ambari_client.model.base_model import  BaseModel , ModelList
+from ambari_client.model.paths import HOSTS_PATH , CLUSTER_HOSTS_PATH , CLUSTER_HOST_PATH ,BOOTSTRAP_PATH
+from ambari_client.model import service ,status
+from ambari_client.model.utils import ModelUtils , retain_self_helper
+
+
+LOG = logging.getLogger(__name__)
+
+def create_host(root_resource, host_name, ip, rack_info=None):
+  """
+  Create a host
+  @param root_resource: The root Resource object.
+  @param host_name: Host name
+  @param ip: IP address
+  @param rack_info: Rack id. Default None
+  @return: An HostModel object
+  """
+  host = HostModel(root_resource, host_name, ip, rack_info)
+  host_list = ModelList([host])
+  body = json.dumps(host_list.to_json_dict())
+  resp = root_resource.post(HOSTS_PATH, data=body)
+  # The server returns a created hosts 
+  return get_host(root_resource, host_name)
+
+
+
+
+def get_host(root_resource, cluster_name , host_name):
+  """
+  Lookup up by host_name
+  @param root_resource: The root Resource object.
+  @param cluster_name: Cluster name
+  @param host_name: Host name
+  @return: A HostModel object
+  """
+  path = CLUSTER_HOST_PATH % (cluster_name, host_name)
+  dic = root_resource.get(path)
+  return ModelUtils.create_model(HostModel , dic, root_resource, "Hosts") 
+
+
+
+def get_all_hosts(root_resource):
+  """
+  Get all hosts
+  @param root_resource: The root Resource.
+  @return: A list of HostModel objects.
+  """
+  dic = root_resource.get(HOSTS_PATH)
+  return ModelUtils.get_model_list(HostModel, dic, root_resource , "Hosts")
+  
+  
+  
+def get_all_cluster_hosts(root_resource, cluster_name):
+  """
+  Get all hosts in the cluster
+  @param root_resource: The root Resource.
+  @return: A list of HostModel objects.
+  """
+  path = "%s/%s" % (HOSTS_PATH, cluster_name)
+  dic = root_resource.get(path)
+  return ModelUtils.get_model_list(HostModel, dic, root_resource , "Hosts")
+
+
+
+def delete_host(root_resource, host_id):
+  """
+  Delete a host by id
+  @param root_resource: The root Resource object.
+  @param host_id: Host id
+  @return: The deleted HostModel object
+  """
+  resp = root_resource.delete("%s/%s" % (HOSTS_PATH, host_id))
+  return HostModel.from_json_dict(resp, root_resource)
+  
+  
+def bootstrap_hosts(root_resource , hosts_list,ssh_key):
+  """
+  Bootstrap hosts.
+  @param hosts_list list of host_names.
+  @return: A  StatusModel object.
+  """
+  payload_dic = {'sshKey':ssh_key.encode('string_escape') ,'hosts':hosts_list}
+  resp = root_resource.post(BOOTSTRAP_PATH,payload_dic ,content_type="application/json")
+  return ModelUtils.create_model(status.StatusModel, resp, root_resource, "NO_KEY")
+
+
+
+ 
+class HostModel(BaseModel):
+  RO_ATTR = ('host_state', 'public_host_name')
+  RW_ATTR = ('host_name', 'ip', 'rack_info')
+  REF_ATTR = ('cluster_name',)
+  
+  def __init__(self, resource_root, host_name, ip=None , rack_info=None):
+    retain_self_helper(**locals())
+
+  def __str__(self):
+    return "<<HostModel>>: = %s; ip = %s" % (self.host_name, self.ip)
+
+  def _path(self):
+    return HOSTS_PATH + '/' + self.host_name
+

+ 4 - 6
ambari-client/src/main/python/ambari_client/model/paths.py

@@ -14,13 +14,11 @@
 #  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.
-'''
 
-
-
-'''
 CLUSTERS_PATH = "/clusters"
 SERVICES_PATH = "/clusters/%s/services"
 SERVICE_PATH = "/clusters/%s/services/%s"
-
-
+HOSTS_PATH = "/hosts"
+CLUSTER_HOSTS_PATH = "/clusters/%s/hosts"
+CLUSTER_HOST_PATH = "/clusters/%s/hosts/%s"
+BOOTSTRAP_PATH="/bootstrap"

+ 18 - 8
ambari-client/src/main/python/ambari_client/model/service.py

@@ -13,13 +13,9 @@
 #  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 logging
-
+import time
 from ambari_client.model.base_model import  BaseModel 
 from ambari_client.model.paths import SERVICES_PATH ,SERVICE_PATH 
 from ambari_client.model.utils import ModelUtils ,retain_self_helper
@@ -39,19 +35,33 @@ def get_service(resource_root, service_name, cluster_name="default"):
   dic = resource_root.get(path)
   return ModelUtils.create_model(ServiceModel ,dic, resource_root,"ServiceInfo") 
 
-
-    
+def create_service(root_resource, service_name, cluster_name):
+  """
+  Create a service
+  @param root_resource: The root Resource object.
+  @param service_name: Service service_name
+  @param cluster_name: Cluster service_name
+  @return: An ServiceModel object
+  """
+  data ={"ServiceInfo":{"service_name":str(service_name)}}
+  service = ServiceModel(root_resource, service_name,cluster_name)
+  path = SERVICE_PATH
+  root_resource.post(path=SERVICE_PATH , payload=data)
+  return get_service(root_resource, service_name, cluster_name)
     
+
+   
     
 class ServiceModel(BaseModel):
   RO_ATTR = ('state',  'cluster_name')
   RW_ATTR = ('service_name', 'type')
   REF_ATTR = ('cluster_name',)
 
-  def __init__(self, resource_root, service_name):
+  def __init__(self, resource_root, service_name ):
     #BaseModel.__init__(self, **locals())
     retain_self_helper(**locals())
 
+
   def __str__(self):
     return "<<ServiceModel>> = %s (cluster_name = %s)" % (self.service_name, self._get_cluster_name())
 

+ 40 - 0
ambari-client/src/main/python/ambari_client/model/status.py

@@ -0,0 +1,40 @@
+#  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 logging
+from ambari_client.model.base_model import  BaseModel 
+from ambari_client.model.utils import retain_self_helper
+from ambari_client.model.paths import BOOTSTRAP_PATH
+LOG = logging.getLogger(__name__)
+
+
+
+
+class StatusModel(BaseModel):
+  RO_ATTR = ()
+  RW_ATTR = ('status','requestId')
+  REF_ATTR = ('cluster_name',)
+
+  def __init__(self, resource_root, status ,requestId=None):
+    #BaseModel.__init__(self, **locals())
+    retain_self_helper(**locals())
+
+  def __str__(self):
+    return "<<StatusModel>> = %s (requestId = %s)" % (self.status, self.requestId)
+
+  def get_request_path(self):
+    return BOOTSTRAP_PATH + '/' + self.requestId
+

+ 0 - 4
ambari-client/src/main/python/ambari_client/model/utils.py

@@ -14,11 +14,7 @@
 #  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 logging
 import sys
 

+ 0 - 0
ambari-client/src/main/python/ambari_client/resources/__init__.py


+ 40 - 6
ambari-client/src/main/python/ambari_client/resources/clusters.py

@@ -14,12 +14,7 @@
 #  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.
-'''
 
-
-
-'''
-  
 from ambari_client.model import  cluster
 __docformat__ = "epytext"
 
@@ -41,4 +36,43 @@ def get_all_clusters(root_resource):
   @param root_resource: The root Resource object.
   @return: A list of ClusterModel objects in ModelList.
   """
-  return cluster.get_all_clusters(root_resource)
+  return cluster.get_all_clusters(root_resource)
+
+ 
+def create_cluster(root_resource, cluster_name, version):
+  """
+  Create a cluster
+  @param root_resource: The root Resource.
+  @param cluster_name: Cluster cluster_name
+  @param version: HDP version
+  @return: An ClusterModel object
+  """
+  return cluster.create_cluster(root_resource, cluster_name, version)
+  
+  
+def delete_cluster(root_resource, cluster_name):
+  """
+  Create a cluster
+  @param root_resource: The root Resource.
+  @param cluster_name: Cluster cluster_name
+  """
+  return cluster.delete_cluster(root_resource, cluster_name)
+ 
+def create_cluster(root_resource, cluster_name, version):
+  """
+  Create a cluster
+  @param root_resource: The root Resource.
+  @param cluster_name: Cluster cluster_name
+  @param version: HDP version
+  @return: An ClusterModel object
+  """
+  return cluster.create_cluster(root_resource, cluster_name, version)
+  
+  
+def delete_cluster(root_resource, cluster_name):
+  """
+  Create a cluster
+  @param root_resource: The root Resource.
+  @param cluster_name: Cluster cluster_name
+  """
+  return cluster.delete_cluster(root_resource, cluster_name)

+ 72 - 0
ambari-client/src/main/python/ambari_client/resources/hosts.py

@@ -0,0 +1,72 @@
+  #
+#  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.
+
+from ambari_client.model import  host
+__docformat__ = "epytext"
+
+
+def create_host(root_resource,  host_name, ip, rack_info=None):
+  """
+  Create a host
+  @param root_resource: The root Resource.
+  @param host_name: Host name
+  @param ip: IP address
+  @param rack_info: Rack id. Default None
+  @return: An HostModel object
+  """
+  return host.create_host(root_resource,  host_name, ip, rack_info=None)
+
+def get_host(root_resource, host_name):
+  """
+  Lookup a host by id
+  @param root_resource: The root Resource.
+  @param host_name: Host name
+  @return: An HostModel object
+  """
+  return host.get_host(root_resource, host_name)
+
+
+
+def get_all_hosts(root_resource):
+  """
+  Get all hosts
+  @param root_resource: The root Resource.
+  @return: A list of HostModel objects.
+  """
+  return host.get_all_hosts(root_resource)
+
+
+
+
+def delete_host(root_resource, host_name):
+  """
+  Delete a host by id
+  @param root_resource: The root Resource.
+  @param host_name: Host name
+  @return: The deleted HostModel object
+  """
+  return host.delete_host(root_resource,host_name)
+
+
+
+def bootstrap_hosts(root_resource , hosts_list ,ssh_key):
+  """
+  Bootstrap hosts.
+  @param hosts list of host_names.
+  @return: A  StatusModel object.
+  """
+  return host.bootstrap_hosts(root_resource, hosts_list ,ssh_key)

+ 0 - 5
ambari-client/src/main/python/ambari_client/resources/services.py

@@ -13,11 +13,6 @@
 #  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.
-'''
-
-
-
-'''
 
 from ambari_client.model import  service
 __docformat__ = "epytext"

+ 4 - 4
ambari-client/src/test/python/TestAmbariClient.py

@@ -49,7 +49,7 @@ class TestAmbariClient(unittest.TestCase):
     
   
     
-  @patch("ambari_client.http_client.HttpClient")  
+  @patch("ambari_client.core.http_client.HttpClient")  
   def test_get_all_clusters_valid(self ,http_client):
     """
     Get all clusters.
@@ -74,7 +74,7 @@ class TestAmbariClient(unittest.TestCase):
     self.assertEqual(all_clusters.to_json_dict(), expected_output, "to_json_dict should convert ModelList")
     
    
-  @patch("ambari_client.http_client.HttpClient")  
+  @patch("ambari_client.core.http_client.HttpClient")  
   def test_get_cluster_valid(self ,http_client):
     """
     Get all clusters.
@@ -98,7 +98,7 @@ class TestAmbariClient(unittest.TestCase):
 
 
 
-  @patch("ambari_client.http_client.HttpClient")  
+  @patch("ambari_client.core.http_client.HttpClient")  
   def test_get_all_services_valid(self ,http_client):
     """
     Get all services.
@@ -120,7 +120,7 @@ class TestAmbariClient(unittest.TestCase):
     self.assertEqual(cluster.to_json_dict(), expected_dict_output, "to_json_dict should convert ClusterModel")
     self.assertEqual(len(serviceList), 3, "There should be a 3 services from the response")
  
-  @patch("ambari_client.http_client.HttpClient")  
+  @patch("ambari_client.core.http_client.HttpClient")  
   def test_get_service_valid(self ,http_client):
     """
     Get the service.