Hello community,
here is the log from the commit of package python-ironicclient for
openSUSE:Factory checked in at 2018-03-19 23:34:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ironicclient (Old)
and /work/SRC/openSUSE:Factory/.python-ironicclient.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ironicclient"
Mon Mar 19 23:34:40 2018 rev:12 rq:583301 version:2.2.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ironicclient/python-ironicclient.changes
2018-01-31 19:52:04.552963268 +0100
+++
/work/SRC/openSUSE:Factory/.python-ironicclient.new/python-ironicclient.changes
2018-03-19 23:34:42.441298773 +0100
@@ -1,0 +2,19 @@
+Fri Feb 23 13:03:45 UTC 2018 - [email protected]
+
+- Switch to stable/queens spec template
+
+-------------------------------------------------------------------
+Mon Feb 12 09:56:58 UTC 2018 - [email protected]
+
+- update to version 2.2.0 (bsc#1078607)
+ - Use StrictVersion to compare versions
+ - Facilitate latest Rest API use
+ - Allow API user to define list of versions
+ - Ignore .eggs from git
+ - Traits support
+ - Add release note for fix to bug 1745099
+ - Can not set portgroup mode as a number
+ - Accept port and portgroup as volume connector types
+ - Updated from global requirements
+
+-------------------------------------------------------------------
Old:
----
python-ironicclient-2.1.0.tar.gz
New:
----
python-ironicclient-2.2.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-ironicclient.spec ++++++
--- /var/tmp/diff_new_pack.8yVrkH/_old 2018-03-19 23:34:43.133273810 +0100
+++ /var/tmp/diff_new_pack.8yVrkH/_new 2018-03-19 23:34:43.137273666 +0100
@@ -16,50 +16,78 @@
#
-%global sname python-ironicclient
Name: python-ironicclient
-Version: 2.1.0
+Version: 2.2.0
Release: 0
Summary: Python API and CLI for OpenStack Ironic
License: Apache-2.0
Group: Development/Languages/Python
-Url: https://launchpad.net/%{sname}
-Source0:
https://files.pythonhosted.org/packages/source/p/%{sname}/%{sname}-%{version}.tar.gz
+Url: https://launchpad.net/python-ironicclient
+Source0:
https://files.pythonhosted.org/packages/source/p/python-ironicclient/python-ironicclient-2.2.0.tar.gz
BuildRequires: openstack-macros
-BuildRequires: python-Babel >= 2.3.4
-BuildRequires: python-PrettyTable >= 0.7.1
-BuildRequires: python-PyYAML >= 3.10
-BuildRequires: python-appdirs >= 1.3.0
BuildRequires: python-devel
-BuildRequires: python-dogpile.cache >= 0.6.2
-BuildRequires: python-fixtures >= 3.0.0
-BuildRequires: python-jsonschema >= 2.6.0
-BuildRequires: python-mock >= 2.0.0
-BuildRequires: python-openstackclient >= 3.12.0
-BuildRequires: python-os-testr >= 1.0.0
-BuildRequires: python-osc-lib >= 1.7.0
-BuildRequires: python-oslo.i18n >= 3.15.3
-BuildRequires: python-oslo.utils >= 3.31.0
-BuildRequires: python-oslotest >= 1.10.0
-BuildRequires: python-pbr >= 2.0.0
-BuildRequires: python-python-subunit >= 1.0.0
-BuildRequires: python-requests >= 2.14.2
-BuildRequires: python-requests-mock >= 1.1.0
-BuildRequires: python-testtools >= 2.2.0
+BuildRequires: python2-Babel >= 2.3.4
+BuildRequires: python2-PrettyTable >= 0.7.1
+BuildRequires: python2-PyYAML >= 3.10
+BuildRequires: python2-appdirs >= 1.3.0
+BuildRequires: python2-dogpile.cache >= 0.6.2
+BuildRequires: python2-fixtures >= 3.0.0
+BuildRequires: python2-jsonschema >= 2.6.0
+BuildRequires: python2-mock >= 2.0.0
+BuildRequires: python2-openstackclient >= 3.12.0
+BuildRequires: python2-os-testr >= 1.0.0
+BuildRequires: python2-osc-lib >= 1.8.0
+BuildRequires: python2-oslo.i18n >= 3.15.3
+BuildRequires: python2-oslo.utils >= 3.33.0
+BuildRequires: python2-oslotest >= 3.2.0
+BuildRequires: python2-pbr >= 2.0.0
+BuildRequires: python2-python-subunit >= 1.0.0
+BuildRequires: python2-requests >= 2.14.2
+BuildRequires: python2-requests-mock >= 1.1.0
+BuildRequires: python2-testtools >= 2.2.0
+BuildRequires: python3-Babel >= 2.3.4
+BuildRequires: python3-PrettyTable >= 0.7.1
+BuildRequires: python3-PyYAML >= 3.10
+BuildRequires: python3-appdirs >= 1.3.0
+BuildRequires: python3-devel
+BuildRequires: python3-dogpile.cache >= 0.6.2
+BuildRequires: python3-fixtures >= 3.0.0
+BuildRequires: python3-jsonschema >= 2.6.0
+BuildRequires: python3-mock >= 2.0.0
+BuildRequires: python3-openstackclient >= 3.12.0
+BuildRequires: python3-os-testr >= 1.0.0
+BuildRequires: python3-osc-lib >= 1.8.0
+BuildRequires: python3-oslo.i18n >= 3.15.3
+BuildRequires: python3-oslo.utils >= 3.33.0
+BuildRequires: python3-oslotest >= 3.2.0
+BuildRequires: python3-pbr >= 2.0.0
+BuildRequires: python3-python-subunit >= 1.0.0
+BuildRequires: python3-requests >= 2.14.2
+BuildRequires: python3-requests-mock >= 1.1.0
+BuildRequires: python3-testtools >= 2.2.0
Requires: python-PrettyTable >= 0.7.1
Requires: python-PyYAML >= 3.10
Requires: python-appdirs >= 1.3.0
Requires: python-dogpile.cache >= 0.6.2
Requires: python-jsonschema >= 2.6.0
-Requires: python-keystoneauth1 >= 3.2.0
+Requires: python-keystoneauth1 >= 3.3.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.utils >= 3.31.0
+Requires: python-oslo.utils >= 3.33.0
Requires: python-pbr >= 2.0.0
Requires: python-requests >= 2.14.2
Requires: python-six >= 1.10.0
BuildArch: noarch
+%if 0%{?suse_version}
+Requires(post): update-alternatives
+Requires(postun): update-alternatives
+%else
+# on RDO, update-alternatives is in chkconfig
+Requires(post): chkconfig
+Requires(postun): chkconfig
+%endif
+%python_subpackages
%description
OpenStack Bare Metal Provisioning API Client Library
@@ -67,49 +95,58 @@
This is a client for the OpenStack Ironic API. It provides a Python API (the
ironicclient module) and a command-line interface (ironic).
-%package doc
+%package -n python-ironicclient-doc
Summary: Documentation for OpenStack Ironic API Client
Group: Documentation/HTML
BuildRequires: python-Sphinx
-BuildRequires: python-openstackdocstheme >= 1.17.0
+BuildRequires: python-openstackdocstheme >= 1.18.1
BuildRequires: python-reno >= 2.5.0
-%description doc
+%description -n python-ironicclient-doc
This is a client for the OpenStack Ironic API (Bare Metal. There's a
Python API (the ironicclient module), and a command-line script (ironic).
Each implements 100% of the OpenStack Ironic API.
This package contains auto-generated documentation.
%prep
-%autosetup -n %{sname}-%{version}
+%autosetup -p1 -n python-ironicclient-2.2.0
%py_req_cleanup
sed -i 's/^warning-is-error.*/warning-is-error = 0/g' setup.cfg
%build
-%{py2_build}
+%{python_build}
%{__python2} setup.py build_sphinx
# remove the sphinx-build leftovers
rm -rf doc/build/html/.{doctrees,buildinfo}
%install
-%{py2_install}
+%{python_install}
# bash completion
install -p -D -m 644 tools/ironic.bash_completion
%{buildroot}%{_sysconfdir}/bash_completion.d/ironic.bash_completion
+%python_clone -a %{buildroot}%{_bindir}/ironic
+%python_clone -a
%{buildroot}%{_sysconfdir}/bash_completion.d/ironic.bash_completion
+
+%post
+%{python_install_alternative ironic
%{_sysconfdir}/bash_completion.d/ironic.bash_completion}
+
+%postun
+%python_uninstall_alternative ironic
%check
+%{python_expand rm -rf .testrepository
ostestr
+}
-%files
+%files %{python_files}
%license LICENSE
%doc README.rst
-%{_bindir}/ironic
-%{python2_sitelib}/ironicclient
-%{python2_sitelib}/*.egg-info
-%{_bindir}/ironic
-%{_sysconfdir}/bash_completion.d/ironic.bash_completion
+%{python_sitelib}/ironicclient
+%{python_sitelib}/*.egg-info
+%python_alternative %{_bindir}/ironic
+%python_alternative %{_sysconfdir}/bash_completion.d/ironic.bash_completion
-%files doc
+%files -n python-ironicclient-doc
%license LICENSE
%doc doc/build/html
++++++ _service ++++++
--- /var/tmp/diff_new_pack.8yVrkH/_old 2018-03-19 23:34:43.181272079 +0100
+++ /var/tmp/diff_new_pack.8yVrkH/_new 2018-03-19 23:34:43.185271935 +0100
@@ -1,8 +1,8 @@
<services>
<service mode="disabled" name="renderspec">
- <param
name="input-template">https://git.openstack.org/cgit/openstack/rpm-packaging/plain/openstack/python-ironicclient/python-ironicclient.spec.j2?h=master</param>
+ <param
name="input-template">https://git.openstack.org/cgit/openstack/rpm-packaging/plain/openstack/python-ironicclient/python-ironicclient.spec.j2?h=stable/queens</param>
<param name="output-name">python-ironicclient.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-ironicclient</param>
</service>
++++++ python-ironicclient-2.1.0.tar.gz -> python-ironicclient-2.2.0.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/AUTHORS
new/python-ironicclient-2.2.0/AUTHORS
--- old/python-ironicclient-2.1.0/AUTHORS 2018-01-08 14:52:17.000000000
+0100
+++ new/python-ironicclient-2.2.0/AUTHORS 2018-01-26 01:44:32.000000000
+0100
@@ -47,6 +47,7 @@
Julia Kreger <[email protected]>
KATO Tomoyuki <[email protected]>
KaiFeng Wang <[email protected]>
+Kaifeng Wang <[email protected]>
Kan <[email protected]>
Kevin McDonald <[email protected]>
Kui Shi <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/ChangeLog
new/python-ironicclient-2.2.0/ChangeLog
--- old/python-ironicclient-2.1.0/ChangeLog 2018-01-08 14:52:16.000000000
+0100
+++ new/python-ironicclient-2.2.0/ChangeLog 2018-01-26 01:44:32.000000000
+0100
@@ -1,6 +1,22 @@
CHANGES
=======
+2.2.0
+-----
+
+* Add release note for fix to bug 1745099
+* Traits support
+* Can not set portgroup mode as a number
+* Updated from global requirements
+* Allow API user to define list of versions
+* Facilitate latest Rest API use
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Use StrictVersion to compare versions
+* Accept port and portgroup as volume connector types
+* Ignore .eggs from git
+
2.1.0
-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/PKG-INFO
new/python-ironicclient-2.2.0/PKG-INFO
--- old/python-ironicclient-2.1.0/PKG-INFO 2018-01-08 14:52:18.000000000
+0100
+++ new/python-ironicclient-2.2.0/PKG-INFO 2018-01-26 01:44:33.000000000
+0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: python-ironicclient
-Version: 2.1.0
+Version: 2.2.0
Summary: OpenStack Bare Metal Provisioning API Client Library
Home-page: https://docs.openstack.org/python-ironicclient/latest/
Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/ironicclient/client.py
new/python-ironicclient-2.2.0/ironicclient/client.py
--- old/python-ironicclient-2.1.0/ironicclient/client.py 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/client.py 2018-01-26
01:40:03.000000000 +0100
@@ -58,7 +58,8 @@
:param cert_file: path to cert file, deprecated in favour of os_cert
:param os_key: path to key file
:param key_file: path to key file, deprecated in favour of os_key
- :param os_ironic_api_version: ironic API version to use
+ :param os_ironic_api_version: ironic API version to use or a list of
+ available API versions to attempt to negotiate.
:param max_retries: Maximum number of retries in case of conflict error
:param retry_interval: Amount of time (in seconds) between retries in case
of conflict error
@@ -66,6 +67,11 @@
:param ignored_kwargs: all the other params that are passed. Left for
backwards compatibility. They are ignored.
"""
+ # TODO(TheJulia): At some point, we should consider possibly noting
+ # the "latest" flag for os_ironic_api_version to cause the client to
+ # auto-negotiate to the greatest available version, however we do not
+ # have the ability yet for a caller to cap the version, and will hold
+ # off doing so until then.
os_service_type = os_service_type or 'baremetal'
os_endpoint_type = os_endpoint_type or 'publicURL'
project_id = (os_project_id or os_tenant_id)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/common/base.py
new/python-ironicclient-2.2.0/ironicclient/common/base.py
--- old/python-ironicclient-2.1.0/ironicclient/common/base.py 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/common/base.py 2018-01-26
01:40:27.000000000 +0100
@@ -170,25 +170,34 @@
return object_list
- def _list(self, url, response_key=None, obj_class=None, body=None):
+ def __list(self, url, response_key=None, body=None):
resp, body = self.api.json_request('GET', url)
+ data = self._format_body_data(body, response_key)
+ return data
+ def _list(self, url, response_key=None, obj_class=None, body=None):
if obj_class is None:
obj_class = self.resource_class
- data = self._format_body_data(body, response_key)
+ data = self.__list(url, response_key=response_key, body=body)
return [obj_class(self, res, loaded=True) for res in data if res]
+ def _list_primitives(self, url, response_key=None):
+ return self.__list(url, response_key=response_key)
+
def _update(self, resource_id, patch, method='PATCH'):
"""Update a resource.
:param resource_id: Resource identifier.
- :param patch: New version of a given resource.
+ :param patch: New version of a given resource, a dictionary or None.
:param method: Name of the method for the request.
"""
url = self._path(resource_id)
- resp, body = self.api.json_request(method, url, body=patch)
+ kwargs = {}
+ if patch is not None:
+ kwargs['body'] = patch
+ resp, body = self.api.json_request(method, url, **kwargs)
# PATCH/PUT requests may not return a body
if body:
return self.resource_class(self, body)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/common/http.py
new/python-ironicclient-2.2.0/ironicclient/common/http.py
--- old/python-ironicclient-2.1.0/ironicclient/common/http.py 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/common/http.py 2018-01-26
01:40:27.000000000 +0100
@@ -44,7 +44,8 @@
#
http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html
# noqa
# for full details.
DEFAULT_VER = '1.9'
-
+LAST_KNOWN_API_VERSION = 37
+LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
LOG = logging.getLogger(__name__)
USER_AGENT = 'python-ironicclient'
@@ -98,6 +99,18 @@
param conn: A connection object
param resp: The response object from http request
"""
+ def _query_server(conn):
+ if (self.os_ironic_api_version and
+ not isinstance(self.os_ironic_api_version, list) and
+ self.os_ironic_api_version != 'latest'):
+ base_version = ("/v%s" %
+ str(self.os_ironic_api_version).split('.')[0])
+ else:
+ base_version = API_VERSION
+ return self._make_simple_request(conn, 'GET', base_version)
+
+ if not resp:
+ resp = _query_server(conn)
if self.api_version_select_state not in API_VERSION_SELECTED_STATES:
raise RuntimeError(
_('Error: self.api_version_select_state should be one of the '
@@ -110,22 +123,31 @@
# the supported version range
if not max_ver:
LOG.debug('No version header in response, requesting from server')
- if self.os_ironic_api_version:
- base_version = ("/v%s" %
- str(self.os_ironic_api_version).split('.')[0])
- else:
- base_version = API_VERSION
- resp = self._make_simple_request(conn, 'GET', base_version)
+ resp = _query_server(conn)
min_ver, max_ver = self._parse_version_headers(resp)
+ # Reset the maximum version that we permit
+ if StrictVersion(max_ver) > StrictVersion(LATEST_VERSION):
+ LOG.debug("Remote API version %(max_ver)s is greater than the "
+ "version supported by ironicclient. Maximum available "
+ "version is %(client_ver)s",
+ {'max_ver': max_ver,
+ 'client_ver': LATEST_VERSION})
+ max_ver = LATEST_VERSION
+
# If the user requested an explicit version or we have negotiated a
# version and still failing then error now. The server could
# support the version requested but the requested operation may not
# be supported by the requested version.
- if self.api_version_select_state == 'user':
+ # TODO(TheJulia): We should break this method into several parts,
+ # such as a sanity check/error method.
+ if (self.api_version_select_state == 'user' and
+ self.os_ironic_api_version != 'latest' and
+ not isinstance(self.os_ironic_api_version, list)):
raise exc.UnsupportedVersion(textwrap.fill(
_("Requested API version %(req)s is not supported by the "
- "server or the requested operation is not supported by the "
- "requested version. Supported version range is %(min)s to "
+ "server, client, or the requested operation is not "
+ "supported by the requested version."
+ "Supported version range is %(min)s to "
"%(max)s")
% {'req': self.os_ironic_api_version,
'min': min_ver, 'max': max_ver}))
@@ -137,9 +159,46 @@
% {'req': self.os_ironic_api_version,
'min': min_ver, 'max': max_ver}))
- negotiated_ver = str(min(StrictVersion(self.os_ironic_api_version),
- StrictVersion(max_ver)))
- if negotiated_ver < min_ver:
+ if isinstance(self.os_ironic_api_version, six.string_types):
+ if self.os_ironic_api_version == 'latest':
+ negotiated_ver = max_ver
+ else:
+ negotiated_ver = str(
+ min(StrictVersion(self.os_ironic_api_version),
+ StrictVersion(max_ver)))
+
+ elif isinstance(self.os_ironic_api_version, list):
+ if 'latest' in self.os_ironic_api_version:
+ raise ValueError(textwrap.fill(
+ _("The 'latest' API version can not be requested "
+ "in a list of versions. Please explicitly request "
+ "'latest' or request only versios between "
+ "%(min)s to %(max)s")
+ % {'min': min_ver, 'max': max_ver}))
+
+ versions = []
+ for version in self.os_ironic_api_version:
+ if min_ver <= StrictVersion(version) <= max_ver:
+ versions.append(StrictVersion(version))
+ if versions:
+ negotiated_ver = str(max(versions))
+ else:
+ raise exc.UnsupportedVersion(textwrap.fill(
+ _("Requested API version specified and the requested "
+ "operation was not supported by the client's "
+ "requested API version %(req)s. Supported "
+ "version range is: %(min)s to %(max)s")
+ % {'req': self.os_ironic_api_version,
+ 'min': min_ver, 'max': max_ver}))
+
+ else:
+ raise ValueError(textwrap.fill(
+ _("Requested API version %(req)s type is unsupported. "
+ "Valid types are Strings such as '1.1', 'latest' "
+ "or a list of string values representing API versions.")
+ % {'req': self.os_ironic_api_version}))
+
+ if StrictVersion(negotiated_ver) < StrictVersion(min_ver):
negotiated_ver = min_ver
# server handles microversions, but doesn't support
# the requested version, so try a negotiated version
@@ -310,6 +369,14 @@
Wrapper around request.Session.request to handle tasks such
as setting headers and error handling.
"""
+ # NOTE(TheJulia): self.os_ironic_api_version is reset in
+ # the self.negotiate_version() call if negotiation occurs.
+ if (self.os_ironic_api_version and
+ self.api_version_select_state == 'user' and
+ (self.os_ironic_api_version == 'latest' or
+ isinstance(self.os_ironic_api_version, list))):
+ self.negotiate_version(self.session, None)
+
# Copy the kwargs so we can reuse the original in case of redirects
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
kwargs['headers'].setdefault('User-Agent', USER_AGENT)
@@ -517,6 +584,15 @@
@with_retries
def _http_request(self, url, method, **kwargs):
+
+ # NOTE(TheJulia): self.os_ironic_api_version is reset in
+ # the self.negotiate_version() call if negotiation occurs.
+ if (self.os_ironic_api_version and
+ self.api_version_select_state == 'user' and
+ (self.os_ironic_api_version == 'latest' or
+ isinstance(self.os_ironic_api_version, list))):
+ self.negotiate_version(self.session, None)
+
kwargs.setdefault('user_agent', USER_AGENT)
kwargs.setdefault('auth', self.auth)
if isinstance(self.endpoint_override, six.string_types):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/ironicclient/osc/plugin.py
new/python-ironicclient-2.2.0/ironicclient/osc/plugin.py
--- old/python-ironicclient-2.1.0/ironicclient/osc/plugin.py 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/osc/plugin.py 2018-01-26
01:40:03.000000000 +0100
@@ -19,6 +19,7 @@
import argparse
import logging
+from ironicclient.common import http
from osc_lib import utils
LOG = logging.getLogger(__name__)
@@ -26,8 +27,13 @@
CLIENT_CLASS = 'ironicclient.v1.client.Client'
API_VERSION_OPTION = 'os_baremetal_api_version'
API_NAME = 'baremetal'
-LAST_KNOWN_API_VERSION = 35
-LATEST_VERSION = "1.{}".format(LAST_KNOWN_API_VERSION)
+# NOTE(TheJulia) Latest known version tracking has been moved
+# to the ironicclient/common/http.py file as the OSC committment
+# is latest known, and we should only store it in one location.
+LAST_KNOWN_API_VERSION = http.LAST_KNOWN_API_VERSION
+LATEST_VERSION = http.LATEST_VERSION
+
+
API_VERSIONS = {
'1.%d' % i: CLIENT_CLASS
for i in range(1, LAST_KNOWN_API_VERSION + 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/osc/v1/baremetal_node.py
new/python-ironicclient-2.2.0/ironicclient/osc/v1/baremetal_node.py
--- old/python-ironicclient-2.1.0/ironicclient/osc/v1/baremetal_node.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/osc/v1/baremetal_node.py
2018-01-26 01:40:27.000000000 +0100
@@ -1574,3 +1574,116 @@
baremetal_client = self.app.client_manager.baremetal
baremetal_client.node.inject_nmi(parsed_args.node)
+
+
+class ListTraitsBaremetalNode(command.Lister):
+ """List a node's traits."""
+
+ log = logging.getLogger(__name__ + ".ListTraitsBaremetalNode")
+
+ def get_parser(self, prog_name):
+ parser = super(ListTraitsBaremetalNode, self).get_parser(prog_name)
+
+ parser.add_argument(
+ 'node',
+ metavar='<node>',
+ help=_("Name or UUID of the node"))
+
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action(%s)", parsed_args)
+
+ labels = res_fields.TRAIT_RESOURCE.labels
+
+ baremetal_client = self.app.client_manager.baremetal
+ traits = baremetal_client.node.get_traits(parsed_args.node)
+
+ return (labels, [[trait] for trait in traits])
+
+
+class AddTraitBaremetalNode(command.Command):
+ """Add traits to a node."""
+
+ log = logging.getLogger(__name__ + ".AddTraitBaremetalNode")
+
+ def get_parser(self, prog_name):
+ parser = super(AddTraitBaremetalNode, self).get_parser(prog_name)
+
+ parser.add_argument(
+ 'node',
+ metavar='<node>',
+ help=_("Name or UUID of the node"))
+ parser.add_argument(
+ 'traits',
+ nargs='+',
+ metavar='<trait>',
+ help=_("Trait(s) to add"))
+
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action(%s)", parsed_args)
+
+ baremetal_client = self.app.client_manager.baremetal
+
+ failures = []
+ for trait in parsed_args.traits:
+ try:
+ baremetal_client.node.add_trait(parsed_args.node, trait)
+ print(_('Added trait %s') % trait)
+ except exc.ClientException as e:
+ failures.append(_("Failed to add trait %(trait)s: %(error)s")
+ % {'trait': trait, 'error': e})
+
+ if failures:
+ raise exc.ClientException("\n".join(failures))
+
+
+class RemoveTraitBaremetalNode(command.Command):
+ """Remove trait(s) from a node."""
+
+ log = logging.getLogger(__name__ + ".RemoveTraitBaremetalNode")
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveTraitBaremetalNode, self).get_parser(prog_name)
+
+ parser.add_argument(
+ 'node',
+ metavar='<node>',
+ help=_("Name or UUID of the node"))
+ all_or_trait = parser.add_mutually_exclusive_group(required=True)
+ all_or_trait.add_argument(
+ '--all',
+ dest='remove_all',
+ action='store_true',
+ help=_("Remove all traits"))
+ all_or_trait.add_argument(
+ 'traits',
+ metavar='<trait>',
+ nargs='*',
+ default=[],
+ help=_("Trait(s) to remove"))
+
+ return parser
+
+ def take_action(self, parsed_args):
+ self.log.debug("take_action(%s)", parsed_args)
+
+ baremetal_client = self.app.client_manager.baremetal
+
+ failures = []
+ if parsed_args.remove_all:
+ baremetal_client.node.remove_all_traits(parsed_args.node)
+ else:
+ for trait in parsed_args.traits:
+ try:
+ baremetal_client.node.remove_trait(parsed_args.node, trait)
+ print(_('Removed trait %s') % trait)
+ except exc.ClientException as e:
+ failures.append(_("Failed to remove trait %(trait)s: "
+ "%(error)s")
+ % {'trait': trait, 'error': e})
+
+ if failures:
+ raise exc.ClientException("\n".join(failures))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/osc/v1/baremetal_portgroup.py
new/python-ironicclient-2.2.0/ironicclient/osc/v1/baremetal_portgroup.py
--- old/python-ironicclient-2.1.0/ironicclient/osc/v1/baremetal_portgroup.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/osc/v1/baremetal_portgroup.py
2018-01-26 01:40:27.000000000 +0100
@@ -379,7 +379,7 @@
'add', ["standalone_ports_supported=False"]))
if parsed_args.mode:
properties.extend(utils.args_array_to_patch(
- 'add', ["mode=%s" % parsed_args.mode]))
+ 'add', ["mode=\"%s\"" % parsed_args.mode]))
if parsed_args.extra:
properties.extend(utils.args_array_to_patch(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/osc/v1/baremetal_volume_connector.py
new/python-ironicclient-2.2.0/ironicclient/osc/v1/baremetal_volume_connector.py
---
old/python-ironicclient-2.1.0/ironicclient/osc/v1/baremetal_volume_connector.py
2018-01-08 14:49:17.000000000 +0100
+++
new/python-ironicclient-2.2.0/ironicclient/osc/v1/baremetal_volume_connector.py
2018-01-26 01:40:27.000000000 +0100
@@ -45,9 +45,9 @@
dest='type',
metavar="<type>",
required=True,
- choices=('iqn', 'ip', 'mac', 'wwnn', 'wwpn'),
+ choices=('iqn', 'ip', 'mac', 'wwnn', 'wwpn', 'port', 'portgroup'),
help=_("Type of the volume connector. Can be 'iqn', 'ip', 'mac', "
- "'wwnn', 'wwpn'."))
+ "'wwnn', 'wwpn', 'port', 'portgroup'."))
parser.add_argument(
'--connector-id',
dest='connector_id',
@@ -279,9 +279,9 @@
'--type',
dest='type',
metavar="<type>",
- choices=('iqn', 'ip', 'mac', 'wwnn', 'wwpn'),
+ choices=('iqn', 'ip', 'mac', 'wwnn', 'wwpn', 'port', 'portgroup'),
help=_("Type of the volume connector. Can be 'iqn', 'ip', 'mac', "
- "'wwnn', 'wwpn'."))
+ "'wwnn', 'wwpn', 'port', 'portgroup'."))
parser.add_argument(
'--connector-id',
dest='connector_id',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/common/test_http.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/common/test_http.py
--- old/python-ironicclient-2.1.0/ironicclient/tests/unit/common/test_http.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/tests/unit/common/test_http.py
2018-01-26 01:40:03.000000000 +0100
@@ -183,6 +183,141 @@
self.assertEqual(1, mock_pvh.call_count)
self.assertEqual(0, mock_save_data.call_count)
+ @mock.patch.object(filecache, 'save_data', autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers',
+ autospec=True)
+ def test_negotiate_version_strict_version_comparison(self, mock_pvh,
+ mock_save_data):
+ # Test version comparison with StrictVersion
+ max_ver = '1.10'
+ mock_pvh.return_value = ('1.2', max_ver)
+ mock_conn = mock.MagicMock()
+ self.test_object.os_ironic_api_version = '1.10'
+ result = self.test_object.negotiate_version(mock_conn, self.response)
+ self.assertEqual(max_ver, result)
+ self.assertEqual(1, mock_pvh.call_count)
+ host, port = http.get_server(self.test_object.endpoint)
+ mock_save_data.assert_called_once_with(host=host, port=port,
+ data=max_ver)
+
+ @mock.patch.object(filecache, 'save_data', autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_make_simple_request',
+ autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers',
+ autospec=True)
+ def test_negotiate_version_server_user_latest(
+ self, mock_pvh, mock_msr, mock_save_data):
+ # have to retry with simple get
+ mock_pvh.side_effect = iter([(None, None), ('1.1', '1.99')])
+ mock_conn = mock.MagicMock()
+ self.test_object.api_version_select_state = 'user'
+ self.test_object.os_ironic_api_version = 'latest'
+ result = self.test_object.negotiate_version(mock_conn, None)
+ self.assertEqual(http.LATEST_VERSION, result)
+ self.assertEqual('negotiated',
+ self.test_object.api_version_select_state)
+ self.assertEqual(http.LATEST_VERSION,
+ self.test_object.os_ironic_api_version)
+
+ self.assertTrue(mock_msr.called)
+ self.assertEqual(2, mock_pvh.call_count)
+ self.assertEqual(1, mock_save_data.call_count)
+
+ @mock.patch.object(filecache, 'save_data', autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_make_simple_request',
+ autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers',
+ autospec=True)
+ def test_negotiate_version_server_user_list(
+ self, mock_pvh, mock_msr, mock_save_data):
+ # have to retry with simple get
+ mock_pvh.side_effect = iter([(None, None), ('1.1', '1.26')])
+ mock_conn = mock.MagicMock()
+ self.test_object.api_version_select_state = 'user'
+ self.test_object.os_ironic_api_version = ['1.1', '1.6', '1.25',
+ '1.26', '1.26.1', '1.27',
+ '1.30']
+ result = self.test_object.negotiate_version(mock_conn, self.response)
+ self.assertEqual('1.26', result)
+ self.assertEqual('negotiated',
+ self.test_object.api_version_select_state)
+ self.assertEqual('1.26',
+ self.test_object.os_ironic_api_version)
+
+ self.assertTrue(mock_msr.called)
+ self.assertEqual(2, mock_pvh.call_count)
+ self.assertEqual(1, mock_save_data.call_count)
+
+ @mock.patch.object(filecache, 'save_data', autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_make_simple_request',
+ autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers',
+ autospec=True)
+ def test_negotiate_version_server_user_list_fails_nomatch(
+ self, mock_pvh, mock_msr, mock_save_data):
+ # have to retry with simple get
+ mock_pvh.side_effect = iter([(None, None), ('1.2', '1.26')])
+ mock_conn = mock.MagicMock()
+ self.test_object.api_version_select_state = 'user'
+ self.test_object.os_ironic_api_version = ['1.39', '1.1']
+ self.assertRaises(
+ exc.UnsupportedVersion,
+ self.test_object.negotiate_version,
+ mock_conn, self.response)
+ self.assertEqual('user',
+ self.test_object.api_version_select_state)
+ self.assertEqual(['1.39', '1.1'],
+ self.test_object.os_ironic_api_version)
+ self.assertEqual(2, mock_pvh.call_count)
+ self.assertEqual(0, mock_save_data.call_count)
+
+ @mock.patch.object(filecache, 'save_data', autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_make_simple_request',
+ autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers',
+ autospec=True)
+ def test_negotiate_version_server_user_list_single_value(
+ self, mock_pvh, mock_msr, mock_save_data):
+ # have to retry with simple get
+ mock_pvh.side_effect = iter([(None, None), ('1.1', '1.26')])
+ mock_conn = mock.MagicMock()
+ self.test_object.api_version_select_state = 'user'
+ # NOTE(TheJulia): Lets test this value explicitly because the
+ # minor number is actually the same.
+ self.test_object.os_ironic_api_version = ['1.01']
+ result = self.test_object.negotiate_version(mock_conn, None)
+ self.assertEqual('1.1', result)
+ self.assertEqual('negotiated',
+ self.test_object.api_version_select_state)
+ self.assertEqual('1.1',
+ self.test_object.os_ironic_api_version)
+ self.assertTrue(mock_msr.called)
+ self.assertEqual(2, mock_pvh.call_count)
+ self.assertEqual(1, mock_save_data.call_count)
+
+ @mock.patch.object(filecache, 'save_data', autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_make_simple_request',
+ autospec=True)
+ @mock.patch.object(http.VersionNegotiationMixin, '_parse_version_headers',
+ autospec=True)
+ def test_negotiate_version_server_user_list_fails_latest(
+ self, mock_pvh, mock_msr, mock_save_data):
+ # have to retry with simple get
+ mock_pvh.side_effect = iter([(None, None), ('1.1', '1.2')])
+ mock_conn = mock.MagicMock()
+ self.test_object.api_version_select_state = 'user'
+ self.test_object.os_ironic_api_version = ['1.01', 'latest']
+ self.assertRaises(
+ ValueError,
+ self.test_object.negotiate_version,
+ mock_conn, self.response)
+ self.assertEqual('user',
+ self.test_object.api_version_select_state)
+ self.assertEqual(['1.01', 'latest'],
+ self.test_object.os_ironic_api_version)
+ self.assertEqual(2, mock_pvh.call_count)
+ self.assertEqual(0, mock_save_data.call_count)
+
def test_get_server(self):
host = 'ironic-host'
port = '6385'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/osc/v1/fakes.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/osc/v1/fakes.py
--- old/python-ironicclient-2.1.0/ironicclient/tests/unit/osc/v1/fakes.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/tests/unit/osc/v1/fakes.py
2018-01-26 01:40:27.000000000 +0100
@@ -137,6 +137,7 @@
}
VIFS = {'vifs': [{'id': 'aaa-aa'}]}
+TRAITS = ['CUSTOM_FOO', 'CUSTOM_BAR']
baremetal_volume_connector_uuid = 'vvv-cccccc-vvvv'
baremetal_volume_connector_type = 'iqn'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
---
old/python-ironicclient-2.1.0/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
2018-01-08 14:49:17.000000000 +0100
+++
new/python-ironicclient-2.2.0/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
2018-01-26 01:40:27.000000000 +0100
@@ -591,7 +591,7 @@
'Current RAID configuration', 'Reservation',
'Resource Class',
'Target Power State', 'Target Provision State',
- 'Target RAID configuration',
+ 'Target RAID configuration', 'Traits',
'Updated At', 'Inspection Finished At',
'Inspection Started At', 'UUID', 'Name',
'Boot Interface', 'Console Interface',
@@ -627,6 +627,7 @@
'',
'',
'',
+ '',
baremetal_fakes.baremetal_uuid,
baremetal_fakes.baremetal_name,
'',
@@ -2663,3 +2664,186 @@
self.baremetal_mock.node.inject_nmi.assert_called_once_with(
'node_uuid')
+
+
+class TestListTraits(TestBaremetal):
+ def setUp(self):
+ super(TestListTraits, self).setUp()
+
+ self.baremetal_mock.node.get_traits.return_value = (
+ baremetal_fakes.TRAITS)
+
+ # Get the command object to test
+ self.cmd = baremetal_node.ListTraitsBaremetalNode(self.app, None)
+
+ def test_baremetal_list_traits(self):
+ arglist = ['node_uuid']
+ verifylist = [('node', 'node_uuid')]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.get_traits.assert_called_once_with(
+ 'node_uuid')
+
+
+class TestAddTrait(TestBaremetal):
+ def setUp(self):
+ super(TestAddTrait, self).setUp()
+
+ # Get the command object to test
+ self.cmd = baremetal_node.AddTraitBaremetalNode(self.app, None)
+
+ def test_baremetal_add_trait(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO']
+ verifylist = [('node', 'node_uuid'), ('traits', ['CUSTOM_FOO'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.add_trait.assert_called_once_with(
+ 'node_uuid', 'CUSTOM_FOO')
+
+ def test_baremetal_add_traits_multiple(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.add_trait.call_args_list)
+
+ def test_baremetal_add_traits_multiple_with_failure(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ self.baremetal_mock.node.add_trait.side_effect = [
+ '', exc.ClientException]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exc.ClientException,
+ self.cmd.take_action,
+ parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.add_trait.call_args_list)
+
+ def test_baremetal_add_traits_no_traits(self):
+ arglist = ['node_uuid']
+ verifylist = [('node', 'node_uuid')]
+
+ self.assertRaises(oscutils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+
+class TestRemoveTrait(TestBaremetal):
+ def setUp(self):
+ super(TestRemoveTrait, self).setUp()
+
+ # Get the command object to test
+ self.cmd = baremetal_node.RemoveTraitBaremetalNode(self.app, None)
+
+ def test_baremetal_remove_trait(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO']
+ verifylist = [('node', 'node_uuid'), ('traits', ['CUSTOM_FOO'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.remove_trait.assert_called_once_with(
+ 'node_uuid', 'CUSTOM_FOO')
+
+ def test_baremetal_remove_trait_multiple(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.remove_trait.call_args_list)
+
+ def test_baremetal_remove_trait_multiple_with_failure(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', 'CUSTOM_BAR']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO', 'CUSTOM_BAR'])]
+
+ self.baremetal_mock.node.remove_trait.side_effect = [
+ '', exc.ClientException]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exc.ClientException,
+ self.cmd.take_action,
+ parsed_args)
+
+ expected_calls = [
+ mock.call('node_uuid', 'CUSTOM_FOO'),
+ mock.call('node_uuid', 'CUSTOM_BAR'),
+ ]
+ self.assertEqual(expected_calls,
+ self.baremetal_mock.node.remove_trait.call_args_list)
+
+ def test_baremetal_remove_trait_all(self):
+ arglist = ['node_uuid', '--all']
+ verifylist = [('node', 'node_uuid'), ('remove_all', True)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.baremetal_mock.node.remove_all_traits.assert_called_once_with(
+ 'node_uuid')
+
+ def test_baremetal_remove_trait_traits_and_all(self):
+ arglist = ['node_uuid', 'CUSTOM_FOO', '--all']
+ verifylist = [('node', 'node_uuid'),
+ ('traits', ['CUSTOM_FOO']),
+ ('remove_all', True)]
+
+ self.assertRaises(oscutils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ self.baremetal_mock.node.remove_all_traits.assert_not_called()
+ self.baremetal_mock.node.remove_trait.assert_not_called()
+
+ def test_baremetal_remove_traits_no_traits_no_all(self):
+ arglist = ['node_uuid']
+ verifylist = [('node', 'node_uuid')]
+
+ self.assertRaises(oscutils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ self.baremetal_mock.node.remove_all_traits.assert_not_called()
+ self.baremetal_mock.node.remove_trait.assert_not_called()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py
---
old/python-ironicclient-2.1.0/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py
2018-01-08 14:49:17.000000000 +0100
+++
new/python-ironicclient-2.2.0/ironicclient/tests/unit/osc/v1/test_baremetal_portgroup.py
2018-01-26 01:40:27.000000000 +0100
@@ -546,6 +546,23 @@
[{'path': '/mode', 'value': new_portgroup_mode,
'op': 'add'}])
+ def test_baremetal_portgroup_set_mode_int(self):
+ new_portgroup_mode = '4'
+ arglist = [
+ baremetal_fakes.baremetal_portgroup_uuid,
+ '--mode', new_portgroup_mode]
+ verifylist = [
+ ('portgroup', baremetal_fakes.baremetal_portgroup_uuid),
+ ('mode', new_portgroup_mode)]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+ self.baremetal_mock.portgroup.update.assert_called_once_with(
+ baremetal_fakes.baremetal_portgroup_uuid,
+ [{'path': '/mode', 'value': new_portgroup_mode,
+ 'op': 'add'}])
+
def test_baremetal_portgroup_set_node_uuid(self):
new_node_uuid = 'nnnnnn-uuuuuuuu'
arglist = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/test_client.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/test_client.py
--- old/python-ironicclient-2.1.0/ironicclient/tests/unit/test_client.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/tests/unit/test_client.py
2018-01-26 01:40:03.000000000 +0100
@@ -58,7 +58,13 @@
interface=kwargs.get('os_endpoint_type') or 'publicURL',
region_name=kwargs.get('os_region_name'))
if 'os_ironic_api_version' in kwargs:
+ # NOTE(TheJulia): This does not test the negotiation logic
+ # as a request must be triggered in order for any verison
+ # negotiation actions to occur.
self.assertEqual(0, mock_retrieve_data.call_count)
+ self.assertEqual(kwargs['os_ironic_api_version'],
+ client.current_api_version)
+ self.assertFalse(client.is_api_version_negotiated)
else:
mock_retrieve_data.assert_called_once_with(
host='localhost',
@@ -132,6 +138,17 @@
}
self._test_get_client(**kwargs)
+ def test_get_client_with_api_version_list(self):
+ kwargs = {
+ 'os_project_name': 'PROJECT_NAME',
+ 'os_username': 'USERNAME',
+ 'os_password': 'PASSWORD',
+ 'os_auth_url': 'http://localhost:35357/v2.0',
+ 'os_auth_token': '',
+ 'os_ironic_api_version': ['1.1', '1.99'],
+ }
+ self._test_get_client(**kwargs)
+
def test_get_client_with_api_version_numeric(self):
kwargs = {
'os_project_name': 'PROJECT_NAME',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/v1/test_client.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/v1/test_client.py
--- old/python-ironicclient-2.1.0/ironicclient/tests/unit/v1/test_client.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/tests/unit/v1/test_client.py
2018-01-26 01:40:03.000000000 +0100
@@ -49,6 +49,16 @@
os_ironic_api_version=os_ironic_api_version,
api_version_select_state='default')
+ def test_client_user_api_version_latest_with_downgrade(self,
+ http_client_mock):
+ endpoint = 'http://ironic:6385'
+ token = 'safe_token'
+ os_ironic_api_version = 'latest'
+
+ self.assertRaises(ValueError, client.Client, endpoint,
+ token=token, allow_api_version_downgrade=True,
+ os_ironic_api_version=os_ironic_api_version)
+
@mock.patch.object(filecache, 'retrieve_data', autospec=True)
def test_client_cache_api_version(self, cache_mock, http_client_mock):
endpoint = 'http://ironic:6385'
@@ -93,3 +103,19 @@
self.assertIsInstance(cl.port, client.port.PortManager)
self.assertIsInstance(cl.driver, client.driver.DriverManager)
self.assertIsInstance(cl.chassis, client.chassis.ChassisManager)
+
+ def test_negotiate_api_version(self, http_client_mock):
+ endpoint = 'http://ironic:6385'
+ token = 'safe_token'
+ os_ironic_api_version = 'latest'
+ cl = client.Client(endpoint, token=token,
+ os_ironic_api_version=os_ironic_api_version)
+
+ cl.negotiate_api_version()
+ http_client_mock.assert_called_once_with(
+ endpoint, api_version_select_state='user',
+ os_ironic_api_version='latest', token=token)
+ # TODO(TheJulia): We should verify that negotiate_version
+ # is being called in the client and returns a version,
+ # although mocking might need to be restrutured to
+ # properly achieve that.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/v1/test_node.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/v1/test_node.py
--- old/python-ironicclient-2.1.0/ironicclient/tests/unit/v1/test_node.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/tests/unit/v1/test_node.py
2018-01-26 01:40:27.000000000 +0100
@@ -103,6 +103,7 @@
"async": "true"}}
VIFS = {'vifs': [{'id': 'aaa-aaa'}]}
+TRAITS = {'traits': ['CUSTOM_FOO', 'CUSTOM_BAR']}
CREATE_NODE = copy.deepcopy(NODE1)
del CREATE_NODE['uuid']
@@ -448,6 +449,32 @@
{},
VIFS,
),
+ },
+ '/v1/nodes/%s/traits' % NODE1['uuid']:
+ {
+ 'GET': (
+ {},
+ TRAITS,
+ ),
+ 'PUT': (
+ {},
+ None,
+ ),
+ 'DELETE': (
+ {},
+ None,
+ ),
+ },
+ '/v1/nodes/%s/traits/CUSTOM_FOO' % NODE1['uuid']:
+ {
+ 'PUT': (
+ {},
+ None,
+ ),
+ 'DELETE': (
+ {},
+ None,
+ ),
}
}
@@ -1641,3 +1668,49 @@
self.assertEqual(4, mock_get.call_count)
mock_sleep.assert_called_with(node._DEFAULT_POLL_INTERVAL)
self.assertEqual(3, mock_sleep.call_count)
+
+ def test_node_get_traits(self):
+ traits = self.mgr.get_traits(NODE1['uuid'])
+ expect = [
+ ('GET', '/v1/nodes/%s/traits' % NODE1['uuid'], {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertEqual(TRAITS['traits'], traits)
+
+ def test_node_add_trait(self):
+ trait = 'CUSTOM_FOO'
+ resp = self.mgr.add_trait(NODE1['uuid'], trait)
+ expect = [
+ ('PUT', '/v1/nodes/%s/traits/%s' % (NODE1['uuid'], trait),
+ {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
+
+ def test_node_set_traits(self):
+ traits = ['CUSTOM_FOO', 'CUSTOM_BAR']
+ resp = self.mgr.set_traits(NODE1['uuid'], traits)
+ expect = [
+ ('PUT', '/v1/nodes/%s/traits' % NODE1['uuid'],
+ {}, {'traits': traits}),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
+
+ def test_node_remove_all_traits(self):
+ resp = self.mgr.remove_all_traits(NODE1['uuid'])
+ expect = [
+ ('DELETE', '/v1/nodes/%s/traits' % NODE1['uuid'], {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
+
+ def test_node_remove_trait(self):
+ trait = 'CUSTOM_FOO'
+ resp = self.mgr.remove_trait(NODE1['uuid'], trait)
+ expect = [
+ ('DELETE', '/v1/nodes/%s/traits/%s' % (NODE1['uuid'], trait),
+ {}, None),
+ ]
+ self.assertEqual(expect, self.api.calls)
+ self.assertIsNone(resp)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/tests/unit/v1/test_node_shell.py
new/python-ironicclient-2.2.0/ironicclient/tests/unit/v1/test_node_shell.py
--- old/python-ironicclient-2.1.0/ironicclient/tests/unit/v1/test_node_shell.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/tests/unit/v1/test_node_shell.py
2018-01-26 01:40:27.000000000 +0100
@@ -65,6 +65,7 @@
'resource_class',
'target_power_state',
'target_provision_state',
+ 'traits',
'updated_at',
'inspection_finished_at',
'inspection_started_at',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/ironicclient/v1/client.py
new/python-ironicclient-2.2.0/ironicclient/v1/client.py
--- old/python-ironicclient-2.1.0/ironicclient/v1/client.py 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/v1/client.py 2018-01-26
01:40:03.000000000 +0100
@@ -41,7 +41,17 @@
"""Initialize a new client for the Ironic v1 API."""
allow_downgrade = kwargs.pop('allow_api_version_downgrade', False)
if kwargs.get('os_ironic_api_version'):
+ # TODO(TheJulia): We should sanity check os_ironic_api_version
+ # against our maximum suported version, so the client fails
+ # immediately upon an unsupported version being provided.
+ # This logic should also likely live in common/http.py
if allow_downgrade:
+ if kwargs['os_ironic_api_version'] == 'latest':
+ raise ValueError(
+ "Invalid configuration defined. "
+ "The os_ironic_api_versioncan not be set "
+ "to 'latest' while allow_api_version_downgrade "
+ "is set.")
# NOTE(dtantsur): here we allow the HTTP client to negotiate a
# lower version if the requested is too high
kwargs['api_version_select_state'] = "default"
@@ -76,3 +86,26 @@
self.http_client)
self.driver = driver.DriverManager(self.http_client)
self.portgroup = portgroup.PortgroupManager(self.http_client)
+
+ @property
+ def current_api_version(self):
+ """Return the current API version in use.
+
+ This returns the version of the REST API that the API client
+ is presently set to request. This value may change as a result
+ of API version negotiation.
+ """
+ return self.http_client.os_ironic_api_version
+
+ @property
+ def is_api_version_negotiated(self):
+ """Returns True if microversion negotiation has occured."""
+ return self.http_client.api_version_select_state == 'negotiated'
+
+ def negotiate_api_version(self):
+ """Triggers negotiation with the remote API endpoint.
+
+ :returns: the negotiated API version.
+ """
+ return self.http_client.negotiate_version(
+ self.http_client.session, None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/ironicclient/v1/node.py
new/python-ironicclient-2.2.0/ironicclient/v1/node.py
--- old/python-ironicclient-2.1.0/ironicclient/v1/node.py 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/v1/node.py 2018-01-26
01:40:27.000000000 +0100
@@ -553,6 +553,53 @@
path = "%s/vendor_passthru/methods" % node_ident
return self._get_as_dict(path)
+ def get_traits(self, node_ident):
+ """Get traits for a node.
+
+ :param node_ident: node UUID or name.
+ """
+ path = "%s/traits" % node_ident
+ return self._list_primitives(self._path(path), 'traits')
+
+ def add_trait(self, node_ident, trait):
+ """Add a trait to a node.
+
+ :param node_ident: node UUID or name.
+ :param trait: trait to add to the node.
+ """
+ path = "%s/traits/%s" % (node_ident, trait)
+ return self.update(path, None, http_method='PUT')
+
+ def set_traits(self, node_ident, traits):
+ """Set traits for a node.
+
+ Removes any existing traits and adds the traits passed in to this
+ method.
+
+ :param node_ident: node UUID or name.
+ :param traits: list of traits to add to the node.
+ """
+ path = "%s/traits" % node_ident
+ body = {'traits': traits}
+ return self.update(path, body, http_method='PUT')
+
+ def remove_trait(self, node_ident, trait):
+ """Remove a trait from a node.
+
+ :param node_ident: node UUID or name.
+ :param trait: trait to remove from the node.
+ """
+ path = "%s/traits/%s" % (node_ident, trait)
+ return self.delete(path)
+
+ def remove_all_traits(self, node_ident):
+ """Remove all traits from a node.
+
+ :param node_ident: node UUID or name.
+ """
+ path = "%s/traits" % node_ident
+ return self.delete(path)
+
def wait_for_provision_state(self, node_ident, expected_state,
timeout=0,
poll_interval=_DEFAULT_POLL_INTERVAL,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/ironicclient/v1/resource_fields.py
new/python-ironicclient-2.2.0/ironicclient/v1/resource_fields.py
--- old/python-ironicclient-2.1.0/ironicclient/v1/resource_fields.py
2018-01-08 14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/ironicclient/v1/resource_fields.py
2018-01-26 01:40:27.000000000 +0100
@@ -87,6 +87,7 @@
'target_power_state': 'Target Power State',
'target_provision_state': 'Target Provision State',
'target_raid_config': 'Target RAID configuration',
+ 'traits': 'Traits',
'type': 'Type',
'updated_at': 'Updated At',
'uuid': 'UUID',
@@ -210,6 +211,7 @@
'target_power_state',
'target_provision_state',
'target_raid_config',
+ 'traits',
'updated_at',
'inspection_finished_at',
'inspection_started_at',
@@ -239,6 +241,7 @@
'properties',
'raid_config',
'target_raid_config',
+ 'traits',
])
NODE_RESOURCE = Resource(
['uuid',
@@ -319,6 +322,10 @@
['id'],
)
+TRAIT_RESOURCE = Resource(
+ ['traits'],
+)
+
# Drivers
DRIVER_DETAILED_RESOURCE = Resource(
['name',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/python_ironicclient.egg-info/PKG-INFO
new/python-ironicclient-2.2.0/python_ironicclient.egg-info/PKG-INFO
--- old/python-ironicclient-2.1.0/python_ironicclient.egg-info/PKG-INFO
2018-01-08 14:52:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/python_ironicclient.egg-info/PKG-INFO
2018-01-26 01:44:32.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: python-ironicclient
-Version: 2.1.0
+Version: 2.2.0
Summary: OpenStack Bare Metal Provisioning API Client Library
Home-page: https://docs.openstack.org/python-ironicclient/latest/
Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/python_ironicclient.egg-info/SOURCES.txt
new/python-ironicclient-2.2.0/python_ironicclient.egg-info/SOURCES.txt
--- old/python-ironicclient-2.1.0/python_ironicclient.egg-info/SOURCES.txt
2018-01-08 14:52:18.000000000 +0100
+++ new/python-ironicclient-2.2.0/python_ironicclient.egg-info/SOURCES.txt
2018-01-26 01:44:33.000000000 +0100
@@ -173,11 +173,14 @@
releasenotes/notes/add-volume-target-api-e062303f4b3b40ef.yaml
releasenotes/notes/add-volume-target-cli-e062303f4b3b40f0.yaml
releasenotes/notes/add_api_versions-a59e5b6899833c33.yaml
+releasenotes/notes/allow-api-user-to-use-latest-6b80e9f584eaaa4e.yaml
+releasenotes/notes/allow-client-to-request-list-of-versions-88f019cad76e6464.yaml
releasenotes/notes/bug-1524745-adds-node-create-args-a7ace744515e5943.yaml
releasenotes/notes/bug-1524745-extend-driver-list-and-driver-show-800d96393aa17342.yaml
releasenotes/notes/bug-1524745-update-baremetal-node-set-c1ac57de0d481efe.yaml
releasenotes/notes/bug-1712935-allow-os_baremetal_api_version_env_var_to_be_latest-28c8eed24f389673.yaml
releasenotes/notes/bug-1724974-add-wanboot-to-supported-boot-devices.yaml
+releasenotes/notes/bug-1745099-allow-integer-portgroup-mode-6be4d3b35e216486.yaml
releasenotes/notes/continue-del-next-node-8827e67e1c41a0a5.yaml
releasenotes/notes/deprecate-ironic-cli-686b7a238ddf3e25.yaml
releasenotes/notes/display-empty-string-for-chassis-uuid-if-it-is-empty-a5471c3aa740a27d.yaml
@@ -242,6 +245,7 @@
releasenotes/notes/soft-reboot-poweroff-e33d078a05db3894.yaml
releasenotes/notes/start-using-reno-ccd220efa2c7022a.yaml
releasenotes/notes/switch-requests-8304d4465a8976b1.yaml
+releasenotes/notes/traits-support-8864f6816abecdb2.yaml
releasenotes/source/conf.py
releasenotes/source/index.rst
releasenotes/source/mitaka.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/python_ironicclient.egg-info/entry_points.txt
new/python-ironicclient-2.2.0/python_ironicclient.egg-info/entry_points.txt
--- old/python-ironicclient-2.1.0/python_ironicclient.egg-info/entry_points.txt
2018-01-08 14:52:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/python_ironicclient.egg-info/entry_points.txt
2018-01-26 01:44:32.000000000 +0100
@@ -16,6 +16,7 @@
baremetal_driver_raid_property_list =
ironicclient.osc.v1.baremetal_driver:ListBaremetalDriverRaidProperty
baremetal_driver_show =
ironicclient.osc.v1.baremetal_driver:ShowBaremetalDriver
baremetal_node_abort = ironicclient.osc.v1.baremetal_node:AbortBaremetalNode
+baremetal_node_add_trait =
ironicclient.osc.v1.baremetal_node:AddTraitBaremetalNode
baremetal_node_adopt = ironicclient.osc.v1.baremetal_node:AdoptBaremetalNode
baremetal_node_boot_device_set =
ironicclient.osc.v1.baremetal_node:BootdeviceSetBaremetalNode
baremetal_node_boot_device_show =
ironicclient.osc.v1.baremetal_node:BootdeviceShowBaremetalNode
@@ -39,8 +40,10 @@
baremetal_node_provide =
ironicclient.osc.v1.baremetal_node:ProvideBaremetalNode
baremetal_node_reboot = ironicclient.osc.v1.baremetal_node:RebootBaremetalNode
baremetal_node_rebuild =
ironicclient.osc.v1.baremetal_node:RebuildBaremetalNode
+baremetal_node_remove_trait =
ironicclient.osc.v1.baremetal_node:RemoveTraitBaremetalNode
baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode
baremetal_node_show = ironicclient.osc.v1.baremetal_node:ShowBaremetalNode
+baremetal_node_trait_list =
ironicclient.osc.v1.baremetal_node:ListTraitsBaremetalNode
baremetal_node_undeploy =
ironicclient.osc.v1.baremetal_node:UndeployBaremetalNode
baremetal_node_unset = ironicclient.osc.v1.baremetal_node:UnsetBaremetalNode
baremetal_node_validate =
ironicclient.osc.v1.baremetal_node:ValidateBaremetalNode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/python_ironicclient.egg-info/pbr.json
new/python-ironicclient-2.2.0/python_ironicclient.egg-info/pbr.json
--- old/python-ironicclient-2.1.0/python_ironicclient.egg-info/pbr.json
2018-01-08 14:52:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/python_ironicclient.egg-info/pbr.json
2018-01-26 01:44:32.000000000 +0100
@@ -1 +1 @@
-{"git_version": "5a427ee", "is_release": true}
\ No newline at end of file
+{"git_version": "683b7c6", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/releasenotes/notes/allow-api-user-to-use-latest-6b80e9f584eaaa4e.yaml
new/python-ironicclient-2.2.0/releasenotes/notes/allow-api-user-to-use-latest-6b80e9f584eaaa4e.yaml
---
old/python-ironicclient-2.1.0/releasenotes/notes/allow-api-user-to-use-latest-6b80e9f584eaaa4e.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/python-ironicclient-2.2.0/releasenotes/notes/allow-api-user-to-use-latest-6b80e9f584eaaa4e.yaml
2018-01-26 01:40:03.000000000 +0100
@@ -0,0 +1,26 @@
+---
+features:
+ - |
+ Allows a python API user to pass ``latest`` to the client creation request
+ for the ``os_ironic_api_version`` parameter. The version utilized for REST
+ API requests will, as a result, be the highest available version
+ understood by both the ironicclient library and the server.
+ - |
+ Adds base client properties to provide insight to a python API user of
+ what the current REST API version that will be utilized, and if API
+ version negotiation has occured.
+ These new properties are ``client.current_api_version`` and
+ ``client.is_api_version_negotiated`` respectively.
+ - |
+ Adds additional base client method to allow a python API user to trigger
+ version negotiation and return the negotiated version. This new method is
+ ``client.negotiate_api_version()``.
+other:
+ - |
+ The maximum supported version supported for negotiation is now defined
+ in the ``common/http.py`` file. Any new feature added to the API client
+ library must increment this version.
+ - |
+ The maximum known version supported by the ``OpenStackClient`` plugin is
+ now defined by the maximum supported version for API negotiation as
+ defined in the ``common/http.py`` file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/releasenotes/notes/allow-client-to-request-list-of-versions-88f019cad76e6464.yaml
new/python-ironicclient-2.2.0/releasenotes/notes/allow-client-to-request-list-of-versions-88f019cad76e6464.yaml
---
old/python-ironicclient-2.1.0/releasenotes/notes/allow-client-to-request-list-of-versions-88f019cad76e6464.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/python-ironicclient-2.2.0/releasenotes/notes/allow-client-to-request-list-of-versions-88f019cad76e6464.yaml
2018-01-26 01:40:03.000000000 +0100
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ The ``os_ironic_api_version`` parameter now accepts a list of REST
+ API micro-versions to attempt to negotiate with the remote server.
+ The highest available microversion in the list will be negotiated
+ for the remaining lifetime of the client session.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/releasenotes/notes/bug-1745099-allow-integer-portgroup-mode-6be4d3b35e216486.yaml
new/python-ironicclient-2.2.0/releasenotes/notes/bug-1745099-allow-integer-portgroup-mode-6be4d3b35e216486.yaml
---
old/python-ironicclient-2.1.0/releasenotes/notes/bug-1745099-allow-integer-portgroup-mode-6be4d3b35e216486.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/python-ironicclient-2.2.0/releasenotes/notes/bug-1745099-allow-integer-portgroup-mode-6be4d3b35e216486.yaml
2018-01-26 01:40:27.000000000 +0100
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ Fixes `bug 1745099
+ <https://bugs.launchpad.net/python-ironicclient/+bug/1745099>`_,
+ which prevented a port group's mode from being set to an integer value
+ via the ``openstack baremetal port group set`` command.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-ironicclient-2.1.0/releasenotes/notes/traits-support-8864f6816abecdb2.yaml
new/python-ironicclient-2.2.0/releasenotes/notes/traits-support-8864f6816abecdb2.yaml
---
old/python-ironicclient-2.1.0/releasenotes/notes/traits-support-8864f6816abecdb2.yaml
1970-01-01 01:00:00.000000000 +0100
+++
new/python-ironicclient-2.2.0/releasenotes/notes/traits-support-8864f6816abecdb2.yaml
2018-01-26 01:40:27.000000000 +0100
@@ -0,0 +1,20 @@
+---
+features:
+ - |
+ Adds support for reading and modifying traits for a node, including adding
+ traits to the detailed output of a node. This is available starting
+ with Bare Metal API version 1.37.
+
+ The new commands are:
+
+ * ``openstack baremetal node trait list <node>``
+ * ``openstack baremetal node add trait <node> <trait> [...]``
+ * ``openstack baremetal node remove trait <node> [<trait> [...]] [--all]``
+
+ It also adds the following methods to the Python SDK:
+
+ * ``NodeManager.get_traits``
+ * ``NodeManager.add_trait``
+ * ``NodeManager.set_traits``
+ * ``NodeManager.remove_trait``
+ * ``NodeManager.remove_all_traits``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/setup.cfg
new/python-ironicclient-2.2.0/setup.cfg
--- old/python-ironicclient-2.1.0/setup.cfg 2018-01-08 14:52:18.000000000
+0100
+++ new/python-ironicclient-2.2.0/setup.cfg 2018-01-26 01:44:33.000000000
+0100
@@ -40,6 +40,7 @@
baremetal_driver_raid_property_list =
ironicclient.osc.v1.baremetal_driver:ListBaremetalDriverRaidProperty
baremetal_driver_show =
ironicclient.osc.v1.baremetal_driver:ShowBaremetalDriver
baremetal_node_abort =
ironicclient.osc.v1.baremetal_node:AbortBaremetalNode
+ baremetal_node_add_trait =
ironicclient.osc.v1.baremetal_node:AddTraitBaremetalNode
baremetal_node_adopt =
ironicclient.osc.v1.baremetal_node:AdoptBaremetalNode
baremetal_node_boot_device_set =
ironicclient.osc.v1.baremetal_node:BootdeviceSetBaremetalNode
baremetal_node_boot_device_show =
ironicclient.osc.v1.baremetal_node:BootdeviceShowBaremetalNode
@@ -62,8 +63,10 @@
baremetal_node_provide =
ironicclient.osc.v1.baremetal_node:ProvideBaremetalNode
baremetal_node_reboot =
ironicclient.osc.v1.baremetal_node:RebootBaremetalNode
baremetal_node_rebuild =
ironicclient.osc.v1.baremetal_node:RebuildBaremetalNode
+ baremetal_node_remove_trait =
ironicclient.osc.v1.baremetal_node:RemoveTraitBaremetalNode
baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode
baremetal_node_show =
ironicclient.osc.v1.baremetal_node:ShowBaremetalNode
+ baremetal_node_trait_list =
ironicclient.osc.v1.baremetal_node:ListTraitsBaremetalNode
baremetal_node_undeploy =
ironicclient.osc.v1.baremetal_node:UndeployBaremetalNode
baremetal_node_unset =
ironicclient.osc.v1.baremetal_node:UnsetBaremetalNode
baremetal_node_validate =
ironicclient.osc.v1.baremetal_node:ValidateBaremetalNode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-ironicclient-2.1.0/test-requirements.txt
new/python-ironicclient-2.2.0/test-requirements.txt
--- old/python-ironicclient-2.1.0/test-requirements.txt 2018-01-08
14:49:17.000000000 +0100
+++ new/python-ironicclient-2.2.0/test-requirements.txt 2018-01-26
01:40:03.000000000 +0100
@@ -8,10 +8,10 @@
requests-mock>=1.1.0 # Apache-2.0
mock>=2.0.0 # BSD
Babel!=2.4.0,>=2.3.4 # BSD
-openstackdocstheme>=1.17.0 # Apache-2.0
+openstackdocstheme>=1.18.1 # Apache-2.0
reno>=2.5.0 # Apache-2.0
-oslotest>=1.10.0 # Apache-2.0
-sphinx>=1.6.2 # BSD
+oslotest>=3.2.0 # Apache-2.0
+sphinx!=1.6.6,>=1.6.2 # BSD
testtools>=2.2.0 # MIT
tempest>=17.1.0 # Apache-2.0
os-testr>=1.0.0 # Apache-2.0