From c9c958a11eabe9d9caba26df65187c75edc36b78 Mon Sep 17 00:00:00 2001
From: Robert Kukura <kukura@noironetworks.com>
Date: Tue, 16 Jun 2015 10:21:36 -0400
Subject: [PATCH] Support ServiceProfile resource and new attributes

Adds support for the ServiceProfile resource, for the ServiceChainNode
resource's service_profile_id attribute, and for the shared attribute
of the ServiceChainNode and ServiceChainSpec resources.

Also updates test_requirements.txt to use the current hacking version,
and disables checks that fail. These will need to addressed in a
separate patch.

Partially implements blueprint node-centric-chain-plugin

Change-Id: I62b59b878138d3d9ad5d340a0b8f7ff0b74a39a5
---
 gbpclient/gbp/v2_0/servicechain.py            | 139 +++++++++++++-
 gbpclient/gbpshell.py                         |   5 +
 .../tests/unit/test_cli20_service_profile.py  | 170 ++++++++++++++++++
 .../unit/test_cli20_servicechain_node.py      |  28 ++-
 .../unit/test_cli20_servicechain_spec.py      |  16 +-
 gbpclient/v2_0/client.py                      |  34 ++++
 test-requirements.txt                         |   2 +-
 tox.ini                                       |   5 +-
 8 files changed, 387 insertions(+), 12 deletions(-)
 create mode 100644 gbpclient/tests/unit/test_cli20_service_profile.py

diff --git a/gbpclient/gbp/v2_0/servicechain.py b/gbpclient/gbp/v2_0/servicechain.py
index d832628..63fca55 100644
--- a/gbpclient/gbp/v2_0/servicechain.py
+++ b/gbpclient/gbp/v2_0/servicechain.py
@@ -147,6 +147,107 @@ class DeleteServiceChainInstance(neutronV20.DeleteCommand):
     log = logging.getLogger(__name__ + '.DeleteServiceChainInstance')
 
 
+class ListServiceProfile(neutronV20.ListCommand):
+    """List service profiles that belong to a given tenant."""
+
+    resource = 'service_profile'
+    log = logging.getLogger(__name__ + '.ListServiceProfile')
+    _formatters = {}
+    list_columns = ['id', 'name', 'description', 'service_type']
+    pagination_support = True
+    sorting_support = True
+
+
+class ShowServiceProfile(neutronV20.ShowCommand):
+    """Show information of a given service profile."""
+
+    resource = 'service_profile'
+    log = logging.getLogger(__name__ + '.ShowServiceProfile')
+
+
+class CreateServiceProfile(neutronV20.CreateCommand):
+    """Create a service profile."""
+
+    resource = 'service_profile'
+    log = logging.getLogger(__name__ + '.CreateServiceProfile')
+
+    def add_known_arguments(self, parser):
+        parser.add_argument(
+            'name',
+            help=_('Name for the Service Profile.'))
+        parser.add_argument(
+            '--description',
+            help=_('Description of the Service Profile.'))
+        parser.add_argument(
+            '--shared', type=bool,
+            help=_('Shared flag'))
+        parser.add_argument(
+            '--vendor',
+            help=_('Vendor providing the service node'))
+        parser.add_argument(
+            '--insertion-mode',
+            help=_('Insertion mode of the service'))
+        parser.add_argument(
+            '--servicetype', dest='service_type',
+            help=_('Type of the service'))
+        parser.add_argument(
+            '--service-flavor',
+            help=_('Flavor of the service'))
+
+    def args2body(self, parsed_args):
+        body = {self.resource: {}, }
+        neutronV20.update_dict(parsed_args, body[self.resource],
+                               ['name', 'description', 'tenant_id', 'shared',
+                                'vendor', 'insertion_mode', 'service_type',
+                                'service_flavor'])
+        return body
+
+
+class UpdateServiceProfile(neutronV20.UpdateCommand):
+    """Update a given service profile."""
+
+    resource = 'service_profile'
+    log = logging.getLogger(__name__ + '.UpdateServiceProfile')
+
+    def add_known_arguments(self, parser):
+        parser.add_argument(
+            '--name',
+            help=_('Name for the Service Profile.'))
+        parser.add_argument(
+            '--description',
+            help=_('Description of the Service Profile.'))
+        parser.add_argument(
+            '--shared', type=bool,
+            help=_('Shared flag'))
+        parser.add_argument(
+            '--vendor',
+            help=_('Vendor providing the service node'))
+        parser.add_argument(
+            '--insertion-mode',
+            help=_('Insertion mode of the service'))
+        parser.add_argument(
+            '--servicetype', dest='service_type',
+            help=_('Type of the service'))
+        parser.add_argument(
+            '--service-flavor',
+            help=_('Flavor of the service'))
+
+    def args2body(self, parsed_args):
+        body = {self.resource: {}, }
+        neutronV20.update_dict(parsed_args, body[self.resource],
+                               ['name', 'description', 'shared', 'vendor',
+                                'insertion_mode', 'service_type',
+                                'service_flavor'])
+        return body
+
+
+class DeleteServiceProfile(neutronV20.DeleteCommand):
+    """Delete a given service profile."""
+
+    resource = 'service_profile'
+    log = logging.getLogger(__name__ + '.DeleteServiceProfile')
+
+
 class ListServiceChainNode(neutronV20.ListCommand):
     """List service chain nodes that belong to a given tenant."""
 
