diff --git a/ospurge/ospurge.py b/ospurge/ospurge.py index 9b691e9..c126cba 100755 --- a/ospurge/ospurge.py +++ b/ospurge/ospurge.py @@ -35,6 +35,8 @@ import cinderclient.exceptions from cinderclient.v1 import client as cinder_client import glanceclient.exc from glanceclient.v1 import client as glance_client +from heatclient import client as heat_client +import heatclient.openstack.common.apiclient.exceptions from keystoneclient.apiclient import exceptions as api_exceptions import keystoneclient.openstack.common.apiclient.exceptions from keystoneclient.v2_0 import client as keystone_client @@ -98,7 +100,8 @@ RESOURCES_CLASSES = ['CinderSnapshots', 'SwiftObjects', 'SwiftContainers', 'CinderVolumes', - 'CeilometerAlarms'] + 'CeilometerAlarms', + 'HeatStacks'] # Decorators @@ -582,6 +585,29 @@ class GlanceImages(Resources): return res.owner == self.project_id +class HeatStacks(Resources): + + def __init__(self, session): + self.client = heat_client.Client( + "1", + endpoint=session.get_endpoint("orchestration"), + token=session.token, insecure=session.insecure) + self.project_id = session.project_id + + def list(self): + return self.client.stacks.list() + + def delete(self, stack): + super(HeatStacks, self).delete(stack) + if stack.stack_status == "DELETE_FAILED": + self.client.stacks.abandon(stack.id) + else: + self.client.stacks.delete(stack.id) + + def resource_str(self, stack): + return "stack {})".format(stack.id) + + class CeilometerAlarms(Resources): def __init__(self, session): @@ -704,6 +730,7 @@ def perform_on_project(admin_name, password, project, auth_url, neutronclient.common.exceptions.EndpointNotFound, cinderclient.exceptions.EndpointNotFound, novaclient.exceptions.EndpointNotFound, + heatclient.openstack.common.apiclient.exceptions.EndpointNotFound, ResourceNotEnabled): # If service is not in Keystone's services catalog, ignoring it pass diff --git a/ospurge/tests/client_fixtures.py b/ospurge/tests/client_fixtures.py index f9ecc22..672d51f 100644 --- a/ospurge/tests/client_fixtures.py +++ b/ospurge/tests/client_fixtures.py @@ -25,12 +25,14 @@ STORAGE_PUBLIC_ENDPOINT = 'http://public:8080/v1/AUTH_ee5b90900a4b4e85938b0ceadf NETWORK_PUBLIC_ENDPOINT = 'https://network0.cw-labs.net' COMPUTE_PUBLIC_ENDPOINT = 'https://compute0.cw-labs.net/v2/43c9e28327094e1b81484f4b9aee74d5' METERING_PUBLIC_ENDPOINT = 'https://metric0.cw-labs.net' +ORCHESTRATION_PUBLIC_ENDPOINT = 'https://orchestration0.cw-labs.net/v1' VOLUME_INTERNAL_ENDPOINT = 'http://internal:8776/v1/225da22d3ce34b15877ea70b2a575f58' IMAGE_INTERNAL_ENDPOINT = 'http://internal:9292' STORAGE_INTERNAL_ENDPOINT = 'http://internal:8080/v1/AUTH_ee5b90900a4b4e85938b0ceadf4467f8' NETWORK_INTERNAL_ENDPOINT = 'http://neutron.usr.lab0.aub.cw-labs.net:9696' COMPUTE_INTERNAL_ENDPOINT = 'http://nova.usr.lab0.aub.cw-labs.net:8774/v2/43c9e28327094e1b81484f4b9aee74d5' METERING_INTERNAL_ENDPOINT = 'http://ceilometer.usr.lab0.aub.cw-labs.net:8777' +ORCHESTRATION_INTERNAL_ENDPOINT = 'http://heat.usr.lab0.aub.cw-labs.net:8004/v1' STORAGE_CONTAINERS = ['janeausten', 'marktwain'] @@ -54,6 +56,8 @@ SERVERS_IDS = ["616fb98f-46ca-475e-917e-2563e5a8cd19"] IMAGES_IDS = ["37717f53-3707-49b9-9dd0-fd063e6b9fc5", "4e150966-cbe7-4fd7-a964-41e008d20f10", "482fbcc3-d831-411d-a073-ddc828a7a9ed"] ALARMS_IDS = ["ca950223-e982-4552-9dec-5dc5d3ea4172"] +STACKS_IDS = ["5c136348-5550-4ec5-8bd6-b83241844db3", + "ec4083c1-3667-47d2-91c9-ce0bc8e3c2b9"] UNBOUND_PORT_ID = "abcdb45e-45fe-4e04-8704-bf6f58760000" PRIVATE_PORT_IDS = ["p7815f5b-a228-47bb-a5e5-f139c4f476ft", "p78o5f5t-a228-47bb-a5e2-f139c4f476ft"] @@ -145,6 +149,15 @@ PROJECT_SCOPED_TOKEN = { 'endpoints_links': [], 'name': 'Metering service', 'type': 'metering' + }, { + 'endpoints': [{ + 'adminURL': 'http://heat.usr.lab0.aub.cw-labs.net:8777', + 'internalURL': ORCHESTRATION_INTERNAL_ENDPOINT, + 'publicURL': ORCHESTRATION_PUBLIC_ENDPOINT, + 'region': 'RegionOne'}], + 'endpoints_links': [], + 'name': 'Orchestration service', + 'type': 'orchestration' }], 'token': { 'expires': '2012-10-03T16:53:36Z', @@ -1002,3 +1015,38 @@ ALARMS_LIST = [ "user_id": "c96c887c216949acbdfbd8b494863567" } ] + +STACKS_LIST = { + "stacks": [ + { + "description": "First test", + "links": [ + { + "href": "http://site/5c136348-5550-4ec5-8bd6-b83241844db3", + "rel": "self" + } + ], + "stack_status_reason": "", + "stack_name": "stack1", + "creation_time": "2015-03-03T14:08:54Z", + "updated_time": None, + "stack_status": "CREATE_SUCCESS", + "id": "5c136348-5550-4ec5-8bd6-b83241844db3" + }, + { + "description": "Second test", + "links": [ + { + "href": "http://site/ec4083c1-3667-47d2-91c9-ce0bc8e3c2b9", + "rel": "self" + } + ], + "stack_status_reason": "", + "stack_name": "stack2", + "creation_time": "2015-03-03T17:34:21Z", + "updated_time": None, + "stack_status": "DELETE_FAILED", + "id": "ec4083c1-3667-47d2-91c9-ce0bc8e3c2b9" + } + ] +} diff --git a/ospurge/tests/test_ospurge.py b/ospurge/tests/test_ospurge.py index bfceafd..7b22f17 100644 --- a/ospurge/tests/test_ospurge.py +++ b/ospurge/tests/test_ospurge.py @@ -626,3 +626,41 @@ class TestCeilometerAlarms(TestResourcesBase): def test_delete(self): self._test_delete() + + +class TestHeatStacks(TestResourcesBase): + TEST_URL = client_fixtures.ORCHESTRATION_PUBLIC_ENDPOINT + IDS = client_fixtures.STACKS_IDS + + def stub_list(self): + self.stub_url('GET', parts=['stacks?'], + json=client_fixtures.STACKS_LIST) + + def stub_delete(self): + self.stub_url( + 'DELETE', parts=['stacks', client_fixtures.STACKS_IDS[0]]) + + def setUp(self): + super(TestHeatStacks, self).setUp() + self.resources = ospurge.HeatStacks(self.session) + + def test_list(self): + self._test_list() + + def test_delete(self): + self._test_delete() + + @httpretty.activate + def test_abandon(self): + self.stub_auth() + self.stub_list() + get_result = {'stack': client_fixtures.STACKS_LIST['stacks'][1]} + self.stub_url( + 'GET', parts=['stacks', client_fixtures.STACKS_IDS[1]], + json=get_result) + self.stub_url( + 'DELETE', + parts=['stacks', 'stack2', client_fixtures.STACKS_IDS[1], + 'abandon']) + elts = list(self.resources.list()) + self.resources.delete(elts[1]) diff --git a/requirements.txt b/requirements.txt index 2316161..469b289 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ python-ceilometerclient python-cinderclient python-glanceclient +python-heatclient python-keystoneclient python-neutronclient python-novaclient