Hello community,

here is the log from the commit of package python-saharaclient for 
openSUSE:Factory checked in at 2018-03-19 23:36:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-saharaclient (Old)
 and      /work/SRC/openSUSE:Factory/.python-saharaclient.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-saharaclient"

Mon Mar 19 23:36:52 2018 rev:8 rq:583357 version:1.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-saharaclient/python-saharaclient.changes  
2018-01-24 15:28:06.305095171 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-saharaclient.new/python-saharaclient.changes 
    2018-03-19 23:36:52.580604078 +0100
@@ -1,0 +2,20 @@
+Fri Feb 23 13:41:56 UTC 2018 - [email protected]
+
+- Switch to stable/queens spec template
+
+-------------------------------------------------------------------
+Mon Feb 12 10:10:07 UTC 2018 - [email protected]
+
+- update to version 1.5.0 (bsc#1078607)
+  - Remove -U from pip install
+  - APIv2 support in client
+  - Fix misleading docstring
+  - Remove setting of version/release from releasenotes
+  - Modify home page in setup.cfg
+  - Properly document job binary "extra"
+  - Auto-document members properly
+  - Avoid tox_install.sh for constraints support
+  - Updated from global requirements
+  - Support of S3 binaries in OSC
+
+-------------------------------------------------------------------

Old:
----
  python-saharaclient-1.4.0.tar.gz

New:
----
  python-saharaclient-1.5.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-saharaclient.spec ++++++
--- /var/tmp/diff_new_pack.y7bOsN/_old  2018-03-19 23:36:53.460572334 +0100
+++ /var/tmp/diff_new_pack.y7bOsN/_new  2018-03-19 23:36:53.464572190 +0100
@@ -18,7 +18,7 @@
 
 %global sname saharaclient
 Name:           python-saharaclient
-Version:        1.4.0
+Version:        1.5.0
 Release:        0
 Summary:        Client library for OpenStack Sahara API
 License:        Apache-2.0
@@ -30,12 +30,12 @@
 BuildRequires:  python-keystoneclient >= 3.8.0
 BuildRequires:  python-mock >= 2.0.0
 BuildRequires:  python-os-testr >= 1.0.0
-BuildRequires:  python-osc-lib >= 1.7.0
+BuildRequires:  python-osc-lib >= 1.8.0
 BuildRequires:  python-oslo.i18n >= 3.15.3
-BuildRequires:  python-oslo.log >= 3.30.0
+BuildRequires:  python-oslo.log >= 3.36.0
 BuildRequires:  python-oslo.serialization >= 2.18.0
-BuildRequires:  python-oslo.utils >= 3.31.0
-BuildRequires:  python-oslotest >= 1.10.0
+BuildRequires:  python-oslo.utils >= 3.33.0
+BuildRequires:  python-oslotest >= 3.2.0
 BuildRequires:  python-pbr >= 2.0.0
 BuildRequires:  python-requests >= 2.14.2
 BuildRequires:  python-requests-mock >= 1.1.0
@@ -43,14 +43,14 @@
 BuildRequires:  python-testrepository >= 0.0.18
 Requires:       python-Babel >= 2.3.4
 Requires:       python-PrettyTable >= 0.7.1
-Requires:       python-keystoneauth1 >= 3.2.0
+Requires:       python-keystoneauth1 >= 3.3.0
 Requires:       python-keystoneclient >= 3.8.0
 Requires:       python-openstackclient >= 3.12.0
-Requires:       python-osc-lib >= 1.7.0
+Requires:       python-osc-lib >= 1.8.0
 Requires:       python-oslo.i18n >= 3.15.3
-Requires:       python-oslo.log >= 3.30.0
+Requires:       python-oslo.log >= 3.36.0
 Requires:       python-oslo.serialization >= 2.18.0
-Requires:       python-oslo.utils >= 3.31.0
+Requires:       python-oslo.utils >= 3.33.0
 Requires:       python-requests >= 2.14.2
 Requires:       python-six >= 1.10.0
 BuildArch:      noarch
@@ -62,7 +62,7 @@
 Summary:        Documentation for Client library for OpenStack Sahara API
 Group:          Documentation/HTML
 BuildRequires:  python-Sphinx
-BuildRequires:  python-openstackdocstheme >= 1.17.0
+BuildRequires:  python-openstackdocstheme >= 1.18.1
 
 %description doc
 Python client library for interacting with OpenStack Sahara API.

++++++ _service ++++++
--- /var/tmp/diff_new_pack.y7bOsN/_old  2018-03-19 23:36:53.496571035 +0100
+++ /var/tmp/diff_new_pack.y7bOsN/_new  2018-03-19 23:36:53.500570891 +0100
@@ -1,8 +1,8 @@
 <services>
   <service mode="disabled" name="renderspec">
-    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/master/openstack/python-saharaclient/python-saharaclient.spec.j2</param>
+    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/queens/openstack/python-saharaclient/python-saharaclient.spec.j2</param>
     <param name="output-name">python-saharaclient.spec</param>
-    <param 
name="requirements">https://raw.githubusercontent.com/openstack/rpm-packaging/master/requirements.txt</param>
+    <param 
name="requirements">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/queens/requirements.txt</param>
     <param name="changelog-email">[email protected]</param>
     <param name="changelog-provider">gh,openstack,python-saharaclient</param>
   </service>

++++++ python-saharaclient-1.4.0.tar.gz -> python-saharaclient-1.5.0.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/AUTHORS 
new/python-saharaclient-1.5.0/AUTHORS
--- old/python-saharaclient-1.4.0/AUTHORS       2017-11-17 00:10:10.000000000 
+0100
+++ new/python-saharaclient-1.5.0/AUTHORS       2018-01-30 00:39:20.000000000 
+0100
@@ -21,6 +21,7 @@
 James E. Blair <[email protected]>
 Jamie Lennox <[email protected]>
 Jaxon Wang <[email protected]>
+Jeremy Freudberg <[email protected]>
 Jeremy Liu <[email protected]>
 Jeremy Stanley <[email protected]>
 KATO Tomoyuki <[email protected]>
@@ -67,6 +68,7 @@
 Zhiqiang Fan <[email protected]>
 Zuul <[email protected]>
 bhagyashris <[email protected]>
+caishan <[email protected]>
 chioleong <[email protected]>
 daohanli <[email protected]>
 henriquetruta <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/ChangeLog 
new/python-saharaclient-1.5.0/ChangeLog
--- old/python-saharaclient-1.4.0/ChangeLog     2017-11-17 00:10:10.000000000 
+0100
+++ new/python-saharaclient-1.5.0/ChangeLog     2018-01-30 00:39:20.000000000 
+0100
@@ -1,6 +1,25 @@
 CHANGES
 =======
 
+1.5.0
+-----
+
+* Auto-document members properly
+* APIv2 support in client
+* Updated from global requirements
+* Modify home page in setup.cfg
+* Updated from global requirements
+* Updated from global requirements
+* Support of S3 binaries in OSC
+* Fix misleading docstring
+* Properly document job binary "extra"
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Remove -U from pip install
+* Avoid tox\_install.sh for constraints support
+* Remove setting of version/release from releasenotes
+
 1.4.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/PKG-INFO 
new/python-saharaclient-1.5.0/PKG-INFO
--- old/python-saharaclient-1.4.0/PKG-INFO      2017-11-17 00:10:11.000000000 
+0100
+++ new/python-saharaclient-1.5.0/PKG-INFO      2018-01-30 00:39:21.000000000 
+0100
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: python-saharaclient
-Version: 1.4.0
+Version: 1.5.0
 Summary: Client library for Sahara API
-Home-page: https://github.com/openstack/python-saharaclient
+Home-page: https://docs.openstack.org/python-saharaclient/latest/
 Author: OpenStack
 Author-email: [email protected]
 License: Apache License, Version 2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/doc/source/reference/index.rst 
new/python-saharaclient-1.5.0/doc/source/reference/index.rst
--- old/python-saharaclient-1.4.0/doc/source/reference/index.rst        
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/doc/source/reference/index.rst        
2018-01-30 00:35:49.000000000 +0100
@@ -6,3 +6,4 @@
    :maxdepth: 2
 
    pythonclient
+   pythonclient_v2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/doc/source/reference/pythonclient.rst 
new/python-saharaclient-1.5.0/doc/source/reference/pythonclient.rst
--- old/python-saharaclient-1.4.0/doc/source/reference/pythonclient.rst 
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/doc/source/reference/pythonclient.rst 
2018-01-30 00:35:49.000000000 +0100
@@ -103,38 +103,44 @@
 Plugin ops
 ~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.plugins.PluginManager
+.. autoclass:: saharaclient.api.plugins.PluginManagerV1
     :members:
+    :inherited-members:
 
 Image Registry ops
 ~~~~~~~~~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.images.ImageManager
+.. autoclass:: saharaclient.api.images.ImageManagerV1
     :members:
+    :inherited-members:
 
 Node Group Template ops
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.node_group_templates.NodeGroupTemplateManager
+.. autoclass:: saharaclient.api.node_group_templates.NodeGroupTemplateManagerV1
     :members:
+    :inherited-members:
 
 Cluster Template ops
 ~~~~~~~~~~~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.cluster_templates.ClusterTemplateManager
+.. autoclass:: saharaclient.api.cluster_templates.ClusterTemplateManagerV1
     :members:
+    :inherited-members:
 
 Cluster ops
 ~~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.clusters.ClusterManager
+.. autoclass:: saharaclient.api.clusters.ClusterManagerV1
    :members:
+   :inherited-members:
 
 Data Source ops
 ~~~~~~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.data_sources.DataSourceManager
+.. autoclass:: saharaclient.api.data_sources.DataSourceManagerV1
    :members:
+   :inherited-members:
 
 Job Binary Internal ops
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -145,23 +151,27 @@
 Job Binary ops
 ~~~~~~~~~~~~~~
 
-.. autoclass:: saharaclient.api.job_binaries.JobBinariesManager
+.. autoclass:: saharaclient.api.job_binaries.JobBinariesManagerV1
    :members:
+   :inherited-members:
 
 Job ops
 ~~~~~~~
 
-.. autoclass:: saharaclient.api.jobs.JobsManager
+.. autoclass:: saharaclient.api.jobs.JobsManagerV1
    :members:
+   :inherited-members:
 
 Job Execution ops
 ~~~~~~~~~~~~~~~~~
 
 .. autoclass:: saharaclient.api.job_executions.JobExecutionsManager
    :members:
+   :inherited-members:
 
 Job Types ops
 ~~~~~~~~~~~~~
 
 .. autoclass:: saharaclient.api.job_types.JobTypesManager
    :members:
+   :inherited-members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/doc/source/reference/pythonclient_v2.rst 
new/python-saharaclient-1.5.0/doc/source/reference/pythonclient_v2.rst
--- old/python-saharaclient-1.4.0/doc/source/reference/pythonclient_v2.rst      
1970-01-01 01:00:00.000000000 +0100
+++ new/python-saharaclient-1.5.0/doc/source/reference/pythonclient_v2.rst      
2018-01-30 00:35:49.000000000 +0100
@@ -0,0 +1,82 @@
+Python Sahara client for APIv2
+==============================
+
+Overview
+--------
+
+There is also support for Sahara's experimental APIv2.
+
+
+Supported operations
+--------------------
+
+Plugin ops
+~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.plugins.PluginManagerV2
+    :members:
+    :inherited-members:
+
+Image Registry ops
+~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.images.ImageManagerV2
+    :members:
+    :inherited-members:
+
+Node Group Template ops
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.node_group_templates.NodeGroupTemplateManagerV2
+    :members:
+    :inherited-members:
+
+Cluster Template ops
+~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.cluster_templates.ClusterTemplateManagerV2
+    :members:
+    :inherited-members:
+
+Cluster ops
+~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.clusters.ClusterManagerV2
+   :members:
+   :inherited-members:
+
+Data Source ops
+~~~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.data_sources.DataSourceManagerV2
+   :members:
+   :inherited-members:
+
+Job Binary ops
+~~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.job_binaries.JobBinariesManagerV2
+   :members:
+   :inherited-members:
+
+Job Template ops
+~~~~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.v2.job_templates.JobTemplatesManagerV2
+   :members:
+   :inherited-members:
+
+Job ops
+~~~~~~~
+
+.. autoclass:: saharaclient.api.v2.jobs.JobsManagerV2
+   :members:
+   :inherited-members:
+
+Job Types ops
+~~~~~~~~~~~~~
+
+.. autoclass:: saharaclient.api.job_types.JobTypesManager
+   :members:
+   :inherited-members:
+   :noindex:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/python_saharaclient.egg-info/PKG-INFO 
new/python-saharaclient-1.5.0/python_saharaclient.egg-info/PKG-INFO
--- old/python-saharaclient-1.4.0/python_saharaclient.egg-info/PKG-INFO 
2017-11-17 00:10:10.000000000 +0100
+++ new/python-saharaclient-1.5.0/python_saharaclient.egg-info/PKG-INFO 
2018-01-30 00:39:20.000000000 +0100
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: python-saharaclient
-Version: 1.4.0
+Version: 1.5.0
 Summary: Client library for Sahara API
-Home-page: https://github.com/openstack/python-saharaclient
+Home-page: https://docs.openstack.org/python-saharaclient/latest/
 Author: OpenStack
 Author-email: [email protected]
 License: Apache License, Version 2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/python_saharaclient.egg-info/SOURCES.txt 
new/python-saharaclient-1.5.0/python_saharaclient.egg-info/SOURCES.txt
--- old/python-saharaclient-1.4.0/python_saharaclient.egg-info/SOURCES.txt      
2017-11-17 00:10:11.000000000 +0100
+++ new/python-saharaclient-1.5.0/python_saharaclient.egg-info/SOURCES.txt      
2018-01-30 00:39:20.000000000 +0100
@@ -28,6 +28,7 @@
 doc/source/contributor/index.rst
 doc/source/reference/index.rst
 doc/source/reference/pythonclient.rst
+doc/source/reference/pythonclient_v2.rst
 python_saharaclient.egg-info/PKG-INFO
 python_saharaclient.egg-info/SOURCES.txt
 python_saharaclient.egg-info/dependency_links.txt
@@ -42,6 +43,7 @@
 releasenotes/notes/cli-deprecation-da0e7b6dfe77af52.yaml
 releasenotes/notes/designate-integration-16c59a6b57dbcfa4.yaml
 releasenotes/notes/event-logs-c6d286e25dc7d9b1.yaml
+releasenotes/notes/experimental-v2-support-67ccf699e056ed78.yaml
 releasenotes/notes/fields-unset-068db4c3e680c37d.yaml
 releasenotes/notes/implement-pagination-2ba52769d240a3ce.yaml
 releasenotes/notes/job-binary-create-optional-bc0f9ee6426c5659.yaml
@@ -88,6 +90,9 @@
 saharaclient/api/node_group_templates.py
 saharaclient/api/parameters.py
 saharaclient/api/plugins.py
+saharaclient/api/v2/__init__.py
+saharaclient/api/v2/job_templates.py
+saharaclient/api/v2/jobs.py
 saharaclient/osc/__init__.py
 saharaclient/osc/plugin.py
 saharaclient/osc/v1/__init__.py
@@ -142,5 +147,4 @@
 saharaclient/tests/unit/osc/v1/test_utils.py
 tools/install_venv.py
 tools/install_venv_common.py
-tools/tox_install.sh
 tools/with_venv.sh
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/python_saharaclient.egg-info/pbr.json 
new/python-saharaclient-1.5.0/python_saharaclient.egg-info/pbr.json
--- old/python-saharaclient-1.4.0/python_saharaclient.egg-info/pbr.json 
2017-11-17 00:10:10.000000000 +0100
+++ new/python-saharaclient-1.5.0/python_saharaclient.egg-info/pbr.json 
2018-01-30 00:39:20.000000000 +0100
@@ -1 +1 @@
-{"git_version": "4728d99", "is_release": true}
\ No newline at end of file
+{"git_version": "ee5f173", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/python_saharaclient.egg-info/requires.txt 
new/python-saharaclient-1.5.0/python_saharaclient.egg-info/requires.txt
--- old/python-saharaclient-1.4.0/python_saharaclient.egg-info/requires.txt     
2017-11-17 00:10:10.000000000 +0100
+++ new/python-saharaclient-1.5.0/python_saharaclient.egg-info/requires.txt     
2018-01-30 00:39:20.000000000 +0100
@@ -1,11 +1,11 @@
 pbr!=2.1.0,>=2.0.0
 Babel!=2.4.0,>=2.3.4
-keystoneauth1>=3.2.0
-osc-lib>=1.7.0
-oslo.log>=3.30.0
+keystoneauth1>=3.3.0
+osc-lib>=1.8.0
+oslo.log>=3.36.0
 oslo.serialization!=2.19.1,>=2.18.0
 oslo.i18n>=3.15.3
-oslo.utils>=3.31.0
+oslo.utils>=3.33.0
 python-openstackclient>=3.12.0
 requests>=2.14.2
 six>=1.10.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/releasenotes/notes/experimental-v2-support-67ccf699e056ed78.yaml
 
new/python-saharaclient-1.5.0/releasenotes/notes/experimental-v2-support-67ccf699e056ed78.yaml
--- 
old/python-saharaclient-1.4.0/releasenotes/notes/experimental-v2-support-67ccf699e056ed78.yaml
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/python-saharaclient-1.5.0/releasenotes/notes/experimental-v2-support-67ccf699e056ed78.yaml
      2018-01-30 00:35:49.000000000 +0100
@@ -0,0 +1,3 @@
+---
+features:
+  - Initial support for Sahara's experimental APIv2 is present.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/releasenotes/source/conf.py 
new/python-saharaclient-1.5.0/releasenotes/source/conf.py
--- old/python-saharaclient-1.4.0/releasenotes/source/conf.py   2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/releasenotes/source/conf.py   2018-01-30 
00:35:49.000000000 +0100
@@ -38,16 +38,11 @@
 project = u'Saharaclient Release Notes'
 copyright = u'2015, Sahara Developers'
 
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-from saharaclient.version import version_info as saharaclient_version
+# Release notes are version independent.
 # The full version, including alpha/beta/rc tags.
-release = saharaclient_version.version_string_with_vcs()
+release = ''
 # The short X.Y version.
-version = saharaclient_version.canonical_version_string()
+version = ''
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/requirements.txt 
new/python-saharaclient-1.5.0/requirements.txt
--- old/python-saharaclient-1.4.0/requirements.txt      2017-11-17 
00:07:07.000000000 +0100
+++ new/python-saharaclient-1.5.0/requirements.txt      2018-01-30 
00:35:49.000000000 +0100
@@ -5,12 +5,12 @@
 pbr!=2.1.0,>=2.0.0 # Apache-2.0
 
 Babel!=2.4.0,>=2.3.4 # BSD
-keystoneauth1>=3.2.0 # Apache-2.0
-osc-lib>=1.7.0 # Apache-2.0
-oslo.log>=3.30.0 # Apache-2.0
+keystoneauth1>=3.3.0 # Apache-2.0
+osc-lib>=1.8.0 # Apache-2.0
+oslo.log>=3.36.0 # Apache-2.0
 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
 oslo.i18n>=3.15.3 # Apache-2.0
-oslo.utils>=3.31.0 # Apache-2.0
+oslo.utils>=3.33.0 # Apache-2.0
 python-openstackclient>=3.12.0 # Apache-2.0
 requests>=2.14.2 # Apache-2.0
 six>=1.10.0 # MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/saharaclient/api/base.py 
new/python-saharaclient-1.5.0/saharaclient/api/base.py
--- old/python-saharaclient-1.4.0/saharaclient/api/base.py      2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/base.py      2018-01-30 
00:35:49.000000000 +0100
@@ -120,7 +120,7 @@
 
         resp = self.api.put(url, **kwargs)
 
-        if resp.status_code != 202:
+        if resp.status_code not in [200, 202]:
             self._raise_api_exception(resp)
         if response_key is not None:
             data = get_json(resp)[response_key]
@@ -206,8 +206,12 @@
         else:
             self._raise_api_exception(resp)
 
-    def _delete(self, url):
-        resp = self.api.delete(url)
+    def _delete(self, url, data=None):
+        if data is not None:
+            kwargs = {'json': data}
+            resp = self.api.delete(url, **kwargs)
+        else:
+            resp = self.api.delete(url)
 
         if resp.status_code != 204:
             self._raise_api_exception(resp)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/saharaclient/api/client.py 
new/python-saharaclient-1.5.0/saharaclient/api/client.py
--- old/python-saharaclient-1.4.0/saharaclient/api/client.py    2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/client.py    2018-01-30 
00:35:49.000000000 +0100
@@ -16,7 +16,6 @@
 import warnings
 
 from keystoneauth1 import adapter
-from keystoneauth1 import exceptions
 from keystoneauth1.identity import v2
 from keystoneauth1.identity import v3
 from keystoneauth1 import session as keystone_session
@@ -33,6 +32,8 @@
 from saharaclient.api import jobs
 from saharaclient.api import node_group_templates
 from saharaclient.api import plugins
+from saharaclient.api.v2 import job_templates
+from saharaclient.api.v2 import jobs as jobs_v2
 
 
 USER_AGENT = 'python-saharaclient'
@@ -42,11 +43,15 @@
 
     def request(self, *args, **kwargs):
         kwargs.setdefault('raise_exc', False)
+        kwargs.setdefault('allow', {'allow_experimental': True})
         return super(HTTPClient, self).request(*args, **kwargs)
 
 
 class Client(object):
-    """Client for the OpenStack Data Processing v1 API.
+
+    _api_version = '1.1'
+
+    """Client for the OpenStack Data Processing API.
 
         :param str username: Username for Keystone authentication.
         :param str api_key: Password for Keystone authentication.
@@ -101,16 +106,6 @@
         if not auth:
             auth = session.auth
 
-        # NOTE(Toan): bug #1512801. If sahara_url is provided, it does not
-        # matter if service_type is orthographically correct or not.
-        # Only find Sahara service_type and endpoint in Keystone catalog
-        # if sahara_url is not provided.
-        if not sahara_url:
-            service_type = self._determine_service_type(session,
-                                                        auth,
-                                                        service_type,
-                                                        endpoint_type)
-
         kwargs['user_agent'] = USER_AGENT
         kwargs.setdefault('interface', endpoint_type)
         kwargs.setdefault('endpoint_override', sahara_url)
@@ -119,22 +114,25 @@
                             auth=auth,
                             service_type=service_type,
                             region_name=region_name,
+                            version=self._api_version,
                             **kwargs)
 
-        self.clusters = clusters.ClusterManager(client)
+        self._register_managers(client)
+
+    def _register_managers(self, client):
+        self.clusters = clusters.ClusterManagerV1(client)
         self.cluster_templates = (
-            cluster_templates.ClusterTemplateManager(client)
+            cluster_templates.ClusterTemplateManagerV1(client)
         )
         self.node_group_templates = (
-            node_group_templates.NodeGroupTemplateManager(client)
+            node_group_templates.NodeGroupTemplateManagerV1(client)
         )
-        self.plugins = plugins.PluginManager(client)
-        self.images = images.ImageManager(client)
-
-        self.data_sources = data_sources.DataSourceManager(client)
-        self.jobs = jobs.JobsManager(client)
+        self.plugins = plugins.PluginManagerV1(client)
+        self.images = images.ImageManagerV1(client)
+        self.data_sources = data_sources.DataSourceManagerV1(client)
+        self.jobs = jobs.JobsManagerV1(client)
         self.job_executions = job_executions.JobExecutionsManager(client)
-        self.job_binaries = job_binaries.JobBinariesManager(client)
+        self.job_binaries = job_binaries.JobBinariesManagerV1(client)
         self.job_binary_internals = (
             job_binary_internals.JobBinaryInternalsManager(client)
         )
@@ -162,27 +160,23 @@
                                project_name=project_name,
                                project_domain_id='default')
 
