¡@

Home 

OpenStack Study: model.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright 2011 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 functools

import eventlet

import netaddr

import six

from nova import exception

from nova.openstack.common.gettextutils import _

from nova.openstack.common import jsonutils

**** CubicPower OpenStack Study ****

def ensure_string_keys(d):

    # http://bugs.python.org/issue4978

    return dict([(str(k), v) for k, v in d.iteritems()])

# Constants for the 'vif_type' field in VIF class

VIF_TYPE_OVS = 'ovs'

VIF_TYPE_IVS = 'ivs'

VIF_TYPE_IOVISOR = 'iovisor'

VIF_TYPE_BRIDGE = 'bridge'

VIF_TYPE_802_QBG = '802.1qbg'

VIF_TYPE_802_QBH = '802.1qbh'

VIF_TYPE_MLNX_DIRECT = 'mlnx_direct'

VIF_TYPE_MIDONET = 'midonet'

VIF_TYPE_OTHER = 'other'

# Constants for dictionary keys in the 'vif_details' field in the VIF

# class

VIF_DETAIL_PORT_FILTER = 'port_filter'

VIF_DETAIL_OVS_HYBRID_PLUG = 'ovs_hybrid_plug'

# Constant for max length of network interface names

# eg 'bridge' in the Network class or 'devname' in

# the VIF class

NIC_NAME_LEN = 14

**** CubicPower OpenStack Study ****

class Model(dict):

"""Defines some necessary structures for most of the network models."""

**** CubicPower OpenStack Study ****

    def __repr__(self):

        return self.__class__.__name__ + '(' + dict.__repr__(self) + ')'

**** CubicPower OpenStack Study ****

    def _set_meta(self, kwargs):

        # pull meta out of kwargs if it's there

        self['meta'] = kwargs.pop('meta', {})

        # update meta with any additional kwargs that may exist

        self['meta'].update(kwargs)

**** CubicPower OpenStack Study ****

    def get_meta(self, key, default=None):

        """calls get(key, default) on self['meta']."""

        return self['meta'].get(key, default)

**** CubicPower OpenStack Study ****

class IP(Model):

"""Represents an IP address in Nova."""

**** CubicPower OpenStack Study ****

    def __init__(self, address=None, type=None, **kwargs):

        super(IP, self).__init__()

        self['address'] = address

        self['type'] = type

        self['version'] = kwargs.pop('version', None)

        self._set_meta(kwargs)

        # determine version from address if not passed in

        if self['address'] and not self['version']:

            try:

                self['version'] = netaddr.IPAddress(self['address']).version

            except netaddr.AddrFormatError:

                msg = _("Invalid IP format %s") % self['address']

                raise exception.InvalidIpAddressError(msg)

**** CubicPower OpenStack Study ****

    def __eq__(self, other):

        keys = ['address', 'type', 'version']

        return all(self[k] == other[k] for k in keys)

**** CubicPower OpenStack Study ****

    def __ne__(self, other):

        return not self.__eq__(other)

**** CubicPower OpenStack Study ****

    def is_in_subnet(self, subnet):

        if self['address'] and subnet['cidr']:

            return (netaddr.IPAddress(self['address']) in

                    netaddr.IPNetwork(subnet['cidr']))

        else:

            return False

    @classmethod

**** CubicPower OpenStack Study ****

    def hydrate(cls, ip):

        if ip:

            return cls(**ensure_string_keys(ip))

        return None

**** CubicPower OpenStack Study ****

class FixedIP(IP):

"""Represents a Fixed IP address in Nova."""

**** CubicPower OpenStack Study ****

    def __init__(self, floating_ips=None, **kwargs):

        super(FixedIP, self).__init__(**kwargs)

        self['floating_ips'] = floating_ips or []

        if not self['type']:

            self['type'] = 'fixed'

**** CubicPower OpenStack Study ****

    def add_floating_ip(self, floating_ip):

        if floating_ip not in self['floating_ips']:

            self['floating_ips'].append(floating_ip)

**** CubicPower OpenStack Study ****

    def floating_ip_addresses(self):

        return [ip['address'] for ip in self['floating_ips']]

    @staticmethod

