diff --git a/doc/source/user/proxies/identity_v3.rst b/doc/source/user/proxies/identity_v3.rst index e044066f9..548abf4ca 100644 --- a/doc/source/user/proxies/identity_v3.rst +++ b/doc/source/user/proxies/identity_v3.rst @@ -42,7 +42,8 @@ Endpoint Operations .. autoclass:: openstack.identity.v3._proxy.Proxy :noindex: :members: create_endpoint, update_endpoint, delete_endpoint, get_endpoint, - find_endpoint, endpoints, project_endpoints + find_endpoint, endpoints, project_endpoints, + associate_endpoint_with_project, disassociate_endpoint_from_project Group Operations ^^^^^^^^^^^^^^^^ diff --git a/openstack/identity/v3/_proxy.py b/openstack/identity/v3/_proxy.py index b37a8eeb1..45cbaa042 100644 --- a/openstack/identity/v3/_proxy.py +++ b/openstack/identity/v3/_proxy.py @@ -414,6 +414,8 @@ class Proxy(proxy.Proxy): """ return self._update(_endpoint.Endpoint, endpoint, **attrs) + # ========== Project endpoints ========== + def project_endpoints(self, project, **query): """Retrieve a generator of endpoints which are associated with the project. @@ -431,6 +433,32 @@ class Proxy(proxy.Proxy): _endpoint.ProjectEndpoint, project_id=project_id, **query ) + def associate_endpoint_with_project(self, project, endpoint): + """Creates a direct association between project and endpoint + + :param project: Either the ID of a project or a + :class:`~openstack.identity.v3.project.Project` instance. + :param endpoint: Either the ID of an endpoint or a + :class:`~openstack.identity.v3.endpoint.Endpoint` instance. + :returns: None + """ + project = self._get_resource(_project.Project, project) + endpoint = self._get_resource(_endpoint.Endpoint, endpoint) + project.associate_endpoint(self, endpoint.id) + + def disassociate_endpoint_from_project(self, project, endpoint): + """Removes a direct association between project and endpoint + + :param project: Either the ID of a project or a + :class:`~openstack.identity.v3.project.Project` instance. + :param endpoint: Either the ID of an endpoint or a + :class:`~openstack.identity.v3.endpoint.Endpoint` instance. + :returns: None + """ + project = self._get_resource(_project.Project, project) + endpoint = self._get_resource(_endpoint.Endpoint, endpoint) + project.disassociate_endpoint(self, endpoint.id) + # ========== Groups ========== def create_group(self, **attrs): diff --git a/openstack/identity/v3/project.py b/openstack/identity/v3/project.py index f5f23196c..bb56d4c42 100644 --- a/openstack/identity/v3/project.py +++ b/openstack/identity/v3/project.py @@ -11,6 +11,7 @@ # under the License. from openstack.common import tag +from openstack import exceptions from openstack import resource from openstack import utils @@ -159,6 +160,38 @@ class Project(resource.Resource, tag.TagMixin): return True return False + def associate_endpoint(self, session, endpoint_id): + """Associate endpoint with project. + + :param session: The session to use for making this request. + :param endpoint_id: The ID of an endpoint. + :returns: None + """ + url = utils.urljoin( + '/OS-EP-FILTER/projects', + self.id, + 'endpoints', + endpoint_id, + ) + response = session.put(url) + exceptions.raise_from_response(response) + + def disassociate_endpoint(self, session, endpoint_id): + """Disassociate endpoint from project. + + :param session: The session to use for making this request. + :param endpoint_id: The ID of an endpoint. + :returns: None + """ + url = utils.urljoin( + '/OS-EP-FILTER/projects', + self.id, + 'endpoints', + endpoint_id, + ) + response = session.delete(url) + exceptions.raise_from_response(response) + class UserProject(Project): base_path = '/users/%(user_id)s/projects' diff --git a/openstack/tests/unit/identity/v3/test_proxy.py b/openstack/tests/unit/identity/v3/test_proxy.py index 1556fe169..e582f31f8 100644 --- a/openstack/tests/unit/identity/v3/test_proxy.py +++ b/openstack/tests/unit/identity/v3/test_proxy.py @@ -36,7 +36,8 @@ from openstack.identity.v3 import user from openstack.tests.unit import test_proxy_base USER_ID = 'user-id-' + uuid.uuid4().hex -ENDPOINT_ID = 'user-id-' + uuid.uuid4().hex +ENDPOINT_ID = 'endpoint-id-' + uuid.uuid4().hex +PROJECT_ID = 'project-id-' + uuid.uuid4().hex class TestIdentityProxyBase(test_proxy_base.TestProxyBase): @@ -185,6 +186,14 @@ class TestIdentityProxyEndpoint(TestIdentityProxyBase): def test_endpoints(self): self.verify_list(self.proxy.endpoints, endpoint.Endpoint) + def test_project_endpoints(self): + self.verify_list( + self.proxy.project_endpoints, + endpoint.ProjectEndpoint, + method_kwargs={'project': PROJECT_ID}, + expected_kwargs={'project_id': PROJECT_ID}, + ) + def test_endpoint_update(self): self.verify_update(self.proxy.update_endpoint, endpoint.Endpoint) @@ -314,6 +323,22 @@ class TestIdentityProxyProject(TestIdentityProxyBase): def test_project_update(self): self.verify_update(self.proxy.update_project, project.Project) + def test_project_associate_endpoint(self): + self._verify( + 'openstack.identity.v3.project.Project.associate_endpoint', + self.proxy.associate_endpoint_with_project, + method_args=['project_id', 'endpoint_id'], + expected_args=[self.proxy, 'endpoint_id'], + ) + + def test_project_disassociate_endpoint(self): + self._verify( + 'openstack.identity.v3.project.Project.disassociate_endpoint', + self.proxy.disassociate_endpoint_from_project, + method_args=['project_id', 'endpoint_id'], + expected_args=[self.proxy, 'endpoint_id'], + ) + class TestIdentityProxyService(TestIdentityProxyBase): def test_service_create_attrs(self):