-    @staticmethod
-    def _determine_service_type(session, auth, service_type, interface):
-        """Check a catalog for data-processing or data_processing"""
-
-        # NOTE(jamielennox): calling get_endpoint forces an auth on
-        # initialization which is required for backwards compatibility. It
-        # also allows us to reset the service type if not in the catalog.
-        for st in (service_type, service_type.replace('-', '_')):
-            try:
-                url = auth.get_endpoint(session,
-                                        service_type=st,
-                                        interface=interface)
-            except exceptions.Unauthorized:
-                raise RuntimeError("Not Authorized")
-            except exceptions.EndpointNotFound:
-                # NOTE(jamielennox): bug #1428447. This should not be
-                # raised, instead None should be returned. Handle in case
-                # it changes in the future
-                url = None
 
-            if url:
-                return st
+class ClientV2(Client):
+
+    _api_version = '2'
 
-        raise RuntimeError("Could not find Sahara endpoint in catalog")
+    def _register_managers(self, client):
+        self.clusters = clusters.ClusterManagerV2(client)
+        self.cluster_templates = (
+            cluster_templates.ClusterTemplateManagerV2(client)
+        )
+        self.node_group_templates = (
+            node_group_templates.NodeGroupTemplateManagerV2(client)
+        )
+        self.plugins = plugins.PluginManagerV2(client)
+        self.images = images.ImageManagerV2(client)
+        self.data_sources = data_sources.DataSourceManagerV2(client)
+        self.job_templates = job_templates.JobTemplatesManagerV2(client)
+        self.jobs = jobs_v2.JobsManagerV2(client)
+        self.job_binaries = job_binaries.JobBinariesManagerV2(client)
+        self.job_types = job_types.JobTypesManager(client)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/cluster_templates.py 
new/python-saharaclient-1.5.0/saharaclient/api/cluster_templates.py
--- old/python-saharaclient-1.4.0/saharaclient/api/cluster_templates.py 
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/cluster_templates.py 
2018-01-30 00:35:49.000000000 +0100
@@ -20,7 +20,7 @@
     resource_name = 'Cluster Template'
 
 