@@ -181,9 +282,15 @@ class CreateServiceChainNode(neutronV20.CreateCommand):
         parser.add_argument(
             '--servicetype', dest='service_type',
             help=_('Service type ID or the Service Type name'))
+        parser.add_argument(
+            '--service-profile',
+            help=_('Service Profile name or UUID'))
         parser.add_argument(
             '--config',
             help=_('Service Configuration for the Service Chain Node.'))
+        parser.add_argument(
+            '--shared', type=bool,
+            help=_('Shared flag'))
         parser.add_argument(
             '--template-file',
             help=_('Service Configuration Template for the Service Chain '
@@ -195,6 +302,11 @@ class CreateServiceChainNode(neutronV20.CreateCommand):
 
     def args2body(self, parsed_args):
         body = {self.resource: {}, }
+        if parsed_args.service_profile:
+            body[self.resource]['service_profile_id'] = \
+                neutronV20.find_resourceid_by_name_or_id(
+                    self.get_client(), 'service_profile',
+                    parsed_args.service_profile)
         if parsed_args.template_file:
             if os.path.isfile(parsed_args.template_file):
                 tpl_files, template = template_utils.get_template_contents(
@@ -205,7 +317,7 @@ class CreateServiceChainNode(neutronV20.CreateCommand):
                                                  "Please check the path"
                                                  % parsed_args.template_file)
         neutronV20.update_dict(parsed_args, body[self.resource],
-                               ['name', 'service_type', 'config',
+                               ['name', 'service_type', 'config', 'shared',
                                 'tenant_id', 'param_names', 'description'])
         return body
 
@@ -220,15 +332,26 @@ class UpdateServiceChainNode(neutronV20.UpdateCommand):
         parser.add_argument(
             '--servicetype', dest='service_type',
             help=_('Service type ID or the Service Type name'))
+        parser.add_argument(
+            '--service-profile',
+            help=_('Service Profile name or UUID'))
         parser.add_argument(
             '--config',
             help=_('Service Configuration for the Service Chain Node.'))
+        parser.add_argument(
+            '--shared', type=bool,
+            help=_('Shared flag'))
 
     def args2body(self, parsed_args):
         body = {self.resource: {}, }
+        if parsed_args.service_profile:
+            body[self.resource]['service_profile_id'] = \
+                neutronV20.find_resourceid_by_name_or_id(
+                    self.get_client(), 'service_profile',
+                    parsed_args.service_profile)
         neutronV20.update_dict(parsed_args, body[self.resource],
-                               ['name', 'service_type', 'config',
-                                'tenant_id', 'description'])
+                               ['name', 'service_type', 'config', 'shared',
+                                'description'])
         return body
 
 
@@ -273,6 +396,9 @@ class CreateServiceChainSpec(neutronV20.CreateCommand):
         parser.add_argument(
             '--nodes', metavar='NODES', type=string.split,
             help=_('Service Chain Node ID or name of the Service Chain Node'))
+        parser.add_argument(
+            '--shared', type=bool,
+            help=_('Shared flag'))
 
     def args2body(self, parsed_args):
         body = {self.resource: {}, }
@@ -285,7 +411,7 @@ class CreateServiceChainSpec(neutronV20.CreateCommand):
                     elem) for elem in parsed_args.nodes]
 
         neutronV20.update_dict(parsed_args, body[self.resource],
-                               ['name', 'tenant_id', 'description'])
+                               ['name', 'tenant_id', 'description', 'shared'])
         return body
 
 
