Merge "Allow tempest cleanup delete resources based on prefix"
This commit is contained in:
commit
8794025588
@ -17,6 +17,16 @@
|
|||||||
# fail early if anything missing the IPv6 settings or deployments.
|
# fail early if anything missing the IPv6 settings or deployments.
|
||||||
- devstack-ipv6-only-deployments-verification
|
- devstack-ipv6-only-deployments-verification
|
||||||
tasks:
|
tasks:
|
||||||
|
- name: Run tempest cleanup init-saved-state
|
||||||
|
include_role:
|
||||||
|
name: tempest-cleanup
|
||||||
|
vars:
|
||||||
|
init_saved_state: true
|
||||||
|
when: (run_tempest_dry_cleanup is defined and run_tempest_dry_cleanup | bool) or
|
||||||
|
(run_tempest_cleanup is defined and run_tempest_cleanup | bool) or
|
||||||
|
(run_tempest_fail_if_leaked_resources is defined and run_tempest_fail_if_leaked_resources | bool) or
|
||||||
|
(run_tempest_cleanup_prefix is defined and run_tempest_cleanup_prefix | bool)
|
||||||
|
|
||||||
- name: Run Tempest version <= 26.0.0
|
- name: Run Tempest version <= 26.0.0
|
||||||
include_role:
|
include_role:
|
||||||
name: run-tempest-26
|
name: run-tempest-26
|
||||||
@ -30,3 +40,15 @@
|
|||||||
when:
|
when:
|
||||||
- zuul.branch is defined
|
- zuul.branch is defined
|
||||||
- zuul.branch not in ["stable/ocata", "stable/pike", "stable/queens", "stable/rocky", "stable/stein"]
|
- zuul.branch not in ["stable/ocata", "stable/pike", "stable/queens", "stable/rocky", "stable/stein"]
|
||||||
|
|
||||||
|
- name: Run tempest cleanup dry-run
|
||||||
|
include_role:
|
||||||
|
name: tempest-cleanup
|
||||||
|
vars:
|
||||||
|
dry_run: true
|
||||||
|
when: run_tempest_dry_cleanup is defined and run_tempest_dry_cleanup | bool
|
||||||
|
|
||||||
|
- name: Run tempest cleanup
|
||||||
|
include_role:
|
||||||
|
name: tempest-cleanup
|
||||||
|
when: run_tempest_cleanup is defined and run_tempest_cleanup | bool
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
init_saved_state: true
|
init_saved_state: true
|
||||||
when: (run_tempest_dry_cleanup is defined and run_tempest_dry_cleanup | bool) or
|
when: (run_tempest_dry_cleanup is defined and run_tempest_dry_cleanup | bool) or
|
||||||
(run_tempest_cleanup is defined and run_tempest_cleanup | bool) or
|
(run_tempest_cleanup is defined and run_tempest_cleanup | bool) or
|
||||||
(run_tempest_fail_if_leaked_resources is defined and run_tempest_fail_if_leaked_resources | bool)
|
(run_tempest_fail_if_leaked_resources is defined and run_tempest_fail_if_leaked_resources | bool) or
|
||||||
|
(run_tempest_cleanup_prefix is defined and run_tempest_cleanup_prefix | bool)
|
||||||
|
|
||||||
- name: Run Tempest version <= 26.0.0
|
- name: Run Tempest version <= 26.0.0
|
||||||
include_role:
|
include_role:
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
We add a new argument, ``--prefix``, to ``tempest cleanup`` tool that will
|
||||||
|
allow users delete only resources that match the prefix. When this option
|
||||||
|
is used, ``saved_state.json`` file is not needed (no need to run with
|
||||||
|
``--init-saved-state`` first). If there is one, it will be ignored and the
|
||||||
|
cleanup will be done based on the given prefix only.
|
||||||
|
Note, that some resources are not named thus they will not be deleted when
|
||||||
|
filtering based on the prefix.
|
@ -40,6 +40,12 @@ saved_state.json file.
|
|||||||
some must have been leaked. This can be also used to verify that tempest
|
some must have been leaked. This can be also used to verify that tempest
|
||||||
cleanup was successful.
|
cleanup was successful.
|
||||||
|
|
||||||
|
.. zuul:rolevar:: run_tempest_cleanup_prefix
|
||||||
|
:default: false
|
||||||
|
|
||||||
|
When true, tempest cleanup will be called with '--prefix tempest' to delete
|
||||||
|
only resources with names that match the prefix. This option can be used
|
||||||
|
together with dry_run.
|
||||||
|
|
||||||
Role usage
|
Role usage
|
||||||
----------
|
----------
|
||||||
|
@ -2,3 +2,4 @@ devstack_base_dir: /opt/stack
|
|||||||
init_saved_state: false
|
init_saved_state: false
|
||||||
dry_run: false
|
dry_run: false
|
||||||
run_tempest_fail_if_leaked_resources: false
|
run_tempest_fail_if_leaked_resources: false
|
||||||
|
run_tempest_cleanup_prefix: false
|
||||||
|
@ -5,3 +5,12 @@
|
|||||||
command: tox -evenv-tempest -- tempest cleanup --dry-run --debug
|
command: tox -evenv-tempest -- tempest cleanup --dry-run --debug
|
||||||
args:
|
args:
|
||||||
chdir: "{{ devstack_base_dir }}/tempest"
|
chdir: "{{ devstack_base_dir }}/tempest"
|
||||||
|
when: not run_tempest_cleanup_prefix
|
||||||
|
|
||||||
|
- name: Run tempest cleanup dry-run with tempest prefix
|
||||||
|
become: yes
|
||||||
|
become_user: tempest
|
||||||
|
command: tox -evenv-tempest -- tempest cleanup --dry-run --debug --prefix tempest
|
||||||
|
args:
|
||||||
|
chdir: "{{ devstack_base_dir }}/tempest"
|
||||||
|
when: run_tempest_cleanup_prefix
|
@ -27,6 +27,15 @@
|
|||||||
command: tox -evenv-tempest -- tempest cleanup --debug
|
command: tox -evenv-tempest -- tempest cleanup --debug
|
||||||
args:
|
args:
|
||||||
chdir: "{{ devstack_base_dir }}/tempest"
|
chdir: "{{ devstack_base_dir }}/tempest"
|
||||||
|
when: not run_tempest_cleanup_prefix
|
||||||
|
|
||||||
|
- name: Run tempest cleanup with tempest prefix
|
||||||
|
become: yes
|
||||||
|
become_user: tempest
|
||||||
|
command: tox -evenv-tempest -- tempest cleanup --debug --prefix tempest
|
||||||
|
args:
|
||||||
|
chdir: "{{ devstack_base_dir }}/tempest"
|
||||||
|
when: run_tempest_cleanup_prefix
|
||||||
|
|
||||||
- when:
|
- when:
|
||||||
- run_tempest_fail_if_leaked_resources
|
- run_tempest_fail_if_leaked_resources
|
||||||
|
@ -26,6 +26,10 @@ specified in ``tempest.conf`` is never deleted.
|
|||||||
Example Run
|
Example Run
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
We advice not to run tempest cleanup on production environments.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
If step 1 is skipped in the example below, the cleanup procedure
|
If step 1 is skipped in the example below, the cleanup procedure
|
||||||
@ -45,7 +49,10 @@ Runtime Arguments
|
|||||||
* ``--init-saved-state``: Initializes the saved state of the OpenStack
|
* ``--init-saved-state``: Initializes the saved state of the OpenStack
|
||||||
deployment and will output a ``saved_state.json`` file containing resources
|
deployment and will output a ``saved_state.json`` file containing resources
|
||||||
from your deployment that will be preserved from the cleanup command. This
|
from your deployment that will be preserved from the cleanup command. This
|
||||||
should be done prior to running Tempest tests.
|
should be done prior to running Tempest tests. Note, that if other users of
|
||||||
|
your cloud could have created resources after running ``--init-saved-state``,
|
||||||
|
it would not protect those resources as they wouldn't be present in the
|
||||||
|
saved_state.json file.
|
||||||
|
|
||||||
* ``--delete-tempest-conf-objects``: If option is present, then the command
|
* ``--delete-tempest-conf-objects``: If option is present, then the command
|
||||||
will delete the admin project in addition to the resources associated with
|
will delete the admin project in addition to the resources associated with
|
||||||
@ -58,7 +65,27 @@ Runtime Arguments
|
|||||||
global objects that will be removed (domains, flavors, images, roles,
|
global objects that will be removed (domains, flavors, images, roles,
|
||||||
projects, and users). Once the cleanup command is executed (e.g. run without
|
projects, and users). Once the cleanup command is executed (e.g. run without
|
||||||
parameters), running it again with ``--dry-run`` should yield an empty
|
parameters), running it again with ``--dry-run`` should yield an empty
|
||||||
report.
|
report. We STRONGLY ENCOURAGE to run ``tempest cleanup`` with ``--dry-run``
|
||||||
|
first and then verify that the resources listed in the ``dry_run.json`` file
|
||||||
|
are meant to be deleted.
|
||||||
|
|
||||||
|
* ``--prefix``: Only resources that match the prefix will be deleted. When this
|
||||||
|
option is used, ``saved_state.json`` file is not needed (no need to run with
|
||||||
|
``--init-saved-state`` first).
|
||||||
|
|
||||||
|
All tempest resources are created with the prefix value from the config
|
||||||
|
option ``resource_name_prefix`` in tempest.conf. To cleanup only the
|
||||||
|
resources created by tempest, you should use the prefix set in your
|
||||||
|
tempest.conf (the default value of ``resource_name_prefix`` is ``tempest``.
|
||||||
|
|
||||||
|
Note, that some resources are not named thus they will not be deleted when
|
||||||
|
filtering based on the prefix. This option will be ignored when
|
||||||
|
``--init-saved-state`` is used so that it can capture the true init state -
|
||||||
|
all resources present at that moment. If there is any ``saved_state.json``
|
||||||
|
file present (e.g. if you ran the tempest cleanup with ``--init-saved-state``
|
||||||
|
before) and you run the tempest cleanup with ``--prefix``, the
|
||||||
|
``saved_state.json`` file will be ignored and cleanup will be done based on
|
||||||
|
the passed prefix only.
|
||||||
|
|
||||||
* ``--help``: Print the help text for the command and parameters.
|
* ``--help``: Print the help text for the command and parameters.
|
||||||
|
|
||||||
@ -157,6 +184,7 @@ class TempestCleanup(command.Command):
|
|||||||
is_dry_run = self.options.dry_run
|
is_dry_run = self.options.dry_run
|
||||||
is_preserve = not self.options.delete_tempest_conf_objects
|
is_preserve = not self.options.delete_tempest_conf_objects
|
||||||
is_save_state = False
|
is_save_state = False
|
||||||
|
cleanup_prefix = self.options.prefix
|
||||||
|
|
||||||
if is_dry_run:
|
if is_dry_run:
|
||||||
self.dry_run_data["_projects_to_clean"] = {}
|
self.dry_run_data["_projects_to_clean"] = {}
|
||||||
@ -168,7 +196,8 @@ class TempestCleanup(command.Command):
|
|||||||
'is_dry_run': is_dry_run,
|
'is_dry_run': is_dry_run,
|
||||||
'saved_state_json': self.json_data,
|
'saved_state_json': self.json_data,
|
||||||
'is_preserve': False,
|
'is_preserve': False,
|
||||||
'is_save_state': is_save_state}
|
'is_save_state': is_save_state,
|
||||||
|
'prefix': cleanup_prefix}
|
||||||
project_service = cleanup_service.ProjectService(admin_mgr, **kwargs)
|
project_service = cleanup_service.ProjectService(admin_mgr, **kwargs)
|
||||||
projects = project_service.list()
|
projects = project_service.list()
|
||||||
LOG.info("Processing %s projects", len(projects))
|
LOG.info("Processing %s projects", len(projects))
|
||||||
@ -182,6 +211,7 @@ class TempestCleanup(command.Command):
|
|||||||
'saved_state_json': self.json_data,
|
'saved_state_json': self.json_data,
|
||||||
'is_preserve': is_preserve,
|
'is_preserve': is_preserve,
|
||||||
'is_save_state': is_save_state,
|
'is_save_state': is_save_state,
|
||||||
|
'prefix': cleanup_prefix,
|
||||||
'got_exceptions': self.GOT_EXCEPTIONS}
|
'got_exceptions': self.GOT_EXCEPTIONS}
|
||||||
LOG.info("Processing global services")
|
LOG.info("Processing global services")
|
||||||
for service in self.global_services:
|
for service in self.global_services:
|
||||||
@ -206,6 +236,7 @@ class TempestCleanup(command.Command):
|
|||||||
project_id = project['id']
|
project_id = project['id']
|
||||||
project_name = project['name']
|
project_name = project['name']
|
||||||
project_data = None
|
project_data = None
|
||||||
|
cleanup_prefix = self.options.prefix
|
||||||
if is_dry_run:
|
if is_dry_run:
|
||||||
project_data = dry_run_data["_projects_to_clean"][project_id] = {}
|
project_data = dry_run_data["_projects_to_clean"][project_id] = {}
|
||||||
project_data['name'] = project_name
|
project_data['name'] = project_name
|
||||||
@ -216,6 +247,7 @@ class TempestCleanup(command.Command):
|
|||||||
'is_preserve': is_preserve,
|
'is_preserve': is_preserve,
|
||||||
'is_save_state': False,
|
'is_save_state': False,
|
||||||
'project_id': project_id,
|
'project_id': project_id,
|
||||||
|
'prefix': cleanup_prefix,
|
||||||
'got_exceptions': self.GOT_EXCEPTIONS}
|
'got_exceptions': self.GOT_EXCEPTIONS}
|
||||||
for service in self.project_associated_services:
|
for service in self.project_associated_services:
|
||||||
svc = service(self.admin_mgr, **kwargs)
|
svc = service(self.admin_mgr, **kwargs)
|
||||||
@ -243,10 +275,26 @@ class TempestCleanup(command.Command):
|
|||||||
help="Generate JSON file:" + DRY_RUN_JSON +
|
help="Generate JSON file:" + DRY_RUN_JSON +
|
||||||
", that reports the objects that would have "
|
", that reports the objects that would have "
|
||||||
"been deleted had a full cleanup been run.")
|
"been deleted had a full cleanup been run.")
|
||||||
|
parser.add_argument('--prefix', dest='prefix', default=None,
|
||||||
|
help="Only resources that match the prefix will "
|
||||||
|
"be deleted (resources in saved_state.json are "
|
||||||
|
"not taken into account). All tempest resources "
|
||||||
|
"are created with the prefix value set by "
|
||||||
|
"resource_name_prefix in tempest.conf, default "
|
||||||
|
"prefix is tempest. Note that some resources are "
|
||||||
|
"not named thus they will not be deleted when "
|
||||||
|
"filtering based on the prefix. This opt will be "
|
||||||
|
"ignored when --init-saved-state is used so that "
|
||||||
|
"it can capture the true init state - all "
|
||||||
|
"resources present at that moment.")
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return 'Cleanup after tempest run'
|
return ('tempest cleanup tool, read the full documentation before '
|
||||||
|
'using this tool. We advice not to run it on production '
|
||||||
|
'environments. On environments where also other users may '
|
||||||
|
'create resources, we strongly advice using --dry-run '
|
||||||
|
'argument first and verify the content of dry_run.json file.')
|
||||||
|
|
||||||
def _init_state(self):
|
def _init_state(self):
|
||||||
LOG.info("Initializing saved state.")
|
LOG.info("Initializing saved state.")
|
||||||
@ -257,6 +305,10 @@ class TempestCleanup(command.Command):
|
|||||||
'saved_state_json': data,
|
'saved_state_json': data,
|
||||||
'is_preserve': False,
|
'is_preserve': False,
|
||||||
'is_save_state': True,
|
'is_save_state': True,
|
||||||
|
# must be None as we want to capture true init state
|
||||||
|
# (all resources present) thus no filtering based
|
||||||
|
# on the prefix
|
||||||
|
'prefix': None,
|
||||||
'got_exceptions': self.GOT_EXCEPTIONS}
|
'got_exceptions': self.GOT_EXCEPTIONS}
|
||||||
for service in self.global_services:
|
for service in self.global_services:
|
||||||
svc = service(admin_mgr, **kwargs)
|
svc = service(admin_mgr, **kwargs)
|
||||||
|
@ -115,6 +115,16 @@ class BaseService(object):
|
|||||||
return [item for item in item_list
|
return [item for item in item_list
|
||||||
if item['tenant_id'] == self.tenant_id]
|
if item['tenant_id'] == self.tenant_id]
|
||||||
|
|
||||||
|
def _filter_by_prefix(self, item_list):
|
||||||
|
items = [item for item in item_list
|
||||||
|
if item['name'].startswith(self.prefix)]
|
||||||
|
return items
|
||||||
|
|
||||||
|
def _filter_out_ids_from_saved(self, item_list, attr):
|
||||||
|
items = [item for item in item_list if item['id']
|
||||||
|
not in self.saved_state_json[attr].keys()]
|
||||||
|
return items
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -156,10 +166,11 @@ class SnapshotService(BaseService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.client
|
client = self.client
|
||||||
snaps = client.list_snapshots()['snapshots']
|
snaps = client.list_snapshots()['snapshots']
|
||||||
if not self.is_save_state:
|
if self.prefix:
|
||||||
|
snaps = self._filter_by_prefix(snaps)
|
||||||
|
elif not self.is_save_state:
|
||||||
# recreate list removing saved snapshots
|
# recreate list removing saved snapshots
|
||||||
snaps = [snap for snap in snaps if snap['id']
|
snaps = self._filter_out_ids_from_saved(snaps, 'snapshots')
|
||||||
not in self.saved_state_json['snapshots'].keys()]
|
|
||||||
LOG.debug("List count, %s Snapshots", len(snaps))
|
LOG.debug("List count, %s Snapshots", len(snaps))
|
||||||
return snaps
|
return snaps
|
||||||
|
|
||||||
@ -194,10 +205,11 @@ class ServerService(BaseService):
|
|||||||
client = self.client
|
client = self.client
|
||||||
servers_body = client.list_servers()
|
servers_body = client.list_servers()
|
||||||
servers = servers_body['servers']
|
servers = servers_body['servers']
|
||||||
if not self.is_save_state:
|
if self.prefix:
|
||||||
|
servers = self._filter_by_prefix(servers)
|
||||||
|
elif not self.is_save_state:
|
||||||
# recreate list removing saved servers
|
# recreate list removing saved servers
|
||||||
servers = [server for server in servers if server['id']
|
servers = self._filter_out_ids_from_saved(servers, 'servers')
|
||||||
not in self.saved_state_json['servers'].keys()]
|
|
||||||
LOG.debug("List count, %s Servers", len(servers))
|
LOG.debug("List count, %s Servers", len(servers))
|
||||||
return servers
|
return servers
|
||||||
|
|
||||||
@ -227,10 +239,11 @@ class ServerGroupService(ServerService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.server_groups_client
|
client = self.server_groups_client
|
||||||
sgs = client.list_server_groups()['server_groups']
|
sgs = client.list_server_groups()['server_groups']
|
||||||
if not self.is_save_state:
|
if self.prefix:
|
||||||
|
sgs = self._filter_by_prefix(sgs)
|
||||||
|
elif not self.is_save_state:
|
||||||
# recreate list removing saved server_groups
|
# recreate list removing saved server_groups
|
||||||
sgs = [sg for sg in sgs if sg['id']
|
sgs = self._filter_out_ids_from_saved(sgs, 'server_groups')
|
||||||
not in self.saved_state_json['server_groups'].keys()]
|
|
||||||
LOG.debug("List count, %s Server Groups", len(sgs))
|
LOG.debug("List count, %s Server Groups", len(sgs))
|
||||||
return sgs
|
return sgs
|
||||||
|
|
||||||
@ -263,7 +276,9 @@ class KeyPairService(BaseService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.client
|
client = self.client
|
||||||
keypairs = client.list_keypairs()['keypairs']
|
keypairs = client.list_keypairs()['keypairs']
|
||||||
if not self.is_save_state:
|
if self.prefix:
|
||||||
|
keypairs = self._filter_by_prefix(keypairs)
|
||||||
|
elif not self.is_save_state:
|
||||||
# recreate list removing saved keypairs
|
# recreate list removing saved keypairs
|
||||||
keypairs = [keypair for keypair in keypairs
|
keypairs = [keypair for keypair in keypairs
|
||||||
if keypair['keypair']['name']
|
if keypair['keypair']['name']
|
||||||
@ -302,10 +317,11 @@ class VolumeService(BaseService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.client
|
client = self.client
|
||||||
vols = client.list_volumes()['volumes']
|
vols = client.list_volumes()['volumes']
|
||||||
if not self.is_save_state:
|
if self.prefix:
|
||||||
|
vols = self._filter_by_prefix(vols)
|
||||||
|
elif not self.is_save_state:
|
||||||
# recreate list removing saved volumes
|
# recreate list removing saved volumes
|
||||||
vols = [vol for vol in vols if vol['id']
|
vols = self._filter_out_ids_from_saved(vols, 'volumes')
|
||||||
not in self.saved_state_json['volumes'].keys()]
|
|
||||||
LOG.debug("List count, %s Volumes", len(vols))
|
LOG.debug("List count, %s Volumes", len(vols))
|
||||||
return vols
|
return vols
|
||||||
|
|
||||||
@ -336,6 +352,10 @@ class VolumeQuotaService(BaseService):
|
|||||||
self.client = manager.volume_quotas_client_latest
|
self.client = manager.volume_quotas_client_latest
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore do nothing
|
||||||
|
return
|
||||||
client = self.client
|
client = self.client
|
||||||
try:
|
try:
|
||||||
LOG.debug("Deleting Volume Quotas for project with id %s",
|
LOG.debug("Deleting Volume Quotas for project with id %s",
|
||||||
@ -346,6 +366,10 @@ class VolumeQuotaService(BaseService):
|
|||||||
self.project_id)
|
self.project_id)
|
||||||
|
|
||||||
def dry_run(self):
|
def dry_run(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore do nothing
|
||||||
|
return
|
||||||
quotas = self.client.show_quota_set(
|
quotas = self.client.show_quota_set(
|
||||||
self.project_id, params={'usage': True})['quota_set']
|
self.project_id, params={'usage': True})['quota_set']
|
||||||
self.data['volume_quotas'] = quotas
|
self.data['volume_quotas'] = quotas
|
||||||
@ -358,6 +382,10 @@ class NovaQuotaService(BaseService):
|
|||||||
self.limits_client = manager.limits_client
|
self.limits_client = manager.limits_client
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore do nothing
|
||||||
|
return
|
||||||
client = self.client
|
client = self.client
|
||||||
try:
|
try:
|
||||||
LOG.debug("Deleting Nova Quotas for project with id %s",
|
LOG.debug("Deleting Nova Quotas for project with id %s",
|
||||||
@ -368,6 +396,10 @@ class NovaQuotaService(BaseService):
|
|||||||
self.project_id)
|
self.project_id)
|
||||||
|
|
||||||
def dry_run(self):
|
def dry_run(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore do nothing
|
||||||
|
return
|
||||||
client = self.limits_client
|
client = self.limits_client
|
||||||
quotas = client.show_limits()['limits']
|
quotas = client.show_limits()['limits']
|
||||||
self.data['compute_quotas'] = quotas['absolute']
|
self.data['compute_quotas'] = quotas['absolute']
|
||||||
@ -379,6 +411,10 @@ class NetworkQuotaService(BaseService):
|
|||||||
self.client = manager.network_quotas_client
|
self.client = manager.network_quotas_client
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore do nothing
|
||||||
|
return
|
||||||
client = self.client
|
client = self.client
|
||||||
try:
|
try:
|
||||||
LOG.debug("Deleting Network Quotas for project with id %s",
|
LOG.debug("Deleting Network Quotas for project with id %s",
|
||||||
@ -389,6 +425,10 @@ class NetworkQuotaService(BaseService):
|
|||||||
self.project_id)
|
self.project_id)
|
||||||
|
|
||||||
def dry_run(self):
|
def dry_run(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore do nothing
|
||||||
|
return
|
||||||
resp = [quota for quota in self.client.list_quotas()['quotas']
|
resp = [quota for quota in self.client.list_quotas()['quotas']
|
||||||
if quota['project_id'] == self.project_id]
|
if quota['project_id'] == self.project_id]
|
||||||
self.data['network_quotas'] = resp
|
self.data['network_quotas'] = resp
|
||||||
@ -422,11 +462,13 @@ class NetworkService(BaseNetworkService):
|
|||||||
client = self.networks_client
|
client = self.networks_client
|
||||||
networks = client.list_networks(**self.tenant_filter)
|
networks = client.list_networks(**self.tenant_filter)
|
||||||
networks = networks['networks']
|
networks = networks['networks']
|
||||||
|
if self.prefix:
|
||||||
|
networks = self._filter_by_prefix(networks)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved networks
|
# recreate list removing saved networks
|
||||||
networks = [network for network in networks if network['id']
|
networks = self._filter_out_ids_from_saved(
|
||||||
not in self.saved_state_json['networks'].keys()]
|
networks, 'networks')
|
||||||
# filter out networks declared in tempest.conf
|
# filter out networks declared in tempest.conf
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
networks = [network for network in networks
|
networks = [network for network in networks
|
||||||
@ -458,14 +500,17 @@ class NetworkService(BaseNetworkService):
|
|||||||
class NetworkFloatingIpService(BaseNetworkService):
|
class NetworkFloatingIpService(BaseNetworkService):
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore return empty list
|
||||||
|
return []
|
||||||
client = self.floating_ips_client
|
client = self.floating_ips_client
|
||||||
flips = client.list_floatingips(**self.tenant_filter)
|
flips = client.list_floatingips(**self.tenant_filter)
|
||||||
flips = flips['floatingips']
|
flips = flips['floatingips']
|
||||||
|
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved flips
|
# recreate list removing saved flips
|
||||||
flips = [flip for flip in flips if flip['id']
|
flips = self._filter_out_ids_from_saved(flips, 'floatingips')
|
||||||
not in self.saved_state_json['floatingips'].keys()]
|
|
||||||
LOG.debug("List count, %s Network Floating IPs", len(flips))
|
LOG.debug("List count, %s Network Floating IPs", len(flips))
|
||||||
return flips
|
return flips
|
||||||
|
|
||||||
@ -498,15 +543,15 @@ class NetworkRouterService(BaseNetworkService):
|
|||||||
client = self.routers_client
|
client = self.routers_client
|
||||||
routers = client.list_routers(**self.tenant_filter)
|
routers = client.list_routers(**self.tenant_filter)
|
||||||
routers = routers['routers']
|
routers = routers['routers']
|
||||||
|
if self.prefix:
|
||||||
|
routers = self._filter_by_prefix(routers)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved routers
|
# recreate list removing saved routers
|
||||||
routers = [router for router in routers if router['id']
|
routers = self._filter_out_ids_from_saved(routers, 'routers')
|
||||||
not in self.saved_state_json['routers'].keys()]
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
routers = [router for router in routers
|
routers = [router for router in routers
|
||||||
if router['id'] != CONF_PUB_ROUTER]
|
if router['id'] != CONF_PUB_ROUTER]
|
||||||
|
|
||||||
LOG.debug("List count, %s Routers", len(routers))
|
LOG.debug("List count, %s Routers", len(routers))
|
||||||
return routers
|
return routers
|
||||||
|
|
||||||
@ -547,15 +592,19 @@ class NetworkRouterService(BaseNetworkService):
|
|||||||
class NetworkMeteringLabelRuleService(NetworkService):
|
class NetworkMeteringLabelRuleService(NetworkService):
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore return empty list
|
||||||
|
return []
|
||||||
client = self.metering_label_rules_client
|
client = self.metering_label_rules_client
|
||||||
rules = client.list_metering_label_rules()
|
rules = client.list_metering_label_rules()
|
||||||
rules = rules['metering_label_rules']
|
rules = rules['metering_label_rules']
|
||||||
rules = self._filter_by_tenant_id(rules)
|
rules = self._filter_by_tenant_id(rules)
|
||||||
|
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
saved_rules = self.saved_state_json['metering_label_rules'].keys()
|
rules = self._filter_out_ids_from_saved(
|
||||||
|
rules, 'metering_label_rules')
|
||||||
# recreate list removing saved rules
|
# recreate list removing saved rules
|
||||||
rules = [rule for rule in rules if rule['id'] not in saved_rules]
|
|
||||||
LOG.debug("List count, %s Metering Label Rules", len(rules))
|
LOG.debug("List count, %s Metering Label Rules", len(rules))
|
||||||
return rules
|
return rules
|
||||||
|
|
||||||
@ -589,11 +638,12 @@ class NetworkMeteringLabelService(BaseNetworkService):
|
|||||||
labels = client.list_metering_labels()
|
labels = client.list_metering_labels()
|
||||||
labels = labels['metering_labels']
|
labels = labels['metering_labels']
|
||||||
labels = self._filter_by_tenant_id(labels)
|
labels = self._filter_by_tenant_id(labels)
|
||||||
|
if self.prefix:
|
||||||
if not self.is_save_state:
|
labels = self._filter_by_prefix(labels)
|
||||||
|
elif not self.is_save_state:
|
||||||
# recreate list removing saved labels
|
# recreate list removing saved labels
|
||||||
labels = [label for label in labels if label['id']
|
labels = self._filter_out_ids_from_saved(
|
||||||
not in self.saved_state_json['metering_labels'].keys()]
|
labels, 'metering_labels')
|
||||||
LOG.debug("List count, %s Metering Labels", len(labels))
|
LOG.debug("List count, %s Metering Labels", len(labels))
|
||||||
return labels
|
return labels
|
||||||
|
|
||||||
@ -627,14 +677,14 @@ class NetworkPortService(BaseNetworkService):
|
|||||||
client.list_ports(**self.tenant_filter)['ports']
|
client.list_ports(**self.tenant_filter)['ports']
|
||||||
if port["device_owner"] == "" or
|
if port["device_owner"] == "" or
|
||||||
port["device_owner"].startswith("compute:")]
|
port["device_owner"].startswith("compute:")]
|
||||||
|
if self.prefix:
|
||||||
|
ports = self._filter_by_prefix(ports)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved ports
|
# recreate list removing saved ports
|
||||||
ports = [port for port in ports if port['id']
|
ports = self._filter_out_ids_from_saved(ports, 'ports')
|
||||||
not in self.saved_state_json['ports'].keys()]
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
ports = self._filter_by_conf_networks(ports)
|
ports = self._filter_by_conf_networks(ports)
|
||||||
|
|
||||||
LOG.debug("List count, %s Ports", len(ports))
|
LOG.debug("List count, %s Ports", len(ports))
|
||||||
return ports
|
return ports
|
||||||
|
|
||||||
@ -667,14 +717,16 @@ class NetworkSecGroupService(BaseNetworkService):
|
|||||||
secgroups = [secgroup for secgroup in
|
secgroups = [secgroup for secgroup in
|
||||||
client.list_security_groups(**filter)['security_groups']
|
client.list_security_groups(**filter)['security_groups']
|
||||||
if secgroup['name'] != 'default']
|
if secgroup['name'] != 'default']
|
||||||
|
if self.prefix:
|
||||||
|
secgroups = self._filter_by_prefix(secgroups)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved security_groups
|
# recreate list removing saved security_groups
|
||||||
secgroups = [secgroup for secgroup in secgroups if secgroup['id']
|
secgroups = self._filter_out_ids_from_saved(
|
||||||
not in self.saved_state_json['security_groups'].keys()
|
secgroups, 'security_groups')
|
||||||
]
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
secgroups = [secgroup for secgroup in secgroups
|
secgroups = [
|
||||||
|
secgroup for secgroup in secgroups
|
||||||
if secgroup['security_group_rules'][0]['project_id']
|
if secgroup['security_group_rules'][0]['project_id']
|
||||||
not in CONF_PROJECTS]
|
not in CONF_PROJECTS]
|
||||||
LOG.debug("List count, %s security_groups", len(secgroups))
|
LOG.debug("List count, %s security_groups", len(secgroups))
|
||||||
@ -708,10 +760,12 @@ class NetworkSubnetService(BaseNetworkService):
|
|||||||
client = self.subnets_client
|
client = self.subnets_client
|
||||||
subnets = client.list_subnets(**self.tenant_filter)
|
subnets = client.list_subnets(**self.tenant_filter)
|
||||||
subnets = subnets['subnets']
|
subnets = subnets['subnets']
|
||||||
|
if self.prefix:
|
||||||
|
subnets = self._filter_by_prefix(subnets)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved subnets
|
# recreate list removing saved subnets
|
||||||
subnets = [subnet for subnet in subnets if subnet['id']
|
subnets = self._filter_out_ids_from_saved(subnets, 'subnets')
|
||||||
not in self.saved_state_json['subnets'].keys()]
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
subnets = self._filter_by_conf_networks(subnets)
|
subnets = self._filter_by_conf_networks(subnets)
|
||||||
LOG.debug("List count, %s Subnets", len(subnets))
|
LOG.debug("List count, %s Subnets", len(subnets))
|
||||||
@ -743,10 +797,12 @@ class NetworkSubnetPoolsService(BaseNetworkService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.subnetpools_client
|
client = self.subnetpools_client
|
||||||
pools = client.list_subnetpools(**self.tenant_filter)['subnetpools']
|
pools = client.list_subnetpools(**self.tenant_filter)['subnetpools']
|
||||||
|
if self.prefix:
|
||||||
|
pools = self._filter_by_prefix(pools)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved subnet pools
|
# recreate list removing saved subnet pools
|
||||||
pools = [pool for pool in pools if pool['id']
|
pools = self._filter_out_ids_from_saved(pools, 'subnetpools')
|
||||||
not in self.saved_state_json['subnetpools'].keys()]
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
pools = [pool for pool in pools if pool['project_id']
|
pools = [pool for pool in pools if pool['project_id']
|
||||||
not in CONF_PROJECTS]
|
not in CONF_PROJECTS]
|
||||||
@ -782,11 +838,15 @@ class RegionService(BaseService):
|
|||||||
self.client = manager.regions_client
|
self.client = manager.regions_client
|
||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
|
if self.prefix:
|
||||||
|
# this means we're cleaning resources based on a certain prefix,
|
||||||
|
# this resource doesn't have a name, therefore return empty list
|
||||||
|
return []
|
||||||
client = self.client
|
client = self.client
|
||||||
regions = client.list_regions()
|
regions = client.list_regions()
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
regions = [region for region in regions['regions'] if region['id']
|
regions = self._filter_out_ids_from_saved(
|
||||||
not in self.saved_state_json['regions'].keys()]
|
regions['regions'], 'regions')
|
||||||
LOG.debug("List count, %s Regions", len(regions))
|
LOG.debug("List count, %s Regions", len(regions))
|
||||||
return regions
|
return regions
|
||||||
else:
|
else:
|
||||||
@ -824,11 +884,12 @@ class FlavorService(BaseService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.client
|
client = self.client
|
||||||
flavors = client.list_flavors({"is_public": None})['flavors']
|
flavors = client.list_flavors({"is_public": None})['flavors']
|
||||||
|
if self.prefix:
|
||||||
|
flavors = self._filter_by_prefix(flavors)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
# recreate list removing saved flavors
|
# recreate list removing saved flavors
|
||||||
flavors = [flavor for flavor in flavors if flavor['id']
|
flavors = self._filter_out_ids_from_saved(flavors, 'flavors')
|
||||||
not in self.saved_state_json['flavors'].keys()]
|
|
||||||
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
flavors = [flavor for flavor in flavors
|
flavors = [flavor for flavor in flavors
|
||||||
if flavor['id'] not in CONF_FLAVORS]
|
if flavor['id'] not in CONF_FLAVORS]
|
||||||
@ -871,10 +932,11 @@ class ImageService(BaseService):
|
|||||||
marker = urllib.parse_qs(parsed.query)['marker'][0]
|
marker = urllib.parse_qs(parsed.query)['marker'][0]
|
||||||
response = client.list_images(params={"marker": marker})
|
response = client.list_images(params={"marker": marker})
|
||||||
images.extend(response['images'])
|
images.extend(response['images'])
|
||||||
|
if self.prefix:
|
||||||
|
images = self._filter_by_prefix(images)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
images = [image for image in images if image['id']
|
images = self._filter_out_ids_from_saved(images, 'images')
|
||||||
not in self.saved_state_json['images'].keys()]
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
images = [image for image in images
|
images = [image for image in images
|
||||||
if image['id'] not in CONF_IMAGES]
|
if image['id'] not in CONF_IMAGES]
|
||||||
@ -910,19 +972,17 @@ class UserService(BaseService):
|
|||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
users = self.client.list_users()['users']
|
users = self.client.list_users()['users']
|
||||||
|
if self.prefix:
|
||||||
|
users = self._filter_by_prefix(users)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
users = [user for user in users if user['id']
|
users = self._filter_out_ids_from_saved(users, 'users')
|
||||||
not in self.saved_state_json['users'].keys()]
|
|
||||||
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
users = [user for user in users if user['name']
|
users = [user for user in users if user['name']
|
||||||
not in CONF_USERS]
|
not in CONF_USERS]
|
||||||
|
|
||||||
elif not self.is_save_state: # Never delete admin user
|
elif not self.is_save_state: # Never delete admin user
|
||||||
users = [user for user in users if user['name'] !=
|
users = [user for user in users if user['name'] !=
|
||||||
CONF.auth.admin_username]
|
CONF.auth.admin_username]
|
||||||
|
|
||||||
LOG.debug("List count, %s Users after reconcile", len(users))
|
LOG.debug("List count, %s Users after reconcile", len(users))
|
||||||
return users
|
return users
|
||||||
|
|
||||||
@ -955,12 +1015,13 @@ class RoleService(BaseService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
try:
|
try:
|
||||||
roles = self.client.list_roles()['roles']
|
roles = self.client.list_roles()['roles']
|
||||||
|
if self.prefix:
|
||||||
|
roles = self._filter_by_prefix(roles)
|
||||||
|
elif not self.is_save_state:
|
||||||
# reconcile roles with saved state and never list admin role
|
# reconcile roles with saved state and never list admin role
|
||||||
if not self.is_save_state:
|
roles = self._filter_out_ids_from_saved(roles, 'roles')
|
||||||
roles = [role for role in roles if
|
roles = [role for role in roles
|
||||||
(role['id'] not in
|
if role['name'] != CONF.identity.admin_role]
|
||||||
self.saved_state_json['roles'].keys() and
|
|
||||||
role['name'] != CONF.identity.admin_role)]
|
|
||||||
LOG.debug("List count, %s Roles after reconcile", len(roles))
|
LOG.debug("List count, %s Roles after reconcile", len(roles))
|
||||||
return roles
|
return roles
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -995,18 +1056,17 @@ class ProjectService(BaseService):
|
|||||||
|
|
||||||
def list(self):
|
def list(self):
|
||||||
projects = self.client.list_projects()['projects']
|
projects = self.client.list_projects()['projects']
|
||||||
|
if self.prefix:
|
||||||
|
projects = self._filter_by_prefix(projects)
|
||||||
|
else:
|
||||||
if not self.is_save_state:
|
if not self.is_save_state:
|
||||||
project_ids = self.saved_state_json['projects']
|
projects = self._filter_out_ids_from_saved(
|
||||||
projects = [project
|
projects, 'projects')
|
||||||
for project in projects
|
projects = [project for project in projects
|
||||||
if (project['id'] not in project_ids and
|
if project['name'] != CONF.auth.admin_project_name]
|
||||||
project['name'] != CONF.auth.admin_project_name)]
|
|
||||||
|
|
||||||
if self.is_preserve:
|
if self.is_preserve:
|
||||||
projects = [project
|
projects = [project for project in projects
|
||||||
for project in projects
|
|
||||||
if project['name'] not in CONF_PROJECTS]
|
if project['name'] not in CONF_PROJECTS]
|
||||||
|
|
||||||
LOG.debug("List count, %s Projects after reconcile", len(projects))
|
LOG.debug("List count, %s Projects after reconcile", len(projects))
|
||||||
return projects
|
return projects
|
||||||
|
|
||||||
@ -1039,10 +1099,10 @@ class DomainService(BaseService):
|
|||||||
def list(self):
|
def list(self):
|
||||||
client = self.client
|
client = self.client
|
||||||
domains = client.list_domains()['domains']
|
domains = client.list_domains()['domains']
|
||||||
if not self.is_save_state:
|
if self.prefix:
|
||||||
domains = [domain for domain in domains if domain['id']
|
domains = self._filter_by_prefix(domains)
|
||||||
not in self.saved_state_json['domains'].keys()]
|
elif not self.is_save_state:
|
||||||
|
domains = self._filter_out_ids_from_saved(domains, 'domains')
|
||||||
LOG.debug("List count, %s Domains after reconcile", len(domains))
|
LOG.debug("List count, %s Domains after reconcile", len(domains))
|
||||||
return domains
|
return domains
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ class TestBaseService(base.TestCase):
|
|||||||
'saved_state_json': {'saved': 'data'},
|
'saved_state_json': {'saved': 'data'},
|
||||||
'is_preserve': False,
|
'is_preserve': False,
|
||||||
'is_save_state': True,
|
'is_save_state': True,
|
||||||
|
'prefix': 'tempest',
|
||||||
'tenant_id': 'project_id',
|
'tenant_id': 'project_id',
|
||||||
'got_exceptions': []}
|
'got_exceptions': []}
|
||||||
base = cleanup_service.BaseService(kwargs)
|
base = cleanup_service.BaseService(kwargs)
|
||||||
@ -54,6 +55,7 @@ class TestBaseService(base.TestCase):
|
|||||||
self.assertTrue(base.is_save_state)
|
self.assertTrue(base.is_save_state)
|
||||||
self.assertEqual(base.tenant_filter['project_id'], kwargs['tenant_id'])
|
self.assertEqual(base.tenant_filter['project_id'], kwargs['tenant_id'])
|
||||||
self.assertEqual(base.got_exceptions, kwargs['got_exceptions'])
|
self.assertEqual(base.got_exceptions, kwargs['got_exceptions'])
|
||||||
|
self.assertEqual(base.prefix, kwargs['prefix'])
|
||||||
|
|
||||||
def test_not_implemented_ex(self):
|
def test_not_implemented_ex(self):
|
||||||
kwargs = {'data': {'data': 'test'},
|
kwargs = {'data': {'data': 'test'},
|
||||||
@ -61,6 +63,7 @@ class TestBaseService(base.TestCase):
|
|||||||
'saved_state_json': {'saved': 'data'},
|
'saved_state_json': {'saved': 'data'},
|
||||||
'is_preserve': False,
|
'is_preserve': False,
|
||||||
'is_save_state': False,
|
'is_save_state': False,
|
||||||
|
'prefix': 'tempest',
|
||||||
'tenant_id': 'project_id',
|
'tenant_id': 'project_id',
|
||||||
'got_exceptions': []}
|
'got_exceptions': []}
|
||||||
base = self.TestException(kwargs)
|
base = self.TestException(kwargs)
|
||||||
@ -188,7 +191,8 @@ class BaseCmdServiceTests(MockFunctionsBase):
|
|||||||
service_name = 'default'
|
service_name = 'default'
|
||||||
|
|
||||||
def _create_cmd_service(self, service_type, is_save_state=False,
|
def _create_cmd_service(self, service_type, is_save_state=False,
|
||||||
is_preserve=False, is_dry_run=False):
|
is_preserve=False, is_dry_run=False,
|
||||||
|
prefix=''):
|
||||||
creds = fake_credentials.FakeKeystoneV3Credentials()
|
creds = fake_credentials.FakeKeystoneV3Credentials()
|
||||||
os = clients.Manager(creds)
|
os = clients.Manager(creds)
|
||||||
return getattr(cleanup_service, service_type)(
|
return getattr(cleanup_service, service_type)(
|
||||||
@ -196,6 +200,7 @@ class BaseCmdServiceTests(MockFunctionsBase):
|
|||||||
is_save_state=is_save_state,
|
is_save_state=is_save_state,
|
||||||
is_preserve=is_preserve,
|
is_preserve=is_preserve,
|
||||||
is_dry_run=is_dry_run,
|
is_dry_run=is_dry_run,
|
||||||
|
prefix=prefix,
|
||||||
project_id='b8e3ece07bb049138d224436756e3b57',
|
project_id='b8e3ece07bb049138d224436756e3b57',
|
||||||
data={},
|
data={},
|
||||||
saved_state_json=self.saved_state
|
saved_state_json=self.saved_state
|
||||||
|
@ -58,6 +58,8 @@
|
|||||||
Base integration test with Neutron networking, IPv6 and py3.
|
Base integration test with Neutron networking, IPv6 and py3.
|
||||||
vars:
|
vars:
|
||||||
tox_envlist: full
|
tox_envlist: full
|
||||||
|
run_tempest_cleanup: true
|
||||||
|
run_tempest_cleanup_prefix: true
|
||||||
devstack_localrc:
|
devstack_localrc:
|
||||||
USE_PYTHON3: true
|
USE_PYTHON3: true
|
||||||
FORCE_CONFIG_DRIVE: true
|
FORCE_CONFIG_DRIVE: true
|
||||||
|
Loading…
Reference in New Issue
Block a user