**** CubicPower OpenStack Study ****

    def hydrate(fixed_ip):

        fixed_ip = FixedIP(**ensure_string_keys(fixed_ip))

        fixed_ip['floating_ips'] = [IP.hydrate(floating_ip)

                                   for floating_ip in fixed_ip['floating_ips']]

        return fixed_ip

**** CubicPower OpenStack Study ****

    def __eq__(self, other):

        keys = ['address', 'type', 'version', 'floating_ips']

        return all(self[k] == other[k] for k in keys)

**** CubicPower OpenStack Study ****

    def __ne__(self, other):

        return not self.__eq__(other)

**** CubicPower OpenStack Study ****

class Route(Model):

"""Represents an IP Route in Nova."""

**** CubicPower OpenStack Study ****

    def __init__(self, cidr=None, gateway=None, interface=None, **kwargs):

        super(Route, self).__init__()

        self['cidr'] = cidr

        self['gateway'] = gateway

        self['interface'] = interface

        self._set_meta(kwargs)

    @classmethod

**** CubicPower OpenStack Study ****

    def hydrate(cls, route):

        route = cls(**ensure_string_keys(route))

        route['gateway'] = IP.hydrate(route['gateway'])

        return route

**** CubicPower OpenStack Study ****

class Subnet(Model):

"""Represents a Subnet in Nova."""

**** CubicPower OpenStack Study ****

    def __init__(self, cidr=None, dns=None, gateway=None, ips=None,

                 routes=None, **kwargs):

        super(Subnet, self).__init__()

        self['cidr'] = cidr

        self['dns'] = dns or []

        self['gateway'] = gateway

        self['ips'] = ips or []

        self['routes'] = routes or []

        self['version'] = kwargs.pop('version', None)

        self._set_meta(kwargs)

        if self['cidr'] and not self['version']:

            self['version'] = netaddr.IPNetwork(self['cidr']).version

**** CubicPower OpenStack Study ****

    def __eq__(self, other):

        keys = ['cidr', 'dns', 'gateway', 'ips', 'routes', 'version']

        return all(self[k] == other[k] for k in keys)

**** CubicPower OpenStack Study ****

    def __ne__(self, other):

        return not self.__eq__(other)

**** CubicPower OpenStack Study ****

    def add_route(self, new_route):

        if new_route not in self['routes']:

            self['routes'].append(new_route)

**** CubicPower OpenStack Study ****

    def add_dns(self, dns):

        if dns not in self['dns']:

            self['dns'].append(dns)

**** CubicPower OpenStack Study ****

    def add_ip(self, ip):

        if ip not in self['ips']:

            self['ips'].append(ip)

**** CubicPower OpenStack Study ****

    def as_netaddr(self):

        """Convience function to get cidr as a netaddr object."""

        return netaddr.IPNetwork(self['cidr'])

    @classmethod

**** CubicPower OpenStack Study ****

    def hydrate(cls, subnet):

        subnet = cls(**ensure_string_keys(subnet))

        subnet['dns'] = [IP.hydrate(dns) for dns in subnet['dns']]

        subnet['ips'] = [FixedIP.hydrate(ip) for ip in subnet['ips']]

        subnet['routes'] = [Route.hydrate(route) for route in subnet['routes']]

        subnet['gateway'] = IP.hydrate(subnet['gateway'])

        return subnet

**** CubicPower OpenStack Study ****

class Network(Model):

"""Represents a Network in Nova."""

**** CubicPower OpenStack Study ****

    def __init__(self, id=None, bridge=None, label=None,

                 subnets=None, **kwargs):

        super(Network, self).__init__()

        self['id'] = id

        self['bridge'] = bridge

        self['label'] = label

        self['subnets'] = subnets or []

        self._set_meta(kwargs)

**** CubicPower OpenStack Study ****

    def add_subnet(self, subnet):

        if subnet not in self['subnets']:

            self['subnets'].append(subnet)

    @classmethod

**** CubicPower OpenStack Study ****

    def hydrate(cls, network):

        if network:

            network = cls(**ensure_string_keys(network))

            network['subnets'] = [Subnet.hydrate(subnet)

                                  for subnet in network['subnets']]

        return network

**** CubicPower OpenStack Study ****

    def __eq__(self, other):

        keys = ['id', 'bridge', 'label', 'subnets']

        return all(self[k] == other[k] for k in keys)

