Check network conflict

The user's network to create instance should not conflict with the
management network.

Change-Id: I922a1c5469309704cc6dd60a1ef57e43a98a3c00
This commit is contained in:
Lingxian Kong 2020-01-14 11:15:37 +13:00
parent a5f6c9b82c
commit 263339b4db
3 changed files with 55 additions and 7 deletions

View File

@ -596,6 +596,10 @@ class PublicNetworkNotFound(TroveError):
message = _("Public network cannot be found.") message = _("Public network cannot be found.")
class NetworkConflict(BadRequest):
message = _("User network conflicts with the management network.")
class ClusterVolumeSizeRequired(TroveError): class ClusterVolumeSizeRequired(TroveError):
message = _("A volume size is required for each instance in the cluster.") message = _("A volume size is required for each instance in the cluster.")

View File

@ -21,6 +21,7 @@ from trove.common import exception
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
MGMT_NETWORKS = None MGMT_NETWORKS = None
MGMT_CIDRS = None
def get_management_networks(context): def get_management_networks(context):
@ -147,3 +148,27 @@ def create_security_group_rule(client, sg_id, protocol, ports, remote_ips):
} }
client.create_security_group_rule(body) client.create_security_group_rule(body)
def get_subnet_cidrs(client, network_id):
cidrs = []
subnets = client.list_subnets(network_id=network_id)['subnets']
for subnet in subnets:
cidrs.append(subnet.get('cidr'))
return cidrs
def get_mamangement_subnet_cidrs(client):
"""Cache the management subnet CIDRS."""
global MGMT_CIDRS
if MGMT_CIDRS is not None:
return MGMT_CIDRS
MGMT_CIDRS = []
if len(CONF.management_networks) > 0:
MGMT_CIDRS = get_subnet_cidrs(client, CONF.management_networks[0])
return MGMT_CIDRS

View File

