Create GCE Service outside Neutron service start path

Creating gce client inside Neutron service start causes neutron-server
crash if service_key is not there at mentioned path. Neutron service
should not crash at start if service key is not there.

Change-Id: I8e0f8b150c60d55d71846face217d5213b5df9b7
Closes-Bug: #1707872
This commit is contained in:
Sanket 2017-08-01 17:57:58 +05:30
parent 6c6d849778
commit 8d58fd2f16
4 changed files with 203 additions and 180 deletions

View File

@ -11,6 +11,7 @@ License for the specific language governing permissions and limitations
under the License. under the License.
""" """
import os
import time import time
import uuid import uuid
@ -75,6 +76,10 @@ class GceResourceNotFound(e.NotFound):
message = _("GCE Resource %(name)s %(identifier)s was not found") message = _("GCE Resource %(name)s %(identifier)s was not found")
class GceServiceKeyNotFound(e.NotFound):
message = _("GCE service key was not found at %(path)s location")
def list_instances(compute, project, zone): def list_instances(compute, project, zone):
"""Returns list of GCE instance resources for specified project """Returns list of GCE instance resources for specified project
@ -151,6 +156,9 @@ def get_gce_service(service_key):
:return: :class:`Resource <Resource>` object :return: :class:`Resource <Resource>` object
:rtype: googleapiclient.discovery.Resource :rtype: googleapiclient.discovery.Resource
""" """
if not os.path.exists(service_key):
raise GceServiceKeyNotFound(path=service_key)
credentials = GoogleCredentials.from_stream(service_key) credentials = GoogleCredentials.from_stream(service_key)
service = build('compute', 'v1', credentials=credentials) service = build('compute', 'v1', credentials=credentials)
return service return service

View File

@ -48,13 +48,19 @@ class GceMechanismDriver(api.MechanismDriver):
self.gce_region = gceconf.region self.gce_region = gceconf.region
self.gce_project = gceconf.project_id self.gce_project = gceconf.project_id
self.gce_svc_key = gceconf.service_key_path self.gce_svc_key = gceconf.service_key_path
self._gce_svc = None
def initialize(self): def initialize(self):
self.gce_svc = gceutils.get_gce_service(self.gce_svc_key)
LOG.info("GCE Mechanism driver init with %s project, %s region" % LOG.info("GCE Mechanism driver init with %s project, %s region" %
(self.gce_project, self.gce_region)) (self.gce_project, self.gce_region))
self._subscribe_events() self._subscribe_events()
@property
def gce_svc(self):
if self._gce_svc is None:
self._gce_svc = gceutils.get_gce_service(self.gce_svc_key)
return self._gce_svc
def _subscribe_events(self): def _subscribe_events(self):
registry.subscribe(self.secgroup_callback, resources.SECURITY_GROUP, registry.subscribe(self.secgroup_callback, resources.SECURITY_GROUP,
events.BEFORE_DELETE) events.BEFORE_DELETE)

View File