@@ -300,6 +426,9 @@ class UpdateServiceChainSpec(neutronV20.UpdateCommand):
             '--nodes', type=string.split,
             help=_('List of Service Chain Node IDs or names of the Service '
                    'Chain Nodes'))
+        parser.add_argument(
+            '--shared', type=bool,
+            help=_('Shared flag'))
 
     def args2body(self, parsed_args):
         body = {self.resource: {}, }
@@ -309,6 +438,8 @@ class UpdateServiceChainSpec(neutronV20.UpdateCommand):
                     self.get_client(),
                     'servicechain_node',
                     elem) for elem in parsed_args.nodes]
+        neutronV20.update_dict(parsed_args, body[self.resource],
+                               ['name', 'description', 'shared'])
         return body
 
 
diff --git a/gbpclient/gbpshell.py b/gbpclient/gbpshell.py
index d5a335e..ba84f7c 100644
--- a/gbpclient/gbpshell.py
+++ b/gbpclient/gbpshell.py
@@ -152,6 +152,11 @@ COMMAND_V2 = {
     'policy-rule-set-update': gbp.UpdatePolicyRuleSet,
     'policy-rule-set-list': gbp.ListPolicyRuleSet,
     'policy-rule-set-show': gbp.ShowPolicyRuleSet,
+    'service-profile-list': servicechain.ListServiceProfile,
+    'service-profile-show': servicechain.ShowServiceProfile,
+    'service-profile-create': servicechain.CreateServiceProfile,
+    'service-profile-delete': servicechain.DeleteServiceProfile,
+    'service-profile-update': servicechain.UpdateServiceProfile,
     'servicechain-node-list': servicechain.ListServiceChainNode,
     'servicechain-node-show': servicechain.ShowServiceChainNode,
     'servicechain-node-create': servicechain.CreateServiceChainNode,
diff --git a/gbpclient/tests/unit/test_cli20_service_profile.py b/gbpclient/tests/unit/test_cli20_service_profile.py
new file mode 100644
index 0000000..540c02d
--- /dev/null
+++ b/gbpclient/tests/unit/test_cli20_service_profile.py
@@ -0,0 +1,170 @@
+# Copyright 2015 OpenStack Foundation.
+# All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+#
+
+import sys
+
+from gbpclient.gbp.v2_0 import servicechain
+from gbpclient.tests.unit import test_cli20
+
+
+class CLITestV20ServiceProfileJSON(test_cli20.CLITestV20Base):
+    def setUp(self):
+        super(CLITestV20ServiceProfileJSON, self).setUp()
+
+    def test_create_service_profile_with_mandatory_params(self):
+        """service-profile-create with all mandatory params."""
+        resource = 'service_profile'
+        cmd = servicechain.CreateServiceProfile(test_cli20.MyApp(sys.stdout),
+                                                None)
+        name = 'my-name'
+        tenant_id = 'my-tenant'
+        my_id = 'my-id'
+        args = ['--tenant-id', tenant_id, name]
+        position_names = ['name', ]
+        position_values = [name, ]
+        self._test_create_resource(resource, cmd, name, my_id, args,
+                                   position_names, position_values,
+                                   tenant_id=tenant_id)
+
+    def test_create_service_profile_with_all_params(self):
+        """service-profile-create with all params."""
+        resource = 'service_profile'
+        cmd = servicechain.CreateServiceProfile(test_cli20.MyApp(sys.stdout),
+                                                None)
+        name = 'my-name'
+        description = 'My Service Profile'
+        tenant_id = 'my-tenant'
+        shared = 'True'
+        vendor = 'vendor'
+        insertion_mode = 'some mode'
+        service_type = 'servicetype1'
+        service_flavor = 'cherry-garcia'
+        my_id = 'my-id'
+        args = ['--description', description,
+                '--tenant-id', tenant_id,
+                '--shared', shared,
+                '--vendor', vendor,
+                '--insertion-mode', insertion_mode,
+                '--servicetype', service_type,
+                '--service-flavor', service_flavor,
+                name]
+        position_names = ['name', ]
+        position_values = [name, ]
+        self._test_create_resource(resource, cmd, name, my_id, args,
+                                   position_names, position_values,
+                                   description=description,
+                                   tenant_id=tenant_id,
+                                   shared=True,
+                                   vendor=vendor,
+                                   insertion_mode=insertion_mode,
+                                   service_type=service_type,
+                                   service_flavor=service_flavor)
+
+    def test_list_service_profiles(self):
+        """service-profile-list."""
+        resources = 'service_profiles'
+        cmd = servicechain.ListServiceProfile(test_cli20.MyApp(sys.stdout),
+                                              None)
+        self._test_list_resources(resources, cmd, True)
+
+    def test_list_service_profiles_pagination(self):
+        """service-profile-list."""
+        resources = 'service_profiles'
+        cmd = servicechain.ListServiceProfile(test_cli20.MyApp(sys.stdout),
+                                              None)
+        self._test_list_resources_with_pagination(resources, cmd)
+
+    def test_list_service_profiles_sort(self):
+        """service-profile-list --sort-key name --sort-key id --sort-key asc
+        --sort-key desc
+        """
+        resources = 'service_profiles'
+        cmd = servicechain.ListServiceProfile(test_cli20.MyApp(sys.stdout),
+                                              None)
+        self._test_list_resources(resources, cmd,
+                                  sort_key=["name", "id"],
+                                  sort_dir=["asc", "desc"])
+
+    def test_list_service_profiles_limit(self):
+        """service-profile-list -P."""
+        resources = 'service_profiles'
+        cmd = servicechain.ListServiceProfile(test_cli20.MyApp(sys.stdout),
+                                              None)
+        self._test_list_resources(resources, cmd, page_size=1000)
+
+    def test_show_service_profile_id(self):
+        """service-profile-show test_id."""
+        resource = 'service_profile'
+        cmd = servicechain.ShowServiceProfile(test_cli20.MyApp(sys.stdout),
+                                              None)
+        args = ['--fields', 'id', self.test_id]
+        self._test_show_resource(resource, cmd, self.test_id, args, ['id'])
+
+    def test_show_service_profile_id_name(self):
+        """service-profile-show."""
+        resource = 'service_profile'
+        cmd = servicechain.ShowServiceProfile(test_cli20.MyApp(sys.stdout),
+                                              None)
+        args = ['--fields', 'id', '--fields', 'name', self.test_id]
+        self._test_show_resource(resource, cmd, self.test_id,
+                                 args, ['id', 'name'])
+
+    def test_update_service_profile(self):
+        """service-profile-update  myid --name myname --tags a b."""
+        resource = 'service_profile'
+        cmd = servicechain.UpdateServiceProfile(test_cli20.MyApp(sys.stdout),
+                                                None)
+        self._test_update_resource(resource, cmd, 'myid',
+                                   ['myid', '--name', 'myname',
+                                    '--tags', 'a', 'b'],
+                                   {'name': 'myname', 'tags': ['a', 'b'], })
+
+    def test_update_service_profile_with_all_params(self):
+        resource = 'service_profile'
+        cmd = servicechain.UpdateServiceProfile(test_cli20.MyApp(sys.stdout),
+                                                None)
+        name = 'new-name'
+        description = 'My Updated Service Profile'
+        shared = 'True'
+        vendor = 'open-source'
+        insertion_mode = 'another mode'
+        service_type = 'servicetype2'
+        service_flavor = 'phish-food'
+        body = {
+            'name': name,
+            'description': description,
+            'shared': True,
+            'vendor': vendor,
+            'insertion_mode': insertion_mode,
+            'service_type': service_type,
+            'service_flavor': service_flavor}
+        args = ['myid', '--name', name,
+                '--description', description,
+                '--shared', shared,
+                '--vendor', vendor,
+                '--insertion-mode', insertion_mode,
+                '--servicetype', service_type,
+                '--service-flavor', service_flavor]
+        self._test_update_resource(resource, cmd, 'myid', args, body)
+
+    def test_delete_service_profile(self):
+        """service-profile-delete my-id."""
+        resource = 'service_profile'
+        cmd = servicechain.DeleteServiceProfile(test_cli20.MyApp(sys.stdout),
+                                                None)
+        my_id = 'my-id'
+        args = [my_id]
+        self._test_delete_resource(resource, cmd, my_id, args)
diff --git a/gbpclient/tests/unit/test_cli20_servicechain_node.py b/gbpclient/tests/unit/test_cli20_servicechain_node.py
index b10dda6..7b85f75 100644
--- a/gbpclient/tests/unit/test_cli20_servicechain_node.py
+++ b/gbpclient/tests/unit/test_cli20_servicechain_node.py
@@ -49,11 +49,15 @@ class CLITestV20ServiceChainNodeJSON(test_cli20.CLITestV20Base):
         config = 'config1'
         tenant_id = 'my-tenant'
         description = 'My Service Chain Node'
+        service_profile_id = 'my-service-profile'
         my_id = 'my-id'
+        shared = 'True'
         args = ['--servicetype', service_type,
                 '--config', config,
                 '--tenant-id', tenant_id,
                 '--description', description,
+                '--service-profile', service_profile_id,
+                '--shared', shared,
                 name]
         position_names = ['name', ]
         position_values = [name, ]
@@ -61,7 +65,9 @@ class CLITestV20ServiceChainNodeJSON(test_cli20.CLITestV20Base):
                                    position_names, position_values,
                                    service_type=service_type, config=config,
                                    tenant_id=tenant_id,
-                                   description=description)
+                                   description=description,
+                                   service_profile_id=service_profile_id,
+                                   shared=True)
 
     def test_list_servicechain_nodes(self):
         """service-chain-node-list."""