-class ClusterTemplateManager(base.ResourceManager):
+class ClusterTemplateManagerV1(base.ResourceManager):
     resource_class = ClusterTemplate
     NotUpdated = base.NotUpdated()
 
@@ -37,6 +37,15 @@
             'hadoop_version': hadoop_version,
         }
 
+        return self._do_create(data, description, cluster_configs,
+                               node_groups, anti_affinity, net_id,
+                               default_image_id, use_autoconfig, shares,
+                               is_public, is_protected, domain_name)
+
+    def _do_create(self, data, description, cluster_configs, node_groups,
+                   anti_affinity, net_id, default_image_id, use_autoconfig,
+                   shares, is_public, is_protected, domain_name):
+
         self._copy_if_defined(data,
                               description=description,
                               cluster_configs=cluster_configs,
@@ -101,3 +110,58 @@
     def export(self, cluster_template_id):
         """Export a Cluster Template."""
         return self._get('/cluster-templates/%s/export' % cluster_template_id)
+
+
+class ClusterTemplateManagerV2(ClusterTemplateManagerV1):
+    NotUpdated = base.NotUpdated()
+
+    def create(self, name, plugin_name, plugin_version, description=None,
+               cluster_configs=None, node_groups=None, anti_affinity=None,
+               net_id=None, default_image_id=None, use_autoconfig=None,
+               shares=None, is_public=None, is_protected=None,
+               domain_name=None):
+        """Create a Cluster Template."""
+
+        data = {
+            'name': name,
+            'plugin_name': plugin_name,
+            'plugin_version': plugin_version
+        }
+
+        return self._do_create(data, description, cluster_configs,
+                               node_groups, anti_affinity, net_id,
+                               default_image_id, use_autoconfig, shares,
+                               is_public, is_protected, domain_name)
+
+    def update(self, cluster_template_id, name=NotUpdated,
+               plugin_name=NotUpdated, plugin_version=NotUpdated,
+               description=NotUpdated, cluster_configs=NotUpdated,
+               node_groups=NotUpdated, anti_affinity=NotUpdated,
+               net_id=NotUpdated, default_image_id=NotUpdated,
+               use_autoconfig=NotUpdated, shares=NotUpdated,
+               is_public=NotUpdated, is_protected=NotUpdated,
+               domain_name=NotUpdated):
+        """Update a Cluster Template."""
+
+        data = {}
+        self._copy_if_updated(data, name=name,
+                              plugin_name=plugin_name,
+                              plugin_version=plugin_version,
+                              description=description,
+                              cluster_configs=cluster_configs,
+                              node_groups=node_groups,
+                              anti_affinity=anti_affinity,
+                              neutron_management_network=net_id,
+                              default_image_id=default_image_id,
+                              use_autoconfig=use_autoconfig,
+                              shares=shares,
+                              is_public=is_public,
+                              is_protected=is_protected,
+                              domain_name=domain_name)
+
+        return self._patch('/cluster-templates/%s' % cluster_template_id,
+                           data, 'cluster_template')
+
+
+# NOTE(jfreud): keep this around for backwards compatibility
+ClusterTemplateManager = ClusterTemplateManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/clusters.py 
new/python-saharaclient-1.5.0/saharaclient/api/clusters.py
--- old/python-saharaclient-1.4.0/saharaclient/api/clusters.py  2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/clusters.py  2018-01-30 
00:35:49.000000000 +0100
@@ -22,7 +22,7 @@
     resource_name = 'Cluster'
 
 
-class ClusterManager(base.ResourceManager):
+class ClusterManagerV1(base.ResourceManager):
     resource_class = Cluster
     NotUpdated = base.NotUpdated()
 
@@ -41,6 +41,17 @@
             'hadoop_version': hadoop_version,
         }
 