**** CubicPower OpenStack Study ****

    def __ne__(self, other):

        return not self.__eq__(other)

**** CubicPower OpenStack Study ****

class VIF8021QbgParams(Model):

"""Represents the parameters for a 802.1qbg VIF."""

**** CubicPower OpenStack Study ****

    def __init__(self, managerid, typeid, typeidversion, instanceid):

        self['managerid'] = managerid

        self['typeid'] = typeid

        self['typeidversion'] = typeidversion

        self['instanceid'] = instanceid

**** CubicPower OpenStack Study ****

class VIF8021QbhParams(Model):

"""Represents the parameters for a 802.1qbh VIF."""

**** CubicPower OpenStack Study ****

    def __init__(self, profileid):

        self['profileid'] = profileid

**** CubicPower OpenStack Study ****

class VIF(Model):

"""Represents a Virtual Interface in Nova."""

**** CubicPower OpenStack Study ****

    def __init__(self, id=None, address=None, network=None, type=None,

                 details=None, devname=None, ovs_interfaceid=None,

                 qbh_params=None, qbg_params=None, active=False,

                 **kwargs):

        super(VIF, self).__init__()

        self['id'] = id

        self['address'] = address

        self['network'] = network or None

        self['type'] = type

        self['details'] = details or {}

        self['devname'] = devname

        self['ovs_interfaceid'] = ovs_interfaceid

        self['qbh_params'] = qbh_params

        self['qbg_params'] = qbg_params

        self['active'] = active

        self._set_meta(kwargs)

**** CubicPower OpenStack Study ****

    def __eq__(self, other):

        keys = ['id', 'address', 'network', 'type', 'details', 'devname',

                'ovs_interfaceid', 'qbh_params', 'qbg_params',

                'active']

        return all(self[k] == other[k] for k in keys)

**** CubicPower OpenStack Study ****

    def __ne__(self, other):

        return not self.__eq__(other)

**** CubicPower OpenStack Study ****

    def fixed_ips(self):

        return [fixed_ip for subnet in self['network']['subnets']

                         for fixed_ip in subnet['ips']]

**** CubicPower OpenStack Study ****

    def floating_ips(self):

        return [floating_ip for fixed_ip in self.fixed_ips()

                            for floating_ip in fixed_ip['floating_ips']]

**** CubicPower OpenStack Study ****

    def labeled_ips(self):

        """Returns the list of all IPs

        The return value looks like this flat structure::

            {'network_label': 'my_network',

             'network_id': 'n8v29837fn234782f08fjxk3ofhb84',

             'ips': [{'address': '123.123.123.123',

                      'version': 4,

                      'type: 'fixed',

                      'meta': {...}},

                     {'address': '124.124.124.124',

                      'version': 4,

                      'type': 'floating',

                      'meta': {...}},

                     {'address': 'fe80::4',

                      'version': 6,

                      'type': 'fixed',

                      'meta': {...}}]

        """

        if self['network']:

            # remove unnecessary fields on fixed_ips

            ips = [IP(**ensure_string_keys(ip)) for ip in self.fixed_ips()]

            for ip in ips:

                # remove floating ips from IP, since this is a flat structure

                # of all IPs

                del ip['meta']['floating_ips']

            # add floating ips to list (if any)

            ips.extend(self.floating_ips())

            return {'network_label': self['network']['label'],

                    'network_id': self['network']['id'],

                    'ips': ips}

        return []

**** CubicPower OpenStack Study ****

    def is_hybrid_plug_enabled(self):

        return self['details'].get(VIF_DETAIL_OVS_HYBRID_PLUG, False)

**** CubicPower OpenStack Study ****

    def is_neutron_filtering_enabled(self):

        return self['details'].get(VIF_DETAIL_PORT_FILTER, False)

    @classmethod

**** CubicPower OpenStack Study ****

    def hydrate(cls, vif):

        vif = cls(**ensure_string_keys(vif))

        vif['network'] = Network.hydrate(vif['network'])

        return vif

def get_netmask(ip, subnet):

    """Returns the netmask appropriate for injection into a guest."""

    if ip['version'] == 4:

        return str(subnet.as_netaddr().netmask)

    return subnet.as_netaddr()._prefixlen

