You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ma...@apache.org on 2013/08/23 08:36:30 UTC

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

Updated Branches:
  refs/heads/trunk 81bc7d830 -> 23754e344


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


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

Branch: refs/heads/trunk
Commit: 23754e344ab034fc53a3f72d40f65acc5a4b37c5
Parents: 81bc7d8
Author: Mahadev Konar <ma...@apache.org>
Authored: Thu Aug 22 23:35:52 2013 -0700
Committer: Mahadev Konar <ma...@apache.org>
Committed: Thu Aug 22 23:35:52 2013 -0700

----------------------------------------------------------------------
 .../src/main/python/ambari_client/__init__.py   |   0
 .../src/main/python/ambari_client/ambari_api.py |  59 ++++++-
 .../main/python/ambari_client/core/__init__.py  |   0
 .../main/python/ambari_client/core/errors.py    |  49 ++++++
 .../python/ambari_client/core/http_client.py    | 162 ++++++++++++++++++
 .../python/ambari_client/core/http_utils.py     |  52 ++++++
 .../python/ambari_client/core/rest_resource.py  | 121 ++++++++++++++
 .../main/python/ambari_client/http_client.py    | 166 -------------------
 .../src/main/python/ambari_client/http_utils.py |  56 -------
 .../main/python/ambari_client/model/__init__.py |   0
 .../python/ambari_client/model/base_model.py    |   6 +-
 .../main/python/ambari_client/model/cluster.py  |  44 ++++-
 .../src/main/python/ambari_client/model/host.py | 124 ++++++++++++++
 .../main/python/ambari_client/model/paths.py    |  10 +-
 .../main/python/ambari_client/model/service.py  |  26 ++-
 .../main/python/ambari_client/model/status.py   |  40 +++++
 .../main/python/ambari_client/model/utils.py    |   4 -
 .../python/ambari_client/resources/__init__.py  |   0
 .../python/ambari_client/resources/clusters.py  |  46 ++++-
 .../python/ambari_client/resources/hosts.py     |  72 ++++++++
 .../python/ambari_client/resources/services.py  |   5 -
 .../main/python/ambari_client/rest_resource.py  | 104 ------------
 .../src/test/python/TestAmbariClient.py         |   8 +-
 23 files changed, 777 insertions(+), 377 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/__init__.py b/ambari-client/src/main/python/ambari_client/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/ambari_api.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/ambari_api.py b/ambari-client/src/main/python/ambari_client/ambari_api.py