+        return self._do_create(data, cluster_template_id, default_image_id,
+                               is_transient, description, cluster_configs,
+                               node_groups, user_keypair_id, anti_affinity,
+                               net_id, count, use_autoconfig, shares,
+                               is_public, is_protected)
+
+    def _do_create(self, data, cluster_template_id, default_image_id,
+                   is_transient, description, cluster_configs, node_groups,
+                   user_keypair_id, anti_affinity, net_id, count,
+                   use_autoconfig, shares, is_public, is_protected):
+
         # Checking if count is greater than 1, otherwise we set it to None
         # so the created dict in the _copy_if_defined method does not contain
         # the count parameter.
@@ -136,3 +147,69 @@
         """Start a verification for a Cluster."""
         data = {'verification': {'status': status}}
         return self._patch("/clusters/%s" % cluster_id, data)
+
+
+class ClusterManagerV2(ClusterManagerV1):
+
+    def create(self, name, plugin_name, plugin_version,
+               cluster_template_id=None, default_image_id=None,
+               is_transient=None, description=None, cluster_configs=None,
+               node_groups=None, user_keypair_id=None,
+               anti_affinity=None, net_id=None, count=None,
+               use_autoconfig=None, shares=None,
+               is_public=None, is_protected=None):
+        """Launch a Cluster."""
+
+        data = {
+            'name': name,
+            'plugin_name': plugin_name,
+            'plugin_version': plugin_version,
+        }
+
+        return self._do_create(data, cluster_template_id, default_image_id,
+                               is_transient, description, cluster_configs,
+                               node_groups, user_keypair_id, anti_affinity,
+                               net_id, count, use_autoconfig, shares,
+                               is_public, is_protected)
+
+    def scale(self, cluster_id, scale_object):
+        """Scale an existing Cluster.
+
+        :param scale_object: dict that describes scaling operation
+
+        :Example:
+
+        The following `scale_object` can be used to change the number of
+        instances in the node group (optionally specifiying which instances to
+        delete) or add instances of a new node group to an existing cluster:
+
+        .. sourcecode:: json
+
+            {
+                "add_node_groups": [
+                    {
+                        "count": 3,
+                        "name": "new_ng",
+                        "node_group_template_id": "ngt_id"
+                    }
+                ],
+                "resize_node_groups": [
+                    {
+                        "count": 2,
+                        "name": "old_ng",
+                        "instances": ["instance_id1", "instance_id2"]
+                    }
+                ]
+            }
+
+        """
+        return self._update('/clusters/%s' % cluster_id, scale_object)
+
+    def force_delete(self, cluster_id):
+        """Force Delete a Cluster."""
+        data = {'force': True}
+        self._delete('/clusters/%s' % cluster_id, data)
+
+
+# NOTE(jfreud): keep this around for backwards compatibility
+ClusterManager = ClusterManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/data_sources.py 
new/python-saharaclient-1.5.0/saharaclient/api/data_sources.py
--- old/python-saharaclient-1.4.0/saharaclient/api/data_sources.py      
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/data_sources.py      
2018-01-30 00:35:49.000000000 +0100
@@ -20,8 +20,9 @@
     resource_name = 'Data Source'
 
 