**** CubicPower OpenStack Study ****

def get_netmask(ip, subnet):

    """Returns the netmask appropriate for injection into a guest."""

    if ip['version'] == 4:

        return str(subnet.as_netaddr().netmask)

    return subnet.as_netaddr()._prefixlen

**** CubicPower OpenStack Study ****

class NetworkInfo(list):

"""Stores and manipulates network information for a Nova instance."""

# NetworkInfo is a list of VIFs

**** CubicPower OpenStack Study ****

    def fixed_ips(self):

        """Returns all fixed_ips without floating_ips attached."""

        return [ip for vif in self for ip in vif.fixed_ips()]

**** CubicPower OpenStack Study ****

    def floating_ips(self):

        """Returns all floating_ips."""

        return [ip for vif in self for ip in vif.floating_ips()]

    @classmethod

**** CubicPower OpenStack Study ****

    def hydrate(cls, network_info):

        if isinstance(network_info, six.string_types):

            network_info = jsonutils.loads(network_info)

        return cls([VIF.hydrate(vif) for vif in network_info])

**** CubicPower OpenStack Study ****

    def json(self):

        return jsonutils.dumps(self)

**** CubicPower OpenStack Study ****

class NetworkInfoAsyncWrapper(NetworkInfo):

"""Wrapper around NetworkInfo that allows retrieving NetworkInfo

in an async manner.

This allows one to start querying for network information before

you know you will need it. If you have a long-running

operation, this allows the network model retrieval to occur in the

background. When you need the data, it will ensure the async

operation has completed.

As an example:

**** CubicPower OpenStack Study ****

    def allocate_net_info(arg1, arg2)

        return call_neutron_to_allocate(arg1, arg2)

    network_info = NetworkInfoAsyncWrapper(allocate_net_info, arg1, arg2)

    [do a long running operation -- real network_info will be retrieved

    in the background]

    [do something with network_info]

    """

**** CubicPower OpenStack Study ****

    def __init__(self, async_method, *args, **kwargs):

        self._gt = eventlet.spawn(async_method, *args, **kwargs)

        methods = ['json', 'fixed_ips', 'floating_ips']

        for method in methods:

            fn = getattr(self, method)

            wrapper = functools.partial(self._sync_wrapper, fn)

            functools.update_wrapper(wrapper, fn)

            setattr(self, method, wrapper)

**** CubicPower OpenStack Study ****

    def _sync_wrapper(self, wrapped, *args, **kwargs):

        """Synchronize the model before running a method."""

        self.wait()

        return wrapped(*args, **kwargs)

**** CubicPower OpenStack Study ****

    def __getitem__(self, *args, **kwargs):

        fn = super(NetworkInfoAsyncWrapper, self).__getitem__

        return self._sync_wrapper(fn, *args, **kwargs)

**** CubicPower OpenStack Study ****

    def __iter__(self, *args, **kwargs):

        fn = super(NetworkInfoAsyncWrapper, self).__iter__

        return self._sync_wrapper(fn, *args, **kwargs)

**** CubicPower OpenStack Study ****

    def __len__(self, *args, **kwargs):

        fn = super(NetworkInfoAsyncWrapper, self).__len__

        return self._sync_wrapper(fn, *args, **kwargs)

**** CubicPower OpenStack Study ****

    def __str__(self, *args, **kwargs):

        fn = super(NetworkInfoAsyncWrapper, self).__str__

        return self._sync_wrapper(fn, *args, **kwargs)

**** CubicPower OpenStack Study ****

    def __repr__(self, *args, **kwargs):

        fn = super(NetworkInfoAsyncWrapper, self).__repr__

        return self._sync_wrapper(fn, *args, **kwargs)

**** CubicPower OpenStack Study ****

    def wait(self, do_raise=True):

        """Wait for async call to finish."""

        if self._gt is not None:

            try:

                # NOTE(comstud): This looks funky, but this object is

                # subclassed from list.  In other words, 'self' is really

                # just a list with a bunch of extra methods.  So this

                # line just replaces the current list (which should be

                # empty) with the result.

                self[:] = self._gt.wait()

            except Exception:

                if do_raise:

                    raise

            finally:

                self._gt = None