@ -75,10 +75,16 @@ class GceRouterPlugin(
self.gce_region = gceconf.region self.gce_region = gceconf.region
self.gce_project = gceconf.project_id self.gce_project = gceconf.project_id
self.gce_svc_key = gceconf.service_key_path self.gce_svc_key = gceconf.service_key_path
self.gce_svc = gceutils.get_gce_service(self.gce_svc_key) self._gce_svc = None
LOG.info("GCE Router plugin init with %s project, %s region" % LOG.info("GCE Router plugin init with %s project, %s region" %
(self.gce_project, self.gce_region)) (self.gce_project, self.gce_region))
@property
def gce_svc(self):
if self._gce_svc is None:
self._gce_svc = gceutils.get_gce_service(self.gce_svc_key)
return self._gce_svc
def get_plugin_type(self): def get_plugin_type(self):
return plugin_type return plugin_type

View File

@ -1,178 +1,181 @@
""" """
Copyright (c) 2017 Platform9 Systems Inc. Copyright (c) 2017 Platform9 Systems Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may 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 not use this file except in compliance with the License. You may obtain
a copy of the License at a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the
License for the specific language governing permissions and limitations License for the specific language governing permissions and limitations
under the License. under the License.
""" """
import mock import mock
import os import os
from neutron.extensions import securitygroup as sg from neutron.extensions import securitygroup as sg
from neutron.manager import NeutronManager from neutron.manager import NeutronManager
from neutron.plugins.ml2.drivers.gce.mech_gce import GceMechanismDriver from neutron.plugins.ml2.drivers.gce.mech_gce import GceMechanismDriver
from neutron.plugins.ml2.drivers.gce.mech_gce import SecurityGroupInvalidDirection # noqa from neutron.plugins.ml2.drivers.gce.mech_gce import SecurityGroupInvalidDirection # noqa
from neutron.tests import base from neutron.tests import base
from neutron.tests.common.gce import gce_mock from neutron.tests.common.gce import gce_mock
from neutron.tests.common.gce.gce_mock import FakeNeutronManager from neutron.tests.common.gce.gce_mock import FakeNeutronManager
from neutron.tests.unit.extensions import test_securitygroup as test_sg from neutron.tests.unit.extensions import test_securitygroup as test_sg
from neutron_lib import constants as const from neutron_lib import constants as const
DATA_DIR = os.path.dirname(os.path.abspath("gce_mock.py")) + '/data' DATA_DIR = os.path.dirname(os.path.abspath("gce_mock.py")) + '/data'
NETWORKS_LINK = "projects/omni-163105/global/networks" NETWORKS_LINK = "projects/omni-163105/global/networks"
NETWORK_LINK = NETWORKS_LINK + "/net-03c4f178-670e-4805-a511-9470ca4a0b06" NETWORK_LINK = NETWORKS_LINK + "/net-03c4f178-670e-4805-a511-9470ca4a0b06"
if hasattr(NeutronManager, "get_plugin"): if hasattr(NeutronManager, "get_plugin"):
neutron_get_plugin = 'neutron.manager.NeutronManager.get_plugin' neutron_get_plugin = 'neutron.manager.NeutronManager.get_plugin'
else: else:
neutron_get_plugin = 'neutron_lib.plugins.directory.get_plugin' neutron_get_plugin = 'neutron_lib.plugins.directory.get_plugin'
class GCENeutronTestCase(test_sg.SecurityGroupsTestCase, base.BaseTestCase): class GCENeutronTestCase(test_sg.SecurityGroupsTestCase, base.BaseTestCase):
@mock.patch('neutron.common.gceutils.get_gce_service') def setUp(self):
def setUp(self, mock_service): super(GCENeutronTestCase, self).setUp()
mock_service.side_effect = gce_mock.get_gce_service self.service_patcher = mock.patch(
super(GCENeutronTestCase, self).setUp() 'neutron.common.gceutils.get_gce_service').start()
self._driver = GceMechanismDriver() mock_service = self.service_patcher.start()
self._driver.gce_zone = 'us-central1-c' mock_service.side_effect = gce_mock.get_gce_service
self._driver.gce_region = 'us-central1' self.addCleanup(self.service_patcher.stop)
self._driver.gce_project = 'omni-163105' self._driver = GceMechanismDriver()
self._driver.gce_svc_key = "{0}/omni.json".format(DATA_DIR) self._driver.gce_zone = 'us-central1-c'
self.context = self._create_fake_context() self._driver.gce_region = 'us-central1'
self._driver.initialize() self._driver.gce_project = 'omni-163105'
self._driver.gce_svc_key = "{0}/omni.json".format(DATA_DIR)
def _create_fake_context(self): self.context = self._create_fake_context()
context = mock.Mock() self._driver.initialize()
context.current = {}
context.current['id'] = "fake_id_1234" def _create_fake_context(self):
context.current['cidr'] = "192.168.1.0/24" context = mock.Mock()
context.current['network_id'] = "fake_network_id_1234" context.current = {}
return context context.current['id'] = "fake_id_1234"
context.current['cidr'] = "192.168.1.0/24"
def get_fake_sg_rule(self, ethertype=const.IPv4, direction="ingress", context.current['network_id'] = "fake_network_id_1234"
protocol=const.PROTO_NAME_TCP): return context
data = {
'id': 'fake_rule_id', def get_fake_sg_rule(self, ethertype=const.IPv4, direction="ingress",
'security_group_id': '4cd70774-cc67-4a87-9b39-7d1db38eb087', protocol=const.PROTO_NAME_TCP):
'direction': direction, data = {
'protocol': protocol, 'id': 'fake_rule_id',
'ethertype': ethertype, 'security_group_id': '4cd70774-cc67-4a87-9b39-7d1db38eb087',
'tenant_id': 'fake_tenant_id', 'direction': direction,
'port_range_min': '22', 'protocol': protocol,
'port_range_max': '22', 'ethertype': ethertype,
'remote_ip_prefix': None, 'tenant_id': 'fake_tenant_id',
'remote_group_id': None 'port_range_min': '22',
} 'port_range_max': '22',
return data 'remote_ip_prefix': None,
'remote_group_id': None
@mock.patch('neutron.common.gceutils.wait_for_operation') }
@mock.patch('neutron.common.gceutils.create_network') return data
def test_create_network_postcommit(self, mock_create, mock_wait):
mock_create.side_effect = gce_mock.create_anything @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_wait.side_effect = gce_mock.wait_for_operation @mock.patch('neutron.common.gceutils.create_network')
self.assertIsNone(self._driver.create_network_postcommit(self.context)) def test_create_network_postcommit(self, mock_create, mock_wait):
mock_wait.assert_called_once_with(self._driver.gce_svc, mock_create.side_effect = gce_mock.create_anything
self._driver.gce_project, mock_wait.side_effect = gce_mock.wait_for_operation
gce_mock.fake_operation()) self.assertIsNone(self._driver.create_network_postcommit(self.context))
mock_wait.assert_called_once_with(self._driver.gce_svc,
@mock.patch('neutron.common.gceutils.wait_for_operation') self._driver.gce_project,
@mock.patch('neutron.common.gceutils.delete_network') gce_mock.fake_operation())
def test_delete_network_postcommit(self, mock_delete, mock_wait):
mock_delete.side_effect = gce_mock.delete_anything @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_wait.side_effect = gce_mock.wait_for_operation @mock.patch('neutron.common.gceutils.delete_network')
self.assertIsNone(self._driver.delete_network_postcommit(self.context)) def test_delete_network_postcommit(self, mock_delete, mock_wait):
mock_wait.assert_called_once_with(self._driver.gce_svc, mock_delete.side_effect = gce_mock.delete_anything
self._driver.gce_project, mock_wait.side_effect = gce_mock.wait_for_operation
gce_mock.fake_operation()) self.assertIsNone(self._driver.delete_network_postcommit(self.context))
mock_wait.assert_called_once_with(self._driver.gce_svc,
@mock.patch('neutron.common.gceutils.wait_for_operation') self._driver.gce_project,
@mock.patch('neutron.common.gceutils.create_subnet') gce_mock.fake_operation())
@mock.patch('neutron.common.gceutils.get_network')
def test_create_subnet_postcommit(self, mock_get, mock_create, mock_wait): @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_get.side_effect = gce_mock.get_network @mock.patch('neutron.common.gceutils.create_subnet')
mock_create.side_effect = gce_mock.create_anything @mock.patch('neutron.common.gceutils.get_network')
mock_wait.side_effect = gce_mock.wait_for_operation def test_create_subnet_postcommit(self, mock_get, mock_create, mock_wait):
self.assertIsNone(self._driver.create_subnet_postcommit(self.context)) mock_get.side_effect = gce_mock.get_network
mock_wait.assert_called_once_with(self._driver.gce_svc, mock_create.side_effect = gce_mock.create_anything
self._driver.gce_project, mock_wait.side_effect = gce_mock.wait_for_operation
gce_mock.fake_operation()) self.assertIsNone(self._driver.create_subnet_postcommit(self.context))
mock_wait.assert_called_once_with(self._driver.gce_svc,
@mock.patch('neutron.common.gceutils.wait_for_operation') self._driver.gce_project,
@mock.patch('neutron.common.gceutils.delete_subnet') gce_mock.fake_operation())
def test_delete_subnet_postcommit(self, mock_delete, mock_wait):
mock_delete.side_effect = gce_mock.delete_anything @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_wait.side_effect = gce_mock.wait_for_operation @mock.patch('neutron.common.gceutils.delete_subnet')
self.assertIsNone(self._driver.delete_subnet_postcommit(self.context)) def test_delete_subnet_postcommit(self, mock_delete, mock_wait):
mock_wait.assert_called_once_with(self._driver.gce_svc, mock_delete.side_effect = gce_mock.delete_anything
self._driver.gce_project, mock_wait.side_effect = gce_mock.wait_for_operation
gce_mock.fake_operation()) self.assertIsNone(self._driver.delete_subnet_postcommit(self.context))
mock_wait.assert_called_once_with(self._driver.gce_svc,
def test_convert_sg_to_gce_failure_with_wrong_ethertype(self): self._driver.gce_project,
sg_rule = self.get_fake_sg_rule(ethertype=const.IPv6) gce_mock.fake_operation())
self.assertRaises(sg.SecurityGroupRuleInvalidEtherType,
self._driver._convert_secgrp_rule_to_gce, def test_convert_sg_to_gce_failure_with_wrong_ethertype(self):
rule=sg_rule, network_link=NETWORK_LINK) sg_rule = self.get_fake_sg_rule(ethertype=const.IPv6)
self.assertRaises(sg.SecurityGroupRuleInvalidEtherType,
def test_convert_sg_to_gce_failure_with_wrong_direction(self): self._driver._convert_secgrp_rule_to_gce,
sg_rule = self.get_fake_sg_rule(direction="egress") rule=sg_rule, network_link=NETWORK_LINK)
self.assertRaises(SecurityGroupInvalidDirection,
self._driver._convert_secgrp_rule_to_gce, def test_convert_sg_to_gce_failure_with_wrong_direction(self):
rule=sg_rule, network_link=NETWORK_LINK) sg_rule = self.get_fake_sg_rule(direction="egress")
self.assertRaises(SecurityGroupInvalidDirection,
def test_convert_sg_to_gce_failure_with_wrong_protocol(self): self._driver._convert_secgrp_rule_to_gce,
sg_rule = self.get_fake_sg_rule(protocol="fake_protocol") rule=sg_rule, network_link=NETWORK_LINK)
self.assertRaises(sg.SecurityGroupRuleInvalidProtocol,
self._driver._convert_secgrp_rule_to_gce, def test_convert_sg_to_gce_failure_with_wrong_protocol(self):
rule=sg_rule, network_link=NETWORK_LINK) sg_rule = self.get_fake_sg_rule(protocol="fake_protocol")
self.assertRaises(sg.SecurityGroupRuleInvalidProtocol,
def test_convert_sg_to_gce_success(self): self._driver._convert_secgrp_rule_to_gce,
sg_rule = self.get_fake_sg_rule() rule=sg_rule, network_link=NETWORK_LINK)
gce_rule = self._driver._convert_secgrp_rule_to_gce(
sg_rule, NETWORK_LINK) def test_convert_sg_to_gce_success(self):
self.assertTrue(isinstance(gce_rule, dict)) sg_rule = self.get_fake_sg_rule()
gce_rule = self._driver._convert_secgrp_rule_to_gce(
@mock.patch('neutron.common.gceutils.wait_for_operation') sg_rule, NETWORK_LINK)
@mock.patch('neutron.common.gceutils.create_firewall_rule') self.assertTrue(isinstance(gce_rule, dict))
def test_create_sg_rule(self, mock_create, mock_wait):
mock_create.side_effect = gce_mock.create_anything @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_wait.side_effect = gce_mock.wait_for_operation @mock.patch('neutron.common.gceutils.create_firewall_rule')
sg_rule = self.get_fake_sg_rule() def test_create_sg_rule(self, mock_create, mock_wait):
self.assertIsNone( mock_create.side_effect = gce_mock.create_anything
self._driver._create_secgrp_rule(self.context, sg_rule, mock_wait.side_effect = gce_mock.wait_for_operation
NETWORK_LINK)) sg_rule = self.get_fake_sg_rule()
mock_wait.assert_called_once_with(self._driver.gce_svc, self.assertIsNone(
self._driver.gce_project, self._driver._create_secgrp_rule(self.context, sg_rule,
gce_mock.fake_operation()) NETWORK_LINK))
mock_wait.assert_called_once_with(self._driver.gce_svc,
@mock.patch(neutron_get_plugin) self._driver.gce_project,
@mock.patch('neutron.common.gceutils.wait_for_operation') gce_mock.fake_operation())
@mock.patch('neutron.common.gceutils.update_firewall_rule')
@mock.patch('neutron.common.gceutils.get_firewall_rule') @mock.patch(neutron_get_plugin)
def test_update_sg_rule(self, mock_get, mock_update, mock_wait, @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_plugin): @mock.patch('neutron.common.gceutils.update_firewall_rule')
mock_get.side_effect = gce_mock.get_firewall_rule @mock.patch('neutron.common.gceutils.get_firewall_rule')
mock_update.side_effect = gce_mock.create_anything def test_update_sg_rule(self, mock_get, mock_update, mock_wait,
mock_wait.side_effect = gce_mock.wait_for_operation mock_plugin):
mock_plugin.side_effect = FakeNeutronManager mock_get.side_effect = gce_mock.get_firewall_rule
sg_rule = self.get_fake_sg_rule() mock_update.side_effect = gce_mock.create_anything
self.assertIsNone( mock_wait.side_effect = gce_mock.wait_for_operation
self._driver._update_secgrp_rule(self.context, sg_rule['id'])) mock_plugin.side_effect = FakeNeutronManager
self.assertTrue(mock_update.called) sg_rule = self.get_fake_sg_rule()
self.assertIsNone(
@mock.patch('neutron.common.gceutils.wait_for_operation') self._driver._update_secgrp_rule(self.context, sg_rule['id']))
@mock.patch('neutron.common.gceutils.delete_firewall_rule') self.assertTrue(mock_update.called)
def test_delete_sg_rule(self, mock_delete, mock_wait):
mock_delete.side_effect = gce_mock.delete_anything @mock.patch('neutron.common.gceutils.wait_for_operation')
mock_wait.side_effect = gce_mock.wait_for_operation @mock.patch('neutron.common.gceutils.delete_firewall_rule')
sg_rule = self.get_fake_sg_rule() def test_delete_sg_rule(self, mock_delete, mock_wait):
self.assertIsNone( mock_delete.side_effect = gce_mock.delete_anything
self._driver._delete_secgrp_rule(self.context, sg_rule['id'])) mock_wait.side_effect = gce_mock.wait_for_operation
mock_delete.assert_called_once_with(self._driver.gce_svc, sg_rule = self.get_fake_sg_rule()
self._driver.gce_project, self.assertIsNone(
"secgrp-" + sg_rule['id']) self._driver._delete_secgrp_rule(self.context, sg_rule['id']))
mock_delete.assert_called_once_with(self._driver.gce_svc,
self._driver.gce_project,
"secgrp-" + sg_rule['id'])