Hacking: enable H904

It's a really cool rule that will avoid suboptimal usage of the
logging library.

Change-Id: I6414624f6b51333d477dd88290158aaeb51b851f
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index d7e01f0..d77ea90 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -139,15 +139,15 @@
                 test_utils.call_and_ignore_notfound_exc(
                     cls.servers_client.delete_server, server['id'])
             except Exception:
-                LOG.exception('Deleting server %s failed' % server['id'])
+                LOG.exception('Deleting server %s failed', server['id'])
 
         for server in cls.servers:
             try:
                 waiters.wait_for_server_termination(cls.servers_client,
                                                     server['id'])
             except Exception:
-                LOG.exception('Waiting for deletion of server %s failed'
-                              % server['id'])
+                LOG.exception('Waiting for deletion of server %s failed',
+                              server['id'])
 
     @classmethod
     def server_check_teardown(cls):
@@ -179,7 +179,7 @@
                 test_utils.call_and_ignore_notfound_exc(
                     cls.compute_images_client.delete_image, image_id)
             except Exception:
-                LOG.exception('Exception raised deleting image %s' % image_id)
+                LOG.exception('Exception raised deleting image %s', image_id)
 
     @classmethod
     def clear_security_groups(cls):
@@ -283,7 +283,7 @@
             volumes_client.wait_for_resource_deletion(volume_id)
         except lib_exc.NotFound:
             LOG.warning("Unable to delete volume '%s' since it was not found. "
-                        "Maybe it was already deleted?" % volume_id)
+                        "Maybe it was already deleted?", volume_id)
 
     @classmethod
     def prepare_instance_network(cls):
@@ -336,7 +336,7 @@
             waiters.wait_for_server_termination(cls.servers_client,
                                                 server_id)
         except Exception:
-            LOG.exception('Failed to delete server %s' % server_id)
+            LOG.exception('Failed to delete server %s', server_id)
 
     @classmethod
     def resize_server(cls, server_id, new_flavor_id, **kwargs):
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 1c9b3f1..cd71de7 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -47,8 +47,8 @@
             waiters.wait_for_server_status(self.servers_client, self.server_id,
                                            'ACTIVE')
         except Exception:
-            LOG.exception('server %s timed out to become ACTIVE. rebuilding'
-                          % self.server_id)
+            LOG.exception('server %s timed out to become ACTIVE. rebuilding',
+                          self.server_id)
             # Rebuild server if cannot reach the ACTIVE state
             # Usually it means the server had a serious accident
             self._reset_server()
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 0a94d5e..0334eff 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -350,7 +350,7 @@
                 else:
                     LOG.warning("Deletion of oldest backup %s should not have "
                                 "been successful as it should have been "
-                                "deleted during rotation." % oldest_backup)
+                                "deleted during rotation.", oldest_backup)
 
         image1_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(_clean_oldest_backup, image1_id)
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 6e57aff..d171cd5 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -42,7 +42,7 @@
             raise self.skipException('There are not any extensions configured')
         # Log extensions list
         extension_list = map(lambda x: x['alias'], extensions)
-        LOG.debug("Nova extensions: %s" % ','.join(extension_list))
+        LOG.debug("Nova extensions: %s", ','.join(extension_list))
 
     @test.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
     @test.requires_ext(extension='os-consoles', service='compute')
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 1edadef..30549ec 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -68,8 +68,8 @@
                                            volume_id, 'available')
         except lib_exc.NotFound:
             LOG.warning("Unable to detach volume %s from server %s "
-                        "possibly it was already detached" % (volume_id,
-                                                              server_id))
+                        "possibly it was already detached", volume_id,
+                        server_id)
 
     def _attach_volume(self, server_id, volume_id, device=None):
         # Attach the volume to the server
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index cce9ace..f044124 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -35,7 +35,7 @@
         if len(CONF.volume_feature_enabled.api_extensions) == 0:
             raise self.skipException('There are not any extensions configured')
         extension_list = [extension.get('alias') for extension in extensions]
-        LOG.debug("Cinder extensions: %s" % ','.join(extension_list))
+        LOG.debug("Cinder extensions: %s", ','.join(extension_list))
         ext = CONF.volume_feature_enabled.api_extensions[0]
         if ext == 'all':
             self.assertIn('Hosts', map(lambda x: x['name'], extensions))
diff --git a/tempest/clients.py b/tempest/clients.py
index 1ab7cfe..48ee59f 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -91,7 +91,7 @@
                         config.service_client_config(service_for_config))
             except lib_exc.UnknownServiceClient:
                 LOG.warning(
-                    'Could not load configuration for service %s' % service)
+                    'Could not load configuration for service %s', service)
 
         return configuration
 
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 3d38e25..172d9e1 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -205,7 +205,7 @@
         os.rename(account_file, '.'.join((account_file, 'bak')))
     with open(account_file, 'w') as f:
         yaml.safe_dump(accounts, f, default_flow_style=False)
-    LOG.info('%s generated successfully!' % account_file)
+    LOG.info('%s generated successfully!', account_file)
 
 
 def _parser_add_args(parser):
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index af86fe3..ec76103 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -149,8 +149,8 @@
 
     def _remove_admin_user_roles(self):
         tenant_ids = self.admin_role_added
