Implement the 'gbp purge <tenant ID>' CLI
This basically follows what 'neutron purge' CLI is doing. And here is the neutron client patch for that: https://review.openstack.org/#/c/276541 Some special care has to be done to take care of auto_ptg/l2p/l3p created under implicit workflow otherwise the CLI will report failures while deleting those. Also publish the purge() API thru gbpclient interface. Change-Id: Ib1c515f0b66cf4b958472b8f56ba1a4e574e8431
This commit is contained in:
112
gbpclient/gbp/v2_0/purge.py
Normal file
112
gbpclient/gbp/v2_0/purge.py
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from neutronclient.common import exceptions as nexc
|
||||||
|
from neutronclient.neutron.v2_0 import purge as n_purge
|
||||||
|
|
||||||
|
AUTO_PTG_REGEX = 'auto[0-9a-f]{32}\Z'
|
||||||
|
|
||||||
|
|
||||||
|
class Purge(n_purge.Purge):
|
||||||
|
"""Delete all resources that belong to a given tenant."""
|
||||||
|
|
||||||
|
def _pluralize(self, string):
|
||||||
|
if re.search('_policy$', string):
|
||||||
|
return re.sub('_policy$', '_policies', string)
|
||||||
|
return string + 's'
|
||||||
|
|
||||||
|
def _get_resources(self, neutron_client, resource_types, tenant_id):
|
||||||
|
resources = super(Purge, self)._get_resources(neutron_client,
|
||||||
|
resource_types,
|
||||||
|
tenant_id)
|
||||||
|
# exclude auto_ptg as it was created by implicit workflow
|
||||||
|
if 'policy_target_group' in resource_types:
|
||||||
|
index = resource_types.index('policy_target_group')
|
||||||
|
for resource in list(resources[index]):
|
||||||
|
if re.match(AUTO_PTG_REGEX, resource['id']):
|
||||||
|
resources[index].remove(resource)
|
||||||
|
self.total_resources -= 1
|
||||||
|
return resources
|
||||||
|
|
||||||
|
def _purge_resources(self, neutron_client, resource_types,
|
||||||
|
tenant_resources):
|
||||||
|
deleted = {}
|
||||||
|
failed = {}
|
||||||
|
failures = False
|
||||||
|
for index, resources in enumerate(tenant_resources):
|
||||||
|
resource_type = resource_types[index]
|
||||||
|
failed[resource_type] = 0
|
||||||
|
deleted[resource_type] = 0
|
||||||
|
for resource in resources:
|
||||||
|
try:
|
||||||
|
self._delete_resource(neutron_client, resource_type,
|
||||||
|
resource)
|
||||||
|
deleted[resource_type] += 1
|
||||||
|
self.deleted_resources += 1
|
||||||
|
except nexc.NotFound:
|
||||||
|
# this is for l2p/l3p created under the
|
||||||
|
# implicit workflow.
|
||||||
|
deleted[resource_type] += 1
|
||||||
|
self.deleted_resources += 1
|
||||||
|
except Exception:
|
||||||
|
failures = True
|
||||||
|
failed[resource_type] += 1
|
||||||
|
self.total_resources -= 1
|
||||||
|
percent_complete = 100
|
||||||
|
if self.total_resources > 0:
|
||||||
|
percent_complete = (self.deleted_resources /
|
||||||
|
float(self.total_resources)) * 100
|
||||||
|
sys.stdout.write("\rPurging resources: %d%% complete." %
|
||||||
|
percent_complete)
|
||||||
|
sys.stdout.flush()
|
||||||
|
return (deleted, failed, failures)
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
neutron_client = self.get_client()
|
||||||
|
|
||||||
|
self.any_failures = False
|
||||||
|
|
||||||
|
# A list of the types of resources supported in the order in which
|
||||||
|
# they should be deleted.
|
||||||
|
resource_types = ['policy_target', 'policy_target_group', 'l2_policy',
|
||||||
|
'l3_policy', 'external_policy', 'nat_pool',
|
||||||
|
'external_segment', 'policy_rule_set',
|
||||||
|
'policy_rule', 'policy_classifier',
|
||||||
|
'policy_action', 'network_service_policy',
|
||||||
|
'servicechain_instance', 'servicechain_spec',
|
||||||
|
'servicechain_node', 'service_profile']
|
||||||
|
deleted = {}
|
||||||
|
failed = {}
|
||||||
|
self.total_resources = 0
|
||||||
|
self.deleted_resources = 0
|
||||||
|
resources = self._get_resources(neutron_client, resource_types,
|
||||||
|
parsed_args.tenant)
|
||||||
|
deleted, failed, failures = self._purge_resources(neutron_client,
|
||||||
|
resource_types,
|
||||||
|
resources)
|
||||||
|
print('\n%s' % self._build_message(deleted, failed, failures))
|
||||||
|
|
||||||
|
# TODO(Kent): clean up Neutron resources also
|
||||||
|
# super(Purge, self).take_action(parsed_args)
|
||||||
|
|
||||||
|
|
||||||
|
class PurgeAPI(Purge):
|
||||||
|
def __init__(self, app, app_args, gbp_client):
|
||||||
|
self.gbp_client = gbp_client
|
||||||
|
super(PurgeAPI, self).__init__(app, app_args)
|
||||||
|
|
||||||
|
def get_client(self):
|
||||||
|
return self.gbp_client
|
@@ -39,6 +39,7 @@ from neutronclient.i18n import _
|
|||||||
from neutronclient.version import __version__
|
from neutronclient.version import __version__
|
||||||
|
|
||||||
from gbpclient.gbp.v2_0 import groupbasedpolicy as gbp
|
from gbpclient.gbp.v2_0 import groupbasedpolicy as gbp
|
||||||
|
from gbpclient.gbp.v2_0 import purge
|
||||||
from gbpclient.gbp.v2_0 import servicechain
|
from gbpclient.gbp.v2_0 import servicechain
|
||||||
|
|
||||||
VERSION = '2.0'
|
VERSION = '2.0'
|
||||||
@@ -152,6 +153,7 @@ COMMAND_V2 = {
|
|||||||
'policy-rule-set-update': gbp.UpdatePolicyRuleSet,
|
'policy-rule-set-update': gbp.UpdatePolicyRuleSet,
|
||||||
'policy-rule-set-list': gbp.ListPolicyRuleSet,
|
'policy-rule-set-list': gbp.ListPolicyRuleSet,
|
||||||
'policy-rule-set-show': gbp.ShowPolicyRuleSet,
|
'policy-rule-set-show': gbp.ShowPolicyRuleSet,
|
||||||
|
'purge': purge.Purge,
|
||||||
'service-profile-list': servicechain.ListServiceProfile,
|
'service-profile-list': servicechain.ListServiceProfile,
|
||||||
'service-profile-show': servicechain.ShowServiceProfile,
|
'service-profile-show': servicechain.ShowServiceProfile,
|
||||||
'service-profile-create': servicechain.CreateServiceProfile,
|
'service-profile-create': servicechain.CreateServiceProfile,
|
||||||
|
27
gbpclient/tests/unit/test_cli20_purge.py
Normal file
27
gbpclient/tests/unit/test_cli20_purge.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# 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 neutronclient.tests.unit import test_cli20_purge
|
||||||
|
|
||||||
|
|
||||||
|
class CLITestV20Purge(test_cli20_purge.CLITestV20Purge):
|
||||||
|
def setUp(self):
|
||||||
|
super(CLITestV20Purge, self).setUp()
|
||||||
|
self.resource_types = ['policy_target', 'policy_target_group',
|
||||||
|
'l2_policy', 'l3_policy', 'external_policy',
|
||||||
|
'nat_pool', 'external_segment',
|
||||||
|
'policy_rule_set', 'policy_rule',
|
||||||
|
'policy_classifier', 'policy_action',
|
||||||
|
'network_service_policy',
|
||||||
|
'servicechain_instance', 'servicechain_spec',
|
||||||
|
'servicechain_node', 'service_profile']
|
@@ -14,6 +14,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from gbpclient.gbp.v2_0 import purge as gbpclient_purge
|
||||||
from neutronclient import client
|
from neutronclient import client
|
||||||
from neutronclient.common import exceptions
|
from neutronclient.common import exceptions
|
||||||
from neutronclient.common import serializer
|
from neutronclient.common import serializer
|
||||||
@@ -685,6 +686,10 @@ class Client(object):
|
|||||||
return self.delete(self.servicechain_instance_path %
|
return self.delete(self.servicechain_instance_path %
|
||||||
(servicechain_instance))
|
(servicechain_instance))
|
||||||
|
|
||||||
|
def purge(self, tenant_id):
|
||||||
|
purge_obj = gbpclient_purge.PurgeAPI(None, None, self)
|
||||||
|
purge_obj.take_action(tenant_id)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""Initialize a new client for the GBP v2.0 API."""
|
"""Initialize a new client for the GBP v2.0 API."""
|
||||||
super(Client, self).__init__()
|
super(Client, self).__init__()
|
||||||
|
Reference in New Issue
Block a user