@ -13,6 +13,8 @@
# 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 ipaddress
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import strutils from oslo_utils import strutils
@ -20,9 +22,10 @@ from trove.backup.models import Backup as backup_model
from trove.backup import views as backup_views from trove.backup import views as backup_views
import trove.common.apischema as apischema import trove.common.apischema as apischema
from trove.common import cfg from trove.common import cfg
from trove.common.clients import create_guest_client from trove.common import clients
from trove.common import exception from trove.common import exception
from trove.common.i18n import _ from trove.common.i18n import _
from trove.common import neutron
from trove.common import notification from trove.common import notification
from trove.common.notification import StartNotification from trove.common.notification import StartNotification
from trove.common import pagination from trove.common import pagination
@ -279,6 +282,19 @@ class InstanceController(wsgi.Controller):
instance.delete() instance.delete()
return wsgi.Result(None, 202) return wsgi.Result(None, 202)
def _check_network_overlap(self, context, user_network):
neutron_client = clients.create_neutron_client(context)
user_cidrs = neutron.get_subnet_cidrs(neutron_client, user_network)
mgmt_cidrs = neutron.get_mamangement_subnet_cidrs(neutron_client)
LOG.debug("Cidrs of the user network: %s, cidrs of the management "
"network: %s", user_cidrs, mgmt_cidrs)
for user_cidr in user_cidrs:
user_net = ipaddress.ip_network(user_cidr)
for mgmt_cidr in mgmt_cidrs:
mgmt_net = ipaddress.ip_network(mgmt_cidr)
if user_net.overlaps(mgmt_net):
raise exception.NetworkConflict()
def create(self, req, body, tenant_id): def create(self, req, body, tenant_id):
# TODO(hub-cap): turn this into middleware # TODO(hub-cap): turn this into middleware
LOG.info("Creating a database instance for tenant '%s'", LOG.info("Creating a database instance for tenant '%s'",
@ -342,7 +358,10 @@ class InstanceController(wsgi.Controller):
backup_id = None backup_id = None
availability_zone = body['instance'].get('availability_zone') availability_zone = body['instance'].get('availability_zone')
nics = body['instance'].get('nics', []) nics = body['instance'].get('nics', [])
if len(nics) > 0:
self._check_network_overlap(context, nics[0].get('net-id'))
slave_of_id = body['instance'].get('replica_of', slave_of_id = body['instance'].get('replica_of',
# also check for older name # also check for older name
@ -499,7 +518,7 @@ class InstanceController(wsgi.Controller):
if not instance: if not instance:
raise exception.NotFound(uuid=id) raise exception.NotFound(uuid=id)
self.authorize_instance_action(context, 'guest_log_list', instance) self.authorize_instance_action(context, 'guest_log_list', instance)
client = create_guest_client(context, id) client = clients.create_guest_client(context, id)
guest_log_list = client.guest_log_list() guest_log_list = client.guest_log_list()
return wsgi.Result({'logs': guest_log_list}, 200) return wsgi.Result({'logs': guest_log_list}, 200)
@ -523,7 +542,7 @@ class InstanceController(wsgi.Controller):
discard = body.get('discard', None) discard = body.get('discard', None)
if enable and disable: if enable and disable:
raise exception.BadRequest(_("Cannot enable and disable log.")) raise exception.BadRequest(_("Cannot enable and disable log."))
client = create_guest_client(context, id) client = clients.create_guest_client(context, id)
guest_log = client.guest_log_action(log_name, enable, disable, guest_log = client.guest_log_action(log_name, enable, disable,
publish, discard) publish, discard)
return wsgi.Result({'log': guest_log}, 200) return wsgi.Result({'log': guest_log}, 200)
@ -546,13 +565,13 @@ class InstanceController(wsgi.Controller):
def _module_list_guest(self, context, id, include_contents): def _module_list_guest(self, context, id, include_contents):
"""Return information about modules on an instance.""" """Return information about modules on an instance."""
client = create_guest_client(context, id) client = clients.create_guest_client(context, id)
result_list = client.module_list(include_contents) result_list = client.module_list(include_contents)
return wsgi.Result({'modules': result_list}, 200) return wsgi.Result({'modules': result_list}, 200)
def _module_list(self, context, id, include_contents): def _module_list(self, context, id, include_contents):
"""Return information about instance modules.""" """Return information about instance modules."""
client = create_guest_client(context, id) client = clients.create_guest_client(context, id)
result_list = client.module_list(include_contents) result_list = client.module_list(include_contents)
return wsgi.Result({'modules': result_list}, 200) return wsgi.Result({'modules': result_list}, 200)
@ -568,7 +587,7 @@ class InstanceController(wsgi.Controller):
module_models.Modules.validate( module_models.Modules.validate(
modules, instance.datastore.id, instance.datastore_version.id) modules, instance.datastore.id, instance.datastore_version.id)
module_list = module_views.convert_modules_to_list(modules) module_list = module_views.convert_modules_to_list(modules)
client = create_guest_client(context, id) client = clients.create_guest_client(context, id)
result_list = client.module_apply(module_list) result_list = client.module_apply(module_list)
models.Instance.add_instance_modules(context, id, modules) models.Instance.add_instance_modules(context, id, modules)
return wsgi.Result({'modules': result_list}, 200) return wsgi.Result({'modules': result_list}, 200)
@ -582,7 +601,7 @@ class InstanceController(wsgi.Controller):
self.authorize_instance_action(context, 'module_remove', instance) self.authorize_instance_action(context, 'module_remove', instance)
module = module_models.Module.load(context, module_id) module = module_models.Module.load(context, module_id)
module_info = module_views.DetailedModuleView(module).data() module_info = module_views.DetailedModuleView(module).data()
client = create_guest_client(context, id) client = clients.create_guest_client(context, id)
client.module_remove(module_info) client.module_remove(module_info)
instance_modules = module_models.InstanceModules.load_all( instance_modules = module_models.InstanceModules.load_all(
context, instance_id=id, module_id=module_id) context, instance_id=id, module_id=module_id)