-        LOG.debug("Removing admin user roles where needed for tenants: %s"
-                  % tenant_ids)
+        LOG.debug("Removing admin user roles where needed for tenants: %s",
+                  tenant_ids)
         for tenant_id in tenant_ids:
             self._remove_admin_role(tenant_id)
 
@@ -236,13 +236,13 @@
                 needs_role = False
                 LOG.debug("User already had admin privilege for this tenant")
         if needs_role:
-            LOG.debug("Adding admin privilege for : %s" % tenant_id)
+            LOG.debug("Adding admin privilege for : %s", tenant_id)
             rl_cl.create_user_role_on_project(tenant_id, self.admin_id,
                                               self.admin_role_id)
             self.admin_role_added.append(tenant_id)
 
     def _remove_admin_role(self, tenant_id):
-        LOG.debug("Remove admin user role for tenant: %s" % tenant_id)
+        LOG.debug("Remove admin user role for tenant: %s", tenant_id)
         # Must initialize AdminManager for each user role
         # Otherwise authentication exception is thrown, weird
         id_cl = credentials.AdminManager().identity_client
@@ -253,16 +253,16 @@
                                                        self.admin_role_id)
             except Exception as ex:
                 LOG.exception("Failed removing role from tenant which still"
-                              "exists, exception: %s" % ex)
+                              "exists, exception: %s", ex)
 
     def _tenant_exists(self, tenant_id):
         tn_cl = self.admin_mgr.tenants_client
         try:
             t = tn_cl.show_tenant(tenant_id)
-            LOG.debug("Tenant is: %s" % str(t))
+            LOG.debug("Tenant is: %s", str(t))
             return True
         except Exception as ex:
-            LOG.debug("Tenant no longer exists? %s" % ex)
+            LOG.debug("Tenant no longer exists? %s", ex)
             return False
 
     def _init_state(self):
@@ -290,8 +290,8 @@
         except IOError as ex:
             LOG.exception("Failed loading saved state, please be sure you"
                           " have first run cleanup with --init-saved-state "
-                          "flag prior to running tempest. Exception: %s" % ex)
+                          "flag prior to running tempest. Exception: %s", ex)
             sys.exit(ex)
         except Exception as ex:
-            LOG.exception("Exception parsing saved state json : %s" % ex)
+            LOG.exception("Exception parsing saved state json : %s", ex)
             sys.exit(ex)
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 32b0ebb..a632726 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -144,7 +144,7 @@
     def list(self):
         client = self.client
         snaps = client.list_snapshots()['snapshots']
-        LOG.debug("List count, %s Snapshots" % len(snaps))
+        LOG.debug("List count, %s Snapshots", len(snaps))
         return snaps
 
     def delete(self):
@@ -171,7 +171,7 @@
         client = self.client
         servers_body = client.list_servers()
         servers = servers_body['servers']
-        LOG.debug("List count, %s Servers" % len(servers))
+        LOG.debug("List count, %s Servers", len(servers))
         return servers
 
     def delete(self):
@@ -193,7 +193,7 @@
     def list(self):
         client = self.server_groups_client
         sgs = client.list_server_groups()['server_groups']
-        LOG.debug("List count, %s Server Groups" % len(sgs))
+        LOG.debug("List count, %s Server Groups", len(sgs))
         return sgs
 
     def delete(self):
@@ -218,7 +218,7 @@
     def list(self):
         client = self.client
         stacks = client.list_stacks()['stacks']
-        LOG.debug("List count, %s Stacks" % len(stacks))
+        LOG.debug("List count, %s Stacks", len(stacks))
         return stacks
 
     def delete(self):
@@ -243,7 +243,7 @@
     def list(self):
         client = self.client
         keypairs = client.list_keypairs()['keypairs']
-        LOG.debug("List count, %s Keypairs" % len(keypairs))
+        LOG.debug("List count, %s Keypairs", len(keypairs))
         return keypairs
 
     def delete(self):
@@ -270,7 +270,7 @@
         client = self.client
         secgrps = client.list_security_groups()['security_groups']
         secgrp_del = [grp for grp in secgrps if grp['name'] != 'default']
-        LOG.debug("List count, %s Security Groups" % len(secgrp_del))
+        LOG.debug("List count, %s Security Groups", len(secgrp_del))
         return secgrp_del
 
     def delete(self):
@@ -295,7 +295,7 @@
     def list(self):
         client = self.client
         floating_ips = client.list_floating_ips()['floating_ips']
-        LOG.debug("List count, %s Floating IPs" % len(floating_ips))
+        LOG.debug("List count, %s Floating IPs", len(floating_ips))
         return floating_ips
 
     def delete(self):
@@ -320,7 +320,7 @@
     def list(self):
         client = self.client
         vols = client.list_volumes()['volumes']
-        LOG.debug("List count, %s Volumes" % len(vols))
+        LOG.debug("List count, %s Volumes", len(vols))
         return vols
 
     def delete(self):
@@ -402,7 +402,7 @@
         if self.is_preserve:
             networks = [network for network in networks
                         if network['id'] not in CONF_NETWORKS]
-        LOG.debug("List count, %s Networks" % networks)
+        LOG.debug("List count, %s Networks", networks)
         return networks
 
     def delete(self):
@@ -425,7 +425,7 @@
         client = self.floating_ips_client
         flips = client.list_floatingips(**self.tenant_filter)
         flips = flips['floatingips']
-        LOG.debug("List count, %s Network Floating IPs" % len(flips))
+        LOG.debug("List count, %s Network Floating IPs", len(flips))
         return flips
 
     def delete(self):
@@ -452,7 +452,7 @@
             routers = [router for router in routers
                        if router['id'] != CONF_PUB_ROUTER]
 
-        LOG.debug("List count, %s Routers" % len(routers))
+        LOG.debug("List count, %s Routers", len(routers))
         return routers
 
     def delete(self):
@@ -483,7 +483,7 @@
         hms = client.list_health_monitors()
         hms = hms['health_monitors']
         hms = self._filter_by_tenant_id(hms)
-        LOG.debug("List count, %s Health Monitors" % len(hms))
+        LOG.debug("List count, %s Health Monitors", len(hms))
         return hms
 
     def delete(self):
@@ -507,7 +507,7 @@
         members = client.list_members()
         members = members['members']
         members = self._filter_by_tenant_id(members)
-        LOG.debug("List count, %s Members" % len(members))
+        LOG.debug("List count, %s Members", len(members))
         return members
 
     def delete(self):
@@ -531,7 +531,7 @@
         vips = client.list_vips()
         vips = vips['vips']
         vips = self._filter_by_tenant_id(vips)
-        LOG.debug("List count, %s VIPs" % len(vips))
+        LOG.debug("List count, %s VIPs", len(vips))
         return vips
 
     def delete(self):
@@ -555,7 +555,7 @@
         pools = client.list_pools()
         pools = pools['pools']
         pools = self._filter_by_tenant_id(pools)
-        LOG.debug("List count, %s Pools" % len(pools))
+        LOG.debug("List count, %s Pools", len(pools))
         return pools
 
     def delete(self):
@@ -579,7 +579,7 @@
         rules = client.list_metering_label_rules()
         rules = rules['metering_label_rules']
         rules = self._filter_by_tenant_id(rules)
-        LOG.debug("List count, %s Metering Label Rules" % len(rules))
+        LOG.debug("List count, %s Metering Label Rules", len(rules))
         return rules
 
     def delete(self):
@@ -603,7 +603,7 @@
         labels = client.list_metering_labels()
         labels = labels['metering_labels']
         labels = self._filter_by_tenant_id(labels)
-        LOG.debug("List count, %s Metering Labels" % len(labels))
+        LOG.debug("List count, %s Metering Labels", len(labels))
         return labels
 
     def delete(self):
@@ -632,7 +632,7 @@
         if self.is_preserve:
             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
 
     def delete(self):
@@ -660,7 +660,7 @@
 
         if self.is_preserve:
             secgroups = self._filter_by_conf_networks(secgroups)
-        LOG.debug("List count, %s security_groups" % len(secgroups))
+        LOG.debug("List count, %s security_groups", len(secgroups))
         return secgroups
 
     def delete(self):
@@ -685,7 +685,7 @@
         subnets = subnets['subnets']
         if self.is_preserve:
             subnets = self._filter_by_conf_networks(subnets)
-        LOG.debug("List count, %s Subnets" % len(subnets))
+        LOG.debug("List count, %s Subnets", len(subnets))
         return subnets
 
     def delete(self):
@@ -719,7 +719,7 @@
         if self.is_preserve:
             flavors = [flavor for flavor in flavors
                        if flavor['id'] not in CONF_FLAVORS]
-        LOG.debug("List count, %s Flavors after reconcile" % len(flavors))
+        LOG.debug("List count, %s Flavors after reconcile", len(flavors))
         return flavors
 
     def delete(self):
@@ -756,7 +756,7 @@
         if self.is_preserve:
             images = [image for image in images
                       if image['id'] not in CONF_IMAGES]
-        LOG.debug("List count, %s Images after reconcile" % len(images))
+        LOG.debug("List count, %s Images after reconcile", len(images))
         return images
 
     def delete(self):