-class DataSourceManager(base.ResourceManager):
+class DataSourceManagerV1(base.ResourceManager):
     resource_class = DataSources
+    version = 1.1
 
     def create(self, name, description, data_source_type,
                url, credential_user=None, credential_pass=None,
@@ -76,5 +77,18 @@
         * is_protected
         * credentials - dict with `user` and `password` keyword arguments
         """
-        return self._update('/data-sources/%s' % data_source_id,
-                            update_data)
+
+        if self.version >= 2:
+            UPDATE_FUNC = self._patch
+        else:
+            UPDATE_FUNC = self._update
+
+        return UPDATE_FUNC('/data-sources/%s' % data_source_id,
+                           update_data)
+
+
+class DataSourceManagerV2(DataSourceManagerV1):
+    version = 2
+
+# NOTE(jfreud): keep this around for backwards compatibility
+DataSourceManager = DataSourceManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/saharaclient/api/images.py 
new/python-saharaclient-1.5.0/saharaclient/api/images.py
--- old/python-saharaclient-1.4.0/saharaclient/api/images.py    2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/images.py    2018-01-30 
00:35:49.000000000 +0100
@@ -21,7 +21,7 @@
     defaults = {'description': ''}
 
 
-class ImageManager(base.ResourceManager):
+class _ImageManager(base.ResourceManager):
     resource_class = Image
 
     def list(self, search_opts=None):
@@ -45,6 +45,8 @@
 
         return self._post('/images/%s' % image_id, data)
 
+
+class ImageManagerV1(_ImageManager):
     def update_tags(self, image_id, new_tags):
         """Update an Image tags.
 
@@ -72,3 +74,18 @@
                                          {'tags': to_remove}, 'image')
 
         return remove_response or add_response or self.get(image_id)
+
+
+class ImageManagerV2(_ImageManager):
+    def get_tags(self, image_id):
+        return self._get('/images/%s/tags' % image_id)
+
+    def update_tags(self, image_id, new_tags):
+        return self._update('/images/%s/tags' % image_id,
+                            {'tags': new_tags})
+
+    def delete_tags(self, image_id):
+        return self._delete('/images/%s/tags' % image_id)
+
+# NOTE(jfreud): keep this around for backwards compatibility
+ImageManager = ImageManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/job_binaries.py 
new/python-saharaclient-1.5.0/saharaclient/api/job_binaries.py
--- old/python-saharaclient-1.4.0/saharaclient/api/job_binaries.py      
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/job_binaries.py      
2018-01-30 00:35:49.000000000 +0100
@@ -20,12 +20,20 @@
     resource_name = 'Job Binary'
 
 
-class JobBinariesManager(base.ResourceManager):
+class JobBinariesManagerV1(base.ResourceManager):
     resource_class = JobBinaries
+    version = 1.1
 
     def create(self, name, url, description=None, extra=None, is_public=None,
                is_protected=None):
-        """Create a Job Binary."""
+        """Create a Job Binary.
+
+        :param dict extra: authentication info needed for some job binaries,
+            containing the keys `user` and `password` for job binary in Swift
+            or the keys `accesskey`, `secretkey`, and `endpoint` for job
+            binary in S3
+
+        """
         data = {
             "name": name,
             "url": url
@@ -73,7 +81,23 @@
         * url
         * is_public
         * is_protected
-        * extra - dict with `user` and `password` keyword arguments
+        * extra - dict with the keys `user` and `password` for job binary
+          in Swift, or with the keys `accesskey`, `secretkey`, and `endpoint`
+          for job binary in S3
         """
-        return self._update(
+
+        if self.version >= 2:
+            UPDATE_FUNC = self._patch
+        else:
+            UPDATE_FUNC = self._update
+
+        return UPDATE_FUNC(
             '/job-binaries/%s' % job_binary_id, data, 'job_binary')
+
+
+class JobBinariesManagerV2(JobBinariesManagerV1):
+    version = 2
+
+
+# NOTE(jfreud): keep this around for backwards compatibility
+JobBinariesManager = JobBinariesManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/saharaclient/api/jobs.py 
new/python-saharaclient-1.5.0/saharaclient/api/jobs.py
--- old/python-saharaclient-1.4.0/saharaclient/api/jobs.py      2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/jobs.py      2018-01-30 
00:35:49.000000000 +0100
@@ -20,7 +20,7 @@
     resource_name = 'Job'
 
 
-class JobsManager(base.ResourceManager):
+class JobsManagerV1(base.ResourceManager):
     resource_class = Job
     NotUpdated = base.NotUpdated()
 
@@ -67,3 +67,7 @@
                               is_public=is_public, is_protected=is_protected)
 
         return self._patch('/jobs/%s' % job_id, data)
+
+
+# NOTE(jfreud): keep this around for backwards compatibility
+JobsManager = JobsManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/node_group_templates.py 
new/python-saharaclient-1.5.0/saharaclient/api/node_group_templates.py
--- old/python-saharaclient-1.4.0/saharaclient/api/node_group_templates.py      
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/node_group_templates.py      
2018-01-30 00:35:49.000000000 +0100
@@ -20,7 +20,7 @@
     resource_name = 'Node Group Template'
 
 
-class NodeGroupTemplateManager(base.ResourceManager):
+class NodeGroupTemplateManagerV1(base.ResourceManager):
     resource_class = NodeGroupTemplate
     NotUpdated = base.NotUpdated()
 
@@ -43,6 +43,22 @@
             'node_processes': node_processes
         }
 
+        return self._do_create(data, description, volumes_per_node,
+                               volumes_size, node_configs, floating_ip_pool,
+                               security_groups, auto_security_group,
+                               availability_zone, volumes_availability_zone,
+                               volume_type, image_id, is_proxy_gateway,
+                               volume_local_to_instance, use_autoconfig,
+                               shares, is_public, is_protected,
+                               volume_mount_prefix)
+
+    def _do_create(self, data, description, volumes_per_node, volumes_size,
+                   node_configs, floating_ip_pool, security_groups,
+                   auto_security_group, availability_zone,
+                   volumes_availability_zone, volume_type, image_id,
+                   is_proxy_gateway, volume_local_to_instance, use_autoconfig,
+                   shares, is_public, is_protected, volume_mount_prefix):
+
         self._copy_if_defined(data,
                               description=description,
                               node_configs=node_configs,
@@ -131,3 +147,75 @@
     def export(self, ng_template_id):
         """Export a Node Group Template."""
         return self._get('/node-group-templates/%s/export' % ng_template_id)
+
+
+class NodeGroupTemplateManagerV2(NodeGroupTemplateManagerV1):
+    NotUpdated = base.NotUpdated()
+
+    def create(self, name, plugin_name, plugin_version, flavor_id,
+               description=None, volumes_per_node=None, volumes_size=None,
+               node_processes=None, node_configs=None, floating_ip_pool=None,
+               security_groups=None, auto_security_group=None,
+               availability_zone=None, volumes_availability_zone=None,
+               volume_type=None, image_id=None, is_proxy_gateway=None,
+               volume_local_to_instance=None, use_autoconfig=None,
+               shares=None, is_public=None, is_protected=None,
+               volume_mount_prefix=None):
+        """Create a Node Group Template."""
+
+        data = {
+            'name': name,
+            'plugin_name': plugin_name,
+            'plugin_version': plugin_version,
+            'flavor_id': flavor_id,
+            'node_processes': node_processes
+        }
+
+        return self._do_create(data, description, volumes_per_node,
+                               volumes_size, node_configs, floating_ip_pool,
+                               security_groups, auto_security_group,
+                               availability_zone, volumes_availability_zone,
+                               volume_type, image_id, is_proxy_gateway,
+                               volume_local_to_instance, use_autoconfig,
+                               shares, is_public, is_protected,
+                               volume_mount_prefix)
+
+    def update(self, ng_template_id, name=NotUpdated, plugin_name=NotUpdated,
+               plugin_version=NotUpdated, flavor_id=NotUpdated,
+               description=NotUpdated, volumes_per_node=NotUpdated,
+               volumes_size=NotUpdated, node_processes=NotUpdated,
+               node_configs=NotUpdated, floating_ip_pool=NotUpdated,
+               security_groups=NotUpdated, auto_security_group=NotUpdated,
+               availability_zone=NotUpdated,
+               volumes_availability_zone=NotUpdated, volume_type=NotUpdated,
+               image_id=NotUpdated, is_proxy_gateway=NotUpdated,
+               volume_local_to_instance=NotUpdated, use_autoconfig=NotUpdated,
+               shares=NotUpdated, is_public=NotUpdated,
+               is_protected=NotUpdated, volume_mount_prefix=NotUpdated):
+        """Update a Node Group Template."""
+
+        data = {}
+        self._copy_if_updated(
+            data, name=name, plugin_name=plugin_name,
+            plugin_version=plugin_version, flavor_id=flavor_id,
+            description=description, volumes_per_node=volumes_per_node,
+            volumes_size=volumes_size, node_processes=node_processes,
+            node_configs=node_configs, floating_ip_pool=floating_ip_pool,
+            security_groups=security_groups,
+            auto_security_group=auto_security_group,
+            availability_zone=availability_zone,
+            volumes_availability_zone=volumes_availability_zone,
+            volume_type=volume_type, image_id=image_id,
+            is_proxy_gateway=is_proxy_gateway,
+            volume_local_to_instance=volume_local_to_instance,
+            use_autoconfig=use_autoconfig, shares=shares,
+            is_public=is_public, is_protected=is_protected,
+            volume_mount_prefix=volume_mount_prefix
+        )
+
+        return self._patch('/node-group-templates/%s' % ng_template_id, data,
+                           'node_group_template')
+
+
+# NOTE(jfreud): keep this around for backwards compatibility
+NodeGroupTemplateManager = NodeGroupTemplateManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/plugins.py 
new/python-saharaclient-1.5.0/saharaclient/api/plugins.py
--- old/python-saharaclient-1.4.0/saharaclient/api/plugins.py   2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/plugins.py   2018-01-30 
00:35:49.000000000 +0100
@@ -28,7 +28,7 @@
         self.id = self.name
 
 
-class PluginManager(base.ResourceManager):
+class _PluginManager(base.ResourceManager):
     resource_class = Plugin
 
     def list(self, search_opts=None):
@@ -55,6 +55,8 @@
         """
         return self._patch("/plugins/%s" % plugin_name, values, 'plugin')
 
+
+class PluginManagerV1(_PluginManager):
     def convert_to_cluster_template(self, plugin_name, hadoop_version,
                                     template_name, filecontent):
         """Convert to cluster template
@@ -73,3 +75,17 @@
                                (plugin_name, hadoop_version))
         else:
             return base.get_json(resp)['cluster_template']
+
+
+class PluginManagerV2(_PluginManager):
+    def get_version_details(self, plugin_name, plugin_version):
+        """Get version details
+
+        Get the list of Services and Service Parameters for a specified
+        Plugin and Plugin Version.
+        """
+        return self._get('/plugins/%s/%s' % (plugin_name, plugin_version),
+                         'plugin')
+
+# NOTE(jfreud): keep this around for backwards compatibility
+PluginManager = PluginManagerV1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/v2/job_templates.py 
new/python-saharaclient-1.5.0/saharaclient/api/v2/job_templates.py
--- old/python-saharaclient-1.4.0/saharaclient/api/v2/job_templates.py  
1970-01-01 01:00:00.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/v2/job_templates.py  
2018-01-30 00:35:49.000000000 +0100
@@ -0,0 +1,70 @@
+# Copyright (c) 2018 OpenStack Foundation
+#
+# Licensed 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 saharaclient.api import base
+
+
+class JobTemplate(base.Resource):
+    resource_name = 'Job Template'
+
+
+class JobTemplatesManagerV2(base.ResourceManager):
+    resource_class = JobTemplate
+    NotUpdated = base.NotUpdated()
+
+    def create(self, name, type, mains=None, libs=None, description=None,
+               interface=None, is_public=None, is_protected=None):
+        """Create a Job Template."""
+        data = {
+            'name': name,
+            'type': type
+        }
+
+        self._copy_if_defined(data, description=description, mains=mains,
+                              libs=libs, interface=interface,
+                              is_public=is_public, is_protected=is_protected)
+
+        return self._create('/%s' % 'job-templates', data, 'job')
+
+    def list(self, search_opts=None, limit=None,
+             marker=None, sort_by=None, reverse=None):
+        """Get a list of Job Templates."""
+        query = base.get_query_string(search_opts, limit=limit, marker=marker,
+                                      sort_by=sort_by, reverse=reverse)
+
+        url = "/%s%s" % ('job-templates', query)
+        return self._page(url, 'job_templates', limit)
+
+    def get(self, job_id):
+        """Get information about a Job Template."""
+        return self._get('/%s/%s' % ('job-templates', job_id), 'job')
+
+    def get_configs(self, job_type):
+        """Get config hints for a specified Job Template type."""
+        return self._get('/%s/config-hints/%s' % ('job-templates', job_type))
+
+    def delete(self, job_id):
+        """Delete a Job Template."""
+        self._delete('/%s/%s' % ('job-templates', job_id))
+
+    def update(self, job_id, name=NotUpdated, description=NotUpdated,
+               is_public=NotUpdated, is_protected=NotUpdated):
+        """Update a Job Template."""
+
+        data = {}
+        self._copy_if_updated(data, name=name, description=description,
+                              is_public=is_public, is_protected=is_protected)
+
+        return self._patch('/%s/%s' % ('job-templates', job_id), data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/api/v2/jobs.py 
new/python-saharaclient-1.5.0/saharaclient/api/v2/jobs.py
--- old/python-saharaclient-1.4.0/saharaclient/api/v2/jobs.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/api/v2/jobs.py   2018-01-30 
00:35:49.000000000 +0100
@@ -0,0 +1,72 @@
+# Copyright (c) 2018 OpenStack Foundation
+#
+# Licensed 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 saharaclient.api import base
+
+
+class Job(base.Resource):
+    resource_name = 'Job'
+
+
+class JobsManagerV2(base.ResourceManager):
+    resource_class = Job
+    NotUpdated = base.NotUpdated()
+
+    def list(self, search_opts=None, marker=None, limit=None,
+             sort_by=None, reverse=None):
+        """Get a list of Jobs."""
+        query = base.get_query_string(search_opts, limit=limit, marker=marker,
+                                      sort_by=sort_by, reverse=reverse)
+        url = "/jobs%s" % query
+        return self._page(url, 'jobs', limit)
+
+    def get(self, obj_id):
+        """Get information about a Job."""
+        return self._get('/jobs/%s' % obj_id, 'job_execution')
+
+    def delete(self, obj_id):
+        """Delete a Job."""
+        self._delete('/jobs/%s' % obj_id)
+
+    def create(self, job_template_id, cluster_id, input_id=None,
+               output_id=None, configs=None, interface=None, is_public=None,
+               is_protected=None):
+        """Launch a Job."""
+
+        data = {
+            "cluster_id": cluster_id,
+            "job_template_id": job_template_id
+        }
+
+        self._copy_if_defined(data, input_id=input_id, output_id=output_id,
+                              job_configs=configs, interface=interface,
+                              is_public=is_public, is_protected=is_protected)
+
+        return self._create('/jobs', data, 'job_execution')
+
+    def refresh_status(self, obj_id):
+        """Refresh Job Status."""
+        return self._get(
+            '/jobs/%s?refresh_status=True' % obj_id,
+            'job_execution'
+        )
+
+    def update(self, obj_id, is_public=NotUpdated, is_protected=NotUpdated):
+        """Update a Job."""
+
+        data = {}
+        self._copy_if_updated(data, is_public=is_public,
+                              is_protected=is_protected)
+        return self._patch('/jobs/%s' % obj_id, data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/saharaclient/client.py 
new/python-saharaclient-1.5.0/saharaclient/client.py
--- old/python-saharaclient-1.4.0/saharaclient/client.py        2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/client.py        2018-01-30 
00:35:49.000000000 +0100
@@ -29,6 +29,7 @@
     version_map = {
         '1.0': 'saharaclient.api.client.Client',
         '1.1': 'saharaclient.api.client.Client',
+        '2': 'saharaclient.api.client.ClientV2',
     }
     try:
         client_path = version_map[str(version)]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/osc/v1/job_binaries.py 
new/python-saharaclient-1.5.0/saharaclient/osc/v1/job_binaries.py
--- old/python-saharaclient-1.4.0/saharaclient/osc/v1/job_binaries.py   
2017-11-17 00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/saharaclient/osc/v1/job_binaries.py   
2018-01-30 00:35:49.000000000 +0100
@@ -60,11 +60,17 @@
             metavar="<description>",
             help="Description of the job binary"
         )
-        parser.add_argument(
+        username = parser.add_mutually_exclusive_group()
+        username.add_argument(
             '--username',
             metavar='<username>',
             help='Username for accessing the job binary URL',
         )
+        username.add_argument(
+            '--access-key',
+            metavar='<accesskey>',
+            help='S3 access key for accessing the job binary URL',
+        )
         password = parser.add_mutually_exclusive_group()
         password.add_argument(
             '--password',
@@ -72,11 +78,28 @@
             help='Password for accessing the job binary URL',
         )
         password.add_argument(
+            '--secret-key',
+            metavar='<secretkey>',
+            help='S3 secret key for accessing the job binary URL',
+        )
+        password.add_argument(
             '--password-prompt',
             dest="password_prompt",
             action="store_true",
             help='Prompt interactively for password',
         )
+        password.add_argument(
+            '--secret-key-prompt',
+            dest="secret_key_prompt",
+            action="store_true",
+            help='Prompt interactively for S3 secret key',
+        )
+        parser.add_argument(
+            '--s3-endpoint',
+            metavar='<endpoint>',
+            help='S3 endpoint for accessing the job binary URL (ignored if '
+                 'binary not in S3',
+        )
         parser.add_argument(
             '--public',
             action='store_true',
@@ -122,20 +145,47 @@
                 parsed_args.password = osc_utils.get_password(
                     self.app.stdin, confirm=False)
 
+            if parsed_args.secret_key_prompt:
+                parsed_args.secret_key = osc_utils.get_password(
+                    self.app.stdin, confirm=False)
+
+            if not parsed_args.password:
+                parsed_args.password = parsed_args.secret_key
+
+            if not parsed_args.username:
+                parsed_args.username = parsed_args.access_key
+
             if parsed_args.password and not parsed_args.username:
                 raise exceptions.CommandError(
-                    'Username via --username should be provided with password')
+                    'Username via --username, or S3 access key via '
+                    '--access-key should be provided with password')
 
             if parsed_args.username and not parsed_args.password:
                 raise exceptions.CommandError(
-                    'Password should be provided via --password or entered '
-                    'interactively with --password-prompt')
+                    'Password should be provided via --password or '
+                    '--secret-key, or entered interactively with '
+                    '--password-prompt or --secret-key-prompt')
 
             if parsed_args.password and parsed_args.username:
-                extra = {
-                    'user': parsed_args.username,
-                    'password': parsed_args.password
-                }
+                if not parsed_args.url:
+                    raise exceptions.CommandError(
+                        'URL must be provided via --url')
+                if parsed_args.url.startswith('s3'):
+                    if not parsed_args.s3_endpoint:
+                        raise exceptions.CommandError(
+                            'S3 job binaries need an endpoint provided via '
+                            '--s3-endpoint')
+                    extra = {
+                        'accesskey': parsed_args.username,
+                        'secretkey': parsed_args.password,
+                        'endpoint': parsed_args.s3_endpoint,
+                    }
+
+                else:
+                    extra = {
+                        'user': parsed_args.username,
+                        'password': parsed_args.password
+                    }
             else:
                 extra = None
 
@@ -290,11 +340,17 @@
             metavar="<description>",
             help='Description of the job binary'
         )
-        parser.add_argument(
+        username = parser.add_mutually_exclusive_group()
+        username.add_argument(
             '--username',
             metavar='<username>',
             help='Username for accessing the job binary URL',
         )
+        username.add_argument(
+            '--access-key',
+            metavar='<accesskey>',
+            help='S3 access key for accessing the job binary URL',
+        )
         password = parser.add_mutually_exclusive_group()
         password.add_argument(
             '--password',
@@ -302,11 +358,28 @@
             help='Password for accessing the job binary URL',
         )
         password.add_argument(
+            '--secret-key',
+            metavar='<secretkey>',
+            help='S3 secret key for accessing the job binary URL',
+        )
+        password.add_argument(
             '--password-prompt',
             dest="password_prompt",
             action="store_true",
             help='Prompt interactively for password',
         )
+        password.add_argument(
+            '--secret-key-prompt',
+            dest="secret_key_prompt",
+            action="store_true",
+            help='Prompt interactively for S3 secret key',
+        )
+        parser.add_argument(
+            '--s3-endpoint',
+            metavar='<endpoint>',
+            help='S3 endpoint for accessing the job binary URL (ignored if '
+                 'binary not in S3',
+        )
         public = parser.add_mutually_exclusive_group()
         public.add_argument(
             '--public',
@@ -365,12 +438,21 @@
             if parsed_args.password_prompt:
                 parsed_args.password = osc_utils.get_password(
                     self.app.stdin, confirm=False)
+            if parsed_args.secret_key_prompt:
+                parsed_args.secret_key = osc_utils.get_password(
+                    self.app.stdin, confirm=False)
 
             extra = {}
             if parsed_args.password:
                 extra['password'] = parsed_args.password
             if parsed_args.username:
                 extra['user'] = parsed_args.username
+            if parsed_args.access_key:
+                extra['accesskey'] = parsed_args.access_key
+            if parsed_args.secret_key:
+                extra['secretkey'] = parsed_args.secret_key
+            if parsed_args.s3_endpoint:
+                extra['endpoint'] = parsed_args.s3_endpoint
             if not extra:
                 extra = None
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-saharaclient-1.4.0/saharaclient/tests/unit/osc/v1/test_job_binaries.py
 
new/python-saharaclient-1.5.0/saharaclient/tests/unit/osc/v1/test_job_binaries.py
--- 
old/python-saharaclient-1.4.0/saharaclient/tests/unit/osc/v1/test_job_binaries.py
   2017-11-17 00:06:53.000000000 +0100
+++ 
new/python-saharaclient-1.5.0/saharaclient/tests/unit/osc/v1/test_job_binaries.py
   2018-01-30 00:35:49.000000000 +0100
@@ -14,6 +14,8 @@
 # limitations under the License.
 
 import mock
+from osc_lib.tests import utils as osc_u
+import testtools
 
 from saharaclient.api import job_binaries as api_jb
 from saharaclient.osc.v1 import job_binaries as osc_jb
@@ -96,6 +98,14 @@
 
             self.jbi_mock.create.assert_called_once_with('job-binary', '')
 
+    def test_job_binary_create_mutual_exclusion(self):
+        arglist = ['job-binary', '--name', 'job-binary', '--access-key', 'ak',
+                   '--secret-key', 'sk', '--url', 's3://abc/def',
+                   '--password', 'pw']
+
+        with testtools.ExpectedException(osc_u.ParserException):
+            self.check_parser(self.cmd, arglist, mock.Mock())
+
 
 class TestListJobBinaries(TestJobBinaries):
     def setUp(self):
@@ -278,6 +288,14 @@
         self.jb_mock.update.assert_called_once_with(
             'jb_id', {})
 
+    def test_job_binary_update_mutual_exclusion(self):
+        arglist = ['job-binary', '--name', 'job-binary', '--access-key', 'ak',
+                   '--secret-key', 'sk', '--url', 's3://abc/def',
+                   '--password', 'pw']
+
+        with testtools.ExpectedException(osc_u.ParserException):
+            self.check_parser(self.cmd, arglist, mock.Mock())
+
 
 class TestDownloadJobBinary(TestJobBinaries):
     def setUp(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/setup.cfg 
new/python-saharaclient-1.5.0/setup.cfg
--- old/python-saharaclient-1.4.0/setup.cfg     2017-11-17 00:10:11.000000000 
+0100
+++ new/python-saharaclient-1.5.0/setup.cfg     2018-01-30 00:39:21.000000000 
+0100
@@ -6,7 +6,7 @@
 license = Apache License, Version 2.0
 author = OpenStack
 author-email = [email protected]
-home-page = https://github.com/openstack/python-saharaclient
+home-page = https://docs.openstack.org/python-saharaclient/latest/
 classifier = 
        Environment :: OpenStack
        Intended Audience :: Information Technology
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/test-requirements.txt 
new/python-saharaclient-1.5.0/test-requirements.txt
--- old/python-saharaclient-1.4.0/test-requirements.txt 2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/test-requirements.txt 2018-01-30 
00:35:49.000000000 +0100
@@ -6,10 +6,10 @@
 
 coverage!=4.4,>=4.0 # Apache-2.0
 mock>=2.0.0 # BSD
-openstackdocstheme>=1.17.0 # Apache-2.0
-oslotest>=1.10.0 # Apache-2.0
+openstackdocstheme>=1.18.1 # Apache-2.0
+oslotest>=3.2.0 # Apache-2.0
 os-testr>=1.0.0 # Apache-2.0
 reno>=2.5.0 # Apache-2.0
 requests-mock>=1.1.0 # Apache-2.0
-sphinx>=1.6.2 # BSD
+sphinx!=1.6.6,>=1.6.2 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/tools/tox_install.sh 
new/python-saharaclient-1.5.0/tools/tox_install.sh
--- old/python-saharaclient-1.4.0/tools/tox_install.sh  2017-11-17 
00:06:53.000000000 +0100
+++ new/python-saharaclient-1.5.0/tools/tox_install.sh  1970-01-01 
01:00:00.000000000 +0100
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-
-# Client constraint file contains this client version pin that is in conflict
-# with installing the client from source. We should remove the version pin in
-# the constraints file before applying it for from-source installation.
-
-CONSTRAINTS_FILE="$1"
-shift 1
-
-set -e
-
-# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
-# published to logs.openstack.org for easy debugging.
-localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
-
-if [[ "$CONSTRAINTS_FILE" != http* ]]; then
-    CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
-fi
-# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
-curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
-
-pip install -c"$localfile" openstack-requirements
-
-# This is the main purpose of the script: Allow local installation of
-# the current repo. It is listed in constraints file and thus any
-# install will be constrained and we need to unconstrain it.
-edit-constraints "$localfile" -- "$CLIENT_NAME"
-
-pip install -c"$localfile" -U "$@"
-exit $?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-saharaclient-1.4.0/tox.ini 
new/python-saharaclient-1.5.0/tox.ini
--- old/python-saharaclient-1.4.0/tox.ini       2017-11-17 00:06:53.000000000 
+0100
+++ new/python-saharaclient-1.5.0/tox.ini       2018-01-30 00:35:49.000000000 
+0100
@@ -5,13 +5,12 @@
 
 [testenv]
 usedevelop = True
-install_command = {toxinidir}/tools/tox_install.sh 
{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
 {opts} {packages}
+install_command = pip install {opts} {packages}
 setenv =
     VIRTUAL_ENV={envdir}
-    BRANCH_NAME=master
-    CLIENT_NAME=python-saharaclient
     DISCOVER_DIRECTORY=saharaclient/tests/unit
 deps =
+    
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test-requirements.txt
 commands = find . -type f -name "*.pyc" -delete
@@ -44,6 +43,7 @@
 
 [testenv:doc8]
 deps =
+    
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test-requirements.txt
     doc8


Reply via email to