index 216af87..6cdaf8c 100644
--- a/ambari-client/src/main/python/ambari_client/ambari_api.py
+++ b/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)
 
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/core/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/core/__init__.py b/ambari-client/src/main/python/ambari_client/core/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/core/errors.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/core/errors.py b/ambari-client/src/main/python/ambari_client/core/errors.py
new file mode 100644
index 0000000..7031d52
--- /dev/null
+++ b/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  """
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/core/http_client.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/core/http_client.py b/ambari-client/src/main/python/ambari_client/core/http_client.py
new file mode 100644
index 0000000..5b49be3
--- /dev/null
+++ b/ambari-client/src/main/python/ambari_client/core/http_client.py
@@ -0,0 +1,162 @@
+#
+#  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
+import posixpath
+import sys
+import pycurl
+import cStringIO
+import StringIO
+import pdb
+try:
+  import json
+except ImportError:
+  import simplejson as json
+from ambari_client.core.http_utils import uri_encoding
+
+__docformat__ = "epytext"
+
+LOG = logging.getLogger(__name__)
+
+ 
+class HttpClient(object):
+  """
+  Basic HTTP client for rest APIs.
+  """
+  def __init__(self, host_url, user_name , password ):
+    """
+    @param host_url: The base url to the API.
+
+    """
+
+    self._host_url = host_url.rstrip('/')
+    self._headers = { }
+    self.c = pycurl.Curl()
+    if user_name is not None:
+        self.c.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
+        userpass = user_name + ':'
+        if password is not None: 
+            userpass += password
+    LOG.debug( "pycurl.USERPWD value = "+str(userpass))
+    self.c.setopt(pycurl.USERPWD, userpass)
+
+
+  def set_headers(self, headers):
+    """
+    Add headers to the request
+    """
+    self._headers = headers
+    return self
+
+  @property
+  def host_url(self):
+    return self._host_url
+
+  def _get_headers(self, headers):
+    res = self._headers.copy()
+    if headers:
+      res.update(headers)
+    return res
+
+  def invoke(self, http_method, path, payload=None, headers=None):
+    """
+    Submit an HTTP request.
+    @param http_method: GET, POST, PUT, DELETE
+    @param path: The path of the resource.
+    @param payload: The payload to attach to the body of the request.
+    @param headers: The headers to set for this request.
+
+    @return: The result of REST request
+    """
+    #pdb.set_trace()
+    LOG.debug ("invoke : http_method = "+str(http_method))
+    # Prepare URL and params
+    url = self._normalize(path)
+    if http_method in ("GET", "DELETE"):
+      if payload is not None:
+        self.logger.warn(
+            "GET http_method does not pass any payload. Path '%s'" % (path,))
+        payload = None
+
+
+    buf = cStringIO.StringIO()
+    self.c.setopt(pycurl.WRITEFUNCTION, buf.write)
+    LOG.debug ("invoke : url = "+str(url))
+    # set http_method
+    if http_method == "GET":
+        self.c.setopt(pycurl.HTTPGET, 1)
+    elif http_method == "HEAD":
+        self.c.setopt(pycurl.HTTPGET, 1)
+        self.c.setopt(pycurl.NOBODY, 1)
+    elif http_method == "POST":
+        self.c.setopt(pycurl.POST, 1)
+    elif http_method == "PUT":
+        self.c.setopt(pycurl.UPLOAD, 1)
+    else:
+        self.c.setopt(pycurl.CUSTOMREQUEST, http_method)
+        
+    if http_method in ('POST','PUT'):
+      LOG.debug( "data..........."+str(payload))
+      data = json.dumps(payload)
+      data= data.decode('unicode-escape')
+      LOG.debug( data)
+      data = self._to_bytestring(data)
+      LOG.debug( data)
+      content = StringIO.StringIO(data)
+      LOG.debug( content)
+      content_length = len(data)
+      LOG.debug( "content_length........."+str(content_length))
+
+      if http_method == 'POST':
+        self.c.setopt(pycurl.POSTFIELDSIZE, content_length)
+      else:
+        self.c.setopt(pycurl.INFILESIZE, content_length)
+      self.c.setopt(pycurl.READFUNCTION, content.read)
+      
+      
+    self.c.setopt(self.c.URL, url)
+    headers = self._get_headers(headers)
+    self.c.setopt(pycurl.HTTPHEADER,
+                        ["%s: %s" % pair for pair in sorted(headers.iteritems())])
+
+    LOG.debug ("invoke : pycurl.EFFECTIVE_URL = "+self.c.getinfo(pycurl.EFFECTIVE_URL))
+    try:
+        self.c.perform()
+    except Exception, ex:
+        LOG.debug (sys.stderr, str(ex))
+        raise ex
+    contents_type= self.c.getinfo(pycurl.CONTENT_TYPE)
+    LOG.debug ("invoke : pycurl.CONTENT_TYPE = "+contents_type)
+    code = self.c.getinfo(pycurl.RESPONSE_CODE)
+    LOG.debug ("invoke : pycurl.RESPONSE_CODE = "+str(code))
+    response = buf.getvalue()
+    buf.close()
+    LOG.debug ("invoke : COMPLETED ")
+    return response , code , contents_type
+
+  def _to_bytestring(self ,s):
+#    if not isinstance(s, basestring):
+#      raise TypeError("value should be a str or unicode")
+    if isinstance(s, unicode):
+      return s.encode('utf-8')
+    return s
+
+  def _normalize(self, path):
+    res = self._host_url
+    if path:
+      res += posixpath.normpath('/' + path.lstrip('/'))
+    return uri_encoding(res)

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/core/http_utils.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/core/http_utils.py b/ambari-client/src/main/python/ambari_client/core/http_utils.py
new file mode 100644
index 0000000..07fea45
--- /dev/null
+++ b/ambari-client/src/main/python/ambari_client/core/http_utils.py
@@ -0,0 +1,52 @@
+#
+#  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 types
+import urllib
+import urllib2
+
+
+def uri_encoding(url):
+    """
+    Returns an ASCII string version of the URL.
+    """
+    if url is None:
+        return url
+    return urllib.quote(get_utf8_str(url), safe="/#%[]=:;$&()+,!?*@'~")
+
+
+
+def get_utf8_str(strr, encoding='utf-8'):
+    """
+    Returns a utf8 ecoded 'str'.
+    """
+    errors='strict'
+    if not isinstance(strr, basestring):
+        try:
+            return str(strr)
+        except UnicodeEncodeError:
+            if isinstance(strr, Exception):
+                return ' '.join([get_utf8_str(arg, encoding) for arg in strr])
+            return unicode(strr).encode(encoding, errors)
+    elif isinstance(strr, unicode):
+        return strr.encode(encoding, errors)
+    elif strr and encoding != 'utf-8':
+        return strr.decode('utf-8', errors).encode(encoding, errors)
+    else:
+        return strr
+

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/core/rest_resource.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/core/rest_resource.py b/ambari-client/src/main/python/ambari_client/core/rest_resource.py
new file mode 100644
index 0000000..683d1af
--- /dev/null
+++ b/ambari-client/src/main/python/ambari_client/core/rest_resource.py
@@ -0,0 +1,121 @@
+#
+#  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
+import posixpath
+
+LOG = logging.getLogger(__name__)
+
+
+class RestResource(object):
+  """
+  RestResource wrapper.
+  """
+  def __init__(self, client, path=""):
+    """
+    @param client: A Client object.
+    @param path: The relative path of the resource.
+    """
+    self._client = client
+    self._path = path.strip('/')
+
+  @property
+  def host_url(self):
+    return self._client.host_url
+
+  def _join_uri(self, relpath):
+    if relpath is None:
+      return self._path
+    return self._path + posixpath.normpath('/' + relpath)
+  
+  def _set_headers(self, content_type=None):
+    if content_type:
+      return { 'Content-Type': content_type }
+    return None
+
+
+  def make_invoke(self, http_method, payload, headers, path):
+      return self._client.invoke(http_method, path, payload=payload, headers=headers)
+
+  def invoke(self, http_method, url_path=None, payload=None, headers=None):
+    """
+    Invoke an API http_method.
+    """
+    path = self._join_uri(url_path)
+    resp ,code , content  = self.make_invoke(http_method, payload, headers, path)
+
+    LOG.debug ("RESPONSE from the REST request >>>>>>> \n"+str(resp) )
+    LOG.debug ("\n===========================================================")
+    #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 or code==201) and not resp:
+          return {}
+        json_dict = json.loads(resp)
+        return json_dict
+    except Exception, ex:
+        LOG.error('JSON decode error: %s' % (resp,))
+        raise ex
+
+
+
+  def get(self, path=None):
+    """
+    Invoke the GET method .
+    @param path: resource path
+    @return: A dictionary of the REST result.
+    """
+    return self.invoke("GET", path)
+
+
+  def put(self, path=None, payload=None, content_type=None):
+    """
+    Invoke the PUT 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("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)

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/http_client.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/http_client.py b/ambari-client/src/main/python/ambari_client/http_client.py
deleted file mode 100644
index a966807..0000000
--- a/ambari-client/src/main/python/ambari_client/http_client.py
+++ /dev/null
@@ -1,166 +0,0 @@
-#
-#  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
-import posixpath
-import sys
-import pycurl
-import cStringIO
-import StringIO
-import pdb
-try:
-  import json
-except ImportError:
-  import simplejson as json
-from ambari_client.http_utils import uri_encoding
-
-__docformat__ = "epytext"
-
-LOG = logging.getLogger(__name__)
-
- 
-class HttpClient(object):
-  """
-  Basic HTTP client for rest APIs.
-  """
-  def __init__(self, host_url, user_name , password ):
-    """
-    @param host_url: The base url to the API.
-
-    """
-
-    self._host_url = host_url.rstrip('/')
-    self._headers = { }
-    self.c = pycurl.Curl()
-    if user_name is not None:
-        self.c.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
-        userpass = user_name + ':'
-        if password is not None: 
-            userpass += password
-    LOG.debug( "pycurl.USERPWD value = "+str(userpass))
-    self.c.setopt(pycurl.USERPWD, userpass)
-
-
-  def set_headers(self, headers):
-    """
-    Add headers to the request
-    """
-    self._headers = headers
-    return self
-
-  @property
-  def host_url(self):
-    return self._host_url
-
-  def _get_headers(self, headers):
-    res = self._headers.copy()
-    if headers:
-      res.update(headers)
-    return res
-
-  def invoke(self, http_method, path, payload=None, headers=None):
-    """
-    Submit an HTTP request.
-    @param http_method: GET, POST, PUT, DELETE
-    @param path: The path of the resource.
-    @param payload: The payload to attach to the body of the request.
-    @param headers: The headers to set for this request.
-
-    @return: The result of REST request
-    """
-    #pdb.set_trace()
-    LOG.debug ("invoke : http_method = "+str(http_method))
-    # Prepare URL and params
-    url = self._normalize(path)
-    if http_method in ("GET", "DELETE"):
-      if payload is not None:
-        self.logger.warn(
-            "GET http_method does not pass any payload. Path '%s'" % (path,))
-        payload = None
-
-
-    buf = cStringIO.StringIO()
-    self.c.setopt(pycurl.WRITEFUNCTION, buf.write)
-    LOG.debug ("invoke : url = "+str(url))
-    # set http_method
-    if http_method == "GET":
-        self.c.setopt(pycurl.HTTPGET, 1)
-    elif http_method == "HEAD":
-        self.c.setopt(pycurl.HTTPGET, 1)
-        self.c.setopt(pycurl.NOBODY, 1)
-    elif http_method == "POST":
-        self.c.setopt(pycurl.POST, 1)
-    elif http_method == "PUT":
-        self.c.setopt(pycurl.UPLOAD, 1)
-    else:
-        self.c.setopt(pycurl.CUSTOMREQUEST, http_method)
-        
-    if http_method in ('POST','PUT'):
-      LOG.debug( "data..........."+str(payload))
-      data = json.dumps(payload)
-      data= data.decode('unicode-escape')
-      LOG.debug( data)
-      data = self._to_bytestring(data)
-      LOG.debug( data)
-      content = StringIO.StringIO(data)
-      LOG.debug( content)
-      content_length = len(data)
-      LOG.debug( "content_length........."+str(content_length))
-
-      if http_method == 'POST':
-        self.c.setopt(pycurl.POSTFIELDSIZE, content_length)
-      else:
-        self.c.setopt(pycurl.INFILESIZE, content_length)
-      self.c.setopt(pycurl.READFUNCTION, content.read)
-      
-      
-    self.c.setopt(self.c.URL, url)
-    headers = self._get_headers(headers)
-    self.c.setopt(pycurl.HTTPHEADER,
-                        ["%s: %s" % pair for pair in sorted(headers.iteritems())])
-
-    LOG.debug ("invoke : pycurl.EFFECTIVE_URL = "+self.c.getinfo(pycurl.EFFECTIVE_URL))
-    try:
-        self.c.perform()
-    except Exception, ex:
-        LOG.debug (sys.stderr, str(ex))
-        raise ex
-    contents_type= self.c.getinfo(pycurl.CONTENT_TYPE)
-    LOG.debug ("invoke : pycurl.CONTENT_TYPE = "+contents_type)
-    code = self.c.getinfo(pycurl.RESPONSE_CODE)
-    LOG.debug ("invoke : pycurl.RESPONSE_CODE = "+str(code))
-    response = buf.getvalue()
-    buf.close()
-    LOG.debug ("invoke : COMPLETED ")
-    return response , code , contents_type
-
-  def _to_bytestring(self ,s):
-#    if not isinstance(s, basestring):
-#      raise TypeError("value should be a str or unicode")
-    if isinstance(s, unicode):
-      return s.encode('utf-8')
-    return s
-
-  def _normalize(self, path):
-    res = self._host_url
-    if path:
-      res += posixpath.normpath('/' + path.lstrip('/'))
-    return uri_encoding(res)

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/http_utils.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/http_utils.py b/ambari-client/src/main/python/ambari_client/http_utils.py
deleted file mode 100644
index 8c53c9e..0000000
--- a/ambari-client/src/main/python/ambari_client/http_utils.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-#  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 types
-import urllib
-import urllib2
-
-
-def uri_encoding(url):
-    """
-    Returns an ASCII string version of the URL.
-    """
-    if url is None:
-        return url
-    return urllib.quote(get_utf8_str(url), safe="/#%[]=:;$&()+,!?*@'~")
-
-
-
-def get_utf8_str(strr, encoding='utf-8'):
-    """
-    Returns a utf8 ecoded 'str'.
-    """
-    errors='strict'
-    if not isinstance(strr, basestring):
-        try:
-            return str(strr)
-        except UnicodeEncodeError:
-            if isinstance(strr, Exception):
-                return ' '.join([get_utf8_str(arg, encoding) for arg in strr])
-            return unicode(strr).encode(encoding, errors)
-    elif isinstance(strr, unicode):
-        return strr.encode(encoding, errors)
-    elif strr and encoding != 'utf-8':
-        return strr.decode('utf-8', errors).encode(encoding, errors)
-    else:
-        return strr
-

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/__init__.py b/ambari-client/src/main/python/ambari_client/model/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/base_model.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/base_model.py b/ambari-client/src/main/python/ambari_client/model/base_model.py
index fe0939b..1c00e60 100644
--- a/ambari-client/src/main/python/ambari_client/model/base_model.py
+++ b/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:

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/cluster.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/cluster.py b/ambari-client/src/main/python/ambari_client/model/cluster.py
index 27c9e34..7a012dd 100644
--- a/ambari-client/src/main/python/ambari_client/model/cluster.py
+++ b/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',)

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/host.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/host.py b/ambari-client/src/main/python/ambari_client/model/host.py
new file mode 100644
index 0000000..3e7fc48
--- /dev/null
+++ b/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
+

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/paths.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/paths.py b/ambari-client/src/main/python/ambari_client/model/paths.py
index 9c78230..cc39a2a 100644
--- a/ambari-client/src/main/python/ambari_client/model/paths.py
+++ b/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"

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/service.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/service.py b/ambari-client/src/main/python/ambari_client/model/service.py
index ff07d6d..03b6421 100644
--- a/ambari-client/src/main/python/ambari_client/model/service.py
+++ b/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())
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/status.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/status.py b/ambari-client/src/main/python/ambari_client/model/status.py
new file mode 100644
index 0000000..657afdd
--- /dev/null
+++ b/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
+

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/model/utils.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/model/utils.py b/ambari-client/src/main/python/ambari_client/model/utils.py
index 83c1887..904154d 100644
--- a/ambari-client/src/main/python/ambari_client/model/utils.py
+++ b/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
 

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/resources/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/resources/__init__.py b/ambari-client/src/main/python/ambari_client/resources/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/resources/clusters.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/resources/clusters.py b/ambari-client/src/main/python/ambari_client/resources/clusters.py
index 125bec2..0e3f0be 100644
--- a/ambari-client/src/main/python/ambari_client/resources/clusters.py
+++ b/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)
\ No newline at end of file
+  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)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/resources/hosts.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/resources/hosts.py b/ambari-client/src/main/python/ambari_client/resources/hosts.py
new file mode 100644
index 0000000..cc4bcc4
--- /dev/null
+++ b/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)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/resources/services.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/resources/services.py b/ambari-client/src/main/python/ambari_client/resources/services.py
index 3345f95..abddbec 100644
--- a/ambari-client/src/main/python/ambari_client/resources/services.py
+++ b/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"

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/main/python/ambari_client/rest_resource.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/main/python/ambari_client/rest_resource.py b/ambari-client/src/main/python/ambari_client/rest_resource.py
deleted file mode 100644
index 0f62b52..0000000
--- a/ambari-client/src/main/python/ambari_client/rest_resource.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#
-#  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
-import posixpath
-
-LOG = logging.getLogger(__name__)
-
-
-class RestResource(object):
-  """
-  RestResource wrapper.
-  """
-  def __init__(self, client, path=""):
-    """
-    @param client: A Client object.
-    @param path: The relative path of the resource.
-    """
-    self._client = client
-    self._path = path.strip('/')
-
-  @property
-  def host_url(self):
-    return self._client.host_url
-
-  def _join_uri(self, relpath):
-    if relpath is None:
-      return self._path
-    return self._path + posixpath.normpath('/' + relpath)
-  
-  def _set_headers(self, content_type=None):
-    if content_type:
-      return { 'Content-Type': content_type }
-    return None
-
-
-  def make_invoke(self, http_method, payload, headers, path):
-      return self._client.invoke(http_method, path, payload=payload, headers=headers)
-
-  def invoke(self, http_method, url_path=None, payload=None, headers=None):
-    """
-    Invoke an API http_method.
-    """
-    path = self._join_uri(url_path)
-    resp ,code , content  = self.make_invoke(http_method, payload, headers, path)
-
-    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))
-    try:
-        if code==200 and not resp:
-          return {}
-        json_dict = json.loads(resp)
-        return json_dict
-    except Exception, ex:
-        LOG.error('JSON decode error: %s' % (resp,))
-        raise ex
-
-
-
-  def get(self, path=None):
-    """
-    Invoke the GET method .
-    @param path: resource path
-    @return: A dictionary of the REST result.
-    """
-    return self.invoke("GET", path)
-
-
-  def put(self, path=None, payload=None, content_type=None):
-    """
-    Invoke the PUT 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("PUT", path, payload,self._set_headers(content_type))
-
-
-

http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/23754e34/ambari-client/src/test/python/TestAmbariClient.py
----------------------------------------------------------------------
diff --git a/ambari-client/src/test/python/TestAmbariClient.py b/ambari-client/src/test/python/TestAmbariClient.py
index 891cca1..ed0ff9c 100644
--- a/ambari-client/src/test/python/TestAmbariClient.py
+++ b/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.