@@ -806,7 +806,7 @@
             users = [user for user in users if user['name'] !=
                      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
 
     def delete(self):
@@ -843,7 +843,7 @@
                          (role['id'] not in
                           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
         except Exception:
             LOG.exception("Cannot retrieve Roles.")
@@ -885,7 +885,7 @@
             tenants = [tenant for tenant in tenants if tenant['name']
                        not in CONF_TENANTS]
 
-        LOG.debug("List count, %s Tenants after reconcile" % len(tenants))
+        LOG.debug("List count, %s Tenants after reconcile", len(tenants))
         return tenants
 
     def delete(self):
@@ -920,7 +920,7 @@
             domains = [domain for domain in domains if domain['id']
                        not in self.saved_state_json['domains'].keys()]
 
-        LOG.debug("List count, %s Domains after reconcile" % len(domains))
+        LOG.debug("List count, %s Domains after reconcile", len(domains))
         return domains
 
     def delete(self):
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index 99185d2..7634d9e 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -120,7 +120,7 @@
         if os.path.isdir(config_dir):
             shutil.copytree(config_dir, etc_dir)
         else:
-            LOG.warning("Global config dir %s can't be found" % config_dir)
+            LOG.warning("Global config dir %s can't be found", config_dir)
 
     def generate_sample_config(self, local_dir):
         conf_generator = os.path.join(os.path.dirname(__file__),
@@ -131,14 +131,14 @@
                             output_file])
         else:
             LOG.warning("Skipping sample config generation because global "
-                        "config file %s can't be found" % conf_generator)
+                        "config file %s can't be found", conf_generator)
 
     def create_working_dir(self, local_dir, config_dir):
         # make sure we are working with abspath however tempest init is called
         local_dir = os.path.abspath(local_dir)
         # Create local dir if missing
         if not os.path.isdir(local_dir):
