Merge "Use code from AdvNetworking for MS SQL Cluster IP validation."

This commit is contained in:
Jenkins 2013-12-10 16:17:42 +00:00 committed by Gerrit Code Review
commit a3e579de5b
7 changed files with 205 additions and 17 deletions

View File

@ -21,6 +21,8 @@ from muranoclient.v1.client import Client
from muranodashboard.environments.services import get_service_name
from muranoclient.common.exceptions import HTTPForbidden, HTTPNotFound
from consts import STATUS_ID_READY, STATUS_ID_NEW
from .network import get_network_params
log = logging.getLogger(__name__)
@ -178,9 +180,10 @@ def environments_list(request):
def environment_create(request, parameters):
body = get_network_params(request)
#name is required param
name = parameters['name']
env = muranoclient(request).environments.create(name)
body['name'] = parameters['name']
env = muranoclient(request).environments.create(body)
log.debug('Environment::Create {0}'.format(env))
return env

View File

@ -0,0 +1,134 @@
# Copyright (c) 2013 Mirantis Inc.
#
# 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 math
from django.conf import settings
from keystoneclient.v2_0 import client as ksclient
import netaddr
from netaddr.strategy import ipv4
from neutronclient.v2_0 import client as neutronclient
import logging
log = logging.getLogger(__name__)
class NeutronSubnetGetter(object):
def __init__(self, tenant_id, token, router_id=None):
conf = getattr(settings, 'ADVANCED_NETWORKING_CONFIG', {})
self.env_count = conf.get('max_environments', 100)
self.host_count = conf.get('max_hosts', 250)
self.address = conf.get('env_ip_template', '10.0.0.0')
self.tenant_id = tenant_id
self.router_id = router_id
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
endpoint_type = getattr(
settings, 'OPENSTACK_ENDPOINT_TYPE', 'publicURL')
keystone_client = ksclient.Client(
auth_url=settings.OPENSTACK_KEYSTONE_URL,
tenant_id=tenant_id,
token=token,
cacert=cacert,
insecure=insecure)
if not keystone_client.authenticate():
raise ksclient.exceptions.Unauthorized()
neutron_url = keystone_client.service_catalog.url_for(
service_type='network', endpoint_type=endpoint_type)
self.neutron = neutronclient.Client(endpoint_url=neutron_url,
token=token,
ca_cert=cacert,
insecure=insecure)
def _get_router_id(self):
routers = self.neutron.list_routers(tenant_id=self.tenant_id).\
get("routers")
if not len(routers):
router_id = None
else:
router_id = routers[0]["id"]
if len(routers) > 1:
for router in routers:
if "murano" in router["name"].lower():
router_id = router["id"]
break
return router_id
def _get_subnet(self, router_id=None, count=1):
if router_id:
taken_cidrs = self._get_taken_cidrs_by_router(router_id)
else:
taken_cidrs = self._get_all_taken_cidrs()
results = []
for i in range(0, count):
res = self._generate_cidr(taken_cidrs)
results.append(res)
taken_cidrs.append(res)
return results
def _get_taken_cidrs_by_router(self, router_id):
ports = self.neutron.list_ports(device_id=router_id)["ports"]
subnet_ids = []
for port in ports:
for fixed_ip in port["fixed_ips"]:
subnet_ids.append(fixed_ip["subnet_id"])
all_subnets = self.neutron.list_subnets()["subnets"]
filtered_cidrs = [subnet["cidr"] for subnet in all_subnets if
subnet["id"] in subnet_ids]
return filtered_cidrs
def _get_all_taken_cidrs(self):
return [subnet["cidr"] for subnet in
self.neutron.list_subnets()["subnets"]]
def _generate_cidr(self, taken_cidrs):
bits_for_envs = int(math.ceil(math.log(self.env_count, 2)))
bits_for_hosts = int(math.ceil(math.log(self.host_count, 2)))
width = ipv4.width
mask_width = width - bits_for_hosts - bits_for_envs
net = netaddr.IPNetwork(self.address + "/" + str(mask_width))
for subnet in net.subnet(width - bits_for_hosts):
if str(subnet) in taken_cidrs:
continue
return str(subnet)
return None
def get_subnet(self, environment_id=None):
# TODO: should use environment_id for getting cidr in future
router_id = self.router_id or self._get_router_id()
return self._get_subnet(router_id)[0]
def get_network_params(request):
network_topology = getattr(settings, 'NETWORK_TOPOLOGY', 'routed')
if network_topology != 'nova':
getter = NeutronSubnetGetter(request.user.tenant_id,
request.user.token.id)
existing_subnet = getter.get_subnet()
if existing_subnet:
return {'networking': {'topology': network_topology,
'createNetwork': True,
'cidr': existing_subnet}}
else:
log.error('Cannot get subnet')
return {'networking': {'topology': network_topology}}

View File

@ -16,7 +16,7 @@ import re
import json
from django import forms
from django.core.validators import RegexValidator, validate_ipv4_address
from netaddr import all_matching_cidrs
from netaddr import all_matching_cidrs, IPNetwork, IPAddress
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_text
from muranodashboard.environments import api
@ -32,6 +32,7 @@ import horizon.tables as tables
import floppyforms
from django.template.loader import render_to_string
log = logging.getLogger(__name__)
@ -53,6 +54,10 @@ def with_request(func):
"""
def update(self, initial, request=None, **kwargs):
initial_request = initial.get('request')
for key, value in initial.iteritems():
if key != 'request' and key not in kwargs:
kwargs[key] = value
if initial_request:
log.debug("Using 'request' value from initial dictionary")
func(self, initial_request, **kwargs)
@ -553,8 +558,12 @@ class BooleanField(forms.BooleanField, CustomPropertiesField):
class ClusterIPField(CharField):
existing_subnet = None
network_topology = None
router_id = None
@staticmethod
def validate_cluster_ip(request, ip_ranges):
def make_nova_validator(request, ip_ranges):
def perform_checking(ip):
validate_ipv4_address(ip)
if not all_matching_cidrs(ip, ip_ranges) and ip_ranges:
@ -581,19 +590,45 @@ class ClusterIPField(CharField):
_('Specified Cluster Static IP is already in use'))
return perform_checking
def update_network_params(self, request, environment_id):
env = api.environment_get(request, environment_id)
self.existing_subnet = env.networking.get('cidr')
self.network_topology = env.networking.get('topology')
def make_neutron_validator(self):
def perform_checking(ip):
validate_ipv4_address(ip)
if not self.existing_subnet:
raise forms.ValidationError(
_('Cannot get allowed subnet for the environment, '
'consult your admin'))
elif not IPAddress(ip) in IPNetwork(self.existing_subnet):
raise forms.ValidationError(
_('Specified IP address should belong to {0} '
'subnet'.format(self.existing_subnet)))
return perform_checking
@with_request
def update(self, request, **kwargs):
try:
network_list = novaclient(request).networks.list()
ip_ranges = [network.cidr for network in network_list]
ranges = ', '.join(ip_ranges)
except StandardError:
ip_ranges, ranges = [], ''
if ip_ranges:
self.help_text = _('Select IP from available range: ' + ranges)
else:
self.help_text = _('Specify valid fixed IP')
self.validators = [self.validate_cluster_ip(request, ip_ranges)]
def update(self, request, environment_id, **kwargs):
self.update_network_params(request, environment_id)
if self.network_topology == 'nova':
try:
network_list = novaclient(request).networks.list()
ip_ranges = [network.cidr for network in network_list]
ranges = ', '.join(ip_ranges)
except StandardError:
ip_ranges, ranges = [], ''
if ip_ranges:
self.help_text = _('Select IP from available range: ' + ranges)
else:
self.help_text = _('Specify valid fixed IP')
self.validators = [self.make_nova_validator(request, ip_ranges)]
elif self.network_topology == 'routed':
self.validators = [self.make_neutron_validator()]
else: # 'flat' topology
raise NotImplementedError('Flat topology is not implemented yet')
self.error_messages['invalid'] = validate_ipv4_address.message

View File

@ -133,7 +133,10 @@ class Wizard(ModalFormMixin, LazyWizard):
def get_form_initial(self, step):
init_dict = {}
if step != 'service_choice':
init_dict['request'] = self.request
init_dict.update({
'request': self.request,
'environment_id': self.kwargs.get('environment_id')
})
return self.initial_dict.get(step, init_dict)
def get_context_data(self, form, **kwargs):

View File

@ -159,3 +159,12 @@ except ImportError:
if DEBUG:
logging.basicConfig(level=logging.DEBUG)
ADVANCED_NETWORKING_CONFIG = {
# Maximum number of environments that can be processed simultaneously
'max_environments': 100,
# Maximum number of VMs per environment
'max_hosts': 250,
# Template IP address for generating environment subnet cidrs
'env_ip_template': '10.0.0.0'
}

View File

@ -121,6 +121,8 @@ LOGGING['loggers']['muranoclient'] = {'handlers': ['murano-file'], 'level': 'ERR
#MURANO_METADATA_URL = "http://localhost:8084/v1"
#if murano-api set up with ssl uncomment next strings
#MURANO_API_INSECURE = True
ADVANCED_NETWORKING_CONFIG = {'max_environments': 100, 'max_hosts': 250, 'env_ip_template': '10.0.0.0'}
NETWORK_TOPOLOGY = 'routed'
#END_MURANO_DASHBOARD
EOF
if [ $? -ne 0 ];then

View File

@ -101,6 +101,8 @@ LOGGING['loggers']['muranoclient'] = {'handlers': ['murano-file'], 'level': 'ERR
#MURANO_METADATA_URL = "http://localhost:8084/v1"
#if murano-api set up with ssl uncomment next strings
#MURANO_API_INSECURE = True
ADVANCED_NETWORKING_CONFIG = {'max_environments': 100, 'max_hosts': 250, 'env_ip_template': '10.0.0.0'}
NETWORK_TOPOLOGY = 'routed'
#END_MURANO_DASHBOARD
EOF
if [ $? -ne 0 ];then