@@ -122,6 +128,26 @@ class CLITestV20ServiceChainNodeJSON(test_cli20.CLITestV20Base):
                                     '--tags', 'a', 'b'],
                                    {'name': 'myname', 'tags': ['a', 'b'], })
 
+    def test_update_servicechain_node_with_all_params(self):
+        resource = 'servicechain_node'
+        cmd = servicechain.UpdateServiceChainNode(test_cli20.MyApp(sys.stdout),
+                                                  None)
+        body = {
+            'name': 'new_name',
+            'description': 'new_description',
+            'service_profile_id': 'new_service_profile_id',
+            'shared': True,
+        }
+        args = ['myid', '--name', 'new_name',
+                '--description', 'new_description',
+                '--service-profile', 'new_service_profile_id',
+                '--shared', 'True']
+        self._test_update_resource(resource, cmd, 'myid', args, body)
+
+    # REVISIT(rkukura): Not sure why the following two methods are
+    # needed, since allow_put for both the service_type and config
+    # attributes is False.
+
     def test_update_servicechain_node_with_servicetype(self):
         resource = 'servicechain_node'
         cmd = servicechain.UpdateServiceChainNode(test_cli20.MyApp(sys.stdout),
diff --git a/gbpclient/tests/unit/test_cli20_servicechain_spec.py b/gbpclient/tests/unit/test_cli20_servicechain_spec.py
index f08f05a..fc697e8 100644
--- a/gbpclient/tests/unit/test_cli20_servicechain_spec.py
+++ b/gbpclient/tests/unit/test_cli20_servicechain_spec.py
@@ -50,16 +50,18 @@ class CLITestV20ServiceChainSpecJSON(test_cli20.CLITestV20Base):
         tenant_id = 'my-tenant'
         description = 'My Service Chain Spec'
         my_id = 'my-id'
+        shared = 'True'
         args = ['--nodes', nodes_arg,
                 '--tenant-id', tenant_id,
                 '--description', description,
+                '--shared', shared,
                 name]
         position_names = ['name', ]
         position_values = [name, ]
         self._test_create_resource(resource, cmd, name, my_id, args,
                                    position_names, position_values,
                                    nodes=nodes_res, tenant_id=tenant_id,
-                                   description=description)
+                                   description=description, shared=True)
 
     def test_list_servicechain_specs(self):
         """service-chain-spec-list."""