-            LOG.debug('Creating local working dir: %s' % local_dir)
+            LOG.debug('Creating local working dir: %s', local_dir)
             os.mkdir(local_dir)
         elif not os.listdir(local_dir) == []:
             raise OSError("Directory you are trying to initialize already "
@@ -151,11 +151,11 @@
         testr_dir = os.path.join(local_dir, '.testrepository')
         # Create lock dir
         if not os.path.isdir(lock_dir):
-            LOG.debug('Creating lock dir: %s' % lock_dir)
+            LOG.debug('Creating lock dir: %s', lock_dir)
             os.mkdir(lock_dir)
         # Create log dir
         if not os.path.isdir(log_dir):
-            LOG.debug('Creating log dir: %s' % log_dir)
+            LOG.debug('Creating log dir: %s', log_dir)
             os.mkdir(log_dir)
         # Create and copy local etc dir
         self.copy_config(etc_dir, config_dir)
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 64543fb..4f2fe67 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -163,8 +163,8 @@
                             clients.servers_client.delete_server(
                                 server['id'])
                         except Exception:
-                            LOG.exception('Deleting server %s failed'
-                                          % server['id'])
+                            LOG.exception('Deleting server %s failed',
+                                          server['id'])
 
     return body, servers
 
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index 2763d16..632a876 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -254,7 +254,7 @@
                 msg = "There was an exception trying to setup network " \
                       "resources for tenant %s, and this error happened " \
                       "trying to clean them up: %s"
-                LOG.warning(msg % (tenant_id, cleanup_exception))
+                LOG.warning(msg, tenant_id, cleanup_exception)
             raise
         return network, subnet, router
 
@@ -316,8 +316,7 @@
                 credentials = self._create_creds(roles=credential_type)
             self._creds[str(credential_type)] = credentials
             # Maintained until tests are ported
-            LOG.info("Acquired dynamic creds:\n credentials: %s"
-                     % credentials)
+            LOG.info("Acquired dynamic creds:\n credentials: %s", credentials)
             if (self.neutron_available and
                 self.create_networks):
                 network, subnet, router = self._create_network_resources(
@@ -325,7 +324,7 @@
                 credentials.set_resources(network=network, subnet=subnet,
                                           router=router)
                 LOG.info("Created isolated network resources for : \n"
-                         + " credentials: %s" % credentials)
+                         + " credentials: %s", credentials)
         return credentials
 
     def get_primary_creds(self):
@@ -356,7 +355,7 @@
         try:
             client.delete_router(router_id)
         except lib_exc.NotFound:
-            LOG.warning('router with name: %s not found for delete' %
+            LOG.warning('router with name: %s not found for delete',
                         router_name)
 
     def _clear_isolated_subnet(self, subnet_id, subnet_name):
@@ -364,7 +363,7 @@
         try:
             client.delete_subnet(subnet_id)
         except lib_exc.NotFound:
-            LOG.warning('subnet with name: %s not found for delete' %
+            LOG.warning('subnet with name: %s not found for delete',
                         subnet_name)
 
     def _clear_isolated_network(self, network_id, network_name):
@@ -372,7 +371,7 @@
         try:
             net_client.delete_network(network_id)
         except lib_exc.NotFound:
-            LOG.warning('network with name: %s not found for delete' %
+            LOG.warning('network with name: %s not found for delete',
                         network_name)
 
     def _cleanup_default_secgroup(self, tenant):
@@ -384,8 +383,8 @@
             try:
                 nsg_client.delete_security_group(secgroup['id'])
             except lib_exc.NotFound:
-                LOG.warning('Security group %s, id %s not found for clean-up' %
-                            (secgroup['name'], secgroup['id']))
+                LOG.warning('Security group %s, id %s not found for clean-up',
+                            secgroup['name'], secgroup['id'])
 
     def _clear_isolated_net_resources(self):
         client = self.routers_admin_client
@@ -405,7 +404,7 @@
                         creds.router['id'],
                         subnet_id=creds.subnet['id'])
                 except lib_exc.NotFound:
-                    LOG.warning('router with name: %s not found for delete' %
+                    LOG.warning('router with name: %s not found for delete',
                                 creds.router['name'])
                 self._clear_isolated_router(creds.router['id'],
                                             creds.router['name'])
@@ -426,7 +425,7 @@
             try:
                 self.creds_client.delete_user(creds.user_id)
             except lib_exc.NotFound:
-                LOG.warning("user with name: %s not found for delete" %
+                LOG.warning("user with name: %s not found for delete",
                             creds.username)
             # NOTE(zhufl): Only when neutron's security_group ext is
             # enabled, _cleanup_default_secgroup will not raise error. But
@@ -437,12 +436,12 @@
                 if self.neutron_available:
                     self._cleanup_default_secgroup(creds.tenant_id)
             except lib_exc.NotFound:
-                LOG.warning("failed to cleanup tenant %s's secgroup" %
+                LOG.warning("failed to cleanup tenant %s's secgroup",
                             creds.tenant_name)
             try:
                 self.creds_client.delete_project(creds.tenant_id)
             except lib_exc.NotFound:
-                LOG.warning("tenant with name: %s not found for delete" %
+                LOG.warning("tenant with name: %s not found for delete",
                             creds.tenant_name)
         self._creds = {}
 
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index f57c18a..f50edbd 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -122,5 +122,5 @@
             params.update({"networks": [{'uuid': network['id']}]})
         else:
             LOG.warning('The provided network dict: %s was invalid and did '
-                        'not contain an id' % network)
+                        'not contain an id', network)
     return params
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 3f68ae8..0b0f692 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -158,8 +158,10 @@
                 if resource == 'network':
                     hash_dict['networks'][temp_hash_key] = resources[resource]
                 else:
-                    LOG.warning('Unknown resource type %s, ignoring this field'
-                                % resource)
+                    LOG.warning(
+                        'Unknown resource type %s, ignoring this field',
+                        resource
+                    )
         return hash_dict
 
     def is_multi_user(self):
@@ -245,7 +247,7 @@
         free_hash = self._get_free_hash(useable_hashes)
         clean_creds = self._sanitize_creds(
             self.hash_dict['creds'][free_hash])
-        LOG.info('%s allocated creds:\n%s' % (self.name, clean_creds))
+        LOG.info('%s allocated creds:\n%s', self.name, clean_creds)
         return self._wrap_creds_with_network(free_hash)
 
     @lockutils.synchronized('test_accounts_io', external=True)
@@ -253,7 +255,7 @@
         hash_path = os.path.join(self.accounts_dir, hash_string)
         if not os.path.isfile(hash_path):
             LOG.warning('Expected an account lock file %s to remove, but '
-                        'one did not exist' % hash_path)
+                        'one did not exist', hash_path)
         else:
             os.remove(hash_path)
             if not os.listdir(self.accounts_dir):
@@ -278,7 +280,7 @@
         _hash = self.get_hash(creds)
         clean_creds = self._sanitize_creds(self.hash_dict['creds'][_hash])
         self.remove_hash(_hash)
-        LOG.info("%s returned allocated creds:\n%s" % (self.name, clean_creds))
+        LOG.info("%s returned allocated creds:\n%s", self.name, clean_creds)
 
     def get_primary_creds(self):
         if self._creds.get('primary'):
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index d8993bb..009812e 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -87,7 +87,7 @@
         # Shell options below add more clearness on failures,
         # path is extended for some non-cirros guest oses (centos7)
         cmd = CONF.validation.ssh_shell_prologue + " " + cmd
-        LOG.debug("Remote command: %s" % cmd)
+        LOG.debug("Remote command: %s", cmd)
         return self.ssh_client.exec_command(cmd)
 
     @debug_ssh
@@ -248,5 +248,5 @@
         except tempest.lib.exceptions.SSHExecCommandFailed:
             LOG.error("Couldn't mke2fs")
             cmd_why = 'sudo ls -lR /dev'
-            LOG.info("Contents of /dev: %s" % self.exec_command(cmd_why))
+            LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
             raise
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index a55ee32..88697c4 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -60,8 +60,7 @@
                 parent_group_id=security_group['id'], ip_protocol='icmp',
                 from_port=-1, to_port=-1)
     LOG.debug("SSH Validation resource security group with tcp and icmp "
-              "rules %s created"
-              % sg_name)
+              "rules %s created", sg_name)
     return security_group
 
 
@@ -73,7 +72,7 @@
             keypair_name = data_utils.rand_name('keypair')
             validation_data.update(os.keypairs_client.create_keypair(
                 name=keypair_name))
-            LOG.debug("Validation resource key %s created" % keypair_name)
+            LOG.debug("Validation resource key %s created", keypair_name)
         add_rule = False
         if validation_resources['security_group']:
             if validation_resources['security_group_rules']:
@@ -98,11 +97,13 @@
             try:
                 keypair_client.delete_keypair(keypair_name)
             except lib_exc.NotFound:
-                LOG.warning("Keypair %s is not found when attempting to delete"
-                            % keypair_name)
+                LOG.warning(
+                    "Keypair %s is not found when attempting to delete",
+                    keypair_name
+                )
             except Exception as exc:
-                LOG.exception('Exception raised while deleting key %s'
-                              % keypair_name)
+                LOG.exception('Exception raised while deleting key %s',
+                              keypair_name)
                 if not has_exception:
                     has_exception = exc
         if 'security_group' in validation_data:
@@ -113,15 +114,15 @@
                 security_group_client.wait_for_resource_deletion(sec_id)
             except lib_exc.NotFound:
                 LOG.warning("Security group %s is not found when attempting "
-                            "to delete" % sec_id)
+                            "to delete", sec_id)
             except lib_exc.Conflict as exc:
                 LOG.exception('Conflict while deleting security '
-                              'group %s VM might not be deleted ' % sec_id)
+                              'group %s VM might not be deleted', sec_id)
                 if not has_exception:
                     has_exception = exc
             except Exception as exc:
                 LOG.exception('Exception raised while deleting security '
-                              'group %s ' % sec_id)
+                              'group %s', sec_id)
                 if not has_exception:
                     has_exception = exc
         if 'floating_ip' in validation_data:
