{"action":"created","comment":{"url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/comments/65522602","id":65522602,"diff_hunk":"@@ -0,0 +1,457 @@\n+#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n+#    not use this file except in compliance with the License. You may obtain\n+#    a copy of the License at\n+#\n+#         http://www.apache.org/licenses/LICENSE-2.0\n+#\n+#    Unless required by applicable law or agreed to in writing, software\n+#    distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n+#    License for the specific language governing permissions and limitations\n+#    under the License.\n+\n+import ast\n+import copy\n+\n+from gbpservice.nfp.common import constants as const\n+from gbpservice.nfp.config_orchestrator.agent import common\n+from gbpservice.nfp.config_orchestrator.agent import topics as a_topics\n+from gbpservice.nfp.core import common as nfp_common\n+from gbpservice.nfp.lib import transport\n+\n+from neutron_lbaas.db.loadbalancer import loadbalancer_dbv2\n+\n+from oslo_log import helpers as log_helpers\n+from oslo_log import log as oslo_logging\n+import oslo_messaging as messaging\n+\n+LOGGER = oslo_logging.getLogger(__name__)\n+LOG = nfp_common.log\n+\n+\"\"\"\n+RPC handler for Loadbalancer service\n+\"\"\"\n+\n+\n+class Lbv2Agent(loadbalancer_dbv2.LoadBalancerPluginDbv2):\n+    RPC_API_VERSION = '1.0'\n+    target = messaging.Target(version=RPC_API_VERSION)\n+\n+    def __init__(self, conf, sc):\n+        super(Lbv2Agent, self).__init__()\n+        self._conf = conf\n+        self._sc = sc\n+        self._db_inst = super(Lbv2Agent, self)\n+\n+    def _filter_service_info_with_resource(self, lb_db, core_db):\n+        updated_db = {'subnets': [],\n+                      'ports': []}\n+        for lb in lb_db['loadbalancers']:\n+            lb_port_id = lb['vip_port_id']\n+            lb_subnet_id = lb['vip_subnet_id']\n+            for subnet in core_db['subnets']:\n+                if subnet['id'] == lb_subnet_id:\n+                    updated_db['subnets'].append(subnet)\n+            for port in core_db['ports']:\n+                if port['id'] == lb_port_id:\n+                    updated_db['ports'].append(port)\n+        lb_db.update(updated_db)\n+        return lb_db\n+\n+    def _to_api_dict(self, objs):\n+        ret_list = []\n+        for obj in objs:\n+            ret_list.append(obj.to_api_dict())\n+        return ret_list\n+\n+    def _get_core_context(self, context, tenant_id):\n+        filters = {'tenant_id': [tenant_id]}\n+        core_context_dict = common.get_core_context(context,\n+                                                    filters,\n+                                                    self._conf.host)\n+        del core_context_dict['routers']\n+        return core_context_dict\n+\n+    def _get_lb_context(self, context, filters):\n+        args = {'context': context, 'filters': filters}\n+        db_data = super(Lbv2Agent, self)\n+        return {'loadbalancers': self._to_api_dict(\n+                    db_data.get_loadbalancers(**args)),\n+                'listeners': self._to_api_dict(\n+                    db_data.get_listeners(**args)),\n+                'pools': self._to_api_dict(\n+                    db_data.get_pools(**args)),\n+                'pool_members': self._to_api_dict(\n+                    db_data.get_pool_members(**args)),\n+                'healthmonitors': self._to_api_dict(\n+                    db_data.get_healthmonitors(**args))}\n+\n+    def _context(self, **kwargs):\n+        context = kwargs.get('context')\n+        if context.is_admin:\n+            kwargs['tenant_id'] = context.tenant_id\n+        core_db = self._get_core_context(context, kwargs['tenant_id'])\n+        # TODO(jiahao): _get_lb_context() fails for flavor_id, disable it\n+        # for now. Sent the whole core_db to cofigurator\n+        # lb_db = self._get_lb_context(**kwargs)\n+        # db = self._filter_service_info_with_resource(lb_db, core_db)\n+        db = core_db\n+        return db\n+\n+    def _prepare_resource_context_dicts(self, **kwargs):\n+        # Prepare context_dict\n+        context = kwargs.get('context')\n+        ctx_dict = context.to_dict()\n+        # Collecting db entry required by configurator.\n+        # Addind service_info to neutron context and sending\n+        # dictionary format to the configurator.\n+        db = self._context(**kwargs)\n+        rsrc_ctx_dict = copy.deepcopy(ctx_dict)\n+        rsrc_ctx_dict.update({'service_info': db})\n+        return ctx_dict, rsrc_ctx_dict\n+\n+    def _data_wrapper(self, context, tenant_id, name, reason, nf, **kwargs):\n+        nfp_context = {}\n+        description = ast.literal_eval((nf['description'].split('\\n'))[1])\n+        if name.lower() == 'loadbalancer':\n+            lb_id = kwargs['loadbalancer']['id']\n+            kwargs['loadbalancer'].update({'description': str(description)})\n+            nfp_context = {'network_function_id': nf['id'],\n+                           'loadbalancer_id': kwargs['loadbalancer']['id']}\n+        elif name.lower() == 'listener':\n+            lb_id = kwargs['listener'].get('loadbalancer_id')\n+            kwargs['listener']['description'] = str(description)\n+        elif name.lower() == 'pool':\n+            lb_id = kwargs['pool'].get('loadbalancer_id')\n+            kwargs['pool']['description'] = str(description)\n+        elif name.lower() == 'member':\n+            pool = kwargs['member'].get('pool')\n+            if pool:\n+                lb_id = pool.get('loadbalancer_id')\n+            kwargs['member']['description'] = str(description)\n+        elif name.lower() == 'healthmonitor':\n+            pool = kwargs['healthmonitor'].get('pool')\n+            if pool:\n+                lb_id = pool.get('loadbalancer_id')\n+            kwargs['healthmonitor']['description'] = str(description)\n+        else:\n+            kwargs[name.lower()].update({'description': str(description)})\n+            lb_id = kwargs[name.lower()].get('loadbalancer_id')\n+\n+        args = {'tenant_id': tenant_id,\n+                'lb_id': lb_id,\n+                'context': context,\n+                'description': str(description)}\n+\n+        ctx_dict, rsrc_ctx_dict = self.\\\n+            _prepare_resource_context_dicts(**args)\n+\n+        nfp_context.update({'neutron_context': ctx_dict,\n+                            'requester': 'nas_service'})\n+        resource_type = 'loadbalancerv2'\n+        resource = name\n+        resource_data = {'neutron_context': rsrc_ctx_dict}\n+        resource_data.update(**kwargs)\n+        body = common.prepare_request_data(nfp_context, resource,\n+                                           resource_type, resource_data,\n+                                           description['service_vendor'])\n+        return body\n+\n+    def _post(self, context, tenant_id, name, nf, **kwargs):\n+        body = self._data_wrapper(context, tenant_id, name,\n+                                  'CREATE', nf, **kwargs)\n+        transport.send_request_to_configurator(self._conf,\n+                                               context, body, \"CREATE\")\n+\n+    def _delete(self, context, tenant_id, name, nf, **kwargs):\n+        body = self._data_wrapper(context, tenant_id, name,\n+                                  'DELETE', nf, **kwargs)\n+        transport.send_request_to_configurator(self._conf,\n+                                               context, body, \"DELETE\")\n+\n+    def _fetch_nf_from_resource_desc(self, desc):\n+        desc_dict = ast.literal_eval(desc)\n+        nf_id = desc_dict['network_function_id']\n+        return nf_id\n+\n+    #TODO(jiahao): Argument allocate_vip and\n+    # delete_vip_port are not implememnted.\n+    @log_helpers.log_method_call\n+    def create_loadbalancer(self, context, loadbalancer, driver_name,\n+                            allocate_vip=True):\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._post(\n+            context, loadbalancer['tenant_id'],\n+            'loadbalancer', nf,\n+            loadbalancer=loadbalancer, driver_name=driver_name)\n+\n+    @log_helpers.log_method_call\n+    def delete_loadbalancer(self, context, loadbalancer,\n+                            delete_vip_port=True):\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._delete(\n+            context, loadbalancer['tenant_id'],\n+            'loadbalancer', nf, loadbalancer=loadbalancer)\n+\n+    @log_helpers.log_method_call\n+    def create_listener(self, context, listener):\n+        loadbalancer = listener['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._post(\n+            context, listener['tenant_id'],\n+            'listener', nf, listener=listener)\n+\n+    @log_helpers.log_method_call\n+    def delete_listener(self, context, listener):\n+        loadbalancer = listener['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._delete(\n+            context, listener['tenant_id'],\n+            'listener', nf, listener=listener)\n+\n+    @log_helpers.log_method_call\n+    def create_pool(self, context, pool):\n+        loadbalancer = pool['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._post(\n+            context, pool['tenant_id'],\n+            'pool', nf, pool=pool)\n+\n+    @log_helpers.log_method_call\n+    def delete_pool(self, context, pool):\n+        loadbalancer = pool['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._delete(\n+            context, pool['tenant_id'],\n+            'pool', nf, pool=pool)\n+\n+    @log_helpers.log_method_call\n+    def create_member(self, context, member):\n+        loadbalancer = member['pool']['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._post(\n+            context, member['tenant_id'],\n+            'member', nf, member=member)\n+\n+    @log_helpers.log_method_call\n+    def delete_member(self, context, member):\n+        loadbalancer = member['pool']['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._delete(\n+            context, member['tenant_id'],\n+            'member', nf, member=member)\n+\n+    @log_helpers.log_method_call\n+    def create_healthmonitor_on_pool(self, context, pool_id, healthmonitor):\n+        loadbalancer = healthmonitor['pool']['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._post(\n+            context, healthmonitor['tenant_id'],\n+            'healthmonitor', nf, healthmonitor=healthmonitor)\n+\n+    @log_helpers.log_method_call\n+    def create_healthmonitor(self, context, healthmonitor):\n+        loadbalancer = healthmonitor['pool']['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._post(\n+            context, healthmonitor['tenant_id'],\n+            'healthmonitor', nf, healthmonitor=healthmonitor)\n+\n+    @log_helpers.log_method_call\n+    def delete_healthmonitor(self, context, healthmonitor):\n+        loadbalancer = healthmonitor['pool']['loadbalancer']\n+        # Fetch nf_id from description of the resource\n+        nf_id = self._fetch_nf_from_resource_desc(loadbalancer[\"description\"])\n+        nf = common.get_network_function_details(context, nf_id)\n+        self._delete(\n+            context, healthmonitor['tenant_id'],\n+            'healthmonitor', nf, healthmonitor=healthmonitor)\n+\n+    # TODO(jiahao): L7policy support not implemented\n+    # disable L7policy\n+    # def create_l7policy(self, context, l7policy):\n+    #     self._post(\n+    #         context, l7policy['tenant_id'],\n+    #         'l7policy', l7policy=l7policy)\n+    #\n+    # def delete_l7policy(self, context, l7policy):\n+    #     self._delete(\n+    #         context, l7policy['tenant_id'],\n+    #         'l7policy', l7policy=l7policy)\n+    #\n+    # def create_l7policy_rule(self, context, rule, l7policy_id):\n+    #     self._post(\n+    #         context, rule['tenant_id'],\n+    #         'rule', rule=rule)\n+    #\n+    # def delete_l7policy_rule(self, context, rule):\n+    #     self._delete(\n+    #         context, rule['tenant_id'],\n+    #         'rule', rule=rule)\n+    #\n+    # def _get_lb_context(self, context, filters):\n+    #     args = {'context': context, 'filters': filters}\n+    #     db_data = super(Lbv2Agent, self)\n+    #     return {'loadbalancers': db_data.get_loadbalancers(**args),\n+    #             'listeners': db_data.get_listeners(**args),\n+    #             'pools': db_data.get_pools(**args),\n+    #             'pool_members': db_data.get_pool_members(**args),\n+    #             'healthmonitors': db_data.get_healthmonitors(**args),\n+    #             'l7policies': db_data.get_l7policies(**args),\n+    #             'l7policy_rules': db_data.get_l7policy_rules(**args)}\n+\n+\n+class LoadbalancerV2Notifier(object):\n+\n+    def __init__(self, conf, sc):\n+        self._sc = sc\n+        self._conf = conf\n+\n+    # TODO(jiahao): copy from v1 agent need to review\n+    def _prepare_request_data(self, context, nf_id,\n+                              resource_id, lb_id,\n+                              service_type):\n+        request_data = None\n+        try:\n+            request_data = common.get_network_function_map(\n+                context, nf_id)\n+            # Adding Service Type #\n+            # TODO(jiahao): is the key name \"loadbalancer_id\" correct?\n+            request_data.update({\"service_type\": service_type,\n+                                 \"loadbalancer_id\": lb_id,\n+                                 \"neutron_resource_id\": resource_id,\n+                                 \"LogMetaID\": nf_id})\n+        except Exception as e:\n+            LOG(LOGGER, 'ERROR', '%s' % (e))\n+            return request_data\n+        return request_data\n+\n+    # TODO(jiahao): copy from v1 agent need to review\n+    def _trigger_service_event(self, context, event_type, event_id,\n+                               request_data):\n+        event_data = {'resource': None,\n+                      'context': context.to_dict()}\n+        event_data['resource'] = {'eventtype': event_type,\n+                                  'eventid': event_id,\n+                                  'eventdata': request_data}\n+        ev = self._sc.new_event(id=event_id,\n+                                key=event_id, data=event_data)\n+        self._sc.post_event(ev)\n+\n+    def update_status(self, context, notification_data):\n+        notification = notification_data['notification'][0]\n+        notification_info = notification_data['info']\n+        resource_data = notification['data']\n+        obj_type = resource_data['obj_type']\n+        obj_id = resource_data['obj_id']\n+        service_type = notification_info['service_type']\n+\n+        rpcClient = transport.RPCClient(a_topics.LBV2_NFP_PLUGIN_TOPIC)\n+        rpcClient.cctxt = rpcClient.client.prepare(\n+            version=const.LOADBALANCERV2_RPC_API_VERSION)\n+\n+        lb_p_status = const.ACTIVE\n+        lb_o_status = None\n+        obj_p_status = resource_data['provisioning_status']\n+        obj_o_status = resource_data['operating_status']\n+\n+        msg = (\"NCO received LB's update_status API, making an update_status \"\n+               \"RPC call to plugin for %s: %s with status %s\" % (\n+                   obj_type, obj_id, obj_p_status))\n+        LOG(LOGGER, 'INFO', '%s' % (msg))\n+\n+        if obj_type == 'healthmonitor':\n+                obj_o_status = None\n+\n+        if obj_type != 'loadbalancer':\n+            rpcClient.cctxt.cast(context, 'update_status',\n+                                 obj_type=obj_type,\n+                                 obj_id=obj_id,\n+                                 provisioning_status=obj_p_status,\n+                                 operating_status=obj_o_status)\n+        else:\n+            lb_o_status = const.ONLINE\n+            if obj_p_status == const.ERROR:\n+                lb_p_status = const.ERROR\n+                lb_o_status = const.OFFLINE\n+\n+        rpcClient.cctxt.cast(context, 'update_status',\n+                             obj_type='loadbalancer',\n+                             obj_id=resource_data['root_lb_id'],\n+                             provisioning_status=lb_p_status,\n+                             operating_status=lb_o_status)\n+\n+        if obj_type.lower() == 'loadbalancer':\n+            nf_id = notification_info['context']['network_function_id']\n+            lb_id = notification_info['context']['loadbalancer_id']\n+            # sending notification to visibility\n+            event_data = {'context': context.to_dict(),\n+                          'nf_id': nf_id,\n+                          'loadbalancer_id': lb_id,\n+                          'service_type': service_type,\n+                          'resource_id': lb_id\n+                          }\n+            ev = self._sc.new_event(id='SERVICE_CREATE_PENDING',\n+                                    key='SERVICE_CREATE_PENDING',\n+                                    data=event_data, max_times=24)\n+            self._sc.poll_event(ev)\n+\n+    # TODO(jiahao): copy from v1 agent need to review\n+    # def update_pool_stats(self, context, notification_data):","path":"gbpservice/nfp/config_orchestrator/agent/loadbalancerv2.py","position":427,"original_position":420,"commit_id":"09697501018ac2f9542d3b6096b6607a23a5775d","original_commit_id":"f110effd96c910150f26077765cb753fd74a1e32","user":{"login":"njagadish","id":13430691,"avatar_url":"https://avatars.githubusercontent.com/u/13430691?v=3","gravatar_id":"","url":"https://api.github.com/users/njagadish","html_url":"https://github.com/njagadish","followers_url":"https://api.github.com/users/njagadish/followers","following_url":"https://api.github.com/users/njagadish/following{/other_user}","gists_url":"https://api.github.com/users/njagadish/gists{/gist_id}","starred_url":"https://api.github.com/users/njagadish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/njagadish/subscriptions","organizations_url":"https://api.github.com/users/njagadish/orgs","repos_url":"https://api.github.com/users/njagadish/repos","events_url":"https://api.github.com/users/njagadish/events{/privacy}","received_events_url":"https://api.github.com/users/njagadish/received_events","type":"User","site_admin":false},"body":"We need to check the LBaaSV2 resources and check where pool stats are shown. Need to add this. This is invoked in the configurator driver but not handled here.","created_at":"2016-06-02T11:24:56Z","updated_at":"2016-06-02T11:24:56Z","html_url":"https://github.com/oneconvergence/group-based-policy/pull/358#discussion_r65522602","pull_request_url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358","_links":{"self":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/comments/65522602"},"html":{"href":"https://github.com/oneconvergence/group-based-policy/pull/358#discussion_r65522602"},"pull_request":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358"}}},"pull_request":{"url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358","id":70810522,"html_url":"https://github.com/oneconvergence/group-based-policy/pull/358","diff_url":"https://github.com/oneconvergence/group-based-policy/pull/358.diff","patch_url":"https://github.com/oneconvergence/group-based-policy/pull/358.patch","issue_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/358","number":358,"state":"open","locked":false,"title":"add agents and haproxy_lbaasv2 driver to support lbaasv2","user":{"login":"jiahaoliang","id":5660181,"avatar_url":"https://avatars.githubusercontent.com/u/5660181?v=3","gravatar_id":"","url":"https://api.github.com/users/jiahaoliang","html_url":"https://github.com/jiahaoliang","followers_url":"https://api.github.com/users/jiahaoliang/followers","following_url":"https://api.github.com/users/jiahaoliang/following{/other_user}","gists_url":"https://api.github.com/users/jiahaoliang/gists{/gist_id}","starred_url":"https://api.github.com/users/jiahaoliang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jiahaoliang/subscriptions","organizations_url":"https://api.github.com/users/jiahaoliang/orgs","repos_url":"https://api.github.com/users/jiahaoliang/repos","events_url":"https://api.github.com/users/jiahaoliang/events{/privacy}","received_events_url":"https://api.github.com/users/jiahaoliang/received_events","type":"User","site_admin":false},"body":"@ashutosh-mishra @songole @njagadish\r\n\r\nThis is a pull request for LbaaS V2 support.\r\n\r\n**Added features:**\r\n\r\nneutron/services/servicechain/:\r\n- A new service type: LOADBALANCERV2\r\n\r\nconfig_orchestrator:\r\n- A loadbalancerv2 agent to handle lbaasv2 request\r\n\r\nconfigurator:\r\n- A loadbalancerv2 agent to handle lbaasv2 request\r\n- haproxy driver for lbaasv2 based on Octavia lbassv2 amphora driver\r\n\r\norchestrator:\r\n- New functions for generating lbaasv2 heat templates\r\n\r\nservice_plugins:\r\n- A neutron lbaasv2 plugin driver \r\n\r\n**Known issues:**\r\n\r\n- No sharing support\r\n- In service orchestrator, changed pool_event max_times from 20 to 400 to avoid timeout. Since every lbaasv2 operation takes 10 sec.\r\n- In config_orchestrator lbaasv2 agent, we are not able access neutron lb database due to this [issue](https://bugs.launchpad.net/neutron/+bug/1573337). Instead of filtering only relevant ports and subnets, I pass all ports and subnets under given tenant to configurator.\r\n- No multiple listeners support for loadbalancer\r\n- No multiple pools support for listener\r\n- No L7policy support\r\n- No SSL support\r\n\r\n\r\n**Steps for testing:**\r\n\r\n- In devstack local.conf:\r\n  - Remove:\r\n    - enable_service q-lbaas\r\n  - Add:\r\n    - enable_service q-lbaasv2\r\n    - NEUTRON_LBAAS_SERVICE_PROVIDERV2=LOADBALANCERV2:loadbalancerv2:gbpservice.nfp.service_plugins.loadbalancer.drivers.nfp_lbaasv2_plugin_driver.HaproxyOnVMPluginDriver:default\r\n    - enable_plugin neutron-lbaas https://git.openstack.org/openstack/neutron-lbaas stable/mitaka\r\n- Install following pkgs in configurator vm docker and then restart the configurator process: \r\n  - sudo apt-get install build-essential libssl-dev libffi-dev python-dev\r\n  - cd /tmp; git clone -b stable/mitaka --single-branch https://github.com/openstack/neutron-lbaas.git; cd /tmp/neutron-lbaas; sudo pip install -r requirements.txt --allow-all-external && sudo python setup.py install\r\n  - pip install \"octavia<0.8\"\r\n-  upload haproxy_lbaasv2.qcow image to glance: 192.168.100.50:/var/www/partners/haproxy_lbaasv2/haproxy_lbaasv2.qcow2\r\n- Create service profile for lbaasv2:\r\n  - gbp service-profile-create --shared True --vendor NFP --servicetype LOADBALANCERV2 --service-flavor service_vendor=haproxy_lbaasv2,device_type=nova,flavor=m1.small --insertion-mode l3 lbv2_profile\r\n  - Optional: haproxy_lbaasv2 vm is able to work with a smaller flavor\r\n    - create a flavor smaller than m1.small:\r\n      - nova flavor-create --is-public True m1.amphora 10 1024 2 1\r\n    - create service profile for lbaasv2\r\n      - gbp service-profile-create --shared True --vendor NFP --servicetype LOADBALANCERV2 --service-flavor service_vendor=haproxy_lbaasv2,device_type=nova,flavor=m1.amphora --insertion-mode l3 \r\n- Create a service chain node for lbaasv2\r\n  - lbaasv2 heat template is included in this PR: gbpservice/nfp/Automation-Scripts/NFP_SCRIPTS/templates/haproxy_lbaasv2.templete\r\n- Follow same steps for testing lbaasv1","created_at":"2016-05-20T07:10:34Z","updated_at":"2016-06-02T11:24:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6dd6f8efc5228efce0b36db031b42fe993875fec","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358/commits","review_comments_url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358/comments","review_comment_url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/comments{/number}","comments_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/358/comments","statuses_url":"https://api.github.com/repos/oneconvergence/group-based-policy/statuses/09697501018ac2f9542d3b6096b6607a23a5775d","head":{"label":"oneconvergence:lbaasv2-mitaka-pull-request","ref":"lbaasv2-mitaka-pull-request","sha":"09697501018ac2f9542d3b6096b6607a23a5775d","user":{"login":"oneconvergence","id":8160602,"avatar_url":"https://avatars.githubusercontent.com/u/8160602?v=3","gravatar_id":"","url":"https://api.github.com/users/oneconvergence","html_url":"https://github.com/oneconvergence","followers_url":"https://api.github.com/users/oneconvergence/followers","following_url":"https://api.github.com/users/oneconvergence/following{/other_user}","gists_url":"https://api.github.com/users/oneconvergence/gists{/gist_id}","starred_url":"https://api.github.com/users/oneconvergence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oneconvergence/subscriptions","organizations_url":"https://api.github.com/users/oneconvergence/orgs","repos_url":"https://api.github.com/users/oneconvergence/repos","events_url":"https://api.github.com/users/oneconvergence/events{/privacy}","received_events_url":"https://api.github.com/users/oneconvergence/received_events","type":"Organization","site_admin":false},"repo":{"id":34099604,"name":"group-based-policy","full_name":"oneconvergence/group-based-policy","owner":{"login":"oneconvergence","id":8160602,"avatar_url":"https://avatars.githubusercontent.com/u/8160602?v=3","gravatar_id":"","url":"https://api.github.com/users/oneconvergence","html_url":"https://github.com/oneconvergence","followers_url":"https://api.github.com/users/oneconvergence/followers","following_url":"https://api.github.com/users/oneconvergence/following{/other_user}","gists_url":"https://api.github.com/users/oneconvergence/gists{/gist_id}","starred_url":"https://api.github.com/users/oneconvergence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oneconvergence/subscriptions","organizations_url":"https://api.github.com/users/oneconvergence/orgs","repos_url":"https://api.github.com/users/oneconvergence/repos","events_url":"https://api.github.com/users/oneconvergence/events{/privacy}","received_events_url":"https://api.github.com/users/oneconvergence/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/oneconvergence/group-based-policy","description":"Group Based Policy","fork":true,"url":"https://api.github.com/repos/oneconvergence/group-based-policy","forks_url":"https://api.github.com/repos/oneconvergence/group-based-policy/forks","keys_url":"https://api.github.com/repos/oneconvergence/group-based-policy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/oneconvergence/group-based-policy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/oneconvergence/group-based-policy/teams","hooks_url":"https://api.github.com/repos/oneconvergence/group-based-policy/hooks","issue_events_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/events{/number}","events_url":"https://api.github.com/repos/oneconvergence/group-based-policy/events","assignees_url":"https://api.github.com/repos/oneconvergence/group-based-policy/assignees{/user}","branches_url":"https://api.github.com/repos/oneconvergence/group-based-policy/branches{/branch}","tags_url":"https://api.github.com/repos/oneconvergence/group-based-policy/tags","blobs_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/refs{/sha}","trees_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/oneconvergence/group-based-policy/statuses/{sha}","languages_url":"https://api.github.com/repos/oneconvergence/group-based-policy/languages","stargazers_url":"https://api.github.com/repos/oneconvergence/group-based-policy/stargazers","contributors_url":"https://api.github.com/repos/oneconvergence/group-based-policy/contributors","subscribers_url":"https://api.github.com/repos/oneconvergence/group-based-policy/subscribers","subscription_url":"https://api.github.com/repos/oneconvergence/group-based-policy/subscription","commits_url":"https://api.github.com/repos/oneconvergence/group-based-policy/commits{/sha}","git_commits_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/commits{/sha}","comments_url":"https://api.github.com/repos/oneconvergence/group-based-policy/comments{/number}","issue_comment_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/comments{/number}","contents_url":"https://api.github.com/repos/oneconvergence/group-based-policy/contents/{+path}","compare_url":"https://api.github.com/repos/oneconvergence/group-based-policy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/oneconvergence/group-based-policy/merges","archive_url":"https://api.github.com/repos/oneconvergence/group-based-policy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/oneconvergence/group-based-policy/downloads","issues_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues{/number}","pulls_url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls{/number}","milestones_url":"https://api.github.com/repos/oneconvergence/group-based-policy/milestones{/number}","notifications_url":"https://api.github.com/repos/oneconvergence/group-based-policy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/oneconvergence/group-based-policy/labels{/name}","releases_url":"https://api.github.com/repos/oneconvergence/group-based-policy/releases{/id}","deployments_url":"https://api.github.com/repos/oneconvergence/group-based-policy/deployments","created_at":"2015-04-17T06:06:34Z","updated_at":"2016-03-09T19:50:22Z","pushed_at":"2016-06-02T11:17:53Z","git_url":"git://github.com/oneconvergence/group-based-policy.git","ssh_url":"git@github.com:oneconvergence/group-based-policy.git","clone_url":"https://github.com/oneconvergence/group-based-policy.git","svn_url":"https://github.com/oneconvergence/group-based-policy","homepage":"http://openstack.org","size":8166,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":false,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":8,"forks":5,"open_issues":8,"watchers":1,"default_branch":"oneconvergence_service_node_driver"}},"base":{"label":"oneconvergence:non-hotplug-support-966","ref":"non-hotplug-support-966","sha":"1d0097bef138a9d0fdb2ecbf3d47b176913af4f6","user":{"login":"oneconvergence","id":8160602,"avatar_url":"https://avatars.githubusercontent.com/u/8160602?v=3","gravatar_id":"","url":"https://api.github.com/users/oneconvergence","html_url":"https://github.com/oneconvergence","followers_url":"https://api.github.com/users/oneconvergence/followers","following_url":"https://api.github.com/users/oneconvergence/following{/other_user}","gists_url":"https://api.github.com/users/oneconvergence/gists{/gist_id}","starred_url":"https://api.github.com/users/oneconvergence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oneconvergence/subscriptions","organizations_url":"https://api.github.com/users/oneconvergence/orgs","repos_url":"https://api.github.com/users/oneconvergence/repos","events_url":"https://api.github.com/users/oneconvergence/events{/privacy}","received_events_url":"https://api.github.com/users/oneconvergence/received_events","type":"Organization","site_admin":false},"repo":{"id":34099604,"name":"group-based-policy","full_name":"oneconvergence/group-based-policy","owner":{"login":"oneconvergence","id":8160602,"avatar_url":"https://avatars.githubusercontent.com/u/8160602?v=3","gravatar_id":"","url":"https://api.github.com/users/oneconvergence","html_url":"https://github.com/oneconvergence","followers_url":"https://api.github.com/users/oneconvergence/followers","following_url":"https://api.github.com/users/oneconvergence/following{/other_user}","gists_url":"https://api.github.com/users/oneconvergence/gists{/gist_id}","starred_url":"https://api.github.com/users/oneconvergence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oneconvergence/subscriptions","organizations_url":"https://api.github.com/users/oneconvergence/orgs","repos_url":"https://api.github.com/users/oneconvergence/repos","events_url":"https://api.github.com/users/oneconvergence/events{/privacy}","received_events_url":"https://api.github.com/users/oneconvergence/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/oneconvergence/group-based-policy","description":"Group Based Policy","fork":true,"url":"https://api.github.com/repos/oneconvergence/group-based-policy","forks_url":"https://api.github.com/repos/oneconvergence/group-based-policy/forks","keys_url":"https://api.github.com/repos/oneconvergence/group-based-policy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/oneconvergence/group-based-policy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/oneconvergence/group-based-policy/teams","hooks_url":"https://api.github.com/repos/oneconvergence/group-based-policy/hooks","issue_events_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/events{/number}","events_url":"https://api.github.com/repos/oneconvergence/group-based-policy/events","assignees_url":"https://api.github.com/repos/oneconvergence/group-based-policy/assignees{/user}","branches_url":"https://api.github.com/repos/oneconvergence/group-based-policy/branches{/branch}","tags_url":"https://api.github.com/repos/oneconvergence/group-based-policy/tags","blobs_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/refs{/sha}","trees_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/oneconvergence/group-based-policy/statuses/{sha}","languages_url":"https://api.github.com/repos/oneconvergence/group-based-policy/languages","stargazers_url":"https://api.github.com/repos/oneconvergence/group-based-policy/stargazers","contributors_url":"https://api.github.com/repos/oneconvergence/group-based-policy/contributors","subscribers_url":"https://api.github.com/repos/oneconvergence/group-based-policy/subscribers","subscription_url":"https://api.github.com/repos/oneconvergence/group-based-policy/subscription","commits_url":"https://api.github.com/repos/oneconvergence/group-based-policy/commits{/sha}","git_commits_url":"https://api.github.com/repos/oneconvergence/group-based-policy/git/commits{/sha}","comments_url":"https://api.github.com/repos/oneconvergence/group-based-policy/comments{/number}","issue_comment_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/comments{/number}","contents_url":"https://api.github.com/repos/oneconvergence/group-based-policy/contents/{+path}","compare_url":"https://api.github.com/repos/oneconvergence/group-based-policy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/oneconvergence/group-based-policy/merges","archive_url":"https://api.github.com/repos/oneconvergence/group-based-policy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/oneconvergence/group-based-policy/downloads","issues_url":"https://api.github.com/repos/oneconvergence/group-based-policy/issues{/number}","pulls_url":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls{/number}","milestones_url":"https://api.github.com/repos/oneconvergence/group-based-policy/milestones{/number}","notifications_url":"https://api.github.com/repos/oneconvergence/group-based-policy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/oneconvergence/group-based-policy/labels{/name}","releases_url":"https://api.github.com/repos/oneconvergence/group-based-policy/releases{/id}","deployments_url":"https://api.github.com/repos/oneconvergence/group-based-policy/deployments","created_at":"2015-04-17T06:06:34Z","updated_at":"2016-03-09T19:50:22Z","pushed_at":"2016-06-02T11:17:53Z","git_url":"git://github.com/oneconvergence/group-based-policy.git","ssh_url":"git@github.com:oneconvergence/group-based-policy.git","clone_url":"https://github.com/oneconvergence/group-based-policy.git","svn_url":"https://github.com/oneconvergence/group-based-policy","homepage":"http://openstack.org","size":8166,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":false,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":8,"forks":5,"open_issues":8,"watchers":1,"default_branch":"oneconvergence_service_node_driver"}},"_links":{"self":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358"},"html":{"href":"https://github.com/oneconvergence/group-based-policy/pull/358"},"issue":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/358"},"comments":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/issues/358/comments"},"review_comments":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358/comments"},"review_comment":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/pulls/358/commits"},"statuses":{"href":"https://api.github.com/repos/oneconvergence/group-based-policy/statuses/09697501018ac2f9542d3b6096b6607a23a5775d"}}}}
{"actor":{"display_login":"njagadish"}}