@@ -120,18 +122,22 @@ class CLITestV20ServiceChainSpecJSON(test_cli20.CLITestV20Base):
                                     '--tags', 'a', 'b'],
                                    {'name': 'myname', 'tags': ['a', 'b'], })
 
-    def test_update_servicechain_spec_with_nodes(self):
+    def test_update_servicechain_node_with_all_params(self):
         resource = 'servicechain_spec'
         cmd = servicechain.UpdateServiceChainSpec(test_cli20.MyApp(sys.stdout),
                                                   None)
         nodes_arg = 'node1 node2'
         nodes_res = ['node1', 'node2']
-        description = 'My Service Chain Spec'
         body = {
+            'name': 'new_name',
+            'description': 'new_description',
             'nodes': nodes_res,
-            'description': description
+            'shared': True,
         }
-        args = ['myid', '--nodes', nodes_arg, '--description', description]
+        args = ['myid', '--name', 'new_name',
+                '--description', 'new_description',
+                '--nodes', nodes_arg,
+                '--shared', 'True']
         self._test_update_resource(resource, cmd, 'myid', args, body)
 
     def test_delete_servicechain_spec(self):
diff --git a/gbpclient/v2_0/client.py b/gbpclient/v2_0/client.py
index b258d73..34c68ec 100644
--- a/gbpclient/v2_0/client.py
+++ b/gbpclient/v2_0/client.py
@@ -171,6 +171,8 @@ class Client(object):
     policy_rule_path = "/grouppolicy/policy_rules/%s"
     policy_rule_sets_path = "/grouppolicy/policy_rule_sets"
     policy_rule_set_path = "/grouppolicy/policy_rule_sets/%s"