@@ -131,10 +132,9 @@
                 floating_client.delete_floating_ip(fip_id)
             except lib_exc.NotFound:
                 LOG.warning('Floating ip %s not found while attempting to '
-                            'delete' % fip_id)
+                            'delete', fip_id)
             except Exception as exc:
-                LOG.exception('Exception raised while deleting ip %s '
-                              % fip_id)
+                LOG.exception('Exception raised while deleting ip %s', fip_id)
                 if not has_exception:
                     has_exception = exc
     if has_exception:
diff --git a/tempest/config.py b/tempest/config.py
index 9e03b7f..a922367 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1166,7 +1166,7 @@
 
         logging.setup(_CONF, 'tempest')
         LOG = logging.getLogger('tempest')
-        LOG.info("Using tempest config file %s" % path)
+        LOG.info("Using tempest config file %s", path)
         register_opts()
         self._set_attrs()
         if parse_conf:
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index 72a15b5..5d7fbe3 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -54,7 +54,7 @@
     cmd = ' '.join([prefix, os.path.join(cli_dir, cmd),
                     flags, action, params])
     cmd = cmd.strip()
-    LOG.info("running: '%s'" % cmd)
+    LOG.info("running: '%s'", cmd)
     if six.PY2:
         cmd = cmd.encode('utf-8')
     cmd = shlex.split(cmd)
diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py
index 0313505..c71c7a7 100644
--- a/tempest/lib/cli/output_parser.py
+++ b/tempest/lib/cli/output_parser.py
@@ -112,7 +112,7 @@
             if label is None:
                 label = line
             else:
-                LOG.warning('Invalid line between tables: %s' % line)
+                LOG.warning('Invalid line between tables: %s', line)
     if len(table_) > 0:
         LOG.warning('Missing end of table')
 
@@ -140,7 +140,7 @@
             columns = _table_columns(line)
             continue
         if '|' not in line:
-            LOG.warning('skipping invalid table line: %s' % line)
+            LOG.warning('skipping invalid table line: %s', line)
             continue
         row = []
         for col in columns:
diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py
index 3f10dee..ea06011 100644
--- a/tempest/lib/common/cred_client.py
+++ b/tempest/lib/common/cred_client.py
@@ -78,8 +78,8 @@
                                                           user['id'],
                                                           role['id'])
         except lib_exc.Conflict:
-            LOG.debug("Role %s already assigned on project %s for user %s" % (
-                role['id'], project['id'], user['id']))
+            LOG.debug("Role %s already assigned on project %s for user %s",
+                      role['id'], project['id'], user['id'])
 
     @abc.abstractmethod
     def get_credentials(self, user, project, password):
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 2d2771f..31d2ba5 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -406,8 +406,8 @@
     def _log_request_start(self, method, req_url):
         caller_name = test_utils.find_test_caller()
         if self.trace_requests and re.search(self.trace_requests, caller_name):
-            self.LOG.debug('Starting Request (%s): %s %s' %
-                           (caller_name, method, req_url))
+            self.LOG.debug('Starting Request (%s): %s %s', caller_name,
+                           method, req_url)
 
     def _log_request_full(self, resp, req_headers=None, req_body=None,
                           resp_body=None, extra=None):
@@ -423,11 +423,11 @@
         Body: %s"""
 
         self.LOG.debug(
-            log_fmt % (
-                str(req_headers),
-                self._safe_body(req_body),
-                str(resp_log),
-                self._safe_body(resp_body)),
+            log_fmt,
+            str(req_headers),
+            self._safe_body(req_body),
+            str(resp_log),
+            self._safe_body(resp_body),
             extra=extra)
 
     def _log_request(self, method, req_url, resp,
@@ -445,12 +445,12 @@
         if secs:
             secs = " %.3fs" % secs
         self.LOG.info(
-            'Request (%s): %s %s %s%s' % (
-                caller_name,
-                resp['status'],
-                method,
-                req_url,
-                secs),
+            'Request (%s): %s %s %s%s',
+            caller_name,
+            resp['status'],
+            method,
+            req_url,
+            secs,
             extra=extra)
 
         # Also look everything at DEBUG if you want to filter this
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
index 3b28701..bd0db7c 100644
--- a/tempest/lib/common/utils/test_utils.py
+++ b/tempest/lib/common/utils/test_utils.py
@@ -74,7 +74,7 @@
     # prevents frame leaks
     del frame
     if caller_name is None:
-        LOG.debug("Sane call name not found in %s" % names)
+        LOG.debug("Sane call name not found in %s", names)
     return caller_name
 
 
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index 0e8e3c6..e5497d2 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -373,7 +373,7 @@
                 except Exception:
                     LOG.exception(
                         'Failed to register service client from plugin %s '
-                        'with parameters %s' % (plugin, service_client))
+                        'with parameters %s', plugin, service_client)
                     raise
 
     def register_service_client_module(self, name, service_version,
diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py
index a5d7c86..c4fd483 100644
--- a/tempest/lib/services/identity/v2/token_client.py
+++ b/tempest/lib/services/identity/v2/token_client.py
@@ -117,8 +117,8 @@
     LOG = logging.getLogger(__name__)
 
     def _warn(self):
-        self.LOG.warning("%s class was deprecated and renamed to %s" %
-                         (self.__class__.__name__, 'TokenClient'))
+        self.LOG.warning("%s class was deprecated and renamed to %s",
+                         self.__class__.__name__, 'TokenClient')
 
     def __init__(self, *args, **kwargs):
         self._warn()
diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py
index c1f7e7b..06927f4 100644
--- a/tempest/lib/services/identity/v3/token_client.py
+++ b/tempest/lib/services/identity/v3/token_client.py
@@ -179,8 +179,8 @@
     LOG = logging.getLogger(__name__)
 
     def _warn(self):
-        self.LOG.warning("%s class was deprecated and renamed to %s" %
-                         (self.__class__.__name__, 'V3TokenClient'))
+        self.LOG.warning("%s class was deprecated and renamed to %s",
+                         self.__class__.__name__, 'V3TokenClient')
 
     def __init__(self, *args, **kwargs):
         self._warn()
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 376dd19..052f175 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -380,9 +380,9 @@
         img_disk_format = CONF.scenario.img_disk_format
         img_properties = CONF.scenario.img_properties
         LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
-                  "properties: %s, ami: %s, ari: %s, aki: %s" %
-                  (img_path, img_container_format, img_disk_format,
-                   img_properties, ami_img_path, ari_img_path, aki_img_path))
+                  "properties: %s, ami: %s, ari: %s, aki: %s",
+                  img_path, img_container_format, img_disk_format,
+                  img_properties, ami_img_path, ari_img_path, aki_img_path)
         try:
             image = self._image_create('scenario-img',
                                        img_container_format,
@@ -397,7 +397,7 @@
             image = self._image_create('scenario-ami', 'ami',
                                        path=ami_img_path,
                                        properties=properties)
-        LOG.debug("image:%s" % image)
+        LOG.debug("image:%s", image)
 
         return image
 
@@ -530,14 +530,14 @@
 
         caller = test_utils.find_test_caller()
         LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
-                  ' expected result is %(should_succeed)s' % {
+                  ' expected result is %(should_succeed)s', **{
                       'caller': caller, 'ip': ip_address, 'timeout': timeout,
                       'should_succeed':
                       'reachable' if should_succeed else 'unreachable'
                   })
         result = test_utils.call_until_true(ping, timeout, 1)
         LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
-                  'ping result is %(result)s' % {
+                  'ping result is %(result)s', **{
                       'caller': caller, 'ip': ip_address, 'timeout': timeout,
                       'result': 'expected' if result else 'unexpected'
                   })
@@ -578,8 +578,8 @@
                                           msg=None, servers=None, mtu=None):
         # The target login is assumed to have been configured for
         # key-based authentication by cloud-init.
-        LOG.debug('checking network connections to IP %s with user: %s' %
-                  (ip_address, username))
+        LOG.debug('checking network connections to IP %s with user: %s',
+                  ip_address, username)
         try:
             self.check_vm_connectivity(ip_address,
                                        username,
@@ -948,7 +948,7 @@
                 source.ping_host(dest, nic=nic)
             except lib_exc.SSHExecCommandFailed:
                 LOG.warning('Failed to ping IP: %s via a ssh connection '
-                            'from: %s.' % (dest, source.ssh_client.host))
+                            'from: %s.', dest, source.ssh_client.host)
                 return not should_succeed
             return should_succeed
 
@@ -1315,7 +1315,7 @@
         self.container_client.create_container(name)
         # look for the container to assure it is created
         self.list_and_check_container_objects(name)
-        LOG.debug('Container %s created' % (name))
+        LOG.debug('Container %s created', name)
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.container_client.delete_container,
                         name)
@@ -1323,7 +1323,7 @@
 
     def delete_container(self, container_name):
         self.container_client.delete_container(container_name)
-        LOG.debug('Container %s deleted' % (container_name))
+        LOG.debug('Container %s deleted', container_name)
 
     def upload_object_to_container(self, container_name, obj_name=None):
         obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index dff00e7..b10be11 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -86,7 +86,7 @@
 
         def _func():
             disks = ssh.get_disks()
-            LOG.debug("Disks: %s" % disks)
+            LOG.debug("Disks: %s", disks)
             return CONF.compute.volume_device_name in disks
 
         if not test_utils.call_until_true(_func,
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 46aebfe..2c8b618 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -118,36 +118,36 @@
         volume_origin = self._create_volume_from_image()
         instance_1st = self._boot_instance_from_volume(volume_origin['id'],
                                                        keypair, security_group)
-        LOG.info("Booted first instance: %s" % instance_1st)
+        LOG.info("Booted first instance: %s", instance_1st)
 
         # write content to volume on instance
-        LOG.info("Setting timestamp in instance %s" % instance_1st)
+        LOG.info("Setting timestamp in instance %s", instance_1st)
         ip_instance_1st = self.get_server_ip(instance_1st)
         timestamp = self.create_timestamp(ip_instance_1st,
                                           private_key=keypair['private_key'])
 
         # delete instance
-        LOG.info("Deleting first instance: %s" % instance_1st)
+        LOG.info("Deleting first instance: %s", instance_1st)
         self._delete_server(instance_1st)
 
         # create a 2nd instance from volume
         instance_2nd = self._boot_instance_from_volume(volume_origin['id'],
                                                        keypair, security_group)
-        LOG.info("Booted second instance %s" % instance_2nd)
+        LOG.info("Booted second instance %s", instance_2nd)
 
         # check the content of written file
-        LOG.info("Getting timestamp in instance %s" % instance_2nd)
+        LOG.info("Getting timestamp in instance %s", instance_2nd)
         ip_instance_2nd = self.get_server_ip(instance_2nd)
         timestamp2 = self.get_timestamp(ip_instance_2nd,
                                         private_key=keypair['private_key'])
         self.assertEqual(timestamp, timestamp2)
 
         # snapshot a volume
-        LOG.info("Creating snapshot from volume: %s" % volume_origin['id'])
+        LOG.info("Creating snapshot from volume: %s", volume_origin['id'])
         snapshot = self._create_snapshot_from_volume(volume_origin['id'])
 
         # create a 3rd instance from snapshot
-        LOG.info("Creating third instance from snapshot: %s" % snapshot['id'])
+        LOG.info("Creating third instance from snapshot: %s", snapshot['id'])
         volume = self.create_volume(snapshot_id=snapshot['id'],
                                     size=snapshot['size'])
         LOG.info("Booting third instance from snapshot")
@@ -157,7 +157,7 @@
         LOG.info("Booted third instance %s", server_from_snapshot)
 
         # check the content of written file
-        LOG.info("Logging into third instance to get timestamp: %s" %
+        LOG.info("Logging into third instance to get timestamp: %s",
                  server_from_snapshot)
         server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
         timestamp3 = self.get_timestamp(server_from_snapshot_ip,
diff --git a/tempest/test.py b/tempest/test.py
index 4cc2a2b..17dc94c 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -156,7 +156,7 @@
                 if status_code is None or status_code == exc_status_code:
                     LOG.error('Hints: This test was made for the bug %s. '
                               'The failure could be related to '
-                              'https://launchpad.net/bugs/%s' % (bug, bug))
+                              'https://launchpad.net/bugs/%s', bug, bug)
                 raise exc
         return wrapper
     return decorator
@@ -263,8 +263,8 @@
             cls.resource_setup()
         except Exception:
             etype, value, trace = sys.exc_info()
-            LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass." % (
-                     etype, cls.__name__))
+            LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
+                     etype, cls.__name__)
             cls.tearDownClass()
             try:
                 six.reraise(etype, value, trace)
@@ -296,9 +296,9 @@
                 # resources that were successfully setup in resource_cleanup,
                 # log AttributeError as info instead of exception.
                 if tetype is AttributeError and name == 'resources':
-                    LOG.info("tearDownClass of %s failed: %s" % (name, te))
+                    LOG.info("tearDownClass of %s failed: %s", name, te)
                 else:
-                    LOG.exception("teardown of %s failed: %s" % (name, te))
+                    LOG.exception("teardown of %s failed: %s", name, te)
                 if not etype:
                     etype, value, trace = sys_exec_info
         # If exceptions were raised during teardown, and not before, re-raise
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index f8d5d9d..e9f59af 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -143,7 +143,7 @@
                 plug.obj.register_opts(conf)
             except Exception:
                 LOG.exception('Plugin %s raised an exception trying to run '
-                              'register_opts' % plug.name)
+                              'register_opts', plug.name)
 
     def get_plugin_options_list(self):
         plugin_options = []
@@ -163,4 +163,4 @@
                         plug.name, service_clients)
             except Exception:
                 LOG.exception('Plugin %s raised an exception trying to run '
-                              'get_service_clients' % plug.name)
+                              'get_service_clients', plug.name)
diff --git a/tox.ini b/tox.ini
index 7a36e84..46823d8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -146,7 +146,7 @@
 ignore = E125,E123,E129
 show-source = True
 exclude = .git,.venv,.tox,dist,doc,*egg
-enable-extensions = H106,H203
+enable-extensions = H106,H203,H904
 
 [testenv:releasenotes]
 commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html