diff --git a/doc/source/user/proxies/network.rst b/doc/source/user/proxies/network.rst index 5a2ea9a95..a9af0b922 100644 --- a/doc/source/user/proxies/network.rst +++ b/doc/source/user/proxies/network.rst @@ -38,6 +38,7 @@ Port Operations .. autoclass:: openstack.network.v2._proxy.Proxy .. automethod:: openstack.network.v2._proxy.Proxy.create_port + .. automethod:: openstack.network.v2._proxy.Proxy.create_ports .. automethod:: openstack.network.v2._proxy.Proxy.update_port .. automethod:: openstack.network.v2._proxy.Proxy.delete_port .. automethod:: openstack.network.v2._proxy.Proxy.get_port diff --git a/openstack/network/v2/_proxy.py b/openstack/network/v2/_proxy.py index 7b3229b89..835945cf1 100644 --- a/openstack/network/v2/_proxy.py +++ b/openstack/network/v2/_proxy.py @@ -1687,6 +1687,18 @@ class Proxy(proxy.Proxy): """ return self._create(_port.Port, **attrs) + def create_ports(self, data): + """Create ports from the list of attributes + + :param list data: List of dicts of attributes which will be used to + create a :class:`~openstack.network.v2.port.Port`, + comprised of the properties on the Port class. + + :returns: A generator of port objects + :rtype: :class:`~openstack.network.v2.port.Port` + """ + return self._bulk_create(_port.Port, data) + def delete_port(self, port, ignore_missing=True): """Delete a port diff --git a/openstack/proxy.py b/openstack/proxy.py index 724a816d6..2ea253038 100644 --- a/openstack/proxy.py +++ b/openstack/proxy.py @@ -416,6 +416,26 @@ class Proxy(adapter.Adapter): res = resource_type.new(connection=conn, **attrs) return res.create(self, base_path=base_path) + def _bulk_create(self, resource_type, data, base_path=None): + """Create a resource from attributes + + :param resource_type: The type of resource to create. + :type resource_type: :class:`~openstack.resource.Resource` + :param list data: List of attributes dicts to be passed onto the + :meth:`~openstack.resource.Resource.create` + method to be created. These should correspond + to either :class:`~openstack.resource.Body` + or :class:`~openstack.resource.Header` + values on this resource. + :param str base_path: Base part of the URI for creating resources, if + different from + :data:`~openstack.resource.Resource.base_path`. + + :returns: A generator of Resource objects. + :rtype: :class:`~openstack.resource.Resource` + """ + return resource_type.bulk_create(self, data, base_path=base_path) + @_check_resource(strict=False) def _get(self, resource_type, value=None, requires_id=True, base_path=None, **attrs): diff --git a/openstack/tests/unit/network/v2/test_proxy.py b/openstack/tests/unit/network/v2/test_proxy.py index 24961042b..f1037bf5e 100644 --- a/openstack/tests/unit/network/v2/test_proxy.py +++ b/openstack/tests/unit/network/v2/test_proxy.py @@ -465,6 +465,14 @@ class TestNetworkProxy(test_proxy_base.TestProxyBase): def test_port_update(self): self.verify_update(self.proxy.update_port, port.Port) + @mock.patch('openstack.network.v2._proxy.Proxy._bulk_create') + def test_ports_create(self, bc): + data = mock.sentinel + + self.proxy.create_ports(data) + + bc.assert_called_once_with(port.Port, data) + def test_qos_bandwidth_limit_rule_create_attrs(self): self.verify_create( self.proxy.create_qos_bandwidth_limit_rule, diff --git a/openstack/tests/unit/test_proxy.py b/openstack/tests/unit/test_proxy.py index 42e239086..46c9ff8be 100644 --- a/openstack/tests/unit/test_proxy.py +++ b/openstack/tests/unit/test_proxy.py @@ -320,6 +320,39 @@ class TestProxyCreate(base.TestCase): self.res.create.assert_called_once_with(self.sot, base_path=base_path) +class TestProxyBulkCreate(base.TestCase): + + def setUp(self): + super(TestProxyBulkCreate, self).setUp() + + class Res(resource.Resource): + pass + + self.session = mock.Mock() + self.result = mock.sentinel + self.data = mock.Mock() + + self.sot = proxy.Proxy(self.session) + self.cls = Res + self.cls.bulk_create = mock.Mock(return_value=self.result) + + def test_bulk_create_attributes(self): + rv = self.sot._bulk_create(self.cls, self.data) + + self.assertEqual(rv, self.result) + self.cls.bulk_create.assert_called_once_with(self.sot, self.data, + base_path=None) + + def test_bulk_create_attributes_override_base_path(self): + base_path = 'dummy' + + rv = self.sot._bulk_create(self.cls, self.data, base_path=base_path) + + self.assertEqual(rv, self.result) + self.cls.bulk_create.assert_called_once_with(self.sot, self.data, + base_path=base_path) + + class TestProxyGet(base.TestCase): def setUp(self): diff --git a/releasenotes/notes/add-bulk-create-resources-12192ec9d76c7716.yaml b/releasenotes/notes/add-bulk-create-resources-12192ec9d76c7716.yaml new file mode 100644 index 000000000..896e17bdb --- /dev/null +++ b/releasenotes/notes/add-bulk-create-resources-12192ec9d76c7716.yaml @@ -0,0 +1,5 @@ +--- +features: + - Enabling Resource class for being able to create objects in bulk way. Add + first objects using that feature - Port, which now expose a proxy method + `create_ports` for creating multiple port objects at once.