+    service_profiles_path = "/servicechain/service_profiles"
+    service_profile_path = "/servicechain/service_profiles/%s"
     servicechain_nodes_path = "/servicechain/servicechain_nodes"
     servicechain_node_path = "/servicechain/servicechain_nodes/%s"
     servicechain_specs_path = "/servicechain/servicechain_specs"
@@ -574,6 +576,38 @@ class Client(object):
         """Deletes the specified Policy Rule Set."""
         return self.delete(self.policy_rule_set_path % (policy_rule_set))
 
+    @APIParamsCall
+    def list_service_profiles(self, retrieve_all=True, **_params):
+
+        """Fetches a list of all service profiles for a tenant."""
+        # Pass filters in "params" argument to do_request
+
+        return self.list('service_profiles', self.service_profiles_path,
+                         retrieve_all, **_params)
+
+    @APIParamsCall
+    def show_service_profile(self, service_profile, **_params):
+        """Fetches information of a certain service profile."""
+        return self.get(self.service_profile_path % (service_profile),
+                        params=_params)
+
+    @APIParamsCall
+    def create_service_profile(self, body=None):
+        """Creates a new service profile."""
+        return self.post(self.service_profiles_path, body=body)
+
+    @APIParamsCall
+    def update_service_profile(self, service_profile, body=None):
+        """Updates a service profile."""
+        return self.put(self.service_profile_path % (service_profile),
+                        body=body)
+
+    @APIParamsCall
+    def delete_service_profile(self, service_profile):
+        """Deletes the specified service profile."""
+        return self.delete(self.service_profile_path % (service_profile))
+
+    @APIParamsCall
     def list_servicechain_nodes(self, retrieve_all=True, **_params):
 
         """Fetches a list of all service chain nodes for a tenant."""
diff --git a/test-requirements.txt b/test-requirements.txt
index c430f14..974f01b 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,7 +2,7 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 -e git://github.com/openstack/python-neutronclient.git#egg=python-neutronclient
-hacking>=0.8.0,<0.9
+hacking>=0.9.2,<0.10
 
 cliff-tablib>=1.0
 coverage>=3.6
diff --git a/tox.ini b/tox.ini
index 756f013..b9b9998 100644
--- a/tox.ini
+++ b/tox.ini
@@ -34,6 +34,9 @@ downloadcache = ~/cache/pip
 [flake8]
 # E125 continuation line does not distinguish itself from next logical line
 # H302 import only modules
-ignore = E125,H302
+#
+# REVISIT: Fix code and remove E129,E251,H305,H307,H405,H904 added for
+# hacking 0.9.2
+ignore = E125,H302,E129,E251,H305,H307,H405,H904
 show-source = true
 exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools