+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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 httplib
-
-
-def ctrl_conn_to_str(conn):
- """Returns a string representing a connection URL to the controller."""
- if isinstance(conn, httplib.HTTPSConnection):
- proto = "https://"
- elif isinstance(conn, httplib.HTTPConnection):
- proto = "http://"
- else:
- raise TypeError(_('Invalid connection type: %s') % type(conn))
- return "%s%s:%s" % (proto, conn.host, conn.port)
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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 abc
-import httplib
-import six
-import time
-
-from oslo_config import cfg
-
-from neutron.i18n import _LE, _LI, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware import api_client
-
-LOG = logging.getLogger(__name__)
-
-GENERATION_ID_TIMEOUT = -1
-DEFAULT_CONCURRENT_CONNECTIONS = 3
-DEFAULT_CONNECT_TIMEOUT = 5
-
-
-@six.add_metaclass(abc.ABCMeta)
-class ApiClientBase(object):
- """An abstract baseclass for all API client implementations."""
-
- def _create_connection(self, host, port, is_ssl):
- if is_ssl:
- return httplib.HTTPSConnection(host, port,
- timeout=self._connect_timeout)
- return httplib.HTTPConnection(host, port,
- timeout=self._connect_timeout)
-
- @staticmethod
- def _conn_params(http_conn):
- is_ssl = isinstance(http_conn, httplib.HTTPSConnection)
- return (http_conn.host, http_conn.port, is_ssl)
-
- @property
- def user(self):
- return self._user
-
- @property
- def password(self):
- return self._password
-
- @property
- def config_gen(self):
- # If NSX_gen_timeout is not -1 then:
- # Maintain a timestamp along with the generation ID. Hold onto the
- # ID long enough to be useful and block on sequential requests but
- # not long enough to persist when Onix db is cleared, which resets
- # the generation ID, causing the DAL to block indefinitely with some
- # number that's higher than the cluster's value.
- if self._gen_timeout != -1:
- ts = self._config_gen_ts
- if ts is not None:
- if (time.time() - ts) > self._gen_timeout:
- return None
- return self._config_gen
-
- @config_gen.setter
- def config_gen(self, value):
- if self._config_gen != value:
- if self._gen_timeout != -1:
- self._config_gen_ts = time.time()
- self._config_gen = value
-
- def auth_cookie(self, conn):
- cookie = None
- data = self._get_provider_data(conn)
- if data:
- cookie = data[1]
- return cookie
-
- def set_auth_cookie(self, conn, cookie):
- data = self._get_provider_data(conn)
- if data:
- self._set_provider_data(conn, (data[0], cookie))
-
- def acquire_connection(self, auto_login=True, headers=None, rid=-1):
- '''Check out an available HTTPConnection instance.
-
- Blocks until a connection is available.
- :auto_login: automatically logins before returning conn
- :headers: header to pass on to login attempt
- :param rid: request id passed in from request eventlet.
- :returns: An available HTTPConnection instance or None if no
- api_providers are configured.
- '''
- if not self._api_providers:
- LOG.warn(_LW("[%d] no API providers currently available."), rid)
- return None
- if self._conn_pool.empty():
- LOG.debug("[%d] Waiting to acquire API client connection.", rid)
- priority, conn = self._conn_pool.get()
- now = time.time()
- if getattr(conn, 'last_used', now) < now - cfg.CONF.conn_idle_timeout:
- LOG.info(_LI("[%(rid)d] Connection %(conn)s idle for %(sec)0.2f "
- "seconds; reconnecting."),
- {'rid': rid, 'conn': api_client.ctrl_conn_to_str(conn),
- 'sec': now - conn.last_used})
- conn = self._create_connection(*self._conn_params(conn))
-
- conn.last_used = now
- conn.priority = priority # stash current priority for release
- qsize = self._conn_pool.qsize()
- LOG.debug("[%(rid)d] Acquired connection %(conn)s. %(qsize)d "
- "connection(s) available.",
- {'rid': rid, 'conn': api_client.ctrl_conn_to_str(conn),
- 'qsize': qsize})
- if auto_login and self.auth_cookie(conn) is None:
- self._wait_for_login(conn, headers)
- return conn
-
- def release_connection(self, http_conn, bad_state=False,
- service_unavail=False, rid=-1):
- '''Mark HTTPConnection instance as available for check-out.
-
- :param http_conn: An HTTPConnection instance obtained from this
- instance.
- :param bad_state: True if http_conn is known to be in a bad state
- (e.g. connection fault.)
- :service_unavail: True if http_conn returned 503 response.
- :param rid: request id passed in from request eventlet.
- '''
- conn_params = self._conn_params(http_conn)
- if self._conn_params(http_conn) not in self._api_providers:
- LOG.debug("[%(rid)d] Released connection %(conn)s is not an "
- "API provider for the cluster",
- {'rid': rid,
- 'conn': api_client.ctrl_conn_to_str(http_conn)})
- return
- elif hasattr(http_conn, "no_release"):
- return
-
- priority = http_conn.priority
- if bad_state:
- # Reconnect to provider.
- LOG.warn(_LW("[%(rid)d] Connection returned in bad state, "
- "reconnecting to %(conn)s"),
- {'rid': rid,
- 'conn': api_client.ctrl_conn_to_str(http_conn)})
- http_conn = self._create_connection(*self._conn_params(http_conn))
- elif service_unavail:
- # http_conn returned a service unaviable response, put other
- # connections to the same controller at end of priority queue,
- conns = []
- while not self._conn_pool.empty():
- priority, conn = self._conn_pool.get()
- if self._conn_params(conn) == conn_params:
- priority = self._next_conn_priority
- self._next_conn_priority += 1
- conns.append((priority, conn))
- for priority, conn in conns:
- self._conn_pool.put((priority, conn))
- # put http_conn at end of queue also
- priority = self._next_conn_priority
- self._next_conn_priority += 1
-
- self._conn_pool.put((priority, http_conn))
- LOG.debug("[%(rid)d] Released connection %(conn)s. %(qsize)d "
- "connection(s) available.",
- {'rid': rid, 'conn': api_client.ctrl_conn_to_str(http_conn),
- 'qsize': self._conn_pool.qsize()})
-
- def _wait_for_login(self, conn, headers=None):
- '''Block until a login has occurred for the current API provider.'''
-
- data = self._get_provider_data(conn)
- if data is None:
- LOG.error(_LE("Login request for an invalid connection: '%s'"),
- api_client.ctrl_conn_to_str(conn))
- return
- provider_sem = data[0]
- if provider_sem.acquire(blocking=False):
- try:
- cookie = self._login(conn, headers)
- self.set_auth_cookie(conn, cookie)
- finally:
- provider_sem.release()
- else:
- LOG.debug("Waiting for auth to complete")
- # Wait until we can acquire then release
- provider_sem.acquire(blocking=True)
- provider_sem.release()
-
- def _get_provider_data(self, conn_or_conn_params, default=None):
- """Get data for specified API provider.
-
- Args:
- conn_or_conn_params: either a HTTP(S)Connection object or the
- resolved conn_params tuple returned by self._conn_params().
- default: conn_params if ones passed aren't known
- Returns: Data associated with specified provider
- """
- conn_params = self._normalize_conn_params(conn_or_conn_params)
- return self._api_provider_data.get(conn_params, default)
-
- def _set_provider_data(self, conn_or_conn_params, data):
- """Set data for specified API provider.
-
- Args:
- conn_or_conn_params: either a HTTP(S)Connection object or the
- resolved conn_params tuple returned by self._conn_params().
- data: data to associate with API provider
- """
- conn_params = self._normalize_conn_params(conn_or_conn_params)
- if data is None:
- del self._api_provider_data[conn_params]
- else:
- self._api_provider_data[conn_params] = data
-
- def _normalize_conn_params(self, conn_or_conn_params):
- """Normalize conn_param tuple.
-
- Args:
- conn_or_conn_params: either a HTTP(S)Connection object or the
- resolved conn_params tuple returned by self._conn_params().
-
- Returns: Normalized conn_param tuple
- """
- if (not isinstance(conn_or_conn_params, tuple) and
- not isinstance(conn_or_conn_params, httplib.HTTPConnection)):
- LOG.debug("Invalid conn_params value: '%s'",
- str(conn_or_conn_params))
- return conn_or_conn_params
- if isinstance(conn_or_conn_params, httplib.HTTPConnection):
- conn_params = self._conn_params(conn_or_conn_params)
- else:
- conn_params = conn_or_conn_params
- host, port, is_ssl = conn_params
- if port is None:
- port = 443 if is_ssl else 80
- return (host, port, is_ssl)
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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 httplib
-
-from neutron.i18n import _LE
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.api_client import base
-from neutron.plugins.vmware.api_client import eventlet_client
-from neutron.plugins.vmware.api_client import eventlet_request
-from neutron.plugins.vmware.api_client import exception
-from neutron.plugins.vmware.api_client import version
-
-LOG = logging.getLogger(__name__)
-
-
-class NsxApiClient(eventlet_client.EventletApiClient):
- """The Nsx API Client."""
-
- def __init__(self, api_providers, user, password,
- concurrent_connections=base.DEFAULT_CONCURRENT_CONNECTIONS,
- gen_timeout=base.GENERATION_ID_TIMEOUT,
- use_https=True,
- connect_timeout=base.DEFAULT_CONNECT_TIMEOUT,
- http_timeout=75, retries=2, redirects=2):
- '''Constructor. Adds the following:
-
- :param http_timeout: how long to wait before aborting an
- unresponsive controller (and allow for retries to another
- controller in the cluster)
- :param retries: the number of concurrent connections.
- :param redirects: the number of concurrent connections.
- '''
- super(NsxApiClient, self).__init__(
- api_providers, user, password,
- concurrent_connections=concurrent_connections,
- gen_timeout=gen_timeout, use_https=use_https,
- connect_timeout=connect_timeout)
-
- self._request_timeout = http_timeout * retries
- self._http_timeout = http_timeout
- self._retries = retries
- self._redirects = redirects
- self._version = None
-
- # NOTE(salvatore-orlando): This method is not used anymore. Login is now
- # performed automatically inside the request eventlet if necessary.
- def login(self, user=None, password=None):
- '''Login to NSX controller.
-
- Assumes same password is used for all controllers.
-
- :param user: controller user (usually admin). Provided for
- backwards compatibility. In the normal mode of operation
- this should be None.
- :param password: controller password. Provided for backwards
- compatibility. In the normal mode of operation this should
- be None.
- '''
- if user:
- self._user = user
- if password:
- self._password = password
-
- return self._login()
-
- def request(self, method, url, body="", content_type="application/json"):
- '''Issues request to controller.'''
-
- g = eventlet_request.GenericRequestEventlet(
- self, method, url, body, content_type, auto_login=True,
- http_timeout=self._http_timeout,
- retries=self._retries, redirects=self._redirects)
- g.start()
- response = g.join()
- LOG.debug('Request returns "%s"', response)
-
- # response is a modified HTTPResponse object or None.
- # response.read() will not work on response as the underlying library
- # request_eventlet.ApiRequestEventlet has already called this
- # method in order to extract the body and headers for processing.
- # ApiRequestEventlet derived classes call .read() and
- # .getheaders() on the HTTPResponse objects and store the results in
- # the response object's .body and .headers data members for future
- # access.
-
- if response is None:
- # Timeout.
- LOG.error(_LE('Request timed out: %(method)s to %(url)s'),
- {'method': method, 'url': url})
- raise exception.RequestTimeout()
-
- status = response.status
- if status == httplib.UNAUTHORIZED:
- raise exception.UnAuthorizedRequest()
-
- # Fail-fast: Check for exception conditions and raise the
- # appropriate exceptions for known error codes.
- if status in exception.ERROR_MAPPINGS:
- LOG.error(_LE("Received error code: %s"), status)
- LOG.error(_LE("Server Error Message: %s"), response.body)
- exception.ERROR_MAPPINGS[status](response)
-
- # Continue processing for non-error condition.
- if (status != httplib.OK and status != httplib.CREATED
- and status != httplib.NO_CONTENT):
- LOG.error(_LE("%(method)s to %(url)s, unexpected response code: "
- "%(status)d (content = '%(body)s')"),
- {'method': method, 'url': url,
- 'status': response.status, 'body': response.body})
- return None
-
- if not self._version:
- self._version = version.find_version(response.headers)
- return response.body
-
- def get_version(self):
- if not self._version:
- # Determine the controller version by querying the
- # cluster nodes. Currently, the version will be the
- # one of the server that responds.
- self.request('GET', '/ws.v1/control-cluster/node')
- if not self._version:
- LOG.error(_LE('Unable to determine NSX version. '
- 'Plugin might not work as expected.'))
- return self._version
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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 time
-
-import eventlet
-eventlet.monkey_patch()
-
-from neutron.i18n import _LE
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.api_client import base
-from neutron.plugins.vmware.api_client import eventlet_request
-
-LOG = logging.getLogger(__name__)
-
-
-class EventletApiClient(base.ApiClientBase):
- """Eventlet-based implementation of NSX ApiClient ABC."""
-
- def __init__(self, api_providers, user, password,
- concurrent_connections=base.DEFAULT_CONCURRENT_CONNECTIONS,
- gen_timeout=base.GENERATION_ID_TIMEOUT,
- use_https=True,
- connect_timeout=base.DEFAULT_CONNECT_TIMEOUT):
- '''Constructor
-
- :param api_providers: a list of tuples of the form: (host, port,
- is_ssl).
- :param user: login username.
- :param password: login password.
- :param concurrent_connections: total number of concurrent connections.
- :param use_https: whether or not to use https for requests.
- :param connect_timeout: connection timeout in seconds.
- :param gen_timeout controls how long the generation id is kept
- if set to -1 the generation id is never timed out
- '''
- if not api_providers:
- api_providers = []
- self._api_providers = set([tuple(p) for p in api_providers])
- self._api_provider_data = {} # tuple(semaphore, session_cookie)
- for p in self._api_providers:
- self._set_provider_data(p, (eventlet.semaphore.Semaphore(1), None))
- self._user = user
- self._password = password
- self._concurrent_connections = concurrent_connections
- self._use_https = use_https
- self._connect_timeout = connect_timeout
- self._config_gen = None
- self._config_gen_ts = None
- self._gen_timeout = gen_timeout
-
- # Connection pool is a list of queues.
- self._conn_pool = eventlet.queue.PriorityQueue()
- self._next_conn_priority = 1
- for host, port, is_ssl in api_providers:
- for _ in range(concurrent_connections):
- conn = self._create_connection(host, port, is_ssl)
- self._conn_pool.put((self._next_conn_priority, conn))
- self._next_conn_priority += 1
-
- def acquire_redirect_connection(self, conn_params, auto_login=True,
- headers=None):
- """Check out or create connection to redirected NSX API server.
-
- Args:
- conn_params: tuple specifying target of redirect, see
- self._conn_params()
- auto_login: returned connection should have valid session cookie
- headers: headers to pass on if auto_login
-
- Returns: An available HTTPConnection instance corresponding to the
- specified conn_params. If a connection did not previously
- exist, new connections are created with the highest prioity
- in the connection pool and one of these new connections
- returned.
- """
- result_conn = None
- data = self._get_provider_data(conn_params)
- if data:
- # redirect target already exists in provider data and connections
- # to the provider have been added to the connection pool. Try to
- # obtain a connection from the pool, note that it's possible that
- # all connection to the provider are currently in use.
- conns = []
- while not self._conn_pool.empty():
- priority, conn = self._conn_pool.get_nowait()
- if not result_conn and self._conn_params(conn) == conn_params:
- conn.priority = priority
- result_conn = conn
- else:
- conns.append((priority, conn))
- for priority, conn in conns:
- self._conn_pool.put((priority, conn))
- # hack: if no free connections available, create new connection
- # and stash "no_release" attribute (so that we only exceed
- # self._concurrent_connections temporarily)
- if not result_conn:
- conn = self._create_connection(*conn_params)
- conn.priority = 0 # redirect connections have highest priority
- conn.no_release = True
- result_conn = conn
- else:
- #redirect target not already known, setup provider lists
- self._api_providers.update([conn_params])
- self._set_provider_data(conn_params,
- (eventlet.semaphore.Semaphore(1), None))
- # redirects occur during cluster upgrades, i.e. results to old
- # redirects to new, so give redirect targets highest priority
- priority = 0
- for i in range(self._concurrent_connections):
- conn = self._create_connection(*conn_params)
- conn.priority = priority
- if i == self._concurrent_connections - 1:
- break
- self._conn_pool.put((priority, conn))
- result_conn = conn
- if result_conn:
- result_conn.last_used = time.time()
- if auto_login and self.auth_cookie(conn) is None:
- self._wait_for_login(result_conn, headers)
- return result_conn
-
- def _login(self, conn=None, headers=None):
- '''Issue login request and update authentication cookie.'''
- cookie = None
- g = eventlet_request.LoginRequestEventlet(
- self, self._user, self._password, conn, headers)
- g.start()
- ret = g.join()
- if ret:
- if isinstance(ret, Exception):
- LOG.error(_LE('Login error "%s"'), ret)
- raise ret
-
- cookie = ret.getheader("Set-Cookie")
- if cookie:
- LOG.debug("Saving new authentication cookie '%s'", cookie)
-
- return cookie
-
-# Register as subclass.
-base.ApiClientBase.register(EventletApiClient)
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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 httplib
-import urllib
-
-import eventlet
-from oslo_serialization import jsonutils
-
-from neutron.i18n import _LI, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.api_client import request
-
-LOG = logging.getLogger(__name__)
-USER_AGENT = "Neutron eventlet client/2.0"
-
-
-class EventletApiRequest(request.ApiRequest):
- '''Eventlet-based ApiRequest class.
-
- This class will form the basis for eventlet-based ApiRequest classes
- '''
-
- # Maximum number of green threads present in the system at one time.
- API_REQUEST_POOL_SIZE = request.DEFAULT_API_REQUEST_POOL_SIZE
-
- # Pool of green threads. One green thread is allocated per incoming
- # request. Incoming requests will block when the pool is empty.
- API_REQUEST_POOL = eventlet.GreenPool(API_REQUEST_POOL_SIZE)
-
- # A unique id is assigned to each incoming request. When the current
- # request id reaches MAXIMUM_REQUEST_ID it wraps around back to 0.
- MAXIMUM_REQUEST_ID = request.DEFAULT_MAXIMUM_REQUEST_ID
-
- # The request id for the next incoming request.
- CURRENT_REQUEST_ID = 0
-
- def __init__(self, client_obj, url, method="GET", body=None,
- headers=None,
- retries=request.DEFAULT_RETRIES,
- auto_login=True,
- redirects=request.DEFAULT_REDIRECTS,
- http_timeout=request.DEFAULT_HTTP_TIMEOUT, client_conn=None):
- '''Constructor.'''
- self._api_client = client_obj
- self._url = url
- self._method = method
- self._body = body
- self._headers = headers or {}
- self._request_timeout = http_timeout * retries
- self._retries = retries
- self._auto_login = auto_login
- self._redirects = redirects
- self._http_timeout = http_timeout
- self._client_conn = client_conn
- self._abort = False
-
- self._request_error = None
-
- if "User-Agent" not in self._headers:
- self._headers["User-Agent"] = USER_AGENT
-
- self._green_thread = None
- # Retrieve and store this instance's unique request id.
- self._request_id = EventletApiRequest.CURRENT_REQUEST_ID
- # Update the class variable that tracks request id.
- # Request IDs wrap around at MAXIMUM_REQUEST_ID
- next_request_id = self._request_id + 1
- next_request_id %= self.MAXIMUM_REQUEST_ID
- EventletApiRequest.CURRENT_REQUEST_ID = next_request_id
-
- @classmethod
- def _spawn(cls, func, *args, **kwargs):
- '''Allocate a green thread from the class pool.'''
- return cls.API_REQUEST_POOL.spawn(func, *args, **kwargs)
-
- def spawn(self, func, *args, **kwargs):
- '''Spawn a new green thread with the supplied function and args.'''
- return self.__class__._spawn(func, *args, **kwargs)
-
- @classmethod
- def joinall(cls):
- '''Wait for all outstanding requests to complete.'''
- return cls.API_REQUEST_POOL.waitall()
-
- def join(self):
- '''Wait for instance green thread to complete.'''
- if self._green_thread is not None:
- return self._green_thread.wait()
- return Exception(_('Joining an invalid green thread'))
-
- def start(self):
- '''Start request processing.'''
- self._green_thread = self.spawn(self._run)
-
- def copy(self):
- '''Return a copy of this request instance.'''
- return EventletApiRequest(
- self._api_client, self._url, self._method, self._body,
- self._headers, self._retries,
- self._auto_login, self._redirects, self._http_timeout)
-
- def _run(self):
- '''Method executed within green thread.'''
- if self._request_timeout:
- # No timeout exception escapes the with block.
- with eventlet.timeout.Timeout(self._request_timeout, False):
- return self._handle_request()
-
- LOG.info(_LI('[%d] Request timeout.'), self._rid())
- self._request_error = Exception(_('Request timeout'))
- return None
- else:
- return self._handle_request()
-
- def _handle_request(self):
- '''First level request handling.'''
- attempt = 0
- timeout = 0
- response = None
- while response is None and attempt <= self._retries:
- eventlet.greenthread.sleep(timeout)
- attempt += 1
-
- req = self._issue_request()
- # automatically raises any exceptions returned.
- if isinstance(req, httplib.HTTPResponse):
- timeout = 0
- if attempt <= self._retries and not self._abort:
- if req.status in (httplib.UNAUTHORIZED, httplib.FORBIDDEN):
- continue
- elif req.status == httplib.SERVICE_UNAVAILABLE:
- timeout = 0.5
- continue
- # else fall through to return the error code
-
- LOG.debug("[%(rid)d] Completed request '%(method)s %(url)s'"
- ": %(status)s",
- {'rid': self._rid(), 'method': self._method,
- 'url': self._url, 'status': req.status})
- self._request_error = None
- response = req
- else:
- LOG.info(_LI('[%(rid)d] Error while handling request: '
- '%(req)s'),
- {'rid': self._rid(), 'req': req})
- self._request_error = req
- response = None
- return response
-
-
-class LoginRequestEventlet(EventletApiRequest):
- '''Process a login request.'''
-
- def __init__(self, client_obj, user, password, client_conn=None,
- headers=None):
- if headers is None:
- headers = {}
- headers.update({"Content-Type": "application/x-www-form-urlencoded"})
- body = urllib.urlencode({"username": user, "password": password})
- super(LoginRequestEventlet, self).__init__(
- client_obj, "/ws.v1/login", "POST", body, headers,
- auto_login=False, client_conn=client_conn)
-
- def session_cookie(self):
- if self.successful():
- return self.value.getheader("Set-Cookie")
- return None
-
-
-class GetApiProvidersRequestEventlet(EventletApiRequest):
- '''Get a list of API providers.'''
-
- def __init__(self, client_obj):
- url = "/ws.v1/control-cluster/node?fields=roles"
- super(GetApiProvidersRequestEventlet, self).__init__(
- client_obj, url, "GET", auto_login=True)
-
- def api_providers(self):
- """Parse api_providers from response.
-
- Returns: api_providers in [(host, port, is_ssl), ...] format
- """
- def _provider_from_listen_addr(addr):
- # (pssl|ptcp):<ip>:<port> => (host, port, is_ssl)
- parts = addr.split(':')
- return (parts[1], int(parts[2]), parts[0] == 'pssl')
-
- try:
- if self.successful():
- ret = []
- body = jsonutils.loads(self.value.body)
- for node in body.get('results', []):
- for role in node.get('roles', []):
- if role.get('role') == 'api_provider':
- addr = role.get('listen_addr')
- if addr:
- ret.append(_provider_from_listen_addr(addr))
- return ret
- except Exception as e:
- LOG.warn(_LW("[%(rid)d] Failed to parse API provider: %(e)s"),
- {'rid': self._rid(), 'e': e})
- # intentionally fall through
- return None
-
-
-class GenericRequestEventlet(EventletApiRequest):
- '''Handle a generic request.'''
-
- def __init__(self, client_obj, method, url, body, content_type,
- auto_login=False,
- http_timeout=request.DEFAULT_HTTP_TIMEOUT,
- retries=request.DEFAULT_RETRIES,
- redirects=request.DEFAULT_REDIRECTS):
- headers = {"Content-Type": content_type}
- super(GenericRequestEventlet, self).__init__(
- client_obj, url, method, body, headers,
- retries=retries,
- auto_login=auto_login, redirects=redirects,
- http_timeout=http_timeout)
-
- def session_cookie(self):
- if self.successful():
- return self.value.getheader("Set-Cookie")
- return None
-
-
-request.ApiRequest.register(EventletApiRequest)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-
-
-class NsxApiException(Exception):
- """Base NSX API Client Exception.
-
- To correctly use this class, inherit from it and define
- a 'message' property. That message will get printf'd
- with the keyword arguments provided to the constructor.
-
- """
- message = _("An unknown exception occurred.")
-
- def __init__(self, **kwargs):
- try:
- self._error_string = self.message % kwargs
- except Exception:
- # at least get the core message out if something happened
- self._error_string = self.message
-
- def __str__(self):
- return self._error_string
-
-
-class UnAuthorizedRequest(NsxApiException):
- message = _("Server denied session's authentication credentials.")
-
-
-class ResourceNotFound(NsxApiException):
- message = _("An entity referenced in the request was not found.")
-
-
-class Conflict(NsxApiException):
- message = _("Request conflicts with configuration on a different "
- "entity.")
-
-
-class ServiceUnavailable(NsxApiException):
- message = _("Request could not completed because the associated "
- "resource could not be reached.")
-
-
-class Forbidden(NsxApiException):
- message = _("The request is forbidden from accessing the "
- "referenced resource.")
-
-
-class ReadOnlyMode(Forbidden):
- message = _("Create/Update actions are forbidden when in read-only mode.")
-
-
-class RequestTimeout(NsxApiException):
- message = _("The request has timed out.")
-
-
-class BadRequest(NsxApiException):
- message = _("The server is unable to fulfill the request due "
- "to a bad syntax")
-
-
-class InvalidSecurityCertificate(BadRequest):
- message = _("The backend received an invalid security certificate.")
-
-
-def fourZeroZero(response=None):
- if response and "Invalid SecurityCertificate" in response.body:
- raise InvalidSecurityCertificate()
- raise BadRequest()
-
-
-def fourZeroFour(response=None):
- raise ResourceNotFound()
-
-
-def fourZeroNine(response=None):
- raise Conflict()
-
-
-def fiveZeroThree(response=None):
- raise ServiceUnavailable()
-
-
-def fourZeroThree(response=None):
- if 'read-only' in response.body:
- raise ReadOnlyMode()
- else:
- raise Forbidden()
-
-
-def zero(self, response=None):
- raise NsxApiException()
-
-
-ERROR_MAPPINGS = {
- 400: fourZeroZero,
- 404: fourZeroFour,
- 405: zero,
- 409: fourZeroNine,
- 503: fiveZeroThree,
- 403: fourZeroThree,
- 301: zero,
- 307: zero,
- 500: zero,
- 501: zero,
- 503: zero
-}
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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 abc
-import copy
-import httplib
-import time
-
-import eventlet
-from oslo_utils import excutils
-import six
-import six.moves.urllib.parse as urlparse
-
-from neutron.i18n import _LI, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware import api_client
-
-LOG = logging.getLogger(__name__)
-
-DEFAULT_HTTP_TIMEOUT = 30
-DEFAULT_RETRIES = 2
-DEFAULT_REDIRECTS = 2
-DEFAULT_API_REQUEST_POOL_SIZE = 1000
-DEFAULT_MAXIMUM_REQUEST_ID = 4294967295
-DOWNLOAD_TIMEOUT = 180
-
-
-@six.add_metaclass(abc.ABCMeta)
-class ApiRequest(object):
- '''An abstract baseclass for all ApiRequest implementations.
-
- This defines the interface and property structure for both eventlet and
- gevent-based ApiRequest classes.
- '''
-
- # List of allowed status codes.
- ALLOWED_STATUS_CODES = [
- httplib.OK,
- httplib.CREATED,
- httplib.NO_CONTENT,
- httplib.MOVED_PERMANENTLY,
- httplib.TEMPORARY_REDIRECT,
- httplib.BAD_REQUEST,
- httplib.UNAUTHORIZED,
- httplib.FORBIDDEN,
- httplib.NOT_FOUND,
- httplib.CONFLICT,
- httplib.INTERNAL_SERVER_ERROR,
- httplib.SERVICE_UNAVAILABLE
- ]
-
- @abc.abstractmethod
- def start(self):
- pass
-
- @abc.abstractmethod
- def join(self):
- pass
-
- @abc.abstractmethod
- def copy(self):
- pass
-
- def _issue_request(self):
- '''Issue a request to a provider.'''
- conn = (self._client_conn or
- self._api_client.acquire_connection(True,
- copy.copy(self._headers),
- rid=self._rid()))
- if conn is None:
- error = Exception(_("No API connections available"))
- self._request_error = error
- return error
-
- url = self._url
- LOG.debug("[%(rid)d] Issuing - request url: %(conn)s "
- "body: %(body)s",
- {'rid': self._rid(), 'conn': self._request_str(conn, url),
- 'body': self._body})
- issued_time = time.time()
- is_conn_error = False
- is_conn_service_unavail = False
- response = None
- try:
- redirects = 0
- while (redirects <= self._redirects):
- # Update connection with user specified request timeout,
- # the connect timeout is usually smaller so we only set
- # the request timeout after a connection is established
- if conn.sock is None:
- conn.connect()
- conn.sock.settimeout(self._http_timeout)
- elif conn.sock.gettimeout() != self._http_timeout:
- conn.sock.settimeout(self._http_timeout)
-
- headers = copy.copy(self._headers)
- cookie = self._api_client.auth_cookie(conn)
- if cookie:
- headers["Cookie"] = cookie
-
- gen = self._api_client.config_gen
- if gen:
- headers["X-Nvp-Wait-For-Config-Generation"] = gen
- LOG.debug("Setting X-Nvp-Wait-For-Config-Generation "
- "request header: '%s'", gen)
- try:
- conn.request(self._method, url, self._body, headers)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.warn(_LW("[%(rid)d] Exception issuing request: "
- "%(e)s"),
- {'rid': self._rid(), 'e': e})
-
- response = conn.getresponse()
- response.body = response.read()
- response.headers = response.getheaders()
- elapsed_time = time.time() - issued_time
- LOG.debug("[%(rid)d] Completed request '%(conn)s': "
- "%(status)s (%(elapsed)s seconds)",
- {'rid': self._rid(),
- 'conn': self._request_str(conn, url),
- 'status': response.status,
- 'elapsed': elapsed_time})
-
- new_gen = response.getheader('X-Nvp-Config-Generation', None)
- if new_gen:
- LOG.debug("Reading X-Nvp-config-Generation response "
- "header: '%s'", new_gen)
- if (self._api_client.config_gen is None or
- self._api_client.config_gen < int(new_gen)):
- self._api_client.config_gen = int(new_gen)
-
- if response.status == httplib.UNAUTHORIZED:
-
- if cookie is None and self._url != "/ws.v1/login":
- # The connection still has no valid cookie despite
- # attempts to authenticate and the request has failed
- # with unauthorized status code. If this isn't a
- # a request to authenticate, we should abort the
- # request since there is no point in retrying.
- self._abort = True
-
- # If request is unauthorized, clear the session cookie
- # for the current provider so that subsequent requests
- # to the same provider triggers re-authentication.
- self._api_client.set_auth_cookie(conn, None)
- elif response.status == httplib.SERVICE_UNAVAILABLE:
- is_conn_service_unavail = True
-
- if response.status not in [httplib.MOVED_PERMANENTLY,
- httplib.TEMPORARY_REDIRECT]:
- break
- elif redirects >= self._redirects:
- LOG.info(_LI("[%d] Maximum redirects exceeded, aborting "
- "request"), self._rid())
- break
- redirects += 1
-
- conn, url = self._redirect_params(conn, response.headers,
- self._client_conn is None)
- if url is None:
- response.status = httplib.INTERNAL_SERVER_ERROR
- break
- LOG.info(_LI("[%(rid)d] Redirecting request to: %(conn)s"),
- {'rid': self._rid(),
- 'conn': self._request_str(conn, url)})
- # yield here, just in case we are not out of the loop yet
- eventlet.greenthread.sleep(0)
- # If we receive any of these responses, then
- # our server did not process our request and may be in an
- # errored state. Raise an exception, which will cause the
- # the conn to be released with is_conn_error == True
- # which puts the conn on the back of the client's priority
- # queue.
- if (response.status == httplib.INTERNAL_SERVER_ERROR and
- response.status > httplib.NOT_IMPLEMENTED):
- LOG.warn(_LW("[%(rid)d] Request '%(method)s %(url)s' "
- "received: %(status)s"),
- {'rid': self._rid(), 'method': self._method,
- 'url': self._url, 'status': response.status})
- raise Exception(_('Server error return: %s'), response.status)
- return response
- except Exception as e:
- if isinstance(e, httplib.BadStatusLine):
- msg = (_("Invalid server response"))
- else:
- msg = unicode(e)
- if response is None:
- elapsed_time = time.time() - issued_time
- LOG.warn(_LW("[%(rid)d] Failed request '%(conn)s': '%(msg)s' "
- "(%(elapsed)s seconds)"),
- {'rid': self._rid(), 'conn': self._request_str(conn, url),
- 'msg': msg, 'elapsed': elapsed_time})
- self._request_error = e
- is_conn_error = True
- return e
- finally:
- # Make sure we release the original connection provided by the
- # acquire_connection() call above.
- if self._client_conn is None:
- self._api_client.release_connection(conn, is_conn_error,
- is_conn_service_unavail,
- rid=self._rid())
-
- def _redirect_params(self, conn, headers, allow_release_conn=False):
- """Process redirect response, create new connection if necessary.
-
- Args:
- conn: connection that returned the redirect response
- headers: response headers of the redirect response
- allow_release_conn: if redirecting to a different server,
- release existing connection back to connection pool.
-
- Returns: Return tuple(conn, url) where conn is a connection object
- to the redirect target and url is the path of the API request
- """
-
- url = None
- for name, value in headers:
- if name.lower() == "location":
- url = value
- break
- if not url:
- LOG.warn(_LW("[%d] Received redirect status without location "
- "header field"), self._rid())
- return (conn, None)
- # Accept location with the following format:
- # 1. /path, redirect to same node
- # 2. scheme://hostname:[port]/path where scheme is https or http
- # Reject others
- # 3. e.g. relative paths, unsupported scheme, unspecified host
- result = urlparse.urlparse(url)
- if not result.scheme and not result.hostname and result.path:
- if result.path[0] == "/":
- if result.query:
- url = "%s?%s" % (result.path, result.query)
- else:
- url = result.path
- return (conn, url) # case 1
- else:
- LOG.warn(_LW("[%(rid)d] Received invalid redirect location: "
- "'%(url)s'"), {'rid': self._rid(), 'url': url})
- return (conn, None) # case 3
- elif result.scheme not in ["http", "https"] or not result.hostname:
- LOG.warn(_LW("[%(rid)d] Received malformed redirect "
- "location: %(url)s"),
- {'rid': self._rid(), 'url': url})
- return (conn, None) # case 3
- # case 2, redirect location includes a scheme
- # so setup a new connection and authenticate
- if allow_release_conn:
- self._api_client.release_connection(conn)
- conn_params = (result.hostname, result.port, result.scheme == "https")
- conn = self._api_client.acquire_redirect_connection(conn_params, True,
- self._headers)
- if result.query:
- url = "%s?%s" % (result.path, result.query)
- else:
- url = result.path
- return (conn, url)
-
- def _rid(self):
- '''Return current request id.'''
- return self._request_id
-
- @property
- def request_error(self):
- '''Return any errors associated with this instance.'''
- return self._request_error
-
- def _request_str(self, conn, url):
- '''Return string representation of connection.'''
- return "%s %s/%s" % (self._method, api_client.ctrl_conn_to_str(conn),
- url)
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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.
-#
-
-from neutron.i18n import _LW
-from neutron.openstack.common import log as logging
-
-LOG = logging.getLogger(__name__)
-
-
-def find_version(headers):
- """Retrieve NSX controller version from response headers."""
- for (header_name, header_value) in (headers or ()):
- try:
- if header_name == 'server':
- return Version(header_value.split('/')[1])
- except IndexError:
- LOG.warning(_LW("Unable to fetch NSX version from response "
- "headers :%s"), headers)
-
-
-class Version(object):
- """Abstracts NSX version by exposing major and minor."""
-
- def __init__(self, version):
- self.full_version = version.split('.')
- self.major = int(self.full_version[0])
- self.minor = int(self.full_version[1])
-
- def __str__(self):
- return '.'.join(self.full_version)
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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.
-
-from __future__ import print_function
-
-import sys
-
-from oslo_config import cfg
-
-from neutron.common import config
-from neutron.plugins.vmware.common import config as nsx_config # noqa
-from neutron.plugins.vmware.common import nsx_utils
-from neutron.plugins.vmware import nsxlib
-
-config.setup_logging()
-
-
-def help(name):
- print("Usage: %s path/to/neutron/plugin/ini/config/file" % name)
- sys.exit(1)
-
-
-def get_nsx_controllers(cluster):
- return cluster.nsx_controllers
-
-
-def config_helper(config_entity, cluster):
- try:
- return nsxlib.do_request('GET',
- "/ws.v1/%s?fields=uuid" % config_entity,
- cluster=cluster).get('results', [])
- except Exception as e:
- msg = (_("Error '%(err)s' when connecting to controller(s): %(ctl)s.")
- % {'err': e,
- 'ctl': ', '.join(get_nsx_controllers(cluster))})
- raise Exception(msg)
-
-
-def get_control_cluster_nodes(cluster):
- return config_helper("control-cluster/node", cluster)
-
-
-def get_gateway_services(cluster):
- ret_gw_services = {"L2GatewayServiceConfig": [],
- "L3GatewayServiceConfig": []}
- gw_services = config_helper("gateway-service", cluster)
- for gw_service in gw_services:
- ret_gw_services[gw_service['type']].append(gw_service['uuid'])
- return ret_gw_services
-
-
-def get_transport_zones(cluster):
- transport_zones = config_helper("transport-zone", cluster)
- return [transport_zone['uuid'] for transport_zone in transport_zones]
-
-
-def get_transport_nodes(cluster):
- transport_nodes = config_helper("transport-node", cluster)
- return [transport_node['uuid'] for transport_node in transport_nodes]
-
-
-def is_transport_node_connected(cluster, node_uuid):
- try:
- return nsxlib.do_request('GET',
- "/ws.v1/transport-node/%s/status" % node_uuid,
- cluster=cluster)['connection']['connected']
- except Exception as e:
- msg = (_("Error '%(err)s' when connecting to controller(s): %(ctl)s.")
- % {'err': e,
- 'ctl': ', '.join(get_nsx_controllers(cluster))})
- raise Exception(msg)
-
-
-def main():
- if len(sys.argv) != 2:
- help(sys.argv[0])
- args = ['--config-file']
- args.append(sys.argv[1])
- config.init(args)
- print("----------------------- Database Options -----------------------")
- print("\tconnection: %s" % cfg.CONF.database.connection)
- print("\tretry_interval: %d" % cfg.CONF.database.retry_interval)
- print("\tmax_retries: %d" % cfg.CONF.database.max_retries)
- print("----------------------- NSX Options -----------------------")
- print("\tNSX Generation Timeout %d" % cfg.CONF.NSX.nsx_gen_timeout)
- print("\tNumber of concurrent connections to each controller %d" %
- cfg.CONF.NSX.concurrent_connections)
- print("\tmax_lp_per_bridged_ls: %s" % cfg.CONF.NSX.max_lp_per_bridged_ls)
- print("\tmax_lp_per_overlay_ls: %s" % cfg.CONF.NSX.max_lp_per_overlay_ls)
- print("----------------------- Cluster Options -----------------------")
- print("\tretries: %s" % cfg.CONF.retries)
- print("\tredirects: %s" % cfg.CONF.redirects)
- print("\thttp_timeout: %s" % cfg.CONF.http_timeout)
- cluster = nsx_utils.create_nsx_cluster(
- cfg.CONF,
- cfg.CONF.NSX.concurrent_connections,
- cfg.CONF.NSX.nsx_gen_timeout)
- nsx_controllers = get_nsx_controllers(cluster)
- num_controllers = len(nsx_controllers)
- print("Number of controllers found: %s" % num_controllers)
- if num_controllers == 0:
- print("You must specify at least one controller!")
- sys.exit(1)
-
- get_control_cluster_nodes(cluster)
- for controller in nsx_controllers:
- print("\tController endpoint: %s" % controller)
- gateway_services = get_gateway_services(cluster)
- default_gateways = {
- "L2GatewayServiceConfig": cfg.CONF.default_l2_gw_service_uuid,
- "L3GatewayServiceConfig": cfg.CONF.default_l3_gw_service_uuid}
- errors = 0
- for svc_type in default_gateways.keys():
- for uuid in gateway_services[svc_type]:
- print("\t\tGateway(%s) uuid: %s" % (svc_type, uuid))
- if (default_gateways[svc_type] and
- default_gateways[svc_type] not in gateway_services[svc_type]):
- print("\t\t\tError: specified default %s gateway (%s) is "
- "missing from NSX Gateway Services!" % (
- svc_type,
- default_gateways[svc_type]))
- errors += 1
- transport_zones = get_transport_zones(cluster)
- print("\tTransport zones: %s" % transport_zones)
- if cfg.CONF.default_tz_uuid not in transport_zones:
- print("\t\tError: specified default transport zone "
- "(%s) is missing from NSX transport zones!"
- % cfg.CONF.default_tz_uuid)
- errors += 1
- transport_nodes = get_transport_nodes(cluster)
- print("\tTransport nodes: %s" % transport_nodes)
- node_errors = []
- for node in transport_nodes:
- if not is_transport_node_connected(cluster, node):
- node_errors.append(node)
-
- # Use different exit codes, so that we can distinguish
- # between config and runtime errors
- if len(node_errors):
- print("\nThere are one or mode transport nodes that are "
- "not connected: %s. Please, revise!" % node_errors)
- sys.exit(10)
- elif errors:
- print("\nThere are %d errors with your configuration. "
- "Please, revise!" % errors)
- sys.exit(12)
- else:
- print("Done.")
+++ /dev/null
-# Copyright 2012 VMware, 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.
-
-from oslo_config import cfg
-
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-
-
-class AgentModes(object):
- AGENT = 'agent'
- AGENTLESS = 'agentless'
- COMBINED = 'combined'
-
-
-class MetadataModes(object):
- DIRECT = 'access_network'
- INDIRECT = 'dhcp_host_route'
-
-
-class ReplicationModes(object):
- SERVICE = 'service'
- SOURCE = 'source'
-
-
-base_opts = [
- cfg.IntOpt('max_lp_per_bridged_ls', default=5000,
- deprecated_group='NVP',
- help=_("Maximum number of ports of a logical switch on a "
- "bridged transport zone (default 5000)")),
- cfg.IntOpt('max_lp_per_overlay_ls', default=256,
- deprecated_group='NVP',
- help=_("Maximum number of ports of a logical switch on an "
- "overlay transport zone (default 256)")),
- cfg.IntOpt('concurrent_connections', default=10,
- deprecated_group='NVP',
- help=_("Maximum concurrent connections to each NSX "
- "controller.")),
- cfg.IntOpt('nsx_gen_timeout', default=-1,
- deprecated_name='nvp_gen_timeout',
- deprecated_group='NVP',
- help=_("Number of seconds a generation id should be valid for "
- "(default -1 meaning do not time out)")),
- cfg.StrOpt('metadata_mode', default=MetadataModes.DIRECT,
- deprecated_group='NVP',
- help=_("If set to access_network this enables a dedicated "
- "connection to the metadata proxy for metadata server "
- "access via Neutron router. If set to dhcp_host_route "
- "this enables host route injection via the dhcp agent. "
- "This option is only useful if running on a host that "
- "does not support namespaces otherwise access_network "
- "should be used.")),
- cfg.StrOpt('default_transport_type', default='stt',
- choices=('stt', 'gre', 'bridge', 'ipsec_gre', 'ipsec_stt'),
- deprecated_group='NVP',
- help=_("The default network transport type to use")),
- cfg.StrOpt('agent_mode', default=AgentModes.AGENT,
- deprecated_group='NVP',
- help=_("The mode used to implement DHCP/metadata services.")),
- cfg.StrOpt('replication_mode', default=ReplicationModes.SERVICE,
- help=_("The default option leverages service nodes to perform"
- " packet replication though one could set to this to "
- "'source' to perform replication locally. This is useful"
- " if one does not want to deploy a service node(s). "
- "It must be set to 'service' for leveraging distributed "
- "routers."))
-]
-
-sync_opts = [
- cfg.IntOpt('state_sync_interval', default=10,
- deprecated_group='NVP_SYNC',
- help=_("Interval in seconds between runs of the state "
- "synchronization task. Set it to 0 to disable it")),
- cfg.IntOpt('max_random_sync_delay', default=0,
- deprecated_group='NVP_SYNC',
- help=_("Maximum value for the additional random "
- "delay in seconds between runs of the state "
- "synchronization task")),
- cfg.IntOpt('min_sync_req_delay', default=1,
- deprecated_group='NVP_SYNC',
- help=_('Minimum delay, in seconds, between two state '
- 'synchronization queries to NSX. It must not '
- 'exceed state_sync_interval')),
- cfg.IntOpt('min_chunk_size', default=500,
- deprecated_group='NVP_SYNC',
- help=_('Minimum number of resources to be retrieved from NSX '
- 'during state synchronization')),
- cfg.BoolOpt('always_read_status', default=False,
- deprecated_group='NVP_SYNC',
- help=_('Always read operational status from backend on show '
- 'operations. Enabling this option might slow down '
- 'the system.'))
-]
-
-connection_opts = [
- cfg.StrOpt('nsx_user',
- default='admin',
- deprecated_name='nvp_user',
- help=_('User name for NSX controllers in this cluster')),
- cfg.StrOpt('nsx_password',
- default='admin',
- deprecated_name='nvp_password',
- secret=True,
- help=_('Password for NSX controllers in this cluster')),
- cfg.IntOpt('http_timeout',
- default=75,
- help=_('Time before aborting a request')),
- cfg.IntOpt('retries',
- default=2,
- help=_('Number of time a request should be retried')),
- cfg.IntOpt('redirects',
- default=2,
- help=_('Number of times a redirect should be followed')),
- cfg.ListOpt('nsx_controllers',
- deprecated_name='nvp_controllers',
- help=_("Lists the NSX controllers in this cluster")),
- cfg.IntOpt('conn_idle_timeout',
- default=900,
- help=_('Reconnect connection to nsx if not used within this '
- 'amount of time.')),
-]
-
-cluster_opts = [
- cfg.StrOpt('default_tz_uuid',
- help=_("This is uuid of the default NSX Transport zone that "
- "will be used for creating tunneled isolated "
- "\"Neutron\" networks. It needs to be created in NSX "
- "before starting Neutron with the nsx plugin.")),
- cfg.StrOpt('default_l3_gw_service_uuid',
- help=_("Unique identifier of the NSX L3 Gateway service "
- "which will be used for implementing routers and "
- "floating IPs")),
- cfg.StrOpt('default_l2_gw_service_uuid',
- help=_("Unique identifier of the NSX L2 Gateway service "
- "which will be used by default for network gateways")),
- cfg.StrOpt('default_service_cluster_uuid',
- help=_("Unique identifier of the Service Cluster which will "
- "be used by logical services like dhcp and metadata")),
- cfg.StrOpt('default_interface_name', default='breth0',
- help=_("Name of the interface on a L2 Gateway transport node"
- "which should be used by default when setting up a "
- "network connection")),
-]
-
-DEFAULT_STATUS_CHECK_INTERVAL = 2000
-
-vcns_opts = [
- cfg.StrOpt('user',
- default='admin',
- help=_('User name for vsm')),
- cfg.StrOpt('password',
- default='default',
- secret=True,
- help=_('Password for vsm')),
- cfg.StrOpt('manager_uri',
- help=_('uri for vsm')),
- cfg.StrOpt('datacenter_moid',
- help=_('Optional parameter identifying the ID of datacenter '
- 'to deploy NSX Edges')),
- cfg.StrOpt('deployment_container_id',
- help=_('Optional parameter identifying the ID of datastore to '
- 'deploy NSX Edges')),
- cfg.StrOpt('resource_pool_id',
- help=_('Optional parameter identifying the ID of resource to '
- 'deploy NSX Edges')),
- cfg.StrOpt('datastore_id',
- help=_('Optional parameter identifying the ID of datastore to '
- 'deploy NSX Edges')),
- cfg.StrOpt('external_network',
- help=_('Network ID for physical network connectivity')),
- cfg.IntOpt('task_status_check_interval',
- default=DEFAULT_STATUS_CHECK_INTERVAL,
- help=_("Task status check interval"))
-]
-
-# Register the configuration options
-cfg.CONF.register_opts(connection_opts)
-cfg.CONF.register_opts(cluster_opts)
-cfg.CONF.register_opts(vcns_opts, group="vcns")
-cfg.CONF.register_opts(base_opts, group="NSX")
-cfg.CONF.register_opts(sync_opts, group="NSX_SYNC")
-
-
-def validate_config_options():
- if cfg.CONF.NSX.replication_mode not in (ReplicationModes.SERVICE,
- ReplicationModes.SOURCE):
- error = (_("Invalid replication_mode: %s") %
- cfg.CONF.NSX.replication_mode)
- raise nsx_exc.NsxPluginException(err_msg=error)
+++ /dev/null
-# Copyright 2012 VMware, Inc
-#
-# 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.
-
-from neutron.common import exceptions as n_exc
-
-
-class NsxPluginException(n_exc.NeutronException):
- message = _("An unexpected error occurred in the NSX Plugin: %(err_msg)s")
-
-
-class InvalidVersion(NsxPluginException):
- message = _("Unable to fulfill request with version %(version)s.")
-
-
-class InvalidConnection(NsxPluginException):
- message = _("Invalid NSX connection parameters: %(conn_params)s")
-
-
-class InvalidClusterConfiguration(NsxPluginException):
- message = _("Invalid cluster values: %(invalid_attrs)s. Please ensure "
- "that these values are specified in the [DEFAULT] "
- "section of the NSX plugin ini file.")
-
-
-class InvalidNovaZone(NsxPluginException):
- message = _("Unable to find cluster config entry "
- "for nova zone: %(nova_zone)s")
-
-
-class NoMorePortsException(NsxPluginException):
- message = _("Unable to create port on network %(network)s. "
- "Maximum number of ports reached")
-
-
-class NatRuleMismatch(NsxPluginException):
- message = _("While retrieving NAT rules, %(actual_rules)s were found "
- "whereas rules in the (%(min_rules)s,%(max_rules)s) interval "
- "were expected")
-
-
-class InvalidAttachmentType(NsxPluginException):
- message = _("Invalid NSX attachment type '%(attachment_type)s'")
-
-
-class MaintenanceInProgress(NsxPluginException):
- message = _("The networking backend is currently in maintenance mode and "
- "therefore unable to accept requests which modify its state. "
- "Please try later.")
-
-
-class L2GatewayAlreadyInUse(n_exc.Conflict):
- message = _("Gateway Service %(gateway)s is already in use")
-
-
-class InvalidSecurityCertificate(NsxPluginException):
- message = _("An invalid security certificate was specified for the "
- "gateway device. Certificates must be enclosed between "
- "'-----BEGIN CERTIFICATE-----' and "
- "'-----END CERTIFICATE-----'")
-
-
-class ServiceOverQuota(n_exc.Conflict):
- message = _("Quota exceeded for Vcns resource: %(overs)s: %(err_msg)s")
-
-
-class ServiceClusterUnavailable(NsxPluginException):
- message = _("Service cluster: '%(cluster_id)s' is unavailable. Please, "
- "check NSX setup and/or configuration")
-
-
-class PortConfigurationError(NsxPluginException):
- message = _("An error occurred while connecting LSN %(lsn_id)s "
- "and network %(net_id)s via port %(port_id)s")
-
- def __init__(self, **kwargs):
- super(PortConfigurationError, self).__init__(**kwargs)
- self.port_id = kwargs.get('port_id')
-
-
-class LsnNotFound(n_exc.NotFound):
- message = _('Unable to find LSN for %(entity)s %(entity_id)s')
-
-
-class LsnPortNotFound(n_exc.NotFound):
- message = (_('Unable to find port for LSN %(lsn_id)s '
- 'and %(entity)s %(entity_id)s'))
-
-
-class LsnMigrationConflict(n_exc.Conflict):
- message = _("Unable to migrate network '%(net_id)s' to LSN: %(reason)s")
-
-
-class LsnConfigurationConflict(NsxPluginException):
- message = _("Configuration conflict on Logical Service Node %(lsn_id)s")
+++ /dev/null
-# Copyright 2013 VMware Inc.
-# 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.
-
-from neutron.api.v2 import attributes as attr
-from neutron.common import exceptions as n_exc
-from neutron.extensions import multiprovidernet as mpnet
-from neutron.extensions import providernet as pnet
-from neutron.i18n import _LW
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import client
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import utils as vmw_utils
-from neutron.plugins.vmware.dbexts import db as nsx_db
-from neutron.plugins.vmware.dbexts import networkgw_db
-from neutron.plugins.vmware import nsx_cluster
-from neutron.plugins.vmware.nsxlib import l2gateway as l2gwlib
-from neutron.plugins.vmware.nsxlib import router as routerlib
-from neutron.plugins.vmware.nsxlib import secgroup as secgrouplib
-from neutron.plugins.vmware.nsxlib import switch as switchlib
-
-LOG = log.getLogger(__name__)
-
-
-def fetch_nsx_switches(session, cluster, neutron_net_id):
- """Retrieve logical switches for a neutron network.
-
- This function is optimized for fetching all the lswitches always
- with a single NSX query.
- If there is more than 1 logical switch (chained switches use case)
- NSX lswitches are queried by 'quantum_net_id' tag. Otherwise the NSX
- lswitch is directly retrieved by id (more efficient).
- """
- nsx_switch_ids = get_nsx_switch_ids(session, cluster, neutron_net_id)
- if len(nsx_switch_ids) > 1:
- lswitches = switchlib.get_lswitches(cluster, neutron_net_id)
- else:
- lswitches = [switchlib.get_lswitch_by_id(
- cluster, nsx_switch_ids[0])]
- return lswitches
-
-
-def get_nsx_switch_ids(session, cluster, neutron_network_id):
- """Return the NSX switch id for a given neutron network.
-
- First lookup for mappings in Neutron database. If no mapping is
- found, query the NSX backend and add the mappings.
- """
- nsx_switch_ids = nsx_db.get_nsx_switch_ids(
- session, neutron_network_id)
- if not nsx_switch_ids:
- # Find logical switches from backend.
- # This is a rather expensive query, but it won't be executed
- # more than once for each network in Neutron's lifetime
- nsx_switches = switchlib.get_lswitches(cluster, neutron_network_id)
- if not nsx_switches:
- LOG.warn(_LW("Unable to find NSX switches for Neutron network %s"),
- neutron_network_id)
- return
- nsx_switch_ids = []
- with session.begin(subtransactions=True):
- for nsx_switch in nsx_switches:
- nsx_switch_id = nsx_switch['uuid']
- nsx_switch_ids.append(nsx_switch_id)
- # Create DB mapping
- nsx_db.add_neutron_nsx_network_mapping(
- session,
- neutron_network_id,
- nsx_switch_id)
- return nsx_switch_ids
-
-
-def get_nsx_switch_and_port_id(session, cluster, neutron_port_id):
- """Return the NSX switch and port uuids for a given neutron port.
-
- First, look up the Neutron database. If not found, execute
- a query on NSX platform as the mapping might be missing because
- the port was created before upgrading to grizzly.
-
- This routine also retrieves the identifier of the logical switch in
- the backend where the port is plugged. Prior to Icehouse this
- information was not available in the Neutron Database. For dealing
- with pre-existing records, this routine will query the backend
- for retrieving the correct switch identifier.
-
- As of Icehouse release it is not indeed anymore possible to assume
- the backend logical switch identifier is equal to the neutron
- network identifier.
- """
- nsx_switch_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
- session, neutron_port_id)
- if not nsx_switch_id:
- # Find logical switch for port from backend
- # This is a rather expensive query, but it won't be executed
- # more than once for each port in Neutron's lifetime
- nsx_ports = switchlib.query_lswitch_lports(
- cluster, '*', relations='LogicalSwitchConfig',
- filters={'tag': neutron_port_id,
- 'tag_scope': 'q_port_id'})
- # Only one result expected
- # NOTE(salv-orlando): Not handling the case where more than one
- # port is found with the same neutron port tag
- if not nsx_ports:
- LOG.warn(_LW("Unable to find NSX port for Neutron port %s"),
- neutron_port_id)
- # This method is supposed to return a tuple
- return None, None
- nsx_port = nsx_ports[0]
- nsx_switch_id = (nsx_port['_relations']
- ['LogicalSwitchConfig']['uuid'])
- if nsx_port_id:
- # Mapping already exists. Delete before recreating
- nsx_db.delete_neutron_nsx_port_mapping(
- session, neutron_port_id)
- else:
- nsx_port_id = nsx_port['uuid']
- # (re)Create DB mapping
- nsx_db.add_neutron_nsx_port_mapping(
- session, neutron_port_id,
- nsx_switch_id, nsx_port_id)
- return nsx_switch_id, nsx_port_id
-
-
-def get_nsx_security_group_id(session, cluster, neutron_id):
- """Return the NSX sec profile uuid for a given neutron sec group.
-
- First, look up the Neutron database. If not found, execute
- a query on NSX platform as the mapping might be missing.
- NOTE: Security groups are called 'security profiles' on the NSX backend.
- """
- nsx_id = nsx_db.get_nsx_security_group_id(session, neutron_id)
- if not nsx_id:
- # Find security profile on backend.
- # This is a rather expensive query, but it won't be executed
- # more than once for each security group in Neutron's lifetime
- nsx_sec_profiles = secgrouplib.query_security_profiles(
- cluster, '*',
- filters={'tag': neutron_id,
- 'tag_scope': 'q_sec_group_id'})
- # Only one result expected
- # NOTE(salv-orlando): Not handling the case where more than one
- # security profile is found with the same neutron port tag
- if not nsx_sec_profiles:
- LOG.warn(_LW("Unable to find NSX security profile for Neutron "
- "security group %s"), neutron_id)
- return
- elif len(nsx_sec_profiles) > 1:
- LOG.warn(_LW("Multiple NSX security profiles found for Neutron "
- "security group %s"), neutron_id)
- nsx_sec_profile = nsx_sec_profiles[0]
- nsx_id = nsx_sec_profile['uuid']
- with session.begin(subtransactions=True):
- # Create DB mapping
- nsx_db.add_neutron_nsx_security_group_mapping(
- session, neutron_id, nsx_id)
- return nsx_id
-
-
-def get_nsx_router_id(session, cluster, neutron_router_id):
- """Return the NSX router uuid for a given neutron router.
-
- First, look up the Neutron database. If not found, execute
- a query on NSX platform as the mapping might be missing.
- """
- nsx_router_id = nsx_db.get_nsx_router_id(
- session, neutron_router_id)
- if not nsx_router_id:
- # Find logical router from backend.
- # This is a rather expensive query, but it won't be executed
- # more than once for each router in Neutron's lifetime
- nsx_routers = routerlib.query_lrouters(
- cluster, '*',
- filters={'tag': neutron_router_id,
- 'tag_scope': 'q_router_id'})
- # Only one result expected
- # NOTE(salv-orlando): Not handling the case where more than one
- # port is found with the same neutron port tag
- if not nsx_routers:
- LOG.warn(_LW("Unable to find NSX router for Neutron router %s"),
- neutron_router_id)
- return
- nsx_router = nsx_routers[0]
- nsx_router_id = nsx_router['uuid']
- with session.begin(subtransactions=True):
- # Create DB mapping
- nsx_db.add_neutron_nsx_router_mapping(
- session,
- neutron_router_id,
- nsx_router_id)
- return nsx_router_id
-
-
-def create_nsx_cluster(cluster_opts, concurrent_connections, gen_timeout):
- cluster = nsx_cluster.NSXCluster(**cluster_opts)
-
- def _ctrl_split(x, y):
- return (x, int(y), True)
-
- api_providers = [_ctrl_split(*ctrl.split(':'))
- for ctrl in cluster.nsx_controllers]
- cluster.api_client = client.NsxApiClient(
- api_providers, cluster.nsx_user, cluster.nsx_password,
- http_timeout=cluster.http_timeout,
- retries=cluster.retries,
- redirects=cluster.redirects,
- concurrent_connections=concurrent_connections,
- gen_timeout=gen_timeout)
- return cluster
-
-
-def get_nsx_device_status(cluster, nsx_uuid):
- try:
- status_up = l2gwlib.get_gateway_device_status(
- cluster, nsx_uuid)
- if status_up:
- return networkgw_db.STATUS_ACTIVE
- else:
- return networkgw_db.STATUS_DOWN
- except api_exc.NsxApiException:
- return networkgw_db.STATUS_UNKNOWN
- except n_exc.NotFound:
- return networkgw_db.ERROR
-
-
-def get_nsx_device_statuses(cluster, tenant_id):
- try:
- status_dict = l2gwlib.get_gateway_devices_status(
- cluster, tenant_id)
- return dict((nsx_device_id,
- networkgw_db.STATUS_ACTIVE if connected
- else networkgw_db.STATUS_DOWN) for
- (nsx_device_id, connected) in status_dict.iteritems())
- except api_exc.NsxApiException:
- # Do not make a NSX API exception fatal
- if tenant_id:
- LOG.warn(_LW("Unable to retrieve operational status for gateway "
- "devices belonging to tenant: %s"), tenant_id)
- else:
- LOG.warn(_LW("Unable to retrieve operational status for "
- "gateway devices"))
-
-
-def _convert_bindings_to_nsx_transport_zones(bindings):
- nsx_transport_zones_config = []
- for binding in bindings:
- transport_entry = {}
- if binding.binding_type in [vmw_utils.NetworkTypes.FLAT,
- vmw_utils.NetworkTypes.VLAN]:
- transport_entry['transport_type'] = (
- vmw_utils.NetworkTypes.BRIDGE)
- transport_entry['binding_config'] = {}
- vlan_id = binding.vlan_id
- if vlan_id:
- transport_entry['binding_config'] = (
- {'vlan_translation': [{'transport': vlan_id}]})
- else:
- transport_entry['transport_type'] = binding.binding_type
- transport_entry['zone_uuid'] = binding.phy_uuid
- nsx_transport_zones_config.append(transport_entry)
- return nsx_transport_zones_config
-
-
-def _convert_segments_to_nsx_transport_zones(segments, default_tz_uuid):
- nsx_transport_zones_config = []
- for transport_zone in segments:
- for value in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID]:
- if transport_zone.get(value) == attr.ATTR_NOT_SPECIFIED:
- transport_zone[value] = None
-
- transport_entry = {}
- transport_type = transport_zone.get(pnet.NETWORK_TYPE)
- if transport_type in [vmw_utils.NetworkTypes.FLAT,
- vmw_utils.NetworkTypes.VLAN]:
- transport_entry['transport_type'] = (
- vmw_utils.NetworkTypes.BRIDGE)
- transport_entry['binding_config'] = {}
- vlan_id = transport_zone.get(pnet.SEGMENTATION_ID)
- if vlan_id:
- transport_entry['binding_config'] = (
- {'vlan_translation': [{'transport': vlan_id}]})
- else:
- transport_entry['transport_type'] = transport_type
- transport_entry['zone_uuid'] = (
- transport_zone[pnet.PHYSICAL_NETWORK] or default_tz_uuid)
- nsx_transport_zones_config.append(transport_entry)
- return nsx_transport_zones_config
-
-
-def convert_to_nsx_transport_zones(
- default_tz_uuid, network=None, bindings=None,
- default_transport_type=None):
-
- # Convert fields from provider request to nsx format
- if (network and not attr.is_attr_set(
- network.get(mpnet.SEGMENTS))):
- return [{"zone_uuid": default_tz_uuid,
- "transport_type": default_transport_type}]
-
- # Convert fields from db to nsx format
- if bindings:
- return _convert_bindings_to_nsx_transport_zones(bindings)
-
- # If we end up here we need to convert multiprovider segments into nsx
- # transport zone configurations
- return _convert_segments_to_nsx_transport_zones(
- network.get(mpnet.SEGMENTS), default_tz_uuid)
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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.
-
-from neutron.openstack.common import log
-from neutron.plugins.vmware.common import nsx_utils
-
-LOG = log.getLogger(__name__)
-# Protocol number look up for supported protocols
-protocol_num_look_up = {'tcp': 6, 'icmp': 1, 'udp': 17}
-
-
-def _convert_to_nsx_rule(session, cluster, rule, with_id=False):
- """Converts a Neutron security group rule to the NSX format.
-
- This routine also replaces Neutron IDs with NSX UUIDs.
- """
- nsx_rule = {}
- params = ['remote_ip_prefix', 'protocol',
- 'remote_group_id', 'port_range_min',
- 'port_range_max', 'ethertype']
- if with_id:
- params.append('id')
-
- for param in params:
- value = rule.get(param)
- if param not in rule:
- nsx_rule[param] = value
- elif not value:
- pass
- elif param == 'remote_ip_prefix':
- nsx_rule['ip_prefix'] = rule['remote_ip_prefix']
- elif param == 'remote_group_id':
- nsx_rule['profile_uuid'] = nsx_utils.get_nsx_security_group_id(
- session, cluster, rule['remote_group_id'])
-
- elif param == 'protocol':
- try:
- nsx_rule['protocol'] = int(rule['protocol'])
- except (ValueError, TypeError):
- nsx_rule['protocol'] = (
- protocol_num_look_up[rule['protocol']])
- else:
- nsx_rule[param] = value
- return nsx_rule
-
-
-def _convert_to_nsx_rules(session, cluster, rules, with_id=False):
- """Converts a list of Neutron security group rules to the NSX format."""
- nsx_rules = {'logical_port_ingress_rules': [],
- 'logical_port_egress_rules': []}
- for direction in ['logical_port_ingress_rules',
- 'logical_port_egress_rules']:
- for rule in rules[direction]:
- nsx_rules[direction].append(
- _convert_to_nsx_rule(session, cluster, rule, with_id))
- return nsx_rules
-
-
-def get_security_group_rules_nsx_format(session, cluster,
- security_group_rules, with_id=False):
- """Convert neutron security group rules into NSX format.
-
- This routine splits Neutron security group rules into two lists, one
- for ingress rules and the other for egress rules.
- """
-
- def fields(rule):
- _fields = ['remote_ip_prefix', 'remote_group_id', 'protocol',
- 'port_range_min', 'port_range_max', 'protocol', 'ethertype']
- if with_id:
- _fields.append('id')
- return dict((k, v) for k, v in rule.iteritems() if k in _fields)
-
- ingress_rules = []
- egress_rules = []
- for rule in security_group_rules:
- if rule.get('souce_group_id'):
- rule['remote_group_id'] = nsx_utils.get_nsx_security_group_id(
- session, cluster, rule['remote_group_id'])
-
- if rule['direction'] == 'ingress':
- ingress_rules.append(fields(rule))
- elif rule['direction'] == 'egress':
- egress_rules.append(fields(rule))
- rules = {'logical_port_ingress_rules': egress_rules,
- 'logical_port_egress_rules': ingress_rules}
- return _convert_to_nsx_rules(session, cluster, rules, with_id)
-
-
-def merge_security_group_rules_with_current(session, cluster,
- new_rules, current_rules):
- merged_rules = get_security_group_rules_nsx_format(
- session, cluster, current_rules)
- for new_rule in new_rules:
- rule = new_rule['security_group_rule']
- if rule['direction'] == 'ingress':
- merged_rules['logical_port_egress_rules'].append(
- _convert_to_nsx_rule(session, cluster, rule))
- elif rule['direction'] == 'egress':
- merged_rules['logical_port_ingress_rules'].append(
- _convert_to_nsx_rule(session, cluster, rule))
- return merged_rules
-
-
-def remove_security_group_with_id_and_id_field(rules, rule_id):
- """Remove rule by rule_id.
-
- This function receives all of the current rule associated with a
- security group and then removes the rule that matches the rule_id. In
- addition it removes the id field in the dict with each rule since that
- should not be passed to nsx.
- """
- for rule_direction in rules.values():
- item_to_remove = None
- for port_rule in rule_direction:
- if port_rule['id'] == rule_id:
- item_to_remove = port_rule
- else:
- # remove key from dictionary for NSX
- del port_rule['id']
- if item_to_remove:
- rule_direction.remove(item_to_remove)
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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 random
-
-from oslo_serialization import jsonutils
-from oslo_utils import timeutils
-
-from neutron.common import constants
-from neutron.common import exceptions
-from neutron import context
-from neutron.db import external_net_db
-from neutron.db import l3_db
-from neutron.db import models_v2
-from neutron.extensions import l3
-from neutron.i18n import _LE, _LI, _LW
-from neutron.openstack.common import log
-from neutron.openstack.common import loopingcall
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import nsx_utils
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import router as routerlib
-from neutron.plugins.vmware.nsxlib import switch as switchlib
-
-# Maximum page size for a single request
-# NOTE(salv-orlando): This might become a version-dependent map should the
-# limit be raised in future versions
-MAX_PAGE_SIZE = 5000
-
-LOG = log.getLogger(__name__)
-
-
-class NsxCache(object):
- """A simple Cache for NSX resources.
-
- Associates resource id with resource hash to rapidly identify
- updated resources.
- Each entry in the cache also stores the following information:
- - changed: the resource in the cache has been altered following
- an update or a delete
- - hit: the resource has been visited during an update (and possibly
- left unchanged)
- - data: current resource data
- - data_bk: backup of resource data prior to its removal
- """
-
- def __init__(self):
- # Maps a uuid to the dict containing it
- self._uuid_dict_mappings = {}
- # Dicts for NSX cached resources
- self._lswitches = {}
- self._lswitchports = {}
- self._lrouters = {}
-
- def __getitem__(self, key):
- # uuids are unique across the various types of resources
- # TODO(salv-orlando): Avoid lookups over all dictionaries
- # when retrieving items
- # Fetch lswitches, lports, or lrouters
- resources = self._uuid_dict_mappings[key]
- return resources[key]
-
- def _clear_changed_flag_and_remove_from_cache(self, resources):
- # Clear the 'changed' attribute for all items
- for uuid, item in resources.items():
- if item.pop('changed', None) and not item.get('data'):
- # The item is not anymore in NSX, so delete it
- del resources[uuid]
- del self._uuid_dict_mappings[uuid]
- LOG.debug("Removed item %s from NSX object cache", uuid)
-
- def _update_resources(self, resources, new_resources, clear_changed=True):
- if clear_changed:
- self._clear_changed_flag_and_remove_from_cache(resources)
-
- def do_hash(item):
- return hash(jsonutils.dumps(item))
-
- # Parse new data and identify new, deleted, and updated resources
- for item in new_resources:
- item_id = item['uuid']
- if resources.get(item_id):
- new_hash = do_hash(item)
- if new_hash != resources[item_id]['hash']:
- resources[item_id]['hash'] = new_hash
- resources[item_id]['changed'] = True
- resources[item_id]['data_bk'] = (
- resources[item_id]['data'])
- resources[item_id]['data'] = item
- # Mark the item as hit in any case
- resources[item_id]['hit'] = True
- LOG.debug("Updating item %s in NSX object cache", item_id)
- else:
- resources[item_id] = {'hash': do_hash(item)}
- resources[item_id]['hit'] = True
- resources[item_id]['changed'] = True
- resources[item_id]['data'] = item
- # add a uuid to dict mapping for easy retrieval
- # with __getitem__
- self._uuid_dict_mappings[item_id] = resources
- LOG.debug("Added item %s to NSX object cache", item_id)
-
- def _delete_resources(self, resources):
- # Mark for removal all the elements which have not been visited.
- # And clear the 'hit' attribute.
- for to_delete in [k for (k, v) in resources.iteritems()
- if not v.pop('hit', False)]:
- resources[to_delete]['changed'] = True
- resources[to_delete]['data_bk'] = (
- resources[to_delete].pop('data', None))
-
- def _get_resource_ids(self, resources, changed_only):
- if changed_only:
- return [k for (k, v) in resources.iteritems()
- if v.get('changed')]
- return resources.keys()
-
- def get_lswitches(self, changed_only=False):
- return self._get_resource_ids(self._lswitches, changed_only)
-
- def get_lrouters(self, changed_only=False):
- return self._get_resource_ids(self._lrouters, changed_only)
-
- def get_lswitchports(self, changed_only=False):
- return self._get_resource_ids(self._lswitchports, changed_only)
-
- def update_lswitch(self, lswitch):
- self._update_resources(self._lswitches, [lswitch], clear_changed=False)
-
- def update_lrouter(self, lrouter):
- self._update_resources(self._lrouters, [lrouter], clear_changed=False)
-
- def update_lswitchport(self, lswitchport):
- self._update_resources(self._lswitchports, [lswitchport],
- clear_changed=False)
-
- def process_updates(self, lswitches=None,
- lrouters=None, lswitchports=None):
- self._update_resources(self._lswitches, lswitches)
- self._update_resources(self._lrouters, lrouters)
- self._update_resources(self._lswitchports, lswitchports)
- return (self._get_resource_ids(self._lswitches, changed_only=True),
- self._get_resource_ids(self._lrouters, changed_only=True),
- self._get_resource_ids(self._lswitchports, changed_only=True))
-
- def process_deletes(self):
- self._delete_resources(self._lswitches)
- self._delete_resources(self._lrouters)
- self._delete_resources(self._lswitchports)
- return (self._get_resource_ids(self._lswitches, changed_only=True),
- self._get_resource_ids(self._lrouters, changed_only=True),
- self._get_resource_ids(self._lswitchports, changed_only=True))
-
-
-class SyncParameters(object):
- """Defines attributes used by the synchronization procedure.
-
- chunk_size: Actual chunk size
- extra_chunk_size: Additional data to fetch because of chunk size
- adjustment
- current_chunk: Counter of the current data chunk being synchronized
- Page cursors: markers for the next resource to fetch.
- 'start' means page cursor unset for fetching 1st page
- init_sync_performed: True if the initial synchronization concluded
- """
-
- def __init__(self, min_chunk_size):
- self.chunk_size = min_chunk_size
- self.extra_chunk_size = 0
- self.current_chunk = 0
- self.ls_cursor = 'start'
- self.lr_cursor = 'start'
- self.lp_cursor = 'start'
- self.init_sync_performed = False
- self.total_size = 0
-
-
-def _start_loopingcall(min_chunk_size, state_sync_interval, func):
- """Start a loopingcall for the synchronization task."""
- # Start a looping call to synchronize operational status
- # for neutron resources
- if not state_sync_interval:
- # do not start the looping call if specified
- # sync interval is 0
- return
- state_synchronizer = loopingcall.DynamicLoopingCall(
- func, sp=SyncParameters(min_chunk_size))
- state_synchronizer.start(
- periodic_interval_max=state_sync_interval)
- return state_synchronizer
-
-
-class NsxSynchronizer(object):
-
- LS_URI = nsxlib._build_uri_path(
- switchlib.LSWITCH_RESOURCE, fields='uuid,tags,fabric_status',
- relations='LogicalSwitchStatus')
- LR_URI = nsxlib._build_uri_path(
- routerlib.LROUTER_RESOURCE, fields='uuid,tags,fabric_status',
- relations='LogicalRouterStatus')
- LP_URI = nsxlib._build_uri_path(
- switchlib.LSWITCHPORT_RESOURCE,
- parent_resource_id='*',
- fields='uuid,tags,fabric_status_up',
- relations='LogicalPortStatus')
-
- def __init__(self, plugin, cluster, state_sync_interval,
- req_delay, min_chunk_size, max_rand_delay=0):
- random.seed()
- self._nsx_cache = NsxCache()
- # Store parameters as instance members
- # NOTE(salv-orlando): apologies if it looks java-ish
- self._plugin = plugin
- self._cluster = cluster
- self._req_delay = req_delay
- self._sync_interval = state_sync_interval
- self._max_rand_delay = max_rand_delay
- # Validate parameters
- if self._sync_interval < self._req_delay:
- err_msg = (_("Minimum request delay:%(req_delay)s must not "
- "exceed synchronization interval:%(sync_interval)s") %
- {'req_delay': self._req_delay,
- 'sync_interval': self._sync_interval})
- LOG.error(err_msg)
- raise nsx_exc.NsxPluginException(err_msg=err_msg)
- # Backoff time in case of failures while fetching sync data
- self._sync_backoff = 1
- # Store the looping call in an instance variable to allow unit tests
- # for controlling its lifecycle
- self._sync_looping_call = _start_loopingcall(
- min_chunk_size, state_sync_interval, self._synchronize_state)
-
- def _get_tag_dict(self, tags):
- return dict((tag.get('scope'), tag['tag']) for tag in tags)
-
- def synchronize_network(self, context, neutron_network_data,
- lswitches=None):
- """Synchronize a Neutron network with its NSX counterpart.
-
- This routine synchronizes a set of switches when a Neutron
- network is mapped to multiple lswitches.
- """
- if not lswitches:
- # Try to get logical switches from nsx
- try:
- lswitches = nsx_utils.fetch_nsx_switches(
- context.session, self._cluster,
- neutron_network_data['id'])
- except exceptions.NetworkNotFound:
- # TODO(salv-orlando): We should be catching
- # api_exc.ResourceNotFound here
- # The logical switch was not found
- LOG.warning(_LW("Logical switch for neutron network %s not "
- "found on NSX."), neutron_network_data['id'])
- lswitches = []
- else:
- for lswitch in lswitches:
- self._nsx_cache.update_lswitch(lswitch)
- # By default assume things go wrong
- status = constants.NET_STATUS_ERROR
- # In most cases lswitches will contain a single element
- for ls in lswitches:
- if not ls:
- # Logical switch was deleted
- break
- ls_status = ls['_relations']['LogicalSwitchStatus']
- if not ls_status['fabric_status']:
- status = constants.NET_STATUS_DOWN
- break
- else:
- # No switch was down or missing. Set status to ACTIVE unless
- # there were no switches in the first place!
- if lswitches:
- status = constants.NET_STATUS_ACTIVE
- # Update db object
- if status == neutron_network_data['status']:
- # do nothing
- return
-
- with context.session.begin(subtransactions=True):
- try:
- network = self._plugin._get_network(context,
- neutron_network_data['id'])
- except exceptions.NetworkNotFound:
- pass
- else:
- network.status = status
- LOG.debug("Updating status for neutron resource %(q_id)s to:"
- " %(status)s",
- {'q_id': neutron_network_data['id'],
- 'status': status})
-
- def _synchronize_lswitches(self, ctx, ls_uuids, scan_missing=False):
- if not ls_uuids and not scan_missing:
- return
- neutron_net_ids = set()
- neutron_nsx_mappings = {}
- # TODO(salvatore-orlando): Deal with the case the tag
- # has been tampered with
- for ls_uuid in ls_uuids:
- # If the lswitch has been deleted, get backup copy of data
- lswitch = (self._nsx_cache[ls_uuid].get('data') or
- self._nsx_cache[ls_uuid].get('data_bk'))
- tags = self._get_tag_dict(lswitch['tags'])
- neutron_id = tags.get('quantum_net_id')
- neutron_net_ids.add(neutron_id)
- neutron_nsx_mappings[neutron_id] = (
- neutron_nsx_mappings.get(neutron_id, []) +
- [self._nsx_cache[ls_uuid]])
- # Fetch neutron networks from database
- filters = {'router:external': [False]}
- if not scan_missing:
- filters['id'] = neutron_net_ids
-
- networks = self._plugin._get_collection(
- ctx, models_v2.Network, self._plugin._make_network_dict,
- filters=filters)
-
- for network in networks:
- lswitches = neutron_nsx_mappings.get(network['id'], [])
- lswitches = [lsw.get('data') for lsw in lswitches]
- self.synchronize_network(ctx, network, lswitches)
-
- def synchronize_router(self, context, neutron_router_data,
- lrouter=None):
- """Synchronize a neutron router with its NSX counterpart."""
- if not lrouter:
- # Try to get router from nsx
- try:
- # This query will return the logical router status too
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self._cluster, neutron_router_data['id'])
- if nsx_router_id:
- lrouter = routerlib.get_lrouter(
- self._cluster, nsx_router_id)
- except exceptions.NotFound:
- # NOTE(salv-orlando): We should be catching
- # api_exc.ResourceNotFound here
- # The logical router was not found
- LOG.warning(_LW("Logical router for neutron router %s not "
- "found on NSX."), neutron_router_data['id'])
- if lrouter:
- # Update the cache
- self._nsx_cache.update_lrouter(lrouter)
-
- # Note(salv-orlando): It might worth adding a check to verify neutron
- # resource tag in nsx entity matches a Neutron id.
- # By default assume things go wrong
- status = constants.NET_STATUS_ERROR
- if lrouter:
- lr_status = (lrouter['_relations']
- ['LogicalRouterStatus']
- ['fabric_status'])
- status = (lr_status and
- constants.NET_STATUS_ACTIVE
- or constants.NET_STATUS_DOWN)
- # Update db object
- if status == neutron_router_data['status']:
- # do nothing
- return
-
- with context.session.begin(subtransactions=True):
- try:
- router = self._plugin._get_router(context,
- neutron_router_data['id'])
- except l3.RouterNotFound:
- pass
- else:
- router.status = status
- LOG.debug("Updating status for neutron resource %(q_id)s to:"
- " %(status)s",
- {'q_id': neutron_router_data['id'],
- 'status': status})
-
- def _synchronize_lrouters(self, ctx, lr_uuids, scan_missing=False):
- if not lr_uuids and not scan_missing:
- return
- # TODO(salvatore-orlando): Deal with the case the tag
- # has been tampered with
- neutron_router_mappings = {}
- for lr_uuid in lr_uuids:
- lrouter = (self._nsx_cache[lr_uuid].get('data') or
- self._nsx_cache[lr_uuid].get('data_bk'))
- tags = self._get_tag_dict(lrouter['tags'])
- neutron_router_id = tags.get('q_router_id')
- if neutron_router_id:
- neutron_router_mappings[neutron_router_id] = (
- self._nsx_cache[lr_uuid])
- else:
- LOG.warn(_LW("Unable to find Neutron router id for "
- "NSX logical router: %s"), lr_uuid)
- # Fetch neutron routers from database
- filters = ({} if scan_missing else
- {'id': neutron_router_mappings.keys()})
- routers = self._plugin._get_collection(
- ctx, l3_db.Router, self._plugin._make_router_dict,
- filters=filters)
- for router in routers:
- lrouter = neutron_router_mappings.get(router['id'])
- self.synchronize_router(
- ctx, router, lrouter and lrouter.get('data'))
-
- def synchronize_port(self, context, neutron_port_data,
- lswitchport=None, ext_networks=None):
- """Synchronize a Neutron port with its NSX counterpart."""
- # Skip synchronization for ports on external networks
- if not ext_networks:
- ext_networks = [net['id'] for net in context.session.query(
- models_v2.Network).join(
- external_net_db.ExternalNetwork,
- (models_v2.Network.id ==
- external_net_db.ExternalNetwork.network_id))]
- if neutron_port_data['network_id'] in ext_networks:
- with context.session.begin(subtransactions=True):
- neutron_port_data['status'] = constants.PORT_STATUS_ACTIVE
- return
-
- if not lswitchport:
- # Try to get port from nsx
- try:
- ls_uuid, lp_uuid = nsx_utils.get_nsx_switch_and_port_id(
- context.session, self._cluster, neutron_port_data['id'])
- if lp_uuid:
- lswitchport = switchlib.get_port(
- self._cluster, ls_uuid, lp_uuid,
- relations='LogicalPortStatus')
- except (exceptions.PortNotFoundOnNetwork):
- # NOTE(salv-orlando): We should be catching
- # api_exc.ResourceNotFound here instead
- # of PortNotFoundOnNetwork when the id exists but
- # the logical switch port was not found
- LOG.warning(_LW("Logical switch port for neutron port %s "
- "not found on NSX."), neutron_port_data['id'])
- lswitchport = None
- else:
- # If lswitchport is not None, update the cache.
- # It could be none if the port was deleted from the backend
- if lswitchport:
- self._nsx_cache.update_lswitchport(lswitchport)
- # Note(salv-orlando): It might worth adding a check to verify neutron
- # resource tag in nsx entity matches Neutron id.
- # By default assume things go wrong
- status = constants.PORT_STATUS_ERROR
- if lswitchport:
- lp_status = (lswitchport['_relations']
- ['LogicalPortStatus']
- ['fabric_status_up'])
- status = (lp_status and
- constants.PORT_STATUS_ACTIVE
- or constants.PORT_STATUS_DOWN)
-
- # Update db object
- if status == neutron_port_data['status']:
- # do nothing
- return
-
- with context.session.begin(subtransactions=True):
- try:
- port = self._plugin._get_port(context,
- neutron_port_data['id'])
- except exceptions.PortNotFound:
- pass
- else:
- port.status = status
- LOG.debug("Updating status for neutron resource %(q_id)s to:"
- " %(status)s",
- {'q_id': neutron_port_data['id'],
- 'status': status})
-
- def _synchronize_lswitchports(self, ctx, lp_uuids, scan_missing=False):
- if not lp_uuids and not scan_missing:
- return
- # Find Neutron port id by tag - the tag is already
- # loaded in memory, no reason for doing a db query
- # TODO(salvatore-orlando): Deal with the case the tag
- # has been tampered with
- neutron_port_mappings = {}
- for lp_uuid in lp_uuids:
- lport = (self._nsx_cache[lp_uuid].get('data') or
- self._nsx_cache[lp_uuid].get('data_bk'))
- tags = self._get_tag_dict(lport['tags'])
- neutron_port_id = tags.get('q_port_id')
- if neutron_port_id:
- neutron_port_mappings[neutron_port_id] = (
- self._nsx_cache[lp_uuid])
- # Fetch neutron ports from database
- # At the first sync we need to fetch all ports
- filters = ({} if scan_missing else
- {'id': neutron_port_mappings.keys()})
- # TODO(salv-orlando): Work out a solution for avoiding
- # this query
- ext_nets = [net['id'] for net in ctx.session.query(
- models_v2.Network).join(
- external_net_db.ExternalNetwork,
- (models_v2.Network.id ==
- external_net_db.ExternalNetwork.network_id))]
- ports = self._plugin._get_collection(
- ctx, models_v2.Port, self._plugin._make_port_dict,
- filters=filters)
- for port in ports:
- lswitchport = neutron_port_mappings.get(port['id'])
- self.synchronize_port(
- ctx, port, lswitchport and lswitchport.get('data'),
- ext_networks=ext_nets)
-
- def _get_chunk_size(self, sp):
- # NOTE(salv-orlando): Try to use __future__ for this routine only?
- ratio = ((float(sp.total_size) / float(sp.chunk_size)) /
- (float(self._sync_interval) / float(self._req_delay)))
- new_size = max(1.0, ratio) * float(sp.chunk_size)
- return int(new_size) + (new_size - int(new_size) > 0)
-
- def _fetch_data(self, uri, cursor, page_size):
- # If not cursor there is nothing to retrieve
- if cursor:
- if cursor == 'start':
- cursor = None
- # Chunk size tuning might, in some conditions, make it larger
- # than 5,000, which is the maximum page size allowed by the NSX
- # API. In this case the request should be split in multiple
- # requests. This is not ideal, and therefore a log warning will
- # be emitted.
- num_requests = page_size / (MAX_PAGE_SIZE + 1) + 1
- if num_requests > 1:
- LOG.warn(_LW("Requested page size is %(cur_chunk_size)d. "
- "It might be necessary to do %(num_requests)d "
- "round-trips to NSX for fetching data. Please "
- "tune sync parameters to ensure chunk size "
- "is less than %(max_page_size)d"),
- {'cur_chunk_size': page_size,
- 'num_requests': num_requests,
- 'max_page_size': MAX_PAGE_SIZE})
- # Only the first request might return the total size,
- # subsequent requests will definetely not
- results, cursor, total_size = nsxlib.get_single_query_page(
- uri, self._cluster, cursor,
- min(page_size, MAX_PAGE_SIZE))
- for _req in range(num_requests - 1):
- # If no cursor is returned break the cycle as there is no
- # actual need to perform multiple requests (all fetched)
- # This happens when the overall size of resources exceeds
- # the maximum page size, but the number for each single
- # resource type is below this threshold
- if not cursor:
- break
- req_results, cursor = nsxlib.get_single_query_page(
- uri, self._cluster, cursor,
- min(page_size, MAX_PAGE_SIZE))[:2]
- results.extend(req_results)
- # reset cursor before returning if we queried just to
- # know the number of entities
- return results, cursor if page_size else 'start', total_size
- return [], cursor, None
-
- def _fetch_nsx_data_chunk(self, sp):
- base_chunk_size = sp.chunk_size
- chunk_size = base_chunk_size + sp.extra_chunk_size
- LOG.info(_LI("Fetching up to %s resources "
- "from NSX backend"), chunk_size)
- fetched = ls_count = lr_count = lp_count = 0
- lswitches = lrouters = lswitchports = []
- if sp.ls_cursor or sp.ls_cursor == 'start':
- (lswitches, sp.ls_cursor, ls_count) = self._fetch_data(
- self.LS_URI, sp.ls_cursor, chunk_size)
- fetched = len(lswitches)
- if fetched < chunk_size and sp.lr_cursor or sp.lr_cursor == 'start':
- (lrouters, sp.lr_cursor, lr_count) = self._fetch_data(
- self.LR_URI, sp.lr_cursor, max(chunk_size - fetched, 0))
- fetched += len(lrouters)
- if fetched < chunk_size and sp.lp_cursor or sp.lp_cursor == 'start':
- (lswitchports, sp.lp_cursor, lp_count) = self._fetch_data(
- self.LP_URI, sp.lp_cursor, max(chunk_size - fetched, 0))
- fetched += len(lswitchports)
- if sp.current_chunk == 0:
- # No cursors were provided. Then it must be possible to
- # calculate the total amount of data to fetch
- sp.total_size = ls_count + lr_count + lp_count
- LOG.debug("Total data size: %d", sp.total_size)
- sp.chunk_size = self._get_chunk_size(sp)
- # Calculate chunk size adjustment
- sp.extra_chunk_size = sp.chunk_size - base_chunk_size
- LOG.debug("Fetched %(num_lswitches)d logical switches, "
- "%(num_lswitchports)d logical switch ports,"
- "%(num_lrouters)d logical routers",
- {'num_lswitches': len(lswitches),
- 'num_lswitchports': len(lswitchports),
- 'num_lrouters': len(lrouters)})
- return (lswitches, lrouters, lswitchports)
-
- def _synchronize_state(self, sp):
- # If the plugin has been destroyed, stop the LoopingCall
- if not self._plugin:
- raise loopingcall.LoopingCallDone()
- start = timeutils.utcnow()
- # Reset page cursor variables if necessary
- if sp.current_chunk == 0:
- sp.ls_cursor = sp.lr_cursor = sp.lp_cursor = 'start'
- LOG.info(_LI("Running state synchronization task. Chunk: %s"),
- sp.current_chunk)
- # Fetch chunk_size data from NSX
- try:
- (lswitches, lrouters, lswitchports) = (
- self._fetch_nsx_data_chunk(sp))
- except (api_exc.RequestTimeout, api_exc.NsxApiException):
- sleep_interval = self._sync_backoff
- # Cap max back off to 64 seconds
- self._sync_backoff = min(self._sync_backoff * 2, 64)
- LOG.exception(_LE("An error occurred while communicating with "
- "NSX backend. Will retry synchronization "
- "in %d seconds"), sleep_interval)
- return sleep_interval
- LOG.debug("Time elapsed querying NSX: %s",
- timeutils.utcnow() - start)
- if sp.total_size:
- num_chunks = ((sp.total_size / sp.chunk_size) +
- (sp.total_size % sp.chunk_size != 0))
- else:
- num_chunks = 1
- LOG.debug("Number of chunks: %d", num_chunks)
- # Find objects which have changed on NSX side and need
- # to be synchronized
- LOG.debug("Processing NSX cache for updated objects")
- (ls_uuids, lr_uuids, lp_uuids) = self._nsx_cache.process_updates(
- lswitches, lrouters, lswitchports)
- # Process removed objects only at the last chunk
- scan_missing = (sp.current_chunk == num_chunks - 1 and
- not sp.init_sync_performed)
- if sp.current_chunk == num_chunks - 1:
- LOG.debug("Processing NSX cache for deleted objects")
- self._nsx_cache.process_deletes()
- ls_uuids = self._nsx_cache.get_lswitches(
- changed_only=not scan_missing)
- lr_uuids = self._nsx_cache.get_lrouters(
- changed_only=not scan_missing)
- lp_uuids = self._nsx_cache.get_lswitchports(
- changed_only=not scan_missing)
- LOG.debug("Time elapsed hashing data: %s",
- timeutils.utcnow() - start)
- # Get an admin context
- ctx = context.get_admin_context()
- # Synchronize with database
- self._synchronize_lswitches(ctx, ls_uuids,
- scan_missing=scan_missing)
- self._synchronize_lrouters(ctx, lr_uuids,
- scan_missing=scan_missing)
- self._synchronize_lswitchports(ctx, lp_uuids,
- scan_missing=scan_missing)
- # Increase chunk counter
- LOG.info(_LI("Synchronization for chunk %(chunk_num)d of "
- "%(total_chunks)d performed"),
- {'chunk_num': sp.current_chunk + 1,
- 'total_chunks': num_chunks})
- sp.current_chunk = (sp.current_chunk + 1) % num_chunks
- added_delay = 0
- if sp.current_chunk == 0:
- # Ensure init_sync_performed is True
- if not sp.init_sync_performed:
- sp.init_sync_performed = True
- # Add additional random delay
- added_delay = random.randint(0, self._max_rand_delay)
- LOG.debug("Time elapsed at end of sync: %s",
- timeutils.utcnow() - start)
- return self._sync_interval / num_chunks + added_delay
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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 hashlib
-
-from neutron.api.v2 import attributes
-from neutron.openstack.common import log
-from neutron import version
-
-
-LOG = log.getLogger(__name__)
-MAX_DISPLAY_NAME_LEN = 40
-NEUTRON_VERSION = version.version_info.release_string()
-
-
-# Allowed network types for the NSX Plugin
-class NetworkTypes(object):
- """Allowed provider network types for the NSX Plugin."""
- L3_EXT = 'l3_ext'
- STT = 'stt'
- GRE = 'gre'
- FLAT = 'flat'
- VLAN = 'vlan'
- BRIDGE = 'bridge'
-
-
-def get_tags(**kwargs):
- tags = ([dict(tag=value, scope=key)
- for key, value in kwargs.iteritems()])
- tags.append({"tag": NEUTRON_VERSION, "scope": "quantum"})
- return sorted(tags)
-
-
-def device_id_to_vm_id(device_id, obfuscate=False):
- # device_id can be longer than 40 characters, for example
- # a device_id for a dhcp port is like the following:
- #
- # dhcp83b5fdeb-e3b4-5e18-ac5f-55161...80747326-47d7-46c2-a87a-cf6d5194877c
- #
- # To fit it into an NSX tag we need to hash it, however device_id
- # used for ports associated to VM's are small enough so let's skip the
- # hashing
- if len(device_id) > MAX_DISPLAY_NAME_LEN or obfuscate:
- return hashlib.sha1(device_id).hexdigest()
- else:
- return device_id
-
-
-def check_and_truncate(display_name):
- if (attributes.is_attr_set(display_name) and
- len(display_name) > MAX_DISPLAY_NAME_LEN):
- LOG.debug("Specified name:'%s' exceeds maximum length. "
- "It will be truncated on NSX", display_name)
- return display_name[:MAX_DISPLAY_NAME_LEN]
- return display_name or ''
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-#
-# 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.
-
-from oslo_db import exception as db_exc
-from oslo_utils import excutils
-from sqlalchemy.orm import exc
-
-import neutron.db.api as db
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.dbexts import nsx_models
-
-LOG = logging.getLogger(__name__)
-
-
-def get_network_bindings(session, network_id):
- session = session or db.get_session()
- return (session.query(nsx_models.TzNetworkBinding).
- filter_by(network_id=network_id).
- all())
-
-
-def get_network_bindings_by_vlanid_and_physical_net(session, vlan_id,
- phy_uuid):
- session = session or db.get_session()
- return (session.query(nsx_models.TzNetworkBinding).
- filter_by(vlan_id=vlan_id, phy_uuid=phy_uuid).
- all())
-
-
-def delete_network_bindings(session, network_id):
- return (session.query(nsx_models.TzNetworkBinding).
- filter_by(network_id=network_id).delete())
-
-
-def add_network_binding(session, network_id, binding_type, phy_uuid, vlan_id):
- with session.begin(subtransactions=True):
- binding = nsx_models.TzNetworkBinding(network_id, binding_type,
- phy_uuid, vlan_id)
- session.add(binding)
- return binding
-
-
-def add_neutron_nsx_network_mapping(session, neutron_id, nsx_switch_id):
- with session.begin(subtransactions=True):
- mapping = nsx_models.NeutronNsxNetworkMapping(
- neutron_id=neutron_id, nsx_id=nsx_switch_id)
- session.add(mapping)
- return mapping
-
-
-def add_neutron_nsx_port_mapping(session, neutron_id,
- nsx_switch_id, nsx_port_id):
- session.begin(subtransactions=True)
- try:
- mapping = nsx_models.NeutronNsxPortMapping(
- neutron_id, nsx_switch_id, nsx_port_id)
- session.add(mapping)
- session.commit()
- except db_exc.DBDuplicateEntry:
- with excutils.save_and_reraise_exception() as ctxt:
- session.rollback()
- # do not complain if the same exact mapping is being added,
- # otherwise re-raise because even though it is possible for the
- # same neutron port to map to different back-end ports over time,
- # this should not occur whilst a mapping already exists
- current = get_nsx_switch_and_port_id(session, neutron_id)
- if current[1] == nsx_port_id:
- LOG.debug("Port mapping for %s already available",
- neutron_id)
- ctxt.reraise = False
- except db_exc.DBError:
- with excutils.save_and_reraise_exception():
- # rollback for any other db error
- session.rollback()
- return mapping
-
-
-def add_neutron_nsx_router_mapping(session, neutron_id, nsx_router_id):
- with session.begin(subtransactions=True):
- mapping = nsx_models.NeutronNsxRouterMapping(
- neutron_id=neutron_id, nsx_id=nsx_router_id)
- session.add(mapping)
- return mapping
-
-
-def add_neutron_nsx_security_group_mapping(session, neutron_id, nsx_id):
- """Map a Neutron security group to a NSX security profile.
-
- :param session: a valid database session object
- :param neutron_id: a neutron security group identifier
- :param nsx_id: a nsx security profile identifier
- """
- with session.begin(subtransactions=True):
- mapping = nsx_models.NeutronNsxSecurityGroupMapping(
- neutron_id=neutron_id, nsx_id=nsx_id)
- session.add(mapping)
- return mapping
-
-
-def get_nsx_switch_ids(session, neutron_id):
- # This function returns a list of NSX switch identifiers because of
- # the possibility of chained logical switches
- return [mapping['nsx_id'] for mapping in
- session.query(nsx_models.NeutronNsxNetworkMapping).filter_by(
- neutron_id=neutron_id)]
-
-
-def get_nsx_switch_and_port_id(session, neutron_id):
- try:
- mapping = (session.query(nsx_models.NeutronNsxPortMapping).
- filter_by(neutron_id=neutron_id).
- one())
- return mapping['nsx_switch_id'], mapping['nsx_port_id']
- except exc.NoResultFound:
- LOG.debug("NSX identifiers for neutron port %s not yet "
- "stored in Neutron DB", neutron_id)
- return None, None
-
-
-def get_nsx_router_id(session, neutron_id):
- try:
- mapping = (session.query(nsx_models.NeutronNsxRouterMapping).
- filter_by(neutron_id=neutron_id).one())
- return mapping['nsx_id']
- except exc.NoResultFound:
- LOG.debug("NSX identifiers for neutron router %s not yet "
- "stored in Neutron DB", neutron_id)
-
-
-def get_nsx_security_group_id(session, neutron_id):
- """Return the id of a security group in the NSX backend.
-
- Note: security groups are called 'security profiles' in NSX
- """
- try:
- mapping = (session.query(nsx_models.NeutronNsxSecurityGroupMapping).
- filter_by(neutron_id=neutron_id).
- one())
- return mapping['nsx_id']
- except exc.NoResultFound:
- LOG.debug("NSX identifiers for neutron security group %s not yet "
- "stored in Neutron DB", neutron_id)
- return None
-
-
-def _delete_by_neutron_id(session, model, neutron_id):
- return session.query(model).filter_by(neutron_id=neutron_id).delete()
-
-
-def delete_neutron_nsx_port_mapping(session, neutron_id):
- return _delete_by_neutron_id(
- session, nsx_models.NeutronNsxPortMapping, neutron_id)
-
-
-def delete_neutron_nsx_router_mapping(session, neutron_id):
- return _delete_by_neutron_id(
- session, nsx_models.NeutronNsxRouterMapping, neutron_id)
-
-
-def unset_default_network_gateways(session):
- with session.begin(subtransactions=True):
- session.query(nsx_models.NetworkGateway).update(
- {nsx_models.NetworkGateway.default: False})
-
-
-def set_default_network_gateway(session, gw_id):
- with session.begin(subtransactions=True):
- gw = (session.query(nsx_models.NetworkGateway).
- filter_by(id=gw_id).one())
- gw['default'] = True
-
-
-def set_multiprovider_network(session, network_id):
- with session.begin(subtransactions=True):
- multiprovider_network = nsx_models.MultiProviderNetworks(
- network_id)
- session.add(multiprovider_network)
- return multiprovider_network
-
-
-def is_multiprovider_network(session, network_id):
- with session.begin(subtransactions=True):
- return bool(
- session.query(nsx_models.MultiProviderNetworks).filter_by(
- network_id=network_id).first())
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-
-from oslo_db import exception as d_exc
-from sqlalchemy import orm
-
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import exceptions as p_exc
-from neutron.plugins.vmware.dbexts import nsx_models
-
-
-LOG = logging.getLogger(__name__)
-
-
-def lsn_add(context, network_id, lsn_id):
- """Add Logical Service Node information to persistent datastore."""
- with context.session.begin(subtransactions=True):
- lsn = nsx_models.Lsn(network_id, lsn_id)
- context.session.add(lsn)
-
-
-def lsn_remove(context, lsn_id):
- """Remove Logical Service Node information from datastore given its id."""
- with context.session.begin(subtransactions=True):
- context.session.query(nsx_models.Lsn).filter_by(lsn_id=lsn_id).delete()
-
-
-def lsn_remove_for_network(context, network_id):
- """Remove information about the Logical Service Node given its network."""
- with context.session.begin(subtransactions=True):
- context.session.query(nsx_models.Lsn).filter_by(
- net_id=network_id).delete()
-
-
-def lsn_get_for_network(context, network_id, raise_on_err=True):
- """Retrieve LSN information given its network id."""
- query = context.session.query(nsx_models.Lsn)
- try:
- return query.filter_by(net_id=network_id).one()
- except (orm.exc.NoResultFound, d_exc.DBError):
- msg = _('Unable to find Logical Service Node for network %s')
- if raise_on_err:
- LOG.error(msg, network_id)
- raise p_exc.LsnNotFound(entity='network',
- entity_id=network_id)
- else:
- LOG.warn(msg, network_id)
-
-
-def lsn_port_add_for_lsn(context, lsn_port_id, subnet_id, mac, lsn_id):
- """Add Logical Service Node Port information to persistent datastore."""
- with context.session.begin(subtransactions=True):
- lsn_port = nsx_models.LsnPort(lsn_port_id, subnet_id, mac, lsn_id)
- context.session.add(lsn_port)
-
-
-def lsn_port_get_for_subnet(context, subnet_id, raise_on_err=True):
- """Return Logical Service Node Port information given its subnet id."""
- with context.session.begin(subtransactions=True):
- try:
- return (context.session.query(nsx_models.LsnPort).
- filter_by(sub_id=subnet_id).one())
- except (orm.exc.NoResultFound, d_exc.DBError):
- if raise_on_err:
- raise p_exc.LsnPortNotFound(lsn_id=None,
- entity='subnet',
- entity_id=subnet_id)
-
-
-def lsn_port_get_for_mac(context, mac_address, raise_on_err=True):
- """Return Logical Service Node Port information given its mac address."""
- with context.session.begin(subtransactions=True):
- try:
- return (context.session.query(nsx_models.LsnPort).
- filter_by(mac_addr=mac_address).one())
- except (orm.exc.NoResultFound, d_exc.DBError):
- if raise_on_err:
- raise p_exc.LsnPortNotFound(lsn_id=None,
- entity='mac',
- entity_id=mac_address)
-
-
-def lsn_port_remove(context, lsn_port_id):
- """Remove Logical Service Node port from the given Logical Service Node."""
- with context.session.begin(subtransactions=True):
- (context.session.query(nsx_models.LsnPort).
- filter_by(lsn_port_id=lsn_port_id).delete())
+++ /dev/null
-# Copyright 2013 VMware, Inc. 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.
-#
-
-from sqlalchemy.orm import exc
-
-from neutron.api.v2 import attributes
-from neutron.db import db_base_plugin_v2
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.plugins.vmware.extensions import maclearning as mac
-
-LOG = logging.getLogger(__name__)
-
-
-class MacLearningDbMixin(object):
- """Mixin class for mac learning."""
-
- def _make_mac_learning_state_dict(self, port, fields=None):
- res = {'port_id': port['port_id'],
- mac.MAC_LEARNING: port[mac.MAC_LEARNING]}
- return self._fields(res, fields)
-
- def _extend_port_mac_learning_state(self, port_res, port_db):
- state = port_db.mac_learning_state
- if state and state.mac_learning_enabled:
- port_res[mac.MAC_LEARNING] = state.mac_learning_enabled
-
- # Register dict extend functions for ports
- db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
- attributes.PORTS, ['_extend_port_mac_learning_state'])
-
- def _update_mac_learning_state(self, context, port_id, enabled):
- try:
- query = self._model_query(context, nsx_models.MacLearningState)
- state = query.filter(
- nsx_models.MacLearningState.port_id == port_id).one()
- state.update({mac.MAC_LEARNING: enabled})
- except exc.NoResultFound:
- self._create_mac_learning_state(context,
- {'id': port_id,
- mac.MAC_LEARNING: enabled})
-
- def _create_mac_learning_state(self, context, port):
- with context.session.begin(subtransactions=True):
- enabled = port[mac.MAC_LEARNING]
- state = nsx_models.MacLearningState(
- port_id=port['id'],
- mac_learning_enabled=enabled)
- context.session.add(state)
- return self._make_mac_learning_state_dict(state)
+++ /dev/null
-# Copyright 2013 VMware, Inc. 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.
-
-from sqlalchemy.orm import exc as sa_orm_exc
-
-from neutron.api.v2 import attributes
-from neutron.common import exceptions
-from neutron.common import utils
-from neutron.openstack.common import log as logging
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.plugins.vmware.extensions import networkgw
-
-
-LOG = logging.getLogger(__name__)
-DEVICE_OWNER_NET_GW_INTF = 'network:gateway-interface'
-NETWORK_ID = 'network_id'
-SEGMENTATION_TYPE = 'segmentation_type'
-SEGMENTATION_ID = 'segmentation_id'
-ALLOWED_CONNECTION_ATTRIBUTES = set((NETWORK_ID,
- SEGMENTATION_TYPE,
- SEGMENTATION_ID))
-# Constants for gateway device operational status
-STATUS_UNKNOWN = "UNKNOWN"
-STATUS_ERROR = "ERROR"
-STATUS_ACTIVE = "ACTIVE"
-STATUS_DOWN = "DOWN"
-
-
-class GatewayInUse(exceptions.InUse):
- message = _("Network Gateway '%(gateway_id)s' still has active mappings "
- "with one or more neutron networks.")
-
-
-class GatewayNotFound(exceptions.NotFound):
- message = _("Network Gateway %(gateway_id)s could not be found")
-
-
-class GatewayDeviceInUse(exceptions.InUse):
- message = _("Network Gateway Device '%(device_id)s' is still used by "
- "one or more network gateways.")
-
-
-class GatewayDeviceNotFound(exceptions.NotFound):
- message = _("Network Gateway Device %(device_id)s could not be found.")
-
-
-class GatewayDevicesNotFound(exceptions.NotFound):
- message = _("One or more Network Gateway Devices could not be found: "
- "%(device_ids)s.")
-
-
-class NetworkGatewayPortInUse(exceptions.InUse):
- message = _("Port '%(port_id)s' is owned by '%(device_owner)s' and "
- "therefore cannot be deleted directly via the port API.")
-
-
-class GatewayConnectionInUse(exceptions.InUse):
- message = _("The specified mapping '%(mapping)s' is already in use on "
- "network gateway '%(gateway_id)s'.")
-
-
-class MultipleGatewayConnections(exceptions.Conflict):
- message = _("Multiple network connections found on '%(gateway_id)s' "
- "with provided criteria.")
-
-
-class GatewayConnectionNotFound(exceptions.NotFound):
- message = _("The connection %(network_mapping_info)s was not found on the "
- "network gateway '%(network_gateway_id)s'")
-
-
-class NetworkGatewayUnchangeable(exceptions.InUse):
- message = _("The network gateway %(gateway_id)s "
- "cannot be updated or deleted")
-
-
-class NetworkGatewayMixin(networkgw.NetworkGatewayPluginBase):
-
- gateway_resource = networkgw.GATEWAY_RESOURCE_NAME
- device_resource = networkgw.DEVICE_RESOURCE_NAME
-
- def _get_network_gateway(self, context, gw_id):
- try:
- gw = self._get_by_id(context, nsx_models.NetworkGateway, gw_id)
- except sa_orm_exc.NoResultFound:
- raise GatewayNotFound(gateway_id=gw_id)
- return gw
-
- def _make_gw_connection_dict(self, gw_conn):
- return {'port_id': gw_conn['port_id'],
- 'segmentation_type': gw_conn['segmentation_type'],
- 'segmentation_id': gw_conn['segmentation_id']}
-
- def _make_network_gateway_dict(self, network_gateway, fields=None):
- device_list = []
- for d in network_gateway['devices']:
- device_list.append({'id': d['id'],
- 'interface_name': d['interface_name']})
- res = {'id': network_gateway['id'],
- 'name': network_gateway['name'],
- 'default': network_gateway['default'],
- 'devices': device_list,
- 'tenant_id': network_gateway['tenant_id']}
- # Query gateway connections only if needed
- if not fields or 'ports' in fields:
- res['ports'] = [self._make_gw_connection_dict(conn)
- for conn in network_gateway.network_connections]
- return self._fields(res, fields)
-
- def _set_mapping_info_defaults(self, mapping_info):
- if not mapping_info.get('segmentation_type'):
- mapping_info['segmentation_type'] = 'flat'
- if not mapping_info.get('segmentation_id'):
- mapping_info['segmentation_id'] = 0
-
- def _validate_network_mapping_info(self, network_mapping_info):
- self._set_mapping_info_defaults(network_mapping_info)
- network_id = network_mapping_info.get(NETWORK_ID)
- if not network_id:
- raise exceptions.InvalidInput(
- error_message=_("A network identifier must be specified "
- "when connecting a network to a network "
- "gateway. Unable to complete operation"))
- connection_attrs = set(network_mapping_info.keys())
- if not connection_attrs.issubset(ALLOWED_CONNECTION_ATTRIBUTES):
- raise exceptions.InvalidInput(
- error_message=(_("Invalid keys found among the ones provided "
- "in request body: %(connection_attrs)s."),
- connection_attrs))
- seg_type = network_mapping_info.get(SEGMENTATION_TYPE)
- seg_id = network_mapping_info.get(SEGMENTATION_ID)
- # The NSX plugin accepts 0 as a valid vlan tag
- seg_id_valid = seg_id == 0 or utils.is_valid_vlan_tag(seg_id)
- if seg_type.lower() == 'flat' and seg_id:
- msg = _("Cannot specify a segmentation id when "
- "the segmentation type is flat")
- raise exceptions.InvalidInput(error_message=msg)
- elif (seg_type.lower() == 'vlan' and not seg_id_valid):
- msg = _("Invalid segmentation id (%d) for "
- "vlan segmentation type") % seg_id
- raise exceptions.InvalidInput(error_message=msg)
- return network_id
-
- def _retrieve_gateway_connections(self, context, gateway_id,
- mapping_info={}, only_one=False):
- filters = {'network_gateway_id': [gateway_id]}
- for k, v in mapping_info.iteritems():
- if v and k != NETWORK_ID:
- filters[k] = [v]
- query = self._get_collection_query(context,
- nsx_models.NetworkConnection,
- filters)
- return query.one() if only_one else query.all()
-
- def _unset_default_network_gateways(self, context):
- with context.session.begin(subtransactions=True):
- context.session.query(nsx_models.NetworkGateway).update(
- {nsx_models.NetworkGateway.default: False})
-
- def _set_default_network_gateway(self, context, gw_id):
- with context.session.begin(subtransactions=True):
- gw = (context.session.query(nsx_models.NetworkGateway).
- filter_by(id=gw_id).one())
- gw['default'] = True
-
- def prevent_network_gateway_port_deletion(self, context, port):
- """Pre-deletion check.
-
- Ensures a port will not be deleted if is being used by a network
- gateway. In that case an exception will be raised.
- """
- if port['device_owner'] == DEVICE_OWNER_NET_GW_INTF:
- raise NetworkGatewayPortInUse(port_id=port['id'],
- device_owner=port['device_owner'])
-
- def _validate_device_list(self, context, tenant_id, gateway_data):
- device_query = self._query_gateway_devices(
- context, filters={'id': [device['id']
- for device in gateway_data['devices']]})
- retrieved_device_ids = set()
- for device in device_query:
- retrieved_device_ids.add(device['id'])
- if device['tenant_id'] != tenant_id:
- raise GatewayDeviceNotFound(device_id=device['id'])
- missing_device_ids = (
- set(device['id'] for device in gateway_data['devices']) -
- retrieved_device_ids)
- if missing_device_ids:
- raise GatewayDevicesNotFound(
- device_ids=",".join(missing_device_ids))
-
- def create_network_gateway(self, context, network_gateway,
- validate_device_list=True):
- gw_data = network_gateway[self.gateway_resource]
- tenant_id = self._get_tenant_id_for_create(context, gw_data)
- with context.session.begin(subtransactions=True):
- gw_db = nsx_models.NetworkGateway(
- id=gw_data.get('id', uuidutils.generate_uuid()),
- tenant_id=tenant_id,
- name=gw_data.get('name'))
- # Device list is guaranteed to be a valid list, but some devices
- # might still either not exist or belong to a different tenant
- if validate_device_list:
- self._validate_device_list(context, tenant_id, gw_data)
- gw_db.devices.extend(
- [nsx_models.NetworkGatewayDeviceReference(**device)
- for device in gw_data['devices']])
- context.session.add(gw_db)
- LOG.debug("Created network gateway with id:%s", gw_db['id'])
- return self._make_network_gateway_dict(gw_db)
-
- def update_network_gateway(self, context, id, network_gateway):
- gw_data = network_gateway[self.gateway_resource]
- with context.session.begin(subtransactions=True):
- gw_db = self._get_network_gateway(context, id)
- if gw_db.default:
- raise NetworkGatewayUnchangeable(gateway_id=id)
- # Ensure there is something to update before doing it
- if any([gw_db[k] != gw_data[k] for k in gw_data]):
- gw_db.update(gw_data)
- LOG.debug("Updated network gateway with id:%s", id)
- return self._make_network_gateway_dict(gw_db)
-
- def get_network_gateway(self, context, id, fields=None):
- gw_db = self._get_network_gateway(context, id)
- return self._make_network_gateway_dict(gw_db, fields)
-
- def delete_network_gateway(self, context, id):
- with context.session.begin(subtransactions=True):
- gw_db = self._get_network_gateway(context, id)
- if gw_db.network_connections:
- raise GatewayInUse(gateway_id=id)
- if gw_db.default:
- raise NetworkGatewayUnchangeable(gateway_id=id)
- context.session.delete(gw_db)
- LOG.debug("Network gateway '%s' was destroyed.", id)
-
- def get_network_gateways(self, context, filters=None, fields=None,
- sorts=None, limit=None, marker=None,
- page_reverse=False):
- marker_obj = self._get_marker_obj(
- context, 'network_gateway', limit, marker)
- return self._get_collection(context, nsx_models.NetworkGateway,
- self._make_network_gateway_dict,
- filters=filters, fields=fields,
- sorts=sorts, limit=limit,
- marker_obj=marker_obj,
- page_reverse=page_reverse)
-
- def connect_network(self, context, network_gateway_id,
- network_mapping_info):
- network_id = self._validate_network_mapping_info(network_mapping_info)
- LOG.debug("Connecting network '%(network_id)s' to gateway "
- "'%(network_gateway_id)s'",
- {'network_id': network_id,
- 'network_gateway_id': network_gateway_id})
- with context.session.begin(subtransactions=True):
- gw_db = self._get_network_gateway(context, network_gateway_id)
- tenant_id = self._get_tenant_id_for_create(context, gw_db)
- # TODO(salvatore-orlando): Leverage unique constraint instead
- # of performing another query!
- if self._retrieve_gateway_connections(context,
- network_gateway_id,
- network_mapping_info):
- raise GatewayConnectionInUse(mapping=network_mapping_info,
- gateway_id=network_gateway_id)
- # TODO(salvatore-orlando): Creating a port will give it an IP,
- # but we actually do not need any. Instead of wasting an IP we
- # should have a way to say a port shall not be associated with
- # any subnet
- try:
- # We pass the segmentation type and id too - the plugin
- # might find them useful as the network connection object
- # does not exist yet.
- # NOTE: they're not extended attributes, rather extra data
- # passed in the port structure to the plugin
- # TODO(salvatore-orlando): Verify optimal solution for
- # ownership of the gateway port
- port = self.create_port(context, {
- 'port':
- {'tenant_id': tenant_id,
- 'network_id': network_id,
- 'mac_address': attributes.ATTR_NOT_SPECIFIED,
- 'admin_state_up': True,
- 'fixed_ips': [],
- 'device_id': network_gateway_id,
- 'device_owner': DEVICE_OWNER_NET_GW_INTF,
- 'name': '',
- 'gw:segmentation_type':
- network_mapping_info.get('segmentation_type'),
- 'gw:segmentation_id':
- network_mapping_info.get('segmentation_id')}})
- except exceptions.NetworkNotFound:
- err_msg = (_("Requested network '%(network_id)s' not found."
- "Unable to create network connection on "
- "gateway '%(network_gateway_id)s") %
- {'network_id': network_id,
- 'network_gateway_id': network_gateway_id})
- LOG.error(err_msg)
- raise exceptions.InvalidInput(error_message=err_msg)
- port_id = port['id']
- LOG.debug("Gateway port for '%(network_gateway_id)s' "
- "created on network '%(network_id)s':%(port_id)s",
- {'network_gateway_id': network_gateway_id,
- 'network_id': network_id,
- 'port_id': port_id})
- # Create NetworkConnection record
- network_mapping_info['port_id'] = port_id
- network_mapping_info['tenant_id'] = tenant_id
- gw_db.network_connections.append(
- nsx_models.NetworkConnection(**network_mapping_info))
- port_id = port['id']
- # now deallocate and recycle ip from the port
- for fixed_ip in port.get('fixed_ips', []):
- self._delete_ip_allocation(context, network_id,
- fixed_ip['subnet_id'],
- fixed_ip['ip_address'])
- LOG.debug("Ensured no Ip addresses are configured on port %s",
- port_id)
- return {'connection_info':
- {'network_gateway_id': network_gateway_id,
- 'network_id': network_id,
- 'port_id': port_id}}
-
- def disconnect_network(self, context, network_gateway_id,
- network_mapping_info):
- network_id = self._validate_network_mapping_info(network_mapping_info)
- LOG.debug("Disconnecting network '%(network_id)s' from gateway "
- "'%(network_gateway_id)s'",
- {'network_id': network_id,
- 'network_gateway_id': network_gateway_id})
- with context.session.begin(subtransactions=True):
- # Uniquely identify connection, otherwise raise
- try:
- net_connection = self._retrieve_gateway_connections(
- context, network_gateway_id,
- network_mapping_info, only_one=True)
- except sa_orm_exc.NoResultFound:
- raise GatewayConnectionNotFound(
- network_mapping_info=network_mapping_info,
- network_gateway_id=network_gateway_id)
- except sa_orm_exc.MultipleResultsFound:
- raise MultipleGatewayConnections(
- gateway_id=network_gateway_id)
- # Remove gateway port from network
- # FIXME(salvatore-orlando): Ensure state of port in NSX is
- # consistent with outcome of transaction
- self.delete_port(context, net_connection['port_id'],
- nw_gw_port_check=False)
- # Remove NetworkConnection record
- context.session.delete(net_connection)
-
- def _make_gateway_device_dict(self, gateway_device, fields=None,
- include_nsx_id=False):
- res = {'id': gateway_device['id'],
- 'name': gateway_device['name'],
- 'status': gateway_device['status'],
- 'connector_type': gateway_device['connector_type'],
- 'connector_ip': gateway_device['connector_ip'],
- 'tenant_id': gateway_device['tenant_id']}
- if include_nsx_id:
- # Return the NSX mapping as well. This attribute will not be
- # returned in the API response anyway. Ensure it will not be
- # filtered out in field selection.
- if fields:
- fields.append('nsx_id')
- res['nsx_id'] = gateway_device['nsx_id']
- return self._fields(res, fields)
-
- def _get_gateway_device(self, context, device_id):
- try:
- return self._get_by_id(context,
- nsx_models.NetworkGatewayDevice,
- device_id)
- except sa_orm_exc.NoResultFound:
- raise GatewayDeviceNotFound(device_id=device_id)
-
- def _is_device_in_use(self, context, device_id):
- query = self._get_collection_query(
- context, nsx_models.NetworkGatewayDeviceReference,
- {'id': [device_id]})
- return query.first()
-
- def get_gateway_device(self, context, device_id, fields=None,
- include_nsx_id=False):
- return self._make_gateway_device_dict(
- self._get_gateway_device(context, device_id),
- fields, include_nsx_id)
-
- def _query_gateway_devices(self, context,
- filters=None, sorts=None,
- limit=None, marker=None,
- page_reverse=None):
- marker_obj = self._get_marker_obj(
- context, 'gateway_device', limit, marker)
- return self._get_collection_query(context,
- nsx_models.NetworkGatewayDevice,
- filters=filters,
- sorts=sorts,
- limit=limit,
- marker_obj=marker_obj,
- page_reverse=page_reverse)
-
- def get_gateway_devices(self, context, filters=None, fields=None,
- sorts=None, limit=None, marker=None,
- page_reverse=False, include_nsx_id=False):
- query = self._query_gateway_devices(context, filters, sorts, limit,
- marker, page_reverse)
- return [self._make_gateway_device_dict(row, fields, include_nsx_id)
- for row in query]
-
- def create_gateway_device(self, context, gateway_device,
- initial_status=STATUS_UNKNOWN):
- device_data = gateway_device[self.device_resource]
- tenant_id = self._get_tenant_id_for_create(context, device_data)
- with context.session.begin(subtransactions=True):
- device_db = nsx_models.NetworkGatewayDevice(
- id=device_data.get('id', uuidutils.generate_uuid()),
- tenant_id=tenant_id,
- name=device_data.get('name'),
- connector_type=device_data['connector_type'],
- connector_ip=device_data['connector_ip'],
- status=initial_status)
- context.session.add(device_db)
- LOG.debug("Created network gateway device: %s", device_db['id'])
- return self._make_gateway_device_dict(device_db)
-
- def update_gateway_device(self, context, gateway_device_id,
- gateway_device, include_nsx_id=False):
- device_data = gateway_device[self.device_resource]
- with context.session.begin(subtransactions=True):
- device_db = self._get_gateway_device(context, gateway_device_id)
- # Ensure there is something to update before doing it
- if any([device_db[k] != device_data[k] for k in device_data]):
- device_db.update(device_data)
- LOG.debug("Updated network gateway device: %s",
- gateway_device_id)
- return self._make_gateway_device_dict(
- device_db, include_nsx_id=include_nsx_id)
-
- def delete_gateway_device(self, context, device_id):
- with context.session.begin(subtransactions=True):
- # A gateway device should not be deleted
- # if it is used in any network gateway service
- if self._is_device_in_use(context, device_id):
- raise GatewayDeviceInUse(device_id=device_id)
- device_db = self._get_gateway_device(context, device_id)
- context.session.delete(device_db)
- LOG.debug("Deleted network gateway device: %s.", device_id)
+++ /dev/null
-# Copyright 2013 VMware, Inc. 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.
-#
-
-from sqlalchemy.orm import exc
-
-from neutron.api.v2 import attributes as attr
-from neutron.db import db_base_plugin_v2
-from neutron.db import models_v2
-from neutron.i18n import _LI
-from neutron.openstack.common import log
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.plugins.vmware.extensions import qos
-
-
-LOG = log.getLogger(__name__)
-
-
-class QoSDbMixin(qos.QueuePluginBase):
- """Mixin class to add queues."""
-
- def create_qos_queue(self, context, qos_queue):
- q = qos_queue['qos_queue']
- with context.session.begin(subtransactions=True):
- qos_queue = nsx_models.QoSQueue(
- id=q.get('id', uuidutils.generate_uuid()),
- name=q.get('name'),
- tenant_id=q['tenant_id'],
- default=q.get('default'),
- min=q.get('min'),
- max=q.get('max'),
- qos_marking=q.get('qos_marking'),
- dscp=q.get('dscp'))
- context.session.add(qos_queue)
- return self._make_qos_queue_dict(qos_queue)
-
- def get_qos_queue(self, context, queue_id, fields=None):
- return self._make_qos_queue_dict(
- self._get_qos_queue(context, queue_id), fields)
-
- def _get_qos_queue(self, context, queue_id):
- try:
- return self._get_by_id(context, nsx_models.QoSQueue, queue_id)
- except exc.NoResultFound:
- raise qos.QueueNotFound(id=queue_id)
-
- def get_qos_queues(self, context, filters=None, fields=None, sorts=None,
- limit=None, marker=None, page_reverse=False):
- marker_obj = self._get_marker_obj(context, 'qos_queue', limit, marker)
- return self._get_collection(context, nsx_models.QoSQueue,
- self._make_qos_queue_dict,
- filters=filters, fields=fields,
- sorts=sorts, limit=limit,
- marker_obj=marker_obj,
- page_reverse=page_reverse)
-
- def delete_qos_queue(self, context, queue_id):
- qos_queue = self._get_qos_queue(context, queue_id)
- with context.session.begin(subtransactions=True):
- context.session.delete(qos_queue)
-
- def _process_port_queue_mapping(self, context, port_data, queue_id):
- port_data[qos.QUEUE] = queue_id
- if not queue_id:
- return
- with context.session.begin(subtransactions=True):
- context.session.add(nsx_models.PortQueueMapping(
- port_id=port_data['id'],
- queue_id=queue_id))
-
- def _get_port_queue_bindings(self, context, filters=None, fields=None):
- return self._get_collection(context, nsx_models.PortQueueMapping,
- self._make_port_queue_binding_dict,
- filters=filters, fields=fields)
-
- def _delete_port_queue_mapping(self, context, port_id):
- query = self._model_query(context, nsx_models.PortQueueMapping)
- try:
- binding = query.filter(
- nsx_models.PortQueueMapping.port_id == port_id).one()
- except exc.NoResultFound:
- # return since this can happen if we are updating a port that
- # did not already have a queue on it. There is no need to check
- # if there is one before deleting if we return here.
- return
- with context.session.begin(subtransactions=True):
- context.session.delete(binding)
-
- def _process_network_queue_mapping(self, context, net_data, queue_id):
- net_data[qos.QUEUE] = queue_id
- if not queue_id:
- return
- with context.session.begin(subtransactions=True):
- context.session.add(
- nsx_models.NetworkQueueMapping(network_id=net_data['id'],
- queue_id=queue_id))
-
- def _get_network_queue_bindings(self, context, filters=None, fields=None):
- return self._get_collection(context, nsx_models.NetworkQueueMapping,
- self._make_network_queue_binding_dict,
- filters=filters, fields=fields)
-
- def _delete_network_queue_mapping(self, context, network_id):
- query = self._model_query(context, nsx_models.NetworkQueueMapping)
- with context.session.begin(subtransactions=True):
- binding = query.filter_by(network_id=network_id).first()
- if binding:
- context.session.delete(binding)
-
- def _extend_dict_qos_queue(self, obj_res, obj_db):
- queue_mapping = obj_db['qos_queue']
- if queue_mapping:
- obj_res[qos.QUEUE] = queue_mapping.get('queue_id')
- return obj_res
-
- def _extend_port_dict_qos_queue(self, port_res, port_db):
- self._extend_dict_qos_queue(port_res, port_db)
-
- def _extend_network_dict_qos_queue(self, network_res, network_db):
- self._extend_dict_qos_queue(network_res, network_db)
-
- # Register dict extend functions for networks and ports
- db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
- attr.NETWORKS, ['_extend_network_dict_qos_queue'])
- db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
- attr.PORTS, ['_extend_port_dict_qos_queue'])
-
- def _make_qos_queue_dict(self, queue, fields=None):
- res = {'id': queue['id'],
- 'name': queue.get('name'),
- 'default': queue.get('default'),
- 'tenant_id': queue['tenant_id'],
- 'min': queue.get('min'),
- 'max': queue.get('max'),
- 'qos_marking': queue.get('qos_marking'),
- 'dscp': queue.get('dscp')}
- return self._fields(res, fields)
-
- def _make_port_queue_binding_dict(self, queue, fields=None):
- res = {'port_id': queue['port_id'],
- 'queue_id': queue['queue_id']}
- return self._fields(res, fields)
-
- def _make_network_queue_binding_dict(self, queue, fields=None):
- res = {'network_id': queue['network_id'],
- 'queue_id': queue['queue_id']}
- return self._fields(res, fields)
-
- def _check_for_queue_and_create(self, context, port):
- """Check for queue and create.
-
- This function determines if a port should be associated with a
- queue. It works by first querying NetworkQueueMapping to determine
- if the network is associated with a queue. If so, then it queries
- NetworkQueueMapping for all the networks that are associated with
- this queue. Next, it queries against all the ports on these networks
- with the port device_id. Finally it queries PortQueueMapping. If that
- query returns a queue_id that is returned. Otherwise a queue is
- created that is the size of the queue associated with the network and
- that queue_id is returned.
-
- If the network is not associated with a queue we then query to see
- if there is a default queue in the system. If so, a copy of that is
- created and the queue_id is returned.
-
- Otherwise None is returned. None is also returned if the port does not
- have a device_id or if the device_owner is network:
- """
-
- queue_to_create = None
- # If there is no device_id don't create a queue. The queue will be
- # created on update port when the device_id is present. Also don't
- # apply QoS to network ports.
- if (not port.get('device_id') or
- port['device_owner'].startswith('network:')):
- return
-
- # Check if there is a queue associated with the network
- filters = {'network_id': [port['network_id']]}
- network_queue_id = self._get_network_queue_bindings(
- context, filters, ['queue_id'])
- if network_queue_id:
- # get networks that queue is associated with
- filters = {'queue_id': [network_queue_id[0]['queue_id']]}
- networks_with_same_queue = self._get_network_queue_bindings(
- context, filters)
-
- # get the ports on these networks with the same_queue and device_id
- filters = {'device_id': [port.get('device_id')],
- 'network_id': [network['network_id'] for
- network in networks_with_same_queue]}
- query = self._model_query(context, models_v2.Port.id)
- query = self._apply_filters_to_query(query, models_v2.Port,
- filters)
- ports_ids = [p[0] for p in query]
- if ports_ids:
- # shared queue already exists find the queue id
- queues = self._get_port_queue_bindings(context,
- {'port_id': ports_ids},
- ['queue_id'])
- if queues:
- return queues[0]['queue_id']
-
- # get the size of the queue we want to create
- queue_to_create = self._get_qos_queue(
- context, network_queue_id[0]['queue_id'])
-
- else:
- # check for default queue
- filters = {'default': [True]}
- # context is elevated since default queue is owned by admin
- queue_to_create = self.get_qos_queues(context.elevated(), filters)
- if not queue_to_create:
- return
- queue_to_create = queue_to_create[0]
-
- # create the queue
- tenant_id = self._get_tenant_id_for_create(context, port)
- if port.get(qos.RXTX_FACTOR) and queue_to_create.get('max'):
- queue_to_create['max'] *= int(port[qos.RXTX_FACTOR])
- queue = {'qos_queue': {'name': queue_to_create.get('name'),
- 'min': queue_to_create.get('min'),
- 'max': queue_to_create.get('max'),
- 'dscp': queue_to_create.get('dscp'),
- 'qos_marking':
- queue_to_create.get('qos_marking'),
- 'tenant_id': tenant_id}}
- return self.create_qos_queue(context, queue, False)['id']
-
- def _validate_qos_queue(self, context, qos_queue):
- if qos_queue.get('default'):
- if context.is_admin:
- if self.get_qos_queues(context, filters={'default': [True]}):
- raise qos.DefaultQueueAlreadyExists()
- else:
- raise qos.DefaultQueueCreateNotAdmin()
- if qos_queue.get('qos_marking') == 'trusted':
- dscp = qos_queue.pop('dscp')
- if dscp:
- # must raise because a non-zero dscp was provided
- raise qos.QueueInvalidMarking()
- LOG.info(_LI("DSCP value (%s) will be ignored with 'trusted' "
- "marking"), dscp)
- max = qos_queue.get('max')
- min = qos_queue.get('min')
- # Max can be None
- if max and min > max:
- raise qos.QueueMinGreaterMax()
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-#
-# 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.
-
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.dbexts import vcns_models
-
-LOG = logging.getLogger(__name__)
-
-
-def add_vcns_router_binding(session, router_id, vse_id, lswitch_id, status):
- with session.begin(subtransactions=True):
- binding = vcns_models.VcnsRouterBinding(
- router_id=router_id,
- edge_id=vse_id,
- lswitch_id=lswitch_id,
- status=status)
- session.add(binding)
- return binding
-
-
-def get_vcns_router_binding(session, router_id):
- with session.begin(subtransactions=True):
- return (session.query(vcns_models.VcnsRouterBinding).
- filter_by(router_id=router_id).first())
-
-
-def update_vcns_router_binding(session, router_id, **kwargs):
- with session.begin(subtransactions=True):
- binding = (session.query(vcns_models.VcnsRouterBinding).
- filter_by(router_id=router_id).one())
- for key, value in kwargs.iteritems():
- binding[key] = value
-
-
-def delete_vcns_router_binding(session, router_id):
- with session.begin(subtransactions=True):
- binding = (session.query(vcns_models.VcnsRouterBinding).
- filter_by(router_id=router_id).one())
- session.delete(binding)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-
-from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
-from neutron.common import constants as const
-from neutron.common import topics
-from neutron.plugins.vmware.dhcp_meta import nsx as nsx_svc
-from neutron.plugins.vmware.dhcp_meta import rpc as nsx_rpc
-
-
-class DhcpAgentNotifyAPI(dhcp_rpc_agent_api.DhcpAgentNotifyAPI):
-
- def __init__(self, plugin, manager):
- super(DhcpAgentNotifyAPI, self).__init__(topic=topics.DHCP_AGENT)
- self.agentless_notifier = nsx_svc.DhcpAgentNotifyAPI(plugin, manager)
-
- def notify(self, context, data, methodname):
- [resource, action, _e] = methodname.split('.')
- lsn_manager = self.agentless_notifier.plugin.lsn_manager
- plugin = self.agentless_notifier.plugin
- if resource == 'network':
- net_id = data['network']['id']
- elif resource in ['port', 'subnet']:
- net_id = data[resource]['network_id']
- else:
- # no valid resource
- return
- lsn_exists = lsn_manager.lsn_exists(context, net_id)
- treat_dhcp_owner_specially = False
- if lsn_exists:
- # if lsn exists, the network is one created with the new model
- if (resource == 'subnet' and action == 'create' and
- const.DEVICE_OWNER_DHCP not in plugin.port_special_owners):
- # network/subnet provisioned in the new model have a plain
- # nsx lswitch port, no vif attachment
- plugin.port_special_owners.append(const.DEVICE_OWNER_DHCP)
- treat_dhcp_owner_specially = True
- if (resource == 'port' and action == 'update' or
- resource == 'subnet'):
- self.agentless_notifier.notify(context, data, methodname)
- elif not lsn_exists and resource in ['port', 'subnet']:
- # call notifier for the agent-based mode
- super(DhcpAgentNotifyAPI, self).notify(context, data, methodname)
- if treat_dhcp_owner_specially:
- # if subnets belong to networks created with the old model
- # dhcp port does not need to be special cased, so put things
- # back, since they were modified
- plugin.port_special_owners.remove(const.DEVICE_OWNER_DHCP)
-
-
-def handle_network_dhcp_access(plugin, context, network, action):
- nsx_svc.handle_network_dhcp_access(plugin, context, network, action)
-
-
-def handle_port_dhcp_access(plugin, context, port, action):
- if plugin.lsn_manager.lsn_exists(context, port['network_id']):
- nsx_svc.handle_port_dhcp_access(plugin, context, port, action)
- else:
- nsx_rpc.handle_port_dhcp_access(plugin, context, port, action)
-
-
-def handle_port_metadata_access(plugin, context, port, is_delete=False):
- if plugin.lsn_manager.lsn_exists(context, port['network_id']):
- nsx_svc.handle_port_metadata_access(plugin, context, port, is_delete)
- else:
- nsx_rpc.handle_port_metadata_access(plugin, context, port, is_delete)
-
-
-def handle_router_metadata_access(plugin, context, router_id, interface=None):
- if interface:
- subnet = plugin.get_subnet(context, interface['subnet_id'])
- network_id = subnet['network_id']
- if plugin.lsn_manager.lsn_exists(context, network_id):
- nsx_svc.handle_router_metadata_access(
- plugin, context, router_id, interface)
- else:
- nsx_rpc.handle_router_metadata_access(
- plugin, context, router_id, interface)
- else:
- nsx_rpc.handle_router_metadata_access(
- plugin, context, router_id, interface)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-from neutron.common import constants as const
-from neutron.db import l3_db
-
-# A unique MAC to quickly identify the LSN port used for metadata services
-# when dhcp on the subnet is off. Inspired by leet-speak for 'metadata'.
-METADATA_MAC = "fa:15:73:74:d4:74"
-METADATA_PORT_ID = 'metadata:id'
-METADATA_PORT_NAME = 'metadata:name'
-METADATA_DEVICE_ID = 'metadata:device'
-SPECIAL_OWNERS = (const.DEVICE_OWNER_DHCP,
- const.DEVICE_OWNER_ROUTER_GW,
- l3_db.DEVICE_OWNER_ROUTER_INTF)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-
-from oslo_config import cfg
-from oslo_db import exception as db_exc
-from oslo_utils import excutils
-
-from neutron.common import exceptions as n_exc
-from neutron.i18n import _LE, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as p_exc
-from neutron.plugins.vmware.common import nsx_utils
-from neutron.plugins.vmware.dbexts import lsn_db
-from neutron.plugins.vmware.dhcp_meta import constants as const
-from neutron.plugins.vmware.nsxlib import lsn as lsn_api
-from neutron.plugins.vmware.nsxlib import switch as switch_api
-
-LOG = logging.getLogger(__name__)
-
-META_CONF = 'metadata-proxy'
-DHCP_CONF = 'dhcp'
-
-
-lsn_opts = [
- cfg.BoolOpt('sync_on_missing_data', default=False,
- help=_('Pull LSN information from NSX in case it is missing '
- 'from the local data store. This is useful to rebuild '
- 'the local store in case of server recovery.'))
-]
-
-
-def register_lsn_opts(config):
- config.CONF.register_opts(lsn_opts, "NSX_LSN")
-
-
-class LsnManager(object):
- """Manage LSN entities associated with networks."""
-
- def __init__(self, plugin):
- self.plugin = plugin
-
- @property
- def cluster(self):
- return self.plugin.cluster
-
- def lsn_exists(self, context, network_id):
- """Return True if a Logical Service Node exists for the network."""
- return self.lsn_get(
- context, network_id, raise_on_err=False) is not None
-
- def lsn_get(self, context, network_id, raise_on_err=True):
- """Retrieve the LSN id associated to the network."""
- try:
- return lsn_api.lsn_for_network_get(self.cluster, network_id)
- except (n_exc.NotFound, api_exc.NsxApiException):
- if raise_on_err:
- LOG.error(_LE('Unable to find Logical Service Node for '
- 'network %s.'),
- network_id)
- raise p_exc.LsnNotFound(entity='network',
- entity_id=network_id)
- else:
- LOG.warn(_LW('Unable to find Logical Service Node for '
- 'the requested network %s.'),
- network_id)
-
- def lsn_create(self, context, network_id):
- """Create a LSN associated to the network."""
- try:
- return lsn_api.lsn_for_network_create(self.cluster, network_id)
- except api_exc.NsxApiException:
- err_msg = _('Unable to create LSN for network %s') % network_id
- raise p_exc.NsxPluginException(err_msg=err_msg)
-
- def lsn_delete(self, context, lsn_id):
- """Delete a LSN given its id."""
- try:
- lsn_api.lsn_delete(self.cluster, lsn_id)
- except (n_exc.NotFound, api_exc.NsxApiException):
- LOG.warn(_LW('Unable to delete Logical Service Node %s'), lsn_id)
-
- def lsn_delete_by_network(self, context, network_id):
- """Delete a LSN associated to the network."""
- lsn_id = self.lsn_get(context, network_id, raise_on_err=False)
- if lsn_id:
- self.lsn_delete(context, lsn_id)
-
- def lsn_port_get(self, context, network_id, subnet_id, raise_on_err=True):
- """Retrieve LSN and LSN port for the network and the subnet."""
- lsn_id = self.lsn_get(context, network_id, raise_on_err=raise_on_err)
- if lsn_id:
- try:
- lsn_port_id = lsn_api.lsn_port_by_subnet_get(
- self.cluster, lsn_id, subnet_id)
- except (n_exc.NotFound, api_exc.NsxApiException):
- if raise_on_err:
- LOG.error(_LE('Unable to find Logical Service Node Port '
- 'for LSN %(lsn_id)s and subnet '
- '%(subnet_id)s'),
- {'lsn_id': lsn_id, 'subnet_id': subnet_id})
- raise p_exc.LsnPortNotFound(lsn_id=lsn_id,
- entity='subnet',
- entity_id=subnet_id)
- else:
- LOG.warn(_LW('Unable to find Logical Service Node Port '
- 'for LSN %(lsn_id)s and subnet '
- '%(subnet_id)s'),
- {'lsn_id': lsn_id, 'subnet_id': subnet_id})
- return (lsn_id, None)
- else:
- return (lsn_id, lsn_port_id)
- else:
- return (None, None)
-
- def lsn_port_get_by_mac(self, context, network_id, mac, raise_on_err=True):
- """Retrieve LSN and LSN port given network and mac address."""
- lsn_id = self.lsn_get(context, network_id, raise_on_err=raise_on_err)
- if lsn_id:
- try:
- lsn_port_id = lsn_api.lsn_port_by_mac_get(
- self.cluster, lsn_id, mac)
- except (n_exc.NotFound, api_exc.NsxApiException):
- if raise_on_err:
- LOG.error(_LE('Unable to find Logical Service Node Port '
- 'for LSN %(lsn_id)s and mac address '
- '%(mac)s'),
- {'lsn_id': lsn_id, 'mac': mac})
- raise p_exc.LsnPortNotFound(lsn_id=lsn_id,
- entity='MAC',
- entity_id=mac)
- else:
- LOG.warn(_LW('Unable to find Logical Service Node '
- 'Port for LSN %(lsn_id)s and mac address '
- '%(mac)s'),
- {'lsn_id': lsn_id, 'mac': mac})
- return (lsn_id, None)
- else:
- return (lsn_id, lsn_port_id)
- else:
- return (None, None)
-
- def lsn_port_create(self, context, lsn_id, subnet_info):
- """Create and return LSN port for associated subnet."""
- try:
- return lsn_api.lsn_port_create(self.cluster, lsn_id, subnet_info)
- except n_exc.NotFound:
- raise p_exc.LsnNotFound(entity='', entity_id=lsn_id)
- except api_exc.NsxApiException:
- err_msg = _('Unable to create port for LSN %s') % lsn_id
- raise p_exc.NsxPluginException(err_msg=err_msg)
-
- def lsn_port_delete(self, context, lsn_id, lsn_port_id):
- """Delete a LSN port from the Logical Service Node."""
- try:
- lsn_api.lsn_port_delete(self.cluster, lsn_id, lsn_port_id)
- except (n_exc.NotFound, api_exc.NsxApiException):
- LOG.warn(_LW('Unable to delete LSN Port %s'), lsn_port_id)
-
- def lsn_port_dispose(self, context, network_id, mac_address):
- """Delete a LSN port given the network and the mac address."""
- lsn_id, lsn_port_id = self.lsn_port_get_by_mac(
- context, network_id, mac_address, raise_on_err=False)
- if lsn_port_id:
- self.lsn_port_delete(context, lsn_id, lsn_port_id)
- if mac_address == const.METADATA_MAC:
- try:
- lswitch_port_id = switch_api.get_port_by_neutron_tag(
- self.cluster, network_id,
- const.METADATA_PORT_ID)['uuid']
- switch_api.delete_port(
- self.cluster, network_id, lswitch_port_id)
- except (n_exc.PortNotFoundOnNetwork,
- api_exc.NsxApiException):
- LOG.warn(_LW("Metadata port not found while attempting "
- "to delete it from network %s"), network_id)
- else:
- LOG.warn(_LW("Unable to find Logical Services Node "
- "Port with MAC %s"), mac_address)
-
- def lsn_port_dhcp_setup(
- self, context, network_id, port_id, port_data, subnet_config=None):
- """Connect network to LSN via specified port and port_data."""
- try:
- lsn_id = None
- switch_id = nsx_utils.get_nsx_switch_ids(
- context.session, self.cluster, network_id)[0]
- lswitch_port_id = switch_api.get_port_by_neutron_tag(
- self.cluster, switch_id, port_id)['uuid']
- lsn_id = self.lsn_get(context, network_id)
- lsn_port_id = self.lsn_port_create(context, lsn_id, port_data)
- except (n_exc.NotFound, p_exc.NsxPluginException):
- raise p_exc.PortConfigurationError(
- net_id=network_id, lsn_id=lsn_id, port_id=port_id)
- else:
- try:
- lsn_api.lsn_port_plug_network(
- self.cluster, lsn_id, lsn_port_id, lswitch_port_id)
- except p_exc.LsnConfigurationConflict:
- self.lsn_port_delete(context, lsn_id, lsn_port_id)
- raise p_exc.PortConfigurationError(
- net_id=network_id, lsn_id=lsn_id, port_id=port_id)
- if subnet_config:
- self.lsn_port_dhcp_configure(
- context, lsn_id, lsn_port_id, subnet_config)
- else:
- return (lsn_id, lsn_port_id)
-
- def lsn_port_metadata_setup(self, context, lsn_id, subnet):
- """Connect subnet to specified LSN."""
- data = {
- "mac_address": const.METADATA_MAC,
- "ip_address": subnet['cidr'],
- "subnet_id": subnet['id']
- }
- network_id = subnet['network_id']
- tenant_id = subnet['tenant_id']
- lswitch_port_id = None
- try:
- switch_id = nsx_utils.get_nsx_switch_ids(
- context.session, self.cluster, network_id)[0]
- lswitch_port_id = switch_api.create_lport(
- self.cluster, switch_id, tenant_id,
- const.METADATA_PORT_ID, const.METADATA_PORT_NAME,
- const.METADATA_DEVICE_ID, True)['uuid']
- lsn_port_id = self.lsn_port_create(context, lsn_id, data)
- except (n_exc.NotFound, p_exc.NsxPluginException,
- api_exc.NsxApiException):
- raise p_exc.PortConfigurationError(
- net_id=network_id, lsn_id=lsn_id, port_id=lswitch_port_id)
- else:
- try:
- lsn_api.lsn_port_plug_network(
- self.cluster, lsn_id, lsn_port_id, lswitch_port_id)
- except p_exc.LsnConfigurationConflict:
- self.lsn_port_delete(self.cluster, lsn_id, lsn_port_id)
- switch_api.delete_port(
- self.cluster, network_id, lswitch_port_id)
- raise p_exc.PortConfigurationError(
- net_id=network_id, lsn_id=lsn_id, port_id=lsn_port_id)
-
- def lsn_port_dhcp_configure(self, context, lsn_id, lsn_port_id, subnet):
- """Enable/disable dhcp services with the given config options."""
- is_enabled = subnet["enable_dhcp"]
- dhcp_options = {
- "domain_name": cfg.CONF.NSX_DHCP.domain_name,
- "default_lease_time": cfg.CONF.NSX_DHCP.default_lease_time,
- }
- dns_servers = cfg.CONF.NSX_DHCP.extra_domain_name_servers or []
- dns_servers.extend(subnet["dns_nameservers"])
- if subnet['gateway_ip']:
- dhcp_options["routers"] = subnet["gateway_ip"]
- if dns_servers:
- dhcp_options["domain_name_servers"] = ",".join(dns_servers)
- if subnet["host_routes"]:
- dhcp_options["classless_static_routes"] = (
- ",".join(subnet["host_routes"])
- )
- try:
- lsn_api.lsn_port_dhcp_configure(
- self.cluster, lsn_id, lsn_port_id, is_enabled, dhcp_options)
- except (n_exc.NotFound, api_exc.NsxApiException):
- err_msg = (_('Unable to configure dhcp for Logical Service '
- 'Node %(lsn_id)s and port %(lsn_port_id)s')
- % {'lsn_id': lsn_id, 'lsn_port_id': lsn_port_id})
- LOG.error(err_msg)
- raise p_exc.NsxPluginException(err_msg=err_msg)
-
- def lsn_metadata_configure(self, context, subnet_id, is_enabled):
- """Configure metadata service for the specified subnet."""
- subnet = self.plugin.get_subnet(context, subnet_id)
- network_id = subnet['network_id']
- meta_conf = cfg.CONF.NSX_METADATA
- metadata_options = {
- 'metadata_server_ip': meta_conf.metadata_server_address,
- 'metadata_server_port': meta_conf.metadata_server_port,
- 'metadata_proxy_shared_secret': meta_conf.metadata_shared_secret
- }
- try:
- lsn_id = self.lsn_get(context, network_id)
- lsn_api.lsn_metadata_configure(
- self.cluster, lsn_id, is_enabled, metadata_options)
- except (p_exc.LsnNotFound, api_exc.NsxApiException):
- err_msg = (_('Unable to configure metadata '
- 'for subnet %s') % subnet_id)
- LOG.error(err_msg)
- raise p_exc.NsxPluginException(err_msg=err_msg)
- if is_enabled:
- try:
- # test that the lsn port exists
- self.lsn_port_get(context, network_id, subnet_id)
- except p_exc.LsnPortNotFound:
- # this might happen if subnet had dhcp off when created
- # so create one, and wire it
- self.lsn_port_metadata_setup(context, lsn_id, subnet)
- else:
- self.lsn_port_dispose(context, network_id, const.METADATA_MAC)
-
- def _lsn_port_host_conf(self, context, network_id, subnet_id, data, hdlr):
- lsn_id, lsn_port_id = self.lsn_port_get(
- context, network_id, subnet_id, raise_on_err=False)
- try:
- if lsn_id and lsn_port_id:
- hdlr(self.cluster, lsn_id, lsn_port_id, data)
- except (n_exc.NotFound, api_exc.NsxApiException):
- LOG.error(_LE('Error while configuring LSN '
- 'port %s'), lsn_port_id)
- raise p_exc.PortConfigurationError(
- net_id=network_id, lsn_id=lsn_id, port_id=lsn_port_id)
-
- def lsn_port_dhcp_host_add(self, context, network_id, subnet_id, host):
- """Add dhcp host entry to LSN port configuration."""
- self._lsn_port_host_conf(context, network_id, subnet_id, host,
- lsn_api.lsn_port_dhcp_host_add)
-
- def lsn_port_dhcp_host_remove(self, context, network_id, subnet_id, host):
- """Remove dhcp host entry from LSN port configuration."""
- self._lsn_port_host_conf(context, network_id, subnet_id, host,
- lsn_api.lsn_port_dhcp_host_remove)
-
- def lsn_port_meta_host_add(self, context, network_id, subnet_id, host):
- """Add dhcp host entry to LSN port configuration."""
- self._lsn_port_host_conf(context, network_id, subnet_id, host,
- lsn_api.lsn_port_metadata_host_add)
-
- def lsn_port_meta_host_remove(self, context, network_id, subnet_id, host):
- """Remove dhcp host entry from LSN port configuration."""
- self._lsn_port_host_conf(context, network_id, subnet_id, host,
- lsn_api.lsn_port_metadata_host_remove)
-
- def lsn_port_update(
- self, context, network_id, subnet_id, dhcp=None, meta=None):
- """Update the specified configuration for the LSN port."""
- if not dhcp and not meta:
- return
- try:
- lsn_id, lsn_port_id = self.lsn_port_get(
- context, network_id, subnet_id, raise_on_err=False)
- if dhcp and lsn_id and lsn_port_id:
- lsn_api.lsn_port_host_entries_update(
- self.cluster, lsn_id, lsn_port_id, DHCP_CONF, dhcp)
- if meta and lsn_id and lsn_port_id:
- lsn_api.lsn_port_host_entries_update(
- self.cluster, lsn_id, lsn_port_id, META_CONF, meta)
- except api_exc.NsxApiException:
- raise p_exc.PortConfigurationError(
- net_id=network_id, lsn_id=lsn_id, port_id=lsn_port_id)
-
-
-class PersistentLsnManager(LsnManager):
- """Add local persistent state to LSN Manager."""
-
- def __init__(self, plugin):
- super(PersistentLsnManager, self).__init__(plugin)
- self.sync_on_missing = cfg.CONF.NSX_LSN.sync_on_missing_data
-
- def lsn_get(self, context, network_id, raise_on_err=True):
- try:
- obj = lsn_db.lsn_get_for_network(
- context, network_id, raise_on_err=raise_on_err)
- return obj.lsn_id if obj else None
- except p_exc.LsnNotFound:
- with excutils.save_and_reraise_exception() as ctxt:
- ctxt.reraise = False
- if self.sync_on_missing:
- lsn_id = super(PersistentLsnManager, self).lsn_get(
- context, network_id, raise_on_err=raise_on_err)
- self.lsn_save(context, network_id, lsn_id)
- return lsn_id
- if raise_on_err:
- ctxt.reraise = True
-
- def lsn_save(self, context, network_id, lsn_id):
- """Save LSN-Network mapping to the DB."""
- try:
- lsn_db.lsn_add(context, network_id, lsn_id)
- except db_exc.DBError:
- err_msg = _('Unable to save LSN for network %s') % network_id
- LOG.exception(err_msg)
- raise p_exc.NsxPluginException(err_msg=err_msg)
-
- def lsn_create(self, context, network_id):
- lsn_id = super(PersistentLsnManager,
- self).lsn_create(context, network_id)
- try:
- self.lsn_save(context, network_id, lsn_id)
- except p_exc.NsxPluginException:
- with excutils.save_and_reraise_exception():
- super(PersistentLsnManager, self).lsn_delete(context, lsn_id)
- return lsn_id
-
- def lsn_delete(self, context, lsn_id):
- lsn_db.lsn_remove(context, lsn_id)
- super(PersistentLsnManager, self).lsn_delete(context, lsn_id)
-
- def lsn_port_get(self, context, network_id, subnet_id, raise_on_err=True):
- try:
- obj = lsn_db.lsn_port_get_for_subnet(
- context, subnet_id, raise_on_err=raise_on_err)
- return (obj.lsn_id, obj.lsn_port_id) if obj else (None, None)
- except p_exc.LsnPortNotFound:
- with excutils.save_and_reraise_exception() as ctxt:
- ctxt.reraise = False
- if self.sync_on_missing:
- lsn_id, lsn_port_id = (
- super(PersistentLsnManager, self).lsn_port_get(
- context, network_id, subnet_id,
- raise_on_err=raise_on_err))
- mac_addr = lsn_api.lsn_port_info_get(
- self.cluster, lsn_id, lsn_port_id)['mac_address']
- self.lsn_port_save(
- context, lsn_port_id, subnet_id, mac_addr, lsn_id)
- return (lsn_id, lsn_port_id)
- if raise_on_err:
- ctxt.reraise = True
-
- def lsn_port_get_by_mac(self, context, network_id, mac, raise_on_err=True):
- try:
- obj = lsn_db.lsn_port_get_for_mac(
- context, mac, raise_on_err=raise_on_err)
- return (obj.lsn_id, obj.lsn_port_id) if obj else (None, None)
- except p_exc.LsnPortNotFound:
- with excutils.save_and_reraise_exception() as ctxt:
- ctxt.reraise = False
- if self.sync_on_missing:
- lsn_id, lsn_port_id = (
- super(PersistentLsnManager, self).lsn_port_get_by_mac(
- context, network_id, mac,
- raise_on_err=raise_on_err))
- subnet_id = lsn_api.lsn_port_info_get(
- self.cluster, lsn_id, lsn_port_id).get('subnet_id')
- self.lsn_port_save(
- context, lsn_port_id, subnet_id, mac, lsn_id)
- return (lsn_id, lsn_port_id)
- if raise_on_err:
- ctxt.reraise = True
-
- def lsn_port_save(self, context, lsn_port_id, subnet_id, mac_addr, lsn_id):
- """Save LSN Port information to the DB."""
- try:
- lsn_db.lsn_port_add_for_lsn(
- context, lsn_port_id, subnet_id, mac_addr, lsn_id)
- except db_exc.DBError:
- err_msg = _('Unable to save LSN port for subnet %s') % subnet_id
- LOG.exception(err_msg)
- raise p_exc.NsxPluginException(err_msg=err_msg)
-
- def lsn_port_create(self, context, lsn_id, subnet_info):
- lsn_port_id = super(PersistentLsnManager,
- self).lsn_port_create(context, lsn_id, subnet_info)
- try:
- self.lsn_port_save(context, lsn_port_id, subnet_info['subnet_id'],
- subnet_info['mac_address'], lsn_id)
- except p_exc.NsxPluginException:
- with excutils.save_and_reraise_exception():
- super(PersistentLsnManager, self).lsn_port_delete(
- context, lsn_id, lsn_port_id)
- return lsn_port_id
-
- def lsn_port_delete(self, context, lsn_id, lsn_port_id):
- lsn_db.lsn_port_remove(context, lsn_port_id)
- super(PersistentLsnManager, self).lsn_port_delete(
- context, lsn_id, lsn_port_id)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-
-from neutron.common import constants as const
-from neutron.common import exceptions as n_exc
-from neutron.extensions import external_net
-from neutron.i18n import _LE
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import exceptions as p_exc
-from neutron.plugins.vmware.dhcp_meta import nsx
-from neutron.plugins.vmware.dhcp_meta import rpc
-
-LOG = logging.getLogger(__name__)
-
-
-class DhcpMetadataBuilder(object):
-
- def __init__(self, plugin, agent_notifier):
- self.plugin = plugin
- self.notifier = agent_notifier
-
- def dhcp_agent_get_all(self, context, network_id):
- """Return the agents managing the network."""
- return self.plugin.list_dhcp_agents_hosting_network(
- context, network_id)['agents']
-
- def dhcp_port_get_all(self, context, network_id):
- """Return the dhcp ports allocated for the network."""
- filters = {
- 'network_id': [network_id],
- 'device_owner': [const.DEVICE_OWNER_DHCP]
- }
- return self.plugin.get_ports(context, filters=filters)
-
- def router_id_get(self, context, subnet=None):
- """Return the router and interface used for the subnet."""
- if not subnet:
- return
- network_id = subnet['network_id']
- filters = {
- 'network_id': [network_id],
- 'device_owner': [const.DEVICE_OWNER_ROUTER_INTF]
- }
- ports = self.plugin.get_ports(context, filters=filters)
- for port in ports:
- if port['fixed_ips'][0]['subnet_id'] == subnet['id']:
- return port['device_id']
-
- def metadata_deallocate(self, context, router_id, subnet_id):
- """Deallocate metadata services for the subnet."""
- interface = {'subnet_id': subnet_id}
- self.plugin.remove_router_interface(context, router_id, interface)
-
- def metadata_allocate(self, context, router_id, subnet_id):
- """Allocate metadata resources for the subnet via the router."""
- interface = {'subnet_id': subnet_id}
- self.plugin.add_router_interface(context, router_id, interface)
-
- def dhcp_deallocate(self, context, network_id, agents, ports):
- """Deallocate dhcp resources for the network."""
- for agent in agents:
- self.plugin.remove_network_from_dhcp_agent(
- context, agent['id'], network_id)
- for port in ports:
- try:
- self.plugin.delete_port(context, port['id'])
- except n_exc.PortNotFound:
- LOG.error(_LE('Port %s is already gone'), port['id'])
-
- def dhcp_allocate(self, context, network_id, subnet):
- """Allocate dhcp resources for the subnet."""
- # Create LSN resources
- network_data = {'id': network_id}
- nsx.handle_network_dhcp_access(self.plugin, context,
- network_data, 'create_network')
- if subnet:
- subnet_data = {'subnet': subnet}
- self.notifier.notify(context, subnet_data, 'subnet.create.end')
- # Get DHCP host and metadata entries created for the LSN
- port = {
- 'network_id': network_id,
- 'fixed_ips': [{'subnet_id': subnet['id']}]
- }
- self.notifier.notify(context, {'port': port}, 'port.update.end')
-
-
-class MigrationManager(object):
-
- def __init__(self, plugin, lsn_manager, agent_notifier):
- self.plugin = plugin
- self.manager = lsn_manager
- self.builder = DhcpMetadataBuilder(plugin, agent_notifier)
-
- def validate(self, context, network_id):
- """Validate and return subnet's dhcp info for migration."""
- network = self.plugin.get_network(context, network_id)
-
- if self.manager.lsn_exists(context, network_id):
- reason = _("LSN already exist")
- raise p_exc.LsnMigrationConflict(net_id=network_id, reason=reason)
-
- if network[external_net.EXTERNAL]:
- reason = _("Cannot migrate an external network")
- raise n_exc.BadRequest(resource='network', msg=reason)
-
- filters = {'network_id': [network_id]}
- subnets = self.plugin.get_subnets(context, filters=filters)
- count = len(subnets)
- if count == 0:
- return None
- elif count == 1 and subnets[0]['cidr'] == rpc.METADATA_SUBNET_CIDR:
- reason = _("Cannot migrate a 'metadata' network")
- raise n_exc.BadRequest(resource='network', msg=reason)
- elif count > 1:
- reason = _("Unable to support multiple subnets per network")
- raise p_exc.LsnMigrationConflict(net_id=network_id, reason=reason)
- else:
- return subnets[0]
-
- def migrate(self, context, network_id, subnet=None):
- """Migrate subnet resources to LSN."""
- router_id = self.builder.router_id_get(context, subnet)
- if router_id and subnet:
- # Deallocate resources taken for the router, if any
- self.builder.metadata_deallocate(context, router_id, subnet['id'])
- if subnet:
- # Deallocate reources taken for the agent, if any
- agents = self.builder.dhcp_agent_get_all(context, network_id)
- ports = self.builder.dhcp_port_get_all(context, network_id)
- self.builder.dhcp_deallocate(context, network_id, agents, ports)
- # (re)create the configuration for LSN
- self.builder.dhcp_allocate(context, network_id, subnet)
- if router_id and subnet:
- # Allocate resources taken for the router, if any
- self.builder.metadata_allocate(context, router_id, subnet['id'])
-
- def report(self, context, network_id, subnet_id=None):
- """Return a report of the dhcp and metadata resources in use."""
- if subnet_id:
- lsn_id, lsn_port_id = self.manager.lsn_port_get(
- context, network_id, subnet_id, raise_on_err=False)
- else:
- filters = {'network_id': [network_id]}
- subnets = self.plugin.get_subnets(context, filters=filters)
- if subnets:
- lsn_id, lsn_port_id = self.manager.lsn_port_get(
- context, network_id, subnets[0]['id'], raise_on_err=False)
- else:
- lsn_id = self.manager.lsn_get(context, network_id,
- raise_on_err=False)
- lsn_port_id = None
- if lsn_id:
- ports = [lsn_port_id] if lsn_port_id else []
- report = {
- 'type': 'lsn',
- 'services': [lsn_id],
- 'ports': ports
- }
- else:
- agents = self.builder.dhcp_agent_get_all(context, network_id)
- ports = self.builder.dhcp_port_get_all(context, network_id)
- report = {
- 'type': 'agent',
- 'services': [a['id'] for a in agents],
- 'ports': [p['id'] for p in ports]
- }
- return report
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-
-# 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.
-#
-
-from oslo_config import cfg
-from oslo_utils import excutils
-
-from neutron.api.v2 import attributes as attr
-from neutron.common import constants as const
-from neutron.common import exceptions as n_exc
-from neutron.db import db_base_plugin_v2
-from neutron.db import l3_db
-from neutron.extensions import external_net
-from neutron.i18n import _LE, _LI
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import exceptions as p_exc
-from neutron.plugins.vmware.dhcp_meta import constants as d_const
-from neutron.plugins.vmware.nsxlib import lsn as lsn_api
-
-LOG = logging.getLogger(__name__)
-
-
-dhcp_opts = [
- cfg.ListOpt('extra_domain_name_servers',
- deprecated_group='NVP_DHCP',
- default=[],
- help=_('Comma separated list of additional '
- 'domain name servers')),
- cfg.StrOpt('domain_name',
- deprecated_group='NVP_DHCP',
- default='openstacklocal',
- help=_('Domain to use for building the hostnames')),
- cfg.IntOpt('default_lease_time', default=43200,
- deprecated_group='NVP_DHCP',
- help=_("Default DHCP lease time")),
-]
-
-
-metadata_opts = [
- cfg.StrOpt('metadata_server_address',
- deprecated_group='NVP_METADATA',
- default='127.0.0.1',
- help=_("IP address used by Metadata server.")),
- cfg.IntOpt('metadata_server_port',
- deprecated_group='NVP_METADATA',
- default=8775,
- help=_("TCP Port used by Metadata server.")),
- cfg.StrOpt('metadata_shared_secret',
- deprecated_group='NVP_METADATA',
- default='',
- help=_('Shared secret to sign instance-id request'),
- secret=True)
-]
-
-
-def register_dhcp_opts(config):
- config.CONF.register_opts(dhcp_opts, group="NSX_DHCP")
-
-
-def register_metadata_opts(config):
- config.CONF.register_opts(metadata_opts, group="NSX_METADATA")
-
-
-class DhcpAgentNotifyAPI(object):
-
- def __init__(self, plugin, lsn_manager):
- self.plugin = plugin
- self.lsn_manager = lsn_manager
- self._handle_subnet_dhcp_access = {'create': self._subnet_create,
- 'update': self._subnet_update,
- 'delete': self._subnet_delete}
-
- def notify(self, context, data, methodname):
- [resource, action, _e] = methodname.split('.')
- if resource == 'subnet':
- self._handle_subnet_dhcp_access[action](context, data['subnet'])
- elif resource == 'port' and action == 'update':
- self._port_update(context, data['port'])
-
- def _port_update(self, context, port):
- # With no fixed IP's there's nothing that can be updated
- if not port["fixed_ips"]:
- return
- network_id = port['network_id']
- subnet_id = port["fixed_ips"][0]['subnet_id']
- filters = {'network_id': [network_id]}
- # Because NSX does not support updating a single host entry we
- # got to build the whole list from scratch and update in bulk
- ports = self.plugin.get_ports(context, filters)
- if not ports:
- return
- dhcp_conf = [
- {'mac_address': p['mac_address'],
- 'ip_address': p["fixed_ips"][0]['ip_address']}
- for p in ports if is_user_port(p)
- ]
- meta_conf = [
- {'instance_id': p['device_id'],
- 'ip_address': p["fixed_ips"][0]['ip_address']}
- for p in ports if is_user_port(p, check_dev_id=True)
- ]
- self.lsn_manager.lsn_port_update(
- context, network_id, subnet_id, dhcp=dhcp_conf, meta=meta_conf)
-
- def _subnet_create(self, context, subnet, clean_on_err=True):
- if subnet['enable_dhcp']:
- network_id = subnet['network_id']
- # Create port for DHCP service
- dhcp_port = {
- "name": "",
- "admin_state_up": True,
- "device_id": "",
- "device_owner": const.DEVICE_OWNER_DHCP,
- "network_id": network_id,
- "tenant_id": subnet["tenant_id"],
- "mac_address": attr.ATTR_NOT_SPECIFIED,
- "fixed_ips": [{"subnet_id": subnet['id']}]
- }
- try:
- # This will end up calling handle_port_dhcp_access
- # down below as well as handle_port_metadata_access
- self.plugin.create_port(context, {'port': dhcp_port})
- except p_exc.PortConfigurationError as e:
- LOG.error(_LE("Error while creating subnet %(cidr)s for "
- "network %(network)s. Please, contact "
- "administrator"),
- {"cidr": subnet["cidr"],
- "network": network_id})
- db_base_plugin_v2.NeutronDbPluginV2.delete_port(
- self.plugin, context, e.port_id)
- if clean_on_err:
- self.plugin.delete_subnet(context, subnet['id'])
- raise n_exc.Conflict()
-
- def _subnet_update(self, context, subnet):
- network_id = subnet['network_id']
- try:
- lsn_id, lsn_port_id = self.lsn_manager.lsn_port_get(
- context, network_id, subnet['id'])
- self.lsn_manager.lsn_port_dhcp_configure(
- context, lsn_id, lsn_port_id, subnet)
- except p_exc.LsnPortNotFound:
- # It's possible that the subnet was created with dhcp off;
- # check if the subnet was uplinked onto a router, and if so
- # remove the patch attachment between the metadata port and
- # the lsn port, in favor on the one we'll be creating during
- # _subnet_create
- self.lsn_manager.lsn_port_dispose(
- context, network_id, d_const.METADATA_MAC)
- # also, check that a dhcp port exists first and provision it
- # accordingly
- filters = dict(network_id=[network_id],
- device_owner=[const.DEVICE_OWNER_DHCP])
- ports = self.plugin.get_ports(context, filters=filters)
- if ports:
- handle_port_dhcp_access(
- self.plugin, context, ports[0], 'create_port')
- else:
- self._subnet_create(context, subnet, clean_on_err=False)
-
- def _subnet_delete(self, context, subnet):
- # FIXME(armando-migliaccio): it looks like that a subnet filter
- # is ineffective; so filter by network for now.
- network_id = subnet['network_id']
- filters = dict(network_id=[network_id],
- device_owner=[const.DEVICE_OWNER_DHCP])
- # FIXME(armando-migliaccio): this may be race-y
- ports = self.plugin.get_ports(context, filters=filters)
- if ports:
- # This will end up calling handle_port_dhcp_access
- # down below as well as handle_port_metadata_access
- self.plugin.delete_port(context, ports[0]['id'])
-
-
-def is_user_port(p, check_dev_id=False):
- usable = p['fixed_ips'] and p['device_owner'] not in d_const.SPECIAL_OWNERS
- return usable if not check_dev_id else usable and p['device_id']
-
-
-def check_services_requirements(cluster):
- ver = cluster.api_client.get_version()
- # It sounds like 4.1 is the first one where DHCP in NSX
- # will have the experimental feature
- if ver.major >= 4 and ver.minor >= 1:
- cluster_id = cfg.CONF.default_service_cluster_uuid
- if not lsn_api.service_cluster_exists(cluster, cluster_id):
- raise p_exc.ServiceClusterUnavailable(cluster_id=cluster_id)
- else:
- raise p_exc.InvalidVersion(version=ver)
-
-
-def handle_network_dhcp_access(plugin, context, network, action):
- LOG.info(_LI("Performing DHCP %(action)s for resource: %(resource)s"),
- {"action": action, "resource": network})
- if action == 'create_network':
- network_id = network['id']
- if network.get(external_net.EXTERNAL):
- LOG.info(_LI("Network %s is external: no LSN to create"),
- network_id)
- return
- plugin.lsn_manager.lsn_create(context, network_id)
- elif action == 'delete_network':
- # NOTE(armando-migliaccio): on delete_network, network
- # is just the network id
- network_id = network
- plugin.lsn_manager.lsn_delete_by_network(context, network_id)
- LOG.info(_LI("Logical Services Node for network "
- "%s configured successfully"), network_id)
-
-
-def handle_port_dhcp_access(plugin, context, port, action):
- LOG.info(_LI("Performing DHCP %(action)s for resource: %(resource)s"),
- {"action": action, "resource": port})
- if port["device_owner"] == const.DEVICE_OWNER_DHCP:
- network_id = port["network_id"]
- if action == "create_port":
- # at this point the port must have a subnet and a fixed ip
- subnet_id = port["fixed_ips"][0]['subnet_id']
- subnet = plugin.get_subnet(context, subnet_id)
- subnet_data = {
- "mac_address": port["mac_address"],
- "ip_address": subnet['cidr'],
- "subnet_id": subnet['id']
- }
- try:
- plugin.lsn_manager.lsn_port_dhcp_setup(
- context, network_id, port['id'], subnet_data, subnet)
- except p_exc.PortConfigurationError:
- LOG.error(_LE("Error while configuring DHCP for "
- "port %s"), port['id'])
- raise n_exc.NeutronException()
- elif action == "delete_port":
- plugin.lsn_manager.lsn_port_dispose(context, network_id,
- port['mac_address'])
- elif port["device_owner"] != const.DEVICE_OWNER_DHCP:
- if port.get("fixed_ips"):
- # do something only if there are IP's and dhcp is enabled
- subnet_id = port["fixed_ips"][0]['subnet_id']
- if not plugin.get_subnet(context, subnet_id)['enable_dhcp']:
- LOG.info(_LI("DHCP is disabled for subnet %s: nothing "
- "to do"), subnet_id)
- return
- host_data = {
- "mac_address": port["mac_address"],
- "ip_address": port["fixed_ips"][0]['ip_address']
- }
- network_id = port["network_id"]
- if action == "create_port":
- handler = plugin.lsn_manager.lsn_port_dhcp_host_add
- elif action == "delete_port":
- handler = plugin.lsn_manager.lsn_port_dhcp_host_remove
- try:
- handler(context, network_id, subnet_id, host_data)
- except p_exc.PortConfigurationError:
- with excutils.save_and_reraise_exception():
- if action == 'create_port':
- db_base_plugin_v2.NeutronDbPluginV2.delete_port(
- plugin, context, port['id'])
- LOG.info(_LI("DHCP for port %s configured successfully"), port['id'])
-
-
-def handle_port_metadata_access(plugin, context, port, is_delete=False):
- if is_user_port(port, check_dev_id=True):
- network_id = port["network_id"]
- network = plugin.get_network(context, network_id)
- if network[external_net.EXTERNAL]:
- LOG.info(_LI("Network %s is external: nothing to do"),
- network_id)
- return
- subnet_id = port["fixed_ips"][0]['subnet_id']
- host_data = {
- "instance_id": port["device_id"],
- "tenant_id": port["tenant_id"],
- "ip_address": port["fixed_ips"][0]['ip_address']
- }
- LOG.info(_LI("Configuring metadata entry for port %s"), port)
- if not is_delete:
- handler = plugin.lsn_manager.lsn_port_meta_host_add
- else:
- handler = plugin.lsn_manager.lsn_port_meta_host_remove
- try:
- handler(context, network_id, subnet_id, host_data)
- except p_exc.PortConfigurationError:
- with excutils.save_and_reraise_exception():
- if not is_delete:
- db_base_plugin_v2.NeutronDbPluginV2.delete_port(
- plugin, context, port['id'])
- LOG.info(_LI("Metadata for port %s configured successfully"),
- port['id'])
-
-
-def handle_router_metadata_access(plugin, context, router_id, interface=None):
- LOG.info(_LI("Handle metadata access via router: %(r)s and "
- "interface %(i)s"), {'r': router_id, 'i': interface})
- if interface:
- try:
- plugin.get_port(context, interface['port_id'])
- is_enabled = True
- except n_exc.NotFound:
- is_enabled = False
- subnet_id = interface['subnet_id']
- try:
- plugin.lsn_manager.lsn_metadata_configure(
- context, subnet_id, is_enabled)
- except p_exc.NsxPluginException:
- with excutils.save_and_reraise_exception():
- if is_enabled:
- l3_db.L3_NAT_db_mixin.remove_router_interface(
- plugin, context, router_id, interface)
- LOG.info(_LI("Metadata for router %s handled successfully"), router_id)
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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.
-#
-
-from eventlet import greenthread
-import netaddr
-from oslo_config import cfg
-
-from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
-from neutron.api.v2 import attributes
-from neutron.common import constants as const
-from neutron.common import exceptions as ntn_exc
-from neutron.db import db_base_plugin_v2
-from neutron.db import l3_db
-from neutron.db import models_v2
-from neutron.i18n import _LE, _LI, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import config
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-
-LOG = logging.getLogger(__name__)
-
-METADATA_DEFAULT_PREFIX = 30
-METADATA_SUBNET_CIDR = '169.254.169.252/%d' % METADATA_DEFAULT_PREFIX
-METADATA_GATEWAY_IP = '169.254.169.253'
-METADATA_DHCP_ROUTE = '169.254.169.254/32'
-
-
-def handle_network_dhcp_access(plugin, context, network, action):
- pass
-
-
-def handle_port_dhcp_access(plugin, context, port_data, action):
- active_port = (cfg.CONF.NSX.metadata_mode == config.MetadataModes.INDIRECT
- and port_data.get('device_owner') == const.DEVICE_OWNER_DHCP
- and port_data.get('fixed_ips', []))
- if active_port:
- subnet_id = port_data['fixed_ips'][0]['subnet_id']
- subnet = plugin.get_subnet(context, subnet_id)
- _notify_rpc_agent(context, {'subnet': subnet}, 'subnet.update.end')
-
-
-def handle_port_metadata_access(plugin, context, port, is_delete=False):
- if (cfg.CONF.NSX.metadata_mode == config.MetadataModes.INDIRECT and
- port.get('device_owner') == const.DEVICE_OWNER_DHCP):
- if port.get('fixed_ips', []) or is_delete:
- fixed_ip = port['fixed_ips'][0]
- query = context.session.query(models_v2.Subnet)
- subnet = query.filter(
- models_v2.Subnet.id == fixed_ip['subnet_id']).one()
- # If subnet does not have a gateway do not create metadata
- # route. This is done via the enable_isolated_metadata
- # option if desired.
- if not subnet.get('gateway_ip'):
- LOG.info(_LI('Subnet %s does not have a gateway, the '
- 'metadata route will not be created'),
- subnet['id'])
- return
- metadata_routes = [r for r in subnet.routes
- if r['destination'] == METADATA_DHCP_ROUTE]
- if metadata_routes:
- # We should have only a single metadata route at any time
- # because the route logic forbids two routes with the same
- # destination. Update next hop with the provided IP address
- if not is_delete:
- metadata_routes[0].nexthop = fixed_ip['ip_address']
- else:
- context.session.delete(metadata_routes[0])
- else:
- # add the metadata route
- route = models_v2.SubnetRoute(
- subnet_id=subnet.id,
- destination=METADATA_DHCP_ROUTE,
- nexthop=fixed_ip['ip_address'])
- context.session.add(route)
-
-
-def handle_router_metadata_access(plugin, context, router_id, interface=None):
- if cfg.CONF.NSX.metadata_mode != config.MetadataModes.DIRECT:
- LOG.debug("Metadata access network is disabled")
- return
- if not cfg.CONF.allow_overlapping_ips:
- LOG.warn(_LW("Overlapping IPs must be enabled in order to setup "
- "the metadata access network"))
- return
- ctx_elevated = context.elevated()
- device_filter = {'device_id': [router_id],
- 'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF]}
- # Retrieve ports calling database plugin
- ports = db_base_plugin_v2.NeutronDbPluginV2.get_ports(
- plugin, ctx_elevated, filters=device_filter)
- try:
- if ports:
- if (interface and
- not _find_metadata_port(plugin, ctx_elevated, ports)):
- _create_metadata_access_network(
- plugin, ctx_elevated, router_id)
- elif len(ports) == 1:
- # The only port left might be the metadata port
- _destroy_metadata_access_network(
- plugin, ctx_elevated, router_id, ports)
- else:
- LOG.debug("No router interface found for router '%s'. "
- "No metadata access network should be "
- "created or destroyed", router_id)
- # TODO(salvatore-orlando): A better exception handling in the
- # NSX plugin would allow us to improve error handling here
- except (ntn_exc.NeutronException, nsx_exc.NsxPluginException,
- api_exc.NsxApiException):
- # Any exception here should be regarded as non-fatal
- LOG.exception(_LE("An error occurred while operating on the "
- "metadata access network for router:'%s'"),
- router_id)
-
-
-def _find_metadata_port(plugin, context, ports):
- for port in ports:
- for fixed_ip in port['fixed_ips']:
- cidr = netaddr.IPNetwork(
- plugin.get_subnet(context, fixed_ip['subnet_id'])['cidr'])
- if cidr in netaddr.IPNetwork(METADATA_SUBNET_CIDR):
- return port
-
-
-def _create_metadata_access_network(plugin, context, router_id):
- # Add network
- # Network name is likely to be truncated on NSX
- net_data = {'name': 'meta-%s' % router_id,
- 'tenant_id': '', # intentionally not set
- 'admin_state_up': True,
- 'port_security_enabled': False,
- 'shared': False,
- 'status': const.NET_STATUS_ACTIVE}
- meta_net = plugin.create_network(context,
- {'network': net_data})
- greenthread.sleep(0) # yield
- plugin.schedule_network(context, meta_net)
- greenthread.sleep(0) # yield
- # From this point on there will be resources to garbage-collect
- # in case of failures
- meta_sub = None
- try:
- # Add subnet
- subnet_data = {'network_id': meta_net['id'],
- 'tenant_id': '', # intentionally not set
- 'name': 'meta-%s' % router_id,
- 'ip_version': 4,
- 'shared': False,
- 'cidr': METADATA_SUBNET_CIDR,
- 'enable_dhcp': True,
- # Ensure default allocation pool is generated
- 'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
- 'gateway_ip': METADATA_GATEWAY_IP,
- 'dns_nameservers': [],
- 'host_routes': []}
- meta_sub = plugin.create_subnet(context,
- {'subnet': subnet_data})
- greenthread.sleep(0) # yield
- plugin.add_router_interface(context, router_id,
- {'subnet_id': meta_sub['id']})
- greenthread.sleep(0) # yield
- # Tell to start the metadata agent proxy, only if we had success
- _notify_rpc_agent(context, {'subnet': meta_sub}, 'subnet.create.end')
- except (ntn_exc.NeutronException,
- nsx_exc.NsxPluginException,
- api_exc.NsxApiException):
- # It is not necessary to explicitly delete the subnet
- # as it will be removed with the network
- plugin.delete_network(context, meta_net['id'])
-
-
-def _destroy_metadata_access_network(plugin, context, router_id, ports):
- if not ports:
- return
- meta_port = _find_metadata_port(plugin, context, ports)
- if not meta_port:
- return
- meta_net_id = meta_port['network_id']
- meta_sub_id = meta_port['fixed_ips'][0]['subnet_id']
- plugin.remove_router_interface(
- context, router_id, {'port_id': meta_port['id']})
- greenthread.sleep(0) # yield
- context.session.expunge_all()
- try:
- # Remove network (this will remove the subnet too)
- plugin.delete_network(context, meta_net_id)
- greenthread.sleep(0) # yield
- except (ntn_exc.NeutronException, nsx_exc.NsxPluginException,
- api_exc.NsxApiException):
- # must re-add the router interface
- plugin.add_router_interface(context, router_id,
- {'subnet_id': meta_sub_id})
- # Tell to stop the metadata agent proxy
- _notify_rpc_agent(
- context, {'network': {'id': meta_net_id}}, 'network.delete.end')
-
-
-def _notify_rpc_agent(context, payload, event):
- if cfg.CONF.dhcp_agent_notification:
- dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
- dhcp_notifier.notify(context, payload, event)
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-#
-# 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.
-#
-
-from oslo_config import cfg
-from oslo_utils import importutils
-
-from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
-from neutron.api.rpc.handlers import dhcp_rpc
-from neutron.api.rpc.handlers import metadata_rpc
-from neutron.common import constants as const
-from neutron.common import rpc as n_rpc
-from neutron.common import topics
-from neutron.db import agents_db
-from neutron.i18n import _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import config
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.dhcp_meta import combined
-from neutron.plugins.vmware.dhcp_meta import lsnmanager
-from neutron.plugins.vmware.dhcp_meta import migration
-from neutron.plugins.vmware.dhcp_meta import nsx as nsx_svc
-from neutron.plugins.vmware.dhcp_meta import rpc as nsx_rpc
-from neutron.plugins.vmware.extensions import lsn
-
-LOG = logging.getLogger(__name__)
-
-
-class DhcpMetadataAccess(object):
-
- def setup_dhcpmeta_access(self):
- """Initialize support for DHCP and Metadata services."""
- self._init_extensions()
- if cfg.CONF.NSX.agent_mode == config.AgentModes.AGENT:
- self._setup_rpc_dhcp_metadata()
- mod = nsx_rpc
- elif cfg.CONF.NSX.agent_mode == config.AgentModes.AGENTLESS:
- self._setup_nsx_dhcp_metadata()
- mod = nsx_svc
- elif cfg.CONF.NSX.agent_mode == config.AgentModes.COMBINED:
- notifier = self._setup_nsx_dhcp_metadata()
- self._setup_rpc_dhcp_metadata(notifier=notifier)
- mod = combined
- else:
- error = _("Invalid agent_mode: %s") % cfg.CONF.NSX.agent_mode
- LOG.error(error)
- raise nsx_exc.NsxPluginException(err_msg=error)
- self.handle_network_dhcp_access_delegate = (
- mod.handle_network_dhcp_access
- )
- self.handle_port_dhcp_access_delegate = (
- mod.handle_port_dhcp_access
- )
- self.handle_port_metadata_access_delegate = (
- mod.handle_port_metadata_access
- )
- self.handle_metadata_access_delegate = (
- mod.handle_router_metadata_access
- )
-
- def _setup_rpc_dhcp_metadata(self, notifier=None):
- self.topic = topics.PLUGIN
- self.conn = n_rpc.create_connection(new=True)
- self.endpoints = [dhcp_rpc.DhcpRpcCallback(),
- agents_db.AgentExtRpcCallback(),
- metadata_rpc.MetadataRpcCallback()]
- self.conn.create_consumer(self.topic, self.endpoints, fanout=False)
- self.agent_notifiers[const.AGENT_TYPE_DHCP] = (
- notifier or dhcp_rpc_agent_api.DhcpAgentNotifyAPI())
- self.conn.consume_in_threads()
- self.network_scheduler = importutils.import_object(
- cfg.CONF.network_scheduler_driver
- )
- self.supported_extension_aliases.extend(
- ['agent', 'dhcp_agent_scheduler'])
-
- def _setup_nsx_dhcp_metadata(self):
- self._check_services_requirements()
- nsx_svc.register_dhcp_opts(cfg)
- nsx_svc.register_metadata_opts(cfg)
- lsnmanager.register_lsn_opts(cfg)
- lsn_manager = lsnmanager.PersistentLsnManager(self.safe_reference)
- self.lsn_manager = lsn_manager
- if cfg.CONF.NSX.agent_mode == config.AgentModes.AGENTLESS:
- notifier = nsx_svc.DhcpAgentNotifyAPI(self.safe_reference,
- lsn_manager)
- self.agent_notifiers[const.AGENT_TYPE_DHCP] = notifier
- # In agentless mode, ports whose owner is DHCP need to
- # be special cased; so add it to the list of special
- # owners list
- if const.DEVICE_OWNER_DHCP not in self.port_special_owners:
- self.port_special_owners.append(const.DEVICE_OWNER_DHCP)
- elif cfg.CONF.NSX.agent_mode == config.AgentModes.COMBINED:
- # This becomes ineffective, as all new networks creations
- # are handled by Logical Services Nodes in NSX
- cfg.CONF.set_override('network_auto_schedule', False)
- LOG.warn(_LW('network_auto_schedule has been disabled'))
- notifier = combined.DhcpAgentNotifyAPI(self.safe_reference,
- lsn_manager)
- self.supported_extension_aliases.append(lsn.EXT_ALIAS)
- # Add the capability to migrate dhcp and metadata services over
- self.migration_manager = (
- migration.MigrationManager(
- self.safe_reference, lsn_manager, notifier))
- return notifier
-
- def _init_extensions(self):
- extensions = (lsn.EXT_ALIAS, 'agent', 'dhcp_agent_scheduler')
- for ext in extensions:
- if ext in self.supported_extension_aliases:
- self.supported_extension_aliases.remove(ext)
-
- def _check_services_requirements(self):
- try:
- error = None
- nsx_svc.check_services_requirements(self.cluster)
- except nsx_exc.InvalidVersion:
- error = _("Unable to run Neutron with config option '%s', as NSX "
- "does not support it") % cfg.CONF.NSX.agent_mode
- except nsx_exc.ServiceClusterUnavailable:
- error = _("Unmet dependency for config option "
- "'%s'") % cfg.CONF.NSX.agent_mode
- if error:
- LOG.exception(error)
- raise nsx_exc.NsxPluginException(err_msg=error)
-
- def get_lsn(self, context, network_id, fields=None):
- report = self.migration_manager.report(context, network_id)
- return {'network': network_id, 'report': report}
-
- def create_lsn(self, context, lsn):
- network_id = lsn['lsn']['network']
- subnet = self.migration_manager.validate(context, network_id)
- subnet_id = None if not subnet else subnet['id']
- self.migration_manager.migrate(context, network_id, subnet)
- r = self.migration_manager.report(context, network_id, subnet_id)
- return {'network': network_id, 'report': r}
-
- def handle_network_dhcp_access(self, context, network, action):
- self.handle_network_dhcp_access_delegate(self.safe_reference, context,
- network, action)
-
- def handle_port_dhcp_access(self, context, port_data, action):
- self.handle_port_dhcp_access_delegate(self.safe_reference, context,
- port_data, action)
-
- def handle_port_metadata_access(self, context, port, is_delete=False):
- self.handle_port_metadata_access_delegate(self.safe_reference, context,
- port, is_delete)
-
- def handle_router_metadata_access(self, context,
- router_id, interface=None):
- self.handle_metadata_access_delegate(self.safe_reference, context,
- router_id, interface)
from neutron.api.v2 import attributes
from neutron.api.v2 import resource_helper
-from neutron.plugins.vmware.common import utils
GATEWAY_RESOURCE_NAME = "network_gateway"
DEVICE_RESOURCE_NAME = "gateway_device"
DEVICE_ID_ATTR = 'id'
IFACE_NAME_ATTR = 'interface_name'
+
+# TODO(salv-orlando): This type definition is duplicated into
+# stackforge/vmware-nsx. This temporary duplication should be removed once the
+# plugin decomposition is finished.
+# Allowed network types for the NSX Plugin
+class NetworkTypes(object):
+ """Allowed provider network types for the NSX Plugin."""
+ L3_EXT = 'l3_ext'
+ STT = 'stt'
+ GRE = 'gre'
+ FLAT = 'flat'
+ VLAN = 'vlan'
+ BRIDGE = 'bridge'
+
# Attribute Map for Network Gateway Resource
# TODO(salvatore-orlando): add admin state as other neutron resources
RESOURCE_ATTRIBUTE_MAP = {
msg = _("A connector type is required to create a gateway device")
return msg
connector_types = (valid_values if valid_values else
- [utils.NetworkTypes.GRE,
- utils.NetworkTypes.STT,
- utils.NetworkTypes.BRIDGE,
- 'ipsec%s' % utils.NetworkTypes.GRE,
- 'ipsec%s' % utils.NetworkTypes.STT])
+ [NetworkTypes.GRE,
+ NetworkTypes.STT,
+ NetworkTypes.BRIDGE,
+ 'ipsec%s' % NetworkTypes.GRE,
+ 'ipsec%s' % NetworkTypes.STT])
if data not in connector_types:
msg = _("Unknown connector type: %s") % data
return msg
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-# 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.
-
-from oslo_config import cfg
-
-from neutron.i18n import _LI
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import exceptions
-
-LOG = logging.getLogger(__name__)
-DEFAULT_PORT = 443
-# Raise if one of those attributes is not specified
-REQUIRED_ATTRIBUTES = ['default_tz_uuid', 'nsx_user',
- 'nsx_password', 'nsx_controllers']
-# Emit a INFO log if one of those attributes is not specified
-IMPORTANT_ATTRIBUTES = ['default_l3_gw_service_uuid']
-# Deprecated attributes
-DEPRECATED_ATTRIBUTES = ['metadata_dhcp_host_route',
- 'nvp_user', 'nvp_password', 'nvp_controllers']
-
-
-class NSXCluster(object):
- """NSX cluster class.
-
- Encapsulates controller connections and the API client for a NSX cluster.
-
- Controller-specific parameters, such as timeouts are stored in the
- elements of the controllers attribute, which are dicts.
- """
-
- def __init__(self, **kwargs):
- self._required_attributes = REQUIRED_ATTRIBUTES[:]
- self._important_attributes = IMPORTANT_ATTRIBUTES[:]
- self._deprecated_attributes = {}
- self._sanity_check(kwargs)
-
- for opt, val in self._deprecated_attributes.iteritems():
- LOG.deprecated(_("Attribute '%s' has been deprecated or moved "
- "to a new section. See new configuration file "
- "for details."), opt)
- depr_func = getattr(self, '_process_%s' % opt, None)
- if depr_func:
- depr_func(val)
-
- # If everything went according to plan these two lists should be empty
- if self._required_attributes:
- raise exceptions.InvalidClusterConfiguration(
- invalid_attrs=self._required_attributes)
- if self._important_attributes:
- LOG.info(_LI("The following cluster attributes were "
- "not specified: %s'"), self._important_attributes)
- # The API client will be explicitly created by users of this class
- self.api_client = None
-
- def _sanity_check(self, options):
- # Iterating this way ensures the conf parameters also
- # define the structure of this class
- for arg in cfg.CONF:
- if arg not in DEPRECATED_ATTRIBUTES:
- setattr(self, arg, options.get(arg, cfg.CONF.get(arg)))
- self._process_attribute(arg)
- elif options.get(arg) is not None:
- # Process deprecated attributes only if specified
- self._deprecated_attributes[arg] = options.get(arg)
-
- def _process_attribute(self, attribute):
- # Process the attribute only if it's not empty!
- if getattr(self, attribute, None):
- if attribute in self._required_attributes:
- self._required_attributes.remove(attribute)
- if attribute in self._important_attributes:
- self._important_attributes.remove(attribute)
- handler_func = getattr(self, '_process_%s' % attribute, None)
- if handler_func:
- handler_func()
-
- def _process_nsx_controllers(self):
- # If this raises something is not right, so let it bubble up
- # TODO(salvatore-orlando): Also validate attribute here
- for i, ctrl in enumerate(self.nsx_controllers or []):
- if len(ctrl.split(':')) == 1:
- self.nsx_controllers[i] = '%s:%s' % (ctrl, DEFAULT_PORT)
-
- def _process_nvp_controllers(self):
- self.nsx_controllers = self.nvp_controllers
- self._process_nsx_controllers()
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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.
-
-from oslo_serialization import jsonutils
-
-from neutron.common import exceptions as exception
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron import version
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-# Prefix to be used for all NSX API calls
-URI_PREFIX = "/ws.v1"
-NEUTRON_VERSION = version.version_info.release_string()
-
-LOG = log.getLogger(__name__)
-
-
-def _build_uri_path(resource,
- resource_id=None,
- parent_resource_id=None,
- fields=None,
- relations=None,
- filters=None,
- types=None,
- is_attachment=False,
- extra_action=None):
- resources = resource.split('/')
- res_path = resources[0]
- if resource_id:
- res_path += "/%s" % resource_id
- if len(resources) > 1:
- # There is also a parent resource to account for in the uri
- res_path = "%s/%s/%s" % (resources[1],
- parent_resource_id,
- res_path)
- if is_attachment:
- res_path = "%s/attachment" % res_path
- elif extra_action:
- res_path = "%s/%s" % (res_path, extra_action)
- params = []
- params.append(fields and "fields=%s" % fields)
- params.append(relations and "relations=%s" % relations)
- params.append(types and "types=%s" % types)
- if filters:
- sorted_filters = [
- '%s=%s' % (k, filters[k]) for k in sorted(filters.keys())
- ]
- params.extend(sorted_filters)
- uri_path = "%s/%s" % (URI_PREFIX, res_path)
- non_empty_params = [x for x in params if x is not None]
- if non_empty_params:
- query_string = '&'.join(non_empty_params)
- if query_string:
- uri_path += "?%s" % query_string
- return uri_path
-
-
-def format_exception(etype, e, exception_locals):
- """Consistent formatting for exceptions.
-
- :param etype: a string describing the exception type.
- :param e: the exception.
- :param execption_locals: calling context local variable dict.
- :returns: a formatted string.
- """
- msg = [_("Error. %(type)s exception: %(exc)s.") %
- {'type': etype, 'exc': e}]
- l = dict((k, v) for k, v in exception_locals.iteritems()
- if k != 'request')
- msg.append(_("locals=[%s]") % str(l))
- return ' '.join(msg)
-
-
-def do_request(*args, **kwargs):
- """Issue a request to the cluster specified in kwargs.
-
- :param args: a list of positional arguments.
- :param kwargs: a list of keyworkds arguments.
- :returns: the result of the operation loaded into a python
- object or None.
- """
- cluster = kwargs["cluster"]
- try:
- res = cluster.api_client.request(*args)
- if res:
- return jsonutils.loads(res)
- except api_exc.ResourceNotFound:
- raise exception.NotFound()
- except api_exc.ReadOnlyMode:
- raise nsx_exc.MaintenanceInProgress()
-
-
-def get_single_query_page(path, cluster, page_cursor=None,
- page_length=1000, neutron_only=True):
- params = []
- if page_cursor:
- params.append("_page_cursor=%s" % page_cursor)
- params.append("_page_length=%s" % page_length)
- # NOTE(salv-orlando): On the NSX backend the 'Quantum' tag is still
- # used for marking Neutron entities in order to preserve compatibility
- if neutron_only:
- params.append("tag_scope=quantum")
- query_params = "&".join(params)
- path = "%s%s%s" % (path, "&" if (path.find("?") != -1) else "?",
- query_params)
- body = do_request(HTTP_GET, path, cluster=cluster)
- # Result_count won't be returned if _page_cursor is supplied
- return body['results'], body.get('page_cursor'), body.get('result_count')
-
-
-def get_all_query_pages(path, cluster):
- need_more_results = True
- result_list = []
- page_cursor = None
- while need_more_results:
- results, page_cursor = get_single_query_page(
- path, cluster, page_cursor)[:2]
- if not page_cursor:
- need_more_results = False
- result_list.extend(results)
- return result_list
-
-
-def mk_body(**kwargs):
- """Convenience function creates and dumps dictionary to string.
-
- :param kwargs: the key/value pirs to be dumped into a json string.
- :returns: a json string.
- """
- return jsonutils.dumps(kwargs, ensure_ascii=False)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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.
-#
-
-from oslo_serialization import jsonutils
-
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import switch
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-
-GWSERVICE_RESOURCE = "gateway-service"
-TRANSPORTNODE_RESOURCE = "transport-node"
-
-LOG = log.getLogger(__name__)
-
-
-def create_l2_gw_service(cluster, tenant_id, display_name, devices):
- """Create a NSX Layer-2 Network Gateway Service.
-
- :param cluster: The target NSX cluster
- :param tenant_id: Identifier of the Openstack tenant for which
- the gateway service.
- :param display_name: Descriptive name of this gateway service
- :param devices: List of transport node uuids (and network
- interfaces on them) to use for the network gateway service
- :raise NsxApiException: if there is a problem while communicating
- with the NSX controller
- """
- # NOTE(salvatore-orlando): This is a little confusing, but device_id in
- # NSX is actually the identifier a physical interface on the gateway
- # device, which in the Neutron API is referred as interface_name
- gateways = [{"transport_node_uuid": device['id'],
- "device_id": device['interface_name'],
- "type": "L2Gateway"} for device in devices]
- gwservice_obj = {
- "display_name": utils.check_and_truncate(display_name),
- "tags": utils.get_tags(os_tid=tenant_id),
- "gateways": gateways,
- "type": "L2GatewayServiceConfig"
- }
- return nsxlib.do_request(
- HTTP_POST, nsxlib._build_uri_path(GWSERVICE_RESOURCE),
- jsonutils.dumps(gwservice_obj), cluster=cluster)
-
-
-def plug_l2_gw_service(cluster, lswitch_id, lport_id,
- gateway_id, vlan_id=None):
- """Plug a Layer-2 Gateway Attachment object in a logical port."""
- att_obj = {'type': 'L2GatewayAttachment',
- 'l2_gateway_service_uuid': gateway_id}
- if vlan_id:
- att_obj['vlan_id'] = vlan_id
- return switch.plug_interface(cluster, lswitch_id, lport_id, att_obj)
-
-
-def get_l2_gw_service(cluster, gateway_id):
- return nsxlib.do_request(
- HTTP_GET, nsxlib._build_uri_path(GWSERVICE_RESOURCE,
- resource_id=gateway_id),
- cluster=cluster)
-
-
-def get_l2_gw_services(cluster, tenant_id=None,
- fields=None, filters=None):
- actual_filters = dict(filters or {})
- if tenant_id:
- actual_filters['tag'] = tenant_id
- actual_filters['tag_scope'] = 'os_tid'
- return nsxlib.get_all_query_pages(
- nsxlib._build_uri_path(GWSERVICE_RESOURCE,
- filters=actual_filters),
- cluster)
-
-
-def update_l2_gw_service(cluster, gateway_id, display_name):
- # TODO(salvatore-orlando): Allow updates for gateways too
- gwservice_obj = get_l2_gw_service(cluster, gateway_id)
- if not display_name:
- # Nothing to update
- return gwservice_obj
- gwservice_obj["display_name"] = utils.check_and_truncate(display_name)
- return nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(GWSERVICE_RESOURCE,
- resource_id=gateway_id),
- jsonutils.dumps(gwservice_obj), cluster=cluster)
-
-
-def delete_l2_gw_service(cluster, gateway_id):
- nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(GWSERVICE_RESOURCE,
- resource_id=gateway_id),
- cluster=cluster)
-
-
-def _build_gateway_device_body(tenant_id, display_name, neutron_id,
- connector_type, connector_ip,
- client_certificate, tz_uuid):
-
- connector_type_mappings = {
- utils.NetworkTypes.STT: "STTConnector",
- utils.NetworkTypes.GRE: "GREConnector",
- utils.NetworkTypes.BRIDGE: "BridgeConnector",
- 'ipsec%s' % utils.NetworkTypes.STT: "IPsecSTT",
- 'ipsec%s' % utils.NetworkTypes.GRE: "IPsecGRE"}
- nsx_connector_type = connector_type_mappings.get(connector_type)
- body = {"display_name": utils.check_and_truncate(display_name),
- "tags": utils.get_tags(os_tid=tenant_id,
- q_gw_dev_id=neutron_id),
- "admin_status_enabled": True}
-
- if connector_ip and nsx_connector_type:
- body["transport_connectors"] = [
- {"transport_zone_uuid": tz_uuid,
- "ip_address": connector_ip,
- "type": nsx_connector_type}]
-
- if client_certificate:
- body["credential"] = {"client_certificate":
- {"pem_encoded": client_certificate},
- "type": "SecurityCertificateCredential"}
- return body
-
-
-def create_gateway_device(cluster, tenant_id, display_name, neutron_id,
- tz_uuid, connector_type, connector_ip,
- client_certificate):
- body = _build_gateway_device_body(tenant_id, display_name, neutron_id,
- connector_type, connector_ip,
- client_certificate, tz_uuid)
- try:
- return nsxlib.do_request(
- HTTP_POST, nsxlib._build_uri_path(TRANSPORTNODE_RESOURCE),
- jsonutils.dumps(body, sort_keys=True), cluster=cluster)
- except api_exc.InvalidSecurityCertificate:
- raise nsx_exc.InvalidSecurityCertificate()
-
-
-def update_gateway_device(cluster, gateway_id, tenant_id,
- display_name, neutron_id,
- tz_uuid, connector_type, connector_ip,
- client_certificate):
- body = _build_gateway_device_body(tenant_id, display_name, neutron_id,
- connector_type, connector_ip,
- client_certificate, tz_uuid)
- try:
- return nsxlib.do_request(
- HTTP_PUT,
- nsxlib._build_uri_path(TRANSPORTNODE_RESOURCE,
- resource_id=gateway_id),
- jsonutils.dumps(body, sort_keys=True), cluster=cluster)
- except api_exc.InvalidSecurityCertificate:
- raise nsx_exc.InvalidSecurityCertificate()
-
-
-def delete_gateway_device(cluster, device_uuid):
- return nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(TRANSPORTNODE_RESOURCE,
- device_uuid),
- cluster=cluster)
-
-
-def get_gateway_device_status(cluster, device_uuid):
- status_res = nsxlib.do_request(HTTP_GET,
- nsxlib._build_uri_path(
- TRANSPORTNODE_RESOURCE,
- device_uuid,
- extra_action='status'),
- cluster=cluster)
- # Returns the connection status
- return status_res['connection']['connected']
-
-
-def get_gateway_devices_status(cluster, tenant_id=None):
- if tenant_id:
- gw_device_query_path = nsxlib._build_uri_path(
- TRANSPORTNODE_RESOURCE,
- fields="uuid,tags",
- relations="TransportNodeStatus",
- filters={'tag': tenant_id,
- 'tag_scope': 'os_tid'})
- else:
- gw_device_query_path = nsxlib._build_uri_path(
- TRANSPORTNODE_RESOURCE,
- fields="uuid,tags",
- relations="TransportNodeStatus")
-
- response = nsxlib.get_all_query_pages(gw_device_query_path, cluster)
- results = {}
- for item in response:
- results[item['uuid']] = (item['_relations']['TransportNodeStatus']
- ['connection']['connected'])
- return results
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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.
-
-from oslo_serialization import jsonutils
-
-from neutron.common import exceptions as exception
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-
-SERVICECLUSTER_RESOURCE = "edge-cluster"
-LSERVICESNODE_RESOURCE = "lservices-node"
-LSERVICESNODEPORT_RESOURCE = "lport/%s" % LSERVICESNODE_RESOURCE
-SUPPORTED_METADATA_OPTIONS = ['metadata_proxy_shared_secret']
-
-LOG = log.getLogger(__name__)
-
-
-def service_cluster_exists(cluster, svc_cluster_id):
- exists = False
- try:
- exists = (
- svc_cluster_id and
- nsxlib.do_request(HTTP_GET,
- nsxlib._build_uri_path(
- SERVICECLUSTER_RESOURCE,
- resource_id=svc_cluster_id),
- cluster=cluster) is not None)
- except exception.NotFound:
- pass
- return exists
-
-
-def lsn_for_network_create(cluster, network_id):
- lsn_obj = {
- "edge_cluster_uuid": cluster.default_service_cluster_uuid,
- "tags": utils.get_tags(n_network_id=network_id)
- }
- return nsxlib.do_request(HTTP_POST,
- nsxlib._build_uri_path(LSERVICESNODE_RESOURCE),
- jsonutils.dumps(lsn_obj),
- cluster=cluster)["uuid"]
-
-
-def lsn_for_network_get(cluster, network_id):
- filters = {"tag": network_id, "tag_scope": "n_network_id"}
- results = nsxlib.do_request(HTTP_GET,
- nsxlib._build_uri_path(LSERVICESNODE_RESOURCE,
- fields="uuid",
- filters=filters),
- cluster=cluster)['results']
- if not results:
- raise exception.NotFound()
- elif len(results) == 1:
- return results[0]['uuid']
-
-
-def lsn_delete(cluster, lsn_id):
- nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(LSERVICESNODE_RESOURCE,
- resource_id=lsn_id),
- cluster=cluster)
-
-
-def lsn_port_host_entries_update(
- cluster, lsn_id, lsn_port_id, conf, hosts_data):
- hosts_obj = {'hosts': hosts_data}
- nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- resource_id=lsn_port_id,
- extra_action=conf),
- jsonutils.dumps(hosts_obj),
- cluster=cluster)
-
-
-def lsn_port_create(cluster, lsn_id, port_data):
- port_obj = {
- "ip_address": port_data["ip_address"],
- "mac_address": port_data["mac_address"],
- "tags": utils.get_tags(n_mac_address=port_data["mac_address"],
- n_subnet_id=port_data["subnet_id"]),
- "type": "LogicalServicesNodePortConfig",
- }
- return nsxlib.do_request(HTTP_POST,
- nsxlib._build_uri_path(LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id),
- jsonutils.dumps(port_obj),
- cluster=cluster)["uuid"]
-
-
-def lsn_port_delete(cluster, lsn_id, lsn_port_id):
- return nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- resource_id=lsn_port_id),
- cluster=cluster)
-
-
-def _lsn_port_get(cluster, lsn_id, filters):
- results = nsxlib.do_request(HTTP_GET,
- nsxlib._build_uri_path(
- LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- fields="uuid",
- filters=filters),
- cluster=cluster)['results']
- if not results:
- raise exception.NotFound()
- elif len(results) == 1:
- return results[0]['uuid']
-
-
-def lsn_port_by_mac_get(cluster, lsn_id, mac_address):
- filters = {"tag": mac_address, "tag_scope": "n_mac_address"}
- return _lsn_port_get(cluster, lsn_id, filters)
-
-
-def lsn_port_by_subnet_get(cluster, lsn_id, subnet_id):
- filters = {"tag": subnet_id, "tag_scope": "n_subnet_id"}
- return _lsn_port_get(cluster, lsn_id, filters)
-
-
-def lsn_port_info_get(cluster, lsn_id, lsn_port_id):
- result = nsxlib.do_request(HTTP_GET,
- nsxlib._build_uri_path(
- LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- resource_id=lsn_port_id),
- cluster=cluster)
- for tag in result['tags']:
- if tag['scope'] == 'n_subnet_id':
- result['subnet_id'] = tag['tag']
- break
- return result
-
-
-def lsn_port_plug_network(cluster, lsn_id, lsn_port_id, lswitch_port_id):
- patch_obj = {
- "type": "PatchAttachment",
- "peer_port_uuid": lswitch_port_id
- }
- try:
- nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- resource_id=lsn_port_id,
- is_attachment=True),
- jsonutils.dumps(patch_obj),
- cluster=cluster)
- except api_exc.Conflict:
- # This restriction might be lifted at some point
- msg = (_("Attempt to plug Logical Services Node %(lsn)s into "
- "network with port %(port)s failed. PatchAttachment "
- "already exists with another port") %
- {'lsn': lsn_id, 'port': lswitch_port_id})
- LOG.exception(msg)
- raise nsx_exc.LsnConfigurationConflict(lsn_id=lsn_id)
-
-
-def _lsn_configure_action(
- cluster, lsn_id, action, is_enabled, obj):
- lsn_obj = {"enabled": is_enabled}
- lsn_obj.update(obj)
- nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LSERVICESNODE_RESOURCE,
- resource_id=lsn_id,
- extra_action=action),
- jsonutils.dumps(lsn_obj),
- cluster=cluster)
-
-
-def _lsn_port_configure_action(
- cluster, lsn_id, lsn_port_id, action, is_enabled, obj):
- nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LSERVICESNODE_RESOURCE,
- resource_id=lsn_id,
- extra_action=action),
- jsonutils.dumps({"enabled": is_enabled}),
- cluster=cluster)
- nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- resource_id=lsn_port_id,
- extra_action=action),
- jsonutils.dumps(obj),
- cluster=cluster)
-
-
-def _get_opts(name, value):
- return {"name": name, "value": str(value)}
-
-
-def lsn_port_dhcp_configure(
- cluster, lsn_id, lsn_port_id, is_enabled=True, dhcp_options=None):
- dhcp_options = dhcp_options or {}
- opts = [_get_opts(key, val) for key, val in dhcp_options.iteritems()]
- dhcp_obj = {'options': opts}
- _lsn_port_configure_action(
- cluster, lsn_id, lsn_port_id, 'dhcp', is_enabled, dhcp_obj)
-
-
-def lsn_metadata_configure(
- cluster, lsn_id, is_enabled=True, metadata_info=None):
- meta_obj = {
- 'metadata_server_ip': metadata_info['metadata_server_ip'],
- 'metadata_server_port': metadata_info['metadata_server_port'],
- }
- if metadata_info:
- opts = [
- _get_opts(opt, metadata_info[opt])
- for opt in SUPPORTED_METADATA_OPTIONS
- if metadata_info.get(opt)
- ]
- if opts:
- meta_obj["options"] = opts
- _lsn_configure_action(
- cluster, lsn_id, 'metadata-proxy', is_enabled, meta_obj)
-
-
-def _lsn_port_host_action(
- cluster, lsn_id, lsn_port_id, host_obj, extra_action, action):
- nsxlib.do_request(HTTP_POST,
- nsxlib._build_uri_path(LSERVICESNODEPORT_RESOURCE,
- parent_resource_id=lsn_id,
- resource_id=lsn_port_id,
- extra_action=extra_action,
- filters={"action": action}),
- jsonutils.dumps(host_obj),
- cluster=cluster)
-
-
-def lsn_port_dhcp_host_add(cluster, lsn_id, lsn_port_id, host_data):
- _lsn_port_host_action(
- cluster, lsn_id, lsn_port_id, host_data, 'dhcp', 'add_host')
-
-
-def lsn_port_dhcp_host_remove(cluster, lsn_id, lsn_port_id, host_data):
- _lsn_port_host_action(
- cluster, lsn_id, lsn_port_id, host_data, 'dhcp', 'remove_host')
-
-
-def lsn_port_metadata_host_add(cluster, lsn_id, lsn_port_id, host_data):
- _lsn_port_host_action(
- cluster, lsn_id, lsn_port_id, host_data, 'metadata-proxy', 'add_host')
-
-
-def lsn_port_metadata_host_remove(cluster, lsn_id, lsn_port_id, host_data):
- _lsn_port_host_action(cluster, lsn_id, lsn_port_id,
- host_data, 'metadata-proxy', 'remove_host')
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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.
-
-from oslo_serialization import jsonutils
-from oslo_utils import excutils
-
-from neutron.api.v2 import attributes as attr
-from neutron.common import exceptions as exception
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-
-LQUEUE_RESOURCE = "lqueue"
-
-LOG = log.getLogger(__name__)
-
-
-def create_lqueue(cluster, queue_data):
- params = {
- 'name': 'display_name',
- 'qos_marking': 'qos_marking',
- 'min': 'min_bandwidth_rate',
- 'max': 'max_bandwidth_rate',
- 'dscp': 'dscp'
- }
- queue_obj = dict(
- (nsx_name, queue_data.get(api_name))
- for api_name, nsx_name in params.iteritems()
- if attr.is_attr_set(queue_data.get(api_name))
- )
- if 'display_name' in queue_obj:
- queue_obj['display_name'] = utils.check_and_truncate(
- queue_obj['display_name'])
-
- queue_obj['tags'] = utils.get_tags()
- try:
- return nsxlib.do_request(HTTP_POST,
- nsxlib._build_uri_path(LQUEUE_RESOURCE),
- jsonutils.dumps(queue_obj),
- cluster=cluster)['uuid']
- except api_exc.NsxApiException:
- # FIXME(salv-orlando): This should not raise NeutronException
- with excutils.save_and_reraise_exception():
- raise exception.NeutronException()
-
-
-def delete_lqueue(cluster, queue_id):
- try:
- nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(LQUEUE_RESOURCE,
- resource_id=queue_id),
- cluster=cluster)
- except Exception:
- # FIXME(salv-orlando): This should not raise NeutronException
- with excutils.save_and_reraise_exception():
- raise exception.NeutronException()
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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.
-
-from oslo_config import cfg
-from oslo_serialization import jsonutils
-from oslo_utils import excutils
-
-from neutron.common import exceptions as exception
-from neutron.i18n import _LE, _LI, _LW
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import switch
-from neutron.plugins.vmware.nsxlib import versioning
-
-# @versioning.versioned decorator makes the apparent function body
-# totally unrelated to the real function. This confuses pylint :(
-# pylint: disable=assignment-from-no-return
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-
-LROUTER_RESOURCE = "lrouter"
-LROUTER_RESOURCE = "lrouter"
-LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
-LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
-LROUTERNAT_RESOURCE = "nat/lrouter"
-# Constants for NAT rules
-MATCH_KEYS = ["destination_ip_addresses", "destination_port_max",
- "destination_port_min", "source_ip_addresses",
- "source_port_max", "source_port_min", "protocol"]
-
-LOG = log.getLogger(__name__)
-
-
-def _prepare_lrouter_body(name, neutron_router_id, tenant_id,
- router_type, distributed=None, **kwargs):
- body = {
- "display_name": utils.check_and_truncate(name),
- "tags": utils.get_tags(os_tid=tenant_id,
- q_router_id=neutron_router_id),
- "routing_config": {
- "type": router_type
- },
- "type": "LogicalRouterConfig",
- "replication_mode": cfg.CONF.NSX.replication_mode,
- }
- # add the distributed key only if not None (ie: True or False)
- if distributed is not None:
- body['distributed'] = distributed
- if kwargs:
- body["routing_config"].update(kwargs)
- return body
-
-
-def _create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
- display_name, nexthop, distributed=None):
- implicit_routing_config = {
- "default_route_next_hop": {
- "gateway_ip_address": nexthop,
- "type": "RouterNextHop"
- },
- }
- lrouter_obj = _prepare_lrouter_body(
- display_name, neutron_router_id, tenant_id,
- "SingleDefaultRouteImplicitRoutingConfig",
- distributed=distributed,
- **implicit_routing_config)
- return nsxlib.do_request(HTTP_POST,
- nsxlib._build_uri_path(LROUTER_RESOURCE),
- jsonutils.dumps(lrouter_obj), cluster=cluster)
-
-
-def create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
- display_name, nexthop):
- """Create a NSX logical router on the specified cluster.
-
- :param cluster: The target NSX cluster
- :param tenant_id: Identifier of the Openstack tenant for which
- the logical router is being created
- :param display_name: Descriptive name of this logical router
- :param nexthop: External gateway IP address for the logical router
- :raise NsxApiException: if there is a problem while communicating
- with the NSX controller
- """
- return _create_implicit_routing_lrouter(
- cluster, neutron_router_id, tenant_id, display_name, nexthop)
-
-
-def create_implicit_routing_lrouter_with_distribution(
- cluster, neutron_router_id, tenant_id, display_name,
- nexthop, distributed=None):
- """Create a NSX logical router on the specified cluster.
-
- This function also allows for creating distributed lrouters
- :param cluster: The target NSX cluster
- :param tenant_id: Identifier of the Openstack tenant for which
- the logical router is being created
- :param display_name: Descriptive name of this logical router
- :param nexthop: External gateway IP address for the logical router
- :param distributed: True for distributed logical routers
- :raise NsxApiException: if there is a problem while communicating
- with the NSX controller
- """
- return _create_implicit_routing_lrouter(
- cluster, neutron_router_id, tenant_id,
- display_name, nexthop, distributed)
-
-
-def create_explicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
- display_name, nexthop, distributed=None):
- lrouter_obj = _prepare_lrouter_body(
- display_name, neutron_router_id, tenant_id,
- "RoutingTableRoutingConfig", distributed=distributed)
- router = nsxlib.do_request(HTTP_POST,
- nsxlib._build_uri_path(LROUTER_RESOURCE),
- jsonutils.dumps(lrouter_obj), cluster=cluster)
- default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
- create_explicit_route_lrouter(cluster, router['uuid'], default_gw)
- return router
-
-
-def delete_lrouter(cluster, lrouter_id):
- nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(LROUTER_RESOURCE,
- resource_id=lrouter_id),
- cluster=cluster)
-
-
-def get_lrouter(cluster, lrouter_id):
- return nsxlib.do_request(HTTP_GET,
- nsxlib._build_uri_path(
- LROUTER_RESOURCE,
- resource_id=lrouter_id,
- relations='LogicalRouterStatus'),
- cluster=cluster)
-
-
-def query_lrouters(cluster, fields=None, filters=None):
- return nsxlib.get_all_query_pages(
- nsxlib._build_uri_path(LROUTER_RESOURCE,
- fields=fields,
- relations='LogicalRouterStatus',
- filters=filters),
- cluster)
-
-
-def get_lrouters(cluster, tenant_id, fields=None, filters=None):
- # FIXME(salv-orlando): Fields parameter is ignored in this routine
- actual_filters = {}
- if filters:
- actual_filters.update(filters)
- if tenant_id:
- actual_filters['tag'] = tenant_id
- actual_filters['tag_scope'] = 'os_tid'
- lrouter_fields = "uuid,display_name,fabric_status,tags"
- return query_lrouters(cluster, lrouter_fields, actual_filters)
-
-
-def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
- lrouter_obj = get_lrouter(cluster, r_id)
- if not display_name and not nexthop:
- # Nothing to update
- return lrouter_obj
- # It seems that this is faster than the doing an if on display_name
- lrouter_obj["display_name"] = (utils.check_and_truncate(display_name) or
- lrouter_obj["display_name"])
- if nexthop:
- nh_element = lrouter_obj["routing_config"].get(
- "default_route_next_hop")
- if nh_element:
- nh_element["gateway_ip_address"] = nexthop
- return nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LROUTER_RESOURCE,
- resource_id=r_id),
- jsonutils.dumps(lrouter_obj),
- cluster=cluster)
-
-
-def get_explicit_routes_lrouter(cluster, router_id, protocol_type='static'):
- static_filter = {'protocol': protocol_type}
- existing_routes = nsxlib.do_request(
- HTTP_GET,
- nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
- filters=static_filter,
- fields="*",
- parent_resource_id=router_id),
- cluster=cluster)['results']
- return existing_routes
-
-
-def delete_explicit_route_lrouter(cluster, router_id, route_id):
- nsxlib.do_request(HTTP_DELETE,
- nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
- resource_id=route_id,
- parent_resource_id=router_id),
- cluster=cluster)
-
-
-def create_explicit_route_lrouter(cluster, router_id, route):
- next_hop_ip = route.get("nexthop") or route.get("next_hop_ip")
- prefix = route.get("destination") or route.get("prefix")
- uuid = nsxlib.do_request(
- HTTP_POST,
- nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
- parent_resource_id=router_id),
- jsonutils.dumps({
- "action": "accept",
- "next_hop_ip": next_hop_ip,
- "prefix": prefix,
- "protocol": "static"
- }),
- cluster=cluster)['uuid']
- return uuid
-
-
-def update_explicit_routes_lrouter(cluster, router_id, routes):
- # Update in bulk: delete them all, and add the ones specified
- # but keep track of what is been modified to allow roll-backs
- # in case of failures
- nsx_routes = get_explicit_routes_lrouter(cluster, router_id)
- try:
- deleted_routes = []
- added_routes = []
- # omit the default route (0.0.0.0/0) from the processing;
- # this must be handled through the nexthop for the router
- for route in nsx_routes:
- prefix = route.get("destination") or route.get("prefix")
- if prefix != '0.0.0.0/0':
- delete_explicit_route_lrouter(cluster,
- router_id,
- route['uuid'])
- deleted_routes.append(route)
- for route in routes:
- prefix = route.get("destination") or route.get("prefix")
- if prefix != '0.0.0.0/0':
- uuid = create_explicit_route_lrouter(cluster,
- router_id, route)
- added_routes.append(uuid)
- except api_exc.NsxApiException:
- LOG.exception(_LE('Cannot update NSX routes %(routes)s for '
- 'router %(router_id)s'),
- {'routes': routes, 'router_id': router_id})
- # Roll back to keep NSX in consistent state
- with excutils.save_and_reraise_exception():
- if nsx_routes:
- if deleted_routes:
- for route in deleted_routes:
- create_explicit_route_lrouter(cluster,
- router_id, route)
- if added_routes:
- for route_id in added_routes:
- delete_explicit_route_lrouter(cluster,
- router_id, route_id)
- return nsx_routes
-
-
-def get_default_route_explicit_routing_lrouter_v33(cluster, router_id):
- static_filter = {"protocol": "static",
- "prefix": "0.0.0.0/0"}
- default_route = nsxlib.do_request(
- HTTP_GET,
- nsxlib._build_uri_path(LROUTERRIB_RESOURCE,
- filters=static_filter,
- fields="*",
- parent_resource_id=router_id),
- cluster=cluster)["results"][0]
- return default_route
-
-
-def get_default_route_explicit_routing_lrouter_v32(cluster, router_id):
- # Scan all routes because 3.2 does not support query by prefix
- all_routes = get_explicit_routes_lrouter(cluster, router_id)
- for route in all_routes:
- if route['prefix'] == '0.0.0.0/0':
- return route
-
-
-def update_default_gw_explicit_routing_lrouter(cluster, router_id, next_hop):
- default_route = get_default_route_explicit_routing_lrouter(cluster,
- router_id)
- if next_hop != default_route["next_hop_ip"]:
- new_default_route = {"action": "accept",
- "next_hop_ip": next_hop,
- "prefix": "0.0.0.0/0",
- "protocol": "static"}
- nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(
- LROUTERRIB_RESOURCE,
- resource_id=default_route['uuid'],
- parent_resource_id=router_id),
- jsonutils.dumps(new_default_route),
- cluster=cluster)
-
-
-def update_explicit_routing_lrouter(cluster, router_id,
- display_name, next_hop, routes=None):
- update_implicit_routing_lrouter(cluster, router_id, display_name, next_hop)
- if next_hop:
- update_default_gw_explicit_routing_lrouter(cluster,
- router_id, next_hop)
- if routes is not None:
- return update_explicit_routes_lrouter(cluster, router_id, routes)
-
-
-def query_lrouter_lports(cluster, lr_uuid, fields="*",
- filters=None, relations=None):
- uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE,
- parent_resource_id=lr_uuid,
- fields=fields, filters=filters,
- relations=relations)
- return nsxlib.do_request(HTTP_GET, uri, cluster=cluster)['results']
-
-
-def create_router_lport(cluster, lrouter_uuid, tenant_id, neutron_port_id,
- display_name, admin_status_enabled, ip_addresses,
- mac_address=None):
- """Creates a logical port on the assigned logical router."""
- lport_obj = dict(
- admin_status_enabled=admin_status_enabled,
- display_name=display_name,
- tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
- ip_addresses=ip_addresses,
- type="LogicalRouterPortConfig"
- )
- # Only add the mac_address to lport_obj if present. This is because
- # when creating the fake_ext_gw there is no mac_address present.
- if mac_address:
- lport_obj['mac_address'] = mac_address
- path = nsxlib._build_uri_path(LROUTERPORT_RESOURCE,
- parent_resource_id=lrouter_uuid)
- result = nsxlib.do_request(HTTP_POST, path, jsonutils.dumps(lport_obj),
- cluster=cluster)
-
- LOG.debug("Created logical port %(lport_uuid)s on "
- "logical router %(lrouter_uuid)s",
- {'lport_uuid': result['uuid'],
- 'lrouter_uuid': lrouter_uuid})
- return result
-
-
-def update_router_lport(cluster, lrouter_uuid, lrouter_port_uuid,
- tenant_id, neutron_port_id, display_name,
- admin_status_enabled, ip_addresses):
- """Updates a logical port on the assigned logical router."""
- lport_obj = dict(
- admin_status_enabled=admin_status_enabled,
- display_name=display_name,
- tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
- ip_addresses=ip_addresses,
- type="LogicalRouterPortConfig"
- )
- # Do not pass null items to NSX
- for key in lport_obj.keys():
- if lport_obj[key] is None:
- del lport_obj[key]
- path = nsxlib._build_uri_path(LROUTERPORT_RESOURCE,
- lrouter_port_uuid,
- parent_resource_id=lrouter_uuid)
- result = nsxlib.do_request(HTTP_PUT, path,
- jsonutils.dumps(lport_obj),
- cluster=cluster)
- LOG.debug("Updated logical port %(lport_uuid)s on "
- "logical router %(lrouter_uuid)s",
- {'lport_uuid': lrouter_port_uuid, 'lrouter_uuid': lrouter_uuid})
- return result
-
-
-def delete_router_lport(cluster, lrouter_uuid, lport_uuid):
- """Creates a logical port on the assigned logical router."""
- path = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, lport_uuid,
- lrouter_uuid)
- nsxlib.do_request(HTTP_DELETE, path, cluster=cluster)
- LOG.debug("Delete logical router port %(lport_uuid)s on "
- "logical router %(lrouter_uuid)s",
- {'lport_uuid': lport_uuid,
- 'lrouter_uuid': lrouter_uuid})
-
-
-def delete_peer_router_lport(cluster, lr_uuid, ls_uuid, lp_uuid):
- nsx_port = switch.get_port(cluster, ls_uuid, lp_uuid,
- relations="LogicalPortAttachment")
- relations = nsx_port.get('_relations')
- if relations:
- att_data = relations.get('LogicalPortAttachment')
- if att_data:
- lrp_uuid = att_data.get('peer_port_uuid')
- if lrp_uuid:
- delete_router_lport(cluster, lr_uuid, lrp_uuid)
-
-
-def find_router_gw_port(context, cluster, router_id):
- """Retrieves the external gateway port for a NSX logical router."""
-
- # Find the uuid of nsx ext gw logical router port
- # TODO(salvatore-orlando): Consider storing it in Neutron DB
- results = query_lrouter_lports(
- cluster, router_id,
- relations="LogicalPortAttachment")
- for lport in results:
- if '_relations' in lport:
- attachment = lport['_relations'].get('LogicalPortAttachment')
- if attachment and attachment.get('type') == 'L3GatewayAttachment':
- return lport
-
-
-def plug_router_port_attachment(cluster, router_id, port_id,
- attachment_uuid, nsx_attachment_type,
- attachment_vlan=None):
- """Attach a router port to the given attachment.
-
- Current attachment types:
- - PatchAttachment [-> logical switch port uuid]
- - L3GatewayAttachment [-> L3GatewayService uuid]
- For the latter attachment type a VLAN ID can be specified as well.
- """
- uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, port_id, router_id,
- is_attachment=True)
- attach_obj = {}
- attach_obj["type"] = nsx_attachment_type
- if nsx_attachment_type == "PatchAttachment":
- attach_obj["peer_port_uuid"] = attachment_uuid
- elif nsx_attachment_type == "L3GatewayAttachment":
- attach_obj["l3_gateway_service_uuid"] = attachment_uuid
- if attachment_vlan:
- attach_obj['vlan_id'] = attachment_vlan
- else:
- raise nsx_exc.InvalidAttachmentType(
- attachment_type=nsx_attachment_type)
- return nsxlib.do_request(
- HTTP_PUT, uri, jsonutils.dumps(attach_obj), cluster=cluster)
-
-
-def _create_nat_match_obj(**kwargs):
- nat_match_obj = {'ethertype': 'IPv4'}
- delta = set(kwargs.keys()) - set(MATCH_KEYS)
- if delta:
- raise Exception(_("Invalid keys for NAT match: %s"), delta)
- nat_match_obj.update(kwargs)
- return nat_match_obj
-
-
-def _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj):
- LOG.debug("Creating NAT rule: %s", nat_rule_obj)
- uri = nsxlib._build_uri_path(LROUTERNAT_RESOURCE,
- parent_resource_id=router_id)
- return nsxlib.do_request(HTTP_POST, uri, jsonutils.dumps(nat_rule_obj),
- cluster=cluster)
-
-
-def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
- return {"to_source_ip_address_min": min_src_ip,
- "to_source_ip_address_max": max_src_ip,
- "type": "SourceNatRule",
- "match": nat_match_obj}
-
-
-def create_lrouter_nosnat_rule_v2(cluster, _router_id, _match_criteria=None):
- LOG.info(_LI("No SNAT rules cannot be applied as they are not available "
- "in this version of the NSX platform"))
-
-
-def create_lrouter_nodnat_rule_v2(cluster, _router_id, _match_criteria=None):
- LOG.info(_LI("No DNAT rules cannot be applied as they are not available "
- "in this version of the NSX platform"))
-
-
-def create_lrouter_snat_rule_v2(cluster, router_id,
- min_src_ip, max_src_ip, match_criteria=None):
-
- nat_match_obj = _create_nat_match_obj(**match_criteria)
- nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
- return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
- to_dst_port=None, match_criteria=None):
-
- nat_match_obj = _create_nat_match_obj(**match_criteria)
- nat_rule_obj = {
- "to_destination_ip_address_min": dst_ip,
- "to_destination_ip_address_max": dst_ip,
- "type": "DestinationNatRule",
- "match": nat_match_obj
- }
- if to_dst_port:
- nat_rule_obj['to_destination_port'] = to_dst_port
- return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_nosnat_rule_v3(cluster, router_id, order=None,
- match_criteria=None):
- nat_match_obj = _create_nat_match_obj(**match_criteria)
- nat_rule_obj = {
- "type": "NoSourceNatRule",
- "match": nat_match_obj
- }
- if order:
- nat_rule_obj['order'] = order
- return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_nodnat_rule_v3(cluster, router_id, order=None,
- match_criteria=None):
- nat_match_obj = _create_nat_match_obj(**match_criteria)
- nat_rule_obj = {
- "type": "NoDestinationNatRule",
- "match": nat_match_obj
- }
- if order:
- nat_rule_obj['order'] = order
- return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
- order=None, match_criteria=None):
- nat_match_obj = _create_nat_match_obj(**match_criteria)
- nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
- if order:
- nat_rule_obj['order'] = order
- return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
- order=None, match_criteria=None):
-
- nat_match_obj = _create_nat_match_obj(**match_criteria)
- nat_rule_obj = {
- "to_destination_ip_address": dst_ip,
- "type": "DestinationNatRule",
- "match": nat_match_obj
- }
- if to_dst_port:
- nat_rule_obj['to_destination_port'] = to_dst_port
- if order:
- nat_rule_obj['order'] = order
- return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def delete_nat_rules_by_match(cluster, router_id, rule_type,
- max_num_expected,
- min_num_expected=0,
- raise_on_len_mismatch=True,
- **kwargs):
- # remove nat rules
- nat_rules = query_nat_rules(cluster, router_id)
- to_delete_ids = []
- for r in nat_rules:
- if (r['type'] != rule_type):
- continue
-
- for key, value in kwargs.iteritems():
- if not (key in r['match'] and r['match'][key] == value):
- break
- else:
- to_delete_ids.append(r['uuid'])
- num_rules_to_delete = len(to_delete_ids)
- if (num_rules_to_delete < min_num_expected or
- num_rules_to_delete > max_num_expected):
- if raise_on_len_mismatch:
- raise nsx_exc.NatRuleMismatch(actual_rules=num_rules_to_delete,
- min_rules=min_num_expected,
- max_rules=max_num_expected)
- else:
- LOG.warn(_LW("Found %(actual_rule_num)d matching NAT rules, which "
- "is not in the expected range (%(min_exp_rule_num)d,"
- "%(max_exp_rule_num)d)"),
- {'actual_rule_num': num_rules_to_delete,
- 'min_exp_rule_num': min_num_expected,
- 'max_exp_rule_num': max_num_expected})
-
- for rule_id in to_delete_ids:
- delete_router_nat_rule(cluster, router_id, rule_id)
- # Return number of deleted rules - useful at least for
- # testing purposes
- return num_rules_to_delete
-
-
-def delete_router_nat_rule(cluster, router_id, rule_id):
- uri = nsxlib._build_uri_path(LROUTERNAT_RESOURCE, rule_id, router_id)
- nsxlib.do_request(HTTP_DELETE, uri, cluster=cluster)
-
-
-def query_nat_rules(cluster, router_id, fields="*", filters=None):
- uri = nsxlib._build_uri_path(LROUTERNAT_RESOURCE,
- parent_resource_id=router_id,
- fields=fields, filters=filters)
- return nsxlib.get_all_query_pages(uri, cluster)
-
-
-# NOTE(salvatore-orlando): The following FIXME applies in general to
-# each operation on list attributes.
-# FIXME(salvatore-orlando): need a lock around the list of IPs on an iface
-def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
- ips_to_add, ips_to_remove):
- uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id)
- try:
- port = nsxlib.do_request(HTTP_GET, uri, cluster=cluster)
- # TODO(salvatore-orlando): Enforce ips_to_add intersection with
- # ips_to_remove is empty
- ip_address_set = set(port['ip_addresses'])
- ip_address_set = ip_address_set - set(ips_to_remove)
- ip_address_set = ip_address_set | set(ips_to_add)
- # Set is not JSON serializable - convert to list
- port['ip_addresses'] = list(ip_address_set)
- nsxlib.do_request(HTTP_PUT, uri, jsonutils.dumps(port),
- cluster=cluster)
- except exception.NotFound:
- # FIXME(salv-orlando):avoid raising different exception
- data = {'lport_id': lport_id, 'lrouter_id': lrouter_id}
- msg = (_("Router Port %(lport_id)s not found on router "
- "%(lrouter_id)s") % data)
- LOG.exception(msg)
- raise nsx_exc.NsxPluginException(err_msg=msg)
- except api_exc.NsxApiException as e:
- msg = _("An exception occurred while updating IP addresses on a "
- "router logical port:%s") % e
- LOG.exception(msg)
- raise nsx_exc.NsxPluginException(err_msg=msg)
-
-
-ROUTER_FUNC_DICT = {
- 'create_lrouter': {
- 2: {versioning.DEFAULT_VERSION: create_implicit_routing_lrouter, },
- 3: {versioning.DEFAULT_VERSION: create_implicit_routing_lrouter,
- 1: create_implicit_routing_lrouter_with_distribution,
- 2: create_explicit_routing_lrouter, }, },
- 'update_lrouter': {
- 2: {versioning.DEFAULT_VERSION: update_implicit_routing_lrouter, },
- 3: {versioning.DEFAULT_VERSION: update_implicit_routing_lrouter,
- 2: update_explicit_routing_lrouter, }, },
- 'create_lrouter_dnat_rule': {
- 2: {versioning.DEFAULT_VERSION: create_lrouter_dnat_rule_v2, },
- 3: {versioning.DEFAULT_VERSION: create_lrouter_dnat_rule_v3, }, },
- 'create_lrouter_snat_rule': {
- 2: {versioning.DEFAULT_VERSION: create_lrouter_snat_rule_v2, },
- 3: {versioning.DEFAULT_VERSION: create_lrouter_snat_rule_v3, }, },
- 'create_lrouter_nosnat_rule': {
- 2: {versioning.DEFAULT_VERSION: create_lrouter_nosnat_rule_v2, },
- 3: {versioning.DEFAULT_VERSION: create_lrouter_nosnat_rule_v3, }, },
- 'create_lrouter_nodnat_rule': {
- 2: {versioning.DEFAULT_VERSION: create_lrouter_nodnat_rule_v2, },
- 3: {versioning.DEFAULT_VERSION: create_lrouter_nodnat_rule_v3, }, },
- 'get_default_route_explicit_routing_lrouter': {
- 3: {versioning.DEFAULT_VERSION:
- get_default_route_explicit_routing_lrouter_v32,
- 2: get_default_route_explicit_routing_lrouter_v32, }, },
-}
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def create_lrouter(cluster, *args, **kwargs):
- if kwargs.get('distributed', None):
- v = cluster.api_client.get_version()
- if (v.major, v.minor) < (3, 1):
- raise nsx_exc.InvalidVersion(version=v)
- return v
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
- pass
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def update_lrouter(cluster, *args, **kwargs):
- if kwargs.get('routes', None):
- v = cluster.api_client.get_version()
- if (v.major, v.minor) < (3, 2):
- raise nsx_exc.InvalidVersion(version=v)
- return v
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def create_lrouter_dnat_rule(cluster, *args, **kwargs):
- pass
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def create_lrouter_snat_rule(cluster, *args, **kwargs):
- pass
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
- pass
-
-
-@versioning.versioned(ROUTER_FUNC_DICT)
-def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
- pass
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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.
-
-from oslo_serialization import jsonutils
-from oslo_utils import excutils
-
-from neutron.common import constants
-from neutron.common import exceptions
-from neutron.i18n import _LW
-from neutron.openstack.common import log
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-
-SECPROF_RESOURCE = "security-profile"
-
-LOG = log.getLogger(__name__)
-
-
-def mk_body(**kwargs):
- """Convenience function creates and dumps dictionary to string.
-
- :param kwargs: the key/value pirs to be dumped into a json string.
- :returns: a json string.
- """
- return jsonutils.dumps(kwargs, ensure_ascii=False)
-
-
-def query_security_profiles(cluster, fields=None, filters=None):
- return nsxlib.get_all_query_pages(
- nsxlib._build_uri_path(SECPROF_RESOURCE,
- fields=fields,
- filters=filters),
- cluster)
-
-
-def create_security_profile(cluster, tenant_id, neutron_id, security_profile):
- """Create a security profile on the NSX backend.
-
- :param cluster: a NSX cluster object reference
- :param tenant_id: identifier of the Neutron tenant
- :param neutron_id: neutron security group identifier
- :param security_profile: dictionary with data for
- configuring the NSX security profile.
- """
- path = "/ws.v1/security-profile"
- # Allow all dhcp responses and all ingress traffic
- hidden_rules = {'logical_port_egress_rules':
- [{'ethertype': 'IPv4',
- 'protocol': constants.PROTO_NUM_UDP,
- 'port_range_min': constants.DHCP_RESPONSE_PORT,
- 'port_range_max': constants.DHCP_RESPONSE_PORT,
- 'ip_prefix': '0.0.0.0/0'}],
- 'logical_port_ingress_rules':
- [{'ethertype': 'IPv4'},
- {'ethertype': 'IPv6'}]}
- display_name = utils.check_and_truncate(security_profile.get('name'))
- # NOTE(salv-orlando): neutron-id tags are prepended with 'q' for
- # historical reasons
- body = mk_body(
- tags=utils.get_tags(os_tid=tenant_id, q_sec_group_id=neutron_id),
- display_name=display_name,
- logical_port_ingress_rules=(
- hidden_rules['logical_port_ingress_rules']),
- logical_port_egress_rules=hidden_rules['logical_port_egress_rules']
- )
- rsp = nsxlib.do_request(HTTP_POST, path, body, cluster=cluster)
- if security_profile.get('name') == 'default':
- # If security group is default allow ip traffic between
- # members of the same security profile is allowed and ingress traffic
- # from the switch
- rules = {'logical_port_egress_rules': [{'ethertype': 'IPv4',
- 'profile_uuid': rsp['uuid']},
- {'ethertype': 'IPv6',
- 'profile_uuid': rsp['uuid']}],
- 'logical_port_ingress_rules': [{'ethertype': 'IPv4'},
- {'ethertype': 'IPv6'}]}
-
- update_security_group_rules(cluster, rsp['uuid'], rules)
- LOG.debug("Created Security Profile: %s", rsp)
- return rsp
-
-
-def update_security_group_rules(cluster, spid, rules):
- path = "/ws.v1/security-profile/%s" % spid
-
- # Allow all dhcp responses in
- rules['logical_port_egress_rules'].append(
- {'ethertype': 'IPv4', 'protocol': constants.PROTO_NUM_UDP,
- 'port_range_min': constants.DHCP_RESPONSE_PORT,
- 'port_range_max': constants.DHCP_RESPONSE_PORT,
- 'ip_prefix': '0.0.0.0/0'})
- # If there are no ingress rules add bunk rule to drop all ingress traffic
- if not rules['logical_port_ingress_rules']:
- rules['logical_port_ingress_rules'].append(
- {'ethertype': 'IPv4', 'ip_prefix': '127.0.0.1/32'})
- try:
- body = mk_body(
- logical_port_ingress_rules=rules['logical_port_ingress_rules'],
- logical_port_egress_rules=rules['logical_port_egress_rules'])
- rsp = nsxlib.do_request(HTTP_PUT, path, body, cluster=cluster)
- except exceptions.NotFound as e:
- LOG.error(nsxlib.format_exception("Unknown", e, locals()))
- #FIXME(salvatore-orlando): This should not raise NeutronException
- raise exceptions.NeutronException()
- LOG.debug("Updated Security Profile: %s", rsp)
- return rsp
-
-
-def update_security_profile(cluster, spid, name):
- return nsxlib.do_request(
- HTTP_PUT,
- nsxlib._build_uri_path(SECPROF_RESOURCE, resource_id=spid),
- jsonutils.dumps({"display_name": utils.check_and_truncate(name)}),
- cluster=cluster)
-
-
-def delete_security_profile(cluster, spid):
- path = "/ws.v1/security-profile/%s" % spid
-
- try:
- nsxlib.do_request(HTTP_DELETE, path, cluster=cluster)
- except exceptions.NotFound:
- with excutils.save_and_reraise_exception():
- # This is not necessarily an error condition
- LOG.warn(_LW("Unable to find security profile %s on NSX backend"),
- spid)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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.
-#
-
-from oslo_config import cfg
-from oslo_serialization import jsonutils
-
-from neutron.common import constants
-from neutron.common import exceptions as exception
-from neutron.i18n import _LE, _LI, _LW
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-
-LSWITCH_RESOURCE = "lswitch"
-LSWITCHPORT_RESOURCE = "lport/%s" % LSWITCH_RESOURCE
-
-LOG = log.getLogger(__name__)
-
-
-def _configure_extensions(lport_obj, mac_address, fixed_ips,
- port_security_enabled, security_profiles,
- queue_id, mac_learning_enabled,
- allowed_address_pairs):
- lport_obj['allowed_address_pairs'] = []
- if port_security_enabled:
- for fixed_ip in fixed_ips:
- ip_address = fixed_ip.get('ip_address')
- if ip_address:
- lport_obj['allowed_address_pairs'].append(
- {'mac_address': mac_address, 'ip_address': ip_address})
- # add address pair allowing src_ip 0.0.0.0 to leave
- # this is required for outgoing dhcp request
- lport_obj["allowed_address_pairs"].append(
- {"mac_address": mac_address,
- "ip_address": "0.0.0.0"})
- lport_obj['security_profiles'] = list(security_profiles or [])
- lport_obj['queue_uuid'] = queue_id
- if mac_learning_enabled is not None:
- lport_obj["mac_learning"] = mac_learning_enabled
- lport_obj["type"] = "LogicalSwitchPortConfig"
- for address_pair in list(allowed_address_pairs or []):
- lport_obj['allowed_address_pairs'].append(
- {'mac_address': address_pair['mac_address'],
- 'ip_address': address_pair['ip_address']})
-
-
-def get_lswitch_by_id(cluster, lswitch_id):
- try:
- lswitch_uri_path = nsxlib._build_uri_path(
- LSWITCH_RESOURCE, lswitch_id,
- relations="LogicalSwitchStatus")
- return nsxlib.do_request(HTTP_GET, lswitch_uri_path, cluster=cluster)
- except exception.NotFound:
- # FIXME(salv-orlando): this should not raise a neutron exception
- raise exception.NetworkNotFound(net_id=lswitch_id)
-
-
-def get_lswitches(cluster, neutron_net_id):
-
- def lookup_switches_by_tag():
- # Fetch extra logical switches
- lswitch_query_path = nsxlib._build_uri_path(
- LSWITCH_RESOURCE,
- fields="uuid,display_name,tags,lport_count",
- relations="LogicalSwitchStatus",
- filters={'tag': neutron_net_id,
- 'tag_scope': 'quantum_net_id'})
- return nsxlib.get_all_query_pages(lswitch_query_path, cluster)
-
- lswitch_uri_path = nsxlib._build_uri_path(LSWITCH_RESOURCE, neutron_net_id,
- relations="LogicalSwitchStatus")
- results = []
- try:
- ls = nsxlib.do_request(HTTP_GET, lswitch_uri_path, cluster=cluster)
- results.append(ls)
- for tag in ls['tags']:
- if (tag['scope'] == "multi_lswitch" and
- tag['tag'] == "True"):
- results.extend(lookup_switches_by_tag())
- except exception.NotFound:
- # This is legit if the neutron network was created using
- # a post-Havana version of the plugin
- results.extend(lookup_switches_by_tag())
- if results:
- return results
- else:
- raise exception.NetworkNotFound(net_id=neutron_net_id)
-
-
-def create_lswitch(cluster, neutron_net_id, tenant_id, display_name,
- transport_zones_config,
- shared=None,
- **kwargs):
- # The tag scope adopts a slightly different naming convention for
- # historical reasons
- lswitch_obj = {"display_name": utils.check_and_truncate(display_name),
- "transport_zones": transport_zones_config,
- "replication_mode": cfg.CONF.NSX.replication_mode,
- "tags": utils.get_tags(os_tid=tenant_id,
- quantum_net_id=neutron_net_id)}
- # TODO(salv-orlando): Now that we have async status synchronization
- # this tag is perhaps not needed anymore
- if shared:
- lswitch_obj["tags"].append({"tag": "true",
- "scope": "shared"})
- if "tags" in kwargs:
- lswitch_obj["tags"].extend(kwargs["tags"])
- uri = nsxlib._build_uri_path(LSWITCH_RESOURCE)
- lswitch = nsxlib.do_request(HTTP_POST, uri, jsonutils.dumps(lswitch_obj),
- cluster=cluster)
- LOG.debug("Created logical switch: %s", lswitch['uuid'])
- return lswitch
-
-
-def update_lswitch(cluster, lswitch_id, display_name,
- tenant_id=None, **kwargs):
- uri = nsxlib._build_uri_path(LSWITCH_RESOURCE, resource_id=lswitch_id)
- lswitch_obj = {"display_name": utils.check_and_truncate(display_name)}
- # NOTE: tag update will not 'merge' existing tags with new ones.
- tags = []
- if tenant_id:
- tags = utils.get_tags(os_tid=tenant_id)
- # The 'tags' kwarg might existing and be None
- tags.extend(kwargs.get('tags') or [])
- if tags:
- lswitch_obj['tags'] = tags
- try:
- return nsxlib.do_request(HTTP_PUT, uri, jsonutils.dumps(lswitch_obj),
- cluster=cluster)
- except exception.NotFound:
- LOG.exception(_LE("Network not found."))
- raise exception.NetworkNotFound(net_id=lswitch_id)
-
-
-def delete_network(cluster, net_id, lswitch_id):
- delete_networks(cluster, net_id, [lswitch_id])
-
-
-#TODO(salvatore-orlando): Simplify and harmonize
-def delete_networks(cluster, net_id, lswitch_ids):
- for ls_id in lswitch_ids:
- path = "/ws.v1/lswitch/%s" % ls_id
- try:
- nsxlib.do_request(HTTP_DELETE, path, cluster=cluster)
- except exception.NotFound:
- LOG.exception(_LE("Network not found."))
- raise exception.NetworkNotFound(net_id=ls_id)
-
-
-def query_lswitch_lports(cluster, ls_uuid, fields="*",
- filters=None, relations=None):
- # Fix filter for attachments
- if filters and "attachment" in filters:
- filters['attachment_vif_uuid'] = filters["attachment"]
- del filters['attachment']
- uri = nsxlib._build_uri_path(LSWITCHPORT_RESOURCE,
- parent_resource_id=ls_uuid,
- fields=fields,
- filters=filters,
- relations=relations)
- return nsxlib.do_request(HTTP_GET, uri, cluster=cluster)['results']
-
-
-def delete_port(cluster, switch, port):
- uri = "/ws.v1/lswitch/" + switch + "/lport/" + port
- try:
- nsxlib.do_request(HTTP_DELETE, uri, cluster=cluster)
- except exception.NotFound:
- LOG.exception(_LE("Port or Network not found"))
- raise exception.PortNotFoundOnNetwork(
- net_id=switch, port_id=port)
- except api_exc.NsxApiException:
- raise exception.NeutronException()
-
-
-def get_ports(cluster, networks=None, devices=None, tenants=None):
- vm_filter_obsolete = ""
- vm_filter = ""
- tenant_filter = ""
- # This is used when calling delete_network. Neutron checks to see if
- # the network has any ports.
- if networks:
- # FIXME (Aaron) If we get more than one network_id this won't work
- lswitch = networks[0]
- else:
- lswitch = "*"
- if devices:
- for device_id in devices:
- vm_filter_obsolete = '&'.join(
- ["tag_scope=vm_id",
- "tag=%s" % utils.device_id_to_vm_id(device_id,
- obfuscate=True),
- vm_filter_obsolete])
- vm_filter = '&'.join(
- ["tag_scope=vm_id",
- "tag=%s" % utils.device_id_to_vm_id(device_id),
- vm_filter])
- if tenants:
- for tenant in tenants:
- tenant_filter = '&'.join(
- ["tag_scope=os_tid",
- "tag=%s" % tenant,
- tenant_filter])
-
- nsx_lports = {}
- lport_fields_str = ("tags,admin_status_enabled,display_name,"
- "fabric_status_up")
- try:
- lport_query_path_obsolete = (
- "/ws.v1/lswitch/%s/lport?fields=%s&%s%stag_scope=q_port_id"
- "&relations=LogicalPortStatus" %
- (lswitch, lport_fields_str, vm_filter_obsolete, tenant_filter))
- lport_query_path = (
- "/ws.v1/lswitch/%s/lport?fields=%s&%s%stag_scope=q_port_id"
- "&relations=LogicalPortStatus" %
- (lswitch, lport_fields_str, vm_filter, tenant_filter))
- try:
- # NOTE(armando-migliaccio): by querying with obsolete tag first
- # current deployments won't take the performance hit of a double
- # call. In release L-** or M-**, we might want to swap the calls
- # as it's likely that ports with the new tag would outnumber the
- # ones with the old tag
- ports = nsxlib.get_all_query_pages(lport_query_path_obsolete,
- cluster)
- if not ports:
- ports = nsxlib.get_all_query_pages(lport_query_path, cluster)
- except exception.NotFound:
- LOG.warn(_LW("Lswitch %s not found in NSX"), lswitch)
- ports = None
-
- if ports:
- for port in ports:
- for tag in port["tags"]:
- if tag["scope"] == "q_port_id":
- nsx_lports[tag["tag"]] = port
- except Exception:
- err_msg = _("Unable to get ports")
- LOG.exception(err_msg)
- raise nsx_exc.NsxPluginException(err_msg=err_msg)
- return nsx_lports
-
-
-def get_port_by_neutron_tag(cluster, lswitch_uuid, neutron_port_id):
- """Get port by neutron tag.
-
- Returns the NSX UUID of the logical port with tag q_port_id equal to
- neutron_port_id or None if the port is not Found.
- """
- uri = nsxlib._build_uri_path(LSWITCHPORT_RESOURCE,
- parent_resource_id=lswitch_uuid,
- fields='uuid',
- filters={'tag': neutron_port_id,
- 'tag_scope': 'q_port_id'})
- LOG.debug("Looking for port with q_port_id tag '%(neutron_port_id)s' "
- "on: '%(lswitch_uuid)s'",
- {'neutron_port_id': neutron_port_id,
- 'lswitch_uuid': lswitch_uuid})
- res = nsxlib.do_request(HTTP_GET, uri, cluster=cluster)
- num_results = len(res["results"])
- if num_results >= 1:
- if num_results > 1:
- LOG.warn(_LW("Found '%(num_ports)d' ports with "
- "q_port_id tag: '%(neutron_port_id)s'. "
- "Only 1 was expected."),
- {'num_ports': num_results,
- 'neutron_port_id': neutron_port_id})
- return res["results"][0]
-
-
-def get_port(cluster, network, port, relations=None):
- LOG.info(_LI("get_port() %(network)s %(port)s"),
- {'network': network, 'port': port})
- uri = "/ws.v1/lswitch/" + network + "/lport/" + port + "?"
- if relations:
- uri += "relations=%s" % relations
- try:
- return nsxlib.do_request(HTTP_GET, uri, cluster=cluster)
- except exception.NotFound:
- LOG.exception(_LE("Port or Network not found."))
- raise exception.PortNotFoundOnNetwork(
- port_id=port, net_id=network)
-
-
-def update_port(cluster, lswitch_uuid, lport_uuid, neutron_port_id, tenant_id,
- display_name, device_id, admin_status_enabled,
- mac_address=None, fixed_ips=None, port_security_enabled=None,
- security_profiles=None, queue_id=None,
- mac_learning_enabled=None, allowed_address_pairs=None):
- lport_obj = dict(
- admin_status_enabled=admin_status_enabled,
- display_name=utils.check_and_truncate(display_name),
- tags=utils.get_tags(os_tid=tenant_id,
- q_port_id=neutron_port_id,
- vm_id=utils.device_id_to_vm_id(device_id)))
-
- _configure_extensions(lport_obj, mac_address, fixed_ips,
- port_security_enabled, security_profiles,
- queue_id, mac_learning_enabled,
- allowed_address_pairs)
-
- path = "/ws.v1/lswitch/" + lswitch_uuid + "/lport/" + lport_uuid
- try:
- result = nsxlib.do_request(HTTP_PUT, path, jsonutils.dumps(lport_obj),
- cluster=cluster)
- LOG.debug("Updated logical port %(result)s "
- "on logical switch %(uuid)s",
- {'result': result['uuid'], 'uuid': lswitch_uuid})
- return result
- except exception.NotFound:
- LOG.exception(_LE("Port or Network not found."))
- raise exception.PortNotFoundOnNetwork(
- port_id=lport_uuid, net_id=lswitch_uuid)
-
-
-def create_lport(cluster, lswitch_uuid, tenant_id, neutron_port_id,
- display_name, device_id, admin_status_enabled,
- mac_address=None, fixed_ips=None, port_security_enabled=None,
- security_profiles=None, queue_id=None,
- mac_learning_enabled=None, allowed_address_pairs=None):
- """Creates a logical port on the assigned logical switch."""
- display_name = utils.check_and_truncate(display_name)
- lport_obj = dict(
- admin_status_enabled=admin_status_enabled,
- display_name=display_name,
- tags=utils.get_tags(os_tid=tenant_id,
- q_port_id=neutron_port_id,
- vm_id=utils.device_id_to_vm_id(device_id))
- )
-
- _configure_extensions(lport_obj, mac_address, fixed_ips,
- port_security_enabled, security_profiles,
- queue_id, mac_learning_enabled,
- allowed_address_pairs)
-
- path = nsxlib._build_uri_path(LSWITCHPORT_RESOURCE,
- parent_resource_id=lswitch_uuid)
- result = nsxlib.do_request(HTTP_POST, path, jsonutils.dumps(lport_obj),
- cluster=cluster)
-
- LOG.debug("Created logical port %(result)s on logical switch %(uuid)s",
- {'result': result['uuid'], 'uuid': lswitch_uuid})
- return result
-
-
-def get_port_status(cluster, lswitch_id, port_id):
- """Retrieve the operational status of the port."""
- try:
- r = nsxlib.do_request(HTTP_GET,
- "/ws.v1/lswitch/%s/lport/%s/status" %
- (lswitch_id, port_id), cluster=cluster)
- except exception.NotFound:
- LOG.exception(_LE("Port not found."))
- raise exception.PortNotFoundOnNetwork(
- port_id=port_id, net_id=lswitch_id)
- if r['link_status_up'] is True:
- return constants.PORT_STATUS_ACTIVE
- else:
- return constants.PORT_STATUS_DOWN
-
-
-def plug_interface(cluster, lswitch_id, lport_id, att_obj):
- return nsxlib.do_request(HTTP_PUT,
- nsxlib._build_uri_path(LSWITCHPORT_RESOURCE,
- lport_id, lswitch_id,
- is_attachment=True),
- jsonutils.dumps(att_obj),
- cluster=cluster)
-
-
-def plug_vif_interface(
- cluster, lswitch_id, port_id, port_type, attachment=None):
- """Plug a VIF Attachment object in a logical port."""
- lport_obj = {}
- if attachment:
- lport_obj["vif_uuid"] = attachment
-
- lport_obj["type"] = port_type
- return plug_interface(cluster, lswitch_id, port_id, lport_obj)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-# 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 inspect
-
-from neutron.plugins.vmware.api_client import exception
-
-DEFAULT_VERSION = -1
-
-
-def versioned(func_table):
-
- def versioned_function(wrapped_func):
- func_name = wrapped_func.__name__
-
- def dispatch_versioned_function(cluster, *args, **kwargs):
- # Call the wrapper function, in case we need to
- # run validation checks regarding versions. It
- # should return the NSX version
- v = (wrapped_func(cluster, *args, **kwargs) or
- cluster.api_client.get_version())
- func = get_function_by_version(func_table, func_name, v)
- func_kwargs = kwargs
- arg_spec = inspect.getargspec(func)
- if not arg_spec.keywords and not arg_spec.varargs:
- # drop args unknown to function from func_args
- arg_set = set(func_kwargs.keys())
- for arg in arg_set - set(arg_spec.args):
- del func_kwargs[arg]
- # NOTE(salvatore-orlando): shall we fail here if a required
- # argument is not passed, or let the called function raise?
- return func(cluster, *args, **func_kwargs)
-
- return dispatch_versioned_function
- return versioned_function
-
-
-def get_function_by_version(func_table, func_name, ver):
- if ver:
- if ver.major not in func_table[func_name]:
- major = max(func_table[func_name].keys())
- minor = max(func_table[func_name][major].keys())
- if major > ver.major:
- raise NotImplementedError(_("Operation may not be supported"))
- else:
- major = ver.major
- minor = ver.minor
- if ver.minor not in func_table[func_name][major]:
- minor = DEFAULT_VERSION
- return func_table[func_name][major][minor]
- else:
- msg = _('NSX version is not set. Unable to complete request '
- 'correctly. Check log for NSX communication errors.')
- raise exception.ServiceUnavailable(message=msg)
# under the License.
#
-from neutron.plugins.vmware.plugins import base
+from vmware_nsx.neutron.plugins.vmware.plugins import base as nsx_mh
-NsxPlugin = base.NsxPluginV2
+NsxMhPlugin = nsx_mh.NsxPluginV2
+# The 'NsxPlugin' name will be deprecated in Liberty
+# and replaced by the 'NsxMhPlugin' name
+NsxPlugin = NsxMhPlugin
+++ /dev/null
-# Copyright 2012 VMware, Inc.
-# 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 uuid
-
-from oslo_concurrency import lockutils
-from oslo_config import cfg
-from oslo_db import exception as db_exc
-from oslo_utils import excutils
-from sqlalchemy import exc as sql_exc
-from sqlalchemy.orm import exc as sa_exc
-import webob.exc
-
-from neutron.api import extensions as neutron_extensions
-from neutron.api.v2 import attributes as attr
-from neutron.api.v2 import base
-from neutron.common import constants
-from neutron.common import exceptions as n_exc
-from neutron.common import utils
-from neutron import context as q_context
-from neutron.db import agentschedulers_db
-from neutron.db import allowedaddresspairs_db as addr_pair_db
-from neutron.db import db_base_plugin_v2
-from neutron.db import external_net_db
-from neutron.db import extraroute_db
-from neutron.db import l3_db
-from neutron.db import l3_dvr_db
-from neutron.db import l3_gwmode_db
-from neutron.db import models_v2
-from neutron.db import portbindings_db
-from neutron.db import portsecurity_db
-from neutron.db import quota_db # noqa
-from neutron.db import securitygroups_db
-from neutron.extensions import allowedaddresspairs as addr_pair
-from neutron.extensions import external_net as ext_net_extn
-from neutron.extensions import extraroute
-from neutron.extensions import l3
-from neutron.extensions import multiprovidernet as mpnet
-from neutron.extensions import portbindings as pbin
-from neutron.extensions import portsecurity as psec
-from neutron.extensions import providernet as pnet
-from neutron.extensions import securitygroup as ext_sg
-from neutron.i18n import _LE, _LI, _LW
-from neutron.openstack.common import log as logging
-from neutron.plugins.common import constants as plugin_const
-from neutron.plugins import vmware
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import config # noqa
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import nsx_utils
-from neutron.plugins.vmware.common import securitygroups as sg_utils
-from neutron.plugins.vmware.common import sync
-from neutron.plugins.vmware.common import utils as c_utils
-from neutron.plugins.vmware.dbexts import db as nsx_db
-from neutron.plugins.vmware.dbexts import maclearning as mac_db
-from neutron.plugins.vmware.dbexts import networkgw_db
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.plugins.vmware.dbexts import qos_db
-from neutron.plugins.vmware import dhcpmeta_modes
-from neutron.plugins.vmware.extensions import maclearning as mac_ext
-from neutron.plugins.vmware.extensions import networkgw
-from neutron.plugins.vmware.extensions import qos
-from neutron.plugins.vmware.nsxlib import l2gateway as l2gwlib
-from neutron.plugins.vmware.nsxlib import queue as queuelib
-from neutron.plugins.vmware.nsxlib import router as routerlib
-from neutron.plugins.vmware.nsxlib import secgroup as secgrouplib
-from neutron.plugins.vmware.nsxlib import switch as switchlib
-
-LOG = logging.getLogger(__name__)
-
-NSX_NOSNAT_RULES_ORDER = 10
-NSX_FLOATINGIP_NAT_RULES_ORDER = 224
-NSX_EXTGW_NAT_RULES_ORDER = 255
-NSX_DEFAULT_NEXTHOP = '1.1.1.1'
-
-
-class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
- agentschedulers_db.DhcpAgentSchedulerDbMixin,
- db_base_plugin_v2.NeutronDbPluginV2,
- dhcpmeta_modes.DhcpMetadataAccess,
- l3_dvr_db.L3_NAT_with_dvr_db_mixin,
- external_net_db.External_net_db_mixin,
- extraroute_db.ExtraRoute_db_mixin,
- l3_gwmode_db.L3_NAT_db_mixin,
- mac_db.MacLearningDbMixin,
- networkgw_db.NetworkGatewayMixin,
- portbindings_db.PortBindingMixin,
- portsecurity_db.PortSecurityDbMixin,
- qos_db.QoSDbMixin,
- securitygroups_db.SecurityGroupDbMixin):
-
- supported_extension_aliases = ["allowed-address-pairs",
- "binding",
- "dvr",
- "ext-gw-mode",
- "extraroute",
- "mac-learning",
- "multi-provider",
- "network-gateway",
- "nvp-qos",
- "port-security",
- "provider",
- "qos-queue",
- "quotas",
- "external-net",
- "router",
- "security-group"]
-
- __native_bulk_support = True
- __native_pagination_support = True
- __native_sorting_support = True
-
- # Map nova zones to cluster for easy retrieval
- novazone_cluster_map = {}
-
- def __init__(self):
- super(NsxPluginV2, self).__init__()
- config.validate_config_options()
- # TODO(salv-orlando): Replace These dicts with
- # collections.defaultdict for better handling of default values
- # Routines for managing logical ports in NSX
- self.port_special_owners = [l3_db.DEVICE_OWNER_ROUTER_GW,
- l3_db.DEVICE_OWNER_ROUTER_INTF]
- self._port_drivers = {
- 'create': {l3_db.DEVICE_OWNER_ROUTER_GW:
- self._nsx_create_ext_gw_port,
- l3_db.DEVICE_OWNER_FLOATINGIP:
- self._nsx_create_fip_port,
- l3_db.DEVICE_OWNER_ROUTER_INTF:
- self._nsx_create_router_port,
- networkgw_db.DEVICE_OWNER_NET_GW_INTF:
- self._nsx_create_l2_gw_port,
- 'default': self._nsx_create_port},
- 'delete': {l3_db.DEVICE_OWNER_ROUTER_GW:
- self._nsx_delete_ext_gw_port,
- l3_db.DEVICE_OWNER_ROUTER_INTF:
- self._nsx_delete_router_port,
- l3_db.DEVICE_OWNER_FLOATINGIP:
- self._nsx_delete_fip_port,
- networkgw_db.DEVICE_OWNER_NET_GW_INTF:
- self._nsx_delete_port,
- 'default': self._nsx_delete_port}
- }
-
- neutron_extensions.append_api_extensions_path([vmware.NSX_EXT_PATH])
- self.nsx_opts = cfg.CONF.NSX
- self.nsx_sync_opts = cfg.CONF.NSX_SYNC
- self.cluster = nsx_utils.create_nsx_cluster(
- cfg.CONF,
- self.nsx_opts.concurrent_connections,
- self.nsx_opts.nsx_gen_timeout)
-
- self.base_binding_dict = {
- pbin.VIF_TYPE: pbin.VIF_TYPE_OVS,
- pbin.VIF_DETAILS: {
- # TODO(rkukura): Replace with new VIF security details
- pbin.CAP_PORT_FILTER:
- 'security-group' in self.supported_extension_aliases}}
-
- self._extend_fault_map()
- self.setup_dhcpmeta_access()
- # Set this flag to false as the default gateway has not
- # been yet updated from the config file
- self._is_default_net_gw_in_sync = False
- # Create a synchronizer instance for backend sync
- self._synchronizer = sync.NsxSynchronizer(
- self.safe_reference, self.cluster,
- self.nsx_sync_opts.state_sync_interval,
- self.nsx_sync_opts.min_sync_req_delay,
- self.nsx_sync_opts.min_chunk_size,
- self.nsx_sync_opts.max_random_sync_delay)
- self.start_periodic_dhcp_agent_status_check()
-
- def _ensure_default_network_gateway(self):
- if self._is_default_net_gw_in_sync:
- return
- # Add the gw in the db as default, and unset any previous default
- def_l2_gw_uuid = self.cluster.default_l2_gw_service_uuid
- try:
- ctx = q_context.get_admin_context()
- self._unset_default_network_gateways(ctx)
- if not def_l2_gw_uuid:
- return
- try:
- def_network_gw = self._get_network_gateway(ctx,
- def_l2_gw_uuid)
- except networkgw_db.GatewayNotFound:
- # Create in DB only - don't go to backend
- def_gw_data = {'id': def_l2_gw_uuid,
- 'name': 'default L2 gateway service',
- 'devices': []}
- gw_res_name = networkgw.GATEWAY_RESOURCE_NAME.replace('-', '_')
- def_network_gw = super(
- NsxPluginV2, self).create_network_gateway(
- ctx, {gw_res_name: def_gw_data})
- # In any case set is as default
- self._set_default_network_gateway(ctx, def_network_gw['id'])
- # Ensure this method is executed only once
- self._is_default_net_gw_in_sync = True
- except Exception:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("Unable to process default l2 gw service: "
- "%s"),
- def_l2_gw_uuid)
-
- def _build_ip_address_list(self, context, fixed_ips, subnet_ids=None):
- """Build ip_addresses data structure for logical router port.
-
- No need to perform validation on IPs - this has already been
- done in the l3_db mixin class.
- """
- ip_addresses = []
- for ip in fixed_ips:
- if not subnet_ids or (ip['subnet_id'] in subnet_ids):
- subnet = self._get_subnet(context, ip['subnet_id'])
- ip_prefix = '%s/%s' % (ip['ip_address'],
- subnet['cidr'].split('/')[1])
- ip_addresses.append(ip_prefix)
- return ip_addresses
-
- def _create_and_attach_router_port(self, cluster, context,
- nsx_router_id, port_data,
- attachment_type, attachment,
- attachment_vlan=None,
- subnet_ids=None):
- # Use a fake IP address if gateway port is not 'real'
- ip_addresses = (port_data.get('fake_ext_gw') and
- ['0.0.0.0/31'] or
- self._build_ip_address_list(context,
- port_data['fixed_ips'],
- subnet_ids))
- try:
- lrouter_port = routerlib.create_router_lport(
- cluster, nsx_router_id, port_data.get('tenant_id', 'fake'),
- port_data.get('id', 'fake'), port_data.get('name', 'fake'),
- port_data.get('admin_state_up', True), ip_addresses,
- port_data.get('mac_address'))
- LOG.debug("Created NSX router port:%s", lrouter_port['uuid'])
- except api_exc.NsxApiException:
- LOG.exception(_LE("Unable to create port on NSX logical router "
- "%s"),
- nsx_router_id)
- raise nsx_exc.NsxPluginException(
- err_msg=_("Unable to create logical router port for neutron "
- "port id %(port_id)s on router %(nsx_router_id)s") %
- {'port_id': port_data.get('id'),
- 'nsx_router_id': nsx_router_id})
- self._update_router_port_attachment(cluster, context, nsx_router_id,
- port_data, lrouter_port['uuid'],
- attachment_type, attachment,
- attachment_vlan)
- return lrouter_port
-
- def _update_router_gw_info(self, context, router_id, info):
- # NOTE(salvatore-orlando): We need to worry about rollback of NSX
- # configuration in case of failures in the process
- # Ref. LP bug 1102301
- router = self._get_router(context, router_id)
- # Check whether SNAT rule update should be triggered
- # NSX also supports multiple external networks so there is also
- # the possibility that NAT rules should be replaced
- current_ext_net_id = router.gw_port_id and router.gw_port.network_id
- new_ext_net_id = info and info.get('network_id')
- # SNAT should be enabled unless info['enable_snat'] is
- # explicitly set to false
- enable_snat = new_ext_net_id and info.get('enable_snat', True)
- # Remove if ext net removed, changed, or if snat disabled
- remove_snat_rules = (current_ext_net_id and
- new_ext_net_id != current_ext_net_id or
- router.enable_snat and not enable_snat)
- # Add rules if snat is enabled, and if either the external network
- # changed or snat was previously disabled
- # NOTE: enable_snat == True implies new_ext_net_id != None
- add_snat_rules = (enable_snat and
- (new_ext_net_id != current_ext_net_id or
- not router.enable_snat))
- router = super(NsxPluginV2, self)._update_router_gw_info(
- context, router_id, info, router=router)
- # Add/Remove SNAT rules as needed
- # Create an elevated context for dealing with metadata access
- # cidrs which are created within admin context
- ctx_elevated = context.elevated()
- if remove_snat_rules or add_snat_rules:
- cidrs = self._find_router_subnets_cidrs(ctx_elevated, router_id)
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- if remove_snat_rules:
- # Be safe and concede NAT rules might not exist.
- # Therefore use min_num_expected=0
- for cidr in cidrs:
- routerlib.delete_nat_rules_by_match(
- self.cluster, nsx_router_id, "SourceNatRule",
- max_num_expected=1, min_num_expected=0,
- raise_on_len_mismatch=False,
- source_ip_addresses=cidr)
- if add_snat_rules:
- ip_addresses = self._build_ip_address_list(
- ctx_elevated, router.gw_port['fixed_ips'])
- # Set the SNAT rule for each subnet (only first IP)
- for cidr in cidrs:
- cidr_prefix = int(cidr.split('/')[1])
- routerlib.create_lrouter_snat_rule(
- self.cluster, nsx_router_id,
- ip_addresses[0].split('/')[0],
- ip_addresses[0].split('/')[0],
- order=NSX_EXTGW_NAT_RULES_ORDER - cidr_prefix,
- match_criteria={'source_ip_addresses': cidr})
-
- def _update_router_port_attachment(self, cluster, context,
- nsx_router_id, port_data,
- nsx_router_port_id,
- attachment_type,
- attachment,
- attachment_vlan=None):
- if not nsx_router_port_id:
- nsx_router_port_id = self._find_router_gw_port(context, port_data)
- try:
- routerlib.plug_router_port_attachment(cluster, nsx_router_id,
- nsx_router_port_id,
- attachment,
- attachment_type,
- attachment_vlan)
- LOG.debug("Attached %(att)s to NSX router port %(port)s",
- {'att': attachment, 'port': nsx_router_port_id})
- except api_exc.NsxApiException:
- # Must remove NSX logical port
- routerlib.delete_router_lport(cluster, nsx_router_id,
- nsx_router_port_id)
- LOG.exception(_LE("Unable to plug attachment in NSX logical "
- "router port %(r_port_id)s, associated with "
- "Neutron %(q_port_id)s"),
- {'r_port_id': nsx_router_port_id,
- 'q_port_id': port_data.get('id')})
- raise nsx_exc.NsxPluginException(
- err_msg=(_("Unable to plug attachment in router port "
- "%(r_port_id)s for neutron port id %(q_port_id)s "
- "on router %(router_id)s") %
- {'r_port_id': nsx_router_port_id,
- 'q_port_id': port_data.get('id'),
- 'router_id': nsx_router_id}))
-
- def _get_port_by_device_id(self, context, device_id, device_owner):
- """Retrieve ports associated with a specific device id.
-
- Used for retrieving all neutron ports attached to a given router.
- """
- port_qry = context.session.query(models_v2.Port)
- return port_qry.filter_by(
- device_id=device_id,
- device_owner=device_owner,).all()
-
- def _find_router_subnets_cidrs(self, context, router_id):
- """Retrieve subnets attached to the specified router."""
- ports = self._get_port_by_device_id(context, router_id,
- l3_db.DEVICE_OWNER_ROUTER_INTF)
- # No need to check for overlapping CIDRs
- cidrs = []
- for port in ports:
- for ip in port.get('fixed_ips', []):
- cidrs.append(self._get_subnet(context,
- ip.subnet_id).cidr)
- return cidrs
-
- def _nsx_find_lswitch_for_port(self, context, port_data):
- network = self._get_network(context, port_data['network_id'])
- network_bindings = nsx_db.get_network_bindings(
- context.session, port_data['network_id'])
- max_ports = self.nsx_opts.max_lp_per_overlay_ls
- allow_extra_lswitches = False
- for network_binding in network_bindings:
- if network_binding.binding_type in (c_utils.NetworkTypes.FLAT,
- c_utils.NetworkTypes.VLAN):
- max_ports = self.nsx_opts.max_lp_per_bridged_ls
- allow_extra_lswitches = True
- break
- try:
- return self._handle_lswitch_selection(
- context, self.cluster, network, network_bindings,
- max_ports, allow_extra_lswitches)
- except api_exc.NsxApiException:
- err_desc = _("An exception occurred while selecting logical "
- "switch for the port")
- LOG.exception(err_desc)
- raise nsx_exc.NsxPluginException(err_msg=err_desc)
-
- def _nsx_create_port_helper(self, session, ls_uuid, port_data,
- do_port_security=True):
- # Convert Neutron security groups identifiers into NSX security
- # profiles identifiers
- nsx_sec_profile_ids = [
- nsx_utils.get_nsx_security_group_id(
- session, self.cluster, neutron_sg_id) for
- neutron_sg_id in (port_data[ext_sg.SECURITYGROUPS] or [])]
- return switchlib.create_lport(self.cluster,
- ls_uuid,
- port_data['tenant_id'],
- port_data['id'],
- port_data['name'],
- port_data['device_id'],
- port_data['admin_state_up'],
- port_data['mac_address'],
- port_data['fixed_ips'],
- port_data[psec.PORTSECURITY],
- nsx_sec_profile_ids,
- port_data.get(qos.QUEUE),
- port_data.get(mac_ext.MAC_LEARNING),
- port_data.get(addr_pair.ADDRESS_PAIRS))
-
- def _handle_create_port_exception(self, context, port_id,
- ls_uuid, lp_uuid):
- with excutils.save_and_reraise_exception():
- # rollback nsx logical port only if it was successfully
- # created on NSX. Should this command fail the original
- # exception will be raised.
- if lp_uuid:
- # Remove orphaned port from NSX
- switchlib.delete_port(self.cluster, ls_uuid, lp_uuid)
- # rollback the neutron-nsx port mapping
- nsx_db.delete_neutron_nsx_port_mapping(context.session,
- port_id)
- LOG.exception(_LE("An exception occurred while creating the "
- "neutron port %s on the NSX plaform"), port_id)
-
- def _nsx_create_port(self, context, port_data):
- """Driver for creating a logical switch port on NSX platform."""
- # FIXME(salvatore-orlando): On the NSX platform we do not really have
- # external networks. So if as user tries and create a "regular" VIF
- # port on an external network we are unable to actually create.
- # However, in order to not break unit tests, we need to still create
- # the DB object and return success
- if self._network_is_external(context, port_data['network_id']):
- LOG.info(_LI("NSX plugin does not support regular VIF ports on "
- "external networks. Port %s will be down."),
- port_data['network_id'])
- # No need to actually update the DB state - the default is down
- return port_data
- lport = None
- selected_lswitch = None
- try:
- selected_lswitch = self._nsx_find_lswitch_for_port(context,
- port_data)
- lport = self._nsx_create_port_helper(context.session,
- selected_lswitch['uuid'],
- port_data,
- True)
- nsx_db.add_neutron_nsx_port_mapping(
- context.session, port_data['id'],
- selected_lswitch['uuid'], lport['uuid'])
- if port_data['device_owner'] not in self.port_special_owners:
- switchlib.plug_vif_interface(
- self.cluster, selected_lswitch['uuid'],
- lport['uuid'], "VifAttachment", port_data['id'])
- LOG.debug("_nsx_create_port completed for port %(name)s "
- "on network %(network_id)s. The new port id is "
- "%(id)s.", port_data)
- except (api_exc.NsxApiException, n_exc.NeutronException):
- self._handle_create_port_exception(
- context, port_data['id'],
- selected_lswitch and selected_lswitch['uuid'],
- lport and lport['uuid'])
- except db_exc.DBError as e:
- if (port_data['device_owner'] == constants.DEVICE_OWNER_DHCP and
- isinstance(e.inner_exception, sql_exc.IntegrityError)):
- LOG.warning(
- _LW("Concurrent network deletion detected; Back-end "
- "Port %(nsx_id)s creation to be rolled back for "
- "Neutron port: %(neutron_id)s"),
- {'nsx_id': lport['uuid'],
- 'neutron_id': port_data['id']})
- if selected_lswitch and lport:
- try:
- switchlib.delete_port(self.cluster,
- selected_lswitch['uuid'],
- lport['uuid'])
- except n_exc.NotFound:
- LOG.debug("NSX Port %s already gone", lport['uuid'])
-
- def _nsx_delete_port(self, context, port_data):
- # FIXME(salvatore-orlando): On the NSX platform we do not really have
- # external networks. So deleting regular ports from external networks
- # does not make sense. However we cannot raise as this would break
- # unit tests.
- if self._network_is_external(context, port_data['network_id']):
- LOG.info(_LI("NSX plugin does not support regular VIF ports on "
- "external networks. Port %s will be down."),
- port_data['network_id'])
- return
- nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
- context.session, self.cluster, port_data['id'])
- if not nsx_port_id:
- LOG.debug("Port '%s' was already deleted on NSX platform", id)
- return
- # TODO(bgh): if this is a bridged network and the lswitch we just got
- # back will have zero ports after the delete we should garbage collect
- # the lswitch.
- try:
- switchlib.delete_port(self.cluster, nsx_switch_id, nsx_port_id)
- LOG.debug("_nsx_delete_port completed for port %(port_id)s "
- "on network %(net_id)s",
- {'port_id': port_data['id'],
- 'net_id': port_data['network_id']})
- except n_exc.NotFound:
- LOG.warning(_LW("Port %s not found in NSX"), port_data['id'])
-
- def _nsx_delete_router_port(self, context, port_data):
- # Delete logical router port
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, port_data['device_id'])
- nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
- context.session, self.cluster, port_data['id'])
- if not nsx_port_id:
- LOG.warn(
- _LW("Neutron port %(port_id)s not found on NSX backend. "
- "Terminating delete operation. A dangling router port "
- "might have been left on router %(router_id)s"),
- {'port_id': port_data['id'],
- 'router_id': nsx_router_id})
- return
- try:
- routerlib.delete_peer_router_lport(self.cluster,
- nsx_router_id,
- nsx_switch_id,
- nsx_port_id)
- except api_exc.NsxApiException:
- # Do not raise because the issue might as well be that the
- # router has already been deleted, so there would be nothing
- # to do here
- LOG.exception(_LE("Ignoring exception as this means the peer "
- "for port '%s' has already been deleted."),
- nsx_port_id)
-
- # Delete logical switch port
- self._nsx_delete_port(context, port_data)
-
- def _nsx_create_router_port(self, context, port_data):
- """Driver for creating a switch port to be connected to a router."""
- # No router ports on external networks!
- if self._network_is_external(context, port_data['network_id']):
- raise nsx_exc.NsxPluginException(
- err_msg=(_("It is not allowed to create router interface "
- "ports on external networks as '%s'") %
- port_data['network_id']))
- ls_port = None
- selected_lswitch = None
- try:
- selected_lswitch = self._nsx_find_lswitch_for_port(
- context, port_data)
- # Do not apply port security here!
- ls_port = self._nsx_create_port_helper(
- context.session, selected_lswitch['uuid'],
- port_data, False)
- # Assuming subnet being attached is on first fixed ip
- # element in port data
- subnet_id = port_data['fixed_ips'][0]['subnet_id']
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, port_data['device_id'])
- # Create peer port on logical router
- self._create_and_attach_router_port(
- self.cluster, context, nsx_router_id, port_data,
- "PatchAttachment", ls_port['uuid'],
- subnet_ids=[subnet_id])
- nsx_db.add_neutron_nsx_port_mapping(
- context.session, port_data['id'],
- selected_lswitch['uuid'], ls_port['uuid'])
- LOG.debug("_nsx_create_router_port completed for port "
- "%(name)s on network %(network_id)s. The new "
- "port id is %(id)s.",
- port_data)
- except (api_exc.NsxApiException, n_exc.NeutronException):
- self._handle_create_port_exception(
- context, port_data['id'],
- selected_lswitch and selected_lswitch['uuid'],
- ls_port and ls_port['uuid'])
-
- def _find_router_gw_port(self, context, port_data):
- router_id = port_data['device_id']
- if not router_id:
- raise n_exc.BadRequest(_("device_id field must be populated in "
- "order to create an external gateway "
- "port for network %s"),
- port_data['network_id'])
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- lr_port = routerlib.find_router_gw_port(context, self.cluster,
- nsx_router_id)
- if not lr_port:
- raise nsx_exc.NsxPluginException(
- err_msg=(_("The gateway port for the NSX router %s "
- "was not found on the backend")
- % nsx_router_id))
- return lr_port
-
- @lockutils.synchronized('vmware', 'neutron-')
- def _nsx_create_ext_gw_port(self, context, port_data):
- """Driver for creating an external gateway port on NSX platform."""
- # TODO(salvatore-orlando): Handle NSX resource
- # rollback when something goes not quite as expected
- lr_port = self._find_router_gw_port(context, port_data)
- ip_addresses = self._build_ip_address_list(context,
- port_data['fixed_ips'])
- # This operation actually always updates a NSX logical port
- # instead of creating one. This is because the gateway port
- # is created at the same time as the NSX logical router, otherwise
- # the fabric status of the NSX router will be down.
- # admin_status should always be up for the gateway port
- # regardless of what the user specifies in neutron
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, port_data['device_id'])
- routerlib.update_router_lport(self.cluster,
- nsx_router_id,
- lr_port['uuid'],
- port_data['tenant_id'],
- port_data['id'],
- port_data['name'],
- True,
- ip_addresses)
- ext_network = self.get_network(context, port_data['network_id'])
- if ext_network.get(pnet.NETWORK_TYPE) == c_utils.NetworkTypes.L3_EXT:
- # Update attachment
- physical_network = (ext_network[pnet.PHYSICAL_NETWORK] or
- self.cluster.default_l3_gw_service_uuid)
- self._update_router_port_attachment(
- self.cluster, context, nsx_router_id, port_data,
- lr_port['uuid'],
- "L3GatewayAttachment",
- physical_network,
- ext_network[pnet.SEGMENTATION_ID])
-
- LOG.debug("_nsx_create_ext_gw_port completed on external network "
- "%(ext_net_id)s, attached to router:%(router_id)s. "
- "NSX port id is %(nsx_port_id)s",
- {'ext_net_id': port_data['network_id'],
- 'router_id': nsx_router_id,
- 'nsx_port_id': lr_port['uuid']})
-
- @lockutils.synchronized('vmware', 'neutron-')
- def _nsx_delete_ext_gw_port(self, context, port_data):
- # TODO(salvatore-orlando): Handle NSX resource
- # rollback when something goes not quite as expected
- try:
- lr_port = self._find_router_gw_port(context, port_data)
- # Delete is actually never a real delete, otherwise the NSX
- # logical router will stop working
- router_id = port_data['device_id']
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- routerlib.update_router_lport(self.cluster,
- nsx_router_id,
- lr_port['uuid'],
- port_data['tenant_id'],
- port_data['id'],
- port_data['name'],
- True,
- ['0.0.0.0/31'])
- # Reset attachment
- self._update_router_port_attachment(
- self.cluster, context, nsx_router_id, port_data,
- lr_port['uuid'],
- "L3GatewayAttachment",
- self.cluster.default_l3_gw_service_uuid)
- LOG.debug("_nsx_delete_ext_gw_port completed on external network "
- "%(ext_net_id)s, attached to NSX router:%(router_id)s",
- {'ext_net_id': port_data['network_id'],
- 'router_id': nsx_router_id})
- except n_exc.NotFound:
- LOG.debug("Logical router resource %s not found "
- "on NSX platform : the router may have "
- "already been deleted",
- port_data['device_id'])
- except api_exc.NsxApiException:
- raise nsx_exc.NsxPluginException(
- err_msg=_("Unable to update logical router"
- "on NSX Platform"))
-
- def _nsx_create_l2_gw_port(self, context, port_data):
- """Create a switch port, and attach it to a L2 gateway attachment."""
- # FIXME(salvatore-orlando): On the NSX platform we do not really have
- # external networks. So if as user tries and create a "regular" VIF
- # port on an external network we are unable to actually create.
- # However, in order to not break unit tests, we need to still create
- # the DB object and return success
- if self._network_is_external(context, port_data['network_id']):
- LOG.info(_LI("NSX plugin does not support regular VIF ports on "
- "external networks. Port %s will be down."),
- port_data['network_id'])
- # No need to actually update the DB state - the default is down
- return port_data
- lport = None
- try:
- selected_lswitch = self._nsx_find_lswitch_for_port(
- context, port_data)
- lport = self._nsx_create_port_helper(
- context.session,
- selected_lswitch['uuid'],
- port_data,
- True)
- nsx_db.add_neutron_nsx_port_mapping(
- context.session, port_data['id'],
- selected_lswitch['uuid'], lport['uuid'])
- l2gwlib.plug_l2_gw_service(
- self.cluster,
- selected_lswitch['uuid'],
- lport['uuid'],
- port_data['device_id'],
- int(port_data.get('gw:segmentation_id') or 0))
- except Exception:
- with excutils.save_and_reraise_exception():
- if lport:
- switchlib.delete_port(self.cluster,
- selected_lswitch['uuid'],
- lport['uuid'])
- LOG.debug("_nsx_create_l2_gw_port completed for port %(name)s "
- "on network %(network_id)s. The new port id "
- "is %(id)s.", port_data)
-
- def _nsx_create_fip_port(self, context, port_data):
- # As we do not create ports for floating IPs in NSX,
- # this is a no-op driver
- pass
-
- def _nsx_delete_fip_port(self, context, port_data):
- # As we do not create ports for floating IPs in NSX,
- # this is a no-op driver
- pass
-
- def _extend_fault_map(self):
- """Extends the Neutron Fault Map.
-
- Exceptions specific to the NSX Plugin are mapped to standard
- HTTP Exceptions.
- """
- base.FAULT_MAP.update({nsx_exc.InvalidNovaZone:
- webob.exc.HTTPBadRequest,
- nsx_exc.NoMorePortsException:
- webob.exc.HTTPBadRequest,
- nsx_exc.MaintenanceInProgress:
- webob.exc.HTTPServiceUnavailable,
- nsx_exc.InvalidSecurityCertificate:
- webob.exc.HTTPBadRequest})
-
- def _validate_provider_create(self, context, network):
- segments = network.get(mpnet.SEGMENTS)
- if not attr.is_attr_set(segments):
- return
-
- mpnet.check_duplicate_segments(segments)
- for segment in segments:
- network_type = segment.get(pnet.NETWORK_TYPE)
- physical_network = segment.get(pnet.PHYSICAL_NETWORK)
- physical_network_set = attr.is_attr_set(physical_network)
- segmentation_id = segment.get(pnet.SEGMENTATION_ID)
- network_type_set = attr.is_attr_set(network_type)
- segmentation_id_set = attr.is_attr_set(segmentation_id)
-
- # If the physical_network_uuid isn't passed in use the default one.
- if not physical_network_set:
- physical_network = cfg.CONF.default_tz_uuid
-
- err_msg = None
- if not network_type_set:
- err_msg = _("%s required") % pnet.NETWORK_TYPE
- elif network_type in (c_utils.NetworkTypes.GRE,
- c_utils.NetworkTypes.STT,
- c_utils.NetworkTypes.FLAT):
- if segmentation_id_set:
- err_msg = _("Segmentation ID cannot be specified with "
- "flat network type")
- elif network_type == c_utils.NetworkTypes.VLAN:
- if not segmentation_id_set:
- err_msg = _("Segmentation ID must be specified with "
- "vlan network type")
- elif (segmentation_id_set and
- not utils.is_valid_vlan_tag(segmentation_id)):
- err_msg = (_("%(segmentation_id)s out of range "
- "(%(min_id)s through %(max_id)s)") %
- {'segmentation_id': segmentation_id,
- 'min_id': constants.MIN_VLAN_TAG,
- 'max_id': constants.MAX_VLAN_TAG})
- else:
- # Verify segment is not already allocated
- bindings = (
- nsx_db.get_network_bindings_by_vlanid_and_physical_net(
- context.session, segmentation_id,
- physical_network)
- )
- if bindings:
- raise n_exc.VlanIdInUse(
- vlan_id=segmentation_id,
- physical_network=physical_network)
- elif network_type == c_utils.NetworkTypes.L3_EXT:
- if (segmentation_id_set and
- not utils.is_valid_vlan_tag(segmentation_id)):
- err_msg = (_("%(segmentation_id)s out of range "
- "(%(min_id)s through %(max_id)s)") %
- {'segmentation_id': segmentation_id,
- 'min_id': constants.MIN_VLAN_TAG,
- 'max_id': constants.MAX_VLAN_TAG})
- else:
- err_msg = (_("%(net_type_param)s %(net_type_value)s not "
- "supported") %
- {'net_type_param': pnet.NETWORK_TYPE,
- 'net_type_value': network_type})
- if err_msg:
- raise n_exc.InvalidInput(error_message=err_msg)
- # TODO(salvatore-orlando): Validate tranport zone uuid
- # which should be specified in physical_network
-
- def _extend_network_dict_provider(self, context, network,
- multiprovider=None, bindings=None):
- if not bindings:
- bindings = nsx_db.get_network_bindings(context.session,
- network['id'])
- if not multiprovider:
- multiprovider = nsx_db.is_multiprovider_network(context.session,
- network['id'])
- # With NSX plugin 'normal' overlay networks will have no binding
- # TODO(salvatore-orlando) make sure users can specify a distinct
- # phy_uuid as 'provider network' for STT net type
- if bindings:
- if not multiprovider:
- # network came in through provider networks api
- network[pnet.NETWORK_TYPE] = bindings[0].binding_type
- network[pnet.PHYSICAL_NETWORK] = bindings[0].phy_uuid
- network[pnet.SEGMENTATION_ID] = bindings[0].vlan_id
- else:
- # network come in though multiprovider networks api
- network[mpnet.SEGMENTS] = [
- {pnet.NETWORK_TYPE: binding.binding_type,
- pnet.PHYSICAL_NETWORK: binding.phy_uuid,
- pnet.SEGMENTATION_ID: binding.vlan_id}
- for binding in bindings]
-
- def extend_port_dict_binding(self, port_res, port_db):
- super(NsxPluginV2, self).extend_port_dict_binding(port_res, port_db)
- port_res[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL
-
- def _handle_lswitch_selection(self, context, cluster, network,
- network_bindings, max_ports,
- allow_extra_lswitches):
- lswitches = nsx_utils.fetch_nsx_switches(
- context.session, cluster, network.id)
- try:
- return [ls for ls in lswitches
- if (ls['_relations']['LogicalSwitchStatus']
- ['lport_count'] < max_ports)].pop(0)
- except IndexError:
- # Too bad, no switch available
- LOG.debug("No switch has available ports (%d checked)",
- len(lswitches))
- if allow_extra_lswitches:
- # The 'main' logical switch is either the only one available
- # or the one where the 'multi_lswitch' tag was set
- while lswitches:
- main_ls = lswitches.pop(0)
- tag_dict = dict((x['scope'], x['tag'])
- for x in main_ls['tags'])
- if 'multi_lswitch' in tag_dict:
- break
- else:
- # by construction this statement is hit if there is only one
- # logical switch and the multi_lswitch tag has not been set.
- # The tag must therefore be added.
- tags = main_ls['tags']
- tags.append({'tag': 'True', 'scope': 'multi_lswitch'})
- switchlib.update_lswitch(cluster,
- main_ls['uuid'],
- main_ls['display_name'],
- network['tenant_id'],
- tags=tags)
- transport_zone_config = self._convert_to_nsx_transport_zones(
- cluster, network, bindings=network_bindings)
- selected_lswitch = switchlib.create_lswitch(
- cluster, network.id, network.tenant_id,
- "%s-ext-%s" % (network.name, len(lswitches)),
- transport_zone_config)
- # add a mapping between the neutron network and the newly
- # created logical switch
- nsx_db.add_neutron_nsx_network_mapping(
- context.session, network.id, selected_lswitch['uuid'])
- return selected_lswitch
- else:
- LOG.error(_LE("Maximum number of logical ports reached for "
- "logical network %s"), network.id)
- raise nsx_exc.NoMorePortsException(network=network.id)
-
- def _convert_to_nsx_transport_zones(self, cluster, network=None,
- bindings=None):
- # TODO(salv-orlando): Remove this method and call nsx-utils direct
- return nsx_utils.convert_to_nsx_transport_zones(
- cluster.default_tz_uuid, network, bindings,
- default_transport_type=cfg.CONF.NSX.default_transport_type)
-
- def _convert_to_transport_zones_dict(self, network):
- """Converts the provider request body to multiprovider.
- Returns: True if request is multiprovider False if provider
- and None if neither.
- """
- if any(attr.is_attr_set(network.get(f))
- for f in (pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID)):
- if attr.is_attr_set(network.get(mpnet.SEGMENTS)):
- raise mpnet.SegmentsSetInConjunctionWithProviders()
- # convert to transport zone list
- network[mpnet.SEGMENTS] = [
- {pnet.NETWORK_TYPE: network[pnet.NETWORK_TYPE],
- pnet.PHYSICAL_NETWORK: network[pnet.PHYSICAL_NETWORK],
- pnet.SEGMENTATION_ID: network[pnet.SEGMENTATION_ID]}]
- del network[pnet.NETWORK_TYPE]
- del network[pnet.PHYSICAL_NETWORK]
- del network[pnet.SEGMENTATION_ID]
- return False
- if attr.is_attr_set(mpnet.SEGMENTS):
- return True
-
- def create_network(self, context, network):
- net_data = network['network']
- tenant_id = self._get_tenant_id_for_create(context, net_data)
- self._ensure_default_security_group(context, tenant_id)
- # Process the provider network extension
- provider_type = self._convert_to_transport_zones_dict(net_data)
- self._validate_provider_create(context, net_data)
- # Replace ATTR_NOT_SPECIFIED with None before sending to NSX
- for key, value in network['network'].iteritems():
- if value is attr.ATTR_NOT_SPECIFIED:
- net_data[key] = None
- # FIXME(arosen) implement admin_state_up = False in NSX
- if net_data['admin_state_up'] is False:
- LOG.warning(_LW("Network with admin_state_up=False are not yet "
- "supported by this plugin. Ignoring setting for "
- "network %s"), net_data.get('name', '<unknown>'))
- transport_zone_config = self._convert_to_nsx_transport_zones(
- self.cluster, net_data)
- external = net_data.get(ext_net_extn.EXTERNAL)
- # NOTE(salv-orlando): Pre-generating uuid for Neutron
- # network. This will be removed once the network create operation
- # becomes an asynchronous task
- net_data['id'] = str(uuid.uuid4())
- if (not attr.is_attr_set(external) or
- attr.is_attr_set(external) and not external):
- lswitch = switchlib.create_lswitch(
- self.cluster, net_data['id'],
- tenant_id, net_data.get('name'),
- transport_zone_config,
- shared=net_data.get(attr.SHARED))
-
- with context.session.begin(subtransactions=True):
- new_net = super(NsxPluginV2, self).create_network(context,
- network)
- # Process port security extension
- self._process_network_port_security_create(
- context, net_data, new_net)
- # DB Operations for setting the network as external
- self._process_l3_create(context, new_net, net_data)
- # Process QoS queue extension
- net_queue_id = net_data.get(qos.QUEUE)
- if net_queue_id:
- # Raises if not found
- self.get_qos_queue(context, net_queue_id)
- self._process_network_queue_mapping(
- context, new_net, net_queue_id)
- # Add mapping between neutron network and NSX switch
- if (not attr.is_attr_set(external) or
- attr.is_attr_set(external) and not external):
- nsx_db.add_neutron_nsx_network_mapping(
- context.session, new_net['id'],
- lswitch['uuid'])
- if (net_data.get(mpnet.SEGMENTS) and
- isinstance(provider_type, bool)):
- net_bindings = []
- for tz in net_data[mpnet.SEGMENTS]:
- segmentation_id = tz.get(pnet.SEGMENTATION_ID, 0)
- segmentation_id_set = attr.is_attr_set(segmentation_id)
- if not segmentation_id_set:
- segmentation_id = 0
- net_bindings.append(nsx_db.add_network_binding(
- context.session, new_net['id'],
- tz.get(pnet.NETWORK_TYPE),
- tz.get(pnet.PHYSICAL_NETWORK),
- segmentation_id))
- if provider_type:
- nsx_db.set_multiprovider_network(context.session,
- new_net['id'])
- self._extend_network_dict_provider(context, new_net,
- provider_type,
- net_bindings)
- self.handle_network_dhcp_access(context, new_net,
- action='create_network')
- return new_net
-
- def delete_network(self, context, id):
- external = self._network_is_external(context, id)
- # Before removing entry from Neutron DB, retrieve NSX switch
- # identifiers for removing them from backend
- if not external:
- lswitch_ids = nsx_utils.get_nsx_switch_ids(
- context.session, self.cluster, id)
- with context.session.begin(subtransactions=True):
- self._process_l3_delete(context, id)
- nsx_db.delete_network_bindings(context.session, id)
- super(NsxPluginV2, self).delete_network(context, id)
-
- # Do not go to NSX for external networks
- if not external:
- try:
- switchlib.delete_networks(self.cluster, id, lswitch_ids)
- except n_exc.NotFound:
- LOG.warning(_LW("The following logical switches were not "
- "found on the NSX backend:%s"), lswitch_ids)
- self.handle_network_dhcp_access(context, id, action='delete_network')
- LOG.debug("Delete network complete for network: %s", id)
-
- def get_network(self, context, id, fields=None):
- with context.session.begin(subtransactions=True):
- # goto to the plugin DB and fetch the network
- network = self._get_network(context, id)
- if (self.nsx_sync_opts.always_read_status or
- fields and 'status' in fields):
- # External networks are not backed by nsx lswitches
- if not network.external:
- # Perform explicit state synchronization
- self._synchronizer.synchronize_network(context, network)
- # Don't do field selection here otherwise we won't be able
- # to add provider networks fields
- net_result = self._make_network_dict(network)
- self._extend_network_dict_provider(context, net_result)
- return self._fields(net_result, fields)
-
- def get_networks(self, context, filters=None, fields=None,
- sorts=None, limit=None, marker=None,
- page_reverse=False):
- filters = filters or {}
- with context.session.begin(subtransactions=True):
- networks = (
- super(NsxPluginV2, self).get_networks(
- context, filters, fields, sorts,
- limit, marker, page_reverse))
- for net in networks:
- self._extend_network_dict_provider(context, net)
- return [self._fields(network, fields) for network in networks]
-
- def update_network(self, context, id, network):
- pnet._raise_if_updates_provider_attributes(network['network'])
- if network["network"].get("admin_state_up") is False:
- raise NotImplementedError(_("admin_state_up=False networks "
- "are not supported."))
- with context.session.begin(subtransactions=True):
- net = super(NsxPluginV2, self).update_network(context, id, network)
- if psec.PORTSECURITY in network['network']:
- self._process_network_port_security_update(
- context, network['network'], net)
- net_queue_id = network['network'].get(qos.QUEUE)
- if net_queue_id:
- self._delete_network_queue_mapping(context, id)
- self._process_network_queue_mapping(context, net, net_queue_id)
- self._process_l3_update(context, net, network['network'])
- self._extend_network_dict_provider(context, net)
- # If provided, update port name on backend; treat backend failures as
- # not critical (log error, but do not raise)
- if 'name' in network['network']:
- # in case of chained switches update name only for the first one
- nsx_switch_ids = nsx_utils.get_nsx_switch_ids(
- context.session, self.cluster, id)
- if not nsx_switch_ids or len(nsx_switch_ids) < 1:
- LOG.warn(_LW("Unable to find NSX mappings for neutron "
- "network:%s"), id)
- try:
- switchlib.update_lswitch(self.cluster,
- nsx_switch_ids[0],
- network['network']['name'])
- except api_exc.NsxApiException as e:
- LOG.warn(_LW("Logical switch update on NSX backend failed. "
- "Neutron network id:%(net_id)s; "
- "NSX lswitch id:%(lswitch_id)s;"
- "Error:%(error)s"),
- {'net_id': id, 'lswitch_id': nsx_switch_ids[0],
- 'error': e})
-
- return net
-
- def create_port(self, context, port):
- # If PORTSECURITY is not the default value ATTR_NOT_SPECIFIED
- # then we pass the port to the policy engine. The reason why we don't
- # pass the value to the policy engine when the port is
- # ATTR_NOT_SPECIFIED is for the case where a port is created on a
- # shared network that is not owned by the tenant.
- port_data = port['port']
- # Set port status as 'DOWN'. This will be updated by backend sync.
- port_data['status'] = constants.PORT_STATUS_DOWN
- with context.session.begin(subtransactions=True):
- # First we allocate port in neutron database
- neutron_db = super(NsxPluginV2, self).create_port(context, port)
- neutron_port_id = neutron_db['id']
- # Update fields obtained from neutron db (eg: MAC address)
- port["port"].update(neutron_db)
- self.handle_port_metadata_access(context, neutron_db)
- # port security extension checks
- (port_security, has_ip) = self._determine_port_security_and_has_ip(
- context, port_data)
- port_data[psec.PORTSECURITY] = port_security
- self._process_port_port_security_create(
- context, port_data, neutron_db)
- # allowed address pair checks
- if attr.is_attr_set(port_data.get(addr_pair.ADDRESS_PAIRS)):
- if not port_security:
- raise addr_pair.AddressPairAndPortSecurityRequired()
- else:
- self._process_create_allowed_address_pairs(
- context, neutron_db,
- port_data[addr_pair.ADDRESS_PAIRS])
- else:
- # remove ATTR_NOT_SPECIFIED
- port_data[addr_pair.ADDRESS_PAIRS] = []
-
- # security group extension checks
- # NOTE: check_update_has_security_groups works fine for
- # create operations as well
- if port_security and has_ip:
- self._ensure_default_security_group_on_port(context, port)
- elif self._check_update_has_security_groups(
- {'port': port_data}):
- raise psec.PortSecurityAndIPRequiredForSecurityGroups()
- port_data[ext_sg.SECURITYGROUPS] = (
- self._get_security_groups_on_port(context, port))
- self._process_port_create_security_group(
- context, port_data, port_data[ext_sg.SECURITYGROUPS])
- # QoS extension checks
- port_queue_id = self._check_for_queue_and_create(
- context, port_data)
- self._process_port_queue_mapping(
- context, port_data, port_queue_id)
- if (isinstance(port_data.get(mac_ext.MAC_LEARNING), bool)):
- self._create_mac_learning_state(context, port_data)
- elif mac_ext.MAC_LEARNING in port_data:
- port_data.pop(mac_ext.MAC_LEARNING)
- self._process_portbindings_create_and_update(context,
- port['port'],
- port_data)
- # For some reason the port bindings DB mixin does not handle
- # the VNIC_TYPE attribute, which is required by nova for
- # setting up VIFs.
- context.session.flush()
- port_data[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL
-
- # DB Operation is complete, perform NSX operation
- try:
- port_data = port['port'].copy()
- port_create_func = self._port_drivers['create'].get(
- port_data['device_owner'],
- self._port_drivers['create']['default'])
- port_create_func(context, port_data)
- LOG.debug("port created on NSX backend for tenant "
- "%(tenant_id)s: (%(id)s)", port_data)
- except n_exc.NotFound:
- LOG.warning(_LW("Logical switch for network %s was not "
- "found in NSX."), port_data['network_id'])
- # Put port in error on neutron DB
- with context.session.begin(subtransactions=True):
- port = self._get_port(context, neutron_port_id)
- port_data['status'] = constants.PORT_STATUS_ERROR
- port['status'] = port_data['status']
- context.session.add(port)
- except Exception:
- # Port must be removed from neutron DB
- with excutils.save_and_reraise_exception():
- LOG.error(_LE("Unable to create port or set port "
- "attachment in NSX."))
- with context.session.begin(subtransactions=True):
- self._delete_port(context, neutron_port_id)
-
- self.handle_port_dhcp_access(context, port_data, action='create_port')
- return port_data
-
- def update_port(self, context, id, port):
- delete_security_groups = self._check_update_deletes_security_groups(
- port)
- has_security_groups = self._check_update_has_security_groups(port)
- delete_addr_pairs = self._check_update_deletes_allowed_address_pairs(
- port)
- has_addr_pairs = self._check_update_has_allowed_address_pairs(port)
-
- with context.session.begin(subtransactions=True):
- ret_port = super(NsxPluginV2, self).update_port(
- context, id, port)
- # Save current mac learning state to check whether it's
- # being updated or not
- old_mac_learning_state = ret_port.get(mac_ext.MAC_LEARNING)
- # copy values over - except fixed_ips as
- # they've already been processed
- port['port'].pop('fixed_ips', None)
- ret_port.update(port['port'])
- tenant_id = self._get_tenant_id_for_create(context, ret_port)
-
- # populate port_security setting
- if psec.PORTSECURITY not in port['port']:
- ret_port[psec.PORTSECURITY] = self._get_port_security_binding(
- context, id)
- has_ip = self._ip_on_port(ret_port)
- # validate port security and allowed address pairs
- if not ret_port[psec.PORTSECURITY]:
- # has address pairs in request
- if has_addr_pairs:
- raise addr_pair.AddressPairAndPortSecurityRequired()
- elif not delete_addr_pairs:
- # check if address pairs are in db
- ret_port[addr_pair.ADDRESS_PAIRS] = (
- self.get_allowed_address_pairs(context, id))
- if ret_port[addr_pair.ADDRESS_PAIRS]:
- raise addr_pair.AddressPairAndPortSecurityRequired()
-
- if (delete_addr_pairs or has_addr_pairs):
- # delete address pairs and read them in
- self._delete_allowed_address_pairs(context, id)
- self._process_create_allowed_address_pairs(
- context, ret_port, ret_port[addr_pair.ADDRESS_PAIRS])
- # checks if security groups were updated adding/modifying
- # security groups, port security is set and port has ip
- if not (has_ip and ret_port[psec.PORTSECURITY]):
- if has_security_groups:
- raise psec.PortSecurityAndIPRequiredForSecurityGroups()
- # Update did not have security groups passed in. Check
- # that port does not have any security groups already on it.
- filters = {'port_id': [id]}
- security_groups = (
- super(NsxPluginV2, self)._get_port_security_group_bindings(
- context, filters)
- )
- if security_groups and not delete_security_groups:
- raise psec.PortSecurityPortHasSecurityGroup()
-
- if (delete_security_groups or has_security_groups):
- # delete the port binding and read it with the new rules.
- self._delete_port_security_group_bindings(context, id)
- sgids = self._get_security_groups_on_port(context, port)
- self._process_port_create_security_group(context, ret_port,
- sgids)
-
- if psec.PORTSECURITY in port['port']:
- self._process_port_port_security_update(
- context, port['port'], ret_port)
-
- port_queue_id = self._check_for_queue_and_create(
- context, ret_port)
- # Populate the mac learning attribute
- new_mac_learning_state = port['port'].get(mac_ext.MAC_LEARNING)
- if (new_mac_learning_state is not None and
- old_mac_learning_state != new_mac_learning_state):
- self._update_mac_learning_state(context, id,
- new_mac_learning_state)
- ret_port[mac_ext.MAC_LEARNING] = new_mac_learning_state
- self._delete_port_queue_mapping(context, ret_port['id'])
- self._process_port_queue_mapping(context, ret_port,
- port_queue_id)
- LOG.debug("Updating port: %s", port)
- nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
- context.session, self.cluster, id)
- # Convert Neutron security groups identifiers into NSX security
- # profiles identifiers
- nsx_sec_profile_ids = [
- nsx_utils.get_nsx_security_group_id(
- context.session, self.cluster, neutron_sg_id) for
- neutron_sg_id in (ret_port[ext_sg.SECURITYGROUPS] or [])]
-
- if nsx_port_id:
- try:
- switchlib.update_port(
- self.cluster, nsx_switch_id, nsx_port_id,
- id, tenant_id,
- ret_port['name'],
- ret_port['device_id'],
- ret_port['admin_state_up'],
- ret_port['mac_address'],
- ret_port['fixed_ips'],
- ret_port[psec.PORTSECURITY],
- nsx_sec_profile_ids,
- ret_port[qos.QUEUE],
- ret_port.get(mac_ext.MAC_LEARNING),
- ret_port.get(addr_pair.ADDRESS_PAIRS))
-
- # Update the port status from nsx. If we fail here hide it
- # since the port was successfully updated but we were not
- # able to retrieve the status.
- ret_port['status'] = switchlib.get_port_status(
- self.cluster, nsx_switch_id,
- nsx_port_id)
- # FIXME(arosen) improve exception handling.
- except Exception:
- ret_port['status'] = constants.PORT_STATUS_ERROR
- LOG.exception(_LE("Unable to update port id: %s."),
- nsx_port_id)
-
- # If nsx_port_id is not in database or in nsx put in error state.
- else:
- ret_port['status'] = constants.PORT_STATUS_ERROR
-
- self._process_portbindings_create_and_update(context,
- port['port'],
- ret_port)
- return ret_port
-
- def delete_port(self, context, id, l3_port_check=True,
- nw_gw_port_check=True):
- """Deletes a port on a specified Virtual Network.
-
- If the port contains a remote interface attachment, the remote
- interface is first un-plugged and then the port is deleted.
-
- :returns: None
- :raises: exception.PortInUse
- :raises: exception.PortNotFound
- :raises: exception.NetworkNotFound
- """
- # if needed, check to see if this is a port owned by
- # a l3 router. If so, we should prevent deletion here
- if l3_port_check:
- self.prevent_l3_port_deletion(context, id)
- neutron_db_port = self.get_port(context, id)
- # Perform the same check for ports owned by layer-2 gateways
- if nw_gw_port_check:
- self.prevent_network_gateway_port_deletion(context,
- neutron_db_port)
- port_delete_func = self._port_drivers['delete'].get(
- neutron_db_port['device_owner'],
- self._port_drivers['delete']['default'])
-
- port_delete_func(context, neutron_db_port)
- self.disassociate_floatingips(context, id)
- with context.session.begin(subtransactions=True):
- queue = self._get_port_queue_bindings(context, {'port_id': [id]})
- # metadata_dhcp_host_route
- self.handle_port_metadata_access(
- context, neutron_db_port, is_delete=True)
- super(NsxPluginV2, self).delete_port(context, id)
- # Delete qos queue if possible
- if queue:
- self.delete_qos_queue(context, queue[0]['queue_id'], False)
- self.handle_port_dhcp_access(
- context, neutron_db_port, action='delete_port')
-
- def get_port(self, context, id, fields=None):
- with context.session.begin(subtransactions=True):
- if (self.nsx_sync_opts.always_read_status or
- fields and 'status' in fields):
- # Perform explicit state synchronization
- db_port = self._get_port(context, id)
- self._synchronizer.synchronize_port(
- context, db_port)
- return self._make_port_dict(db_port, fields)
- else:
- return super(NsxPluginV2, self).get_port(context, id, fields)
-
- def get_router(self, context, id, fields=None):
- if (self.nsx_sync_opts.always_read_status or
- fields and 'status' in fields):
- db_router = self._get_router(context, id)
- # Perform explicit state synchronization
- self._synchronizer.synchronize_router(
- context, db_router)
- return self._make_router_dict(db_router, fields)
- else:
- return super(NsxPluginV2, self).get_router(context, id, fields)
-
- def _create_lrouter(self, context, router, nexthop):
- tenant_id = self._get_tenant_id_for_create(context, router)
- distributed = router.get('distributed')
- try:
- lrouter = routerlib.create_lrouter(
- self.cluster, router['id'],
- tenant_id, router['name'], nexthop,
- distributed=attr.is_attr_set(distributed) and distributed)
- except nsx_exc.InvalidVersion:
- msg = _("Cannot create a distributed router with the NSX "
- "platform currently in execution. Please, try "
- "without specifying the 'distributed' attribute.")
- LOG.exception(msg)
- raise n_exc.BadRequest(resource='router', msg=msg)
- except api_exc.NsxApiException:
- err_msg = _("Unable to create logical router on NSX Platform")
- LOG.exception(err_msg)
- raise nsx_exc.NsxPluginException(err_msg=err_msg)
-
- # Create the port here - and update it later if we have gw_info
- try:
- self._create_and_attach_router_port(
- self.cluster, context, lrouter['uuid'], {'fake_ext_gw': True},
- "L3GatewayAttachment",
- self.cluster.default_l3_gw_service_uuid)
- except nsx_exc.NsxPluginException:
- LOG.exception(_LE("Unable to create L3GW port on logical router "
- "%(router_uuid)s. Verify Default Layer-3 "
- "Gateway service %(def_l3_gw_svc)s id is "
- "correct"),
- {'router_uuid': lrouter['uuid'],
- 'def_l3_gw_svc':
- self.cluster.default_l3_gw_service_uuid})
- # Try and remove logical router from NSX
- routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
- # Return user a 500 with an apter message
- raise nsx_exc.NsxPluginException(
- err_msg=(_("Unable to create router %s on NSX backend") %
- router['id']))
- lrouter['status'] = plugin_const.ACTIVE
- return lrouter
-
- def create_router(self, context, router):
- # NOTE(salvatore-orlando): We completely override this method in
- # order to be able to use the NSX ID as Neutron ID
- # TODO(salvatore-orlando): Propose upstream patch for allowing
- # 3rd parties to specify IDs as we do with l2 plugin
- r = router['router']
- has_gw_info = False
- tenant_id = self._get_tenant_id_for_create(context, r)
- # default value to set - nsx wants it (even if we don't have it)
- nexthop = NSX_DEFAULT_NEXTHOP
- # if external gateway info are set, then configure nexthop to
- # default external gateway
- if 'external_gateway_info' in r and r.get('external_gateway_info'):
- has_gw_info = True
- gw_info = r['external_gateway_info']
- del r['external_gateway_info']
- # The following DB read will be performed again when updating
- # gateway info. This is not great, but still better than
- # creating NSX router here and updating it later
- network_id = (gw_info.get('network_id', None) if gw_info
- else None)
- if network_id:
- ext_net = self._get_network(context, network_id)
- if not ext_net.external:
- msg = (_("Network '%s' is not a valid external "
- "network") % network_id)
- raise n_exc.BadRequest(resource='router', msg=msg)
- if ext_net.subnets:
- ext_subnet = ext_net.subnets[0]
- nexthop = ext_subnet.gateway_ip
- # NOTE(salv-orlando): Pre-generating uuid for Neutron
- # router. This will be removed once the router create operation
- # becomes an asynchronous task
- neutron_router_id = str(uuid.uuid4())
- r['id'] = neutron_router_id
- lrouter = self._create_lrouter(context, r, nexthop)
- # Update 'distributed' with value returned from NSX
- # This will be useful for setting the value if the API request
- # did not specify any value for the 'distributed' attribute
- # Platforms older than 3.x do not support the attribute
- r['distributed'] = lrouter.get('distributed', False)
- # TODO(salv-orlando): Deal with backend object removal in case
- # of db failures
- with context.session.begin(subtransactions=True):
- # Transaction nesting is needed to avoid foreign key violations
- # when processing the distributed router binding
- with context.session.begin(subtransactions=True):
- router_db = l3_db.Router(id=neutron_router_id,
- tenant_id=tenant_id,
- name=r['name'],
- admin_state_up=r['admin_state_up'],
- status=lrouter['status'])
- context.session.add(router_db)
- self._process_extra_attr_router_create(context, router_db, r)
- # Ensure neutron router is moved into the transaction's buffer
- context.session.flush()
- # Add mapping between neutron and nsx identifiers
- nsx_db.add_neutron_nsx_router_mapping(
- context.session, router_db['id'], lrouter['uuid'])
-
- if has_gw_info:
- # NOTE(salv-orlando): This operation has been moved out of the
- # database transaction since it performs several NSX queries,
- # ithis ncreasing the risk of deadlocks between eventlet and
- # sqlalchemy operations.
- # Set external gateway and remove router in case of failure
- try:
- self._update_router_gw_info(context, router_db['id'], gw_info)
- except (n_exc.NeutronException, api_exc.NsxApiException):
- with excutils.save_and_reraise_exception():
- # As setting gateway failed, the router must be deleted
- # in order to ensure atomicity
- router_id = router_db['id']
- LOG.warn(_LW("Failed to set gateway info for router being "
- "created:%s - removing router"), router_id)
- self.delete_router(context, router_id)
- LOG.info(_LI("Create router failed while setting external "
- "gateway. Router:%s has been removed from "
- "DB and backend"),
- router_id)
- return self._make_router_dict(router_db)
-
- def _update_lrouter(self, context, router_id, name, nexthop, routes=None):
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- return routerlib.update_lrouter(
- self.cluster, nsx_router_id, name,
- nexthop, routes=routes)
-
- def _update_lrouter_routes(self, context, router_id, routes):
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- routerlib.update_explicit_routes_lrouter(
- self.cluster, nsx_router_id, routes)
-
- def update_router(self, context, router_id, router):
- # Either nexthop is updated or should be kept as it was before
- r = router['router']
- nexthop = None
- if 'external_gateway_info' in r and r.get('external_gateway_info'):
- gw_info = r['external_gateway_info']
- # The following DB read will be performed again when updating
- # gateway info. This is not great, but still better than
- # creating NSX router here and updating it later
- network_id = (gw_info.get('network_id', None) if gw_info
- else None)
- if network_id:
- ext_net = self._get_network(context, network_id)
- if not ext_net.external:
- msg = (_("Network '%s' is not a valid external "
- "network") % network_id)
- raise n_exc.BadRequest(resource='router', msg=msg)
- if ext_net.subnets:
- ext_subnet = ext_net.subnets[0]
- nexthop = ext_subnet.gateway_ip
- try:
- for route in r.get('routes', []):
- if route['destination'] == '0.0.0.0/0':
- msg = _("'routes' cannot contain route '0.0.0.0/0', "
- "this must be updated through the default "
- "gateway attribute")
- raise n_exc.BadRequest(resource='router', msg=msg)
- previous_routes = self._update_lrouter(
- context, router_id, r.get('name'),
- nexthop, routes=r.get('routes'))
- # NOTE(salv-orlando): The exception handling below is not correct, but
- # unfortunately nsxlib raises a neutron notfound exception when an
- # object is not found in the underlying backend
- except n_exc.NotFound:
- # Put the router in ERROR status
- with context.session.begin(subtransactions=True):
- router_db = self._get_router(context, router_id)
- router_db['status'] = constants.NET_STATUS_ERROR
- raise nsx_exc.NsxPluginException(
- err_msg=_("Logical router %s not found "
- "on NSX Platform") % router_id)
- except api_exc.NsxApiException:
- raise nsx_exc.NsxPluginException(
- err_msg=_("Unable to update logical router on NSX Platform"))
- except nsx_exc.InvalidVersion:
- msg = _("Request cannot contain 'routes' with the NSX "
- "platform currently in execution. Please, try "
- "without specifying the static routes.")
- LOG.exception(msg)
- raise n_exc.BadRequest(resource='router', msg=msg)
- try:
- return super(NsxPluginV2, self).update_router(context,
- router_id, router)
- except (extraroute.InvalidRoutes,
- extraroute.RouterInterfaceInUseByRoute,
- extraroute.RoutesExhausted):
- with excutils.save_and_reraise_exception():
- # revert changes made to NSX
- self._update_lrouter_routes(
- context, router_id, previous_routes)
-
- def _delete_lrouter(self, context, router_id, nsx_router_id):
- # The neutron router id (router_id) is ignored in this routine,
- # but used in plugins deriving from this one
- routerlib.delete_lrouter(self.cluster, nsx_router_id)
-
- def delete_router(self, context, router_id):
- with context.session.begin(subtransactions=True):
- # TODO(salv-orlando): This call should have no effect on delete
- # router, but if it does, it should not happen within a
- # transaction, and it should be restored on rollback
- self.handle_router_metadata_access(
- context, router_id, interface=None)
- # Pre-delete checks
- # NOTE(salv-orlando): These checks will be repeated anyway when
- # calling the superclass. This is wasteful, but is the simplest
- # way of ensuring a consistent removal of the router both in
- # the neutron Database and in the NSX backend.
- # TODO(salv-orlando): split pre-delete checks and actual
- # deletion in superclass.
-
- # Ensure that the router is not used
- fips = self.get_floatingips_count(
- context.elevated(), filters={'router_id': [router_id]})
- if fips:
- raise l3.RouterInUse(router_id=router_id)
-
- device_filter = {'device_id': [router_id],
- 'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF]}
- ports = self._core_plugin.get_ports_count(context.elevated(),
- filters=device_filter)
- if ports:
- raise l3.RouterInUse(router_id=router_id)
-
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- # It is safe to remove the router from the database, so remove it
- # from the backend
- try:
- self._delete_lrouter(context, router_id, nsx_router_id)
- except n_exc.NotFound:
- # This is not a fatal error, but needs to be logged
- LOG.warning(_LW("Logical router '%s' not found "
- "on NSX Platform"), router_id)
- except api_exc.NsxApiException:
- raise nsx_exc.NsxPluginException(
- err_msg=(_("Unable to delete logical router '%s' "
- "on NSX Platform") % nsx_router_id))
- # Remove the NSX mapping first in order to ensure a mapping to
- # a non-existent NSX router is not left in the DB in case of
- # failure while removing the router from the neutron DB
- try:
- nsx_db.delete_neutron_nsx_router_mapping(
- context.session, router_id)
- except db_exc.DBError as d_exc:
- # Do not make this error fatal
- LOG.warn(_LW("Unable to remove NSX mapping for Neutron router "
- "%(router_id)s because of the following exception:"
- "%(d_exc)s"), {'router_id': router_id,
- 'd_exc': str(d_exc)})
- # Perform the actual delete on the Neutron DB
- super(NsxPluginV2, self).delete_router(context, router_id)
-
- def _add_subnet_snat_rule(self, context, router, subnet):
- gw_port = router.gw_port
- if gw_port and router.enable_snat:
- # There is a change gw_port might have multiple IPs
- # In that case we will consider only the first one
- if gw_port.get('fixed_ips'):
- snat_ip = gw_port['fixed_ips'][0]['ip_address']
- cidr_prefix = int(subnet['cidr'].split('/')[1])
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router['id'])
- routerlib.create_lrouter_snat_rule(
- self.cluster, nsx_router_id, snat_ip, snat_ip,
- order=NSX_EXTGW_NAT_RULES_ORDER - cidr_prefix,
- match_criteria={'source_ip_addresses': subnet['cidr']})
-
- def _delete_subnet_snat_rule(self, context, router, subnet):
- # Remove SNAT rule if external gateway is configured
- if router.gw_port:
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router['id'])
- routerlib.delete_nat_rules_by_match(
- self.cluster, nsx_router_id, "SourceNatRule",
- max_num_expected=1, min_num_expected=1,
- raise_on_len_mismatch=False,
- source_ip_addresses=subnet['cidr'])
-
- def add_router_interface(self, context, router_id, interface_info):
- # When adding interface by port_id we need to create the
- # peer port on the nsx logical router in this routine
- port_id = interface_info.get('port_id')
- router_iface_info = super(NsxPluginV2, self).add_router_interface(
- context, router_id, interface_info)
- # router_iface_info will always have a subnet_id attribute
- subnet_id = router_iface_info['subnet_id']
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- if port_id:
- port_data = self.get_port(context, port_id)
- # If security groups are present we need to remove them as
- # this is a router port and disable port security.
- if port_data['security_groups']:
- self.update_port(context, port_id,
- {'port': {'security_groups': [],
- psec.PORTSECURITY: False}})
- nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
- context.session, self.cluster, port_id)
- # Unplug current attachment from lswitch port
- switchlib.plug_vif_interface(self.cluster, nsx_switch_id,
- nsx_port_id, "NoAttachment")
- # Create logical router port and plug patch attachment
- self._create_and_attach_router_port(
- self.cluster, context, nsx_router_id, port_data,
- "PatchAttachment", nsx_port_id, subnet_ids=[subnet_id])
- subnet = self._get_subnet(context, subnet_id)
- # If there is an external gateway we need to configure the SNAT rule.
- # Fetch router from DB
- router = self._get_router(context, router_id)
- self._add_subnet_snat_rule(context, router, subnet)
- routerlib.create_lrouter_nosnat_rule(
- self.cluster, nsx_router_id,
- order=NSX_NOSNAT_RULES_ORDER,
- match_criteria={'destination_ip_addresses': subnet['cidr']})
-
- # Ensure the NSX logical router has a connection to a 'metadata access'
- # network (with a proxy listening on its DHCP port), by creating it
- # if needed.
- self.handle_router_metadata_access(
- context, router_id, interface=router_iface_info)
- LOG.debug("Add_router_interface completed for subnet:%(subnet_id)s "
- "and router:%(router_id)s",
- {'subnet_id': subnet_id, 'router_id': router_id})
- return router_iface_info
-
- def remove_router_interface(self, context, router_id, interface_info):
- # The code below is duplicated from base class, but comes handy
- # as we need to retrieve the router port id before removing the port
- subnet = None
- subnet_id = None
- if 'port_id' in interface_info:
- port_id = interface_info['port_id']
- # find subnet_id - it is need for removing the SNAT rule
- port = self._get_port(context, port_id)
- if port.get('fixed_ips'):
- subnet_id = port['fixed_ips'][0]['subnet_id']
- if not (port['device_owner'] == l3_db.DEVICE_OWNER_ROUTER_INTF and
- port['device_id'] == router_id):
- raise l3.RouterInterfaceNotFound(router_id=router_id,
- port_id=port_id)
- elif 'subnet_id' in interface_info:
- subnet_id = interface_info['subnet_id']
- subnet = self._get_subnet(context, subnet_id)
- rport_qry = context.session.query(models_v2.Port)
- ports = rport_qry.filter_by(
- device_id=router_id,
- device_owner=l3_db.DEVICE_OWNER_ROUTER_INTF,
- network_id=subnet['network_id'])
- for p in ports:
- if p['fixed_ips'][0]['subnet_id'] == subnet_id:
- port_id = p['id']
- break
- else:
- raise l3.RouterInterfaceNotFoundForSubnet(router_id=router_id,
- subnet_id=subnet_id)
- # Finally remove the data from the Neutron DB
- # This will also destroy the port on the logical switch
- info = super(NsxPluginV2, self).remove_router_interface(
- context, router_id, interface_info)
-
- try:
- # Ensure the connection to the 'metadata access network'
- # is removed (with the network) if this the last subnet
- # on the router
- self.handle_router_metadata_access(
- context, router_id, interface=info)
- if not subnet:
- subnet = self._get_subnet(context, subnet_id)
- router = self._get_router(context, router_id)
- # If router is enabled_snat = False there are no snat rules to
- # delete.
- if router.enable_snat:
- self._delete_subnet_snat_rule(context, router, subnet)
- # Relax the minimum expected number as the nosnat rules
- # do not exist in 2.x deployments
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- routerlib.delete_nat_rules_by_match(
- self.cluster, nsx_router_id, "NoSourceNatRule",
- max_num_expected=1, min_num_expected=0,
- raise_on_len_mismatch=False,
- destination_ip_addresses=subnet['cidr'])
- except n_exc.NotFound:
- LOG.error(_LE("Logical router resource %s not found "
- "on NSX platform"), router_id)
- except api_exc.NsxApiException:
- raise nsx_exc.NsxPluginException(
- err_msg=(_("Unable to update logical router"
- "on NSX Platform")))
- return info
-
- def _retrieve_and_delete_nat_rules(self, context, floating_ip_address,
- internal_ip, nsx_router_id,
- min_num_rules_expected=0):
- """Finds and removes NAT rules from a NSX router."""
- # NOTE(salv-orlando): The context parameter is ignored in this method
- # but used by derived classes
- try:
- # Remove DNAT rule for the floating IP
- routerlib.delete_nat_rules_by_match(
- self.cluster, nsx_router_id, "DestinationNatRule",
- max_num_expected=1,
- min_num_expected=min_num_rules_expected,
- destination_ip_addresses=floating_ip_address)
-
- # Remove SNAT rules for the floating IP
- routerlib.delete_nat_rules_by_match(
- self.cluster, nsx_router_id, "SourceNatRule",
- max_num_expected=1,
- min_num_expected=min_num_rules_expected,
- source_ip_addresses=internal_ip)
- routerlib.delete_nat_rules_by_match(
- self.cluster, nsx_router_id, "SourceNatRule",
- max_num_expected=1,
- min_num_expected=min_num_rules_expected,
- destination_ip_addresses=internal_ip)
-
- except api_exc.NsxApiException:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("An error occurred while removing NAT rules "
- "on the NSX platform for floating ip:%s"),
- floating_ip_address)
- except nsx_exc.NatRuleMismatch:
- # Do not surface to the user
- LOG.warning(_LW("An incorrect number of matching NAT rules "
- "was found on the NSX platform"))
-
- def _remove_floatingip_address(self, context, fip_db):
- # Remove floating IP address from logical router port
- # Fetch logical port of router's external gateway
- router_id = fip_db.router_id
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- nsx_gw_port_id = routerlib.find_router_gw_port(
- context, self.cluster, nsx_router_id)['uuid']
- ext_neutron_port_db = self._get_port(context.elevated(),
- fip_db.floating_port_id)
- nsx_floating_ips = self._build_ip_address_list(
- context.elevated(), ext_neutron_port_db['fixed_ips'])
- routerlib.update_lrouter_port_ips(self.cluster,
- nsx_router_id,
- nsx_gw_port_id,
- ips_to_add=[],
- ips_to_remove=nsx_floating_ips)
-
- def _get_fip_assoc_data(self, context, fip, floatingip_db):
- if fip.get('fixed_ip_address') and not fip.get('port_id'):
- msg = _("fixed_ip_address cannot be specified without a port_id")
- raise n_exc.BadRequest(resource='floatingip', msg=msg)
- port_id = internal_ip = router_id = None
- if fip.get('port_id'):
- fip_qry = context.session.query(l3_db.FloatingIP)
- port_id, internal_ip, router_id = self.get_assoc_data(
- context,
- fip,
- floatingip_db['floating_network_id'])
- try:
- fip_qry.filter_by(
- fixed_port_id=fip['port_id'],
- floating_network_id=floatingip_db['floating_network_id'],
- fixed_ip_address=internal_ip).one()
- raise l3.FloatingIPPortAlreadyAssociated(
- port_id=fip['port_id'],
- fip_id=floatingip_db['id'],
- floating_ip_address=floatingip_db['floating_ip_address'],
- fixed_ip=floatingip_db['fixed_ip_address'],
- net_id=floatingip_db['floating_network_id'])
- except sa_exc.NoResultFound:
- pass
- return (port_id, internal_ip, router_id)
-
- def _floatingip_status(self, floatingip_db, associated):
- if (associated and
- floatingip_db['status'] != constants.FLOATINGIP_STATUS_ACTIVE):
- return constants.FLOATINGIP_STATUS_ACTIVE
- elif (not associated and
- floatingip_db['status'] != constants.FLOATINGIP_STATUS_DOWN):
- return constants.FLOATINGIP_STATUS_DOWN
- # in any case ensure the status is not reset by this method!
- return floatingip_db['status']
-
- def _update_fip_assoc(self, context, fip, floatingip_db, external_port):
- """Update floating IP association data.
-
- Overrides method from base class.
- The method is augmented for creating NAT rules in the process.
- """
- # Store router currently serving the floating IP
- old_router_id = floatingip_db.router_id
- port_id, internal_ip, router_id = self._get_fip_assoc_data(
- context, fip, floatingip_db)
- floating_ip = floatingip_db['floating_ip_address']
- # If there's no association router_id will be None
- if router_id:
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, router_id)
- self._retrieve_and_delete_nat_rules(
- context, floating_ip, internal_ip, nsx_router_id)
- # Fetch logical port of router's external gateway
- # Fetch logical port of router's external gateway
- nsx_floating_ips = self._build_ip_address_list(
- context.elevated(), external_port['fixed_ips'])
- floating_ip = floatingip_db['floating_ip_address']
- # Retrieve and delete existing NAT rules, if any
- if old_router_id:
- nsx_old_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, old_router_id)
- # Retrieve the current internal ip
- _p, _s, old_internal_ip = self._internal_fip_assoc_data(
- context, {'id': floatingip_db.id,
- 'port_id': floatingip_db.fixed_port_id,
- 'fixed_ip_address': floatingip_db.fixed_ip_address,
- 'tenant_id': floatingip_db.tenant_id})
- nsx_gw_port_id = routerlib.find_router_gw_port(
- context, self.cluster, nsx_old_router_id)['uuid']
- self._retrieve_and_delete_nat_rules(
- context, floating_ip, old_internal_ip, nsx_old_router_id)
- routerlib.update_lrouter_port_ips(
- self.cluster, nsx_old_router_id, nsx_gw_port_id,
- ips_to_add=[], ips_to_remove=nsx_floating_ips)
-
- if router_id:
- nsx_gw_port_id = routerlib.find_router_gw_port(
- context, self.cluster, nsx_router_id)['uuid']
- # Re-create NAT rules only if a port id is specified
- if fip.get('port_id'):
- try:
- # Setup DNAT rules for the floating IP
- routerlib.create_lrouter_dnat_rule(
- self.cluster, nsx_router_id, internal_ip,
- order=NSX_FLOATINGIP_NAT_RULES_ORDER,
- match_criteria={'destination_ip_addresses':
- floating_ip})
- # Setup SNAT rules for the floating IP
- # Create a SNAT rule for enabling connectivity to the
- # floating IP from the same network as the internal port
- # Find subnet id for internal_ip from fixed_ips
- internal_port = self._get_port(context, port_id)
- # Cchecks not needed on statements below since otherwise
- # _internal_fip_assoc_data would have raised
- subnet_ids = [ip['subnet_id'] for ip in
- internal_port['fixed_ips'] if
- ip['ip_address'] == internal_ip]
- internal_subnet_cidr = self._build_ip_address_list(
- context, internal_port['fixed_ips'],
- subnet_ids=subnet_ids)[0]
- routerlib.create_lrouter_snat_rule(
- self.cluster, nsx_router_id, floating_ip, floating_ip,
- order=NSX_NOSNAT_RULES_ORDER - 1,
- match_criteria={'source_ip_addresses':
- internal_subnet_cidr,
- 'destination_ip_addresses':
- internal_ip})
- # setup snat rule such that src ip of a IP packet when
- # using floating is the floating ip itself.
- routerlib.create_lrouter_snat_rule(
- self.cluster, nsx_router_id, floating_ip, floating_ip,
- order=NSX_FLOATINGIP_NAT_RULES_ORDER,
- match_criteria={'source_ip_addresses': internal_ip})
-
- # Add Floating IP address to router_port
- routerlib.update_lrouter_port_ips(
- self.cluster, nsx_router_id, nsx_gw_port_id,
- ips_to_add=nsx_floating_ips, ips_to_remove=[])
- except api_exc.NsxApiException:
- LOG.exception(_LE("An error occurred while creating NAT "
- "rules on the NSX platform for floating "
- "ip:%(floating_ip)s mapped to "
- "internal ip:%(internal_ip)s"),
- {'floating_ip': floating_ip,
- 'internal_ip': internal_ip})
- msg = _("Failed to update NAT rules for floatingip update")
- raise nsx_exc.NsxPluginException(err_msg=msg)
- # Update also floating ip status (no need to call base class method)
- floatingip_db.update(
- {'fixed_ip_address': internal_ip,
- 'fixed_port_id': port_id,
- 'router_id': router_id,
- 'status': self._floatingip_status(floatingip_db, router_id)})
-
- def delete_floatingip(self, context, id):
- fip_db = self._get_floatingip(context, id)
- # Check whether the floating ip is associated or not
- if fip_db.fixed_port_id:
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, fip_db.router_id)
- self._retrieve_and_delete_nat_rules(context,
- fip_db.floating_ip_address,
- fip_db.fixed_ip_address,
- nsx_router_id,
- min_num_rules_expected=1)
- # Remove floating IP address from logical router port
- self._remove_floatingip_address(context, fip_db)
- return super(NsxPluginV2, self).delete_floatingip(context, id)
-
- def disassociate_floatingips(self, context, port_id):
- try:
- fip_qry = context.session.query(l3_db.FloatingIP)
- fip_dbs = fip_qry.filter_by(fixed_port_id=port_id)
-
- for fip_db in fip_dbs:
- nsx_router_id = nsx_utils.get_nsx_router_id(
- context.session, self.cluster, fip_db.router_id)
- self._retrieve_and_delete_nat_rules(context,
- fip_db.floating_ip_address,
- fip_db.fixed_ip_address,
- nsx_router_id,
- min_num_rules_expected=1)
- self._remove_floatingip_address(context, fip_db)
- except sa_exc.NoResultFound:
- LOG.debug("The port '%s' is not associated with floating IPs",
- port_id)
- except n_exc.NotFound:
- LOG.warning(_LW("Nat rules not found in nsx for port: %s"), id)
-
- # NOTE(ihrachys): L3 agent notifications don't make sense for
- # NSX VMWare plugin since there is no L3 agent in such setup, so
- # disabling them here.
- super(NsxPluginV2, self).disassociate_floatingips(
- context, port_id, do_notify=False)
-
- def create_network_gateway(self, context, network_gateway):
- """Create a layer-2 network gateway.
-
- Create the gateway service on NSX platform and corresponding data
- structures in Neutron datase.
- """
- gw_data = network_gateway[networkgw.GATEWAY_RESOURCE_NAME]
- tenant_id = self._get_tenant_id_for_create(context, gw_data)
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- # Validate provided gateway device list
- self._validate_device_list(context, tenant_id, gw_data)
- devices = gw_data['devices']
- # Populate default physical network where not specified
- for device in devices:
- if not device.get('interface_name'):
- device['interface_name'] = self.cluster.default_interface_name
- try:
- # Replace Neutron device identifiers with NSX identifiers
- dev_map = dict((dev['id'], dev['interface_name']) for
- dev in devices)
- nsx_devices = []
- for db_device in self._query_gateway_devices(
- context, filters={'id': [device['id'] for device in devices]}):
- nsx_devices.append(
- {'id': db_device['nsx_id'],
- 'interface_name': dev_map[db_device['id']]})
- nsx_res = l2gwlib.create_l2_gw_service(
- self.cluster, tenant_id, gw_data['name'], nsx_devices)
- nsx_uuid = nsx_res.get('uuid')
- except api_exc.Conflict:
- raise nsx_exc.L2GatewayAlreadyInUse(gateway=gw_data['name'])
- except api_exc.NsxApiException:
- err_msg = _("Unable to create l2_gw_service for: %s") % gw_data
- LOG.exception(err_msg)
- raise nsx_exc.NsxPluginException(err_msg=err_msg)
- gw_data['id'] = nsx_uuid
- return super(NsxPluginV2, self).create_network_gateway(
- context, network_gateway, validate_device_list=False)
-
- def delete_network_gateway(self, context, gateway_id):
- """Remove a layer-2 network gateway.
-
- Remove the gateway service from NSX platform and corresponding data
- structures in Neutron datase.
- """
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- with context.session.begin(subtransactions=True):
- try:
- super(NsxPluginV2, self).delete_network_gateway(
- context, gateway_id)
- l2gwlib.delete_l2_gw_service(self.cluster, gateway_id)
- except api_exc.ResourceNotFound:
- # Do not cause a 500 to be returned to the user if
- # the corresponding NSX resource does not exist
- LOG.exception(_LE("Unable to remove gateway service from "
- "NSX plaform - the resource was not found"))
-
- def get_network_gateway(self, context, id, fields=None):
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- return super(NsxPluginV2, self).get_network_gateway(context,
- id, fields)
-
- def get_network_gateways(self, context, filters=None, fields=None,
- sorts=None, limit=None, marker=None,
- page_reverse=False):
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- # Ensure the tenant_id attribute is populated on returned gateways
- return super(NsxPluginV2, self).get_network_gateways(
- context, filters, fields, sorts, limit, marker, page_reverse)
-
- def update_network_gateway(self, context, id, network_gateway):
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- # Update gateway on backend when there's a name change
- name = network_gateway[networkgw.GATEWAY_RESOURCE_NAME].get('name')
- if name:
- try:
- l2gwlib.update_l2_gw_service(self.cluster, id, name)
- except api_exc.NsxApiException:
- # Consider backend failures as non-fatal, but still warn
- # because this might indicate something dodgy is going on
- LOG.warn(_LW("Unable to update name on NSX backend "
- "for network gateway: %s"), id)
- return super(NsxPluginV2, self).update_network_gateway(
- context, id, network_gateway)
-
- def connect_network(self, context, network_gateway_id,
- network_mapping_info):
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- try:
- return super(NsxPluginV2, self).connect_network(
- context, network_gateway_id, network_mapping_info)
- except api_exc.Conflict:
- raise nsx_exc.L2GatewayAlreadyInUse(gateway=network_gateway_id)
-
- def disconnect_network(self, context, network_gateway_id,
- network_mapping_info):
- # Ensure the default gateway in the config file is in sync with the db
- self._ensure_default_network_gateway()
- return super(NsxPluginV2, self).disconnect_network(
- context, network_gateway_id, network_mapping_info)
-
- def _get_nsx_device_id(self, context, device_id):
- return self._get_gateway_device(context, device_id)['nsx_id']
-
- def _rollback_gw_device(self, context, device_id, gw_data=None,
- new_status=None, is_create=False):
- LOG.error(_LE("Rolling back database changes for gateway device %s "
- "because of an error in the NSX backend"), device_id)
- with context.session.begin(subtransactions=True):
- query = self._model_query(
- context, nsx_models.NetworkGatewayDevice).filter(
- nsx_models.NetworkGatewayDevice.id == device_id)
- if is_create:
- query.delete(synchronize_session=False)
- else:
- super(NsxPluginV2, self).update_gateway_device(
- context, device_id,
- {networkgw.DEVICE_RESOURCE_NAME: gw_data})
- if new_status:
- query.update({'status': new_status},
- synchronize_session=False)
-
- # TODO(salv-orlando): Handlers for Gateway device operations should be
- # moved into the appropriate nsx_handlers package once the code for the
- # blueprint nsx-async-backend-communication merges
- def create_gateway_device_handler(self, context, gateway_device,
- client_certificate):
- neutron_id = gateway_device['id']
- try:
- nsx_res = l2gwlib.create_gateway_device(
- self.cluster,
- gateway_device['tenant_id'],
- gateway_device['name'],
- neutron_id,
- self.cluster.default_tz_uuid,
- gateway_device['connector_type'],
- gateway_device['connector_ip'],
- client_certificate)
-
- # Fetch status (it needs another NSX API call)
- device_status = nsx_utils.get_nsx_device_status(self.cluster,
- nsx_res['uuid'])
-
- # set NSX GW device in neutron database and update status
- with context.session.begin(subtransactions=True):
- query = self._model_query(
- context, nsx_models.NetworkGatewayDevice).filter(
- nsx_models.NetworkGatewayDevice.id == neutron_id)
- query.update({'status': device_status,
- 'nsx_id': nsx_res['uuid']},
- synchronize_session=False)
- LOG.debug("Neutron gateway device: %(neutron_id)s; "
- "NSX transport node identifier: %(nsx_id)s; "
- "Operational status: %(status)s.",
- {'neutron_id': neutron_id,
- 'nsx_id': nsx_res['uuid'],
- 'status': device_status})
- return device_status
- except (nsx_exc.InvalidSecurityCertificate, api_exc.NsxApiException):
- with excutils.save_and_reraise_exception():
- self._rollback_gw_device(context, neutron_id, is_create=True)
-
- def update_gateway_device_handler(self, context, gateway_device,
- old_gateway_device_data,
- client_certificate):
- nsx_id = gateway_device['nsx_id']
- neutron_id = gateway_device['id']
- try:
- l2gwlib.update_gateway_device(
- self.cluster,
- nsx_id,
- gateway_device['tenant_id'],
- gateway_device['name'],
- neutron_id,
- self.cluster.default_tz_uuid,
- gateway_device['connector_type'],
- gateway_device['connector_ip'],
- client_certificate)
-
- # Fetch status (it needs another NSX API call)
- device_status = nsx_utils.get_nsx_device_status(self.cluster,
- nsx_id)
- # update status
- with context.session.begin(subtransactions=True):
- query = self._model_query(
- context, nsx_models.NetworkGatewayDevice).filter(
- nsx_models.NetworkGatewayDevice.id == neutron_id)
- query.update({'status': device_status},
- synchronize_session=False)
- LOG.debug("Neutron gateway device: %(neutron_id)s; "
- "NSX transport node identifier: %(nsx_id)s; "
- "Operational status: %(status)s.",
- {'neutron_id': neutron_id,
- 'nsx_id': nsx_id,
- 'status': device_status})
- return device_status
- except (nsx_exc.InvalidSecurityCertificate, api_exc.NsxApiException):
- with excutils.save_and_reraise_exception():
- self._rollback_gw_device(context, neutron_id,
- gw_data=old_gateway_device_data)
- except n_exc.NotFound:
- # The gateway device was probably deleted in the backend.
- # The DB change should be rolled back and the status must
- # be put in error
- with excutils.save_and_reraise_exception():
- self._rollback_gw_device(context, neutron_id,
- gw_data=old_gateway_device_data,
- new_status=networkgw_db.ERROR)
-
- def get_gateway_device(self, context, device_id, fields=None):
- # Get device from database
- gw_device = super(NsxPluginV2, self).get_gateway_device(
- context, device_id, fields, include_nsx_id=True)
- # Fetch status from NSX
- nsx_id = gw_device['nsx_id']
- device_status = nsx_utils.get_nsx_device_status(self.cluster, nsx_id)
- # TODO(salv-orlando): Asynchronous sync for gateway device status
- # Update status in database
- with context.session.begin(subtransactions=True):
- query = self._model_query(
- context, nsx_models.NetworkGatewayDevice).filter(
- nsx_models.NetworkGatewayDevice.id == device_id)
- query.update({'status': device_status},
- synchronize_session=False)
- gw_device['status'] = device_status
- return gw_device
-
- def get_gateway_devices(self, context, filters=None, fields=None,
- sorts=None, limit=None, marker=None,
- page_reverse=False):
- # Get devices from database
- devices = super(NsxPluginV2, self).get_gateway_devices(
- context, filters, fields, include_nsx_id=True)
- # Fetch operational status from NSX, filter by tenant tag
- # TODO(salv-orlando): Asynchronous sync for gateway device status
- tenant_id = context.tenant_id if not context.is_admin else None
- nsx_statuses = nsx_utils.get_nsx_device_statuses(self.cluster,
- tenant_id)
- # Update statuses in database
- with context.session.begin(subtransactions=True):
- for device in devices:
- new_status = nsx_statuses.get(device['nsx_id'])
- if new_status:
- device['status'] = new_status
- return devices
-
- def create_gateway_device(self, context, gateway_device):
- # NOTE(salv-orlando): client-certificate will not be stored
- # in the database
- device_data = gateway_device[networkgw.DEVICE_RESOURCE_NAME]
- client_certificate = device_data.pop('client_certificate')
- gw_device = super(NsxPluginV2, self).create_gateway_device(
- context, gateway_device)
- # DB operation was successful, perform NSX operation
- gw_device['status'] = self.create_gateway_device_handler(
- context, gw_device, client_certificate)
- return gw_device
-
- def update_gateway_device(self, context, device_id,
- gateway_device):
- # NOTE(salv-orlando): client-certificate will not be stored
- # in the database
- client_certificate = (
- gateway_device[networkgw.DEVICE_RESOURCE_NAME].pop(
- 'client_certificate', None))
- # Retrive current state from DB in case a rollback should be needed
- old_gw_device_data = super(NsxPluginV2, self).get_gateway_device(
- context, device_id, include_nsx_id=True)
- gw_device = super(NsxPluginV2, self).update_gateway_device(
- context, device_id, gateway_device, include_nsx_id=True)
- # DB operation was successful, perform NSX operation
- gw_device['status'] = self.update_gateway_device_handler(
- context, gw_device, old_gw_device_data, client_certificate)
- gw_device.pop('nsx_id')
- return gw_device
-
- def delete_gateway_device(self, context, device_id):
- nsx_device_id = self._get_nsx_device_id(context, device_id)
- super(NsxPluginV2, self).delete_gateway_device(
- context, device_id)
- # DB operation was successful, perform NSX operation
- # TODO(salv-orlando): State consistency with neutron DB
- # should be ensured even in case of backend failures
- try:
- l2gwlib.delete_gateway_device(self.cluster, nsx_device_id)
- except n_exc.NotFound:
- LOG.warn(_LW("Removal of gateway device: %(neutron_id)s failed on "
- "NSX backend (NSX id:%(nsx_id)s) because the NSX "
- "resource was not found"),
- {'neutron_id': device_id, 'nsx_id': nsx_device_id})
- except api_exc.NsxApiException:
- with excutils.save_and_reraise_exception():
- # In this case a 500 should be returned
- LOG.exception(_LE("Removal of gateway device: %(neutron_id)s "
- "failed on NSX backend (NSX id:%(nsx_id)s). "
- "Neutron and NSX states have diverged."),
- {'neutron_id': device_id,
- 'nsx_id': nsx_device_id})
-
- def create_security_group(self, context, security_group, default_sg=False):
- """Create security group.
-
- If default_sg is true that means we are creating a default security
- group and we don't need to check if one exists.
- """
- s = security_group.get('security_group')
-
- tenant_id = self._get_tenant_id_for_create(context, s)
- if not default_sg:
- self._ensure_default_security_group(context, tenant_id)
- # NOTE(salv-orlando): Pre-generating Neutron ID for security group.
- neutron_id = str(uuid.uuid4())
- nsx_secgroup = secgrouplib.create_security_profile(
- self.cluster, tenant_id, neutron_id, s)
- with context.session.begin(subtransactions=True):
- s['id'] = neutron_id
- sec_group = super(NsxPluginV2, self).create_security_group(
- context, security_group, default_sg)
- context.session.flush()
- # Add mapping between neutron and nsx identifiers
- nsx_db.add_neutron_nsx_security_group_mapping(
- context.session, neutron_id, nsx_secgroup['uuid'])
- return sec_group
-
- def update_security_group(self, context, secgroup_id, security_group):
- secgroup = (super(NsxPluginV2, self).
- update_security_group(context,
- secgroup_id,
- security_group))
- if ('name' in security_group['security_group'] and
- secgroup['name'] != 'default'):
- nsx_sec_profile_id = nsx_utils.get_nsx_security_group_id(
- context.session, self.cluster, secgroup_id)
- try:
- name = security_group['security_group']['name']
- secgrouplib.update_security_profile(
- self.cluster, nsx_sec_profile_id, name)
- except (n_exc.NotFound, api_exc.NsxApiException) as e:
- # Reverting the DB change is not really worthwhile
- # for a mismatch between names. It's the rules that
- # we care about.
- LOG.error(_LE('Error while updating security profile '
- '%(uuid)s with name %(name)s: %(error)s.'),
- {'uuid': secgroup_id, 'name': name, 'error': e})
- return secgroup
-
- def delete_security_group(self, context, security_group_id):
- """Delete a security group.
-
- :param security_group_id: security group rule to remove.
- """
- with context.session.begin(subtransactions=True):
- security_group = super(NsxPluginV2, self).get_security_group(
- context, security_group_id)
- if not security_group:
- raise ext_sg.SecurityGroupNotFound(id=security_group_id)
-
- if security_group['name'] == 'default' and not context.is_admin:
- raise ext_sg.SecurityGroupCannotRemoveDefault()
-
- filters = {'security_group_id': [security_group['id']]}
- if super(NsxPluginV2, self)._get_port_security_group_bindings(
- context, filters):
- raise ext_sg.SecurityGroupInUse(id=security_group['id'])
- nsx_sec_profile_id = nsx_utils.get_nsx_security_group_id(
- context.session, self.cluster, security_group_id)
-
- try:
- secgrouplib.delete_security_profile(
- self.cluster, nsx_sec_profile_id)
- except n_exc.NotFound:
- # The security profile was not found on the backend
- # do not fail in this case.
- LOG.warning(_LW("The NSX security profile %(sec_profile_id)s, "
- "associated with the Neutron security group "
- "%(sec_group_id)s was not found on the "
- "backend"),
- {'sec_profile_id': nsx_sec_profile_id,
- 'sec_group_id': security_group_id})
- except api_exc.NsxApiException:
- # Raise and fail the operation, as there is a problem which
- # prevented the sec group from being removed from the backend
- LOG.exception(_LE("An exception occurred while removing the "
- "NSX security profile %(sec_profile_id)s, "
- "associated with Netron security group "
- "%(sec_group_id)s"),
- {'sec_profile_id': nsx_sec_profile_id,
- 'sec_group_id': security_group_id})
- raise nsx_exc.NsxPluginException(
- _("Unable to remove security group %s from backend"),
- security_group['id'])
- return super(NsxPluginV2, self).delete_security_group(
- context, security_group_id)
-
- def _validate_security_group_rules(self, context, rules):
- for rule in rules['security_group_rules']:
- r = rule.get('security_group_rule')
- port_based_proto = (self._get_ip_proto_number(r['protocol'])
- in securitygroups_db.IP_PROTOCOL_MAP.values())
- if (not port_based_proto and
- (r['port_range_min'] is not None or
- r['port_range_max'] is not None)):
- msg = (_("Port values not valid for "
- "protocol: %s") % r['protocol'])
- raise n_exc.BadRequest(resource='security_group_rule',
- msg=msg)
- return super(NsxPluginV2, self)._validate_security_group_rules(context,
- rules)
-
- def create_security_group_rule(self, context, security_group_rule):
- """Create a single security group rule."""
- bulk_rule = {'security_group_rules': [security_group_rule]}
- return self.create_security_group_rule_bulk(context, bulk_rule)[0]
-
- def create_security_group_rule_bulk(self, context, security_group_rule):
- """Create security group rules.
-
- :param security_group_rule: list of rules to create
- """
- s = security_group_rule.get('security_group_rules')
-
- # TODO(arosen) is there anyway we could avoid having the update of
- # the security group rules in nsx outside of this transaction?
- with context.session.begin(subtransactions=True):
- security_group_id = self._validate_security_group_rules(
- context, security_group_rule)
- # Check to make sure security group exists
- security_group = super(NsxPluginV2, self).get_security_group(
- context, security_group_id)
-
- if not security_group:
- raise ext_sg.SecurityGroupNotFound(id=security_group_id)
- # Check for duplicate rules
- self._check_for_duplicate_rules(context, s)
- # gather all the existing security group rules since we need all
- # of them to PUT to NSX.
- existing_rules = self.get_security_group_rules(
- context, {'security_group_id': [security_group['id']]})
- combined_rules = sg_utils.merge_security_group_rules_with_current(
- context.session, self.cluster, s, existing_rules)
- nsx_sec_profile_id = nsx_utils.get_nsx_security_group_id(
- context.session, self.cluster, security_group_id)
- secgrouplib.update_security_group_rules(self.cluster,
- nsx_sec_profile_id,
- combined_rules)
- return super(
- NsxPluginV2, self).create_security_group_rule_bulk_native(
- context, security_group_rule)
-
- def delete_security_group_rule(self, context, sgrid):
- """Delete a security group rule
- :param sgrid: security group id to remove.
- """
- with context.session.begin(subtransactions=True):
- # determine security profile id
- security_group_rule = (
- super(NsxPluginV2, self).get_security_group_rule(
- context, sgrid))
- if not security_group_rule:
- raise ext_sg.SecurityGroupRuleNotFound(id=sgrid)
-
- sgid = security_group_rule['security_group_id']
- current_rules = self.get_security_group_rules(
- context, {'security_group_id': [sgid]})
- current_rules_nsx = sg_utils.get_security_group_rules_nsx_format(
- context.session, self.cluster, current_rules, True)
-
- sg_utils.remove_security_group_with_id_and_id_field(
- current_rules_nsx, sgrid)
- nsx_sec_profile_id = nsx_utils.get_nsx_security_group_id(
- context.session, self.cluster, sgid)
- secgrouplib.update_security_group_rules(
- self.cluster, nsx_sec_profile_id, current_rules_nsx)
- return super(NsxPluginV2, self).delete_security_group_rule(context,
- sgrid)
-
- def create_qos_queue(self, context, qos_queue, check_policy=True):
- q = qos_queue.get('qos_queue')
- self._validate_qos_queue(context, q)
- q['id'] = queuelib.create_lqueue(self.cluster, q)
- return super(NsxPluginV2, self).create_qos_queue(context, qos_queue)
-
- def delete_qos_queue(self, context, queue_id, raise_in_use=True):
- filters = {'queue_id': [queue_id]}
- queues = self._get_port_queue_bindings(context, filters)
- if queues:
- if raise_in_use:
- raise qos.QueueInUseByPort()
- else:
- return
- queuelib.delete_lqueue(self.cluster, queue_id)
- return super(NsxPluginV2, self).delete_qos_queue(context, queue_id)
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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 sys
-
-from neutron.plugins.vmware.shell import commands as cmd
-from neutronclient import shell
-
-
-class NsxManage(shell.NeutronShell):
-
- def __init__(self, api_version):
- super(NsxManage, self).__init__(api_version)
- self.command_manager.add_command('net-migrate', cmd.NetworkMigrate)
- self.command_manager.add_command('net-report', cmd.NetworkReport)
-
- def build_option_parser(self, description, version):
- parser = super(NsxManage, self).build_option_parser(
- description, version)
- return parser
-
- def initialize_app(self, argv):
- super(NsxManage, self).initialize_app(argv)
- self.client = self.client_manager.neutron
-
-
-def main():
- return NsxManage(shell.NEUTRON_API_VERSION).run(sys.argv[1:])
+++ /dev/null
-# Copyright 2014 VMware, Inc.
-#
-# 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.
-#
-
-from neutronclient.neutron import v2_0 as client
-
-LSN_PATH = '/lsns'
-
-
-def print_report(write_func, report):
- write_func(_("\nService type = %s\n") % report['report']['type'])
- services = ','.join(report['report']['services'])
- ports = ','.join(report['report']['ports'])
- write_func(_("Service uuids = %s\n") % services)
- write_func(_("Port uuids = %s\n\n") % ports)
-
-
-class NetworkReport(client.NeutronCommand):
- """Retrieve network migration report."""
-
- def get_parser(self, prog_name):
- parser = super(NetworkReport, self).get_parser(prog_name)
- parser.add_argument('network', metavar='network',
- help=_('ID or name of network to run report on'))
- return parser
-
- def run(self, parsed_args):
- net = parsed_args.network
- net_id = client.find_resourceid_by_name_or_id(self.app.client,
- 'network', net)
- res = self.app.client.get("%s/%s" % (LSN_PATH, net_id))
- if res:
- self.app.stdout.write(_('Migration report is:\n'))
- print_report(self.app.stdout.write, res['lsn'])
-
-
-class NetworkMigrate(client.NeutronCommand):
- """Perform network migration."""
-
- def get_parser(self, prog_name):
- parser = super(NetworkMigrate, self).get_parser(prog_name)
- parser.add_argument('network', metavar='network',
- help=_('ID or name of network to migrate'))
- return parser
-
- def run(self, parsed_args):
- net = parsed_args.network
- net_id = client.find_resourceid_by_name_or_id(self.app.client,
- 'network', net)
- body = {'network': net_id}
- res = self.app.client.post(LSN_PATH, body={'lsn': body})
- if res:
- self.app.stdout.write(_('Migration has been successful:\n'))
- print_report(self.app.stdout.write, res['lsn'])
+++ /dev/null
-# Copyright 2013 VMware, 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 base64
-
-import eventlet
-from oslo_serialization import jsonutils
-
-from neutron.plugins.vmware.vshield.common import exceptions
-
-httplib2 = eventlet.import_patched('httplib2')
-
-
-def xmldumps(obj):
- config = ""
- if isinstance(obj, dict):
- for key, value in obj.iteritems():
- cfg = "<%s>%s</%s>" % (key, xmldumps(value), key)
- config += cfg
- elif isinstance(obj, list):
- for value in obj:
- config += xmldumps(value)
- else:
- config = obj
-
- return config
-
-
-class VcnsApiHelper(object):
- errors = {
- 303: exceptions.ResourceRedirect,
- 400: exceptions.RequestBad,
- 403: exceptions.Forbidden,
- 404: exceptions.ResourceNotFound,
- 415: exceptions.MediaTypeUnsupport,
- 503: exceptions.ServiceUnavailable
- }
-
- def __init__(self, address, user, password, format='json'):
- self.authToken = base64.encodestring("%s:%s" % (user, password))
- self.user = user
- self.passwd = password
- self.address = address
- self.format = format
- if format == 'json':
- self.encode = jsonutils.dumps
- else:
- self.encode = xmldumps
-
- def request(self, method, uri, params=None):
- uri = self.address + uri
- http = httplib2.Http()
- http.disable_ssl_certificate_validation = True
- headers = {
- 'Content-Type': 'application/' + self.format,
- 'Accept': 'application/' + 'json',
- 'Authorization': 'Basic ' + self.authToken
- }
- body = self.encode(params) if params else None
- header, response = http.request(uri, method,
- body=body, headers=headers)
- status = int(header['status'])
- if 200 <= status < 300:
- return header, response
- if status in self.errors:
- cls = self.errors[status]
- else:
- cls = exceptions.VcnsApiException
- raise cls(uri=uri, status=status, header=header, response=response)
+++ /dev/null
-# Copyright 2013 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.
-
-EDGE_ID = 'edge_id'
-ROUTER_ID = 'router_id'
-
-# Interface
-EXTERNAL_VNIC_INDEX = 0
-INTERNAL_VNIC_INDEX = 1
-EXTERNAL_VNIC_NAME = "external"
-INTERNAL_VNIC_NAME = "internal"
-
-INTEGRATION_LR_IPADDRESS = "169.254.2.1/28"
-INTEGRATION_EDGE_IPADDRESS = "169.254.2.3"
-INTEGRATION_SUBNET_NETMASK = "255.255.255.240"
-
-# SNAT rule location
-PREPEND = 0
-APPEND = -1
-
-# error code
-VCNS_ERROR_CODE_EDGE_NOT_RUNNING = 10013
-
-SUFFIX_LENGTH = 8
-
-
-# router status by number
-class RouterStatus(object):
- ROUTER_STATUS_ACTIVE = 0
- ROUTER_STATUS_DOWN = 1
- ROUTER_STATUS_PENDING_CREATE = 2
- ROUTER_STATUS_PENDING_DELETE = 3
- ROUTER_STATUS_ERROR = 4
+++ /dev/null
-# Copyright 2013 VMware, 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.
-
-from neutron.common import exceptions
-
-
-class VcnsException(exceptions.NeutronException):
- pass
-
-
-class VcnsGeneralException(VcnsException):
- def __init__(self, message):
- self.message = message
- super(VcnsGeneralException, self).__init__()
-
-
-class VcnsBadRequest(exceptions.BadRequest):
- pass
-
-
-class VcnsNotFound(exceptions.NotFound):
- message = _('%(resource)s not found: %(msg)s')
-
-
-class VcnsApiException(VcnsException):
- message = _("An unknown exception %(status)s occurred: %(response)s.")
-
- def __init__(self, **kwargs):
- super(VcnsApiException, self).__init__(**kwargs)
-
- self.status = kwargs.get('status')
- self.header = kwargs.get('header')
- self.response = kwargs.get('response')
-
-
-class ResourceRedirect(VcnsApiException):
- message = _("Resource %(uri)s has been redirected")
-
-
-class RequestBad(VcnsApiException):
- message = _("Request %(uri)s is Bad, response %(response)s")
-
-
-class Forbidden(VcnsApiException):
- message = _("Forbidden: %(uri)s")
-
-
-class ResourceNotFound(VcnsApiException):
- message = _("Resource %(uri)s not found")
-
-
-class MediaTypeUnsupport(VcnsApiException):
- message = _("Media Type %(uri)s is not supported")
-
-
-class ServiceUnavailable(VcnsApiException):
- message = _("Service Unavailable: %(uri)s")
+++ /dev/null
-# Copyright 2013 VMware, 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.
-
-from oslo_serialization import jsonutils
-from oslo_utils import excutils
-
-from neutron.i18n import _LE
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware.vshield.common import constants as vcns_const
-from neutron.plugins.vmware.vshield.common import exceptions
-from neutron.plugins.vmware.vshield.tasks import constants
-from neutron.plugins.vmware.vshield.tasks import tasks
-
-LOG = logging.getLogger(__name__)
-
-
-class EdgeApplianceDriver(object):
- def __init__(self):
- # store the last task per edge that has the latest config
- self.updated_task = {
- 'nat': {},
- 'route': {},
- }
-
- def _assemble_edge(self, name, appliance_size="compact",
- deployment_container_id=None, datacenter_moid=None,
- enable_aesni=True, hypervisor_assist=False,
- enable_fips=False, remote_access=False):
- edge = {
- 'name': name,
- 'fqdn': name,
- 'hypervisorAssist': hypervisor_assist,
- 'type': 'gatewayServices',
- 'enableAesni': enable_aesni,
- 'enableFips': enable_fips,
- 'cliSettings': {
- 'remoteAccess': remote_access
- },
- 'appliances': {
- 'applianceSize': appliance_size
- },
- 'vnics': {
- 'vnics': []
- }
- }
- if deployment_container_id:
- edge['appliances']['deploymentContainerId'] = (
- deployment_container_id)
- if datacenter_moid:
- edge['datacenterMoid'] = datacenter_moid
-
- return edge
-
- def _assemble_edge_appliance(self, resource_pool_id, datastore_id):
- appliance = {}
- if resource_pool_id:
- appliance['resourcePoolId'] = resource_pool_id
- if datastore_id:
- appliance['datastoreId'] = datastore_id
- return appliance
-
- def _assemble_edge_vnic(self, name, index, portgroup_id,
- primary_address=None, subnet_mask=None,
- secondary=None,
- type="internal",
- enable_proxy_arp=False,
- enable_send_redirects=True,
- is_connected=True,
- mtu=1500):
- vnic = {
- 'index': index,
- 'name': name,
- 'type': type,
- 'portgroupId': portgroup_id,
- 'mtu': mtu,
- 'enableProxyArp': enable_proxy_arp,
- 'enableSendRedirects': enable_send_redirects,
- 'isConnected': is_connected
- }
- if primary_address and subnet_mask:
- address_group = {
- 'primaryAddress': primary_address,
- 'subnetMask': subnet_mask
- }
- if secondary:
- address_group['secondaryAddresses'] = {
- 'ipAddress': secondary,
- 'type': 'IpAddressesDto'
- }
-
- vnic['addressGroups'] = {
- 'addressGroups': [address_group]
- }
-
- return vnic
-
- def _edge_status_to_level(self, status):
- if status == 'GREEN':
- status_level = vcns_const.RouterStatus.ROUTER_STATUS_ACTIVE
- elif status in ('GREY', 'YELLOW'):
- status_level = vcns_const.RouterStatus.ROUTER_STATUS_DOWN
- else:
- status_level = vcns_const.RouterStatus.ROUTER_STATUS_ERROR
- return status_level
-
- def _enable_loadbalancer(self, edge):
- if not edge.get('featureConfigs') or (
- not edge['featureConfigs'].get('features')):
- edge['featureConfigs'] = {'features': []}
- edge['featureConfigs']['features'].append(
- {'featureType': 'loadbalancer_4.0',
- 'enabled': True})
-
- def get_edge_status(self, edge_id):
- try:
- response = self.vcns.get_edge_status(edge_id)[1]
- status_level = self._edge_status_to_level(
- response['edgeStatus'])
- except exceptions.VcnsApiException as e:
- LOG.exception(_LE("VCNS: Failed to get edge status:\n%s"),
- e.response)
- status_level = vcns_const.RouterStatus.ROUTER_STATUS_ERROR
- try:
- desc = jsonutils.loads(e.response)
- if desc.get('errorCode') == (
- vcns_const.VCNS_ERROR_CODE_EDGE_NOT_RUNNING):
- status_level = (
- vcns_const.RouterStatus.ROUTER_STATUS_DOWN)
- except ValueError:
- LOG.exception(e.response)
-
- return status_level
-
- def get_edges_statuses(self):
- edges_status_level = {}
- edges = self._get_edges()
- for edge in edges['edgePage'].get('data', []):
- edge_id = edge['id']
- status = edge['edgeStatus']
- edges_status_level[edge_id] = self._edge_status_to_level(status)
-
- return edges_status_level
-
- def _update_interface(self, task):
- edge_id = task.userdata['edge_id']
- config = task.userdata['config']
- LOG.debug("VCNS: start updating vnic %s", config)
- try:
- self.vcns.update_interface(edge_id, config)
- except exceptions.VcnsApiException as e:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("VCNS: Failed to update vnic %(config)s:\n"
- "%(response)s"), {
- 'config': config,
- 'response': e.response})
- except Exception:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("VCNS: Failed to update vnic %d"),
- config['index'])
-
- return constants.TaskStatus.COMPLETED
-
- def update_interface(self, router_id, edge_id, index, network,
- address=None, netmask=None, secondary=None,
- jobdata=None):
- LOG.debug("VCNS: update vnic %(index)d: %(addr)s %(netmask)s", {
- 'index': index, 'addr': address, 'netmask': netmask})
- if index == vcns_const.EXTERNAL_VNIC_INDEX:
- name = vcns_const.EXTERNAL_VNIC_NAME
- intf_type = 'uplink'
- elif index == vcns_const.INTERNAL_VNIC_INDEX:
- name = vcns_const.INTERNAL_VNIC_NAME
- intf_type = 'internal'
- else:
- msg = _("Vnic %d currently not supported") % index
- raise exceptions.VcnsGeneralException(msg)
-
- config = self._assemble_edge_vnic(
- name, index, network, address, netmask, secondary, type=intf_type)
-
- userdata = {
- 'edge_id': edge_id,
- 'config': config,
- 'jobdata': jobdata
- }
- task_name = "update-interface-%s-%d" % (edge_id, index)
- task = tasks.Task(task_name, router_id,
- self._update_interface, userdata=userdata)
- task.add_result_monitor(self.callbacks.interface_update_result)
- self.task_manager.add(task)
- return task
-
- def _deploy_edge(self, task):
- userdata = task.userdata
- name = userdata['router_name']
- LOG.debug("VCNS: start deploying edge %s", name)
- request = userdata['request']
- try:
- header = self.vcns.deploy_edge(request)[0]
- objuri = header['location']
- job_id = objuri[objuri.rfind("/") + 1:]
- response = self.vcns.get_edge_id(job_id)[1]
- edge_id = response['edgeId']
- LOG.debug("VCNS: deploying edge %s", edge_id)
- userdata['edge_id'] = edge_id
- status = constants.TaskStatus.PENDING
- except exceptions.VcnsApiException:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("VCNS: deploy edge failed for router %s."),
- name)
-
- return status
-
- def _status_edge(self, task):
- edge_id = task.userdata['edge_id']
- try:
- response = self.vcns.get_edge_deploy_status(edge_id)[1]
- task.userdata['retries'] = 0
- system_status = response.get('systemStatus', None)
- if system_status is None:
- status = constants.TaskStatus.PENDING
- elif system_status == 'good':
- status = constants.TaskStatus.COMPLETED
- else:
- status = constants.TaskStatus.ERROR
- except exceptions.VcnsApiException:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("VCNS: Edge %s status query failed."),
- edge_id)
- except Exception:
- retries = task.userdata.get('retries', 0) + 1
- if retries < 3:
- task.userdata['retries'] = retries
- LOG.exception(_LE("VCNS: Unable to retrieve edge %(edge_id)s "
- "status. Retry %(retries)d."),
- {'edge_id': edge_id,
- 'retries': retries})
- status = constants.TaskStatus.PENDING
- else:
- LOG.exception(_LE("VCNS: Unable to retrieve edge %s status. "
- "Abort."), edge_id)
- status = constants.TaskStatus.ERROR
- LOG.debug("VCNS: Edge %s status", edge_id)
- return status
-
- def _result_edge(self, task):
- router_name = task.userdata['router_name']
- edge_id = task.userdata.get('edge_id')
- if task.status != constants.TaskStatus.COMPLETED:
- LOG.error(_LE("VCNS: Failed to deploy edge %(edge_id)s "
- "for %(name)s, status %(status)d"), {
- 'edge_id': edge_id,
- 'name': router_name,
- 'status': task.status
- })
- else:
- LOG.debug("VCNS: Edge %(edge_id)s deployed for "
- "router %(name)s", {
- 'edge_id': edge_id, 'name': router_name
- })
-
- def _delete_edge(self, task):
- edge_id = task.userdata['edge_id']
- LOG.debug("VCNS: start destroying edge %s", edge_id)
- status = constants.TaskStatus.COMPLETED
- if edge_id:
- try:
- self.vcns.delete_edge(edge_id)
- except exceptions.ResourceNotFound:
- pass
- except exceptions.VcnsApiException as e:
- LOG.exception(_LE("VCNS: Failed to delete %(edge_id)s:\n"
- "%(response)s"),
- {'edge_id': edge_id, 'response': e.response})
- status = constants.TaskStatus.ERROR
- except Exception:
- LOG.exception(_LE("VCNS: Failed to delete %s"), edge_id)
- status = constants.TaskStatus.ERROR
-
- return status
-
- def _get_edges(self):
- try:
- return self.vcns.get_edges()[1]
- except exceptions.VcnsApiException as e:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("VCNS: Failed to get edges:\n%s"),
- e.response)
-
- def deploy_edge(self, router_id, name, internal_network, jobdata=None,
- wait_for_exec=False, loadbalancer_enable=True):
- task_name = 'deploying-%s' % name
- edge_name = name
- edge = self._assemble_edge(
- edge_name, datacenter_moid=self.datacenter_moid,
- deployment_container_id=self.deployment_container_id,
- appliance_size='large', remote_access=True)
- appliance = self._assemble_edge_appliance(self.resource_pool_id,
- self.datastore_id)
- if appliance:
- edge['appliances']['appliances'] = [appliance]
-
- vnic_external = self._assemble_edge_vnic(
- vcns_const.EXTERNAL_VNIC_NAME, vcns_const.EXTERNAL_VNIC_INDEX,
- self.external_network, type="uplink")
- edge['vnics']['vnics'].append(vnic_external)
- vnic_inside = self._assemble_edge_vnic(
- vcns_const.INTERNAL_VNIC_NAME, vcns_const.INTERNAL_VNIC_INDEX,
- internal_network,
- vcns_const.INTEGRATION_EDGE_IPADDRESS,
- vcns_const.INTEGRATION_SUBNET_NETMASK,
- type="internal")
- edge['vnics']['vnics'].append(vnic_inside)
- if loadbalancer_enable:
- self._enable_loadbalancer(edge)
- userdata = {
- 'request': edge,
- 'router_name': name,
- 'jobdata': jobdata
- }
- task = tasks.Task(task_name, router_id,
- self._deploy_edge,
- status_callback=self._status_edge,
- result_callback=self._result_edge,
- userdata=userdata)
- task.add_executed_monitor(self.callbacks.edge_deploy_started)
- task.add_result_monitor(self.callbacks.edge_deploy_result)
- self.task_manager.add(task)
-
- if wait_for_exec:
- # wait until the deploy task is executed so edge_id is available
- task.wait(constants.TaskState.EXECUTED)
-
- return task
-
- def delete_edge(self, router_id, edge_id, jobdata=None):
- task_name = 'delete-%s' % edge_id
- userdata = {
- 'router_id': router_id,
- 'edge_id': edge_id,
- 'jobdata': jobdata
- }
- task = tasks.Task(task_name, router_id, self._delete_edge,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.edge_delete_result)
- self.task_manager.add(task)
- return task
-
- def _assemble_nat_rule(self, action, original_address,
- translated_address,
- vnic_index=vcns_const.EXTERNAL_VNIC_INDEX,
- enabled=True):
- nat_rule = {}
- nat_rule['action'] = action
- nat_rule['vnic'] = vnic_index
- nat_rule['originalAddress'] = original_address
- nat_rule['translatedAddress'] = translated_address
- nat_rule['enabled'] = enabled
- return nat_rule
-
- def get_nat_config(self, edge_id):
- try:
- return self.vcns.get_nat_config(edge_id)[1]
- except exceptions.VcnsApiException as e:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("VCNS: Failed to get nat config:\n%s"),
- e.response)
-
- def _create_nat_rule(self, task):
- # TODO(fank): use POST for optimization
- # return rule_id for future reference
- rule = task.userdata['rule']
- LOG.debug("VCNS: start creating nat rules: %s", rule)
- edge_id = task.userdata['edge_id']
- nat = self.get_nat_config(edge_id)
- location = task.userdata['location']
-
- del nat['version']
-
- if location is None or location == vcns_const.APPEND:
- nat['rules']['natRulesDtos'].append(rule)
- else:
- nat['rules']['natRulesDtos'].insert(location, rule)
-
- try:
- self.vcns.update_nat_config(edge_id, nat)
- status = constants.TaskStatus.COMPLETED
- except exceptions.VcnsApiException as e:
- LOG.exception(_LE("VCNS: Failed to create snat rule:\n%s"),
- e.response)
- status = constants.TaskStatus.ERROR
-
- return status
-
- def create_snat_rule(self, router_id, edge_id, src, translated,
- jobdata=None, location=None):
- LOG.debug("VCNS: create snat rule %(src)s/%(translated)s", {
- 'src': src, 'translated': translated})
- snat_rule = self._assemble_nat_rule("snat", src, translated)
- userdata = {
- 'router_id': router_id,
- 'edge_id': edge_id,
- 'rule': snat_rule,
- 'location': location,
- 'jobdata': jobdata
- }
- task_name = "create-snat-%s-%s-%s" % (edge_id, src, translated)
- task = tasks.Task(task_name, router_id, self._create_nat_rule,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.snat_create_result)
- self.task_manager.add(task)
- return task
-
- def _delete_nat_rule(self, task):
- # TODO(fank): pass in rule_id for optimization
- # handle routes update for optimization
- edge_id = task.userdata['edge_id']
- address = task.userdata['address']
- addrtype = task.userdata['addrtype']
- LOG.debug("VCNS: start deleting %(type)s rules: %(addr)s", {
- 'type': addrtype, 'addr': address})
- nat = self.get_nat_config(edge_id)
- del nat['version']
- status = constants.TaskStatus.COMPLETED
- for nat_rule in nat['rules']['natRulesDtos']:
- if nat_rule[addrtype] == address:
- rule_id = nat_rule['ruleId']
- try:
- self.vcns.delete_nat_rule(edge_id, rule_id)
- except exceptions.VcnsApiException as e:
- LOG.exception(_LE("VCNS: Failed to delete snat rule:\n"
- "%s"), e.response)
- status = constants.TaskStatus.ERROR
-
- return status
-
- def delete_snat_rule(self, router_id, edge_id, src, jobdata=None):
- LOG.debug("VCNS: delete snat rule %s", src)
- userdata = {
- 'edge_id': edge_id,
- 'address': src,
- 'addrtype': 'originalAddress',
- 'jobdata': jobdata
- }
- task_name = "delete-snat-%s-%s" % (edge_id, src)
- task = tasks.Task(task_name, router_id, self._delete_nat_rule,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.snat_delete_result)
- self.task_manager.add(task)
- return task
-
- def create_dnat_rule(self, router_id, edge_id, dst, translated,
- jobdata=None, location=None):
- # TODO(fank): use POST for optimization
- # return rule_id for future reference
- LOG.debug("VCNS: create dnat rule %(dst)s/%(translated)s", {
- 'dst': dst, 'translated': translated})
- dnat_rule = self._assemble_nat_rule(
- "dnat", dst, translated)
- userdata = {
- 'router_id': router_id,
- 'edge_id': edge_id,
- 'rule': dnat_rule,
- 'location': location,
- 'jobdata': jobdata
- }
- task_name = "create-dnat-%s-%s-%s" % (edge_id, dst, translated)
- task = tasks.Task(task_name, router_id, self._create_nat_rule,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.dnat_create_result)
- self.task_manager.add(task)
- return task
-
- def delete_dnat_rule(self, router_id, edge_id, translated,
- jobdata=None):
- # TODO(fank): pass in rule_id for optimization
- LOG.debug("VCNS: delete dnat rule %s", translated)
- userdata = {
- 'edge_id': edge_id,
- 'address': translated,
- 'addrtype': 'translatedAddress',
- 'jobdata': jobdata
- }
- task_name = "delete-dnat-%s-%s" % (edge_id, translated)
- task = tasks.Task(task_name, router_id, self._delete_nat_rule,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.dnat_delete_result)
- self.task_manager.add(task)
- return task
-
- def _update_nat_rule(self, task):
- # TODO(fank): use POST for optimization
- # return rule_id for future reference
- edge_id = task.userdata['edge_id']
- if task != self.updated_task['nat'][edge_id]:
- # this task does not have the latest config, abort now
- # for speedup
- return constants.TaskStatus.ABORT
-
- rules = task.userdata['rules']
- LOG.debug("VCNS: start updating nat rules: %s", rules)
-
- nat = {
- 'featureType': 'nat',
- 'rules': {
- 'natRulesDtos': rules
- }
- }
-
- try:
- self.vcns.update_nat_config(edge_id, nat)
- status = constants.TaskStatus.COMPLETED
- except exceptions.VcnsApiException as e:
- LOG.exception(_LE("VCNS: Failed to create snat rule:\n%s"),
- e.response)
- status = constants.TaskStatus.ERROR
-
- return status
-
- def update_nat_rules(self, router_id, edge_id, snats, dnats,
- jobdata=None):
- LOG.debug("VCNS: update nat rule\n"
- "SNAT:%(snat)s\n"
- "DNAT:%(dnat)s\n", {
- 'snat': snats, 'dnat': dnats})
- nat_rules = []
-
- for dnat in dnats:
- nat_rules.append(self._assemble_nat_rule(
- 'dnat', dnat['dst'], dnat['translated']))
- nat_rules.append(self._assemble_nat_rule(
- 'snat', dnat['translated'], dnat['dst']))
-
- for snat in snats:
- nat_rules.append(self._assemble_nat_rule(
- 'snat', snat['src'], snat['translated']))
-
- userdata = {
- 'edge_id': edge_id,
- 'rules': nat_rules,
- 'jobdata': jobdata,
- }
- task_name = "update-nat-%s" % edge_id
- task = tasks.Task(task_name, router_id, self._update_nat_rule,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.nat_update_result)
- self.updated_task['nat'][edge_id] = task
- self.task_manager.add(task)
- return task
-
- def _update_routes(self, task):
- edge_id = task.userdata['edge_id']
- if (task != self.updated_task['route'][edge_id] and
- task.userdata.get('skippable', True)):
- # this task does not have the latest config, abort now
- # for speedup
- return constants.TaskStatus.ABORT
- gateway = task.userdata['gateway']
- routes = task.userdata['routes']
- LOG.debug("VCNS: start updating routes for %s", edge_id)
- static_routes = []
- for route in routes:
- static_routes.append({
- "description": "",
- "vnic": vcns_const.INTERNAL_VNIC_INDEX,
- "network": route['cidr'],
- "nextHop": route['nexthop']
- })
- request = {
- "staticRoutes": {
- "staticRoutes": static_routes
- }
- }
- if gateway:
- request["defaultRoute"] = {
- "description": "default-gateway",
- "gatewayAddress": gateway,
- "vnic": vcns_const.EXTERNAL_VNIC_INDEX
- }
- try:
- self.vcns.update_routes(edge_id, request)
- status = constants.TaskStatus.COMPLETED
- except exceptions.VcnsApiException as e:
- LOG.exception(_LE("VCNS: Failed to update routes:\n%s"),
- e.response)
- status = constants.TaskStatus.ERROR
-
- return status
-
- def update_routes(self, router_id, edge_id, gateway, routes,
- skippable=True, jobdata=None):
- if gateway:
- gateway = gateway.split('/')[0]
-
- userdata = {
- 'edge_id': edge_id,
- 'gateway': gateway,
- 'routes': routes,
- 'skippable': skippable,
- 'jobdata': jobdata
- }
- task_name = "update-routes-%s" % (edge_id)
- task = tasks.Task(task_name, router_id, self._update_routes,
- userdata=userdata)
- task.add_result_monitor(self.callbacks.routes_update_result)
- self.updated_task['route'][edge_id] = task
- self.task_manager.add(task)
- return task
-
- def create_lswitch(self, name, tz_config, tags=None,
- port_isolation=False, replication_mode="service"):
- lsconfig = {
- 'display_name': utils.check_and_truncate(name),
- "tags": tags or [],
- "type": "LogicalSwitchConfig",
- "_schema": "/ws.v1/schema/LogicalSwitchConfig",
- "transport_zones": tz_config
- }
- if port_isolation is bool:
- lsconfig["port_isolation_enabled"] = port_isolation
- if replication_mode:
- lsconfig["replication_mode"] = replication_mode
-
- response = self.vcns.create_lswitch(lsconfig)[1]
- return response
-
- def delete_lswitch(self, lswitch_id):
- self.vcns.delete_lswitch(lswitch_id)
-
- def get_loadbalancer_config(self, edge_id):
- try:
- header, response = self.vcns.get_loadbalancer_config(
- edge_id)
- except exceptions.VcnsApiException:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("Failed to get service config"))
- return response
-
- def enable_service_loadbalancer(self, edge_id):
- config = self.get_loadbalancer_config(
- edge_id)
- if not config['enabled']:
- config['enabled'] = True
- try:
- self.vcns.enable_service_loadbalancer(edge_id, config)
- except exceptions.VcnsApiException:
- with excutils.save_and_reraise_exception():
- LOG.exception(_LE("Failed to enable loadbalancer "
- "service config"))
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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.
-
-
-class TaskStatus(object):
- """Task running status.
-
- This is used by execution/status callback function to notify the
- task manager what's the status of current task, and also used for
- indication the final task execution result.
- """
- PENDING = 1
- COMPLETED = 2
- ERROR = 3
- ABORT = 4
-
-
-class TaskState(object):
- """Current state of a task.
-
- This is to keep track of the current state of a task.
- NONE: the task is still in the queue
- START: the task is pull out from the queue and is about to be executed
- EXECUTED: the task has been executed
- STATUS: we're running periodic status check for this task
- RESULT: the task has finished and result is ready
- """
- NONE = -1
- START = 0
- EXECUTED = 1
- STATUS = 2
- RESULT = 3
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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 collections
-import uuid
-
-from eventlet import event
-from eventlet import greenthread
-
-from neutron.common import exceptions
-from neutron.i18n import _LE, _LI
-from neutron.openstack.common import log as logging
-from neutron.openstack.common import loopingcall
-from neutron.plugins.vmware.vshield.tasks import constants
-
-DEFAULT_INTERVAL = 1000
-
-LOG = logging.getLogger(__name__)
-
-
-def nop(task):
- return constants.TaskStatus.COMPLETED
-
-
-class TaskException(exceptions.NeutronException):
-
- def __init__(self, message=None, **kwargs):
- if message is not None:
- self.message = message
-
- super(TaskException, self).__init__(**kwargs)
-
-
-class InvalidState(TaskException):
- message = _("Invalid state %(state)d")
-
-
-class TaskStateSkipped(TaskException):
- message = _("State %(state)d skipped. Current state %(current)d")
-
-
-class Task(object):
- def __init__(self, name, resource_id, execute_callback,
- status_callback=nop, result_callback=nop, userdata=None):
- self.name = name
- self.resource_id = resource_id
- self._execute_callback = execute_callback
- self._status_callback = status_callback
- self._result_callback = result_callback
- self.userdata = userdata
- self.id = None
- self.status = None
-
- self._monitors = {
- constants.TaskState.START: [],
- constants.TaskState.EXECUTED: [],
- constants.TaskState.RESULT: []
- }
- self._states = [None, None, None, None]
- self._state = constants.TaskState.NONE
-
- def _add_monitor(self, action, func):
- self._monitors[action].append(func)
- return self
-
- def _move_state(self, state):
- self._state = state
- if self._states[state] is not None:
- e = self._states[state]
- self._states[state] = None
- e.send()
-
- for s in range(state):
- if self._states[s] is not None:
- e = self._states[s]
- self._states[s] = None
- e.send_exception(
- TaskStateSkipped(state=s, current=self._state))
-
- def _invoke_monitor(self, state):
- for func in self._monitors[state]:
- try:
- func(self)
- except Exception:
- LOG.exception(_LE("Task %(task)s encountered exception in "
- "%(func)s at state %(state)s"),
- {'task': str(self),
- 'func': str(func),
- 'state': state})
-
- self._move_state(state)
-
- return self
-
- def _start(self):
- return self._invoke_monitor(constants.TaskState.START)
-
- def _executed(self):
- return self._invoke_monitor(constants.TaskState.EXECUTED)
-
- def _update_status(self, status):
- if self.status == status:
- return self
-
- self.status = status
-
- def _finished(self):
- return self._invoke_monitor(constants.TaskState.RESULT)
-
- def add_start_monitor(self, func):
- return self._add_monitor(constants.TaskState.START, func)
-
- def add_executed_monitor(self, func):
- return self._add_monitor(constants.TaskState.EXECUTED, func)
-
- def add_result_monitor(self, func):
- return self._add_monitor(constants.TaskState.RESULT, func)
-
- def wait(self, state):
- if (state < constants.TaskState.START or
- state > constants.TaskState.RESULT or
- state == constants.TaskState.STATUS):
- raise InvalidState(state=state)
-
- if state <= self._state:
- # we already passed this current state, so no wait
- return
-
- e = event.Event()
- self._states[state] = e
- e.wait()
-
- def __repr__(self):
- return "Task-%s-%s-%s" % (
- self.name, self.resource_id, self.id)
-
-
-class TaskManager(object):
-
- _instance = None
- _default_interval = DEFAULT_INTERVAL
-
- def __init__(self, interval=None):
- self._interval = interval or TaskManager._default_interval
-
- # A queue to pass tasks from other threads
- self._tasks_queue = collections.deque()
-
- # A dict to store resource -> resource's tasks
- self._tasks = {}
-
- # Current task being executed in main thread
- self._main_thread_exec_task = None
-
- # New request event
- self._req = event.Event()
-
- # TaskHandler stopped event
- self._stopped = False
-
- # Periodic function trigger
- self._monitor = None
- self._monitor_busy = False
-
- # Thread handling the task request
- self._thread = None
-
- def _execute(self, task):
- """Execute task."""
- LOG.debug("Start task %s", str(task))
- task._start()
- try:
- status = task._execute_callback(task)
- except Exception:
- LOG.exception(_LE("Task %(task)s encountered exception in %(cb)s"),
- {'task': str(task),
- 'cb': str(task._execute_callback)})
- status = constants.TaskStatus.ERROR
-
- LOG.debug("Task %(task)s return %(status)s", {
- 'task': str(task),
- 'status': status})
-
- task._update_status(status)
- task._executed()
-
- return status
-
- def _result(self, task):
- """Notify task execution result."""
- try:
- task._result_callback(task)
- except Exception:
- LOG.exception(_LE("Task %(task)s encountered exception in %(cb)s"),
- {'task': str(task),
- 'cb': str(task._result_callback)})
-
- LOG.debug("Task %(task)s return %(status)s",
- {'task': str(task), 'status': task.status})
-
- task._finished()
-
- def _check_pending_tasks(self):
- """Check all pending tasks status."""
- for resource_id in self._tasks.keys():
- if self._stopped:
- # Task manager is stopped, return now
- return
-
- tasks = self._tasks[resource_id]
- # only the first task is executed and pending
- task = tasks[0]
- try:
- status = task._status_callback(task)
- except Exception:
- LOG.exception(_LE("Task %(task)s encountered exception in "
- "%(cb)s"),
- {'task': str(task),
- 'cb': str(task._status_callback)})
- status = constants.TaskStatus.ERROR
- task._update_status(status)
- if status != constants.TaskStatus.PENDING:
- self._dequeue(task, True)
-
- def _enqueue(self, task):
- if task.resource_id in self._tasks:
- # append to existing resource queue for ordered processing
- self._tasks[task.resource_id].append(task)
- else:
- # put the task to a new resource queue
- tasks = collections.deque()
- tasks.append(task)
- self._tasks[task.resource_id] = tasks
-
- def _dequeue(self, task, run_next):
- self._result(task)
- tasks = self._tasks[task.resource_id]
- tasks.remove(task)
- if not tasks:
- # no more tasks for this resource
- del self._tasks[task.resource_id]
- return
-
- if run_next:
- # process next task for this resource
- while tasks:
- task = tasks[0]
- status = self._execute(task)
- if status == constants.TaskStatus.PENDING:
- break
- self._dequeue(task, False)
-
- def _abort(self):
- """Abort all tasks."""
- # put all tasks haven't been received by main thread to queue
- # so the following abort handling can cover them
- for t in self._tasks_queue:
- self._enqueue(t)
- self._tasks_queue.clear()
-
- for resource_id in self._tasks.keys():
- tasks = list(self._tasks[resource_id])
- for task in tasks:
- task._update_status(constants.TaskStatus.ABORT)
- self._dequeue(task, False)
-
- def _get_task(self):
- """Get task request."""
- while True:
- for t in self._tasks_queue:
- return self._tasks_queue.popleft()
- self._req.wait()
- self._req.reset()
-
- def run(self):
- while True:
- try:
- if self._stopped:
- # Gracefully terminate this thread if the _stopped
- # attribute was set to true
- LOG.info(_LI("Stopping TaskManager"))
- break
-
- # get a task from queue, or timeout for periodic status check
- task = self._get_task()
- if task.resource_id in self._tasks:
- # this resource already has some tasks under processing,
- # append the task to same queue for ordered processing
- self._enqueue(task)
- continue
-
- try:
- self._main_thread_exec_task = task
- self._execute(task)
- finally:
- self._main_thread_exec_task = None
- if task.status is None:
- # The thread is killed during _execute(). To guarantee
- # the task been aborted correctly, put it to the queue.
- self._enqueue(task)
- elif task.status != constants.TaskStatus.PENDING:
- self._result(task)
- else:
- self._enqueue(task)
- except Exception:
- LOG.exception(_LE("TaskManager terminating because "
- "of an exception"))
- break
-
- def add(self, task):
- task.id = uuid.uuid1()
- self._tasks_queue.append(task)
- if not self._req.ready():
- self._req.send()
- return task.id
-
- def stop(self):
- if self._thread is None:
- return
- self._stopped = True
- self._thread.kill()
- self._thread = None
- # Stop looping call and abort running tasks
- self._monitor.stop()
- if self._monitor_busy:
- self._monitor.wait()
- self._abort()
- LOG.info(_LI("TaskManager terminated"))
-
- def has_pending_task(self):
- if self._tasks_queue or self._tasks or self._main_thread_exec_task:
- return True
- else:
- return False
-
- def show_pending_tasks(self):
- for task in self._tasks_queue:
- LOG.info(str(task))
- for resource, tasks in self._tasks.iteritems():
- for task in tasks:
- LOG.info(str(task))
- if self._main_thread_exec_task:
- LOG.info(str(self._main_thread_exec_task))
-
- def count(self):
- count = 0
- for resource_id, tasks in self._tasks.iteritems():
- count += len(tasks)
- return count
-
- def start(self, interval=None):
- def _inner():
- self.run()
-
- def _loopingcall_callback():
- self._monitor_busy = True
- try:
- self._check_pending_tasks()
- except Exception:
- LOG.exception(_LE("Exception in _check_pending_tasks"))
- self._monitor_busy = False
-
- if self._thread is not None:
- return self
-
- if interval is None or interval == 0:
- interval = self._interval
-
- self._stopped = False
- self._thread = greenthread.spawn(_inner)
- self._monitor = loopingcall.FixedIntervalLoopingCall(
- _loopingcall_callback)
- self._monitor.start(interval / 1000.0,
- interval / 1000.0)
- # To allow the created thread start running
- greenthread.sleep(0)
-
- return self
-
- @classmethod
- def set_default_interval(cls, interval):
- cls._default_interval = interval
+++ /dev/null
-# Copyright 2013 VMware, 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.
-
-from oslo_serialization import jsonutils
-
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.vshield.common import VcnsApiClient
-
-LOG = logging.getLogger(__name__)
-
-HTTP_GET = "GET"
-HTTP_POST = "POST"
-HTTP_DELETE = "DELETE"
-HTTP_PUT = "PUT"
-URI_PREFIX = "/api/4.0/edges"
-
-#FwaaS constants
-FIREWALL_SERVICE = "firewall/config"
-FIREWALL_RULE_RESOURCE = "rules"
-
-#LbaaS Constants
-LOADBALANCER_SERVICE = "loadbalancer/config"
-VIP_RESOURCE = "virtualservers"
-POOL_RESOURCE = "pools"
-MONITOR_RESOURCE = "monitors"
-APP_PROFILE_RESOURCE = "applicationprofiles"
-
-# IPsec VPNaaS Constants
-IPSEC_VPN_SERVICE = 'ipsec/config'
-
-
-class Vcns(object):
-
- def __init__(self, address, user, password):
- self.address = address
- self.user = user
- self.password = password
- self.jsonapi_client = VcnsApiClient.VcnsApiHelper(address, user,
- password, 'json')
-
- def do_request(self, method, uri, params=None, format='json', **kwargs):
- LOG.debug("VcnsApiHelper('%(method)s', '%(uri)s', '%(body)s')", {
- 'method': method,
- 'uri': uri,
- 'body': jsonutils.dumps(params)})
- if format == 'json':
- header, content = self.jsonapi_client.request(method, uri, params)
- else:
- header, content = self.xmlapi_client.request(method, uri, params)
- LOG.debug("Header: '%s'", header)
- LOG.debug("Content: '%s'", content)
- if content == '':
- return header, {}
- if kwargs.get('decode', True):
- content = jsonutils.loads(content)
- return header, content
-
- def deploy_edge(self, request):
- uri = URI_PREFIX + "?async=true"
- return self.do_request(HTTP_POST, uri, request, decode=False)
-
- def get_edge_id(self, job_id):
- uri = URI_PREFIX + "/jobs/%s" % job_id
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def get_edge_deploy_status(self, edge_id):
- uri = URI_PREFIX + "/%s/status?getlatest=false" % edge_id
- return self.do_request(HTTP_GET, uri, decode="True")
-
- def delete_edge(self, edge_id):
- uri = "%s/%s" % (URI_PREFIX, edge_id)
- return self.do_request(HTTP_DELETE, uri)
-
- def update_interface(self, edge_id, vnic):
- uri = "%s/%s/vnics/%d" % (URI_PREFIX, edge_id, vnic['index'])
- return self.do_request(HTTP_PUT, uri, vnic, decode=True)
-
- def get_nat_config(self, edge_id):
- uri = "%s/%s/nat/config" % (URI_PREFIX, edge_id)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def update_nat_config(self, edge_id, nat):
- uri = "%s/%s/nat/config" % (URI_PREFIX, edge_id)
- return self.do_request(HTTP_PUT, uri, nat, decode=True)
-
- def delete_nat_rule(self, edge_id, rule_id):
- uri = "%s/%s/nat/config/rules/%s" % (URI_PREFIX, edge_id, rule_id)
- return self.do_request(HTTP_DELETE, uri, decode=True)
-
- def get_edge_status(self, edge_id):
- uri = "%s/%s/status?getlatest=false" % (URI_PREFIX, edge_id)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def get_edges(self):
- uri = URI_PREFIX
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def update_routes(self, edge_id, routes):
- uri = "%s/%s/routing/config/static" % (URI_PREFIX, edge_id)
- return self.do_request(HTTP_PUT, uri, routes)
-
- def create_lswitch(self, lsconfig):
- uri = "/api/ws.v1/lswitch"
- return self.do_request(HTTP_POST, uri, lsconfig, decode=True)
-
- def delete_lswitch(self, lswitch_id):
- uri = "/api/ws.v1/lswitch/%s" % lswitch_id
- return self.do_request(HTTP_DELETE, uri)
-
- def get_loadbalancer_config(self, edge_id):
- uri = self._build_uri_path(edge_id, LOADBALANCER_SERVICE)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def enable_service_loadbalancer(self, edge_id, config):
- uri = self._build_uri_path(edge_id, LOADBALANCER_SERVICE)
- return self.do_request(HTTP_PUT, uri, config)
-
- def update_firewall(self, edge_id, fw_req):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE)
- return self.do_request(HTTP_PUT, uri, fw_req)
-
- def delete_firewall(self, edge_id):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE, None)
- return self.do_request(HTTP_DELETE, uri)
-
- def update_firewall_rule(self, edge_id, vcns_rule_id, fwr_req):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE,
- FIREWALL_RULE_RESOURCE,
- vcns_rule_id)
- return self.do_request(HTTP_PUT, uri, fwr_req)
-
- def delete_firewall_rule(self, edge_id, vcns_rule_id):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE,
- FIREWALL_RULE_RESOURCE,
- vcns_rule_id)
- return self.do_request(HTTP_DELETE, uri)
-
- def add_firewall_rule_above(self, edge_id, ref_vcns_rule_id, fwr_req):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE,
- FIREWALL_RULE_RESOURCE)
- uri += "?aboveRuleId=" + ref_vcns_rule_id
- return self.do_request(HTTP_POST, uri, fwr_req)
-
- def add_firewall_rule(self, edge_id, fwr_req):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE,
- FIREWALL_RULE_RESOURCE)
- return self.do_request(HTTP_POST, uri, fwr_req)
-
- def get_firewall(self, edge_id):
- uri = self._build_uri_path(edge_id, FIREWALL_SERVICE)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def get_firewall_rule(self, edge_id, vcns_rule_id):
- uri = self._build_uri_path(
- edge_id, FIREWALL_SERVICE,
- FIREWALL_RULE_RESOURCE,
- vcns_rule_id)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- #
- #Edge LBAAS call helper
- #
- def create_vip(self, edge_id, vip_new):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- VIP_RESOURCE)
- return self.do_request(HTTP_POST, uri, vip_new)
-
- def get_vip(self, edge_id, vip_vseid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- VIP_RESOURCE, vip_vseid)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def update_vip(self, edge_id, vip_vseid, vip_new):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- VIP_RESOURCE, vip_vseid)
- return self.do_request(HTTP_PUT, uri, vip_new)
-
- def delete_vip(self, edge_id, vip_vseid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- VIP_RESOURCE, vip_vseid)
- return self.do_request(HTTP_DELETE, uri)
-
- def create_pool(self, edge_id, pool_new):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- POOL_RESOURCE)
- return self.do_request(HTTP_POST, uri, pool_new)
-
- def get_pool(self, edge_id, pool_vseid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- POOL_RESOURCE, pool_vseid)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def update_pool(self, edge_id, pool_vseid, pool_new):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- POOL_RESOURCE, pool_vseid)
- return self.do_request(HTTP_PUT, uri, pool_new)
-
- def delete_pool(self, edge_id, pool_vseid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- POOL_RESOURCE, pool_vseid)
- return self.do_request(HTTP_DELETE, uri)
-
- def create_health_monitor(self, edge_id, monitor_new):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- MONITOR_RESOURCE)
- return self.do_request(HTTP_POST, uri, monitor_new)
-
- def get_health_monitor(self, edge_id, monitor_vseid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- MONITOR_RESOURCE, monitor_vseid)
- return self.do_request(HTTP_GET, uri, decode=True)
-
- def update_health_monitor(self, edge_id, monitor_vseid, monitor_new):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- MONITOR_RESOURCE,
- monitor_vseid)
- return self.do_request(HTTP_PUT, uri, monitor_new)
-
- def delete_health_monitor(self, edge_id, monitor_vseid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- MONITOR_RESOURCE,
- monitor_vseid)
- return self.do_request(HTTP_DELETE, uri)
-
- def create_app_profile(self, edge_id, app_profile):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- APP_PROFILE_RESOURCE)
- return self.do_request(HTTP_POST, uri, app_profile)
-
- def update_app_profile(self, edge_id, app_profileid, app_profile):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- APP_PROFILE_RESOURCE, app_profileid)
- return self.do_request(HTTP_PUT, uri, app_profile)
-
- def delete_app_profile(self, edge_id, app_profileid):
- uri = self._build_uri_path(
- edge_id, LOADBALANCER_SERVICE,
- APP_PROFILE_RESOURCE,
- app_profileid)
- return self.do_request(HTTP_DELETE, uri)
-
- def update_ipsec_config(self, edge_id, ipsec_config):
- uri = self._build_uri_path(edge_id, IPSEC_VPN_SERVICE)
- return self.do_request(HTTP_PUT, uri, ipsec_config)
-
- def delete_ipsec_config(self, edge_id):
- uri = self._build_uri_path(edge_id, IPSEC_VPN_SERVICE)
- return self.do_request(HTTP_DELETE, uri)
-
- def get_ipsec_config(self, edge_id):
- uri = self._build_uri_path(edge_id, IPSEC_VPN_SERVICE)
- return self.do_request(HTTP_GET, uri)
-
- def _build_uri_path(self, edge_id,
- service,
- resource=None,
- resource_id=None,
- parent_resource_id=None,
- fields=None,
- relations=None,
- filters=None,
- types=None,
- is_attachment=False):
- uri_prefix = "%s/%s/%s" % (URI_PREFIX, edge_id, service)
- if resource:
- res_path = resource
- if resource_id:
- res_path += "/%s" % resource_id
- uri_path = "%s/%s" % (uri_prefix, res_path)
- else:
- uri_path = uri_prefix
- return uri_path
+++ /dev/null
-# Copyright 2013 VMware, 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.
-
-from oslo_config import cfg
-
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.common import config # noqa
-from neutron.plugins.vmware.vshield import edge_appliance_driver
-from neutron.plugins.vmware.vshield.tasks import tasks
-from neutron.plugins.vmware.vshield import vcns
-
-LOG = logging.getLogger(__name__)
-
-
-class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver):
-
- def __init__(self, callbacks):
- super(VcnsDriver, self).__init__()
-
- self.callbacks = callbacks
- self.vcns_uri = cfg.CONF.vcns.manager_uri
- self.vcns_user = cfg.CONF.vcns.user
- self.vcns_passwd = cfg.CONF.vcns.password
- self.datacenter_moid = cfg.CONF.vcns.datacenter_moid
- self.deployment_container_id = cfg.CONF.vcns.deployment_container_id
- self.resource_pool_id = cfg.CONF.vcns.resource_pool_id
- self.datastore_id = cfg.CONF.vcns.datastore_id
- self.external_network = cfg.CONF.vcns.external_network
- interval = cfg.CONF.vcns.task_status_check_interval
- self.task_manager = tasks.TaskManager(interval)
- self.task_manager.start()
- self.vcns = vcns.Vcns(self.vcns_uri, self.vcns_user, self.vcns_passwd)
+++ /dev/null
-# Copyright 2013 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 os
-
-from neutron.plugins.vmware.api_client import client as nsx_client
-from neutron.plugins.vmware.api_client import eventlet_client
-from neutron.plugins.vmware import extensions
-import neutron.plugins.vmware.plugin as neutron_plugin
-from neutron.plugins.vmware.vshield import vcns
-
-
-plugin = neutron_plugin.NsxPlugin
-api_client = nsx_client.NsxApiClient
-evt_client = eventlet_client.EventletApiClient
-vcns_class = vcns.Vcns
-
-STUBS_PATH = os.path.join(os.path.dirname(__file__), 'etc')
-NSXEXT_PATH = os.path.dirname(extensions.__file__)
-NSXAPI_NAME = '%s.%s' % (api_client.__module__, api_client.__name__)
-PLUGIN_NAME = '%s.%s' % (plugin.__module__, plugin.__name__)
-CLIENT_NAME = '%s.%s' % (evt_client.__module__, evt_client.__name__)
-VCNS_NAME = '%s.%s' % (vcns_class.__module__, vcns_class.__name__)
-
-
-def get_fake_conf(filename):
- return os.path.join(STUBS_PATH, filename)
-
-
-def nsx_method(method_name, module_name='nsxlib'):
- return '%s.%s.%s' % ('neutron.plugins.vmware', module_name, method_name)
+++ /dev/null
-# Copyright 2012 VMware, 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.
-
-from oslo_serialization import jsonutils
-import six.moves.urllib.parse as urlparse
-
-from neutron.openstack.common import log as logging
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.api_client import exception as api_exc
-
-
-LOG = logging.getLogger(__name__)
-MAX_NAME_LEN = 40
-
-
-def _validate_name(name):
- if name and len(name) > MAX_NAME_LEN:
- raise Exception("Logical switch name exceeds %d characters",
- MAX_NAME_LEN)
-
-
-def _validate_resource(body):
- _validate_name(body.get('display_name'))
-
-
-class FakeClient(object):
-
- LSWITCH_RESOURCE = 'lswitch'
- LPORT_RESOURCE = 'lport'
- LROUTER_RESOURCE = 'lrouter'
- NAT_RESOURCE = 'nat'
- LQUEUE_RESOURCE = 'lqueue'
- SECPROF_RESOURCE = 'securityprofile'
- LSWITCH_STATUS = 'lswitchstatus'
- LROUTER_STATUS = 'lrouterstatus'
- LSWITCH_LPORT_RESOURCE = 'lswitch_lport'
- LROUTER_LPORT_RESOURCE = 'lrouter_lport'
- LROUTER_NAT_RESOURCE = 'lrouter_nat'
- LSWITCH_LPORT_STATUS = 'lswitch_lportstatus'
- LSWITCH_LPORT_ATT = 'lswitch_lportattachment'
- LROUTER_LPORT_STATUS = 'lrouter_lportstatus'
- LROUTER_LPORT_ATT = 'lrouter_lportattachment'
- GWSERVICE_RESOURCE = 'gatewayservice'
-
- RESOURCES = [LSWITCH_RESOURCE, LROUTER_RESOURCE, LQUEUE_RESOURCE,
- LPORT_RESOURCE, NAT_RESOURCE, SECPROF_RESOURCE,
- GWSERVICE_RESOURCE]
-
- FAKE_GET_RESPONSES = {
- LSWITCH_RESOURCE: "fake_get_lswitch.json",
- LSWITCH_LPORT_RESOURCE: "fake_get_lswitch_lport.json",
- LSWITCH_LPORT_STATUS: "fake_get_lswitch_lport_status.json",
- LSWITCH_LPORT_ATT: "fake_get_lswitch_lport_att.json",
- LROUTER_RESOURCE: "fake_get_lrouter.json",
- LROUTER_LPORT_RESOURCE: "fake_get_lrouter_lport.json",
- LROUTER_LPORT_STATUS: "fake_get_lrouter_lport_status.json",
- LROUTER_LPORT_ATT: "fake_get_lrouter_lport_att.json",
- LROUTER_STATUS: "fake_get_lrouter_status.json",
- LROUTER_NAT_RESOURCE: "fake_get_lrouter_nat.json",
- SECPROF_RESOURCE: "fake_get_security_profile.json",
- LQUEUE_RESOURCE: "fake_get_lqueue.json",
- GWSERVICE_RESOURCE: "fake_get_gwservice.json"
- }
-
- FAKE_POST_RESPONSES = {
- LSWITCH_RESOURCE: "fake_post_lswitch.json",
- LROUTER_RESOURCE: "fake_post_lrouter.json",
- LSWITCH_LPORT_RESOURCE: "fake_post_lswitch_lport.json",
- LROUTER_LPORT_RESOURCE: "fake_post_lrouter_lport.json",
- LROUTER_NAT_RESOURCE: "fake_post_lrouter_nat.json",
- SECPROF_RESOURCE: "fake_post_security_profile.json",
- LQUEUE_RESOURCE: "fake_post_lqueue.json",
- GWSERVICE_RESOURCE: "fake_post_gwservice.json"
- }
-
- FAKE_PUT_RESPONSES = {
- LSWITCH_RESOURCE: "fake_post_lswitch.json",
- LROUTER_RESOURCE: "fake_post_lrouter.json",
- LSWITCH_LPORT_RESOURCE: "fake_post_lswitch_lport.json",
- LROUTER_LPORT_RESOURCE: "fake_post_lrouter_lport.json",
- LROUTER_NAT_RESOURCE: "fake_post_lrouter_nat.json",
- LSWITCH_LPORT_ATT: "fake_put_lswitch_lport_att.json",
- LROUTER_LPORT_ATT: "fake_put_lrouter_lport_att.json",
- SECPROF_RESOURCE: "fake_post_security_profile.json",
- LQUEUE_RESOURCE: "fake_post_lqueue.json",
- GWSERVICE_RESOURCE: "fake_post_gwservice.json"
- }
-
- MANAGED_RELATIONS = {
- LSWITCH_RESOURCE: [],
- LROUTER_RESOURCE: [],
- LSWITCH_LPORT_RESOURCE: ['LogicalPortAttachment'],
- LROUTER_LPORT_RESOURCE: ['LogicalPortAttachment'],
- }
-
- _validators = {
- LSWITCH_RESOURCE: _validate_resource,
- LSWITCH_LPORT_RESOURCE: _validate_resource,
- LROUTER_LPORT_RESOURCE: _validate_resource,
- SECPROF_RESOURCE: _validate_resource,
- LQUEUE_RESOURCE: _validate_resource,
- GWSERVICE_RESOURCE: _validate_resource
- }
-
- def __init__(self, fake_files_path):
- self.fake_files_path = fake_files_path
- self._fake_lswitch_dict = {}
- self._fake_lrouter_dict = {}
- self._fake_lswitch_lport_dict = {}
- self._fake_lrouter_lport_dict = {}
- self._fake_lrouter_nat_dict = {}
- self._fake_lswitch_lportstatus_dict = {}
- self._fake_lrouter_lportstatus_dict = {}
- self._fake_securityprofile_dict = {}
- self._fake_lqueue_dict = {}
- self._fake_gatewayservice_dict = {}
-
- def _get_tag(self, resource, scope):
- tags = [tag['tag'] for tag in resource['tags']
- if tag['scope'] == scope]
- return len(tags) > 0 and tags[0]
-
- def _get_filters(self, querystring):
- if not querystring:
- return (None, None, None, None)
- params = urlparse.parse_qs(querystring)
- tag_filter = None
- attr_filter = None
- if 'tag' in params and 'tag_scope' in params:
- tag_filter = {'scope': params['tag_scope'][0],
- 'tag': params['tag'][0]}
- elif 'uuid' in params:
- attr_filter = {'uuid': params['uuid'][0]}
- # Handle page length and page cursor parameter
- page_len = params.get('_page_length')
- page_cursor = params.get('_page_cursor')
- if page_len:
- page_len = int(page_len[0])
- else:
- # Explicitly set it to None (avoid 0 or empty list)
- page_len = None
- return (tag_filter, attr_filter, page_len, page_cursor)
-
- def _add_lswitch(self, body):
- fake_lswitch = jsonutils.loads(body)
- fake_lswitch['uuid'] = uuidutils.generate_uuid()
- self._fake_lswitch_dict[fake_lswitch['uuid']] = fake_lswitch
- # put the tenant_id and the zone_uuid in the main dict
- # for simplyfying templating
- zone_uuid = fake_lswitch['transport_zones'][0]['zone_uuid']
- fake_lswitch['zone_uuid'] = zone_uuid
- fake_lswitch['tenant_id'] = self._get_tag(fake_lswitch, 'os_tid')
- fake_lswitch['lport_count'] = 0
- # set status value
- fake_lswitch['status'] = 'true'
- return fake_lswitch
-
- def _build_lrouter(self, body, uuid=None):
- fake_lrouter = jsonutils.loads(body)
- if uuid:
- fake_lrouter['uuid'] = uuid
- fake_lrouter['tenant_id'] = self._get_tag(fake_lrouter, 'os_tid')
- default_nexthop = fake_lrouter['routing_config'].get(
- 'default_route_next_hop')
- if default_nexthop:
- fake_lrouter['default_next_hop'] = default_nexthop.get(
- 'gateway_ip_address', '0.0.0.0')
- else:
- fake_lrouter['default_next_hop'] = '0.0.0.0'
- # NOTE(salv-orlando): We won't make the Fake NSX API client
- # aware of NSX version. The long term plan is to replace it
- # with behavioral mocking of NSX API requests
- if 'distributed' not in fake_lrouter:
- fake_lrouter['distributed'] = False
- distributed_json = ('"distributed": %s,' %
- str(fake_lrouter['distributed']).lower())
- fake_lrouter['distributed_json'] = distributed_json
- return fake_lrouter
-
- def _add_lrouter(self, body):
- fake_lrouter = self._build_lrouter(body,
- uuidutils.generate_uuid())
- self._fake_lrouter_dict[fake_lrouter['uuid']] = fake_lrouter
- fake_lrouter['lport_count'] = 0
- # set status value
- fake_lrouter['status'] = 'true'
- return fake_lrouter
-
- def _add_lqueue(self, body):
- fake_lqueue = jsonutils.loads(body)
- fake_lqueue['uuid'] = uuidutils.generate_uuid()
- self._fake_lqueue_dict[fake_lqueue['uuid']] = fake_lqueue
- return fake_lqueue
-
- def _add_lswitch_lport(self, body, ls_uuid):
- fake_lport = jsonutils.loads(body)
- new_uuid = uuidutils.generate_uuid()
- fake_lport['uuid'] = new_uuid
- # put the tenant_id and the ls_uuid in the main dict
- # for simplyfying templating
- fake_lport['ls_uuid'] = ls_uuid
- fake_lport['tenant_id'] = self._get_tag(fake_lport, 'os_tid')
- fake_lport['neutron_port_id'] = self._get_tag(fake_lport,
- 'q_port_id')
- fake_lport['neutron_device_id'] = self._get_tag(fake_lport, 'vm_id')
- fake_lport['att_type'] = "NoAttachment"
- fake_lport['att_info_json'] = ''
- self._fake_lswitch_lport_dict[fake_lport['uuid']] = fake_lport
-
- fake_lswitch = self._fake_lswitch_dict[ls_uuid]
- fake_lswitch['lport_count'] += 1
- fake_lport_status = fake_lport.copy()
- fake_lport_status['ls_tenant_id'] = fake_lswitch['tenant_id']
- fake_lport_status['ls_uuid'] = fake_lswitch['uuid']
- fake_lport_status['ls_name'] = fake_lswitch['display_name']
- fake_lport_status['ls_zone_uuid'] = fake_lswitch['zone_uuid']
- # set status value
- fake_lport['status'] = 'true'
- self._fake_lswitch_lportstatus_dict[new_uuid] = fake_lport_status
- return fake_lport
-
- def _build_lrouter_lport(self, body, new_uuid=None, lr_uuid=None):
- fake_lport = jsonutils.loads(body)
- if new_uuid:
- fake_lport['uuid'] = new_uuid
- # put the tenant_id and the le_uuid in the main dict
- # for simplyfying templating
- if lr_uuid:
- fake_lport['lr_uuid'] = lr_uuid
- fake_lport['tenant_id'] = self._get_tag(fake_lport, 'os_tid')
- fake_lport['neutron_port_id'] = self._get_tag(fake_lport,
- 'q_port_id')
- # replace ip_address with its json dump
- if 'ip_addresses' in fake_lport:
- ip_addresses_json = jsonutils.dumps(fake_lport['ip_addresses'])
- fake_lport['ip_addresses_json'] = ip_addresses_json
- return fake_lport
-
- def _add_lrouter_lport(self, body, lr_uuid):
- new_uuid = uuidutils.generate_uuid()
- fake_lport = self._build_lrouter_lport(body, new_uuid, lr_uuid)
- self._fake_lrouter_lport_dict[fake_lport['uuid']] = fake_lport
- try:
- fake_lrouter = self._fake_lrouter_dict[lr_uuid]
- except KeyError:
- raise api_exc.ResourceNotFound()
- fake_lrouter['lport_count'] += 1
- fake_lport_status = fake_lport.copy()
- fake_lport_status['lr_tenant_id'] = fake_lrouter['tenant_id']
- fake_lport_status['lr_uuid'] = fake_lrouter['uuid']
- fake_lport_status['lr_name'] = fake_lrouter['display_name']
- self._fake_lrouter_lportstatus_dict[new_uuid] = fake_lport_status
- return fake_lport
-
- def _add_securityprofile(self, body):
- fake_securityprofile = jsonutils.loads(body)
- fake_securityprofile['uuid'] = uuidutils.generate_uuid()
- fake_securityprofile['tenant_id'] = self._get_tag(
- fake_securityprofile, 'os_tid')
-
- fake_securityprofile['nova_spid'] = self._get_tag(fake_securityprofile,
- 'nova_spid')
- self._fake_securityprofile_dict[fake_securityprofile['uuid']] = (
- fake_securityprofile)
- return fake_securityprofile
-
- def _add_lrouter_nat(self, body, lr_uuid):
- fake_nat = jsonutils.loads(body)
- new_uuid = uuidutils.generate_uuid()
- fake_nat['uuid'] = new_uuid
- fake_nat['lr_uuid'] = lr_uuid
- self._fake_lrouter_nat_dict[fake_nat['uuid']] = fake_nat
- if 'match' in fake_nat:
- match_json = jsonutils.dumps(fake_nat['match'])
- fake_nat['match_json'] = match_json
- return fake_nat
-
- def _add_gatewayservice(self, body):
- fake_gwservice = jsonutils.loads(body)
- fake_gwservice['uuid'] = str(uuidutils.generate_uuid())
- fake_gwservice['tenant_id'] = self._get_tag(
- fake_gwservice, 'os_tid')
- # FIXME(salvatore-orlando): For simplicity we're managing only a
- # single device. Extend the fake client for supporting multiple devices
- first_gw = fake_gwservice['gateways'][0]
- fake_gwservice['transport_node_uuid'] = first_gw['transport_node_uuid']
- fake_gwservice['device_id'] = first_gw['device_id']
- self._fake_gatewayservice_dict[fake_gwservice['uuid']] = (
- fake_gwservice)
- return fake_gwservice
-
- def _build_relation(self, src, dst, resource_type, relation):
- if relation not in self.MANAGED_RELATIONS[resource_type]:
- return # Relation is not desired in output
- if '_relations' not in src or not src['_relations'].get(relation):
- return # Item does not have relation
- relation_data = src['_relations'].get(relation)
- dst_relations = dst.get('_relations', {})
- dst_relations[relation] = relation_data
- dst['_relations'] = dst_relations
-
- def _fill_attachment(self, att_data, ls_uuid=None,
- lr_uuid=None, lp_uuid=None):
- new_data = att_data.copy()
- for k in ('ls_uuid', 'lr_uuid', 'lp_uuid'):
- if locals().get(k):
- new_data[k] = locals()[k]
-
- def populate_field(field_name):
- if field_name in att_data:
- new_data['%s_field' % field_name] = ('"%s" : "%s",'
- % (field_name,
- att_data[field_name]))
- del new_data[field_name]
- else:
- new_data['%s_field' % field_name] = ""
-
- for field in ['vif_uuid', 'peer_port_href', 'vlan_id',
- 'peer_port_uuid', 'l3_gateway_service_uuid']:
- populate_field(field)
- return new_data
-
- def _get_resource_type(self, path):
- """Get resource type.
-
- Identifies resource type and relevant uuids in the uri
-
- /ws.v1/lswitch/xxx
- /ws.v1/lswitch/xxx/status
- /ws.v1/lswitch/xxx/lport/yyy
- /ws.v1/lswitch/xxx/lport/yyy/status
- /ws.v1/lrouter/zzz
- /ws.v1/lrouter/zzz/status
- /ws.v1/lrouter/zzz/lport/www
- /ws.v1/lrouter/zzz/lport/www/status
- /ws.v1/lqueue/xxx
- """
- # The first element will always be 'ws.v1' - so we just discard it
- uri_split = path.split('/')[1:]
- # parse uri_split backwards
- suffix = ""
- idx = len(uri_split) - 1
- if 'status' in uri_split[idx]:
- suffix = "status"
- idx = idx - 1
- elif 'attachment' in uri_split[idx]:
- suffix = "attachment"
- idx = idx - 1
- # then check if we have an uuid
- uuids = []
- if uri_split[idx].replace('-', '') not in self.RESOURCES:
- uuids.append(uri_split[idx])
- idx = idx - 1
- resource_type = "%s%s" % (uri_split[idx], suffix)
- if idx > 1:
- uuids.insert(0, uri_split[idx - 1])
- resource_type = "%s_%s" % (uri_split[idx - 2], resource_type)
- return (resource_type.replace('-', ''), uuids)
-
- def _list(self, resource_type, response_file,
- parent_uuid=None, query=None, relations=None):
- (tag_filter, attr_filter,
- page_len, page_cursor) = self._get_filters(query)
- # result_count attribute in response should appear only when
- # page_cursor is not specified
- do_result_count = not page_cursor
- with open("%s/%s" % (self.fake_files_path, response_file)) as f:
- response_template = f.read()
- res_dict = getattr(self, '_fake_%s_dict' % resource_type)
- if parent_uuid == '*':
- parent_uuid = None
- # NSX raises ResourceNotFound if lswitch doesn't exist and is not *
- elif not res_dict and resource_type == self.LSWITCH_LPORT_RESOURCE:
- raise api_exc.ResourceNotFound()
-
- def _attr_match(res_uuid):
- if not attr_filter:
- return True
- item = res_dict[res_uuid]
- for (attr, value) in attr_filter.iteritems():
- if item.get(attr) != value:
- return False
- return True
-
- def _tag_match(res_uuid):
- if not tag_filter:
- return True
- return any([x['scope'] == tag_filter['scope'] and
- x['tag'] == tag_filter['tag']
- for x in res_dict[res_uuid]['tags']])
-
- def _lswitch_match(res_uuid):
- # verify that the switch exist
- if parent_uuid and parent_uuid not in self._fake_lswitch_dict:
- raise Exception(_("lswitch:%s not found") % parent_uuid)
- if (not parent_uuid
- or res_dict[res_uuid].get('ls_uuid') == parent_uuid):
- return True
- return False
-
- def _lrouter_match(res_uuid):
- # verify that the router exist
- if parent_uuid and parent_uuid not in self._fake_lrouter_dict:
- raise api_exc.ResourceNotFound()
- if (not parent_uuid or
- res_dict[res_uuid].get('lr_uuid') == parent_uuid):
- return True
- return False
-
- def _cursor_match(res_uuid, page_cursor):
- if not page_cursor:
- return True
- if page_cursor == res_uuid:
- # always return True once page_cursor has been found
- page_cursor = None
- return True
- return False
-
- def _build_item(resource):
- item = jsonutils.loads(response_template % resource)
- if relations:
- for relation in relations:
- self._build_relation(resource, item,
- resource_type, relation)
- return item
-
- for item in res_dict.itervalues():
- if 'tags' in item:
- item['tags_json'] = jsonutils.dumps(item['tags'])
- if resource_type in (self.LSWITCH_LPORT_RESOURCE,
- self.LSWITCH_LPORT_ATT,
- self.LSWITCH_LPORT_STATUS):
- parent_func = _lswitch_match
- elif resource_type in (self.LROUTER_LPORT_RESOURCE,
- self.LROUTER_LPORT_ATT,
- self.LROUTER_NAT_RESOURCE,
- self.LROUTER_LPORT_STATUS):
- parent_func = _lrouter_match
- else:
- parent_func = lambda x: True
-
- items = [_build_item(res_dict[res_uuid])
- for res_uuid in res_dict
- if (parent_func(res_uuid) and
- _tag_match(res_uuid) and
- _attr_match(res_uuid) and
- _cursor_match(res_uuid, page_cursor))]
- # Rather inefficient, but hey this is just a mock!
- next_cursor = None
- total_items = len(items)
- if page_len:
- try:
- next_cursor = items[page_len]['uuid']
- except IndexError:
- next_cursor = None
- items = items[:page_len]
- response_dict = {'results': items}
- if next_cursor:
- response_dict['page_cursor'] = next_cursor
- if do_result_count:
- response_dict['result_count'] = total_items
- return jsonutils.dumps(response_dict)
-
- def _show(self, resource_type, response_file,
- uuid1, uuid2=None, relations=None):
- target_uuid = uuid2 or uuid1
- if resource_type.endswith('attachment'):
- resource_type = resource_type[:resource_type.index('attachment')]
- with open("%s/%s" % (self.fake_files_path, response_file)) as f:
- response_template = f.read()
- res_dict = getattr(self, '_fake_%s_dict' % resource_type)
- for item in res_dict.itervalues():
- if 'tags' in item:
- item['tags_json'] = jsonutils.dumps(item['tags'])
-
- # replace sec prof rules with their json dump
- def jsonify_rules(rule_key):
- if rule_key in item:
- rules_json = jsonutils.dumps(item[rule_key])
- item['%s_json' % rule_key] = rules_json
- jsonify_rules('logical_port_egress_rules')
- jsonify_rules('logical_port_ingress_rules')
-
- items = [jsonutils.loads(response_template % res_dict[res_uuid])
- for res_uuid in res_dict if res_uuid == target_uuid]
- if items:
- return jsonutils.dumps(items[0])
- raise api_exc.ResourceNotFound()
-
- def handle_get(self, url):
- #TODO(salvatore-orlando): handle field selection
- parsedurl = urlparse.urlparse(url)
- (res_type, uuids) = self._get_resource_type(parsedurl.path)
- relations = urlparse.parse_qs(parsedurl.query).get('relations')
- response_file = self.FAKE_GET_RESPONSES.get(res_type)
- if not response_file:
- raise api_exc.NsxApiException()
- if 'lport' in res_type or 'nat' in res_type:
- if len(uuids) > 1:
- return self._show(res_type, response_file, uuids[0],
- uuids[1], relations=relations)
- else:
- return self._list(res_type, response_file, uuids[0],
- query=parsedurl.query, relations=relations)
- elif ('lswitch' in res_type or
- 'lrouter' in res_type or
- self.SECPROF_RESOURCE in res_type or
- self.LQUEUE_RESOURCE in res_type or
- 'gatewayservice' in res_type):
- LOG.debug("UUIDS:%s", uuids)
- if uuids:
- return self._show(res_type, response_file, uuids[0],
- relations=relations)
- else:
- return self._list(res_type, response_file,
- query=parsedurl.query,
- relations=relations)
- else:
- raise Exception("unknown resource:%s" % res_type)
-
- def handle_post(self, url, body):
- parsedurl = urlparse.urlparse(url)
- (res_type, uuids) = self._get_resource_type(parsedurl.path)
- response_file = self.FAKE_POST_RESPONSES.get(res_type)
- if not response_file:
- raise Exception("resource not found")
- with open("%s/%s" % (self.fake_files_path, response_file)) as f:
- response_template = f.read()
- add_resource = getattr(self, '_add_%s' % res_type)
- body_json = jsonutils.loads(body)
- val_func = self._validators.get(res_type)
- if val_func:
- val_func(body_json)
- args = [body]
- if uuids:
- args.append(uuids[0])
- response = response_template % add_resource(*args)
- return response
-
- def handle_put(self, url, body):
- parsedurl = urlparse.urlparse(url)
- (res_type, uuids) = self._get_resource_type(parsedurl.path)
- response_file = self.FAKE_PUT_RESPONSES.get(res_type)
- if not response_file:
- raise Exception("resource not found")
- with open("%s/%s" % (self.fake_files_path, response_file)) as f:
- response_template = f.read()
- # Manage attachment operations
- is_attachment = False
- if res_type.endswith('attachment'):
- is_attachment = True
- res_type = res_type[:res_type.index('attachment')]
- res_dict = getattr(self, '_fake_%s_dict' % res_type)
- body_json = jsonutils.loads(body)
- val_func = self._validators.get(res_type)
- if val_func:
- val_func(body_json)
- try:
- resource = res_dict[uuids[-1]]
- except KeyError:
- raise api_exc.ResourceNotFound()
- if not is_attachment:
- edit_resource = getattr(self, '_build_%s' % res_type, None)
- if edit_resource:
- body_json = edit_resource(body)
- resource.update(body_json)
- else:
- relations = resource.get("_relations", {})
- body_2 = jsonutils.loads(body)
- resource['att_type'] = body_2['type']
- relations['LogicalPortAttachment'] = body_2
- resource['_relations'] = relations
- if body_2['type'] == "PatchAttachment":
- # We need to do a trick here
- if self.LROUTER_RESOURCE in res_type:
- res_type_2 = res_type.replace(self.LROUTER_RESOURCE,
- self.LSWITCH_RESOURCE)
- elif self.LSWITCH_RESOURCE in res_type:
- res_type_2 = res_type.replace(self.LSWITCH_RESOURCE,
- self.LROUTER_RESOURCE)
- res_dict_2 = getattr(self, '_fake_%s_dict' % res_type_2)
- body_2['peer_port_uuid'] = uuids[-1]
- resource_2 = \
- res_dict_2[jsonutils.loads(body)['peer_port_uuid']]
- relations_2 = resource_2.get("_relations")
- if not relations_2:
- relations_2 = {}
- relations_2['LogicalPortAttachment'] = body_2
- resource_2['_relations'] = relations_2
- resource['peer_port_uuid'] = body_2['peer_port_uuid']
- resource['att_info_json'] = (
- "\"peer_port_uuid\": \"%s\"," %
- resource_2['uuid'])
- resource_2['att_info_json'] = (
- "\"peer_port_uuid\": \"%s\"," %
- body_2['peer_port_uuid'])
- elif body_2['type'] == "L3GatewayAttachment":
- resource['attachment_gwsvc_uuid'] = (
- body_2['l3_gateway_service_uuid'])
- resource['vlan_id'] = body_2.get('vlan_id')
- elif body_2['type'] == "L2GatewayAttachment":
- resource['attachment_gwsvc_uuid'] = (
- body_2['l2_gateway_service_uuid'])
- elif body_2['type'] == "VifAttachment":
- resource['vif_uuid'] = body_2['vif_uuid']
- resource['att_info_json'] = (
- "\"vif_uuid\": \"%s\"," % body_2['vif_uuid'])
-
- if not is_attachment:
- response = response_template % resource
- else:
- if res_type == self.LROUTER_LPORT_RESOURCE:
- lr_uuid = uuids[0]
- ls_uuid = None
- elif res_type == self.LSWITCH_LPORT_RESOURCE:
- ls_uuid = uuids[0]
- lr_uuid = None
- lp_uuid = uuids[1]
- response = response_template % self._fill_attachment(
- jsonutils.loads(body), ls_uuid, lr_uuid, lp_uuid)
- return response
-
- def handle_delete(self, url):
- parsedurl = urlparse.urlparse(url)
- (res_type, uuids) = self._get_resource_type(parsedurl.path)
- response_file = self.FAKE_PUT_RESPONSES.get(res_type)
- if not response_file:
- raise Exception("resource not found")
- res_dict = getattr(self, '_fake_%s_dict' % res_type)
- try:
- del res_dict[uuids[-1]]
- except KeyError:
- raise api_exc.ResourceNotFound()
- return ""
-
- def fake_request(self, *args, **kwargs):
- method = args[0]
- handler = getattr(self, "handle_%s" % method.lower())
- return handler(*args[1:])
-
- def reset_all(self):
- self._fake_lswitch_dict.clear()
- self._fake_lrouter_dict.clear()
- self._fake_lswitch_lport_dict.clear()
- self._fake_lrouter_lport_dict.clear()
- self._fake_lswitch_lportstatus_dict.clear()
- self._fake_lrouter_lportstatus_dict.clear()
- self._fake_lqueue_dict.clear()
- self._fake_securityprofile_dict.clear()
- self._fake_gatewayservice_dict.clear()
+++ /dev/null
-# Copyright 2011 VMware, Inc.
-#
-# 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 httplib
-
-from neutron.plugins.vmware import api_client
-from neutron.tests import base
-
-
-class ApiCommonTest(base.BaseTestCase):
-
- def test_ctrl_conn_to_str(self):
- conn = httplib.HTTPSConnection('localhost', 4242, timeout=0)
- self.assertTrue(
- api_client.ctrl_conn_to_str(conn) == 'https://localhost:4242')
-
- conn = httplib.HTTPConnection('localhost', 4242, timeout=0)
- self.assertTrue(
- api_client.ctrl_conn_to_str(conn) == 'http://localhost:4242')
-
- self.assertRaises(TypeError, api_client.ctrl_conn_to_str,
- ('not an httplib.HTTPSConnection'))
+++ /dev/null
-# Copyright (C) 2009-2012 VMware, Inc. 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 httplib
-import random
-
-import eventlet
-from eventlet.green import urllib2
-import mock
-
-from neutron.i18n import _LI
-from neutron.openstack.common import log as logging
-from neutron.plugins.vmware.api_client import eventlet_client as client
-from neutron.plugins.vmware.api_client import eventlet_request as request
-from neutron.tests import base
-from neutron.tests.unit import vmware
-
-
-LOG = logging.getLogger(__name__)
-
-
-REQUEST_TIMEOUT = 1
-
-
-def fetch(url):
- return urllib2.urlopen(url).read()
-
-
-class ApiRequestEventletTest(base.BaseTestCase):
-
- def setUp(self):
-
- super(ApiRequestEventletTest, self).setUp()
- self.client = client.EventletApiClient(
- [("127.0.0.1", 4401, True)], "admin", "admin")
- self.url = "/ws.v1/_debug"
- self.req = request.EventletApiRequest(self.client, self.url)
-
- def tearDown(self):
- self.client = None
- self.req = None
- super(ApiRequestEventletTest, self).tearDown()
-
- def test_construct_eventlet_api_request(self):
- e = request.EventletApiRequest(self.client, self.url)
- self.assertIsNotNone(e)
-
- def test_apirequest_spawn(self):
- def x(id):
- eventlet.greenthread.sleep(random.random())
- LOG.info(_LI('spawned: %d'), id)
-
- for i in range(10):
- request.EventletApiRequest._spawn(x, i)
-
- def test_apirequest_start(self):
- for i in range(10):
- a = request.EventletApiRequest(
- self.client, self.url)
- a._handle_request = mock.Mock()
- a.start()
- eventlet.greenthread.sleep(0.1)
- LOG.info(_LI('_handle_request called: %s'),
- a._handle_request.called)
- request.EventletApiRequest.joinall()
-
- def test_join_with_handle_request(self):
- self.req._handle_request = mock.Mock()
- self.req.start()
- self.req.join()
- self.assertTrue(self.req._handle_request.called)
-
- def test_join_without_handle_request(self):
- self.req._handle_request = mock.Mock()
- self.req.join()
- self.assertFalse(self.req._handle_request.called)
-
- def test_copy(self):
- req = self.req.copy()
- for att in [
- '_api_client', '_url', '_method', '_body', '_headers',
- '_http_timeout', '_request_timeout', '_retries',
- '_redirects', '_auto_login']:
- self.assertTrue(getattr(req, att) is getattr(self.req, att))
-
- def test_request_error(self):
- self.assertIsNone(self.req.request_error)
-
- def test_run_and_handle_request(self):
- self.req._request_timeout = None
- self.req._handle_request = mock.Mock()
- self.req.start()
- self.req.join()
- self.assertTrue(self.req._handle_request.called)
-
- def test_run_and_timeout(self):
- def my_handle_request():
- LOG.info('my_handle_request() self: %s' % self.req)
- LOG.info('my_handle_request() dir(self): %s' % dir(self.req))
- eventlet.greenthread.sleep(REQUEST_TIMEOUT * 2)
-
- with mock.patch.object(
- self.req,
- '_handle_request',
- new=my_handle_request
- ):
- self.req._request_timeout = REQUEST_TIMEOUT
- self.req.start()
- self.assertIsNone(self.req.join())
-
- def prep_issue_request(self):
- mysock = mock.Mock()
- mysock.gettimeout.return_value = 4242
-
- myresponse = mock.Mock()
- myresponse.read.return_value = 'body'
- myresponse.getheaders.return_value = 'headers'
- myresponse.status = httplib.MOVED_PERMANENTLY
-
- myconn = mock.Mock()
- myconn.request.return_value = None
- myconn.sock = mysock
- myconn.getresponse.return_value = myresponse
- myconn.__str__ = mock.Mock()
- myconn.__str__.return_value = 'myconn string'
-
- req = self.req
- req._redirect_params = mock.Mock()
- req._redirect_params.return_value = (myconn, 'url')
- req._request_str = mock.Mock()
- req._request_str.return_value = 'http://cool/cool'
-
- client = self.client
- client.need_login = False
- client._auto_login = False
- client._auth_cookie = False
- client.acquire_connection = mock.Mock()
- client.acquire_connection.return_value = myconn
- client.release_connection = mock.Mock()
-
- return (mysock, myresponse, myconn)
-
- def test_issue_request_trigger_exception(self):
- (mysock, myresponse, myconn) = self.prep_issue_request()
- self.client.acquire_connection.return_value = None
-
- self.req._issue_request()
- self.assertIsInstance(self.req._request_error, Exception)
- self.assertTrue(self.client.acquire_connection.called)
-
- def test_issue_request_handle_none_sock(self):
- (mysock, myresponse, myconn) = self.prep_issue_request()
- myconn.sock = None
- self.req.start()
- self.assertIsNone(self.req.join())
- self.assertTrue(self.client.acquire_connection.called)
-
- def test_issue_request_exceed_maximum_retries(self):
- (mysock, myresponse, myconn) = self.prep_issue_request()
- self.req.start()
- self.assertIsNone(self.req.join())
- self.assertTrue(self.client.acquire_connection.called)
-
- def test_issue_request_trigger_non_redirect(self):
- (mysock, myresponse, myconn) = self.prep_issue_request()
- myresponse.status = httplib.OK
- self.req.start()
- self.assertIsNone(self.req.join())
- self.assertTrue(self.client.acquire_connection.called)
-
- def test_issue_request_trigger_internal_server_error(self):
- (mysock, myresponse, myconn) = self.prep_issue_request()
- self.req._redirect_params.return_value = (myconn, None)
- self.req.start()
- self.assertIsNone(self.req.join())
- self.assertTrue(self.client.acquire_connection.called)
-
- def test_redirect_params_break_on_location(self):
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(
- myconn, [('location', None)])
- self.assertIsNone(retval)
-
- def test_redirect_params_parse_a_url(self):
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(
- myconn, [('location', '/path/a/b/c')])
- self.assertIsNotNone(retval)
-
- def test_redirect_params_invalid_redirect_location(self):
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(
- myconn, [('location', '+path/a/b/c')])
- self.assertIsNone(retval)
-
- def test_redirect_params_invalid_scheme(self):
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(
- myconn, [('location', 'invalidscheme://hostname:1/path')])
- self.assertIsNone(retval)
-
- def test_redirect_params_setup_https_with_cooki(self):
- with mock.patch(vmware.CLIENT_NAME) as mock_client:
- api_client = mock_client.return_value
- self.req._api_client = api_client
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(
- myconn, [('location', 'https://host:1/path')])
-
- self.assertIsNotNone(retval)
- self.assertTrue(api_client.acquire_redirect_connection.called)
-
- def test_redirect_params_setup_htttps_and_query(self):
- with mock.patch(vmware.CLIENT_NAME) as mock_client:
- api_client = mock_client.return_value
- self.req._api_client = api_client
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(myconn, [
- ('location', 'https://host:1/path?q=1')])
-
- self.assertIsNotNone(retval)
- self.assertTrue(api_client.acquire_redirect_connection.called)
-
- def test_redirect_params_setup_https_connection_no_cookie(self):
- with mock.patch(vmware.CLIENT_NAME) as mock_client:
- api_client = mock_client.return_value
- self.req._api_client = api_client
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(myconn, [
- ('location', 'https://host:1/path')])
-
- self.assertIsNotNone(retval)
- self.assertTrue(api_client.acquire_redirect_connection.called)
-
- def test_redirect_params_setup_https_and_query_no_cookie(self):
- with mock.patch(vmware.CLIENT_NAME) as mock_client:
- api_client = mock_client.return_value
- self.req._api_client = api_client
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(
- myconn, [('location', 'https://host:1/path?q=1')])
- self.assertIsNotNone(retval)
- self.assertTrue(api_client.acquire_redirect_connection.called)
-
- def test_redirect_params_path_only_with_query(self):
- with mock.patch(vmware.CLIENT_NAME) as mock_client:
- api_client = mock_client.return_value
- api_client.wait_for_login.return_value = None
- api_client.auth_cookie = None
- api_client.acquire_connection.return_value = True
- myconn = mock.Mock()
- (conn, retval) = self.req._redirect_params(myconn, [
- ('location', '/path?q=1')])
- self.assertIsNotNone(retval)
-
- def test_handle_request_auto_login(self):
- self.req._auto_login = True
- self.req._api_client = mock.Mock()
- self.req._api_client.need_login = True
- self.req._request_str = mock.Mock()
- self.req._request_str.return_value = 'http://cool/cool'
- self.req.spawn = mock.Mock()
- self.req._handle_request()
-
- def test_handle_request_auto_login_unauth(self):
- self.req._auto_login = True
- self.req._api_client = mock.Mock()
- self.req._api_client.need_login = True
- self.req._request_str = mock.Mock()
- self.req._request_str.return_value = 'http://cool/cool'
-
- import socket
- resp = httplib.HTTPResponse(socket.socket())
- resp.status = httplib.UNAUTHORIZED
- mywaiter = mock.Mock()
- mywaiter.wait = mock.Mock()
- mywaiter.wait.return_value = resp
- self.req.spawn = mock.Mock(return_value=mywaiter)
- self.req._handle_request()
-
- def test_construct_eventlet_login_request(self):
- r = request.LoginRequestEventlet(self.client, 'user', 'password')
- self.assertIsNotNone(r)
-
- def test_session_cookie_session_cookie_retrieval(self):
- r = request.LoginRequestEventlet(self.client, 'user', 'password')
- r.successful = mock.Mock()
- r.successful.return_value = True
- r.value = mock.Mock()
- r.value.get_header = mock.Mock()
- r.value.get_header.return_value = 'cool'
- self.assertIsNotNone(r.session_cookie())
-
- def test_session_cookie_not_retrieved(self):
- r = request.LoginRequestEventlet(self.client, 'user', 'password')
- r.successful = mock.Mock()
- r.successful.return_value = False
- r.value = mock.Mock()
- r.value.get_header = mock.Mock()
- r.value.get_header.return_value = 'cool'
- self.assertIsNone(r.session_cookie())
-
- def test_construct_eventlet_get_api_providers_request(self):
- r = request.GetApiProvidersRequestEventlet(self.client)
- self.assertIsNotNone(r)
-
- def test_api_providers_none_api_providers(self):
- r = request.GetApiProvidersRequestEventlet(self.client)
- r.successful = mock.Mock(return_value=False)
- self.assertIsNone(r.api_providers())
-
- def test_api_providers_non_none_api_providers(self):
- r = request.GetApiProvidersRequestEventlet(self.client)
- r.value = mock.Mock()
- r.value.body = """{
- "results": [
- { "roles": [
- { "role": "api_provider",
- "listen_addr": "pssl:1.1.1.1:1" }]}]}"""
- r.successful = mock.Mock(return_value=True)
- LOG.info('%s' % r.api_providers())
- self.assertIsNotNone(r.api_providers())
+++ /dev/null
-# Copyright 2014 VMware, 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.
-
-from sqlalchemy import orm
-
-from neutron import context
-from neutron.plugins.vmware.common import exceptions as p_exc
-from neutron.plugins.vmware.dbexts import lsn_db
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.tests.unit import testlib_api
-
-
-class LSNTestCase(testlib_api.SqlTestCase):
-
- def setUp(self):
- super(LSNTestCase, self).setUp()
- self.ctx = context.get_admin_context()
- self.net_id = 'foo_network_id'
- self.lsn_id = 'foo_lsn_id'
- self.lsn_port_id = 'foo_port_id'
- self.subnet_id = 'foo_subnet_id'
- self.mac_addr = 'aa:bb:cc:dd:ee:ff'
-
- def test_lsn_add(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn = (self.ctx.session.query(nsx_models.Lsn).
- filter_by(lsn_id=self.lsn_id).one())
- self.assertEqual(self.lsn_id, lsn.lsn_id)
-
- def test_lsn_remove(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn_db.lsn_remove(self.ctx, self.lsn_id)
- q = self.ctx.session.query(nsx_models.Lsn).filter_by(
- lsn_id=self.lsn_id)
- self.assertRaises(orm.exc.NoResultFound, q.one)
-
- def test_lsn_remove_for_network(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn_db.lsn_remove_for_network(self.ctx, self.net_id)
- q = self.ctx.session.query(nsx_models.Lsn).filter_by(
- lsn_id=self.lsn_id)
- self.assertRaises(orm.exc.NoResultFound, q.one)
-
- def test_lsn_get_for_network(self):
- result = lsn_db.lsn_get_for_network(self.ctx, self.net_id,
- raise_on_err=False)
- self.assertIsNone(result)
-
- def test_lsn_get_for_network_raise_not_found(self):
- self.assertRaises(p_exc.LsnNotFound,
- lsn_db.lsn_get_for_network,
- self.ctx, self.net_id)
-
- def test_lsn_port_add(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn_db.lsn_port_add_for_lsn(self.ctx, self.lsn_port_id,
- self.subnet_id, self.mac_addr, self.lsn_id)
- result = (self.ctx.session.query(nsx_models.LsnPort).
- filter_by(lsn_port_id=self.lsn_port_id).one())
- self.assertEqual(self.lsn_port_id, result.lsn_port_id)
-
- def test_lsn_port_get_for_mac(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn_db.lsn_port_add_for_lsn(self.ctx, self.lsn_port_id,
- self.subnet_id, self.mac_addr, self.lsn_id)
- result = lsn_db.lsn_port_get_for_mac(self.ctx, self.mac_addr)
- self.assertEqual(self.mac_addr, result.mac_addr)
-
- def test_lsn_port_get_for_mac_raise_not_found(self):
- self.assertRaises(p_exc.LsnPortNotFound,
- lsn_db.lsn_port_get_for_mac,
- self.ctx, self.mac_addr)
-
- def test_lsn_port_get_for_subnet(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn_db.lsn_port_add_for_lsn(self.ctx, self.lsn_port_id,
- self.subnet_id, self.mac_addr, self.lsn_id)
- result = lsn_db.lsn_port_get_for_subnet(self.ctx, self.subnet_id)
- self.assertEqual(self.subnet_id, result.sub_id)
-
- def test_lsn_port_get_for_subnet_raise_not_found(self):
- self.assertRaises(p_exc.LsnPortNotFound,
- lsn_db.lsn_port_get_for_subnet,
- self.ctx, self.mac_addr)
-
- def test_lsn_port_remove(self):
- lsn_db.lsn_add(self.ctx, self.net_id, self.lsn_id)
- lsn_db.lsn_port_remove(self.ctx, self.lsn_port_id)
- q = (self.ctx.session.query(nsx_models.LsnPort).
- filter_by(lsn_port_id=self.lsn_port_id))
- self.assertRaises(orm.exc.NoResultFound, q.one)
+++ /dev/null
-# Copyright 2013 VMware, 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.
-
-from oslo_db import exception as d_exc
-
-from neutron import context
-from neutron.db import models_v2
-from neutron.plugins.vmware.dbexts import db as nsx_db
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.tests.unit import testlib_api
-
-
-class NsxDBTestCase(testlib_api.SqlTestCase):
-
- def setUp(self):
- super(NsxDBTestCase, self).setUp()
- self.ctx = context.get_admin_context()
-
- def _setup_neutron_network_and_port(self, network_id, port_id):
- with self.ctx.session.begin(subtransactions=True):
- self.ctx.session.add(models_v2.Network(id=network_id))
- port = models_v2.Port(id=port_id,
- network_id=network_id,
- mac_address='foo_mac_address',
- admin_state_up=True,
- status='ACTIVE',
- device_id='',
- device_owner='')
- self.ctx.session.add(port)
-
- def test_add_neutron_nsx_port_mapping_handle_duplicate_constraint(self):
- neutron_net_id = 'foo_neutron_network_id'
- neutron_port_id = 'foo_neutron_port_id'
- nsx_port_id = 'foo_nsx_port_id'
- nsx_switch_id = 'foo_nsx_switch_id'
- self._setup_neutron_network_and_port(neutron_net_id, neutron_port_id)
-
- nsx_db.add_neutron_nsx_port_mapping(
- self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id)
- # Call the method twice to trigger a db duplicate constraint error
- nsx_db.add_neutron_nsx_port_mapping(
- self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id)
- result = (self.ctx.session.query(nsx_models.NeutronNsxPortMapping).
- filter_by(neutron_id=neutron_port_id).one())
- self.assertEqual(nsx_port_id, result.nsx_port_id)
- self.assertEqual(neutron_port_id, result.neutron_id)
-
- def test_add_neutron_nsx_port_mapping_raise_on_duplicate_constraint(self):
- neutron_net_id = 'foo_neutron_network_id'
- neutron_port_id = 'foo_neutron_port_id'
- nsx_port_id_1 = 'foo_nsx_port_id_1'
- nsx_port_id_2 = 'foo_nsx_port_id_2'
- nsx_switch_id = 'foo_nsx_switch_id'
- self._setup_neutron_network_and_port(neutron_net_id, neutron_port_id)
-
- nsx_db.add_neutron_nsx_port_mapping(
- self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id_1)
- # Call the method twice to trigger a db duplicate constraint error,
- # this time with a different nsx port id!
- self.assertRaises(d_exc.DBDuplicateEntry,
- nsx_db.add_neutron_nsx_port_mapping,
- self.ctx.session, neutron_port_id,
- nsx_switch_id, nsx_port_id_2)
-
- def test_add_neutron_nsx_port_mapping_raise_integrity_constraint(self):
- neutron_port_id = 'foo_neutron_port_id'
- nsx_port_id = 'foo_nsx_port_id'
- nsx_switch_id = 'foo_nsx_switch_id'
- self.assertRaises(d_exc.DBError,
- nsx_db.add_neutron_nsx_port_mapping,
- self.ctx.session, neutron_port_id,
- nsx_switch_id, nsx_port_id)
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "_href": "/ws.v1/gateway-service/%(uuid)s",
- "tags": %(tags_json)s,
- "_schema": "/ws.v1/schema/L2GatewayServiceConfig",
- "gateways": [
- {
- "transport_node_uuid": "%(transport_node_uuid)s",
- "type": "L2Gateway",
- "device_id": "%(device_id)s"
- }
- ],
- "type": "L2GatewayServiceConfig",
- "uuid": "%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "uuid": "%(uuid)s",
- "type": "LogicalSwitchConfig",
- "_schema": "/ws.v1/schema/LogicalQueueConfig",
- "dscp": "%(dscp)s",
- "max_bandwidth_rate": "%(max_bandwidth_rate)s",
- "min_bandwidth_rate": "%(min_bandwidth_rate)s",
- "qos_marking": "%(qos_marking)s",
- "_href": "/ws.v1/lqueue/%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- %(distributed_json)s
- "uuid": "%(uuid)s",
- "tags": %(tags_json)s,
- "routing_config": {
- "type": "SingleDefaultRouteImplicitRoutingConfig",
- "_schema": "/ws.v1/schema/SingleDefaultRouteImplicitRoutingConfig",
- "default_route_next_hop": {
- "type": "RouterNextHop",
- "_schema": "/ws.v1/schema/RouterNextHop",
- "gateway_ip_address": "%(default_next_hop)s"
- }
- },
- "_schema": "/ws.v1/schema/LogicalRouterConfig",
- "_relations": {
- "LogicalRouterStatus": {
- "_href": "/ws.v1/lrouter/%(uuid)s/status",
- "lport_admin_up_count": %(lport_count)d,
- "_schema": "/ws.v1/schema/LogicalRouterStatus",
- "lport_count": %(lport_count)d,
- "fabric_status": %(status)s,
- "type": "LogicalRouterStatus",
- "lport_link_up_count": %(lport_count)d
- }
- },
- "type": "LogicalRouterConfig",
- "_href": "/ws.v1/lrouter/%(uuid)s"
-}
\ No newline at end of file
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "admin_status_enabled": "%(admin_status_enabled)s",
- "_href": "/ws.v1/lrouter/%(lr_uuid)s/lport/%(uuid)s",
- "tags":
- [{"scope": "q_port_id", "tag": "%(neutron_port_id)s"},
- {"scope": "os_tid", "tag": "%(tenant_id)s"}],
- "ip_addresses": %(ip_addresses_json)s,
- "_schema": "/ws.v1/schema/LogicalRouterPortConfig",
- "type": "LogicalRouterPortConfig",
- "uuid": "%(uuid)s"
-}
+++ /dev/null
-{
- "LogicalPortAttachment":
- {
- %(peer_port_href_field)s
- %(peer_port_uuid_field)s
- %(l3_gateway_service_uuid_field)s
- %(vlan_id)s
- "type": "%(type)s",
- "schema": "/ws.v1/schema/%(type)s"
- }
-}
\ No newline at end of file
+++ /dev/null
-{
- "_href": "/ws.v1/lrouter/%(lr_uuid)s/nat/%(uuid)s",
- "type": "%(type)s",
- "match": %(match_json)s,
- "uuid": "%(uuid)s"
-}
\ No newline at end of file
+++ /dev/null
-{"display_name": "%(display_name)s",
- "_href": "/ws.v1/lswitch/%(uuid)s",
- "_schema": "/ws.v1/schema/LogicalSwitchConfig",
- "_relations": {"LogicalSwitchStatus":
- {"fabric_status": %(status)s,
- "type": "LogicalSwitchStatus",
- "lport_count": %(lport_count)d,
- "_href": "/ws.v1/lswitch/%(uuid)s/status",
- "_schema": "/ws.v1/schema/LogicalSwitchStatus"}},
- "type": "LogicalSwitchConfig",
- "tags": %(tags_json)s,
- "uuid": "%(uuid)s"}
+++ /dev/null
-{"display_name": "%(display_name)s",
- "_relations":
- {"LogicalPortStatus":
- {"type": "LogicalSwitchPortStatus",
- "admin_status_enabled": true,
- "fabric_status_up": %(status)s,
- "link_status_up": %(status)s,
- "_href": "/ws.v1/lswitch/%(ls_uuid)s/lport/%(uuid)s/status",
- "_schema": "/ws.v1/schema/LogicalSwitchPortStatus"},
- "LogicalSwitchConfig":
- {"uuid": "%(ls_uuid)s"},
- "LogicalPortAttachment":
- {
- "type": "%(att_type)s",
- %(att_info_json)s
- "schema": "/ws.v1/schema/%(att_type)s"
- }
- },
- "tags":
- [{"scope": "q_port_id", "tag": "%(neutron_port_id)s"},
- {"scope": "vm_id", "tag": "%(neutron_device_id)s"},
- {"scope": "os_tid", "tag": "%(tenant_id)s"}],
- "uuid": "%(uuid)s",
- "admin_status_enabled": "%(admin_status_enabled)s",
- "type": "LogicalSwitchPortConfig",
- "_schema": "/ws.v1/schema/LogicalSwitchPortConfig",
- "_href": "/ws.v1/lswitch/%(ls_uuid)s/lport/%(uuid)s"
- }
+++ /dev/null
-{
- "LogicalPortAttachment":
- {
- "type": "%(att_type)s",
- "schema": "/ws.v1/schema/%(att_type)s"
- }
-}
\ No newline at end of file
+++ /dev/null
-{"_href": "/ws.v1/lswitch/%(ls_uuid)s/lport/%(uuid)s",
- "lswitch":
- {"display_name": "%(ls_name)s",
- "uuid": "%(ls_uuid)s",
- "tags": [
- {"scope": "os_tid",
- "tag": "%(ls_tenant_id)s"}
- ],
- "type": "LogicalSwitchConfig",
- "_schema": "/ws.v1/schema/LogicalSwitchConfig",
- "port_isolation_enabled": false,
- "transport_zones": [
- {"zone_uuid": "%(ls_zone_uuid)s",
- "transport_type": "stt"}
- ],
- "_href": "/ws.v1/lswitch/%(ls_uuid)s"},
- "link_status_up": false,
- "_schema": "/ws.v1/schema/LogicalSwitchPortStatus",
- "admin_status_enabled": true,
- "fabric_status_up": true,
- "link_status_up": true,
- "type": "LogicalSwitchPortStatus"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "_href": "/ws.v1/security-profile/%(uuid)s",
- "tags": [{"scope": "os_tid", "tag": "%(tenant_id)s"},
- {"scope": "nova_spid", "tag": "%(nova_spid)s"}],
- "logical_port_egress_rules": %(logical_port_egress_rules_json)s,
- "_schema": "/ws.v1/schema/SecurityProfileConfig",
- "logical_port_ingress_rules": %(logical_port_ingress_rules_json)s,
- "uuid": "%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "tags": [{"scope": "os_tid", "tag": "%(tenant_id)s"}],
- "gateways": [
- {
- "transport_node_uuid": "%(transport_node_uuid)s",
- "device_id": "%(device_id)s",
- "type": "L2Gateway"
- }
- ],
- "type": "L2GatewayServiceConfig",
- "uuid": "%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "uuid": "%(uuid)s",
- "type": "LogicalSwitchConfig",
- "_schema": "/ws.v1/schema/LogicalQueueConfig",
- "dscp": "%(dscp)s",
- "max_bandwidth_rate": "%(max_bandwidth_rate)s",
- "min_bandwidth_rate": "%(min_bandwidth_rate)s",
- "qos_marking": "%(qos_marking)s",
- "_href": "/ws.v1/lqueue/%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- %(distributed_json)s
- "uuid": "%(uuid)s",
- "tags": [
- {
- "scope": "os_tid",
- "tag": "%(tenant_id)s"
- }
- ],
- "routing_config": {
- "type": "SingleDefaultRouteImplicitRoutingConfig",
- "_schema": "/ws.v1/schema/SingleDefaultRouteImplicitRoutingConfig",
- "default_route_next_hop": {
- "type": "RouterNextHop",
- "_schema": "/ws.v1/schema/RouterNextHop",
- "gateway_ip_address": "%(default_next_hop)s"
- }
- },
- "_schema": "/ws.v1/schema/LogicalRouterConfig",
- "type": "LogicalRouterConfig",
- "_href": "/ws.v1/lrouter/%(uuid)s"
-}
\ No newline at end of file
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "_href": "/ws.v1/lrouter/%(lr_uuid)s/lport/%(uuid)s",
- "_schema": "/ws.v1/schema/LogicalRouterPortConfig",
- "mac_address": "00:00:00:00:00:00",
- "admin_status_enabled": true,
- "ip_addresses": %(ip_addresses_json)s,
- "type": "LogicalRouterPortConfig",
- "uuid": "%(uuid)s"
-}
\ No newline at end of file
+++ /dev/null
-{
- "_href": "/ws.v1/lrouter/%(lr_uuid)s/nat/%(uuid)s",
- "type": "%(type)s",
- "match": %(match_json)s,
- "uuid": "%(uuid)s"
-}
\ No newline at end of file
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "uuid": "%(uuid)s",
- "tags": [{"scope": "os_tid", "tag": "%(tenant_id)s"}],
- "type": "LogicalSwitchConfig",
- "_schema": "/ws.v1/schema/LogicalSwitchConfig",
- "port_isolation_enabled": false,
- "transport_zones": [
- {"zone_uuid": "%(zone_uuid)s",
- "transport_type": "stt"}],
- "_href": "/ws.v1/lswitch/%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(uuid)s",
- "_href": "/ws.v1/lswitch/%(ls_uuid)s/lport/%(uuid)s",
- "security_profiles": [],
- "tags":
- [{"scope": "q_port_id", "tag": "%(neutron_port_id)s"},
- {"scope": "vm_id", "tag": "%(neutron_device_id)s"},
- {"scope": "os_tid", "tag": "%(tenant_id)s"}],
- "portno": 1,
- "queue_uuid": null,
- "_schema": "/ws.v1/schema/LogicalSwitchPortConfig",
- "mirror_targets": [],
- "allowed_address_pairs": [],
- "admin_status_enabled": true,
- "type": "LogicalSwitchPortConfig",
- "uuid": "%(uuid)s"
-}
+++ /dev/null
-{
- "display_name": "%(display_name)s",
- "_href": "/ws.v1/security-profile/%(uuid)s",
- "tags": [{"scope": "os_tid", "tag": "%(tenant_id)s"},
- {"scope": "nova_spid", "tag": "%(nova_spid)s"}],
- "logical_port_egress_rules": [],
- "_schema": "/ws.v1/schema/SecurityProfileConfig",
- "logical_port_ingress_rules": [],
- "uuid": "%(uuid)s"
-}
+++ /dev/null
-{
- "LogicalPortAttachment":
- {
- %(peer_port_href_field)s
- %(peer_port_uuid_field)s
- %(l3_gateway_service_uuid_field)s
- %(vlan_id_field)s
- "_href": "/ws.v1/lrouter/%(lr_uuid)s/lport/%(lp_uuid)s/attachment",
- "type": "%(type)s",
- "schema": "/ws.v1/schema/%(type)s"
- }
-}
\ No newline at end of file
+++ /dev/null
-{
- "LogicalPortAttachment":
- {
- %(peer_port_href_field)s
- %(peer_port_uuid_field)s
- %(vif_uuid_field)s
- "_href": "/ws.v1/lswitch/%(ls_uuid)s/lport/%(lp_uuid)s/attachment",
- "type": "%(type)s",
- "schema": "/ws.v1/schema/%(type)s"
- }
-}
\ No newline at end of file
+++ /dev/null
-[DEFAULT]
-# Show more verbose log output (sets INFO log level output)
-verbose = True
-
-# Show debugging output in logs (sets DEBUG log level output)
-debug = False
-
-# Address to bind the API server
-bind_host = 0.0.0.0
-
-# Port the bind the API server to
-bind_port = 9696
-
-# MISSING Path to the extensions
-# api_extensions_path =
-
-# Paste configuration file
-api_paste_config = api-paste.ini.test
-
-# The messaging module to use, defaults to kombu.
-rpc_backend = fake
-
-lock_path = $state_path/lock
-
-[database]
-connection = 'sqlite://'
+++ /dev/null
-[DEFAULT]
-default_tz_uuid = fake_tz_uuid
-nova_zone_id = whatever
-nsx_controllers = fake_1, fake_2
-nsx_user = foo
-nsx_password = bar
-default_l3_gw_service_uuid = whatever
-default_l2_gw_service_uuid = whatever
-default_service_cluster_uuid = whatever
-default_interface_name = whatever
-http_timeout = 13
-redirects = 12
-retries = 11
-
-[NSX]
-agent_mode = agentless
+++ /dev/null
-[DEFAULT]
-default_tz_uuid = fake_tz_uuid
-nsx_controllers=fake_1,fake_2
-nsx_user=foo
-nsx_password=bar
+++ /dev/null
-[DEFAULT]
-default_tz_uuid = fake_tz_uuid
-nova_zone_id = whatever
-nsx_controllers = fake_1, fake_2
-nsx_user = foo
-nsx_password = bar
-default_l3_gw_service_uuid = whatever
-default_l2_gw_service_uuid = whatever
-default_service_cluster_uuid = whatever
-default_interface_name = whatever
-http_timeout = 13
-redirects = 12
-retries = 11
-
-[NSX]
-agent_mode = combined
+++ /dev/null
-[DEFAULT]
-default_tz_uuid = fake_tz_uuid
-nova_zone_id = whatever
-nsx_controllers = fake_1, fake_2
-nsx_user = foo
-nsx_password = bar
-default_l3_gw_service_uuid = whatever
-default_l2_gw_service_uuid = whatever
-default_interface_name = whatever
-http_timeout = 13
-redirects = 12
-retries = 11
+++ /dev/null
-[DEFAULT]
-default_tz_uuid = fake_tz_uuid
-nsx_controllers=fake_1, fake_2
-nsx_user=foo
-nsx_password=bar
-default_l3_gw_service_uuid = whatever
-default_l2_gw_service_uuid = whatever
+++ /dev/null
-[DEFAULT]
-default_tz_uuid = fake_tz_uuid
-nova_zone_id = whatever
-nvp_controllers = fake_1, fake_2
-nvp_user = foo
-nvp_password = bar
-default_l3_gw_service_uuid = whatever
-default_l2_gw_service_uuid = whatever
-default_interface_name = whatever
-http_timeout = 3
-redirects = 2
-retries = 2
+++ /dev/null
-[vcns]
-manager_uri = https://fake-host
-user = fake-user
-passwordd = fake-password
-datacenter_moid = fake-moid
-resource_pool_id = fake-resgroup
-datastore_id = fake-datastore
-external_network = fake-ext-net
-task_status_check_interval = 100
+++ /dev/null
-# Copyright (c) 2014 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.
-
-from neutron.extensions import allowedaddresspairs as addr_pair
-from neutron.tests.unit import test_extension_allowedaddresspairs as ext_pairs
-from neutron.tests.unit.vmware import test_nsx_plugin
-
-
-class TestAllowedAddressPairs(test_nsx_plugin.NsxPluginV2TestCase,
- ext_pairs.TestAllowedAddressPairs):
-
- # TODO(arosen): move to ext_pairs.TestAllowedAddressPairs once all
- # plugins do this correctly.
- def test_create_port_no_allowed_address_pairs(self):
- with self.network() as net:
- res = self._create_port(self.fmt, net['network']['id'])
- port = self.deserialize(self.fmt, res)
- self.assertEqual(port['port'][addr_pair.ADDRESS_PAIRS], [])
- self._delete('ports', port['port']['id'])
+++ /dev/null
-# Copyright (c) 2013 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 contextlib
-import mock
-
-from oslo_config import cfg
-
-from neutron.api.v2 import attributes
-from neutron.common import test_lib
-from neutron import context
-from neutron.extensions import agent
-from neutron.plugins.vmware.api_client import version
-from neutron.plugins.vmware.common import sync
-from neutron.tests.unit import test_db_plugin
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.apiclient import fake
-
-
-class MacLearningExtensionManager(object):
-
- def get_resources(self):
- # Add the resources to the global attribute map
- # This is done here as the setup process won't
- # initialize the main API router which extends
- # the global attribute map
- attributes.RESOURCE_ATTRIBUTE_MAP.update(
- agent.RESOURCE_ATTRIBUTE_MAP)
- return agent.Agent.get_resources()
-
- def get_actions(self):
- return []
-
- def get_request_extensions(self):
- return []
-
-
-class MacLearningDBTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
- fmt = 'json'
-
- def setUp(self):
- test_lib.test_config['config_files'] = [
- vmware.get_fake_conf('nsx.ini.full.test')]
- cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH)
- # Save the original RESOURCE_ATTRIBUTE_MAP
- self.saved_attr_map = {}
- for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
- self.saved_attr_map[resource] = attrs.copy()
- ext_mgr = MacLearningExtensionManager()
- # mock api client
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsx = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- instance = self.mock_nsx.start()
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
-
- # Emulate tests against NSX 2.x
- instance.return_value.get_version.return_value = version.Version("3.0")
- instance.return_value.request.side_effect = self.fc.fake_request
- cfg.CONF.set_override('metadata_mode', None, 'NSX')
- self.addCleanup(self.fc.reset_all)
- self.addCleanup(self.restore_resource_attribute_map)
- super(MacLearningDBTestCase, self).setUp(plugin=vmware.PLUGIN_NAME,
- ext_mgr=ext_mgr)
- self.adminContext = context.get_admin_context()
-
- def restore_resource_attribute_map(self):
- # Restore the original RESOURCE_ATTRIBUTE_MAP
- attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
-
- def test_create_with_mac_learning(self):
- with self.port(arg_list=('mac_learning_enabled',),
- mac_learning_enabled=True) as port:
- # Validate create operation response
- self.assertEqual(True, port['port']['mac_learning_enabled'])
- # Verify that db operation successfully set mac learning state
- req = self.new_show_request('ports', port['port']['id'], self.fmt)
- sport = self.deserialize(self.fmt, req.get_response(self.api))
- self.assertEqual(True, sport['port']['mac_learning_enabled'])
-
- def test_create_and_show_port_without_mac_learning(self):
- with self.port() as port:
- req = self.new_show_request('ports', port['port']['id'], self.fmt)
- sport = self.deserialize(self.fmt, req.get_response(self.api))
- self.assertNotIn('mac_learning_enabled', sport['port'])
-
- def test_update_port_with_mac_learning(self):
- with self.port(arg_list=('mac_learning_enabled',),
- mac_learning_enabled=False) as port:
- data = {'port': {'mac_learning_enabled': True}}
- req = self.new_update_request('ports', data, port['port']['id'])
- res = self.deserialize(self.fmt, req.get_response(self.api))
- self.assertEqual(True, res['port']['mac_learning_enabled'])
-
- def test_update_preexisting_port_with_mac_learning(self):
- with self.port() as port:
- req = self.new_show_request('ports', port['port']['id'], self.fmt)
- sport = self.deserialize(self.fmt, req.get_response(self.api))
- self.assertNotIn('mac_learning_enabled', sport['port'])
- data = {'port': {'mac_learning_enabled': True}}
- req = self.new_update_request('ports', data, port['port']['id'])
- # Validate update operation response
- res = self.deserialize(self.fmt, req.get_response(self.api))
- self.assertEqual(True, res['port']['mac_learning_enabled'])
- # Verify that db operation successfully updated mac learning state
- req = self.new_show_request('ports', port['port']['id'], self.fmt)
- sport = self.deserialize(self.fmt, req.get_response(self.api))
- self.assertEqual(True, sport['port']['mac_learning_enabled'])
-
- def test_list_ports(self):
- # for this test we need to enable overlapping ips
- cfg.CONF.set_default('allow_overlapping_ips', True)
- with contextlib.nested(self.port(arg_list=('mac_learning_enabled',),
- mac_learning_enabled=True),
- self.port(arg_list=('mac_learning_enabled',),
- mac_learning_enabled=True),
- self.port(arg_list=('mac_learning_enabled',),
- mac_learning_enabled=True)):
- for port in self._list('ports')['ports']:
- self.assertEqual(True, port['mac_learning_enabled'])
-
- def test_show_port(self):
- with self.port(arg_list=('mac_learning_enabled',),
- mac_learning_enabled=True) as p:
- port_res = self._show('ports', p['port']['id'])['port']
- self.assertEqual(True, port_res['mac_learning_enabled'])
+++ /dev/null
-# Copyright 2012 VMware, Inc. 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 contextlib
-import mock
-
-from oslo_config import cfg
-from webob import exc
-import webtest
-
-from neutron.api import extensions
-from neutron.api.v2 import attributes
-from neutron import context
-from neutron.db import api as db_api
-from neutron.db import db_base_plugin_v2
-from neutron import manager
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.dbexts import networkgw_db
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.plugins.vmware.extensions import networkgw
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import l2gateway as l2gwlib
-from neutron import quota
-from neutron.tests import base
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit import test_db_plugin
-from neutron.tests.unit import test_extensions
-from neutron.tests.unit import testlib_plugin
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware import test_nsx_plugin
-
-_uuid = test_api_v2._uuid
-_get_path = test_api_v2._get_path
-
-
-class TestExtensionManager(object):
-
- def get_resources(self):
- # Add the resources to the global attribute map
- # This is done here as the setup process won't
- # initialize the main API router which extends
- # the global attribute map
- attributes.RESOURCE_ATTRIBUTE_MAP.update(
- networkgw.RESOURCE_ATTRIBUTE_MAP)
- return networkgw.Networkgw.get_resources()
-
- def get_actions(self):
- return []
-
- def get_request_extensions(self):
- return []
-
-
-class NetworkGatewayExtensionTestCase(base.BaseTestCase,
- testlib_plugin.PluginSetupHelper):
-
- def setUp(self):
- super(NetworkGatewayExtensionTestCase, self).setUp()
- plugin = '%s.%s' % (networkgw.__name__,
- networkgw.NetworkGatewayPluginBase.__name__)
- self._gw_resource = networkgw.GATEWAY_RESOURCE_NAME
- self._dev_resource = networkgw.DEVICE_RESOURCE_NAME
-
- # Ensure existing ExtensionManager is not used
- extensions.PluginAwareExtensionManager._instance = None
-
- # Create the default configurations
- self.config_parse()
-
- # Update the plugin and extensions path
- self.setup_coreplugin(plugin)
-
- _plugin_patcher = mock.patch(plugin, autospec=True)
- self.plugin = _plugin_patcher.start()
-
- # Instantiate mock plugin and enable extensions
- manager.NeutronManager.get_plugin().supported_extension_aliases = (
- [networkgw.EXT_ALIAS])
- ext_mgr = TestExtensionManager()
- extensions.PluginAwareExtensionManager._instance = ext_mgr
- self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
- self.api = webtest.TestApp(self.ext_mdw)
-
- quota.QUOTAS._driver = None
- cfg.CONF.set_override('quota_driver', 'neutron.quota.ConfDriver',
- group='QUOTAS')
-
- def test_network_gateway_create(self):
- nw_gw_id = _uuid()
- data = {self._gw_resource: {'name': 'nw-gw',
- 'tenant_id': _uuid(),
- 'devices': [{'id': _uuid(),
- 'interface_name': 'xxx'}]}}
- return_value = data[self._gw_resource].copy()
- return_value.update({'id': nw_gw_id})
- instance = self.plugin.return_value
- instance.create_network_gateway.return_value = return_value
- res = self.api.post_json(_get_path(networkgw.NETWORK_GATEWAYS), data)
- instance.create_network_gateway.assert_called_with(
- mock.ANY, network_gateway=data)
- self.assertEqual(res.status_int, exc.HTTPCreated.code)
- self.assertIn(self._gw_resource, res.json)
- nw_gw = res.json[self._gw_resource]
- self.assertEqual(nw_gw['id'], nw_gw_id)
-
- def _test_network_gateway_create_with_error(
- self, data, error_code=exc.HTTPBadRequest.code):
- res = self.api.post_json(_get_path(networkgw.NETWORK_GATEWAYS), data,
- expect_errors=True)
- self.assertEqual(res.status_int, error_code)
-
- def test_network_gateway_create_invalid_device_spec(self):
- data = {self._gw_resource: {'name': 'nw-gw',
- 'tenant_id': _uuid(),
- 'devices': [{'id': _uuid(),
- 'invalid': 'xxx'}]}}
- self._test_network_gateway_create_with_error(data)
-
- def test_network_gateway_create_extra_attr_in_device_spec(self):
- data = {self._gw_resource: {'name': 'nw-gw',
- 'tenant_id': _uuid(),
- 'devices':
- [{'id': _uuid(),
- 'interface_name': 'xxx',
- 'extra_attr': 'onetoomany'}]}}
- self._test_network_gateway_create_with_error(data)
-
- def test_network_gateway_update(self):
- nw_gw_name = 'updated'
- data = {self._gw_resource: {'name': nw_gw_name}}
- nw_gw_id = _uuid()
- return_value = {'id': nw_gw_id,
- 'name': nw_gw_name}
-
- instance = self.plugin.return_value
- instance.update_network_gateway.return_value = return_value
- res = self.api.put_json(
- _get_path('%s/%s' % (networkgw.NETWORK_GATEWAYS, nw_gw_id)), data)
- instance.update_network_gateway.assert_called_with(
- mock.ANY, nw_gw_id, network_gateway=data)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
- self.assertIn(self._gw_resource, res.json)
- nw_gw = res.json[self._gw_resource]
- self.assertEqual(nw_gw['id'], nw_gw_id)
- self.assertEqual(nw_gw['name'], nw_gw_name)
-
- def test_network_gateway_delete(self):
- nw_gw_id = _uuid()
- instance = self.plugin.return_value
- res = self.api.delete(_get_path('%s/%s' % (networkgw.NETWORK_GATEWAYS,
- nw_gw_id)))
-
- instance.delete_network_gateway.assert_called_with(mock.ANY,
- nw_gw_id)
- self.assertEqual(res.status_int, exc.HTTPNoContent.code)
-
- def test_network_gateway_get(self):
- nw_gw_id = _uuid()
- return_value = {self._gw_resource: {'name': 'test',
- 'devices':
- [{'id': _uuid(),
- 'interface_name': 'xxx'}],
- 'id': nw_gw_id}}
- instance = self.plugin.return_value
- instance.get_network_gateway.return_value = return_value
-
- res = self.api.get(_get_path('%s/%s' % (networkgw.NETWORK_GATEWAYS,
- nw_gw_id)))
-
- instance.get_network_gateway.assert_called_with(mock.ANY,
- nw_gw_id,
- fields=mock.ANY)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
-
- def test_network_gateway_list(self):
- nw_gw_id = _uuid()
- return_value = [{self._gw_resource: {'name': 'test',
- 'devices':
- [{'id': _uuid(),
- 'interface_name': 'xxx'}],
- 'id': nw_gw_id}}]
- instance = self.plugin.return_value
- instance.get_network_gateways.return_value = return_value
-
- res = self.api.get(_get_path(networkgw.NETWORK_GATEWAYS))
-
- instance.get_network_gateways.assert_called_with(mock.ANY,
- fields=mock.ANY,
- filters=mock.ANY)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
-
- def test_network_gateway_connect(self):
- nw_gw_id = _uuid()
- nw_id = _uuid()
- gw_port_id = _uuid()
- mapping_data = {'network_id': nw_id,
- 'segmentation_type': 'vlan',
- 'segmentation_id': '999'}
- return_value = {'connection_info': {
- 'network_gateway_id': nw_gw_id,
- 'port_id': gw_port_id,
- 'network_id': nw_id}}
- instance = self.plugin.return_value
- instance.connect_network.return_value = return_value
- res = self.api.put_json(_get_path('%s/%s/connect_network' %
- (networkgw.NETWORK_GATEWAYS,
- nw_gw_id)),
- mapping_data)
- instance.connect_network.assert_called_with(mock.ANY,
- nw_gw_id,
- mapping_data)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
- nw_conn_res = res.json['connection_info']
- self.assertEqual(nw_conn_res['port_id'], gw_port_id)
- self.assertEqual(nw_conn_res['network_id'], nw_id)
-
- def test_network_gateway_disconnect(self):
- nw_gw_id = _uuid()
- nw_id = _uuid()
- mapping_data = {'network_id': nw_id}
- instance = self.plugin.return_value
- res = self.api.put_json(_get_path('%s/%s/disconnect_network' %
- (networkgw.NETWORK_GATEWAYS,
- nw_gw_id)),
- mapping_data)
- instance.disconnect_network.assert_called_with(mock.ANY,
- nw_gw_id,
- mapping_data)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
-
- def test_gateway_device_get(self):
- gw_dev_id = _uuid()
- return_value = {self._dev_resource: {'name': 'test',
- 'connector_type': 'stt',
- 'connector_ip': '1.1.1.1',
- 'id': gw_dev_id}}
- instance = self.plugin.return_value
- instance.get_gateway_device.return_value = return_value
-
- res = self.api.get(_get_path('%s/%s' % (networkgw.GATEWAY_DEVICES,
- gw_dev_id)))
-
- instance.get_gateway_device.assert_called_with(mock.ANY,
- gw_dev_id,
- fields=mock.ANY)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
-
- def test_gateway_device_list(self):
- gw_dev_id = _uuid()
- return_value = [{self._dev_resource: {'name': 'test',
- 'connector_type': 'stt',
- 'connector_ip': '1.1.1.1',
- 'id': gw_dev_id}}]
- instance = self.plugin.return_value
- instance.get_gateway_devices.return_value = return_value
-
- res = self.api.get(_get_path(networkgw.GATEWAY_DEVICES))
-
- instance.get_gateway_devices.assert_called_with(mock.ANY,
- fields=mock.ANY,
- filters=mock.ANY)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
-
- def test_gateway_device_create(self):
- gw_dev_id = _uuid()
- data = {self._dev_resource: {'name': 'test-dev',
- 'tenant_id': _uuid(),
- 'client_certificate': 'xyz',
- 'connector_type': 'stt',
- 'connector_ip': '1.1.1.1'}}
- return_value = data[self._dev_resource].copy()
- return_value.update({'id': gw_dev_id})
- instance = self.plugin.return_value
- instance.create_gateway_device.return_value = return_value
- res = self.api.post_json(_get_path(networkgw.GATEWAY_DEVICES), data)
- instance.create_gateway_device.assert_called_with(
- mock.ANY, gateway_device=data)
- self.assertEqual(res.status_int, exc.HTTPCreated.code)
- self.assertIn(self._dev_resource, res.json)
- gw_dev = res.json[self._dev_resource]
- self.assertEqual(gw_dev['id'], gw_dev_id)
-
- def _test_gateway_device_create_with_error(
- self, data, error_code=exc.HTTPBadRequest.code):
- res = self.api.post_json(_get_path(networkgw.GATEWAY_DEVICES), data,
- expect_errors=True)
- self.assertEqual(res.status_int, error_code)
-
- def test_gateway_device_create_invalid_connector_type(self):
- data = {self._gw_resource: {'name': 'test-dev',
- 'client_certificate': 'xyz',
- 'tenant_id': _uuid(),
- 'connector_type': 'invalid',
- 'connector_ip': '1.1.1.1'}}
- self._test_gateway_device_create_with_error(data)
-
- def test_gateway_device_create_invalid_connector_ip(self):
- data = {self._gw_resource: {'name': 'test-dev',
- 'client_certificate': 'xyz',
- 'tenant_id': _uuid(),
- 'connector_type': 'stt',
- 'connector_ip': 'invalid'}}
- self._test_gateway_device_create_with_error(data)
-
- def test_gateway_device_create_extra_attr_in_device_spec(self):
- data = {self._gw_resource: {'name': 'test-dev',
- 'client_certificate': 'xyz',
- 'tenant_id': _uuid(),
- 'alien_attribute': 'E.T.',
- 'connector_type': 'stt',
- 'connector_ip': '1.1.1.1'}}
- self._test_gateway_device_create_with_error(data)
-
- def test_gateway_device_update(self):
- gw_dev_name = 'updated'
- data = {self._dev_resource: {'name': gw_dev_name}}
- gw_dev_id = _uuid()
- return_value = {'id': gw_dev_id,
- 'name': gw_dev_name}
-
- instance = self.plugin.return_value
- instance.update_gateway_device.return_value = return_value
- res = self.api.put_json(
- _get_path('%s/%s' % (networkgw.GATEWAY_DEVICES, gw_dev_id)), data)
- instance.update_gateway_device.assert_called_with(
- mock.ANY, gw_dev_id, gateway_device=data)
- self.assertEqual(res.status_int, exc.HTTPOk.code)
- self.assertIn(self._dev_resource, res.json)
- gw_dev = res.json[self._dev_resource]
- self.assertEqual(gw_dev['id'], gw_dev_id)
- self.assertEqual(gw_dev['name'], gw_dev_name)
-
- def test_gateway_device_delete(self):
- gw_dev_id = _uuid()
- instance = self.plugin.return_value
- res = self.api.delete(_get_path('%s/%s' % (networkgw.GATEWAY_DEVICES,
- gw_dev_id)))
- instance.delete_gateway_device.assert_called_with(mock.ANY, gw_dev_id)
- self.assertEqual(res.status_int, exc.HTTPNoContent.code)
-
-
-class NetworkGatewayDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
- """Unit tests for Network Gateway DB support."""
-
- def setUp(self, plugin=None, ext_mgr=None):
- if not plugin:
- plugin = '%s.%s' % (__name__, TestNetworkGatewayPlugin.__name__)
- if not ext_mgr:
- ext_mgr = TestExtensionManager()
- self.gw_resource = networkgw.GATEWAY_RESOURCE_NAME
- self.dev_resource = networkgw.DEVICE_RESOURCE_NAME
-
- super(NetworkGatewayDbTestCase, self).setUp(plugin=plugin,
- ext_mgr=ext_mgr)
-
- def _create_network_gateway(self, fmt, tenant_id, name=None,
- devices=None, arg_list=None, **kwargs):
- data = {self.gw_resource: {'tenant_id': tenant_id,
- 'devices': devices}}
- if name:
- data[self.gw_resource]['name'] = name
- for arg in arg_list or ():
- # Arg must be present and not empty
- if kwargs.get(arg):
- data[self.gw_resource][arg] = kwargs[arg]
- nw_gw_req = self.new_create_request(networkgw.NETWORK_GATEWAYS,
- data, fmt)
- if (kwargs.get('set_context') and tenant_id):
- # create a specific auth context for this request
- nw_gw_req.environ['neutron.context'] = context.Context(
- '', tenant_id)
- return nw_gw_req.get_response(self.ext_api)
-
- @contextlib.contextmanager
- def _network_gateway(self, name='gw1', devices=None,
- fmt='json', tenant_id=_uuid()):
- device = None
- if not devices:
- device_res = self._create_gateway_device(
- fmt, tenant_id, 'stt', '1.1.1.1', 'xxxxxx',
- name='whatever')
- if device_res.status_int >= 400:
- raise exc.HTTPClientError(code=device_res.status_int)
- device = self.deserialize(fmt, device_res)
- devices = [{'id': device[self.dev_resource]['id'],
- 'interface_name': 'xyz'}]
-
- res = self._create_network_gateway(fmt, tenant_id, name=name,
- devices=devices)
- if res.status_int >= 400:
- raise exc.HTTPClientError(code=res.status_int)
- network_gateway = self.deserialize(fmt, res)
- yield network_gateway
-
- self._delete(networkgw.NETWORK_GATEWAYS,
- network_gateway[self.gw_resource]['id'])
- if device:
- self._delete(networkgw.GATEWAY_DEVICES,
- device[self.dev_resource]['id'])
-
- def _create_gateway_device(self, fmt, tenant_id,
- connector_type, connector_ip,
- client_certificate, name=None,
- set_context=False):
- data = {self.dev_resource: {'tenant_id': tenant_id,
- 'connector_type': connector_type,
- 'connector_ip': connector_ip,
- 'client_certificate': client_certificate}}
- if name:
- data[self.dev_resource]['name'] = name
- gw_dev_req = self.new_create_request(networkgw.GATEWAY_DEVICES,
- data, fmt)
- if (set_context and tenant_id):
- # create a specific auth context for this request
- gw_dev_req.environ['neutron.context'] = context.Context(
- '', tenant_id)
- return gw_dev_req.get_response(self.ext_api)
-
- def _update_gateway_device(self, fmt, gateway_device_id,
- connector_type=None, connector_ip=None,
- client_certificate=None, name=None,
- set_context=False, tenant_id=None):
- data = {self.dev_resource: {}}
- if connector_type:
- data[self.dev_resource]['connector_type'] = connector_type
- if connector_ip:
- data[self.dev_resource]['connector_ip'] = connector_ip
- if client_certificate:
- data[self.dev_resource]['client_certificate'] = client_certificate
- if name:
- data[self.dev_resource]['name'] = name
- gw_dev_req = self.new_update_request(networkgw.GATEWAY_DEVICES,
- data, gateway_device_id, fmt)
- if (set_context and tenant_id):
- # create a specific auth context for this request
- gw_dev_req.environ['neutron.context'] = context.Context(
- '', tenant_id)
- return gw_dev_req.get_response(self.ext_api)
-
- @contextlib.contextmanager
- def _gateway_device(self, name='gw_dev',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='xxxxxxxxxxxxxxx',
- fmt='json', tenant_id=_uuid()):
- res = self._create_gateway_device(
- fmt,
- tenant_id,
- connector_type=connector_type,
- connector_ip=connector_ip,
- client_certificate=client_certificate,
- name=name)
- if res.status_int >= 400:
- raise exc.HTTPClientError(code=res.status_int)
- gateway_device = self.deserialize(fmt, res)
- yield gateway_device
-
- self._delete(networkgw.GATEWAY_DEVICES,
- gateway_device[self.dev_resource]['id'])
-
- def _gateway_action(self, action, network_gateway_id, network_id,
- segmentation_type, segmentation_id=None,
- expected_status=exc.HTTPOk.code):
- connection_data = {'network_id': network_id,
- 'segmentation_type': segmentation_type}
- if segmentation_id:
- connection_data['segmentation_id'] = segmentation_id
-
- req = self.new_action_request(networkgw.NETWORK_GATEWAYS,
- connection_data,
- network_gateway_id,
- "%s_network" % action)
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, expected_status)
- return self.deserialize('json', res)
-
- def _test_connect_and_disconnect_network(self, segmentation_type,
- segmentation_id=None):
- with self._network_gateway() as gw:
- with self.network() as net:
- body = self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net['network']['id'],
- segmentation_type,
- segmentation_id)
- self.assertIn('connection_info', body)
- connection_info = body['connection_info']
- for attr in ('network_id', 'port_id',
- 'network_gateway_id'):
- self.assertIn(attr, connection_info)
- # fetch port and confirm device_id
- gw_port_id = connection_info['port_id']
- port_body = self._show('ports', gw_port_id)
- self.assertEqual(port_body['port']['device_id'],
- gw[self.gw_resource]['id'])
- # Clean up - otherwise delete will fail
- body = self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net['network']['id'],
- segmentation_type,
- segmentation_id)
- # Check associated port has been deleted too
- body = self._show('ports', gw_port_id,
- expected_code=exc.HTTPNotFound.code)
-
- def test_create_network_gateway(self):
- tenant_id = _uuid()
- with contextlib.nested(
- self._gateway_device(name='dev_1',
- tenant_id=tenant_id),
- self._gateway_device(name='dev_2',
- tenant_id=tenant_id)) as (dev_1, dev_2):
- name = 'test-gw'
- dev_1_id = dev_1[self.dev_resource]['id']
- dev_2_id = dev_2[self.dev_resource]['id']
- devices = [{'id': dev_1_id, 'interface_name': 'xxx'},
- {'id': dev_2_id, 'interface_name': 'yyy'}]
- keys = [('devices', devices), ('name', name)]
- with self._network_gateway(name=name,
- devices=devices,
- tenant_id=tenant_id) as gw:
- for k, v in keys:
- self.assertEqual(gw[self.gw_resource][k], v)
-
- def test_create_network_gateway_no_interface_name(self):
- tenant_id = _uuid()
- with self._gateway_device(tenant_id=tenant_id) as dev:
- name = 'test-gw'
- devices = [{'id': dev[self.dev_resource]['id']}]
- exp_devices = devices
- exp_devices[0]['interface_name'] = 'breth0'
- keys = [('devices', exp_devices), ('name', name)]
- with self._network_gateway(name=name,
- devices=devices,
- tenant_id=tenant_id) as gw:
- for k, v in keys:
- self.assertEqual(gw[self.gw_resource][k], v)
-
- def test_create_network_gateway_not_owned_device_raises_404(self):
- # Create a device with a different tenant identifier
- with self._gateway_device(name='dev', tenant_id=_uuid()) as dev:
- name = 'test-gw'
- dev_id = dev[self.dev_resource]['id']
- devices = [{'id': dev_id, 'interface_name': 'xxx'}]
- res = self._create_network_gateway(
- 'json', _uuid(), name=name, devices=devices)
- self.assertEqual(404, res.status_int)
-
- def test_create_network_gateway_non_existent_device_raises_404(self):
- name = 'test-gw'
- devices = [{'id': _uuid(), 'interface_name': 'xxx'}]
- res = self._create_network_gateway(
- 'json', _uuid(), name=name, devices=devices)
- self.assertEqual(404, res.status_int)
-
- def test_delete_network_gateway(self):
- tenant_id = _uuid()
- with self._gateway_device(tenant_id=tenant_id) as dev:
- name = 'test-gw'
- device_id = dev[self.dev_resource]['id']
- devices = [{'id': device_id,
- 'interface_name': 'xxx'}]
- with self._network_gateway(name=name,
- devices=devices,
- tenant_id=tenant_id) as gw:
- # Nothing to do here - just let the gateway go
- gw_id = gw[self.gw_resource]['id']
- # Verify nothing left on db
- session = db_api.get_session()
- dev_query = session.query(
- nsx_models.NetworkGatewayDevice).filter(
- nsx_models.NetworkGatewayDevice.id == device_id)
- self.assertIsNone(dev_query.first())
- gw_query = session.query(nsx_models.NetworkGateway).filter(
- nsx_models.NetworkGateway.id == gw_id)
- self.assertIsNone(gw_query.first())
-
- def test_update_network_gateway(self):
- with self._network_gateway() as gw:
- data = {self.gw_resource: {'name': 'new_name'}}
- req = self.new_update_request(networkgw.NETWORK_GATEWAYS,
- data,
- gw[self.gw_resource]['id'])
- res = self.deserialize('json', req.get_response(self.ext_api))
- self.assertEqual(res[self.gw_resource]['name'],
- data[self.gw_resource]['name'])
-
- def test_get_network_gateway(self):
- with self._network_gateway(name='test-gw') as gw:
- req = self.new_show_request(networkgw.NETWORK_GATEWAYS,
- gw[self.gw_resource]['id'])
- res = self.deserialize('json', req.get_response(self.ext_api))
- self.assertEqual(res[self.gw_resource]['name'],
- gw[self.gw_resource]['name'])
-
- def test_list_network_gateways(self):
- with self._network_gateway(name='test-gw-1') as gw1:
- with self._network_gateway(name='test_gw_2') as gw2:
- req = self.new_list_request(networkgw.NETWORK_GATEWAYS)
- res = self.deserialize('json', req.get_response(self.ext_api))
- key = self.gw_resource + 's'
- self.assertEqual(len(res[key]), 2)
- self.assertEqual(res[key][0]['name'],
- gw1[self.gw_resource]['name'])
- self.assertEqual(res[key][1]['name'],
- gw2[self.gw_resource]['name'])
-
- def _test_list_network_gateway_with_multiple_connections(
- self, expected_gateways=1):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 777)
- req = self.new_list_request(networkgw.NETWORK_GATEWAYS)
- res = self.deserialize('json', req.get_response(self.ext_api))
- key = self.gw_resource + 's'
- self.assertEqual(len(res[key]), expected_gateways)
- for item in res[key]:
- self.assertIn('ports', item)
- if item['id'] == gw[self.gw_resource]['id']:
- gw_ports = item['ports']
- self.assertEqual(len(gw_ports), 2)
- segmentation_ids = [555, 777]
- for gw_port in gw_ports:
- self.assertEqual('vlan', gw_port['segmentation_type'])
- self.assertIn(gw_port['segmentation_id'], segmentation_ids)
- segmentation_ids.remove(gw_port['segmentation_id'])
- # Required cleanup
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 777)
-
- def test_list_network_gateway_with_multiple_connections(self):
- self._test_list_network_gateway_with_multiple_connections()
-
- def test_connect_and_disconnect_network(self):
- self._test_connect_and_disconnect_network('flat')
-
- def test_connect_and_disconnect_network_no_seg_type(self):
- self._test_connect_and_disconnect_network(None)
-
- def test_connect_and_disconnect_network_vlan_with_segmentation_id(self):
- self._test_connect_and_disconnect_network('vlan', 999)
-
- def test_connect_and_disconnect_network_vlan_without_segmentation_id(self):
- self._test_connect_and_disconnect_network('vlan')
-
- def test_connect_network_multiple_times(self):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 777)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 777)
-
- def test_connect_network_multiple_gateways(self):
- with self._network_gateway() as gw_1:
- with self._network_gateway() as gw_2:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw_1[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('connect',
- gw_2[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('disconnect',
- gw_1[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('disconnect',
- gw_2[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
-
- def test_connect_network_mapping_in_use_returns_409(self):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- with self.network() as net_2:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_2['network']['id'],
- 'vlan', 555,
- expected_status=exc.HTTPConflict.code)
- # Clean up - otherwise delete will fail
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
-
- def test_connect_network_vlan_invalid_seg_id_returns_400(self):
- with self._network_gateway() as gw:
- with self.network() as net:
- # above upper bound
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net['network']['id'],
- 'vlan', 4095,
- expected_status=exc.HTTPBadRequest.code)
- # below lower bound (0 is valid for NSX plugin)
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net['network']['id'],
- 'vlan', -1,
- expected_status=exc.HTTPBadRequest.code)
-
- def test_connect_invalid_network_returns_400(self):
- with self._network_gateway() as gw:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- 'hohoho',
- 'vlan', 555,
- expected_status=exc.HTTPBadRequest.code)
-
- def test_connect_unspecified_network_returns_400(self):
- with self._network_gateway() as gw:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- None,
- 'vlan', 555,
- expected_status=exc.HTTPBadRequest.code)
-
- def test_disconnect_network_ambiguous_returns_409(self):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 777)
- # This should raise
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan',
- expected_status=exc.HTTPConflict.code)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 777)
-
- def test_delete_active_gateway_port_returns_409(self):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- body = self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- # fetch port id and try to delete it
- gw_port_id = body['connection_info']['port_id']
- self._delete('ports', gw_port_id,
- expected_code=exc.HTTPConflict.code)
- body = self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
-
- def test_delete_network_gateway_active_connections_returns_409(self):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'flat')
- self._delete(networkgw.NETWORK_GATEWAYS,
- gw[self.gw_resource]['id'],
- expected_code=exc.HTTPConflict.code)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'flat')
-
- def test_disconnect_non_existing_connection_returns_404(self):
- with self._network_gateway() as gw:
- with self.network() as net_1:
- self._gateway_action('connect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 999,
- expected_status=exc.HTTPNotFound.code)
- self._gateway_action('disconnect',
- gw[self.gw_resource]['id'],
- net_1['network']['id'],
- 'vlan', 555)
-
- def test_create_gateway_device(
- self, expected_status=networkgw_db.STATUS_UNKNOWN):
- with self._gateway_device(name='test-dev',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='xyz') as dev:
- self.assertEqual(dev[self.dev_resource]['name'], 'test-dev')
- self.assertEqual(dev[self.dev_resource]['connector_type'], 'stt')
- self.assertEqual(dev[self.dev_resource]['connector_ip'], '1.1.1.1')
- self.assertEqual(dev[self.dev_resource]['status'], expected_status)
-
- def test_list_gateway_devices(self):
- with contextlib.nested(
- self._gateway_device(name='test-dev-1',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='xyz'),
- self._gateway_device(name='test-dev-2',
- connector_type='stt',
- connector_ip='2.2.2.2',
- client_certificate='qwe')) as (dev_1, dev_2):
- req = self.new_list_request(networkgw.GATEWAY_DEVICES)
- res = self.deserialize('json', req.get_response(self.ext_api))
- devices = res[networkgw.GATEWAY_DEVICES.replace('-', '_')]
- self.assertEqual(len(devices), 2)
- dev_1 = devices[0]
- dev_2 = devices[1]
- self.assertEqual(dev_1['name'], 'test-dev-1')
- self.assertEqual(dev_2['name'], 'test-dev-2')
-
- def test_get_gateway_device(
- self, expected_status=networkgw_db.STATUS_UNKNOWN):
- with self._gateway_device(name='test-dev',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='xyz') as dev:
- req = self.new_show_request(networkgw.GATEWAY_DEVICES,
- dev[self.dev_resource]['id'])
- res = self.deserialize('json', req.get_response(self.ext_api))
- self.assertEqual(res[self.dev_resource]['name'], 'test-dev')
- self.assertEqual(res[self.dev_resource]['connector_type'], 'stt')
- self.assertEqual(res[self.dev_resource]['connector_ip'], '1.1.1.1')
- self.assertEqual(res[self.dev_resource]['status'], expected_status)
-
- def test_update_gateway_device(
- self, expected_status=networkgw_db.STATUS_UNKNOWN):
- with self._gateway_device(name='test-dev',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='xyz') as dev:
- self._update_gateway_device('json', dev[self.dev_resource]['id'],
- connector_type='stt',
- connector_ip='2.2.2.2',
- name='test-dev-upd')
- req = self.new_show_request(networkgw.GATEWAY_DEVICES,
- dev[self.dev_resource]['id'])
- res = self.deserialize('json', req.get_response(self.ext_api))
-
- self.assertEqual(res[self.dev_resource]['name'], 'test-dev-upd')
- self.assertEqual(res[self.dev_resource]['connector_type'], 'stt')
- self.assertEqual(res[self.dev_resource]['connector_ip'], '2.2.2.2')
- self.assertEqual(res[self.dev_resource]['status'], expected_status)
-
- def test_delete_gateway_device(self):
- with self._gateway_device(name='test-dev',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='xyz') as dev:
- # Nothing to do here - just note the device id
- dev_id = dev[self.dev_resource]['id']
- # Verify nothing left on db
- session = db_api.get_session()
- dev_query = session.query(nsx_models.NetworkGatewayDevice)
- dev_query.filter(nsx_models.NetworkGatewayDevice.id == dev_id)
- self.assertIsNone(dev_query.first())
-
-
-class TestNetworkGateway(test_nsx_plugin.NsxPluginV2TestCase,
- NetworkGatewayDbTestCase):
-
- def setUp(self, plugin=vmware.PLUGIN_NAME, ext_mgr=None):
- cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH)
- # Mock l2gwlib calls for gateway devices since this resource is not
- # mocked through the fake NSX API client
- create_gw_dev_patcher = mock.patch.object(
- l2gwlib, 'create_gateway_device')
- update_gw_dev_patcher = mock.patch.object(
- l2gwlib, 'update_gateway_device')
- delete_gw_dev_patcher = mock.patch.object(
- l2gwlib, 'delete_gateway_device')
- get_gw_dev_status_patcher = mock.patch.object(
- l2gwlib, 'get_gateway_device_status')
- get_gw_dev_statuses_patcher = mock.patch.object(
- l2gwlib, 'get_gateway_devices_status')
- self.mock_create_gw_dev = create_gw_dev_patcher.start()
- self.mock_create_gw_dev.return_value = {'uuid': 'callejon'}
- self.mock_update_gw_dev = update_gw_dev_patcher.start()
- delete_gw_dev_patcher.start()
- self.mock_get_gw_dev_status = get_gw_dev_status_patcher.start()
- get_gw_dev_statuses = get_gw_dev_statuses_patcher.start()
- get_gw_dev_statuses.return_value = {}
-
- super(TestNetworkGateway,
- self).setUp(plugin=plugin, ext_mgr=ext_mgr)
-
- def test_create_network_gateway_name_exceeds_40_chars(self):
- name = 'this_is_a_gateway_whose_name_is_longer_than_40_chars'
- with self._network_gateway(name=name) as nw_gw:
- # Assert Neutron name is not truncated
- self.assertEqual(nw_gw[self.gw_resource]['name'], name)
-
- def test_update_network_gateway_with_name_calls_backend(self):
- with mock.patch.object(
- nsxlib.l2gateway, 'update_l2_gw_service') as mock_update_gw:
- with self._network_gateway(name='cavani') as nw_gw:
- nw_gw_id = nw_gw[self.gw_resource]['id']
- self._update(networkgw.NETWORK_GATEWAYS, nw_gw_id,
- {self.gw_resource: {'name': 'higuain'}})
- mock_update_gw.assert_called_once_with(
- mock.ANY, nw_gw_id, 'higuain')
-
- def test_update_network_gateway_without_name_does_not_call_backend(self):
- with mock.patch.object(
- nsxlib.l2gateway, 'update_l2_gw_service') as mock_update_gw:
- with self._network_gateway(name='something') as nw_gw:
- nw_gw_id = nw_gw[self.gw_resource]['id']
- self._update(networkgw.NETWORK_GATEWAYS, nw_gw_id,
- {self.gw_resource: {}})
- self.assertEqual(mock_update_gw.call_count, 0)
-
- def test_update_network_gateway_name_exceeds_40_chars(self):
- new_name = 'this_is_a_gateway_whose_name_is_longer_than_40_chars'
- with self._network_gateway(name='something') as nw_gw:
- nw_gw_id = nw_gw[self.gw_resource]['id']
- self._update(networkgw.NETWORK_GATEWAYS, nw_gw_id,
- {self.gw_resource: {'name': new_name}})
- req = self.new_show_request(networkgw.NETWORK_GATEWAYS,
- nw_gw_id)
- res = self.deserialize('json', req.get_response(self.ext_api))
- # Assert Neutron name is not truncated
- self.assertEqual(new_name, res[self.gw_resource]['name'])
- # Assert NSX name is truncated
- self.assertEqual(
- new_name[:40],
- self.fc._fake_gatewayservice_dict[nw_gw_id]['display_name'])
-
- def test_create_network_gateway_nsx_error_returns_500(self):
- def raise_nsx_api_exc(*args, **kwargs):
- raise api_exc.NsxApiException()
-
- with mock.patch.object(nsxlib.l2gateway,
- 'create_l2_gw_service',
- new=raise_nsx_api_exc):
- tenant_id = _uuid()
- with self._gateway_device(tenant_id=tenant_id) as dev:
- res = self._create_network_gateway(
- self.fmt,
- tenant_id,
- name='yyy',
- devices=[{'id': dev[self.dev_resource]['id']}])
- self.assertEqual(500, res.status_int)
-
- def test_create_network_gateway_nsx_error_returns_409(self):
- with mock.patch.object(nsxlib.l2gateway,
- 'create_l2_gw_service',
- side_effect=api_exc.Conflict):
- tenant_id = _uuid()
- with self._gateway_device(tenant_id=tenant_id) as dev:
- res = self._create_network_gateway(
- self.fmt,
- tenant_id,
- name='yyy',
- devices=[{'id': dev[self.dev_resource]['id']}])
- self.assertEqual(409, res.status_int)
-
- def test_list_network_gateways(self):
- with self._network_gateway(name='test-gw-1') as gw1:
- with self._network_gateway(name='test_gw_2') as gw2:
- req = self.new_list_request(networkgw.NETWORK_GATEWAYS)
- res = self.deserialize('json', req.get_response(self.ext_api))
- # Ensure we always get the list in the same order
- gateways = sorted(
- res[self.gw_resource + 's'], key=lambda k: k['name'])
- self.assertEqual(len(gateways), 3)
- # We expect the default gateway too
- self.assertEqual(gateways[0]['default'], True)
- self.assertEqual(gateways[1]['name'],
- gw1[self.gw_resource]['name'])
- self.assertEqual(gateways[2]['name'],
- gw2[self.gw_resource]['name'])
-
- def test_list_network_gateway_with_multiple_connections(self):
- self._test_list_network_gateway_with_multiple_connections(
- expected_gateways=2)
-
- def test_show_network_gateway_nsx_error_returns_404(self):
- invalid_id = 'b5afd4a9-eb71-4af7-a082-8fc625a35b61'
- req = self.new_show_request(networkgw.NETWORK_GATEWAYS, invalid_id)
- res = req.get_response(self.ext_api)
- self.assertEqual(exc.HTTPNotFound.code, res.status_int)
-
- def test_create_gateway_device(self):
- self.mock_get_gw_dev_status.return_value = True
- super(TestNetworkGateway, self).test_create_gateway_device(
- expected_status=networkgw_db.STATUS_ACTIVE)
-
- def test_create_gateway_device_status_down(self):
- self.mock_get_gw_dev_status.return_value = False
- super(TestNetworkGateway, self).test_create_gateway_device(
- expected_status=networkgw_db.STATUS_DOWN)
-
- def test_create_gateway_device_invalid_cert_returns_400(self):
- self.mock_create_gw_dev.side_effect = (
- nsx_exc.InvalidSecurityCertificate)
- res = self._create_gateway_device(
- 'json',
- _uuid(),
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='invalid_certificate',
- name='whatever')
- self.assertEqual(res.status_int, 400)
-
- def test_get_gateway_device(self):
- self.mock_get_gw_dev_status.return_value = True
- super(TestNetworkGateway, self).test_get_gateway_device(
- expected_status=networkgw_db.STATUS_ACTIVE)
-
- def test_get_gateway_device_status_down(self):
- self.mock_get_gw_dev_status.return_value = False
- super(TestNetworkGateway, self).test_get_gateway_device(
- expected_status=networkgw_db.STATUS_DOWN)
-
- def test_update_gateway_device(self):
- self.mock_get_gw_dev_status.return_value = True
- super(TestNetworkGateway, self).test_update_gateway_device(
- expected_status=networkgw_db.STATUS_ACTIVE)
-
- def test_update_gateway_device_status_down(self):
- self.mock_get_gw_dev_status.return_value = False
- super(TestNetworkGateway, self).test_update_gateway_device(
- expected_status=networkgw_db.STATUS_DOWN)
-
- def test_update_gateway_device_invalid_cert_returns_400(self):
- with self._gateway_device(
- name='whaterver',
- connector_type='stt',
- connector_ip='1.1.1.1',
- client_certificate='iminvalidbutiitdoesnotmatter') as dev:
- self.mock_update_gw_dev.side_effect = (
- nsx_exc.InvalidSecurityCertificate)
- res = self._update_gateway_device(
- 'json',
- dev[self.dev_resource]['id'],
- client_certificate='invalid_certificate')
- self.assertEqual(res.status_int, 400)
-
-
-class TestNetworkGatewayPlugin(db_base_plugin_v2.NeutronDbPluginV2,
- networkgw_db.NetworkGatewayMixin):
- """Simple plugin class for testing db support for network gateway ext."""
-
- supported_extension_aliases = ["network-gateway"]
-
- def __init__(self, **args):
- super(TestNetworkGatewayPlugin, self).__init__(**args)
- extensions.append_api_extensions_path([vmware.NSXEXT_PATH])
-
- def delete_port(self, context, id, nw_gw_port_check=True):
- if nw_gw_port_check:
- port = self._get_port(context, id)
- self.prevent_network_gateway_port_deletion(context, port)
- super(TestNetworkGatewayPlugin, self).delete_port(context, id)
+++ /dev/null
-# Copyright (c) 2014 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 mock
-
-from neutron.common import test_lib
-from neutron.plugins.vmware.common import sync
-from neutron.tests.unit import test_extension_portsecurity as psec
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.apiclient import fake
-
-
-class PortSecurityTestCase(psec.PortSecurityDBTestCase):
-
- def setUp(self):
- test_lib.test_config['config_files'] = [
- vmware.get_fake_conf('nsx.ini.test')]
- # mock api client
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsx = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- instance = self.mock_nsx.start()
- instance.return_value.login.return_value = "the_cookie"
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
-
- instance.return_value.request.side_effect = self.fc.fake_request
- super(PortSecurityTestCase, self).setUp(vmware.PLUGIN_NAME)
- self.addCleanup(self.fc.reset_all)
- self.addCleanup(self.mock_nsx.stop)
- self.addCleanup(patch_sync.stop)
-
-
-class TestPortSecurity(PortSecurityTestCase, psec.TestPortSecurity):
- pass
+++ /dev/null
-# Copyright (c) 2014 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.
-
-from oslo_config import cfg
-import webob.exc
-
-from neutron.extensions import multiprovidernet as mpnet
-from neutron.extensions import providernet as pnet
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware import test_nsx_plugin
-
-
-class TestProvidernet(test_nsx_plugin.NsxPluginV2TestCase):
-
- def test_create_delete_provider_network_default_physical_net(self):
- data = {'network': {'name': 'net1',
- 'admin_state_up': True,
- 'tenant_id': 'admin',
- pnet.NETWORK_TYPE: 'vlan',
- pnet.SEGMENTATION_ID: 411}}
- network_req = self.new_create_request('networks', data, self.fmt)
- net = self.deserialize(self.fmt, network_req.get_response(self.api))
- self.assertEqual(net['network'][pnet.NETWORK_TYPE], 'vlan')
- self.assertEqual(net['network'][pnet.SEGMENTATION_ID], 411)
- req = self.new_delete_request('networks', net['network']['id'])
- res = req.get_response(self.api)
- self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
-
- def test_create_provider_network(self):
- data = {'network': {'name': 'net1',
- 'admin_state_up': True,
- 'tenant_id': 'admin',
- pnet.NETWORK_TYPE: 'vlan',
- pnet.SEGMENTATION_ID: 411,
- pnet.PHYSICAL_NETWORK: 'physnet1'}}
- network_req = self.new_create_request('networks', data, self.fmt)
- net = self.deserialize(self.fmt, network_req.get_response(self.api))
- self.assertEqual(net['network'][pnet.NETWORK_TYPE], 'vlan')
- self.assertEqual(net['network'][pnet.SEGMENTATION_ID], 411)
- self.assertEqual(net['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
-
- # Test that we can create another provider network using the same
- # vlan_id on another physical network.
- data['network'][pnet.PHYSICAL_NETWORK] = 'physnet2'
- network_req = self.new_create_request('networks', data, self.fmt)
- net = self.deserialize(self.fmt, network_req.get_response(self.api))
- self.assertEqual(net['network'][pnet.NETWORK_TYPE], 'vlan')
- self.assertEqual(net['network'][pnet.SEGMENTATION_ID], 411)
- self.assertEqual(net['network'][pnet.PHYSICAL_NETWORK], 'physnet2')
-
-
-class TestMultiProviderNetworks(test_nsx_plugin.NsxPluginV2TestCase):
-
- def setUp(self, plugin=None):
- cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH)
- super(TestMultiProviderNetworks, self).setUp()
-
- def test_create_network_provider(self):
- data = {'network': {'name': 'net1',
- pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1,
- 'tenant_id': 'tenant_one'}}
- network_req = self.new_create_request('networks', data)
- network = self.deserialize(self.fmt,
- network_req.get_response(self.api))
- self.assertEqual(network['network'][pnet.NETWORK_TYPE], 'vlan')
- self.assertEqual(network['network'][pnet.PHYSICAL_NETWORK], 'physnet1')
- self.assertEqual(network['network'][pnet.SEGMENTATION_ID], 1)
- self.assertNotIn(mpnet.SEGMENTS, network['network'])
-
- def test_create_network_provider_flat(self):
- data = {'network': {'name': 'net1',
- pnet.NETWORK_TYPE: 'flat',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- 'tenant_id': 'tenant_one'}}
- network_req = self.new_create_request('networks', data)
- network = self.deserialize(self.fmt,
- network_req.get_response(self.api))
- self.assertEqual('flat', network['network'][pnet.NETWORK_TYPE])
- self.assertEqual('physnet1', network['network'][pnet.PHYSICAL_NETWORK])
- self.assertEqual(0, network['network'][pnet.SEGMENTATION_ID])
- self.assertNotIn(mpnet.SEGMENTS, network['network'])
-
- def test_create_network_single_multiple_provider(self):
- data = {'network': {'name': 'net1',
- mpnet.SEGMENTS:
- [{pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1}],
- 'tenant_id': 'tenant_one'}}
- net_req = self.new_create_request('networks', data)
- network = self.deserialize(self.fmt, net_req.get_response(self.api))
- for provider_field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID]:
- self.assertNotIn(provider_field, network['network'])
- tz = network['network'][mpnet.SEGMENTS][0]
- self.assertEqual(tz[pnet.NETWORK_TYPE], 'vlan')
- self.assertEqual(tz[pnet.PHYSICAL_NETWORK], 'physnet1')
- self.assertEqual(tz[pnet.SEGMENTATION_ID], 1)
-
- # Tests get_network()
- net_req = self.new_show_request('networks', network['network']['id'])
- network = self.deserialize(self.fmt, net_req.get_response(self.api))
- tz = network['network'][mpnet.SEGMENTS][0]
- self.assertEqual(tz[pnet.NETWORK_TYPE], 'vlan')
- self.assertEqual(tz[pnet.PHYSICAL_NETWORK], 'physnet1')
- self.assertEqual(tz[pnet.SEGMENTATION_ID], 1)
-
- def test_create_network_multprovider(self):
- data = {'network': {'name': 'net1',
- mpnet.SEGMENTS:
- [{pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1},
- {pnet.NETWORK_TYPE: 'stt',
- pnet.PHYSICAL_NETWORK: 'physnet1'}],
- 'tenant_id': 'tenant_one'}}
- network_req = self.new_create_request('networks', data)
- network = self.deserialize(self.fmt,
- network_req.get_response(self.api))
- tz = network['network'][mpnet.SEGMENTS]
- for tz in data['network'][mpnet.SEGMENTS]:
- for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID]:
- self.assertEqual(tz.get(field), tz.get(field))
-
- # Tests get_network()
- net_req = self.new_show_request('networks', network['network']['id'])
- network = self.deserialize(self.fmt, net_req.get_response(self.api))
- tz = network['network'][mpnet.SEGMENTS]
- for tz in data['network'][mpnet.SEGMENTS]:
- for field in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID]:
- self.assertEqual(tz.get(field), tz.get(field))
-
- def test_create_network_with_provider_and_multiprovider_fail(self):
- data = {'network': {'name': 'net1',
- mpnet.SEGMENTS:
- [{pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1}],
- pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1,
- 'tenant_id': 'tenant_one'}}
-
- network_req = self.new_create_request('networks', data)
- res = network_req.get_response(self.api)
- self.assertEqual(res.status_int, 400)
-
- def test_create_network_duplicate_segments(self):
- data = {'network': {'name': 'net1',
- mpnet.SEGMENTS:
- [{pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1},
- {pnet.NETWORK_TYPE: 'vlan',
- pnet.PHYSICAL_NETWORK: 'physnet1',
- pnet.SEGMENTATION_ID: 1}],
- 'tenant_id': 'tenant_one'}}
- network_req = self.new_create_request('networks', data)
- res = network_req.get_response(self.api)
- self.assertEqual(res.status_int, 400)
+++ /dev/null
-# Copyright (c) 2014 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 contextlib
-
-import mock
-from oslo_config import cfg
-import webob.exc
-
-from neutron import context
-from neutron.plugins.vmware.dbexts import qos_db
-from neutron.plugins.vmware.extensions import qos as ext_qos
-from neutron.plugins.vmware import nsxlib
-from neutron.tests.unit import test_extensions
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware import test_nsx_plugin
-
-
-class QoSTestExtensionManager(object):
-
- def get_resources(self):
- return ext_qos.Qos.get_resources()
-
- def get_actions(self):
- return []
-
- def get_request_extensions(self):
- return []
-
-
-class TestQoSQueue(test_nsx_plugin.NsxPluginV2TestCase):
-
- def setUp(self, plugin=None):
- cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH)
- super(TestQoSQueue, self).setUp()
- ext_mgr = QoSTestExtensionManager()
- self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
-
- def _create_qos_queue(self, fmt, body, **kwargs):
- qos_queue = self.new_create_request('qos-queues', body)
- if (kwargs.get('set_context') and 'tenant_id' in kwargs):
- # create a specific auth context for this request
- qos_queue.environ['neutron.context'] = context.Context(
- '', kwargs['tenant_id'])
-
- return qos_queue.get_response(self.ext_api)
-
- @contextlib.contextmanager
- def qos_queue(self, name='foo', min='0', max='10',
- qos_marking=None, dscp='0', default=None):
-
- body = {'qos_queue': {'tenant_id': 'tenant',
- 'name': name,
- 'min': min,
- 'max': max}}
-
- if qos_marking:
- body['qos_queue']['qos_marking'] = qos_marking
- if dscp:
- body['qos_queue']['dscp'] = dscp
- if default:
- body['qos_queue']['default'] = default
- res = self._create_qos_queue('json', body)
- qos_queue = self.deserialize('json', res)
- if res.status_int >= 400:
- raise webob.exc.HTTPClientError(code=res.status_int)
-
- yield qos_queue
-
- def test_create_qos_queue(self):
- with self.qos_queue(name='fake_lqueue', min=34, max=44,
- qos_marking='untrusted', default=False) as q:
- self.assertEqual(q['qos_queue']['name'], 'fake_lqueue')
- self.assertEqual(q['qos_queue']['min'], 34)
- self.assertEqual(q['qos_queue']['max'], 44)
- self.assertEqual(q['qos_queue']['qos_marking'], 'untrusted')
- self.assertFalse(q['qos_queue']['default'])
-
- def test_create_trusted_qos_queue(self):
- with mock.patch.object(qos_db.LOG, 'info') as log:
- with mock.patch.object(nsxlib, 'do_request',
- return_value={"uuid": "fake_queue"}):
- with self.qos_queue(name='fake_lqueue', min=34, max=44,
- qos_marking='trusted', default=False) as q:
- self.assertIsNone(q['qos_queue']['dscp'])
- self.assertTrue(log.called)
-
- def test_create_qos_queue_name_exceeds_40_chars(self):
- name = 'this_is_a_queue_whose_name_is_longer_than_40_chars'
- with self.qos_queue(name=name) as queue:
- # Assert Neutron name is not truncated
- self.assertEqual(queue['qos_queue']['name'], name)
-
- def test_create_qos_queue_default(self):
- with self.qos_queue(default=True) as q:
- self.assertTrue(q['qos_queue']['default'])
-
- def test_create_qos_queue_two_default_queues_fail(self):
- with self.qos_queue(default=True):
- body = {'qos_queue': {'tenant_id': 'tenant',
- 'name': 'second_default_queue',
- 'default': True}}
- res = self._create_qos_queue('json', body)
- self.assertEqual(res.status_int, 409)
-
- def test_create_port_with_queue(self):
- with self.qos_queue(default=True) as q1:
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net1 = self.deserialize('json', res)
- self.assertEqual(net1['network'][ext_qos.QUEUE],
- q1['qos_queue']['id'])
- device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
- with self.port(device_id=device_id) as p:
- self.assertEqual(len(p['port'][ext_qos.QUEUE]), 36)
-
- def test_create_shared_queue_networks(self):
- with self.qos_queue(default=True) as q1:
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net1 = self.deserialize('json', res)
- self.assertEqual(net1['network'][ext_qos.QUEUE],
- q1['qos_queue']['id'])
- res = self._create_network('json', 'net2', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net2 = self.deserialize('json', res)
- self.assertEqual(net1['network'][ext_qos.QUEUE],
- q1['qos_queue']['id'])
- device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
- res = self._create_port('json', net1['network']['id'],
- device_id=device_id)
- port1 = self.deserialize('json', res)
- res = self._create_port('json', net2['network']['id'],
- device_id=device_id)
- port2 = self.deserialize('json', res)
- self.assertEqual(port1['port'][ext_qos.QUEUE],
- port2['port'][ext_qos.QUEUE])
-
- self._delete('ports', port1['port']['id'])
- self._delete('ports', port2['port']['id'])
-
- def test_remove_queue_in_use_fail(self):
- with self.qos_queue() as q1:
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net1 = self.deserialize('json', res)
- device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
- res = self._create_port('json', net1['network']['id'],
- device_id=device_id)
- port = self.deserialize('json', res)
- self._delete('qos-queues', port['port'][ext_qos.QUEUE], 409)
-
- def test_update_network_new_queue(self):
- with self.qos_queue() as q1:
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net1 = self.deserialize('json', res)
- with self.qos_queue() as new_q:
- data = {'network': {ext_qos.QUEUE: new_q['qos_queue']['id']}}
- req = self.new_update_request('networks', data,
- net1['network']['id'])
- res = req.get_response(self.api)
- net1 = self.deserialize('json', res)
- self.assertEqual(net1['network'][ext_qos.QUEUE],
- new_q['qos_queue']['id'])
-
- def test_update_port_adding_device_id(self):
- with self.qos_queue() as q1:
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net1 = self.deserialize('json', res)
- device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
- res = self._create_port('json', net1['network']['id'])
- port = self.deserialize('json', res)
- self.assertIsNone(port['port'][ext_qos.QUEUE])
-
- data = {'port': {'device_id': device_id}}
- req = self.new_update_request('ports', data,
- port['port']['id'])
-
- res = req.get_response(self.api)
- port = self.deserialize('json', res)
- self.assertEqual(len(port['port'][ext_qos.QUEUE]), 36)
-
- def test_get_port_with_qos_not_admin(self):
- body = {'qos_queue': {'tenant_id': 'not_admin',
- 'name': 'foo', 'min': 20, 'max': 20}}
- res = self._create_qos_queue('json', body, tenant_id='not_admin')
- q1 = self.deserialize('json', res)
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE, 'tenant_id',),
- queue_id=q1['qos_queue']['id'],
- tenant_id="not_admin")
- net1 = self.deserialize('json', res)
- self.assertEqual(len(net1['network'][ext_qos.QUEUE]), 36)
- res = self._create_port('json', net1['network']['id'],
- tenant_id='not_admin', set_context=True)
-
- port = self.deserialize('json', res)
- self.assertNotIn(ext_qos.QUEUE, port['port'])
-
- def test_dscp_value_out_of_range(self):
- body = {'qos_queue': {'tenant_id': 'admin', 'dscp': '64',
- 'name': 'foo', 'min': 20, 'max': 20}}
- res = self._create_qos_queue('json', body)
- self.assertEqual(res.status_int, 400)
-
- def test_dscp_value_with_qos_marking_trusted_returns_400(self):
- body = {'qos_queue': {'tenant_id': 'admin', 'dscp': '1',
- 'qos_marking': 'trusted',
- 'name': 'foo', 'min': 20, 'max': 20}}
- res = self._create_qos_queue('json', body)
- self.assertEqual(res.status_int, 400)
-
- def test_non_admin_cannot_create_queue(self):
- body = {'qos_queue': {'tenant_id': 'not_admin',
- 'name': 'foo', 'min': 20, 'max': 20}}
- res = self._create_qos_queue('json', body, tenant_id='not_admin',
- set_context=True)
- self.assertEqual(res.status_int, 403)
-
- def test_update_port_non_admin_does_not_show_queue_id(self):
- body = {'qos_queue': {'tenant_id': 'not_admin',
- 'name': 'foo', 'min': 20, 'max': 20}}
- res = self._create_qos_queue('json', body, tenant_id='not_admin')
- q1 = self.deserialize('json', res)
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- tenant_id='not_admin',
- queue_id=q1['qos_queue']['id'])
-
- net1 = self.deserialize('json', res)
- res = self._create_port('json', net1['network']['id'],
- tenant_id='not_admin', set_context=True)
- port = self.deserialize('json', res)
- device_id = "00fff4d0-e4a8-4a3a-8906-4c4cdafb59f1"
- data = {'port': {'device_id': device_id}}
- neutron_context = context.Context('', 'not_admin')
- port = self._update('ports', port['port']['id'], data,
- neutron_context=neutron_context)
- self.assertNotIn(ext_qos.QUEUE, port['port'])
-
- def test_rxtx_factor(self):
- with self.qos_queue(max=10) as q1:
-
- res = self._create_network('json', 'net1', True,
- arg_list=(ext_qos.QUEUE,),
- queue_id=q1['qos_queue']['id'])
- net1 = self.deserialize('json', res)
- res = self._create_port('json', net1['network']['id'],
- arg_list=(ext_qos.RXTX_FACTOR,),
- rxtx_factor=2, device_id='1')
- port = self.deserialize('json', res)
- req = self.new_show_request('qos-queues',
- port['port'][ext_qos.QUEUE])
- res = req.get_response(self.ext_api)
- queue = self.deserialize('json', res)
- self.assertEqual(queue['qos_queue']['max'], 20)
+++ /dev/null
-# Copyright (c) 2014 VMware, 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 mock
-
-from neutron.plugins.vmware.api_client import client
-from neutron.plugins.vmware.api_client import exception
-from neutron.plugins.vmware.api_client import version
-from neutron.plugins.vmware.common import config # noqa
-from neutron.plugins.vmware import nsx_cluster as cluster
-from neutron.tests import base
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.apiclient import fake
-
-_uuid = test_api_v2._uuid
-
-
-class NsxlibTestCase(base.BaseTestCase):
-
- def setUp(self):
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsxapi = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- instance = self.mock_nsxapi.start()
- instance.return_value.login.return_value = "the_cookie"
- fake_version = getattr(self, 'fake_version', "3.0")
- instance.return_value.get_version.return_value = (
- version.Version(fake_version))
-
- instance.return_value.request.side_effect = self.fc.fake_request
- self.fake_cluster = cluster.NSXCluster(
- name='fake-cluster', nsx_controllers=['1.1.1.1:999'],
- default_tz_uuid=_uuid(), nsx_user='foo', nsx_password='bar')
- self.fake_cluster.api_client = client.NsxApiClient(
- ('1.1.1.1', '999', True),
- self.fake_cluster.nsx_user, self.fake_cluster.nsx_password,
- self.fake_cluster.http_timeout,
- self.fake_cluster.retries, self.fake_cluster.redirects)
-
- super(NsxlibTestCase, self).setUp()
- self.addCleanup(self.fc.reset_all)
-
- def _build_tag_dict(self, tags):
- # This syntax is needed for python 2.6 compatibility
- return dict((t['scope'], t['tag']) for t in tags)
-
-
-class NsxlibNegativeBaseTestCase(base.BaseTestCase):
-
- def setUp(self):
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsxapi = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- instance = self.mock_nsxapi.start()
- instance.return_value.login.return_value = "the_cookie"
- # Choose 3.0, but the version is irrelevant for the aim of
- # these tests as calls are throwing up errors anyway
- fake_version = getattr(self, 'fake_version', "3.0")
- instance.return_value.get_version.return_value = (
- version.Version(fake_version))
-
- def _faulty_request(*args, **kwargs):
- raise exception.NsxApiException()
-
- instance.return_value.request.side_effect = _faulty_request
- self.fake_cluster = cluster.NSXCluster(
- name='fake-cluster', nsx_controllers=['1.1.1.1:999'],
- default_tz_uuid=_uuid(), nsx_user='foo', nsx_password='bar')
- self.fake_cluster.api_client = client.NsxApiClient(
- ('1.1.1.1', '999', True),
- self.fake_cluster.nsx_user, self.fake_cluster.nsx_password,
- self.fake_cluster.http_timeout,
- self.fake_cluster.retries, self.fake_cluster.redirects)
-
- super(NsxlibNegativeBaseTestCase, self).setUp()
- self.addCleanup(self.fc.reset_all)
+++ /dev/null
-# Copyright (c) 2014 VMware, 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 mock
-from oslo_serialization import jsonutils
-
-from neutron.plugins.vmware.api_client import exception
-from neutron.plugins.vmware.common import utils as nsx_utils
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import l2gateway as l2gwlib
-from neutron.plugins.vmware.nsxlib import switch as switchlib
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit.vmware.nsxlib import base
-
-_uuid = test_api_v2._uuid
-
-
-class L2GatewayNegativeTestCase(base.NsxlibNegativeBaseTestCase):
-
- def test_create_l2_gw_service_on_failure(self):
- self.assertRaises(exception.NsxApiException,
- l2gwlib.create_l2_gw_service,
- self.fake_cluster,
- 'fake-tenant',
- 'fake-gateway',
- [{'id': _uuid(),
- 'interface_name': 'xxx'}])
-
- def test_delete_l2_gw_service_on_failure(self):
- self.assertRaises(exception.NsxApiException,
- l2gwlib.delete_l2_gw_service,
- self.fake_cluster,
- 'fake-gateway')
-
- def test_get_l2_gw_service_on_failure(self):
- self.assertRaises(exception.NsxApiException,
- l2gwlib.get_l2_gw_service,
- self.fake_cluster,
- 'fake-gateway')
-
- def test_update_l2_gw_service_on_failure(self):
- self.assertRaises(exception.NsxApiException,
- l2gwlib.update_l2_gw_service,
- self.fake_cluster,
- 'fake-gateway',
- 'pluto')
-
-
-class L2GatewayTestCase(base.NsxlibTestCase):
-
- def _create_gw_service(self, node_uuid, display_name,
- tenant_id='fake_tenant'):
- return l2gwlib.create_l2_gw_service(self.fake_cluster,
- tenant_id,
- display_name,
- [{'id': node_uuid,
- 'interface_name': 'xxx'}])
-
- def test_create_l2_gw_service(self):
- display_name = 'fake-gateway'
- node_uuid = _uuid()
- response = self._create_gw_service(node_uuid, display_name)
- self.assertEqual(response.get('type'), 'L2GatewayServiceConfig')
- self.assertEqual(response.get('display_name'), display_name)
- gateways = response.get('gateways', [])
- self.assertEqual(len(gateways), 1)
- self.assertEqual(gateways[0]['type'], 'L2Gateway')
- self.assertEqual(gateways[0]['device_id'], 'xxx')
- self.assertEqual(gateways[0]['transport_node_uuid'], node_uuid)
-
- def test_update_l2_gw_service(self):
- display_name = 'fake-gateway'
- new_display_name = 'still-fake-gateway'
- node_uuid = _uuid()
- res1 = self._create_gw_service(node_uuid, display_name)
- gw_id = res1['uuid']
- res2 = l2gwlib.update_l2_gw_service(
- self.fake_cluster, gw_id, new_display_name)
- self.assertEqual(res2['display_name'], new_display_name)
-
- def test_get_l2_gw_service(self):
- display_name = 'fake-gateway'
- node_uuid = _uuid()
- gw_id = self._create_gw_service(node_uuid, display_name)['uuid']
- response = l2gwlib.get_l2_gw_service(self.fake_cluster, gw_id)
- self.assertEqual(response.get('type'), 'L2GatewayServiceConfig')
- self.assertEqual(response.get('display_name'), display_name)
- self.assertEqual(response.get('uuid'), gw_id)
-
- def test_list_l2_gw_service(self):
- gw_ids = []
- for name in ('fake-1', 'fake-2'):
- gw_ids.append(self._create_gw_service(_uuid(), name)['uuid'])
- results = l2gwlib.get_l2_gw_services(self.fake_cluster)
- self.assertEqual(len(results), 2)
- self.assertEqual(sorted(gw_ids), sorted([r['uuid'] for r in results]))
-
- def test_list_l2_gw_service_by_tenant(self):
- gw_ids = [self._create_gw_service(
- _uuid(), name, tenant_id=name)['uuid']
- for name in ('fake-1', 'fake-2')]
- results = l2gwlib.get_l2_gw_services(self.fake_cluster,
- tenant_id='fake-1')
- self.assertEqual(len(results), 1)
- self.assertEqual(results[0]['uuid'], gw_ids[0])
-
- def test_delete_l2_gw_service(self):
- display_name = 'fake-gateway'
- node_uuid = _uuid()
- gw_id = self._create_gw_service(node_uuid, display_name)['uuid']
- l2gwlib.delete_l2_gw_service(self.fake_cluster, gw_id)
- results = l2gwlib.get_l2_gw_services(self.fake_cluster)
- self.assertEqual(len(results), 0)
-
- def test_plug_l2_gw_port_attachment(self):
- tenant_id = 'pippo'
- node_uuid = _uuid()
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(
- self.fake_cluster, _uuid(), tenant_id,
- 'fake-switch', transport_zones_config)
- gw_id = self._create_gw_service(node_uuid, 'fake-gw')['uuid']
- lport = switchlib.create_lport(
- self.fake_cluster, lswitch['uuid'], tenant_id, _uuid(),
- 'fake-gw-port', gw_id, True)
- l2gwlib.plug_l2_gw_service(
- self.fake_cluster, lswitch['uuid'],
- lport['uuid'], gw_id)
- uri = nsxlib._build_uri_path(switchlib.LSWITCHPORT_RESOURCE,
- lport['uuid'],
- lswitch['uuid'],
- is_attachment=True)
- resp_obj = nsxlib.do_request("GET", uri,
- cluster=self.fake_cluster)
- self.assertIn('LogicalPortAttachment', resp_obj)
- self.assertEqual(resp_obj['LogicalPortAttachment']['type'],
- 'L2GatewayAttachment')
-
- def _create_expected_req_body(self, display_name, neutron_id,
- connector_type, connector_ip,
- client_certificate):
- body = {
- "display_name": display_name,
- "tags": [{"tag": neutron_id, "scope": "q_gw_dev_id"},
- {"tag": 'fake_tenant', "scope": "os_tid"},
- {"tag": nsx_utils.NEUTRON_VERSION,
- "scope": "quantum"}],
- "transport_connectors": [
- {"transport_zone_uuid": 'fake_tz_uuid',
- "ip_address": connector_ip,
- "type": '%sConnector' % connector_type}],
- "admin_status_enabled": True
- }
- body.get("tags").sort()
- if client_certificate:
- body["credential"] = {
- "client_certificate": {
- "pem_encoded": client_certificate},
- "type": "SecurityCertificateCredential"}
- return body
-
- def test_create_gw_device(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- display_name = 'fake-device'
- neutron_id = 'whatever'
- connector_type = 'stt'
- connector_ip = '1.1.1.1'
- client_certificate = 'this_should_be_a_certificate'
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- expected_req_body = self._create_expected_req_body(
- display_name, neutron_id, connector_type.upper(),
- connector_ip, client_certificate)
- l2gwlib.create_gateway_device(
- self.fake_cluster, 'fake_tenant', display_name, neutron_id,
- 'fake_tz_uuid', connector_type, connector_ip,
- client_certificate)
- request_mock.assert_called_once_with(
- "POST",
- "/ws.v1/transport-node",
- jsonutils.dumps(expected_req_body, sort_keys=True),
- cluster=self.fake_cluster)
-
- def test_update_gw_device(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- display_name = 'fake-device'
- neutron_id = 'whatever'
- connector_type = 'stt'
- connector_ip = '1.1.1.1'
- client_certificate = 'this_should_be_a_certificate'
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- expected_req_body = self._create_expected_req_body(
- display_name, neutron_id, connector_type.upper(),
- connector_ip, client_certificate)
- l2gwlib.update_gateway_device(
- self.fake_cluster, 'whatever', 'fake_tenant',
- display_name, neutron_id,
- 'fake_tz_uuid', connector_type, connector_ip,
- client_certificate)
-
- request_mock.assert_called_once_with(
- "PUT",
- "/ws.v1/transport-node/whatever",
- jsonutils.dumps(expected_req_body, sort_keys=True),
- cluster=self.fake_cluster)
-
- def test_update_gw_device_without_certificate(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- display_name = 'fake-device'
- neutron_id = 'whatever'
- connector_type = 'stt'
- connector_ip = '1.1.1.1'
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- expected_req_body = self._create_expected_req_body(
- display_name, neutron_id, connector_type.upper(),
- connector_ip, None)
- l2gwlib.update_gateway_device(
- self.fake_cluster, 'whatever', 'fake_tenant',
- display_name, neutron_id,
- 'fake_tz_uuid', connector_type, connector_ip,
- client_certificate=None)
-
- request_mock.assert_called_once_with(
- "PUT",
- "/ws.v1/transport-node/whatever",
- jsonutils.dumps(expected_req_body, sort_keys=True),
- cluster=self.fake_cluster)
-
- def test_get_gw_device_status(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- l2gwlib.get_gateway_device_status(self.fake_cluster, 'whatever')
- request_mock.assert_called_once_with(
- "GET",
- "/ws.v1/transport-node/whatever/status",
- cluster=self.fake_cluster)
-
- def test_get_gw_devices_status(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- request_mock.return_value = {
- 'results': [],
- 'page_cursor': None,
- 'result_count': 0}
- l2gwlib.get_gateway_devices_status(self.fake_cluster)
- request_mock.assert_called_once_with(
- "GET",
- ("/ws.v1/transport-node?fields=uuid,tags&"
- "relations=TransportNodeStatus&"
- "_page_length=1000&tag_scope=quantum"),
- cluster=self.fake_cluster)
-
- def test_get_gw_devices_status_filter_by_tenant(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- request_mock.return_value = {
- 'results': [],
- 'page_cursor': None,
- 'result_count': 0}
- l2gwlib.get_gateway_devices_status(self.fake_cluster,
- tenant_id='ssc_napoli')
- request_mock.assert_called_once_with(
- "GET",
- ("/ws.v1/transport-node?fields=uuid,tags&"
- "relations=TransportNodeStatus&"
- "tag=ssc_napoli&tag_scope=os_tid&"
- "_page_length=1000&tag_scope=quantum"),
- cluster=self.fake_cluster)
-
- def test_delete_gw_device(self):
- # NOTE(salv-orlando): This unit test mocks backend calls rather than
- # leveraging the fake NSX API client
- with mock.patch.object(nsxlib, 'do_request') as request_mock:
- l2gwlib.delete_gateway_device(self.fake_cluster, 'whatever')
- request_mock.assert_called_once_with(
- "DELETE",
- "/ws.v1/transport-node/whatever",
- cluster=self.fake_cluster)
+++ /dev/null
-# Copyright 2013 VMware, 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 mock
-from oslo_serialization import jsonutils
-
-from neutron.common import exceptions
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware.nsxlib import lsn as lsnlib
-from neutron.tests import base
-
-
-class LSNTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(LSNTestCase, self).setUp()
- self.mock_request_p = mock.patch(
- 'neutron.plugins.vmware.nsxlib.do_request')
- self.mock_request = self.mock_request_p.start()
- self.cluster = mock.Mock()
- self.cluster.default_service_cluster_uuid = 'foo'
-
- def test_service_cluster_None(self):
- self.mock_request.return_value = None
- expected = lsnlib.service_cluster_exists(None, None)
- self.assertFalse(expected)
-
- def test_service_cluster_found(self):
- self.mock_request.return_value = {
- "results": [
- {
- "_href": "/ws.v1/service-cluster/foo_uuid",
- "display_name": "foo_name",
- "uuid": "foo_uuid",
- "tags": [],
- "_schema": "/ws.v1/schema/ServiceClusterConfig",
- "gateways": []
- }
- ],
- "result_count": 1
- }
- expected = lsnlib.service_cluster_exists(None, 'foo_uuid')
- self.assertTrue(expected)
-
- def test_service_cluster_not_found(self):
- self.mock_request.side_effect = exceptions.NotFound()
- expected = lsnlib.service_cluster_exists(None, 'foo_uuid')
- self.assertFalse(expected)
-
- def test_lsn_for_network_create(self):
- net_id = "foo_network_id"
- tags = utils.get_tags(n_network_id=net_id)
- obj = {"edge_cluster_uuid": "foo", "tags": tags}
- lsnlib.lsn_for_network_create(self.cluster, net_id)
- self.mock_request.assert_called_once_with(
- "POST", "/ws.v1/lservices-node",
- jsonutils.dumps(obj), cluster=self.cluster)
-
- def test_lsn_for_network_get(self):
- net_id = "foo_network_id"
- lsn_id = "foo_lsn_id"
- self.mock_request.return_value = {
- "results": [{"uuid": "foo_lsn_id"}],
- "result_count": 1
- }
- result = lsnlib.lsn_for_network_get(self.cluster, net_id)
- self.assertEqual(lsn_id, result)
- self.mock_request.assert_called_once_with(
- "GET",
- ("/ws.v1/lservices-node?fields=uuid&tag=%s&"
- "tag_scope=n_network_id" % net_id),
- cluster=self.cluster)
-
- def test_lsn_for_network_get_none(self):
- net_id = "foo_network_id"
- self.mock_request.return_value = {
- "results": [{"uuid": "foo_lsn_id1"}, {"uuid": "foo_lsn_id2"}],
- "result_count": 2
- }
- result = lsnlib.lsn_for_network_get(self.cluster, net_id)
- self.assertIsNone(result)
-
- def test_lsn_for_network_get_raise_not_found(self):
- net_id = "foo_network_id"
- self.mock_request.return_value = {
- "results": [], "result_count": 0
- }
- self.assertRaises(exceptions.NotFound,
- lsnlib.lsn_for_network_get,
- self.cluster, net_id)
-
- def test_lsn_delete(self):
- lsn_id = "foo_id"
- lsnlib.lsn_delete(self.cluster, lsn_id)
- self.mock_request.assert_called_once_with(
- "DELETE",
- "/ws.v1/lservices-node/%s" % lsn_id, cluster=self.cluster)
-
- def _test_lsn_port_host_entries_update(self, lsn_type, hosts_data):
- lsn_id = 'foo_lsn_id'
- lsn_port_id = 'foo_lsn_port_id'
- lsnlib.lsn_port_host_entries_update(
- self.cluster, lsn_id, lsn_port_id, lsn_type, hosts_data)
- self.mock_request.assert_called_once_with(
- 'PUT',
- '/ws.v1/lservices-node/%s/lport/%s/%s' % (lsn_id,
- lsn_port_id,
- lsn_type),
- jsonutils.dumps({'hosts': hosts_data}),
- cluster=self.cluster)
-
- def test_lsn_port_dhcp_entries_update(self):
- hosts_data = [{"ip_address": "11.22.33.44",
- "mac_address": "aa:bb:cc:dd:ee:ff"},
- {"ip_address": "44.33.22.11",
- "mac_address": "ff:ee:dd:cc:bb:aa"}]
- self._test_lsn_port_host_entries_update("dhcp", hosts_data)
-
- def test_lsn_port_metadata_entries_update(self):
- hosts_data = [{"ip_address": "11.22.33.44",
- "device_id": "foo_vm_uuid"}]
- self._test_lsn_port_host_entries_update("metadata-proxy", hosts_data)
-
- def test_lsn_port_create(self):
- port_data = {
- "ip_address": "1.2.3.0/24",
- "mac_address": "aa:bb:cc:dd:ee:ff",
- "subnet_id": "foo_subnet_id"
- }
- port_id = "foo_port_id"
- self.mock_request.return_value = {"uuid": port_id}
- lsn_id = "foo_lsn_id"
- result = lsnlib.lsn_port_create(self.cluster, lsn_id, port_data)
- self.assertEqual(result, port_id)
- tags = utils.get_tags(n_subnet_id=port_data["subnet_id"],
- n_mac_address=port_data["mac_address"])
- port_obj = {
- "ip_address": port_data["ip_address"],
- "mac_address": port_data["mac_address"],
- "type": "LogicalServicesNodePortConfig",
- "tags": tags
- }
- self.mock_request.assert_called_once_with(
- "POST", "/ws.v1/lservices-node/%s/lport" % lsn_id,
- jsonutils.dumps(port_obj), cluster=self.cluster)
-
- def test_lsn_port_delete(self):
- lsn_id = "foo_lsn_id"
- lsn_port_id = "foo_port_id"
- lsnlib.lsn_port_delete(self.cluster, lsn_id, lsn_port_id)
- self.mock_request.assert_called_once_with(
- "DELETE",
- "/ws.v1/lservices-node/%s/lport/%s" % (lsn_id, lsn_port_id),
- cluster=self.cluster)
-
- def test_lsn_port_get_with_filters(self):
- lsn_id = "foo_lsn_id"
- port_id = "foo_port_id"
- filters = {"tag": "foo_tag", "tag_scope": "foo_scope"}
- self.mock_request.return_value = {
- "results": [{"uuid": port_id}],
- "result_count": 1
- }
- result = lsnlib._lsn_port_get(self.cluster, lsn_id, filters)
- self.assertEqual(result, port_id)
- self.mock_request.assert_called_once_with(
- "GET",
- ("/ws.v1/lservices-node/%s/lport?fields=uuid&tag=%s&"
- "tag_scope=%s" % (lsn_id, filters["tag"], filters["tag_scope"])),
- cluster=self.cluster)
-
- def test_lsn_port_get_with_filters_return_none(self):
- self.mock_request.return_value = {
- "results": [{"uuid": "foo1"}, {"uuid": "foo2"}],
- "result_count": 2
- }
- result = lsnlib._lsn_port_get(self.cluster, "lsn_id", None)
- self.assertIsNone(result)
-
- def test_lsn_port_get_with_filters_raises_not_found(self):
- self.mock_request.return_value = {"results": [], "result_count": 0}
- self.assertRaises(exceptions.NotFound,
- lsnlib._lsn_port_get,
- self.cluster, "lsn_id", None)
-
- def test_lsn_port_info_get(self):
- self.mock_request.return_value = {
- "tags": [
- {"scope": "n_mac_address", "tag": "fa:16:3e:27:fd:a0"},
- {"scope": "n_subnet_id", "tag": "foo_subnet_id"},
- ],
- "mac_address": "aa:bb:cc:dd:ee:ff",
- "ip_address": "0.0.0.0/0",
- "uuid": "foo_lsn_port_id"
- }
- result = lsnlib.lsn_port_info_get(
- self.cluster, 'foo_lsn_id', 'foo_lsn_port_id')
- self.mock_request.assert_called_once_with(
- 'GET', '/ws.v1/lservices-node/foo_lsn_id/lport/foo_lsn_port_id',
- cluster=self.cluster)
- self.assertIn('subnet_id', result)
- self.assertIn('mac_address', result)
-
- def test_lsn_port_info_get_raise_not_found(self):
- self.mock_request.side_effect = exceptions.NotFound
- self.assertRaises(exceptions.NotFound,
- lsnlib.lsn_port_info_get,
- self.cluster, mock.ANY, mock.ANY)
-
- def test_lsn_port_plug_network(self):
- lsn_id = "foo_lsn_id"
- lsn_port_id = "foo_lsn_port_id"
- lswitch_port_id = "foo_lswitch_port_id"
- lsnlib.lsn_port_plug_network(
- self.cluster, lsn_id, lsn_port_id, lswitch_port_id)
- self.mock_request.assert_called_once_with(
- "PUT",
- ("/ws.v1/lservices-node/%s/lport/%s/"
- "attachment") % (lsn_id, lsn_port_id),
- jsonutils.dumps({"peer_port_uuid": lswitch_port_id,
- "type": "PatchAttachment"}),
- cluster=self.cluster)
-
- def test_lsn_port_plug_network_raise_conflict(self):
- lsn_id = "foo_lsn_id"
- lsn_port_id = "foo_lsn_port_id"
- lswitch_port_id = "foo_lswitch_port_id"
- self.mock_request.side_effect = api_exc.Conflict
- self.assertRaises(
- nsx_exc.LsnConfigurationConflict,
- lsnlib.lsn_port_plug_network,
- self.cluster, lsn_id, lsn_port_id, lswitch_port_id)
-
- def _test_lsn_port_dhcp_configure(
- self, lsn_id, lsn_port_id, is_enabled, opts):
- lsnlib.lsn_port_dhcp_configure(
- self.cluster, lsn_id, lsn_port_id, is_enabled, opts)
- opt_array = [
- {"name": key, "value": val}
- for key, val in opts.iteritems()
- ]
- self.mock_request.assert_has_calls([
- mock.call("PUT", "/ws.v1/lservices-node/%s/dhcp" % lsn_id,
- jsonutils.dumps({"enabled": is_enabled}),
- cluster=self.cluster),
- mock.call("PUT",
- ("/ws.v1/lservices-node/%s/"
- "lport/%s/dhcp") % (lsn_id, lsn_port_id),
- jsonutils.dumps({"options": opt_array}),
- cluster=self.cluster)
- ])
-
- def test_lsn_port_dhcp_configure_empty_opts(self):
- lsn_id = "foo_lsn_id"
- lsn_port_id = "foo_lsn_port_id"
- is_enabled = False
- opts = {}
- self._test_lsn_port_dhcp_configure(
- lsn_id, lsn_port_id, is_enabled, opts)
-
- def test_lsn_port_dhcp_configure_with_opts(self):
- lsn_id = "foo_lsn_id"
- lsn_port_id = "foo_lsn_port_id"
- is_enabled = True
- opts = {"opt1": "val1", "opt2": "val2"}
- self._test_lsn_port_dhcp_configure(
- lsn_id, lsn_port_id, is_enabled, opts)
-
- def _test_lsn_metadata_configure(
- self, lsn_id, is_enabled, opts, expected_opts):
- lsnlib.lsn_metadata_configure(
- self.cluster, lsn_id, is_enabled, opts)
- lsn_obj = {"enabled": is_enabled}
- lsn_obj.update(expected_opts)
- self.mock_request.assert_has_calls([
- mock.call("PUT",
- "/ws.v1/lservices-node/%s/metadata-proxy" % lsn_id,
- jsonutils.dumps(lsn_obj),
- cluster=self.cluster),
- ])
-
- def test_lsn_port_metadata_configure_empty_secret(self):
- lsn_id = "foo_lsn_id"
- is_enabled = True
- opts = {
- "metadata_server_ip": "1.2.3.4",
- "metadata_server_port": "8775"
- }
- expected_opts = {
- "metadata_server_ip": "1.2.3.4",
- "metadata_server_port": "8775",
- }
- self._test_lsn_metadata_configure(
- lsn_id, is_enabled, opts, expected_opts)
-
- def test_lsn_metadata_configure_with_secret(self):
- lsn_id = "foo_lsn_id"
- is_enabled = True
- opts = {
- "metadata_server_ip": "1.2.3.4",
- "metadata_server_port": "8775",
- "metadata_proxy_shared_secret": "foo_secret"
- }
- expected_opts = {
- "metadata_server_ip": "1.2.3.4",
- "metadata_server_port": "8775",
- "options": [{
- "name": "metadata_proxy_shared_secret",
- "value": "foo_secret"
- }]
- }
- self._test_lsn_metadata_configure(
- lsn_id, is_enabled, opts, expected_opts)
-
- def _test_lsn_port_host_action(
- self, lsn_port_action_func, extra_action, action, host):
- lsn_id = "foo_lsn_id"
- lsn_port_id = "foo_lsn_port_id"
- lsn_port_action_func(self.cluster, lsn_id, lsn_port_id, host)
- self.mock_request.assert_called_once_with(
- "POST",
- ("/ws.v1/lservices-node/%s/lport/"
- "%s/%s?action=%s") % (lsn_id, lsn_port_id, extra_action, action),
- jsonutils.dumps(host), cluster=self.cluster)
-
- def test_lsn_port_dhcp_host_add(self):
- host = {
- "ip_address": "1.2.3.4",
- "mac_address": "aa:bb:cc:dd:ee:ff"
- }
- self._test_lsn_port_host_action(
- lsnlib.lsn_port_dhcp_host_add, "dhcp", "add_host", host)
-
- def test_lsn_port_dhcp_host_remove(self):
- host = {
- "ip_address": "1.2.3.4",
- "mac_address": "aa:bb:cc:dd:ee:ff"
- }
- self._test_lsn_port_host_action(
- lsnlib.lsn_port_dhcp_host_remove, "dhcp", "remove_host", host)
-
- def test_lsn_port_metadata_host_add(self):
- host = {
- "ip_address": "1.2.3.4",
- "instance_id": "foo_instance_id"
- }
- self._test_lsn_port_host_action(lsnlib.lsn_port_metadata_host_add,
- "metadata-proxy", "add_host", host)
-
- def test_lsn_port_metadata_host_remove(self):
- host = {
- "ip_address": "1.2.3.4",
- "instance_id": "foo_instance_id"
- }
- self._test_lsn_port_host_action(lsnlib.lsn_port_metadata_host_remove,
- "metadata-proxy", "remove_host", host)
+++ /dev/null
-# Copyright (c) 2014 VMware, 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 mock
-
-from neutron.common import exceptions
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import queue as queuelib
-from neutron.tests.unit.vmware.nsxlib import base
-
-
-class TestLogicalQueueLib(base.NsxlibTestCase):
-
- def setUp(self):
- super(TestLogicalQueueLib, self).setUp()
- self.fake_queue = {
- 'name': 'fake_queue',
- 'min': 0, 'max': 256,
- 'dscp': 0, 'qos_marking': False
- }
-
- def test_create_and_get_lqueue(self):
- queue_id = queuelib.create_lqueue(
- self.fake_cluster, self.fake_queue)
- queue_res = nsxlib.do_request(
- 'GET',
- nsxlib._build_uri_path('lqueue', resource_id=queue_id),
- cluster=self.fake_cluster)
- self.assertEqual(queue_id, queue_res['uuid'])
- self.assertEqual('fake_queue', queue_res['display_name'])
-
- def test_create_lqueue_nsx_error_raises(self):
- def raise_nsx_exc(*args, **kwargs):
- raise api_exc.NsxApiException()
-
- with mock.patch.object(nsxlib, 'do_request', new=raise_nsx_exc):
- self.assertRaises(
- exceptions.NeutronException, queuelib.create_lqueue,
- self.fake_cluster, self.fake_queue)
-
- def test_delete_lqueue(self):
- queue_id = queuelib.create_lqueue(
- self.fake_cluster, self.fake_queue)
- queuelib.delete_lqueue(self.fake_cluster, queue_id)
- self.assertRaises(exceptions.NotFound,
- nsxlib.do_request,
- 'GET',
- nsxlib._build_uri_path(
- 'lqueue', resource_id=queue_id),
- cluster=self.fake_cluster)
-
- def test_delete_non_existing_lqueue_raises(self):
- self.assertRaises(exceptions.NeutronException,
- queuelib.delete_lqueue,
- self.fake_cluster, 'whatever')
+++ /dev/null
-# Copyright (c) 2014 VMware, 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 mock
-
-from oslo_config import cfg
-
-from neutron.common import exceptions
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.api_client import version as version_module
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import router as routerlib
-from neutron.plugins.vmware.nsxlib import switch as switchlib
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit.vmware.nsxlib import base
-
-_uuid = test_api_v2._uuid
-
-
-class TestNatRules(base.NsxlibTestCase):
-
- def _test_create_lrouter_dnat_rule(self, version):
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- new=lambda: version_module.Version(version)):
- tenant_id = 'pippo'
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- tenant_id,
- 'fake_router',
- '192.168.0.1')
- nat_rule = routerlib.create_lrouter_dnat_rule(
- self.fake_cluster, lrouter['uuid'], '10.0.0.99',
- match_criteria={'destination_ip_addresses':
- '192.168.0.5'})
- uri = nsxlib._build_uri_path(routerlib.LROUTERNAT_RESOURCE,
- nat_rule['uuid'],
- lrouter['uuid'])
- resp_obj = nsxlib.do_request("GET", uri, cluster=self.fake_cluster)
- self.assertEqual('DestinationNatRule', resp_obj['type'])
- self.assertEqual('192.168.0.5',
- resp_obj['match']['destination_ip_addresses'])
-
- def test_create_lrouter_dnat_rule_v2(self):
- self._test_create_lrouter_dnat_rule('2.9')
-
- def test_create_lrouter_dnat_rule_v31(self):
- self._test_create_lrouter_dnat_rule('3.1')
-
-
-class TestExplicitLRouters(base.NsxlibTestCase):
-
- def setUp(self):
- self.fake_version = '3.2'
- super(TestExplicitLRouters, self).setUp()
-
- def _get_lrouter(self, tenant_id, router_name, router_id, relations=None):
- schema = '/ws.v1/schema/RoutingTableRoutingConfig'
-
- router = {'display_name': router_name,
- 'uuid': router_id,
- 'tags': utils.get_tags(os_tid=tenant_id),
- 'distributed': False,
- 'routing_config': {'type': 'RoutingTableRoutingConfig',
- '_schema': schema},
- '_schema': schema,
- 'nat_synchronization_enabled': True,
- 'replication_mode': 'service',
- 'type': 'LogicalRouterConfig',
- '_href': '/ws.v1/lrouter/%s' % router_id, }
- if relations:
- router['_relations'] = relations
- return router
-
- def _get_single_route(self, router_id, route_id='fake_route_id_0',
- prefix='0.0.0.0/0', next_hop_ip='1.1.1.1'):
- return {'protocol': 'static',
- '_href': '/ws.v1/lrouter/%s/rib/%s' % (router_id, route_id),
- 'prefix': prefix,
- '_schema': '/ws.v1/schema/RoutingTableEntry',
- 'next_hop_ip': next_hop_ip,
- 'action': 'accept',
- 'uuid': route_id}
-
- def test_prepare_body_with_implicit_routing_config(self):
- router_name = 'fake_router_name'
- tenant_id = 'fake_tenant_id'
- neutron_router_id = 'pipita_higuain'
- router_type = 'SingleDefaultRouteImplicitRoutingConfig'
- route_config = {
- 'default_route_next_hop': {'gateway_ip_address': 'fake_address',
- 'type': 'RouterNextHop'}, }
- body = routerlib._prepare_lrouter_body(router_name, neutron_router_id,
- tenant_id, router_type,
- **route_config)
- expected = {'display_name': 'fake_router_name',
- 'routing_config': {
- 'default_route_next_hop':
- {'gateway_ip_address': 'fake_address',
- 'type': 'RouterNextHop'},
- 'type': 'SingleDefaultRouteImplicitRoutingConfig'},
- 'tags': utils.get_tags(os_tid='fake_tenant_id',
- q_router_id='pipita_higuain'),
- 'type': 'LogicalRouterConfig',
- 'replication_mode': cfg.CONF.NSX.replication_mode}
- self.assertEqual(expected, body)
-
- def test_prepare_body_without_routing_config(self):
- router_name = 'fake_router_name'
- tenant_id = 'fake_tenant_id'
- neutron_router_id = 'marekiaro_hamsik'
- router_type = 'RoutingTableRoutingConfig'
- body = routerlib._prepare_lrouter_body(router_name, neutron_router_id,
- tenant_id, router_type)
- expected = {'display_name': 'fake_router_name',
- 'routing_config': {'type': 'RoutingTableRoutingConfig'},
- 'tags': utils.get_tags(os_tid='fake_tenant_id',
- q_router_id='marekiaro_hamsik'),
- 'type': 'LogicalRouterConfig',
- 'replication_mode': cfg.CONF.NSX.replication_mode}
- self.assertEqual(expected, body)
-
- def test_get_lrouter(self):
- tenant_id = 'fake_tenant_id'
- router_name = 'fake_router_name'
- router_id = 'fake_router_id'
- relations = {
- 'LogicalRouterStatus':
- {'_href': '/ws.v1/lrouter/%s/status' % router_id,
- 'lport_admin_up_count': 1,
- '_schema': '/ws.v1/schema/LogicalRouterStatus',
- 'lport_count': 1,
- 'fabric_status': True,
- 'type': 'LogicalRouterStatus',
- 'lport_link_up_count': 0, }, }
-
- with mock.patch.object(nsxlib, 'do_request',
- return_value=self._get_lrouter(tenant_id,
- router_name,
- router_id,
- relations)):
- lrouter = routerlib.get_lrouter(self.fake_cluster, router_id)
- self.assertTrue(
- lrouter['_relations']['LogicalRouterStatus']['fabric_status'])
-
- def test_create_lrouter(self):
- tenant_id = 'fake_tenant_id'
- router_name = 'fake_router_name'
- router_id = 'fake_router_id'
- nexthop_ip = '10.0.0.1'
- with mock.patch.object(
- nsxlib, 'do_request',
- return_value=self._get_lrouter(tenant_id,
- router_name,
- router_id)):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- tenant_id,
- router_name, nexthop_ip)
- self.assertEqual(lrouter['routing_config']['type'],
- 'RoutingTableRoutingConfig')
- self.assertNotIn('default_route_next_hop',
- lrouter['routing_config'])
-
- def test_update_lrouter_with_no_routes(self):
- router_id = 'fake_router_id'
- new_routes = [{"nexthop": "10.0.0.2",
- "destination": "169.254.169.0/30"}, ]
-
- nsx_routes = [self._get_single_route(router_id)]
- with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
- return_value=nsx_routes):
- with mock.patch.object(routerlib, 'create_explicit_route_lrouter',
- return_value='fake_uuid'):
- old_routes = routerlib.update_explicit_routes_lrouter(
- self.fake_cluster, router_id, new_routes)
- self.assertEqual(old_routes, nsx_routes)
-
- def test_update_lrouter_with_no_routes_raise_nsx_exception(self):
- router_id = 'fake_router_id'
- new_routes = [{"nexthop": "10.0.0.2",
- "destination": "169.254.169.0/30"}, ]
-
- nsx_routes = [self._get_single_route(router_id)]
- with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
- return_value=nsx_routes):
- with mock.patch.object(routerlib, 'create_explicit_route_lrouter',
- side_effect=api_exc.NsxApiException):
- self.assertRaises(api_exc.NsxApiException,
- routerlib.update_explicit_routes_lrouter,
- self.fake_cluster, router_id, new_routes)
-
- def test_update_lrouter_with_routes(self):
- router_id = 'fake_router_id'
- new_routes = [{"next_hop_ip": "10.0.0.2",
- "prefix": "169.254.169.0/30"}, ]
-
- nsx_routes = [self._get_single_route(router_id),
- self._get_single_route(router_id, 'fake_route_id_1',
- '0.0.0.1/24', '10.0.0.3'),
- self._get_single_route(router_id, 'fake_route_id_2',
- '0.0.0.2/24', '10.0.0.4'), ]
-
- with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
- return_value=nsx_routes):
- with mock.patch.object(routerlib, 'delete_explicit_route_lrouter',
- return_value=None):
- with mock.patch.object(routerlib,
- 'create_explicit_route_lrouter',
- return_value='fake_uuid'):
- old_routes = routerlib.update_explicit_routes_lrouter(
- self.fake_cluster, router_id, new_routes)
- self.assertEqual(old_routes, nsx_routes)
-
- def test_update_lrouter_with_routes_raises_nsx_expception(self):
- router_id = 'fake_router_id'
- new_routes = [{"nexthop": "10.0.0.2",
- "destination": "169.254.169.0/30"}, ]
-
- nsx_routes = [self._get_single_route(router_id),
- self._get_single_route(router_id, 'fake_route_id_1',
- '0.0.0.1/24', '10.0.0.3'),
- self._get_single_route(router_id, 'fake_route_id_2',
- '0.0.0.2/24', '10.0.0.4'), ]
-
- with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
- return_value=nsx_routes):
- with mock.patch.object(routerlib, 'delete_explicit_route_lrouter',
- side_effect=api_exc.NsxApiException):
- with mock.patch.object(
- routerlib, 'create_explicit_route_lrouter',
- return_value='fake_uuid'):
- self.assertRaises(
- api_exc.NsxApiException,
- routerlib.update_explicit_routes_lrouter,
- self.fake_cluster, router_id, new_routes)
-
-
-class RouterNegativeTestCase(base.NsxlibNegativeBaseTestCase):
-
- def test_create_lrouter_on_failure(self):
- self.assertRaises(api_exc.NsxApiException,
- routerlib.create_lrouter,
- self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pluto',
- 'fake_router',
- 'my_hop')
-
- def test_delete_lrouter_on_failure(self):
- self.assertRaises(api_exc.NsxApiException,
- routerlib.delete_lrouter,
- self.fake_cluster,
- 'fake_router')
-
- def test_get_lrouter_on_failure(self):
- self.assertRaises(api_exc.NsxApiException,
- routerlib.get_lrouter,
- self.fake_cluster,
- 'fake_router')
-
- def test_update_lrouter_on_failure(self):
- self.assertRaises(api_exc.NsxApiException,
- routerlib.update_lrouter,
- self.fake_cluster,
- 'fake_router',
- 'pluto',
- 'new_hop')
-
-
-class TestLogicalRouters(base.NsxlibTestCase):
-
- def _verify_lrouter(self, res_lrouter,
- expected_uuid,
- expected_display_name,
- expected_nexthop,
- expected_tenant_id,
- expected_neutron_id=None,
- expected_distributed=None):
- self.assertEqual(res_lrouter['uuid'], expected_uuid)
- nexthop = (res_lrouter['routing_config']
- ['default_route_next_hop']['gateway_ip_address'])
- self.assertEqual(nexthop, expected_nexthop)
- router_tags = self._build_tag_dict(res_lrouter['tags'])
- self.assertIn('os_tid', router_tags)
- self.assertEqual(res_lrouter['display_name'], expected_display_name)
- self.assertEqual(expected_tenant_id, router_tags['os_tid'])
- if expected_distributed is not None:
- self.assertEqual(expected_distributed,
- res_lrouter['distributed'])
- if expected_neutron_id:
- self.assertIn('q_router_id', router_tags)
- self.assertEqual(expected_neutron_id, router_tags['q_router_id'])
-
- def test_get_lrouters(self):
- lrouter_uuids = [routerlib.create_lrouter(
- self.fake_cluster, 'whatever', 'pippo', 'fake-lrouter-%s' % k,
- '10.0.0.1')['uuid'] for k in range(3)]
- routers = routerlib.get_lrouters(self.fake_cluster, 'pippo')
- for router in routers:
- self.assertIn(router['uuid'], lrouter_uuids)
-
- def _create_lrouter(self, version, neutron_id=None, distributed=None):
- with mock.patch.object(
- self.fake_cluster.api_client, 'get_version',
- return_value=version_module.Version(version)):
- if not neutron_id:
- neutron_id = uuidutils.generate_uuid()
- lrouter = routerlib.create_lrouter(
- self.fake_cluster, neutron_id, 'pippo',
- 'fake-lrouter', '10.0.0.1', distributed=distributed)
- return routerlib.get_lrouter(self.fake_cluster,
- lrouter['uuid'])
-
- def test_create_and_get_lrouter_v30(self):
- neutron_id = uuidutils.generate_uuid()
- res_lrouter = self._create_lrouter('3.0', neutron_id=neutron_id)
- self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
- 'fake-lrouter', '10.0.0.1', 'pippo',
- expected_neutron_id=neutron_id)
-
- def test_create_and_get_lrouter_v31_centralized(self):
- neutron_id = uuidutils.generate_uuid()
- res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
- distributed=False)
- self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
- 'fake-lrouter', '10.0.0.1', 'pippo',
- expected_neutron_id=neutron_id,
- expected_distributed=False)
-
- def test_create_and_get_lrouter_v31_distributed(self):
- neutron_id = uuidutils.generate_uuid()
- res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
- distributed=True)
- self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
- 'fake-lrouter', '10.0.0.1', 'pippo',
- expected_neutron_id=neutron_id,
- expected_distributed=True)
-
- def test_create_and_get_lrouter_name_exceeds_40chars(self):
- neutron_id = uuidutils.generate_uuid()
- display_name = '*' * 50
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- neutron_id,
- 'pippo',
- display_name,
- '10.0.0.1')
- res_lrouter = routerlib.get_lrouter(self.fake_cluster,
- lrouter['uuid'])
- self._verify_lrouter(res_lrouter, lrouter['uuid'],
- '*' * 40, '10.0.0.1', 'pippo',
- expected_neutron_id=neutron_id)
-
- def _test_version_dependent_update_lrouter(self, version):
- def foo(*args, **kwargs):
- return version
-
- foo_func_dict = {
- 'update_lrouter': {
- 2: {-1: foo},
- 3: {-1: foo, 2: foo}
- }
- }
-
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- return_value=version_module.Version(version)):
- with mock.patch.dict(routerlib.ROUTER_FUNC_DICT,
- foo_func_dict, clear=True):
- return routerlib.update_lrouter(
- self.fake_cluster, 'foo_router_id', 'foo_router_name',
- 'foo_nexthop', routes={'foo_destination': 'foo_address'})
-
- def test_version_dependent_update_lrouter_old_versions(self):
- self.assertRaises(nsx_exc.InvalidVersion,
- self._test_version_dependent_update_lrouter,
- "2.9")
- self.assertRaises(nsx_exc.InvalidVersion,
- self._test_version_dependent_update_lrouter,
- "3.0")
- self.assertRaises(nsx_exc.InvalidVersion,
- self._test_version_dependent_update_lrouter,
- "3.1")
-
- def test_version_dependent_update_lrouter_new_versions(self):
- self.assertEqual("3.2",
- self._test_version_dependent_update_lrouter("3.2"))
- self.assertEqual("4.0",
- self._test_version_dependent_update_lrouter("4.0"))
- self.assertEqual("4.1",
- self._test_version_dependent_update_lrouter("4.1"))
-
- def test_update_lrouter_no_nexthop(self):
- neutron_id = uuidutils.generate_uuid()
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- neutron_id,
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter = routerlib.update_lrouter(self.fake_cluster,
- lrouter['uuid'],
- 'new_name',
- None)
- res_lrouter = routerlib.get_lrouter(self.fake_cluster,
- lrouter['uuid'])
- self._verify_lrouter(res_lrouter, lrouter['uuid'],
- 'new_name', '10.0.0.1', 'pippo',
- expected_neutron_id=neutron_id)
-
- def test_update_lrouter(self):
- neutron_id = uuidutils.generate_uuid()
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- neutron_id,
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter = routerlib.update_lrouter(self.fake_cluster,
- lrouter['uuid'],
- 'new_name',
- '192.168.0.1')
- res_lrouter = routerlib.get_lrouter(self.fake_cluster,
- lrouter['uuid'])
- self._verify_lrouter(res_lrouter, lrouter['uuid'],
- 'new_name', '192.168.0.1', 'pippo',
- expected_neutron_id=neutron_id)
-
- def test_update_nonexistent_lrouter_raises(self):
- self.assertRaises(exceptions.NotFound,
- routerlib.update_lrouter,
- self.fake_cluster,
- 'whatever',
- 'foo', '9.9.9.9')
-
- def test_delete_lrouter(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- routerlib.delete_lrouter(self.fake_cluster, lrouter['uuid'])
- self.assertRaises(exceptions.NotFound,
- routerlib.get_lrouter,
- self.fake_cluster,
- lrouter['uuid'])
-
- def test_query_lrouter_ports(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- router_port_uuids = [routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo',
- 'qp_id_%s' % k, 'port-%s' % k, True,
- ['192.168.0.%s' % k], '00:11:22:33:44:55')['uuid']
- for k in range(3)]
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 3)
- for res_port in ports:
- self.assertIn(res_port['uuid'], router_port_uuids)
-
- def test_query_lrouter_lports_nonexistent_lrouter_raises(self):
- self.assertRaises(
- exceptions.NotFound, routerlib.create_router_lport,
- self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-
- def test_create_and_get_lrouter_port(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 1)
- res_port = ports[0]
- port_tags = self._build_tag_dict(res_port['tags'])
- self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
- self.assertIn('os_tid', port_tags)
- self.assertIn('q_port_id', port_tags)
- self.assertEqual('pippo', port_tags['os_tid'])
- self.assertEqual('neutron_port_id', port_tags['q_port_id'])
-
- def test_create_lrouter_port_nonexistent_router_raises(self):
- self.assertRaises(
- exceptions.NotFound, routerlib.create_router_lport,
- self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-
- def test_update_lrouter_port(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
- routerlib.update_router_lport(
- self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
- 'pippo', 'another_port_id', 'name', False,
- ['192.168.0.1', '10.10.10.254'])
-
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 1)
- res_port = ports[0]
- port_tags = self._build_tag_dict(res_port['tags'])
- self.assertEqual(['192.168.0.1', '10.10.10.254'],
- res_port['ip_addresses'])
- self.assertEqual('False', res_port['admin_status_enabled'])
- self.assertIn('os_tid', port_tags)
- self.assertIn('q_port_id', port_tags)
- self.assertEqual('pippo', port_tags['os_tid'])
- self.assertEqual('another_port_id', port_tags['q_port_id'])
-
- def test_update_lrouter_port_nonexistent_router_raises(self):
- self.assertRaises(
- exceptions.NotFound, routerlib.update_router_lport,
- self.fake_cluster, 'boo-router', 'boo-port', 'pippo',
- 'neutron_port_id', 'name', True, ['192.168.0.1'])
-
- def test_update_lrouter_port_nonexistent_port_raises(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- self.assertRaises(
- exceptions.NotFound, routerlib.update_router_lport,
- self.fake_cluster, lrouter['uuid'], 'boo-port', 'pippo',
- 'neutron_port_id', 'name', True, ['192.168.0.1'])
-
- def test_delete_lrouter_port(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
- '00:11:22:33:44:55')
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 1)
- routerlib.delete_router_lport(self.fake_cluster, lrouter['uuid'],
- lrouter_port['uuid'])
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertFalse(len(ports))
-
- def test_delete_lrouter_port_nonexistent_router_raises(self):
- self.assertRaises(exceptions.NotFound,
- routerlib.delete_router_lport,
- self.fake_cluster, 'xyz', 'abc')
-
- def test_delete_lrouter_port_nonexistent_port_raises(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- self.assertRaises(exceptions.NotFound,
- routerlib.delete_router_lport,
- self.fake_cluster, lrouter['uuid'], 'abc')
-
- def test_delete_peer_lrouter_port(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
- '00:11:22:33:44:55')
-
- def fakegetport(*args, **kwargs):
- return {'_relations': {'LogicalPortAttachment':
- {'peer_port_uuid': lrouter_port['uuid']}}}
- # mock get_port
- with mock.patch.object(switchlib, 'get_port', new=fakegetport):
- routerlib.delete_peer_router_lport(self.fake_cluster,
- lrouter_port['uuid'],
- 'whatwever', 'whatever')
-
- def test_update_lrouter_port_ips_add_only(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
- routerlib.update_lrouter_port_ips(
- self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
- ['10.10.10.254'], [])
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 1)
- res_port = ports[0]
- self.assertEqual(['10.10.10.254', '192.168.0.1'],
- res_port['ip_addresses'])
-
- def test_update_lrouter_port_ips_remove_only(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1', '10.10.10.254'],
- '00:11:22:33:44:55')
- routerlib.update_lrouter_port_ips(
- self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
- [], ['10.10.10.254'])
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 1)
- res_port = ports[0]
- self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
-
- def test_update_lrouter_port_ips_add_and_remove(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
- routerlib.update_lrouter_port_ips(
- self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
- ['10.10.10.254'], ['192.168.0.1'])
- ports = routerlib.query_lrouter_lports(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(ports), 1)
- res_port = ports[0]
- self.assertEqual(['10.10.10.254'], res_port['ip_addresses'])
-
- def test_update_lrouter_port_ips_nonexistent_router_raises(self):
- self.assertRaises(
- nsx_exc.NsxPluginException, routerlib.update_lrouter_port_ips,
- self.fake_cluster, 'boo-router', 'boo-port', [], [])
-
- def test_update_lrouter_port_ips_nsx_exception_raises(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-
- def raise_nsx_exc(*args, **kwargs):
- raise api_exc.NsxApiException()
-
- with mock.patch.object(nsxlib, 'do_request', new=raise_nsx_exc):
- self.assertRaises(
- nsx_exc.NsxPluginException, routerlib.update_lrouter_port_ips,
- self.fake_cluster, lrouter['uuid'],
- lrouter_port['uuid'], [], [])
-
- def test_plug_lrouter_port_patch_attachment(self):
- tenant_id = 'pippo'
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(self.fake_cluster,
- _uuid(),
- tenant_id, 'fake-switch',
- transport_zones_config)
- lport = switchlib.create_lport(self.fake_cluster, lswitch['uuid'],
- tenant_id, 'xyz',
- 'name', 'device_id', True)
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- tenant_id,
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
- result = routerlib.plug_router_port_attachment(
- self.fake_cluster, lrouter['uuid'],
- lrouter_port['uuid'],
- lport['uuid'], 'PatchAttachment')
- self.assertEqual(lport['uuid'],
- result['LogicalPortAttachment']['peer_port_uuid'])
-
- def test_plug_lrouter_port_l3_gw_attachment(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
- result = routerlib.plug_router_port_attachment(
- self.fake_cluster, lrouter['uuid'],
- lrouter_port['uuid'],
- 'gw_att', 'L3GatewayAttachment')
- self.assertEqual(
- 'gw_att',
- result['LogicalPortAttachment']['l3_gateway_service_uuid'])
-
- def test_plug_lrouter_port_l3_gw_attachment_with_vlan(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
- result = routerlib.plug_router_port_attachment(
- self.fake_cluster, lrouter['uuid'],
- lrouter_port['uuid'],
- 'gw_att', 'L3GatewayAttachment', 123)
- self.assertEqual(
- 'gw_att',
- result['LogicalPortAttachment']['l3_gateway_service_uuid'])
- self.assertEqual(
- '123',
- result['LogicalPortAttachment']['vlan_id'])
-
- def test_plug_lrouter_port_invalid_attachment_type_raises(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- lrouter_port = routerlib.create_router_lport(
- self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
- 'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
- self.assertRaises(nsx_exc.InvalidAttachmentType,
- routerlib.plug_router_port_attachment,
- self.fake_cluster, lrouter['uuid'],
- lrouter_port['uuid'], 'gw_att', 'BadType')
-
- def _test_create_router_snat_rule(self, version):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- new=lambda: version_module.Version(version)):
- routerlib.create_lrouter_snat_rule(
- self.fake_cluster, lrouter['uuid'],
- '10.0.0.2', '10.0.0.2', order=200,
- match_criteria={'source_ip_addresses': '192.168.0.24'})
- rules = routerlib.query_nat_rules(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 1)
-
- def test_create_router_snat_rule_v3(self):
- self._test_create_router_snat_rule('3.0')
-
- def test_create_router_snat_rule_v2(self):
- self._test_create_router_snat_rule('2.0')
-
- def _test_create_router_dnat_rule(self, version, dest_port=None):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- return_value=version_module.Version(version)):
- routerlib.create_lrouter_dnat_rule(
- self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
- dest_port=dest_port,
- match_criteria={'destination_ip_addresses': '10.0.0.3'})
- rules = routerlib.query_nat_rules(
- self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 1)
-
- def test_create_router_dnat_rule_v3(self):
- self._test_create_router_dnat_rule('3.0')
-
- def test_create_router_dnat_rule_v2(self):
- self._test_create_router_dnat_rule('2.0')
-
- def test_create_router_dnat_rule_v2_with_destination_port(self):
- self._test_create_router_dnat_rule('2.0', 8080)
-
- def test_create_router_dnat_rule_v3_with_destination_port(self):
- self._test_create_router_dnat_rule('3.0', 8080)
-
- def test_create_router_snat_rule_invalid_match_keys_raises(self):
- # In this case the version does not make a difference
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
-
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- new=lambda: '2.0'):
- self.assertRaises(AttributeError,
- routerlib.create_lrouter_snat_rule,
- self.fake_cluster, lrouter['uuid'],
- '10.0.0.2', '10.0.0.2', order=200,
- match_criteria={'foo': 'bar'})
-
- def _test_create_router_nosnat_rule(self, version, expected=1):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- new=lambda: version_module.Version(version)):
- routerlib.create_lrouter_nosnat_rule(
- self.fake_cluster, lrouter['uuid'],
- order=100,
- match_criteria={'destination_ip_addresses': '192.168.0.0/24'})
- rules = routerlib.query_nat_rules(
- self.fake_cluster, lrouter['uuid'])
- # NoSNAT rules do not exist in V2
- self.assertEqual(len(rules), expected)
-
- def test_create_router_nosnat_rule_v2(self):
- self._test_create_router_nosnat_rule('2.0', expected=0)
-
- def test_create_router_nosnat_rule_v3(self):
- self._test_create_router_nosnat_rule('3.0')
-
- def _prepare_nat_rules_for_delete_tests(self):
- lrouter = routerlib.create_lrouter(self.fake_cluster,
- uuidutils.generate_uuid(),
- 'pippo',
- 'fake-lrouter',
- '10.0.0.1')
- # v2 or v3 makes no difference for this test
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- new=lambda: version_module.Version('2.0')):
- routerlib.create_lrouter_snat_rule(
- self.fake_cluster, lrouter['uuid'],
- '10.0.0.2', '10.0.0.2', order=220,
- match_criteria={'source_ip_addresses': '192.168.0.0/24'})
- routerlib.create_lrouter_snat_rule(
- self.fake_cluster, lrouter['uuid'],
- '10.0.0.3', '10.0.0.3', order=200,
- match_criteria={'source_ip_addresses': '192.168.0.2/32'})
- routerlib.create_lrouter_dnat_rule(
- self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
- match_criteria={'destination_ip_addresses': '10.0.0.3'})
- return lrouter
-
- def test_delete_router_nat_rules_by_match_on_destination_ip(self):
- lrouter = self._prepare_nat_rules_for_delete_tests()
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
- routerlib.delete_nat_rules_by_match(
- self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 1, 1,
- destination_ip_addresses='10.0.0.3')
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 2)
-
- def test_delete_router_nat_rules_by_match_on_source_ip(self):
- lrouter = self._prepare_nat_rules_for_delete_tests()
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
- routerlib.delete_nat_rules_by_match(
- self.fake_cluster, lrouter['uuid'], 'SourceNatRule', 1, 1,
- source_ip_addresses='192.168.0.2/32')
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 2)
-
- def test_delete_router_nat_rules_by_match_no_match_expected(self):
- lrouter = self._prepare_nat_rules_for_delete_tests()
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
- routerlib.delete_nat_rules_by_match(
- self.fake_cluster, lrouter['uuid'], 'SomeWeirdType', 0)
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
- routerlib.delete_nat_rules_by_match(
- self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 0,
- destination_ip_addresses='99.99.99.99')
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
-
- def test_delete_router_nat_rules_by_match_no_match_raises(self):
- lrouter = self._prepare_nat_rules_for_delete_tests()
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
- self.assertRaises(
- nsx_exc.NatRuleMismatch,
- routerlib.delete_nat_rules_by_match,
- self.fake_cluster, lrouter['uuid'],
- 'SomeWeirdType', 1, 1)
-
- def test_delete_nat_rules_by_match_len_mismatch_does_not_raise(self):
- lrouter = self._prepare_nat_rules_for_delete_tests()
- rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
- self.assertEqual(len(rules), 3)
- deleted_rules = routerlib.delete_nat_rules_by_match(
- self.fake_cluster, lrouter['uuid'],
- 'DestinationNatRule',
- max_num_expected=1, min_num_expected=1,
- raise_on_len_mismatch=False,
- destination_ip_addresses='99.99.99.99')
- self.assertEqual(0, deleted_rules)
- # add an extra rule to emulate a duplicate one
- with mock.patch.object(self.fake_cluster.api_client,
- 'get_version',
- new=lambda: version_module.Version('2.0')):
- routerlib.create_lrouter_snat_rule(
- self.fake_cluster, lrouter['uuid'],
- '10.0.0.2', '10.0.0.2', order=220,
- match_criteria={'source_ip_addresses': '192.168.0.0/24'})
- deleted_rules_2 = routerlib.delete_nat_rules_by_match(
- self.fake_cluster, lrouter['uuid'], 'SourceNatRule',
- min_num_expected=1, max_num_expected=1,
- raise_on_len_mismatch=False,
- source_ip_addresses='192.168.0.0/24')
- self.assertEqual(2, deleted_rules_2)
+++ /dev/null
-# Copyright (c) 2014 VMware, 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.
-#
-
-from neutron.common import exceptions
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware.nsxlib import secgroup as secgrouplib
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit.vmware.nsxlib import base
-
-_uuid = test_api_v2._uuid
-
-
-class SecurityProfileTestCase(base.NsxlibTestCase):
-
- def test_create_and_get_security_profile(self):
- sec_prof = secgrouplib.create_security_profile(
- self.fake_cluster, _uuid(), 'pippo', {'name': 'test'})
- sec_prof_res = nsxlib.do_request(
- secgrouplib.HTTP_GET,
- nsxlib._build_uri_path('security-profile',
- resource_id=sec_prof['uuid']),
- cluster=self.fake_cluster)
- self.assertEqual(sec_prof['uuid'], sec_prof_res['uuid'])
- # Check for builtin rules
- self.assertEqual(len(sec_prof_res['logical_port_egress_rules']), 1)
- self.assertEqual(len(sec_prof_res['logical_port_ingress_rules']), 2)
-
- def test_create_and_get_default_security_profile(self):
- sec_prof = secgrouplib.create_security_profile(
- self.fake_cluster, _uuid(), 'pippo', {'name': 'default'})
- sec_prof_res = nsxlib.do_request(
- secgrouplib.HTTP_GET,
- nsxlib._build_uri_path('security-profile',
- resource_id=sec_prof['uuid']),
- cluster=self.fake_cluster)
- self.assertEqual(sec_prof['uuid'], sec_prof_res['uuid'])
- # Check for builtin rules
- self.assertEqual(len(sec_prof_res['logical_port_egress_rules']), 3)
- self.assertEqual(len(sec_prof_res['logical_port_ingress_rules']), 2)
-
- def test_update_security_profile_raise_not_found(self):
- self.assertRaises(exceptions.NotFound,
- secgrouplib.update_security_profile,
- self.fake_cluster,
- _uuid(), 'tatore_magno(the great)')
-
- def test_update_security_profile(self):
- tenant_id = 'foo_tenant_uuid'
- secgroup_id = 'foo_secgroup_uuid'
- old_sec_prof = secgrouplib.create_security_profile(
- self.fake_cluster, tenant_id, secgroup_id,
- {'name': 'tatore_magno'})
- new_sec_prof = secgrouplib.update_security_profile(
- self.fake_cluster, old_sec_prof['uuid'], 'aaron_magno')
- self.assertEqual('aaron_magno', new_sec_prof['display_name'])
-
- def test_update_security_profile_rules(self):
- sec_prof = secgrouplib.create_security_profile(
- self.fake_cluster, _uuid(), 'pippo', {'name': 'test'})
- ingress_rule = {'ethertype': 'IPv4'}
- egress_rule = {'ethertype': 'IPv4', 'profile_uuid': 'xyz'}
- new_rules = {'logical_port_egress_rules': [egress_rule],
- 'logical_port_ingress_rules': [ingress_rule]}
- secgrouplib.update_security_group_rules(
- self.fake_cluster, sec_prof['uuid'], new_rules)
- sec_prof_res = nsxlib.do_request(
- nsxlib.HTTP_GET,
- nsxlib._build_uri_path('security-profile',
- resource_id=sec_prof['uuid']),
- cluster=self.fake_cluster)
- self.assertEqual(sec_prof['uuid'], sec_prof_res['uuid'])
- # Check for builtin rules
- self.assertEqual(len(sec_prof_res['logical_port_egress_rules']), 2)
- self.assertIn(egress_rule,
- sec_prof_res['logical_port_egress_rules'])
- self.assertEqual(len(sec_prof_res['logical_port_ingress_rules']), 1)
- self.assertIn(ingress_rule,
- sec_prof_res['logical_port_ingress_rules'])
-
- def test_update_security_profile_rules_noingress(self):
- sec_prof = secgrouplib.create_security_profile(
- self.fake_cluster, _uuid(), 'pippo', {'name': 'test'})
- hidden_ingress_rule = {'ethertype': 'IPv4',
- 'ip_prefix': '127.0.0.1/32'}
- egress_rule = {'ethertype': 'IPv4', 'profile_uuid': 'xyz'}
- new_rules = {'logical_port_egress_rules': [egress_rule],
- 'logical_port_ingress_rules': []}
- secgrouplib.update_security_group_rules(
- self.fake_cluster, sec_prof['uuid'], new_rules)
- sec_prof_res = nsxlib.do_request(
- nsxlib.HTTP_GET,
- nsxlib._build_uri_path('security-profile',
- resource_id=sec_prof['uuid']),
- cluster=self.fake_cluster)
- self.assertEqual(sec_prof['uuid'], sec_prof_res['uuid'])
- # Check for builtin rules
- self.assertEqual(len(sec_prof_res['logical_port_egress_rules']), 2)
- self.assertIn(egress_rule,
- sec_prof_res['logical_port_egress_rules'])
- self.assertEqual(len(sec_prof_res['logical_port_ingress_rules']), 1)
- self.assertIn(hidden_ingress_rule,
- sec_prof_res['logical_port_ingress_rules'])
-
- def test_update_non_existing_securityprofile_raises(self):
- self.assertRaises(exceptions.NeutronException,
- secgrouplib.update_security_group_rules,
- self.fake_cluster, 'whatever',
- {'logical_port_egress_rules': [],
- 'logical_port_ingress_rules': []})
-
- def test_delete_security_profile(self):
- sec_prof = secgrouplib.create_security_profile(
- self.fake_cluster, _uuid(), 'pippo', {'name': 'test'})
- secgrouplib.delete_security_profile(
- self.fake_cluster, sec_prof['uuid'])
- self.assertRaises(exceptions.NotFound,
- nsxlib.do_request,
- nsxlib.HTTP_GET,
- nsxlib._build_uri_path(
- 'security-profile',
- resource_id=sec_prof['uuid']),
- cluster=self.fake_cluster)
-
- def test_delete_non_existing_securityprofile_raises(self):
- self.assertRaises(exceptions.NeutronException,
- secgrouplib.delete_security_profile,
- self.fake_cluster, 'whatever')
+++ /dev/null
-# Copyright (c) 2014 VMware, 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 hashlib
-import mock
-
-from neutron.common import constants
-from neutron.common import exceptions
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware.nsxlib import switch as switchlib
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit.vmware.nsxlib import base
-
-_uuid = test_api_v2._uuid
-
-
-class LogicalSwitchesTestCase(base.NsxlibTestCase):
-
- def test_create_and_get_lswitches_single(self):
- tenant_id = 'pippo'
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(self.fake_cluster,
- _uuid(),
- tenant_id,
- 'fake-switch',
- transport_zones_config)
- res_lswitch = switchlib.get_lswitches(self.fake_cluster,
- lswitch['uuid'])
- self.assertEqual(len(res_lswitch), 1)
- self.assertEqual(res_lswitch[0]['uuid'],
- lswitch['uuid'])
-
- def test_create_and_get_lswitches_single_name_exceeds_40_chars(self):
- tenant_id = 'pippo'
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(self.fake_cluster,
- tenant_id,
- _uuid(),
- '*' * 50,
- transport_zones_config)
- res_lswitch = switchlib.get_lswitches(self.fake_cluster,
- lswitch['uuid'])
- self.assertEqual(len(res_lswitch), 1)
- self.assertEqual(res_lswitch[0]['uuid'], lswitch['uuid'])
- self.assertEqual(res_lswitch[0]['display_name'], '*' * 40)
-
- def test_create_and_get_lswitches_multiple(self):
- tenant_id = 'pippo'
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- network_id = _uuid()
- main_lswitch = switchlib.create_lswitch(
- self.fake_cluster, network_id,
- tenant_id, 'fake-switch', transport_zones_config,
- tags=[{'scope': 'multi_lswitch', 'tag': 'True'}])
- # Create secondary lswitch
- second_lswitch = switchlib.create_lswitch(
- self.fake_cluster, network_id,
- tenant_id, 'fake-switch-2', transport_zones_config)
- res_lswitch = switchlib.get_lswitches(self.fake_cluster,
- network_id)
- self.assertEqual(len(res_lswitch), 2)
- switch_uuids = [ls['uuid'] for ls in res_lswitch]
- self.assertIn(main_lswitch['uuid'], switch_uuids)
- self.assertIn(second_lswitch['uuid'], switch_uuids)
- for ls in res_lswitch:
- if ls['uuid'] == main_lswitch['uuid']:
- main_ls = ls
- else:
- second_ls = ls
- main_ls_tags = self._build_tag_dict(main_ls['tags'])
- second_ls_tags = self._build_tag_dict(second_ls['tags'])
- self.assertIn('multi_lswitch', main_ls_tags)
- self.assertNotIn('multi_lswitch', second_ls_tags)
- self.assertIn('quantum_net_id', main_ls_tags)
- self.assertIn('quantum_net_id', second_ls_tags)
- self.assertEqual(main_ls_tags['quantum_net_id'],
- network_id)
- self.assertEqual(second_ls_tags['quantum_net_id'],
- network_id)
-
- def _test_update_lswitch(self, tenant_id, name, tags):
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(self.fake_cluster,
- _uuid(),
- 'pippo',
- 'fake-switch',
- transport_zones_config)
- switchlib.update_lswitch(self.fake_cluster, lswitch['uuid'],
- name, tenant_id=tenant_id, tags=tags)
- res_lswitch = switchlib.get_lswitches(self.fake_cluster,
- lswitch['uuid'])
- self.assertEqual(len(res_lswitch), 1)
- self.assertEqual(res_lswitch[0]['display_name'], name)
- if not tags:
- # no need to validate tags
- return
- switch_tags = self._build_tag_dict(res_lswitch[0]['tags'])
- for tag in tags:
- self.assertIn(tag['scope'], switch_tags)
- self.assertEqual(tag['tag'], switch_tags[tag['scope']])
-
- def test_update_lswitch(self):
- self._test_update_lswitch(None, 'new-name',
- [{'scope': 'new_tag', 'tag': 'xxx'}])
-
- def test_update_lswitch_no_tags(self):
- self._test_update_lswitch(None, 'new-name', None)
-
- def test_update_lswitch_tenant_id(self):
- self._test_update_lswitch('whatever', 'new-name', None)
-
- def test_update_non_existing_lswitch_raises(self):
- self.assertRaises(exceptions.NetworkNotFound,
- switchlib.update_lswitch,
- self.fake_cluster, 'whatever',
- 'foo', 'bar')
-
- def test_delete_networks(self):
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(self.fake_cluster,
- _uuid(),
- 'pippo',
- 'fake-switch',
- transport_zones_config)
- switchlib.delete_networks(self.fake_cluster, lswitch['uuid'],
- [lswitch['uuid']])
- self.assertRaises(exceptions.NotFound,
- switchlib.get_lswitches,
- self.fake_cluster,
- lswitch['uuid'])
-
- def test_delete_non_existing_lswitch_raises(self):
- self.assertRaises(exceptions.NetworkNotFound,
- switchlib.delete_networks,
- self.fake_cluster, 'whatever', ['whatever'])
-
-
-class LogicalPortsTestCase(base.NsxlibTestCase):
-
- def _create_switch_and_port(self, tenant_id='pippo',
- neutron_port_id='whatever',
- name='name', device_id='device_id'):
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(self.fake_cluster,
- _uuid(), tenant_id, 'fake-switch',
- transport_zones_config)
- lport = switchlib.create_lport(self.fake_cluster, lswitch['uuid'],
- tenant_id, neutron_port_id,
- name, device_id, True)
- return lswitch, lport
-
- def test_create_and_get_port(self):
- lswitch, lport = self._create_switch_and_port()
- lport_res = switchlib.get_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
- self.assertEqual(lport['uuid'], lport_res['uuid'])
- # Try again with relation
- lport_res = switchlib.get_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'],
- relations='LogicalPortStatus')
- self.assertEqual(lport['uuid'], lport_res['uuid'])
-
- def test_plug_interface(self):
- lswitch, lport = self._create_switch_and_port()
- switchlib.plug_vif_interface(self.fake_cluster, lswitch['uuid'],
- lport['uuid'], 'VifAttachment', 'fake')
- lport_res = switchlib.get_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
- self.assertEqual(lport['uuid'], lport_res['uuid'])
-
- def test_get_port_by_tag(self):
- lswitch, lport = self._create_switch_and_port()
- lport2 = switchlib.get_port_by_neutron_tag(self.fake_cluster,
- lswitch['uuid'],
- 'whatever')
- self.assertIsNotNone(lport2)
- self.assertEqual(lport['uuid'], lport2['uuid'])
-
- def test_get_port_by_tag_not_found_with_switch_id_raises_not_found(self):
- tenant_id = 'pippo'
- neutron_port_id = 'whatever'
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- lswitch = switchlib.create_lswitch(
- self.fake_cluster, tenant_id, _uuid(),
- 'fake-switch', transport_zones_config)
- self.assertRaises(exceptions.NotFound,
- switchlib.get_port_by_neutron_tag,
- self.fake_cluster, lswitch['uuid'],
- neutron_port_id)
-
- def test_get_port_by_tag_not_find_wildcard_lswitch_returns_none(self):
- tenant_id = 'pippo'
- neutron_port_id = 'whatever'
- transport_zones_config = [{'zone_uuid': _uuid(),
- 'transport_type': 'stt'}]
- switchlib.create_lswitch(
- self.fake_cluster, tenant_id, _uuid(),
- 'fake-switch', transport_zones_config)
- lport = switchlib.get_port_by_neutron_tag(
- self.fake_cluster, '*', neutron_port_id)
- self.assertIsNone(lport)
-
- def test_get_port_status(self):
- lswitch, lport = self._create_switch_and_port()
- status = switchlib.get_port_status(
- self.fake_cluster, lswitch['uuid'], lport['uuid'])
- self.assertEqual(constants.PORT_STATUS_ACTIVE, status)
-
- def test_get_port_status_non_existent_raises(self):
- self.assertRaises(exceptions.PortNotFoundOnNetwork,
- switchlib.get_port_status,
- self.fake_cluster,
- 'boo', 'boo')
-
- def test_update_port(self):
- lswitch, lport = self._create_switch_and_port()
- switchlib.update_port(
- self.fake_cluster, lswitch['uuid'], lport['uuid'],
- 'neutron_port_id', 'pippo2', 'new_name', 'device_id', False)
- lport_res = switchlib.get_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
- self.assertEqual(lport['uuid'], lport_res['uuid'])
- self.assertEqual('new_name', lport_res['display_name'])
- self.assertEqual('False', lport_res['admin_status_enabled'])
- port_tags = self._build_tag_dict(lport_res['tags'])
- self.assertIn('os_tid', port_tags)
- self.assertIn('q_port_id', port_tags)
- self.assertIn('vm_id', port_tags)
-
- def test_create_port_device_id_less_than_40_chars(self):
- lswitch, lport = self._create_switch_and_port()
- lport_res = switchlib.get_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
- port_tags = self._build_tag_dict(lport_res['tags'])
- self.assertEqual('device_id', port_tags['vm_id'])
-
- def test_create_port_device_id_more_than_40_chars(self):
- dev_id = "this_is_a_very_long_device_id_with_lots_of_characters"
- lswitch, lport = self._create_switch_and_port(device_id=dev_id)
- lport_res = switchlib.get_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
- port_tags = self._build_tag_dict(lport_res['tags'])
- self.assertNotEqual(len(dev_id), len(port_tags['vm_id']))
-
- def test_get_ports_with_obsolete_and_new_vm_id_tag(self):
- def obsolete(device_id, obfuscate=False):
- return hashlib.sha1(device_id).hexdigest()
-
- with mock.patch.object(utils, 'device_id_to_vm_id', new=obsolete):
- dev_id1 = "short-dev-id-1"
- _, lport1 = self._create_switch_and_port(device_id=dev_id1)
- dev_id2 = "short-dev-id-2"
- _, lport2 = self._create_switch_and_port(device_id=dev_id2)
-
- lports = switchlib.get_ports(self.fake_cluster, None, [dev_id1])
- port_tags = self._build_tag_dict(lports['whatever']['tags'])
- self.assertNotEqual(dev_id1, port_tags['vm_id'])
-
- lports = switchlib.get_ports(self.fake_cluster, None, [dev_id2])
- port_tags = self._build_tag_dict(lports['whatever']['tags'])
- self.assertEqual(dev_id2, port_tags['vm_id'])
-
- def test_update_non_existent_port_raises(self):
- self.assertRaises(exceptions.PortNotFoundOnNetwork,
- switchlib.update_port, self.fake_cluster,
- 'boo', 'boo', 'boo', 'boo', 'boo', 'boo', False)
-
- def test_delete_port(self):
- lswitch, lport = self._create_switch_and_port()
- switchlib.delete_port(self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
- self.assertRaises(exceptions.PortNotFoundOnNetwork,
- switchlib.get_port, self.fake_cluster,
- lswitch['uuid'], lport['uuid'])
-
- def test_delete_non_existent_port_raises(self):
- lswitch = self._create_switch_and_port()[0]
- self.assertRaises(exceptions.PortNotFoundOnNetwork,
- switchlib.delete_port, self.fake_cluster,
- lswitch['uuid'], 'bad_port_uuid')
-
- def test_query_lswitch_ports(self):
- lswitch, lport = self._create_switch_and_port()
- switch_port_uuids = [
- switchlib.create_lport(
- self.fake_cluster, lswitch['uuid'], 'pippo', 'qportid-%s' % k,
- 'port-%s' % k, 'deviceid-%s' % k, True)['uuid']
- for k in range(2)]
- switch_port_uuids.append(lport['uuid'])
- ports = switchlib.query_lswitch_lports(
- self.fake_cluster, lswitch['uuid'])
- self.assertEqual(len(ports), 3)
- for res_port in ports:
- self.assertIn(res_port['uuid'], switch_port_uuids)
+++ /dev/null
-# Copyright (c) 2014 VMware, 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.
-#
-
-from neutron.plugins.vmware.api_client import exception
-from neutron.plugins.vmware.api_client import version as version_module
-from neutron.plugins.vmware.nsxlib import router as routerlib
-from neutron.plugins.vmware.nsxlib import versioning
-from neutron.tests import base
-
-
-class TestVersioning(base.BaseTestCase):
-
- def test_function_handling_missing_minor(self):
- version = version_module.Version('2.0')
- function = versioning.get_function_by_version(
- routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
- self.assertEqual(routerlib.create_implicit_routing_lrouter,
- function)
-
- def test_function_handling_with_both_major_and_minor(self):
- version = version_module.Version('3.2')
- function = versioning.get_function_by_version(
- routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
- self.assertEqual(routerlib.create_explicit_routing_lrouter,
- function)
-
- def test_function_handling_with_newer_major(self):
- version = version_module.Version('5.2')
- function = versioning.get_function_by_version(
- routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
- self.assertEqual(routerlib.create_explicit_routing_lrouter,
- function)
-
- def test_function_handling_with_obsolete_major(self):
- version = version_module.Version('1.2')
- self.assertRaises(NotImplementedError,
- versioning.get_function_by_version,
- routerlib.ROUTER_FUNC_DICT,
- 'create_lrouter', version)
-
- def test_function_handling_with_unknown_version(self):
- self.assertRaises(exception.ServiceUnavailable,
- versioning.get_function_by_version,
- routerlib.ROUTER_FUNC_DICT,
- 'create_lrouter', None)
+++ /dev/null
-# Copyright (c) 2013 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 mock
-from oslo_config import cfg
-
-from neutron.common import constants
-from neutron.common import test_lib
-from neutron.plugins.vmware.common import sync
-from neutron.plugins.vmware.dhcp_meta import rpc
-from neutron.tests.unit.openvswitch import test_agent_scheduler as test_base
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.apiclient import fake
-
-
-class DhcpAgentNotifierTestCase(test_base.OvsDhcpAgentNotifierTestCase):
- plugin_str = vmware.PLUGIN_NAME
-
- def setUp(self):
- test_lib.test_config['config_files'] = [
- vmware.get_fake_conf('nsx.ini.full.test')]
-
- # mock api client
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsx_api = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- instance = self.mock_nsx_api.start()
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
-
- # Emulate tests against NSX 2.x
- instance.return_value.get_version.return_value = "2.999"
- instance.return_value.request.side_effect = self.fc.fake_request
- super(DhcpAgentNotifierTestCase, self).setUp()
- self.addCleanup(self.fc.reset_all)
- self.addCleanup(patch_sync.stop)
- self.addCleanup(self.mock_nsx_api.stop)
-
- def _test_gateway_subnet_notification(self, gateway='10.0.0.1'):
- cfg.CONF.set_override('metadata_mode', 'dhcp_host_route', 'NSX')
- hosts = ['hosta']
- with mock.patch.object(rpc.LOG, 'info') as mock_log:
- net, subnet, port = self._network_port_create(
- hosts, gateway=gateway, owner=constants.DEVICE_OWNER_DHCP)
- self.assertEqual(subnet['subnet']['gateway_ip'], gateway)
- called = 1 if gateway is None else 0
- self.assertEqual(called, mock_log.call_count)
-
- def test_gatewayless_subnet_notification(self):
- self._test_gateway_subnet_notification(gateway=None)
-
- def test_subnet_with_gateway_notification(self):
- self._test_gateway_subnet_notification()
+++ /dev/null
-# Copyright 2013 VMware, 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 mock
-
-from oslo_config import cfg
-
-from neutron.common import constants as n_consts
-from neutron.common import exceptions as n_exc
-from neutron import context
-from neutron.plugins.vmware.api_client import exception
-from neutron.plugins.vmware.common import exceptions as p_exc
-from neutron.plugins.vmware.dbexts import lsn_db
-from neutron.plugins.vmware.dhcp_meta import constants
-from neutron.plugins.vmware.dhcp_meta import lsnmanager as lsn_man
-from neutron.plugins.vmware.dhcp_meta import migration as mig_man
-from neutron.plugins.vmware.dhcp_meta import nsx
-from neutron.plugins.vmware.dhcp_meta import rpc
-from neutron.tests import base
-from neutron.tests.unit import testlib_api
-
-
-class DhcpMetadataBuilderTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(DhcpMetadataBuilderTestCase, self).setUp()
- self.builder = mig_man.DhcpMetadataBuilder(mock.Mock(), mock.Mock())
- self.network_id = 'foo_network_id'
- self.subnet_id = 'foo_subnet_id'
- self.router_id = 'foo_router_id'
-
- def test_dhcp_agent_get_all(self):
- expected = []
- self.builder.plugin.list_dhcp_agents_hosting_network.return_value = (
- {'agents': expected})
- agents = self.builder.dhcp_agent_get_all(mock.ANY, self.network_id)
- self.assertEqual(expected, agents)
-
- def test_dhcp_port_get_all(self):
- expected = []
- self.builder.plugin.get_ports.return_value = expected
- ports = self.builder.dhcp_port_get_all(mock.ANY, self.network_id)
- self.assertEqual(expected, ports)
-
- def test_router_id_get(self):
- port = {
- 'device_id': self.router_id,
- 'network_id': self.network_id,
- 'fixed_ips': [{'subnet_id': self.subnet_id}]
- }
- subnet = {
- 'id': self.subnet_id,
- 'network_id': self.network_id
- }
- self.builder.plugin.get_ports.return_value = [port]
- result = self.builder.router_id_get(context, subnet)
- self.assertEqual(self.router_id, result)
-
- def test_router_id_get_none_subnet(self):
- self.assertIsNone(self.builder.router_id_get(mock.ANY, None))
-
- def test_router_id_get_none_no_router(self):
- self.builder.plugin.get_ports.return_value = []
- subnet = {'network_id': self.network_id}
- self.assertIsNone(self.builder.router_id_get(mock.ANY, subnet))
-
- def test_metadata_deallocate(self):
- self.builder.metadata_deallocate(
- mock.ANY, self.router_id, self.subnet_id)
- self.assertTrue(self.builder.plugin.remove_router_interface.call_count)
-
- def test_metadata_allocate(self):
- self.builder.metadata_allocate(
- mock.ANY, self.router_id, self.subnet_id)
- self.assertTrue(self.builder.plugin.add_router_interface.call_count)
-
- def test_dhcp_deallocate(self):
- agents = [{'id': 'foo_agent_id'}]
- ports = [{'id': 'foo_port_id'}]
- self.builder.dhcp_deallocate(mock.ANY, self.network_id, agents, ports)
- self.assertTrue(
- self.builder.plugin.remove_network_from_dhcp_agent.call_count)
- self.assertTrue(self.builder.plugin.delete_port.call_count)
-
- def _test_dhcp_allocate(self, subnet, expected_notify_count):
- with mock.patch.object(mig_man.nsx, 'handle_network_dhcp_access') as f:
- self.builder.dhcp_allocate(mock.ANY, self.network_id, subnet)
- self.assertTrue(f.call_count)
- self.assertEqual(expected_notify_count,
- self.builder.notifier.notify.call_count)
-
- def test_dhcp_allocate(self):
- subnet = {'network_id': self.network_id, 'id': self.subnet_id}
- self._test_dhcp_allocate(subnet, 2)
-
- def test_dhcp_allocate_none_subnet(self):
- self._test_dhcp_allocate(None, 0)
-
-
-class MigrationManagerTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(MigrationManagerTestCase, self).setUp()
- self.manager = mig_man.MigrationManager(mock.Mock(),
- mock.Mock(),
- mock.Mock())
- self.network_id = 'foo_network_id'
- self.router_id = 'foo_router_id'
- self.subnet_id = 'foo_subnet_id'
- self.mock_builder_p = mock.patch.object(self.manager, 'builder')
- self.mock_builder = self.mock_builder_p.start()
-
- def _test_validate(self, lsn_exists=False, ext_net=False, subnets=None):
- network = {'router:external': ext_net}
- self.manager.manager.lsn_exists.return_value = lsn_exists
- self.manager.plugin.get_network.return_value = network
- self.manager.plugin.get_subnets.return_value = subnets
- result = self.manager.validate(mock.ANY, self.network_id)
- if len(subnets):
- self.assertEqual(subnets[0], result)
- else:
- self.assertIsNone(result)
-
- def test_validate_no_subnets(self):
- self._test_validate(subnets=[])
-
- def test_validate_with_one_subnet(self):
- self._test_validate(subnets=[{'cidr': '0.0.0.0/0'}])
-
- def test_validate_raise_conflict_many_subnets(self):
- self.assertRaises(p_exc.LsnMigrationConflict,
- self._test_validate,
- subnets=[{'id': 'sub1'}, {'id': 'sub2'}])
-
- def test_validate_raise_conflict_lsn_exists(self):
- self.assertRaises(p_exc.LsnMigrationConflict,
- self._test_validate,
- lsn_exists=True)
-
- def test_validate_raise_badrequest_external_net(self):
- self.assertRaises(n_exc.BadRequest,
- self._test_validate,
- ext_net=True)
-
- def test_validate_raise_badrequest_metadata_net(self):
- self.assertRaises(n_exc.BadRequest,
- self._test_validate,
- ext_net=False,
- subnets=[{'cidr': rpc.METADATA_SUBNET_CIDR}])
-
- def _test_migrate(self, router, subnet, expected_calls):
- self.mock_builder.router_id_get.return_value = router
- self.manager.migrate(mock.ANY, self.network_id, subnet)
- # testing the exact the order of calls is important
- self.assertEqual(expected_calls, self.mock_builder.mock_calls)
-
- def test_migrate(self):
- subnet = {
- 'id': self.subnet_id,
- 'network_id': self.network_id
- }
- call_sequence = [
- mock.call.router_id_get(mock.ANY, subnet),
- mock.call.metadata_deallocate(
- mock.ANY, self.router_id, self.subnet_id),
- mock.call.dhcp_agent_get_all(mock.ANY, self.network_id),
- mock.call.dhcp_port_get_all(mock.ANY, self.network_id),
- mock.call.dhcp_deallocate(
- mock.ANY, self.network_id, mock.ANY, mock.ANY),
- mock.call.dhcp_allocate(mock.ANY, self.network_id, subnet),
- mock.call.metadata_allocate(
- mock.ANY, self.router_id, self.subnet_id)
- ]
- self._test_migrate(self.router_id, subnet, call_sequence)
-
- def test_migrate_no_router_uplink(self):
- subnet = {
- 'id': self.subnet_id,
- 'network_id': self.network_id
- }
- call_sequence = [
- mock.call.router_id_get(mock.ANY, subnet),
- mock.call.dhcp_agent_get_all(mock.ANY, self.network_id),
- mock.call.dhcp_port_get_all(mock.ANY, self.network_id),
- mock.call.dhcp_deallocate(
- mock.ANY, self.network_id, mock.ANY, mock.ANY),
- mock.call.dhcp_allocate(mock.ANY, self.network_id, subnet),
- ]
- self._test_migrate(None, subnet, call_sequence)
-
- def test_migrate_no_subnet(self):
- call_sequence = [
- mock.call.router_id_get(mock.ANY, None),
- mock.call.dhcp_allocate(mock.ANY, self.network_id, None),
- ]
- self._test_migrate(None, None, call_sequence)
-
- def _test_report(self, lsn_attrs, expected):
- self.manager.manager.lsn_port_get.return_value = lsn_attrs
- report = self.manager.report(mock.ANY, self.network_id, self.subnet_id)
- self.assertEqual(expected, report)
-
- def test_report_for_lsn(self):
- self._test_report(('foo_lsn_id', 'foo_lsn_port_id'),
- {'ports': ['foo_lsn_port_id'],
- 'services': ['foo_lsn_id'], 'type': 'lsn'})
-
- def test_report_for_lsn_without_lsn_port(self):
- self._test_report(('foo_lsn_id', None),
- {'ports': [],
- 'services': ['foo_lsn_id'], 'type': 'lsn'})
-
- def _test_report_for_lsn_without_subnet(self, validated_subnet):
- with mock.patch.object(self.manager.plugin, 'get_subnets',
- return_value=validated_subnet):
- self.manager.manager.lsn_port_get.return_value = (
- ('foo_lsn_id', 'foo_lsn_port_id'))
- report = self.manager.report(context, self.network_id)
- expected = {
- 'ports': ['foo_lsn_port_id'] if validated_subnet else [],
- 'services': ['foo_lsn_id'], 'type': 'lsn'
- }
- self.assertEqual(expected, report)
-
- def test_report_for_lsn_without_subnet_subnet_found(self):
- self._test_report_for_lsn_without_subnet([{'id': self.subnet_id}])
-
- def test_report_for_lsn_without_subnet_subnet_not_found(self):
- self.manager.manager.lsn_get.return_value = 'foo_lsn_id'
- self._test_report_for_lsn_without_subnet(None)
-
- def test_report_for_dhcp_agent(self):
- self.manager.manager.lsn_port_get.return_value = (None, None)
- self.mock_builder.dhcp_agent_get_all.return_value = (
- [{'id': 'foo_agent_id'}])
- self.mock_builder.dhcp_port_get_all.return_value = (
- [{'id': 'foo_dhcp_port_id'}])
- result = self.manager.report(mock.ANY, self.network_id, self.subnet_id)
- expected = {
- 'ports': ['foo_dhcp_port_id'],
- 'services': ['foo_agent_id'],
- 'type': 'agent'
- }
- self.assertEqual(expected, result)
-
-
-class LsnManagerTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(LsnManagerTestCase, self).setUp()
- self.net_id = 'foo_network_id'
- self.sub_id = 'foo_subnet_id'
- self.port_id = 'foo_port_id'
- self.lsn_id = 'foo_lsn_id'
- self.mac = 'aa:bb:cc:dd:ee:ff'
- self.switch_id = 'foo_switch_id'
- self.lsn_port_id = 'foo_lsn_port_id'
- self.tenant_id = 'foo_tenant_id'
- self.manager = lsn_man.LsnManager(mock.Mock())
- self.context = context.get_admin_context()
- self.mock_lsn_api_p = mock.patch.object(lsn_man, 'lsn_api')
- self.mock_lsn_api = self.mock_lsn_api_p.start()
- self.mock_nsx_utils_p = mock.patch.object(lsn_man, 'nsx_utils')
- self.mock_nsx_utils = self.mock_nsx_utils_p.start()
- nsx.register_dhcp_opts(cfg)
- nsx.register_metadata_opts(cfg)
-
- def test_lsn_get(self):
- self.mock_lsn_api.lsn_for_network_get.return_value = self.lsn_id
- expected = self.manager.lsn_get(mock.ANY, self.net_id)
- self.mock_lsn_api.lsn_for_network_get.assert_called_once_with(
- mock.ANY, self.net_id)
- self.assertEqual(expected, self.lsn_id)
-
- def _test_lsn_get_raise_not_found_with_exc(self, exc):
- self.mock_lsn_api.lsn_for_network_get.side_effect = exc
- self.assertRaises(p_exc.LsnNotFound,
- self.manager.lsn_get,
- mock.ANY, self.net_id)
- self.mock_lsn_api.lsn_for_network_get.assert_called_once_with(
- mock.ANY, self.net_id)
-
- def test_lsn_get_raise_not_found_with_not_found(self):
- self._test_lsn_get_raise_not_found_with_exc(n_exc.NotFound)
-
- def test_lsn_get_raise_not_found_with_api_error(self):
- self._test_lsn_get_raise_not_found_with_exc(exception.NsxApiException)
-
- def _test_lsn_get_silent_raise_with_exc(self, exc):
- self.mock_lsn_api.lsn_for_network_get.side_effect = exc
- expected = self.manager.lsn_get(
- mock.ANY, self.net_id, raise_on_err=False)
- self.mock_lsn_api.lsn_for_network_get.assert_called_once_with(
- mock.ANY, self.net_id)
- self.assertIsNone(expected)
-
- def test_lsn_get_silent_raise_with_not_found(self):
- self._test_lsn_get_silent_raise_with_exc(n_exc.NotFound)
-
- def test_lsn_get_silent_raise_with_api_error(self):
- self._test_lsn_get_silent_raise_with_exc(exception.NsxApiException)
-
- def test_lsn_create(self):
- self.mock_lsn_api.lsn_for_network_create.return_value = self.lsn_id
- self.manager.lsn_create(mock.ANY, self.net_id)
- self.mock_lsn_api.lsn_for_network_create.assert_called_once_with(
- mock.ANY, self.net_id)
-
- def test_lsn_create_raise_api_error(self):
- self.mock_lsn_api.lsn_for_network_create.side_effect = (
- exception.NsxApiException)
- self.assertRaises(p_exc.NsxPluginException,
- self.manager.lsn_create,
- mock.ANY, self.net_id)
- self.mock_lsn_api.lsn_for_network_create.assert_called_once_with(
- mock.ANY, self.net_id)
-
- def test_lsn_delete(self):
- self.manager.lsn_delete(mock.ANY, self.lsn_id)
- self.mock_lsn_api.lsn_delete.assert_called_once_with(
- mock.ANY, self.lsn_id)
-
- def _test_lsn_delete_with_exc(self, exc):
- self.mock_lsn_api.lsn_delete.side_effect = exc
- self.manager.lsn_delete(mock.ANY, self.lsn_id)
- self.mock_lsn_api.lsn_delete.assert_called_once_with(
- mock.ANY, self.lsn_id)
-
- def test_lsn_delete_with_not_found(self):
- self._test_lsn_delete_with_exc(n_exc.NotFound)
-
- def test_lsn_delete_api_exception(self):
- self._test_lsn_delete_with_exc(exception.NsxApiException)
-
- def test_lsn_delete_by_network(self):
- self.mock_lsn_api.lsn_for_network_get.return_value = self.lsn_id
- with mock.patch.object(self.manager, 'lsn_delete') as f:
- self.manager.lsn_delete_by_network(mock.ANY, self.net_id)
- self.mock_lsn_api.lsn_for_network_get.assert_called_once_with(
- mock.ANY, self.net_id)
- f.assert_called_once_with(mock.ANY, self.lsn_id)
-
- def _test_lsn_delete_by_network_with_exc(self, exc):
- self.mock_lsn_api.lsn_for_network_get.side_effect = exc
- with mock.patch.object(lsn_man.LOG, 'warn') as l:
- self.manager.lsn_delete_by_network(mock.ANY, self.net_id)
- self.assertEqual(1, l.call_count)
-
- def test_lsn_delete_by_network_with_not_found(self):
- self._test_lsn_delete_by_network_with_exc(n_exc.NotFound)
-
- def test_lsn_delete_by_network_with_not_api_error(self):
- self._test_lsn_delete_by_network_with_exc(exception.NsxApiException)
-
- def test_lsn_port_get(self):
- self.mock_lsn_api.lsn_port_by_subnet_get.return_value = (
- self.lsn_port_id)
- with mock.patch.object(
- self.manager, 'lsn_get', return_value=self.lsn_id):
- expected = self.manager.lsn_port_get(
- mock.ANY, self.net_id, self.sub_id)
- self.assertEqual(expected, (self.lsn_id, self.lsn_port_id))
-
- def test_lsn_port_get_lsn_not_found_on_raise(self):
- with mock.patch.object(
- self.manager, 'lsn_get',
- side_effect=p_exc.LsnNotFound(entity='network',
- entity_id=self.net_id)):
- self.assertRaises(p_exc.LsnNotFound,
- self.manager.lsn_port_get,
- mock.ANY, self.net_id, self.sub_id)
-
- def test_lsn_port_get_lsn_not_found_silent_raise(self):
- with mock.patch.object(self.manager, 'lsn_get', return_value=None):
- expected = self.manager.lsn_port_get(
- mock.ANY, self.net_id, self.sub_id, raise_on_err=False)
- self.assertEqual(expected, (None, None))
-
- def test_lsn_port_get_port_not_found_on_raise(self):
- self.mock_lsn_api.lsn_port_by_subnet_get.side_effect = n_exc.NotFound
- with mock.patch.object(
- self.manager, 'lsn_get', return_value=self.lsn_id):
- self.assertRaises(p_exc.LsnPortNotFound,
- self.manager.lsn_port_get,
- mock.ANY, self.net_id, self.sub_id)
-
- def test_lsn_port_get_port_not_found_silent_raise(self):
- self.mock_lsn_api.lsn_port_by_subnet_get.side_effect = n_exc.NotFound
- with mock.patch.object(
- self.manager, 'lsn_get', return_value=self.lsn_id):
- expected = self.manager.lsn_port_get(
- mock.ANY, self.net_id, self.sub_id, raise_on_err=False)
- self.assertEqual(expected, (self.lsn_id, None))
-
- def test_lsn_port_create(self):
- self.mock_lsn_api.lsn_port_create.return_value = self.lsn_port_id
- expected = self.manager.lsn_port_create(mock.ANY, mock.ANY, mock.ANY)
- self.assertEqual(expected, self.lsn_port_id)
-
- def _test_lsn_port_create_with_exc(self, exc, expected):
- self.mock_lsn_api.lsn_port_create.side_effect = exc
- self.assertRaises(expected,
- self.manager.lsn_port_create,
- mock.ANY, mock.ANY, mock.ANY)
-
- def test_lsn_port_create_with_not_found(self):
- self._test_lsn_port_create_with_exc(n_exc.NotFound, p_exc.LsnNotFound)
-
- def test_lsn_port_create_api_exception(self):
- self._test_lsn_port_create_with_exc(exception.NsxApiException,
- p_exc.NsxPluginException)
-
- def test_lsn_port_delete(self):
- self.manager.lsn_port_delete(mock.ANY, mock.ANY, mock.ANY)
- self.assertEqual(1, self.mock_lsn_api.lsn_port_delete.call_count)
-
- def _test_lsn_port_delete_with_exc(self, exc):
- self.mock_lsn_api.lsn_port_delete.side_effect = exc
- with mock.patch.object(lsn_man.LOG, 'warn') as l:
- self.manager.lsn_port_delete(mock.ANY, mock.ANY, mock.ANY)
- self.assertEqual(1, self.mock_lsn_api.lsn_port_delete.call_count)
- self.assertEqual(1, l.call_count)
-
- def test_lsn_port_delete_with_not_found(self):
- self._test_lsn_port_delete_with_exc(n_exc.NotFound)
-
- def test_lsn_port_delete_api_exception(self):
- self._test_lsn_port_delete_with_exc(exception.NsxApiException)
-
- def _test_lsn_port_dhcp_setup(self, ret_val, sub):
- self.mock_nsx_utils.get_nsx_switch_ids.return_value = [self.switch_id]
- self.mock_lsn_api.lsn_port_create.return_value = self.lsn_port_id
- with mock.patch.object(
- self.manager, 'lsn_get', return_value=self.lsn_id):
- with mock.patch.object(lsn_man.switch_api,
- 'get_port_by_neutron_tag'):
- expected = self.manager.lsn_port_dhcp_setup(
- mock.Mock(), mock.ANY, mock.ANY,
- mock.ANY, subnet_config=sub)
- self.assertEqual(
- 1, self.mock_lsn_api.lsn_port_create.call_count)
- self.assertEqual(
- 1, self.mock_lsn_api.lsn_port_plug_network.call_count)
- self.assertEqual(expected, ret_val)
-
- def test_lsn_port_dhcp_setup(self):
- self._test_lsn_port_dhcp_setup((self.lsn_id, self.lsn_port_id), None)
-
- def test_lsn_port_dhcp_setup_with_config(self):
- with mock.patch.object(self.manager, 'lsn_port_dhcp_configure') as f:
- self._test_lsn_port_dhcp_setup(None, mock.ANY)
- self.assertEqual(1, f.call_count)
-
- def test_lsn_port_dhcp_setup_with_not_found(self):
- self.mock_nsx_utils.get_nsx_switch_ids.return_value = [self.switch_id]
- with mock.patch.object(lsn_man.switch_api,
- 'get_port_by_neutron_tag') as f:
- f.side_effect = n_exc.NotFound
- self.assertRaises(p_exc.PortConfigurationError,
- self.manager.lsn_port_dhcp_setup,
- mock.Mock(), mock.ANY, mock.ANY, mock.ANY)
-
- def test_lsn_port_dhcp_setup_with_conflict(self):
- self.mock_lsn_api.lsn_port_plug_network.side_effect = (
- p_exc.LsnConfigurationConflict(lsn_id=self.lsn_id))
- self.mock_nsx_utils.get_nsx_switch_ids.return_value = [self.switch_id]
- with mock.patch.object(lsn_man.switch_api, 'get_port_by_neutron_tag'):
- with mock.patch.object(self.manager, 'lsn_port_delete') as g:
- self.assertRaises(p_exc.PortConfigurationError,
- self.manager.lsn_port_dhcp_setup,
- mock.Mock(), mock.ANY, mock.ANY, mock.ANY)
- self.assertEqual(1, g.call_count)
-
- def _test_lsn_port_dhcp_configure_with_subnet(
- self, expected, dns=None, gw=None, routes=None):
- subnet = {
- 'enable_dhcp': True,
- 'dns_nameservers': dns or [],
- 'gateway_ip': gw,
- 'host_routes': routes
- }
- self.manager.lsn_port_dhcp_configure(mock.ANY, self.lsn_id,
- self.lsn_port_id, subnet)
- self.mock_lsn_api.lsn_port_dhcp_configure.assert_called_once_with(
- mock.ANY, self.lsn_id, self.lsn_port_id, subnet['enable_dhcp'],
- expected)
-
- def test_lsn_port_dhcp_configure(self):
- expected = {
- 'routers': '127.0.0.1',
- 'default_lease_time': cfg.CONF.NSX_DHCP.default_lease_time,
- 'domain_name': cfg.CONF.NSX_DHCP.domain_name
- }
- self._test_lsn_port_dhcp_configure_with_subnet(
- expected, dns=[], gw='127.0.0.1', routes=[])
-
- def test_lsn_port_dhcp_configure_gatewayless(self):
- expected = {
- 'default_lease_time': cfg.CONF.NSX_DHCP.default_lease_time,
- 'domain_name': cfg.CONF.NSX_DHCP.domain_name
- }
- self._test_lsn_port_dhcp_configure_with_subnet(expected, gw=None)
-
- def test_lsn_port_dhcp_configure_with_extra_dns_servers(self):
- expected = {
- 'default_lease_time': cfg.CONF.NSX_DHCP.default_lease_time,
- 'domain_name_servers': '8.8.8.8,9.9.9.9',
- 'domain_name': cfg.CONF.NSX_DHCP.domain_name
- }
- self._test_lsn_port_dhcp_configure_with_subnet(
- expected, dns=['8.8.8.8', '9.9.9.9'])
-
- def test_lsn_port_dhcp_configure_with_host_routes(self):
- expected = {
- 'default_lease_time': cfg.CONF.NSX_DHCP.default_lease_time,
- 'domain_name': cfg.CONF.NSX_DHCP.domain_name,
- 'classless_static_routes': '8.8.8.8,9.9.9.9'
- }
- self._test_lsn_port_dhcp_configure_with_subnet(
- expected, routes=['8.8.8.8', '9.9.9.9'])
-
- def _test_lsn_metadata_configure(self, is_enabled):
- with mock.patch.object(self.manager, 'lsn_port_dispose') as f:
- self.manager.plugin.get_subnet.return_value = (
- {'network_id': self.net_id})
- self.manager.lsn_metadata_configure(mock.ANY,
- self.sub_id, is_enabled)
- expected = {
- 'metadata_server_port': 8775,
- 'metadata_server_ip': '127.0.0.1',
- 'metadata_proxy_shared_secret': ''
- }
- self.mock_lsn_api.lsn_metadata_configure.assert_called_once_with(
- mock.ANY, mock.ANY, is_enabled, expected)
- if is_enabled:
- self.assertEqual(
- 1, self.mock_lsn_api.lsn_port_by_subnet_get.call_count)
- else:
- self.assertEqual(1, f.call_count)
-
- def test_lsn_metadata_configure_enabled(self):
- self._test_lsn_metadata_configure(True)
-
- def test_lsn_metadata_configure_disabled(self):
- self._test_lsn_metadata_configure(False)
-
- def test_lsn_metadata_configure_not_found(self):
- self.mock_lsn_api.lsn_metadata_configure.side_effect = (
- p_exc.LsnNotFound(entity='lsn', entity_id=self.lsn_id))
- self.manager.plugin.get_subnet.return_value = (
- {'network_id': self.net_id})
- self.assertRaises(p_exc.NsxPluginException,
- self.manager.lsn_metadata_configure,
- mock.ANY, self.sub_id, True)
-
- def test_lsn_port_metadata_setup(self):
- subnet = {
- 'cidr': '0.0.0.0/0',
- 'id': self.sub_id,
- 'network_id': self.net_id,
- 'tenant_id': self.tenant_id
- }
- expected_data = {
- 'subnet_id': subnet['id'],
- 'ip_address': subnet['cidr'],
- 'mac_address': constants.METADATA_MAC
- }
- self.mock_nsx_utils.get_nsx_switch_ids.return_value = [self.switch_id]
- with mock.patch.object(lsn_man.switch_api, 'create_lport') as f:
- with mock.patch.object(self.manager, 'lsn_port_create') as g:
- f.return_value = {'uuid': self.port_id}
- self.manager.lsn_port_metadata_setup(
- self.context, self.lsn_id, subnet)
- (self.mock_lsn_api.lsn_port_plug_network.
- assert_called_once_with(mock.ANY, self.lsn_id,
- mock.ANY, self.port_id))
- g.assert_called_once_with(
- self.context, self.lsn_id, expected_data)
-
- def test_lsn_port_metadata_setup_raise_not_found(self):
- subnet = {
- 'cidr': '0.0.0.0/0',
- 'id': self.sub_id,
- 'network_id': self.net_id,
- 'tenant_id': self.tenant_id
- }
- self.mock_nsx_utils.get_nsx_switch_ids.return_value = [self.switch_id]
- with mock.patch.object(lsn_man.switch_api, 'create_lport') as f:
- f.side_effect = n_exc.NotFound
- self.assertRaises(p_exc.PortConfigurationError,
- self.manager.lsn_port_metadata_setup,
- mock.Mock(), self.lsn_id, subnet)
-
- def test_lsn_port_metadata_setup_raise_conflict(self):
- subnet = {
- 'cidr': '0.0.0.0/0',
- 'id': self.sub_id,
- 'network_id': self.net_id,
- 'tenant_id': self.tenant_id
- }
- self.mock_nsx_utils.get_nsx_switch_ids.return_value = [self.switch_id]
- with mock.patch.object(lsn_man.switch_api, 'create_lport') as f:
- with mock.patch.object(lsn_man.switch_api, 'delete_port') as g:
- f.return_value = {'uuid': self.port_id}
- self.mock_lsn_api.lsn_port_plug_network.side_effect = (
- p_exc.LsnConfigurationConflict(lsn_id=self.lsn_id))
- self.assertRaises(p_exc.PortConfigurationError,
- self.manager.lsn_port_metadata_setup,
- mock.Mock(), self.lsn_id, subnet)
- self.assertEqual(1,
- self.mock_lsn_api.lsn_port_delete.call_count)
- self.assertEqual(1, g.call_count)
-
- def _test_lsn_port_dispose_with_values(self, lsn_id, lsn_port_id, count):
- with mock.patch.object(self.manager,
- 'lsn_port_get_by_mac',
- return_value=(lsn_id, lsn_port_id)):
- self.manager.lsn_port_dispose(mock.ANY, self.net_id, self.mac)
- self.assertEqual(count,
- self.mock_lsn_api.lsn_port_delete.call_count)
-
- def test_lsn_port_dispose(self):
- self._test_lsn_port_dispose_with_values(
- self.lsn_id, self.lsn_port_id, 1)
-
- def test_lsn_port_dispose_meta_mac(self):
- self.mac = constants.METADATA_MAC
- with mock.patch.object(lsn_man.switch_api,
- 'get_port_by_neutron_tag') as f:
- with mock.patch.object(lsn_man.switch_api, 'delete_port') as g:
- f.return_value = {'uuid': self.port_id}
- self._test_lsn_port_dispose_with_values(
- self.lsn_id, self.lsn_port_id, 1)
- f.assert_called_once_with(
- mock.ANY, self.net_id, constants.METADATA_PORT_ID)
- g.assert_called_once_with(mock.ANY, self.net_id, self.port_id)
-
- def test_lsn_port_dispose_lsn_not_found(self):
- self._test_lsn_port_dispose_with_values(None, None, 0)
-
- def test_lsn_port_dispose_lsn_port_not_found(self):
- self._test_lsn_port_dispose_with_values(self.lsn_id, None, 0)
-
- def test_lsn_port_dispose_api_error(self):
- self.mock_lsn_api.lsn_port_delete.side_effect = (
- exception.NsxApiException)
- with mock.patch.object(lsn_man.LOG, 'warn') as l:
- self.manager.lsn_port_dispose(mock.ANY, self.net_id, self.mac)
- self.assertEqual(1, l.call_count)
-
- def test_lsn_port_host_conf(self):
- with mock.patch.object(self.manager,
- 'lsn_port_get',
- return_value=(self.lsn_id, self.lsn_port_id)):
- f = mock.Mock()
- self.manager._lsn_port_host_conf(mock.ANY, self.net_id,
- self.sub_id, mock.ANY, f)
- self.assertEqual(1, f.call_count)
-
- def test_lsn_port_host_conf_lsn_port_not_found(self):
- with mock.patch.object(
- self.manager, 'lsn_port_get', return_value=(None, None)) as f:
- self.manager._lsn_port_host_conf(
- mock.ANY, self.net_id, self.sub_id, mock.ANY, mock.Mock())
- self.assertEqual(1, f.call_count)
-
- def _test_lsn_port_update(self, dhcp=None, meta=None):
- self.manager.lsn_port_update(
- mock.ANY, self.net_id, self.sub_id, dhcp, meta)
- count = 1 if dhcp else 0
- count = count + 1 if meta else count
- self.assertEqual(count, (self.mock_lsn_api.
- lsn_port_host_entries_update.call_count))
-
- def test_lsn_port_update(self):
- self._test_lsn_port_update()
-
- def test_lsn_port_update_dhcp_meta(self):
- self._test_lsn_port_update(mock.ANY, mock.ANY)
-
- def test_lsn_port_update_dhcp_and_nometa(self):
- self._test_lsn_port_update(mock.ANY, None)
-
- def test_lsn_port_update_nodhcp_and_nmeta(self):
- self._test_lsn_port_update(None, mock.ANY)
-
- def test_lsn_port_update_raise_error(self):
- self.mock_lsn_api.lsn_port_host_entries_update.side_effect = (
- exception.NsxApiException)
- self.assertRaises(p_exc.PortConfigurationError,
- self.manager.lsn_port_update,
- mock.ANY, mock.ANY, mock.ANY, mock.ANY)
-
-
-class PersistentLsnManagerTestCase(testlib_api.SqlTestCase):
-
- def setUp(self):
- super(PersistentLsnManagerTestCase, self).setUp()
- self.net_id = 'foo_network_id'
- self.sub_id = 'foo_subnet_id'
- self.port_id = 'foo_port_id'
- self.lsn_id = 'foo_lsn_id'
- self.mac = 'aa:bb:cc:dd:ee:ff'
- self.lsn_port_id = 'foo_lsn_port_id'
- self.tenant_id = 'foo_tenant_id'
- nsx.register_dhcp_opts(cfg)
- nsx.register_metadata_opts(cfg)
- lsn_man.register_lsn_opts(cfg)
- self.manager = lsn_man.PersistentLsnManager(mock.Mock())
- self.context = context.get_admin_context()
- self.mock_lsn_api_p = mock.patch.object(lsn_man, 'lsn_api')
- self.mock_lsn_api = self.mock_lsn_api_p.start()
-
- def test_lsn_get(self):
- lsn_db.lsn_add(self.context, self.net_id, self.lsn_id)
- result = self.manager.lsn_get(self.context, self.net_id)
- self.assertEqual(self.lsn_id, result)
-
- def test_lsn_get_raise_not_found(self):
- self.assertRaises(p_exc.LsnNotFound,
- self.manager.lsn_get, self.context, self.net_id)
-
- def test_lsn_get_silent_not_found(self):
- result = self.manager.lsn_get(
- self.context, self.net_id, raise_on_err=False)
- self.assertIsNone(result)
-
- def test_lsn_get_sync_on_missing(self):
- cfg.CONF.set_override('sync_on_missing_data', True, 'NSX_LSN')
- self.manager = lsn_man.PersistentLsnManager(mock.Mock())
- with mock.patch.object(self.manager, 'lsn_save') as f:
- self.manager.lsn_get(self.context, self.net_id, raise_on_err=True)
- self.assertTrue(self.mock_lsn_api.lsn_for_network_get.call_count)
- self.assertTrue(f.call_count)
-
- def test_lsn_save(self):
- self.manager.lsn_save(self.context, self.net_id, self.lsn_id)
- result = self.manager.lsn_get(self.context, self.net_id)
- self.assertEqual(self.lsn_id, result)
-
- def test_lsn_create(self):
- self.mock_lsn_api.lsn_for_network_create.return_value = self.lsn_id
- with mock.patch.object(self.manager, 'lsn_save') as f:
- result = self.manager.lsn_create(self.context, self.net_id)
- self.assertTrue(
- self.mock_lsn_api.lsn_for_network_create.call_count)
- self.assertTrue(f.call_count)
- self.assertEqual(self.lsn_id, result)
-
- def test_lsn_create_failure(self):
- with mock.patch.object(
- self.manager, 'lsn_save',
- side_effect=p_exc.NsxPluginException(err_msg='')):
- self.assertRaises(p_exc.NsxPluginException,
- self.manager.lsn_create,
- self.context, self.net_id)
- self.assertTrue(self.mock_lsn_api.lsn_delete.call_count)
-
- def test_lsn_delete(self):
- self.mock_lsn_api.lsn_for_network_create.return_value = self.lsn_id
- self.manager.lsn_create(self.context, self.net_id)
- self.manager.lsn_delete(self.context, self.lsn_id)
- self.assertIsNone(self.manager.lsn_get(
- self.context, self.net_id, raise_on_err=False))
-
- def test_lsn_delete_not_existent(self):
- self.manager.lsn_delete(self.context, self.lsn_id)
- self.assertTrue(self.mock_lsn_api.lsn_delete.call_count)
-
- def test_lsn_port_get(self):
- lsn_db.lsn_add(self.context, self.net_id, self.lsn_id)
- lsn_db.lsn_port_add_for_lsn(self.context, self.lsn_port_id,
- self.sub_id, self.mac, self.lsn_id)
- res = self.manager.lsn_port_get(self.context, self.net_id, self.sub_id)
- self.assertEqual((self.lsn_id, self.lsn_port_id), res)
-
- def test_lsn_port_get_raise_not_found(self):
- self.assertRaises(p_exc.LsnPortNotFound,
- self.manager.lsn_port_get,
- self.context, self.net_id, self.sub_id)
-
- def test_lsn_port_get_silent_not_found(self):
- result = self.manager.lsn_port_get(
- self.context, self.net_id, self.sub_id, raise_on_err=False)
- self.assertEqual((None, None), result)
-
- def test_lsn_port_get_sync_on_missing(self):
- return
- cfg.CONF.set_override('sync_on_missing_data', True, 'NSX_LSN')
- self.manager = lsn_man.PersistentLsnManager(mock.Mock())
- self.mock_lsn_api.lsn_for_network_get.return_value = self.lsn_id
- self.mock_lsn_api.lsn_port_by_subnet_get.return_value = (
- self.lsn_id, self.lsn_port_id)
- with mock.patch.object(self.manager, 'lsn_save') as f:
- with mock.patch.object(self.manager, 'lsn_port_save') as g:
- self.manager.lsn_port_get(
- self.context, self.net_id, self.sub_id)
- self.assertTrue(
- self.mock_lsn_api.lsn_port_by_subnet_get.call_count)
- self.assertTrue(
- self.mock_lsn_api.lsn_port_info_get.call_count)
- self.assertTrue(f.call_count)
- self.assertTrue(g.call_count)
-
- def test_lsn_port_get_by_mac(self):
- lsn_db.lsn_add(self.context, self.net_id, self.lsn_id)
- lsn_db.lsn_port_add_for_lsn(self.context, self.lsn_port_id,
- self.sub_id, self.mac, self.lsn_id)
- res = self.manager.lsn_port_get_by_mac(
- self.context, self.net_id, self.mac)
- self.assertEqual((self.lsn_id, self.lsn_port_id), res)
-
- def test_lsn_port_get_by_mac_raise_not_found(self):
- self.assertRaises(p_exc.LsnPortNotFound,
- self.manager.lsn_port_get_by_mac,
- self.context, self.net_id, self.sub_id)
-
- def test_lsn_port_get_by_mac_silent_not_found(self):
- result = self.manager.lsn_port_get_by_mac(
- self.context, self.net_id, self.sub_id, raise_on_err=False)
- self.assertEqual((None, None), result)
-
- def test_lsn_port_create(self):
- lsn_db.lsn_add(self.context, self.net_id, self.lsn_id)
- self.mock_lsn_api.lsn_port_create.return_value = self.lsn_port_id
- subnet = {'subnet_id': self.sub_id, 'mac_address': self.mac}
- with mock.patch.object(self.manager, 'lsn_port_save') as f:
- result = self.manager.lsn_port_create(
- self.context, self.net_id, subnet)
- self.assertTrue(
- self.mock_lsn_api.lsn_port_create.call_count)
- self.assertTrue(f.call_count)
- self.assertEqual(self.lsn_port_id, result)
-
- def test_lsn_port_create_failure(self):
- subnet = {'subnet_id': self.sub_id, 'mac_address': self.mac}
- with mock.patch.object(
- self.manager, 'lsn_port_save',
- side_effect=p_exc.NsxPluginException(err_msg='')):
- self.assertRaises(p_exc.NsxPluginException,
- self.manager.lsn_port_create,
- self.context, self.net_id, subnet)
- self.assertTrue(self.mock_lsn_api.lsn_port_delete.call_count)
-
- def test_lsn_port_delete(self):
- lsn_db.lsn_add(self.context, self.net_id, self.lsn_id)
- lsn_db.lsn_port_add_for_lsn(self.context, self.lsn_port_id,
- self.sub_id, self.mac, self.lsn_id)
- self.manager.lsn_port_delete(
- self.context, self.lsn_id, self.lsn_port_id)
- self.assertEqual((None, None), self.manager.lsn_port_get(
- self.context, self.lsn_id, self.sub_id, raise_on_err=False))
-
- def test_lsn_port_delete_not_existent(self):
- self.manager.lsn_port_delete(
- self.context, self.lsn_id, self.lsn_port_id)
- self.assertTrue(self.mock_lsn_api.lsn_port_delete.call_count)
-
- def test_lsn_port_save(self):
- self.manager.lsn_save(self.context, self.net_id, self.lsn_id)
- self.manager.lsn_port_save(self.context, self.lsn_port_id,
- self.sub_id, self.mac, self.lsn_id)
- result = self.manager.lsn_port_get(
- self.context, self.net_id, self.sub_id, raise_on_err=False)
- self.assertEqual((self.lsn_id, self.lsn_port_id), result)
-
-
-class DhcpAgentNotifyAPITestCase(base.BaseTestCase):
-
- def setUp(self):
- super(DhcpAgentNotifyAPITestCase, self).setUp()
- self.notifier = nsx.DhcpAgentNotifyAPI(mock.Mock(), mock.Mock())
- self.plugin = self.notifier.plugin
- self.lsn_manager = self.notifier.lsn_manager
-
- def _test_notify_port_update(
- self, ports, expected_count, expected_args=None):
- port = {
- 'id': 'foo_port_id',
- 'network_id': 'foo_network_id',
- 'fixed_ips': [{'subnet_id': 'foo_subnet_id'}]
- }
- self.notifier.plugin.get_ports.return_value = ports
- self.notifier.notify(mock.ANY, {'port': port}, 'port.update.end')
- self.lsn_manager.lsn_port_update.assert_has_calls(expected_args)
-
- def test_notify_ports_update_no_ports(self):
- self._test_notify_port_update(None, 0, [])
- self._test_notify_port_update([], 0, [])
-
- def test_notify_ports_update_one_port(self):
- ports = [{
- 'fixed_ips': [{'subnet_id': 'foo_subnet_id',
- 'ip_address': '1.2.3.4'}],
- 'device_id': 'foo_device_id',
- 'device_owner': 'foo_device_owner',
- 'mac_address': 'fa:16:3e:da:1d:46'
- }]
- call_args = mock.call(
- mock.ANY, 'foo_network_id', 'foo_subnet_id',
- dhcp=[{'ip_address': '1.2.3.4',
- 'mac_address': 'fa:16:3e:da:1d:46'}],
- meta=[{'instance_id': 'foo_device_id',
- 'ip_address': '1.2.3.4'}])
- self._test_notify_port_update(ports, 1, call_args)
-
- def test_notify_ports_update_ports_with_empty_device_id(self):
- ports = [{
- 'fixed_ips': [{'subnet_id': 'foo_subnet_id',
- 'ip_address': '1.2.3.4'}],
- 'device_id': '',
- 'device_owner': 'foo_device_owner',
- 'mac_address': 'fa:16:3e:da:1d:46'
- }]
- call_args = mock.call(
- mock.ANY, 'foo_network_id', 'foo_subnet_id',
- dhcp=[{'ip_address': '1.2.3.4',
- 'mac_address': 'fa:16:3e:da:1d:46'}],
- meta=[]
- )
- self._test_notify_port_update(ports, 1, call_args)
-
- def test_notify_ports_update_ports_with_no_fixed_ips(self):
- ports = [{
- 'fixed_ips': [],
- 'device_id': 'foo_device_id',
- 'device_owner': 'foo_device_owner',
- 'mac_address': 'fa:16:3e:da:1d:46'
- }]
- call_args = mock.call(
- mock.ANY, 'foo_network_id', 'foo_subnet_id', dhcp=[], meta=[])
- self._test_notify_port_update(ports, 1, call_args)
-
- def test_notify_ports_update_ports_with_no_fixed_ips_and_no_device(self):
- ports = [{
- 'fixed_ips': [],
- 'device_id': '',
- 'device_owner': 'foo_device_owner',
- 'mac_address': 'fa:16:3e:da:1d:46'
- }]
- call_args = mock.call(
- mock.ANY, 'foo_network_id', 'foo_subnet_id', dhcp=[], meta=[])
- self._test_notify_port_update(ports, 0, call_args)
-
- def test_notify_ports_update_with_special_ports(self):
- ports = [{'fixed_ips': [],
- 'device_id': '',
- 'device_owner': n_consts.DEVICE_OWNER_DHCP,
- 'mac_address': 'fa:16:3e:da:1d:46'},
- {'fixed_ips': [{'subnet_id': 'foo_subnet_id',
- 'ip_address': '1.2.3.4'}],
- 'device_id': 'foo_device_id',
- 'device_owner': n_consts.DEVICE_OWNER_ROUTER_GW,
- 'mac_address': 'fa:16:3e:da:1d:46'}]
- call_args = mock.call(
- mock.ANY, 'foo_network_id', 'foo_subnet_id', dhcp=[], meta=[])
- self._test_notify_port_update(ports, 0, call_args)
-
- def test_notify_ports_update_many_ports(self):
- ports = [{'fixed_ips': [],
- 'device_id': '',
- 'device_owner': 'foo_device_owner',
- 'mac_address': 'fa:16:3e:da:1d:46'},
- {'fixed_ips': [{'subnet_id': 'foo_subnet_id',
- 'ip_address': '1.2.3.4'}],
- 'device_id': 'foo_device_id',
- 'device_owner': 'foo_device_owner',
- 'mac_address': 'fa:16:3e:da:1d:46'}]
- call_args = mock.call(
- mock.ANY, 'foo_network_id', 'foo_subnet_id',
- dhcp=[{'ip_address': '1.2.3.4',
- 'mac_address': 'fa:16:3e:da:1d:46'}],
- meta=[{'instance_id': 'foo_device_id',
- 'ip_address': '1.2.3.4'}])
- self._test_notify_port_update(ports, 1, call_args)
-
- def _test_notify_subnet_action(self, action):
- with mock.patch.object(self.notifier, '_subnet_%s' % action) as f:
- self.notifier._handle_subnet_dhcp_access[action] = f
- subnet = {'subnet': mock.ANY}
- self.notifier.notify(
- mock.ANY, subnet, 'subnet.%s.end' % action)
- f.assert_called_once_with(mock.ANY, subnet)
-
- def test_notify_subnet_create(self):
- self._test_notify_subnet_action('create')
-
- def test_notify_subnet_update(self):
- self._test_notify_subnet_action('update')
-
- def test_notify_subnet_delete(self):
- self._test_notify_subnet_action('delete')
-
- def _test_subnet_create(self, enable_dhcp, exc=None,
- exc_obj=None, call_notify=True):
- subnet = {
- 'id': 'foo_subnet_id',
- 'enable_dhcp': enable_dhcp,
- 'network_id': 'foo_network_id',
- 'tenant_id': 'foo_tenant_id',
- 'cidr': '0.0.0.0/0'
- }
- if exc:
- self.plugin.create_port.side_effect = exc_obj or exc
- self.assertRaises(exc,
- self.notifier.notify,
- mock.ANY,
- {'subnet': subnet},
- 'subnet.create.end')
- self.plugin.delete_subnet.assert_called_with(
- mock.ANY, subnet['id'])
- else:
- if call_notify:
- self.notifier.notify(
- mock.ANY, {'subnet': subnet}, 'subnet.create.end')
- if enable_dhcp:
- dhcp_port = {
- 'name': '',
- 'admin_state_up': True,
- 'network_id': 'foo_network_id',
- 'tenant_id': 'foo_tenant_id',
- 'device_owner': n_consts.DEVICE_OWNER_DHCP,
- 'mac_address': mock.ANY,
- 'fixed_ips': [{'subnet_id': 'foo_subnet_id'}],
- 'device_id': ''
- }
- self.plugin.create_port.assert_called_once_with(
- mock.ANY, {'port': dhcp_port})
- else:
- self.assertEqual(0, self.plugin.create_port.call_count)
-
- def test_subnet_create_enabled_dhcp(self):
- self._test_subnet_create(True)
-
- def test_subnet_create_disabled_dhcp(self):
- self._test_subnet_create(False)
-
- def test_subnet_create_raise_port_config_error(self):
- with mock.patch.object(nsx.db_base_plugin_v2.NeutronDbPluginV2,
- 'delete_port') as d:
- self._test_subnet_create(
- True,
- exc=n_exc.Conflict,
- exc_obj=p_exc.PortConfigurationError(lsn_id='foo_lsn_id',
- net_id='foo_net_id',
- port_id='foo_port_id'))
- d.assert_called_once_with(self.plugin, mock.ANY, 'foo_port_id')
-
- def test_subnet_update(self):
- subnet = {
- 'id': 'foo_subnet_id',
- 'network_id': 'foo_network_id',
- }
- self.lsn_manager.lsn_port_get.return_value = ('foo_lsn_id',
- 'foo_lsn_port_id')
- self.notifier.notify(
- mock.ANY, {'subnet': subnet}, 'subnet.update.end')
- self.lsn_manager.lsn_port_dhcp_configure.assert_called_once_with(
- mock.ANY, 'foo_lsn_id', 'foo_lsn_port_id', subnet)
-
- def test_subnet_update_raise_lsn_not_found(self):
- subnet = {
- 'id': 'foo_subnet_id',
- 'network_id': 'foo_network_id',
- }
- self.lsn_manager.lsn_port_get.side_effect = (
- p_exc.LsnNotFound(entity='network',
- entity_id=subnet['network_id']))
- self.assertRaises(p_exc.LsnNotFound,
- self.notifier.notify,
- mock.ANY, {'subnet': subnet}, 'subnet.update.end')
-
- def _test_subnet_update_lsn_port_not_found(self, dhcp_port):
- subnet = {
- 'id': 'foo_subnet_id',
- 'enable_dhcp': True,
- 'network_id': 'foo_network_id',
- 'tenant_id': 'foo_tenant_id'
- }
- self.lsn_manager.lsn_port_get.side_effect = (
- p_exc.LsnPortNotFound(lsn_id='foo_lsn_id',
- entity='subnet',
- entity_id=subnet['id']))
- self.notifier.plugin.get_ports.return_value = dhcp_port
- count = 0 if dhcp_port is None else 1
- with mock.patch.object(nsx, 'handle_port_dhcp_access') as h:
- self.notifier.notify(
- mock.ANY, {'subnet': subnet}, 'subnet.update.end')
- self.assertEqual(count, h.call_count)
- if not dhcp_port:
- self._test_subnet_create(enable_dhcp=True,
- exc=None, call_notify=False)
-
- def test_subnet_update_lsn_port_not_found_without_dhcp_port(self):
- self._test_subnet_update_lsn_port_not_found(None)
-
- def test_subnet_update_lsn_port_not_found_with_dhcp_port(self):
- self._test_subnet_update_lsn_port_not_found([mock.ANY])
-
- def _test_subnet_delete(self, ports=None):
- subnet = {
- 'id': 'foo_subnet_id',
- 'network_id': 'foo_network_id',
- 'cidr': '0.0.0.0/0'
- }
- self.plugin.get_ports.return_value = ports
- self.notifier.notify(mock.ANY, {'subnet': subnet}, 'subnet.delete.end')
- filters = {
- 'network_id': [subnet['network_id']],
- 'device_owner': [n_consts.DEVICE_OWNER_DHCP]
- }
- self.plugin.get_ports.assert_called_once_with(
- mock.ANY, filters=filters)
- if ports:
- self.plugin.delete_port.assert_called_once_with(
- mock.ANY, ports[0]['id'])
- else:
- self.assertEqual(0, self.plugin.delete_port.call_count)
-
- def test_subnet_delete_enabled_dhcp_no_ports(self):
- self._test_subnet_delete()
-
- def test_subnet_delete_enabled_dhcp_with_dhcp_port(self):
- self._test_subnet_delete([{'id': 'foo_port_id'}])
-
-
-class DhcpTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(DhcpTestCase, self).setUp()
- self.plugin = mock.Mock()
- self.plugin.lsn_manager = mock.Mock()
-
- def test_handle_create_network(self):
- network = {'id': 'foo_network_id'}
- nsx.handle_network_dhcp_access(
- self.plugin, mock.ANY, network, 'create_network')
- self.plugin.lsn_manager.lsn_create.assert_called_once_with(
- mock.ANY, network['id'])
-
- def test_handle_create_network_router_external(self):
- network = {'id': 'foo_network_id', 'router:external': True}
- nsx.handle_network_dhcp_access(
- self.plugin, mock.ANY, network, 'create_network')
- self.assertFalse(self.plugin.lsn_manager.lsn_create.call_count)
-
- def test_handle_delete_network(self):
- network_id = 'foo_network_id'
- self.plugin.lsn_manager.lsn_delete_by_network.return_value = (
- 'foo_lsn_id')
- nsx.handle_network_dhcp_access(
- self.plugin, mock.ANY, network_id, 'delete_network')
- self.plugin.lsn_manager.lsn_delete_by_network.assert_called_once_with(
- mock.ANY, 'foo_network_id')
-
- def _test_handle_create_dhcp_owner_port(self, exc=None):
- subnet = {
- 'cidr': '0.0.0.0/0',
- 'id': 'foo_subnet_id'
- }
- port = {
- 'id': 'foo_port_id',
- 'device_owner': n_consts.DEVICE_OWNER_DHCP,
- 'mac_address': 'aa:bb:cc:dd:ee:ff',
- 'network_id': 'foo_network_id',
- 'fixed_ips': [{'subnet_id': subnet['id']}]
- }
- expected_data = {
- 'subnet_id': subnet['id'],
- 'ip_address': subnet['cidr'],
- 'mac_address': port['mac_address']
- }
- self.plugin.get_subnet.return_value = subnet
- if exc is None:
- nsx.handle_port_dhcp_access(
- self.plugin, mock.ANY, port, 'create_port')
- (self.plugin.lsn_manager.lsn_port_dhcp_setup.
- assert_called_once_with(mock.ANY, port['network_id'],
- port['id'], expected_data, subnet))
- else:
- self.plugin.lsn_manager.lsn_port_dhcp_setup.side_effect = exc
- self.assertRaises(n_exc.NeutronException,
- nsx.handle_port_dhcp_access,
- self.plugin, mock.ANY, port, 'create_port')
-
- def test_handle_create_dhcp_owner_port(self):
- self._test_handle_create_dhcp_owner_port()
-
- def test_handle_create_dhcp_owner_port_raise_port_config_error(self):
- config_error = p_exc.PortConfigurationError(lsn_id='foo_lsn_id',
- net_id='foo_net_id',
- port_id='foo_port_id')
- self._test_handle_create_dhcp_owner_port(exc=config_error)
-
- def test_handle_delete_dhcp_owner_port(self):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': n_consts.DEVICE_OWNER_DHCP,
- 'network_id': 'foo_network_id',
- 'fixed_ips': [],
- 'mac_address': 'aa:bb:cc:dd:ee:ff'
- }
- nsx.handle_port_dhcp_access(self.plugin, mock.ANY, port, 'delete_port')
- self.plugin.lsn_manager.lsn_port_dispose.assert_called_once_with(
- mock.ANY, port['network_id'], port['mac_address'])
-
- def _test_handle_user_port(self, action, handler):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': 'foo_device_owner',
- 'network_id': 'foo_network_id',
- 'mac_address': 'aa:bb:cc:dd:ee:ff',
- 'fixed_ips': [{'subnet_id': 'foo_subnet_id',
- 'ip_address': '1.2.3.4'}]
- }
- expected_data = {
- 'ip_address': '1.2.3.4',
- 'mac_address': 'aa:bb:cc:dd:ee:ff'
- }
- self.plugin.get_subnet.return_value = {'enable_dhcp': True}
- nsx.handle_port_dhcp_access(self.plugin, mock.ANY, port, action)
- handler.assert_called_once_with(
- mock.ANY, port['network_id'], 'foo_subnet_id', expected_data)
-
- def test_handle_create_user_port(self):
- self._test_handle_user_port(
- 'create_port', self.plugin.lsn_manager.lsn_port_dhcp_host_add)
-
- def test_handle_delete_user_port(self):
- self._test_handle_user_port(
- 'delete_port', self.plugin.lsn_manager.lsn_port_dhcp_host_remove)
-
- def _test_handle_user_port_disabled_dhcp(self, action, handler):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': 'foo_device_owner',
- 'network_id': 'foo_network_id',
- 'mac_address': 'aa:bb:cc:dd:ee:ff',
- 'fixed_ips': [{'subnet_id': 'foo_subnet_id',
- 'ip_address': '1.2.3.4'}]
- }
- self.plugin.get_subnet.return_value = {'enable_dhcp': False}
- nsx.handle_port_dhcp_access(self.plugin, mock.ANY, port, action)
- self.assertEqual(0, handler.call_count)
-
- def test_handle_create_user_port_disabled_dhcp(self):
- self._test_handle_user_port_disabled_dhcp(
- 'create_port', self.plugin.lsn_manager.lsn_port_dhcp_host_add)
-
- def test_handle_delete_user_port_disabled_dhcp(self):
- self._test_handle_user_port_disabled_dhcp(
- 'delete_port', self.plugin.lsn_manager.lsn_port_dhcp_host_remove)
-
- def _test_handle_user_port_no_fixed_ips(self, action, handler):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': 'foo_device_owner',
- 'network_id': 'foo_network_id',
- 'fixed_ips': []
- }
- nsx.handle_port_dhcp_access(self.plugin, mock.ANY, port, action)
- self.assertEqual(0, handler.call_count)
-
- def test_handle_create_user_port_no_fixed_ips(self):
- self._test_handle_user_port_no_fixed_ips(
- 'create_port', self.plugin.lsn_manager.lsn_port_dhcp_host_add)
-
- def test_handle_delete_user_port_no_fixed_ips(self):
- self._test_handle_user_port_no_fixed_ips(
- 'delete_port', self.plugin.lsn_manager.lsn_port_dhcp_host_remove)
-
-
-class MetadataTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(MetadataTestCase, self).setUp()
- self.plugin = mock.Mock()
- self.plugin.lsn_manager = mock.Mock()
-
- def _test_handle_port_metadata_access_special_owners(
- self, owner, dev_id='foo_device_id', ips=None):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': owner,
- 'device_id': dev_id,
- 'fixed_ips': ips or []
- }
- nsx.handle_port_metadata_access(self.plugin, mock.ANY, port, mock.ANY)
- self.assertFalse(
- self.plugin.lsn_manager.lsn_port_meta_host_add.call_count)
- self.assertFalse(
- self.plugin.lsn_manager.lsn_port_meta_host_remove.call_count)
-
- def test_handle_port_metadata_access_external_network(self):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': 'foo_device_owner',
- 'device_id': 'foo_device_id',
- 'network_id': 'foo_network_id',
- 'fixed_ips': [{'subnet_id': 'foo_subnet'}]
- }
- self.plugin.get_network.return_value = {'router:external': True}
- nsx.handle_port_metadata_access(self.plugin, mock.ANY, port, mock.ANY)
- self.assertFalse(
- self.plugin.lsn_manager.lsn_port_meta_host_add.call_count)
- self.assertFalse(
- self.plugin.lsn_manager.lsn_port_meta_host_remove.call_count)
-
- def test_handle_port_metadata_access_dhcp_port(self):
- self._test_handle_port_metadata_access_special_owners(
- n_consts.DEVICE_OWNER_DHCP, [{'subnet_id': 'foo_subnet'}])
-
- def test_handle_port_metadata_access_router_port(self):
- self._test_handle_port_metadata_access_special_owners(
- n_consts.DEVICE_OWNER_ROUTER_INTF, [{'subnet_id': 'foo_subnet'}])
-
- def test_handle_port_metadata_access_no_device_id(self):
- self._test_handle_port_metadata_access_special_owners(
- n_consts.DEVICE_OWNER_DHCP, '')
-
- def test_handle_port_metadata_access_no_fixed_ips(self):
- self._test_handle_port_metadata_access_special_owners(
- 'foo', 'foo', None)
-
- def _test_handle_port_metadata_access(self, is_delete, raise_exc=False):
- port = {
- 'id': 'foo_port_id',
- 'device_owner': 'foo_device_id',
- 'network_id': 'foo_network_id',
- 'device_id': 'foo_device_id',
- 'tenant_id': 'foo_tenant_id',
- 'fixed_ips': [
- {'subnet_id': 'foo_subnet_id', 'ip_address': '1.2.3.4'}
- ]
- }
- meta = {
- 'instance_id': port['device_id'],
- 'tenant_id': port['tenant_id'],
- 'ip_address': port['fixed_ips'][0]['ip_address']
- }
- self.plugin.get_network.return_value = {'router:external': False}
- if is_delete:
- mock_func = self.plugin.lsn_manager.lsn_port_meta_host_remove
- else:
- mock_func = self.plugin.lsn_manager.lsn_port_meta_host_add
- if raise_exc:
- mock_func.side_effect = p_exc.PortConfigurationError(
- lsn_id='foo_lsn_id', net_id='foo_net_id', port_id=None)
- with mock.patch.object(nsx.db_base_plugin_v2.NeutronDbPluginV2,
- 'delete_port') as d:
- self.assertRaises(p_exc.PortConfigurationError,
- nsx.handle_port_metadata_access,
- self.plugin, mock.ANY, port,
- is_delete=is_delete)
- if not is_delete:
- d.assert_called_once_with(mock.ANY, mock.ANY, port['id'])
- else:
- self.assertFalse(d.call_count)
- else:
- nsx.handle_port_metadata_access(
- self.plugin, mock.ANY, port, is_delete=is_delete)
- mock_func.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY, meta)
-
- def test_handle_port_metadata_access_on_delete_true(self):
- self._test_handle_port_metadata_access(True)
-
- def test_handle_port_metadata_access_on_delete_false(self):
- self._test_handle_port_metadata_access(False)
-
- def test_handle_port_metadata_access_on_delete_true_raise(self):
- self._test_handle_port_metadata_access(True, raise_exc=True)
-
- def test_handle_port_metadata_access_on_delete_false_raise(self):
- self._test_handle_port_metadata_access(False, raise_exc=True)
-
- def _test_handle_router_metadata_access(
- self, is_port_found, raise_exc=False):
- subnet = {
- 'id': 'foo_subnet_id',
- 'network_id': 'foo_network_id'
- }
- interface = {
- 'subnet_id': subnet['id'],
- 'port_id': 'foo_port_id'
- }
- mock_func = self.plugin.lsn_manager.lsn_metadata_configure
- if not is_port_found:
- self.plugin.get_port.side_effect = n_exc.NotFound
- if raise_exc:
- with mock.patch.object(nsx.l3_db.L3_NAT_db_mixin,
- 'remove_router_interface') as d:
- mock_func.side_effect = p_exc.NsxPluginException(err_msg='')
- self.assertRaises(p_exc.NsxPluginException,
- nsx.handle_router_metadata_access,
- self.plugin, mock.ANY, 'foo_router_id',
- interface)
- d.assert_called_once_with(mock.ANY, mock.ANY, 'foo_router_id',
- interface)
- else:
- nsx.handle_router_metadata_access(
- self.plugin, mock.ANY, 'foo_router_id', interface)
- mock_func.assert_called_once_with(
- mock.ANY, subnet['id'], is_port_found)
-
- def test_handle_router_metadata_access_add_interface(self):
- self._test_handle_router_metadata_access(True)
-
- def test_handle_router_metadata_access_delete_interface(self):
- self._test_handle_router_metadata_access(False)
-
- def test_handle_router_metadata_access_raise_error_on_add(self):
- self._test_handle_router_metadata_access(True, raise_exc=True)
-
- def test_handle_router_metadata_access_raise_error_on_delete(self):
- self._test_handle_router_metadata_access(True, raise_exc=False)
+++ /dev/null
-# Copyright 2013 VMware, 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 fixtures
-
-import mock
-from oslo_config import cfg
-
-from neutron import manager
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.api_client import client
-from neutron.plugins.vmware.api_client import version
-from neutron.plugins.vmware.common import config # noqa
-from neutron.plugins.vmware.common import exceptions
-from neutron.plugins.vmware.common import sync
-from neutron.plugins.vmware import nsx_cluster
-from neutron.plugins.vmware.nsxlib import lsn as lsnlib
-from neutron.tests import base
-from neutron.tests.unit import vmware
-
-BASE_CONF_PATH = vmware.get_fake_conf('neutron.conf.test')
-NSX_INI_PATH = vmware.get_fake_conf('nsx.ini.basic.test')
-NSX_INI_FULL_PATH = vmware.get_fake_conf('nsx.ini.full.test')
-NSX_INI_AGENTLESS_PATH = vmware.get_fake_conf('nsx.ini.agentless.test')
-NSX_INI_COMBINED_PATH = vmware.get_fake_conf('nsx.ini.combined.test')
-NVP_INI_DEPR_PATH = vmware.get_fake_conf('nvp.ini.full.test')
-
-
-class NSXClusterTest(base.BaseTestCase):
-
- cluster_opts = {'default_tz_uuid': uuidutils.generate_uuid(),
- 'default_l2_gw_service_uuid': uuidutils.generate_uuid(),
- 'default_l2_gw_service_uuid': uuidutils.generate_uuid(),
- 'nsx_user': 'foo',
- 'nsx_password': 'bar',
- 'http_timeout': 25,
- 'retries': 7,
- 'redirects': 23,
- 'default_interface_name': 'baz',
- 'nsx_controllers': ['1.1.1.1:443']}
-
- def test_create_cluster(self):
- cluster = nsx_cluster.NSXCluster(**self.cluster_opts)
- for (k, v) in self.cluster_opts.iteritems():
- self.assertEqual(v, getattr(cluster, k))
-
- def test_create_cluster_default_port(self):
- opts = self.cluster_opts.copy()
- opts['nsx_controllers'] = ['1.1.1.1']
- cluster = nsx_cluster.NSXCluster(**opts)
- for (k, v) in self.cluster_opts.iteritems():
- self.assertEqual(v, getattr(cluster, k))
-
- def test_create_cluster_missing_required_attribute_raises(self):
- opts = self.cluster_opts.copy()
- opts.pop('default_tz_uuid')
- self.assertRaises(exceptions.InvalidClusterConfiguration,
- nsx_cluster.NSXCluster, **opts)
-
-
-class ConfigurationTest(base.BaseTestCase):
-
- def setUp(self):
- super(ConfigurationTest, self).setUp()
- self.useFixture(fixtures.MonkeyPatch(
- 'neutron.manager.NeutronManager._instance',
- None))
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
- dhcp_periodic_p = mock.patch('neutron.db.agentschedulers_db.'
- 'DhcpAgentSchedulerDbMixin.'
- 'start_periodic_dhcp_agent_status_check')
- dhcp_periodic_p.start()
-
- def _assert_required_options(self, cluster):
- self.assertEqual(cluster.nsx_controllers, ['fake_1:443', 'fake_2:443'])
- self.assertEqual(cluster.default_tz_uuid, 'fake_tz_uuid')
- self.assertEqual(cluster.nsx_user, 'foo')
- self.assertEqual(cluster.nsx_password, 'bar')
-
- def _assert_extra_options(self, cluster):
- self.assertEqual(13, cluster.http_timeout)
- self.assertEqual(12, cluster.redirects)
- self.assertEqual(11, cluster.retries)
- self.assertEqual('whatever', cluster.default_l2_gw_service_uuid)
- self.assertEqual('whatever', cluster.default_l3_gw_service_uuid)
- self.assertEqual('whatever', cluster.default_interface_name)
-
- def test_load_plugin_with_full_options(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_FULL_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- plugin = manager.NeutronManager().get_plugin()
- cluster = plugin.cluster
- self._assert_required_options(cluster)
- self._assert_extra_options(cluster)
-
- def test_load_plugin_with_required_options_only(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- plugin = manager.NeutronManager().get_plugin()
- self._assert_required_options(plugin.cluster)
-
- def test_defaults(self):
- self.assertEqual(5000, cfg.CONF.NSX.max_lp_per_bridged_ls)
- self.assertEqual(256, cfg.CONF.NSX.max_lp_per_overlay_ls)
- self.assertEqual(10, cfg.CONF.NSX.concurrent_connections)
- self.assertEqual('access_network', cfg.CONF.NSX.metadata_mode)
- self.assertEqual('stt', cfg.CONF.NSX.default_transport_type)
- self.assertEqual('service', cfg.CONF.NSX.replication_mode)
-
- self.assertIsNone(cfg.CONF.default_tz_uuid)
- self.assertEqual('admin', cfg.CONF.nsx_user)
- self.assertEqual('admin', cfg.CONF.nsx_password)
- self.assertEqual(75, cfg.CONF.http_timeout)
- self.assertEqual(2, cfg.CONF.retries)
- self.assertEqual(2, cfg.CONF.redirects)
- self.assertIsNone(cfg.CONF.nsx_controllers)
- self.assertIsNone(cfg.CONF.default_l3_gw_service_uuid)
- self.assertIsNone(cfg.CONF.default_l2_gw_service_uuid)
- self.assertEqual('breth0', cfg.CONF.default_interface_name)
- self.assertEqual(900, cfg.CONF.conn_idle_timeout)
-
- def test_load_api_extensions(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_FULL_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- # Load the configuration, and initialize the plugin
- manager.NeutronManager().get_plugin()
- self.assertIn('extensions', cfg.CONF.api_extensions_path)
-
- def test_agentless_extensions(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_AGENTLESS_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- self.assertEqual(config.AgentModes.AGENTLESS,
- cfg.CONF.NSX.agent_mode)
- # The version returned from NSX does not really matter here
- with mock.patch.object(client.NsxApiClient,
- 'get_version',
- return_value=version.Version("9.9")):
- with mock.patch.object(lsnlib,
- 'service_cluster_exists',
- return_value=True):
- plugin = manager.NeutronManager().get_plugin()
- self.assertNotIn('agent',
- plugin.supported_extension_aliases)
- self.assertNotIn('dhcp_agent_scheduler',
- plugin.supported_extension_aliases)
- self.assertNotIn('lsn',
- plugin.supported_extension_aliases)
-
- def test_agentless_extensions_version_fail(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_AGENTLESS_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- self.assertEqual(config.AgentModes.AGENTLESS,
- cfg.CONF.NSX.agent_mode)
- with mock.patch.object(client.NsxApiClient,
- 'get_version',
- return_value=version.Version("3.2")):
- self.assertRaises(exceptions.NsxPluginException,
- manager.NeutronManager)
-
- def test_agentless_extensions_unmet_deps_fail(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_AGENTLESS_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- self.assertEqual(config.AgentModes.AGENTLESS,
- cfg.CONF.NSX.agent_mode)
- with mock.patch.object(client.NsxApiClient,
- 'get_version',
- return_value=version.Version("3.2")):
- with mock.patch.object(lsnlib,
- 'service_cluster_exists',
- return_value=False):
- self.assertRaises(exceptions.NsxPluginException,
- manager.NeutronManager)
-
- def test_agent_extensions(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_FULL_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- self.assertEqual(config.AgentModes.AGENT,
- cfg.CONF.NSX.agent_mode)
- plugin = manager.NeutronManager().get_plugin()
- self.assertIn('agent',
- plugin.supported_extension_aliases)
- self.assertIn('dhcp_agent_scheduler',
- plugin.supported_extension_aliases)
-
- def test_combined_extensions(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NSX_INI_COMBINED_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- self.assertEqual(config.AgentModes.COMBINED,
- cfg.CONF.NSX.agent_mode)
- with mock.patch.object(client.NsxApiClient,
- 'get_version',
- return_value=version.Version("4.2")):
- with mock.patch.object(lsnlib,
- 'service_cluster_exists',
- return_value=True):
- plugin = manager.NeutronManager().get_plugin()
- self.assertIn('agent',
- plugin.supported_extension_aliases)
- self.assertIn('dhcp_agent_scheduler',
- plugin.supported_extension_aliases)
- self.assertIn('lsn',
- plugin.supported_extension_aliases)
-
-
-class OldNVPConfigurationTest(base.BaseTestCase):
-
- def setUp(self):
- super(OldNVPConfigurationTest, self).setUp()
- self.useFixture(fixtures.MonkeyPatch(
- 'neutron.manager.NeutronManager._instance',
- None))
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
- dhcp_periodic_p = mock.patch('neutron.db.agentschedulers_db.'
- 'DhcpAgentSchedulerDbMixin.'
- 'start_periodic_dhcp_agent_status_check')
- dhcp_periodic_p.start()
-
- def _assert_required_options(self, cluster):
- self.assertEqual(cluster.nsx_controllers, ['fake_1:443', 'fake_2:443'])
- self.assertEqual(cluster.nsx_user, 'foo')
- self.assertEqual(cluster.nsx_password, 'bar')
- self.assertEqual(cluster.default_tz_uuid, 'fake_tz_uuid')
-
- def test_load_plugin_with_deprecated_options(self):
- self.config_parse(args=['--config-file', BASE_CONF_PATH,
- '--config-file', NVP_INI_DEPR_PATH])
- cfg.CONF.set_override('core_plugin', vmware.PLUGIN_NAME)
- plugin = manager.NeutronManager().get_plugin()
- cluster = plugin.cluster
- # Verify old nvp_* params have been fully parsed
- self._assert_required_options(cluster)
- self.assertEqual(3, cluster.http_timeout)
- self.assertEqual(2, cluster.retries)
- self.assertEqual(2, cluster.redirects)
+++ /dev/null
-# Copyright (c) 2012 OpenStack Foundation.
-#
-# 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 contextlib
-import uuid
-
-import mock
-import netaddr
-from oslo_config import cfg
-from oslo_db import exception as db_exc
-from sqlalchemy import exc as sql_exc
-import webob.exc
-
-from neutron.api.v2 import attributes
-from neutron.common import constants
-from neutron.common import exceptions as ntn_exc
-import neutron.common.test_lib as test_lib
-from neutron import context
-from neutron.extensions import dvr
-from neutron.extensions import external_net
-from neutron.extensions import l3
-from neutron.extensions import l3_ext_gw_mode
-from neutron.extensions import portbindings
-from neutron.extensions import providernet as pnet
-from neutron.extensions import securitygroup as secgrp
-from neutron import manager
-from neutron.openstack.common import log
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.api_client import version as version_module
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import sync
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware.dbexts import db as nsx_db
-from neutron.plugins.vmware import nsxlib
-from neutron.tests.unit import _test_extension_portbindings as test_bindings
-import neutron.tests.unit.test_db_plugin as test_plugin
-import neutron.tests.unit.test_extension_ext_gw_mode as test_ext_gw_mode
-import neutron.tests.unit.test_extension_security_group as ext_sg
-import neutron.tests.unit.test_l3_plugin as test_l3_plugin
-from neutron.tests.unit import testlib_api
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.apiclient import fake
-
-LOG = log.getLogger(__name__)
-
-
-class NsxPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
-
- def _create_network(self, fmt, name, admin_state_up,
- arg_list=None, providernet_args=None, **kwargs):
- data = {'network': {'name': name,
- 'admin_state_up': admin_state_up,
- 'tenant_id': self._tenant_id}}
- # Fix to allow the router:external attribute and any other
- # attributes containing a colon to be passed with
- # a double underscore instead
- kwargs = dict((k.replace('__', ':'), v) for k, v in kwargs.items())
- if external_net.EXTERNAL in kwargs:
- arg_list = (external_net.EXTERNAL, ) + (arg_list or ())
-
- attrs = kwargs
- if providernet_args:
- attrs.update(providernet_args)
- for arg in (('admin_state_up', 'tenant_id', 'shared') +
- (arg_list or ())):
- # Arg must be present and not empty
- if kwargs.get(arg):
- data['network'][arg] = kwargs[arg]
- network_req = self.new_create_request('networks', data, fmt)
- if (kwargs.get('set_context') and 'tenant_id' in kwargs):
- # create a specific auth context for this request
- network_req.environ['neutron.context'] = context.Context(
- '', kwargs['tenant_id'])
- return network_req.get_response(self.api)
-
- def setUp(self,
- plugin=vmware.PLUGIN_NAME,
- ext_mgr=None,
- service_plugins=None):
- test_lib.test_config['config_files'] = [
- vmware.get_fake_conf('nsx.ini.test')]
- # mock api client
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsx = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- self.mock_instance = self.mock_nsx.start()
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
-
- # Emulate tests against NSX 2.x
- self.mock_instance.return_value.get_version.return_value = (
- version_module.Version("2.9"))
- self.mock_instance.return_value.request.side_effect = (
- self.fc.fake_request)
- super(NsxPluginV2TestCase, self).setUp(plugin=plugin,
- ext_mgr=ext_mgr)
- # Newly created port's status is always 'DOWN' till NSX wires them.
- self.port_create_status = constants.PORT_STATUS_DOWN
- cfg.CONF.set_override('metadata_mode', None, 'NSX')
- self.addCleanup(self.fc.reset_all)
-
-
-class TestBasicGet(test_plugin.TestBasicGet, NsxPluginV2TestCase):
- pass
-
-
-class TestV2HTTPResponse(test_plugin.TestV2HTTPResponse, NsxPluginV2TestCase):
- pass
-
-
-class TestPortsV2(NsxPluginV2TestCase,
- test_plugin.TestPortsV2,
- test_bindings.PortBindingsTestCase,
- test_bindings.PortBindingsHostTestCaseMixin,
- test_bindings.PortBindingsVnicTestCaseMixin):
-
- VIF_TYPE = portbindings.VIF_TYPE_OVS
- HAS_PORT_FILTER = True
-
- def test_exhaust_ports_overlay_network(self):
- cfg.CONF.set_override('max_lp_per_overlay_ls', 1, group='NSX')
- with self.network(name='testnet',
- arg_list=(pnet.NETWORK_TYPE,
- pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID)) as net:
- with self.subnet(network=net) as sub:
- with self.port(subnet=sub):
- # creating another port should see an exception
- self._create_port('json', net['network']['id'], 400)
-
- def test_exhaust_ports_bridged_network(self):
- cfg.CONF.set_override('max_lp_per_bridged_ls', 1, group="NSX")
- providernet_args = {pnet.NETWORK_TYPE: 'flat',
- pnet.PHYSICAL_NETWORK: 'tzuuid'}
- with self.network(name='testnet',
- providernet_args=providernet_args,
- arg_list=(pnet.NETWORK_TYPE,
- pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID)) as net:
- with self.subnet(network=net) as sub:
- with self.port(subnet=sub):
- with self.port(subnet=sub):
- plugin = manager.NeutronManager.get_plugin()
- ls = nsxlib.switch.get_lswitches(plugin.cluster,
- net['network']['id'])
- self.assertEqual(len(ls), 2)
-
- def test_update_port_delete_ip(self):
- # This test case overrides the default because the nsx plugin
- # implements port_security/security groups and it is not allowed
- # to remove an ip address from a port unless the security group
- # is first removed.
- with self.subnet() as subnet:
- with self.port(subnet=subnet) as port:
- data = {'port': {'admin_state_up': False,
- 'fixed_ips': [],
- secgrp.SECURITYGROUPS: []}}
- req = self.new_update_request('ports',
- data, port['port']['id'])
- res = self.deserialize('json', req.get_response(self.api))
- self.assertEqual(res['port']['admin_state_up'],
- data['port']['admin_state_up'])
- self.assertEqual(res['port']['fixed_ips'],
- data['port']['fixed_ips'])
-
- def test_create_port_name_exceeds_40_chars(self):
- name = 'this_is_a_port_whose_name_is_longer_than_40_chars'
- with self.port(name=name) as port:
- # Assert the neutron name is not truncated
- self.assertEqual(name, port['port']['name'])
-
- def _verify_no_orphan_left(self, net_id):
- # Verify no port exists on net
- # ie: cleanup on db was successful
- query_params = "network_id=%s" % net_id
- self._test_list_resources('port', [],
- query_params=query_params)
- # Also verify no orphan port was left on nsx
- # no port should be there at all
- self.assertFalse(self.fc._fake_lswitch_lport_dict)
-
- def test_create_port_nsx_error_no_orphan_left(self):
- with mock.patch.object(nsxlib.switch, 'create_lport',
- side_effect=api_exc.NsxApiException):
- with self.network() as net:
- net_id = net['network']['id']
- self._create_port(self.fmt, net_id,
- webob.exc.HTTPInternalServerError.code)
- self._verify_no_orphan_left(net_id)
-
- def test_create_port_neutron_error_no_orphan_left(self):
- with mock.patch.object(nsx_db, 'add_neutron_nsx_port_mapping',
- side_effect=ntn_exc.NeutronException):
- with self.network() as net:
- net_id = net['network']['id']
- self._create_port(self.fmt, net_id,
- webob.exc.HTTPInternalServerError.code)
- self._verify_no_orphan_left(net_id)
-
- def test_create_port_db_error_no_orphan_left(self):
- db_exception = db_exc.DBError(
- inner_exception=sql_exc.IntegrityError(mock.ANY,
- mock.ANY,
- mock.ANY))
- with mock.patch.object(nsx_db, 'add_neutron_nsx_port_mapping',
- side_effect=db_exception):
- with self.network() as net:
- with self.port(device_owner=constants.DEVICE_OWNER_DHCP):
- self._verify_no_orphan_left(net['network']['id'])
-
- def test_create_port_maintenance_returns_503(self):
- with self.network() as net:
- with mock.patch.object(nsxlib, 'do_request',
- side_effect=nsx_exc.MaintenanceInProgress):
- data = {'port': {'network_id': net['network']['id'],
- 'admin_state_up': False,
- 'fixed_ips': [],
- 'tenant_id': self._tenant_id}}
- plugin = manager.NeutronManager.get_plugin()
- with mock.patch.object(plugin, 'get_network',
- return_value=net['network']):
- port_req = self.new_create_request('ports', data, self.fmt)
- res = port_req.get_response(self.api)
- self.assertEqual(webob.exc.HTTPServiceUnavailable.code,
- res.status_int)
-
-
-class TestNetworksV2(test_plugin.TestNetworksV2, NsxPluginV2TestCase):
-
- def _test_create_bridge_network(self, vlan_id=0):
- net_type = 'vlan' if vlan_id else 'flat'
- name = 'bridge_net'
- expected = [('subnets', []), ('name', name), ('admin_state_up', True),
- ('status', 'ACTIVE'), ('shared', False),
- (pnet.NETWORK_TYPE, net_type),
- (pnet.PHYSICAL_NETWORK, 'tzuuid'),
- (pnet.SEGMENTATION_ID, vlan_id)]
- providernet_args = {pnet.NETWORK_TYPE: net_type,
- pnet.PHYSICAL_NETWORK: 'tzuuid'}
- if vlan_id:
- providernet_args[pnet.SEGMENTATION_ID] = vlan_id
- with self.network(name=name,
- providernet_args=providernet_args,
- arg_list=(pnet.NETWORK_TYPE,
- pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID)) as net:
- for k, v in expected:
- self.assertEqual(net['network'][k], v)
-
- def test_create_bridge_network(self):
- self._test_create_bridge_network()
-
- def test_create_bridge_vlan_network(self):
- self._test_create_bridge_network(vlan_id=123)
-
- def test_create_bridge_vlan_network_outofrange_returns_400(self):
- with testlib_api.ExpectedException(
- webob.exc.HTTPClientError) as ctx_manager:
- self._test_create_bridge_network(vlan_id=5000)
- self.assertEqual(ctx_manager.exception.code, 400)
-
- def test_list_networks_filter_by_id(self):
- # We add this unit test to cover some logic specific to the
- # nsx plugin
- with contextlib.nested(self.network(name='net1'),
- self.network(name='net2')) as (net1, net2):
- query_params = 'id=%s' % net1['network']['id']
- self._test_list_resources('network', [net1],
- query_params=query_params)
- query_params += '&id=%s' % net2['network']['id']
- self._test_list_resources('network', [net1, net2],
- query_params=query_params)
-
- def test_delete_network_after_removing_subet(self):
- gateway_ip = '10.0.0.1'
- cidr = '10.0.0.0/24'
- fmt = 'json'
- # Create new network
- res = self._create_network(fmt=fmt, name='net',
- admin_state_up=True)
- network = self.deserialize(fmt, res)
- subnet = self._make_subnet(fmt, network, gateway_ip,
- cidr, ip_version=4)
- req = self.new_delete_request('subnets', subnet['subnet']['id'])
- sub_del_res = req.get_response(self.api)
- self.assertEqual(sub_del_res.status_int, 204)
- req = self.new_delete_request('networks', network['network']['id'])
- net_del_res = req.get_response(self.api)
- self.assertEqual(net_del_res.status_int, 204)
-
- def test_list_networks_with_shared(self):
- with self.network(name='net1'):
- with self.network(name='net2', shared=True):
- req = self.new_list_request('networks')
- res = self.deserialize('json', req.get_response(self.api))
- self.assertEqual(len(res['networks']), 2)
- req_2 = self.new_list_request('networks')
- req_2.environ['neutron.context'] = context.Context('',
- 'somebody')
- res = self.deserialize('json', req_2.get_response(self.api))
- # tenant must see a single network
- self.assertEqual(len(res['networks']), 1)
-
- def test_create_network_name_exceeds_40_chars(self):
- name = 'this_is_a_network_whose_name_is_longer_than_40_chars'
- with self.network(name=name) as net:
- # Assert neutron name is not truncated
- self.assertEqual(net['network']['name'], name)
-
- def test_create_network_maintenance_returns_503(self):
- data = {'network': {'name': 'foo',
- 'admin_state_up': True,
- 'tenant_id': self._tenant_id}}
- with mock.patch.object(nsxlib, 'do_request',
- side_effect=nsx_exc.MaintenanceInProgress):
- net_req = self.new_create_request('networks', data, self.fmt)
- res = net_req.get_response(self.api)
- self.assertEqual(webob.exc.HTTPServiceUnavailable.code,
- res.status_int)
-
- def test_update_network_with_admin_false(self):
- data = {'network': {'admin_state_up': False}}
- with self.network() as net:
- plugin = manager.NeutronManager.get_plugin()
- self.assertRaises(NotImplementedError,
- plugin.update_network,
- context.get_admin_context(),
- net['network']['id'], data)
-
- def test_update_network_with_name_calls_nsx(self):
- with mock.patch.object(
- nsxlib.switch, 'update_lswitch') as update_lswitch_mock:
- # don't worry about deleting this network, do not use
- # context manager
- ctx = context.Context(user_id=None, tenant_id='gonzalo')
- plugin = manager.NeutronManager.get_plugin()
- net = plugin.create_network(
- ctx, {'network': {'name': 'xxx',
- 'admin_state_up': True,
- 'shared': False,
- 'port_security_enabled': True}})
- plugin.update_network(ctx, net['id'],
- {'network': {'name': 'yyy'}})
- update_lswitch_mock.assert_called_once_with(
- mock.ANY, mock.ANY, 'yyy')
-
-
-class SecurityGroupsTestCase(ext_sg.SecurityGroupDBTestCase):
-
- def setUp(self):
- test_lib.test_config['config_files'] = [
- vmware.get_fake_conf('nsx.ini.test')]
- # mock nsx api client
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- self.mock_nsx = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- instance = self.mock_nsx.start()
- instance.return_value.login.return_value = "the_cookie"
- # Avoid runs of the synchronizer looping call
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- patch_sync.start()
-
- instance.return_value.request.side_effect = self.fc.fake_request
- super(SecurityGroupsTestCase, self).setUp(vmware.PLUGIN_NAME)
-
-
-class TestSecurityGroup(ext_sg.TestSecurityGroups, SecurityGroupsTestCase):
-
- def test_create_security_group_name_exceeds_40_chars(self):
- name = 'this_is_a_secgroup_whose_name_is_longer_than_40_chars'
- with self.security_group(name=name) as sg:
- # Assert Neutron name is not truncated
- self.assertEqual(sg['security_group']['name'], name)
-
- def test_create_security_group_rule_bad_input(self):
- name = 'foo security group'
- description = 'foo description'
- with self.security_group(name, description) as sg:
- security_group_id = sg['security_group']['id']
- protocol = 200
- min_range = 32
- max_range = 4343
- rule = self._build_security_group_rule(
- security_group_id, 'ingress', protocol,
- min_range, max_range)
- res = self._create_security_group_rule(self.fmt, rule)
- self.deserialize(self.fmt, res)
- self.assertEqual(res.status_int, 400)
-
-
-class TestL3ExtensionManager(object):
-
- def get_resources(self):
- # Simulate extension of L3 attribute map
- # First apply attribute extensions
- for key in l3.RESOURCE_ATTRIBUTE_MAP.keys():
- l3.RESOURCE_ATTRIBUTE_MAP[key].update(
- l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
- l3.RESOURCE_ATTRIBUTE_MAP[key].update(
- dvr.EXTENDED_ATTRIBUTES_2_0.get(key, {}))
- # Finally add l3 resources to the global attribute map
- attributes.RESOURCE_ATTRIBUTE_MAP.update(
- l3.RESOURCE_ATTRIBUTE_MAP)
- return l3.L3.get_resources()
-
- def get_actions(self):
- return []
-
- def get_request_extensions(self):
- return []
-
-
-class TestL3SecGrpExtensionManager(TestL3ExtensionManager):
- """A fake extension manager for L3 and Security Group extensions.
-
- Includes also NSX specific L3 attributes.
- """
-
- def get_resources(self):
- resources = super(TestL3SecGrpExtensionManager,
- self).get_resources()
- resources.extend(secgrp.Securitygroup.get_resources())
- return resources
-
-
-def backup_l3_attribute_map():
- """Return a backup of the original l3 attribute map."""
- return dict((res, attrs.copy()) for
- (res, attrs) in l3.RESOURCE_ATTRIBUTE_MAP.iteritems())
-
-
-def restore_l3_attribute_map(map_to_restore):
- """Ensure changes made by fake ext mgrs are reverted."""
- l3.RESOURCE_ATTRIBUTE_MAP = map_to_restore
-
-
-class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxPluginV2TestCase):
-
- def _restore_l3_attribute_map(self):
- l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk
-
- def setUp(self, plugin=vmware.PLUGIN_NAME, ext_mgr=None,
- service_plugins=None):
- self._l3_attribute_map_bk = {}
- for item in l3.RESOURCE_ATTRIBUTE_MAP:
- self._l3_attribute_map_bk[item] = (
- l3.RESOURCE_ATTRIBUTE_MAP[item].copy())
- cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH)
- l3_attribute_map_bk = backup_l3_attribute_map()
- self.addCleanup(restore_l3_attribute_map, l3_attribute_map_bk)
- ext_mgr = ext_mgr or TestL3ExtensionManager()
- super(L3NatTest, self).setUp(
- plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins)
- plugin_instance = manager.NeutronManager.get_plugin()
- self._plugin_name = "%s.%s" % (
- plugin_instance.__module__,
- plugin_instance.__class__.__name__)
- self._plugin_class = plugin_instance.__class__
-
- def _create_l3_ext_network(self, vlan_id=None):
- name = 'l3_ext_net'
- net_type = utils.NetworkTypes.L3_EXT
- providernet_args = {pnet.NETWORK_TYPE: net_type,
- pnet.PHYSICAL_NETWORK: 'l3_gw_uuid'}
- if vlan_id:
- providernet_args[pnet.SEGMENTATION_ID] = vlan_id
- return self.network(name=name,
- router__external=True,
- providernet_args=providernet_args,
- arg_list=(pnet.NETWORK_TYPE,
- pnet.PHYSICAL_NETWORK,
- pnet.SEGMENTATION_ID))
-
- #REVISIT: remove the following skips if external IP spec support is added
- def test_router_create_with_gwinfo_ext_ip(self):
- raise self.skipException('External IP specification unsupported')
-
- def test_router_create_with_gwinfo_ext_ip_non_admin(self):
- raise self.skipException('External IP specification unsupported')
-
- def test_router_update_gateway_with_different_external_subnet(self):
- raise self.skipException('External IP specification unsupported')
-
- def test_router_create_with_gwinfo_ext_ip_subnet(self):
- raise self.skipException('External IP specification unsupported')
-
-
-class TestL3NatTestCase(L3NatTest,
- test_l3_plugin.L3NatDBIntTestCase,
- NsxPluginV2TestCase):
-
- def _test_create_l3_ext_network(self, vlan_id=0):
- name = 'l3_ext_net'
- net_type = utils.NetworkTypes.L3_EXT
- expected = [('subnets', []), ('name', name), ('admin_state_up', True),
- ('status', 'ACTIVE'), ('shared', False),
- (external_net.EXTERNAL, True),
- (pnet.NETWORK_TYPE, net_type),
- (pnet.PHYSICAL_NETWORK, 'l3_gw_uuid'),
- (pnet.SEGMENTATION_ID, vlan_id)]
- with self._create_l3_ext_network(vlan_id) as net:
- for k, v in expected:
- self.assertEqual(net['network'][k], v)
-
- def _nsx_validate_ext_gw(self, router_id, l3_gw_uuid, vlan_id):
- """Verify data on fake NSX API client in order to validate
- plugin did set them properly
- """
- # First find the NSX router ID
- ctx = context.get_admin_context()
- nsx_router_id = nsx_db.get_nsx_router_id(ctx.session, router_id)
- ports = [port for port in self.fc._fake_lrouter_lport_dict.values()
- if (port['lr_uuid'] == nsx_router_id and
- port['att_type'] == "L3GatewayAttachment")]
- self.assertEqual(len(ports), 1)
- self.assertEqual(ports[0]['attachment_gwsvc_uuid'], l3_gw_uuid)
- self.assertEqual(ports[0].get('vlan_id'), vlan_id)
-
- def test_create_l3_ext_network_without_vlan(self):
- self._test_create_l3_ext_network()
-
- def _test_router_create_with_gwinfo_and_l3_ext_net(self, vlan_id=None,
- validate_ext_gw=True):
- with self._create_l3_ext_network(vlan_id) as net:
- with self.subnet(network=net) as s:
- data = {'router': {'tenant_id': 'whatever'}}
- data['router']['name'] = 'router1'
- data['router']['external_gateway_info'] = {
- 'network_id': s['subnet']['network_id']}
- router_req = self.new_create_request('routers', data,
- self.fmt)
- try:
- res = router_req.get_response(self.ext_api)
- router = self.deserialize(self.fmt, res)
- self.assertEqual(
- s['subnet']['network_id'],
- (router['router']['external_gateway_info']
- ['network_id']))
- if validate_ext_gw:
- self._nsx_validate_ext_gw(router['router']['id'],
- 'l3_gw_uuid', vlan_id)
- finally:
- self._delete('routers', router['router']['id'])
-
- def test_router_create_with_gwinfo_and_l3_ext_net(self):
- self._test_router_create_with_gwinfo_and_l3_ext_net()
-
- def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self):
- self._test_router_create_with_gwinfo_and_l3_ext_net(444)
-
- def _test_router_create_with_distributed(self, dist_input, dist_expected,
- version='3.1', return_code=201):
- self.mock_instance.return_value.get_version.return_value = (
- version_module.Version(version))
-
- data = {'tenant_id': 'whatever'}
- data['name'] = 'router1'
- data['distributed'] = dist_input
- router_req = self.new_create_request(
- 'routers', {'router': data}, self.fmt)
- try:
- res = router_req.get_response(self.ext_api)
- self.assertEqual(return_code, res.status_int)
- if res.status_int == 201:
- router = self.deserialize(self.fmt, res)
- self.assertIn('distributed', router['router'])
- self.assertEqual(dist_expected,
- router['router']['distributed'])
- finally:
- if res.status_int == 201:
- self._delete('routers', router['router']['id'])
-
- def test_router_create_distributed_with_3_1(self):
- self._test_router_create_with_distributed(True, True)
-
- def test_router_create_distributed_with_new_nsx_versions(self):
- with mock.patch.object(nsxlib.router, 'create_explicit_route_lrouter'):
- self._test_router_create_with_distributed(True, True, '3.2')
- self._test_router_create_with_distributed(True, True, '4.0')
- self._test_router_create_with_distributed(True, True, '4.1')
-
- def test_router_create_not_distributed(self):
- self._test_router_create_with_distributed(False, False)
-
- def test_router_create_distributed_unspecified(self):
- self._test_router_create_with_distributed(None, False)
-
- def test_router_create_distributed_returns_400(self):
- self._test_router_create_with_distributed(True, None, '3.0', 400)
-
- def test_router_create_on_obsolete_platform(self):
-
- def obsolete_response(*args, **kwargs):
- response = (nsxlib.router.
- _create_implicit_routing_lrouter(*args, **kwargs))
- response.pop('distributed')
- return response
-
- with mock.patch.object(
- nsxlib.router, 'create_lrouter', new=obsolete_response):
- self._test_router_create_with_distributed(None, False, '2.2')
-
- def _create_router_with_gw_info_for_test(self, subnet):
- data = {'router': {'tenant_id': 'whatever',
- 'name': 'router1',
- 'external_gateway_info':
- {'network_id': subnet['subnet']['network_id']}}}
- router_req = self.new_create_request(
- 'routers', data, self.fmt)
- return router_req.get_response(self.ext_api)
-
- def test_router_create_nsx_error_returns_500(self, vlan_id=None):
- with mock.patch.object(nsxlib.router,
- 'create_router_lport',
- side_effect=api_exc.NsxApiException):
- with self._create_l3_ext_network(vlan_id) as net:
- with self.subnet(network=net) as s:
- res = self._create_router_with_gw_info_for_test(s)
- self.assertEqual(
- webob.exc.HTTPInternalServerError.code,
- res.status_int)
-
- def test_router_add_gateway_invalid_network_returns_404(self):
- # NOTE(salv-orlando): This unit test has been overridden
- # as the nsx plugin support the ext_gw_mode extension
- # which mandates a uuid for the external network identifier
- with self.router() as r:
- self._add_external_gateway_to_router(
- r['router']['id'],
- uuidutils.generate_uuid(),
- expected_code=webob.exc.HTTPNotFound.code)
-
- def _verify_router_rollback(self):
- # Check that nothing is left on DB
- # TODO(salv-orlando): Verify whehter this is thread-safe
- # w.r.t. sqllite and parallel testing
- self._test_list_resources('router', [])
- # Check that router is not in NSX
- self.assertFalse(self.fc._fake_lrouter_dict)
-
- def test_router_create_with_gw_info_neutron_fail_does_rollback(self):
- # Simulate get subnet error while building list of ips with prefix
- with mock.patch.object(self._plugin_class,
- '_build_ip_address_list',
- side_effect=ntn_exc.SubnetNotFound(
- subnet_id='xxx')):
- with self._create_l3_ext_network() as net:
- with self.subnet(network=net) as s:
- res = self._create_router_with_gw_info_for_test(s)
- self.assertEqual(
- webob.exc.HTTPNotFound.code,
- res.status_int)
- self._verify_router_rollback()
-
- def test_router_create_with_gw_info_nsx_fail_does_rollback(self):
- # Simulate error while fetching nsx router gw port
- with mock.patch.object(self._plugin_class,
- '_find_router_gw_port',
- side_effect=api_exc.NsxApiException):
- with self._create_l3_ext_network() as net:
- with self.subnet(network=net) as s:
- res = self._create_router_with_gw_info_for_test(s)
- self.assertEqual(
- webob.exc.HTTPInternalServerError.code,
- res.status_int)
- self._verify_router_rollback()
-
- def _test_router_update_gateway_on_l3_ext_net(self, vlan_id=None,
- validate_ext_gw=True):
- with self.router() as r:
- with self.subnet() as s1:
- with self._create_l3_ext_network(vlan_id) as net:
- with self.subnet(network=net) as s2:
- self._set_net_external(s1['subnet']['network_id'])
- try:
- self._add_external_gateway_to_router(
- r['router']['id'],
- s1['subnet']['network_id'])
- body = self._show('routers', r['router']['id'])
- net_id = (body['router']
- ['external_gateway_info']['network_id'])
- self.assertEqual(net_id,
- s1['subnet']['network_id'])
- # Plug network with external mapping
- self._set_net_external(s2['subnet']['network_id'])
- self._add_external_gateway_to_router(
- r['router']['id'],
- s2['subnet']['network_id'])
- body = self._show('routers', r['router']['id'])
- net_id = (body['router']
- ['external_gateway_info']['network_id'])
- self.assertEqual(net_id,
- s2['subnet']['network_id'])
- if validate_ext_gw:
- self._nsx_validate_ext_gw(
- body['router']['id'],
- 'l3_gw_uuid', vlan_id)
- finally:
- # Cleanup
- self._remove_external_gateway_from_router(
- r['router']['id'],
- s2['subnet']['network_id'])
-
- def test_router_update_gateway_on_l3_ext_net(self):
- self._test_router_update_gateway_on_l3_ext_net()
-
- def test_router_update_gateway_on_l3_ext_net_with_vlan(self):
- self._test_router_update_gateway_on_l3_ext_net(444)
-
- def test_router_list_by_tenant_id(self):
- with contextlib.nested(self.router(tenant_id='custom'),
- self.router(),
- self.router()
- ) as routers:
- self._test_list_resources('router', [routers[0]],
- query_params="tenant_id=custom")
-
- def test_create_l3_ext_network_with_vlan(self):
- self._test_create_l3_ext_network(666)
-
- def test_floatingip_with_assoc_fails(self):
- self._test_floatingip_with_assoc_fails(
- "%s.%s" % (self._plugin_name, "_update_fip_assoc"))
-
- def test_floatingip_with_invalid_create_port(self):
- self._test_floatingip_with_invalid_create_port(self._plugin_name)
-
- def _metadata_setup(self):
- cfg.CONF.set_override('metadata_mode', 'access_network', 'NSX')
-
- def _metadata_teardown(self):
- cfg.CONF.set_override('metadata_mode', None, 'NSX')
-
- def test_create_router_name_exceeds_40_chars(self):
- name = 'this_is_a_router_whose_name_is_longer_than_40_chars'
- with self.router(name=name) as rtr:
- # Assert Neutron name is not truncated
- self.assertEqual(rtr['router']['name'], name)
-
- def test_router_add_interface_subnet_with_metadata_access(self):
- self._metadata_setup()
- self.test_router_add_interface_subnet()
- self._metadata_teardown()
-
- def test_router_add_interface_port_with_metadata_access(self):
- self._metadata_setup()
- self.test_router_add_interface_port()
- self._metadata_teardown()
-
- def test_router_add_interface_dupsubnet_returns_400_with_metadata(self):
- self._metadata_setup()
- self.test_router_add_interface_dup_subnet1_returns_400()
- self._metadata_teardown()
-
- def test_router_add_interface_overlapped_cidr_returns_400_with(self):
- self._metadata_setup()
- self.test_router_add_interface_overlapped_cidr_returns_400()
- self._metadata_teardown()
-
- def test_router_remove_interface_inuse_returns_409_with_metadata(self):
- self._metadata_setup()
- self.test_router_remove_interface_inuse_returns_409()
- self._metadata_teardown()
-
- def test_router_remove_iface_wrong_sub_returns_400_with_metadata(self):
- self._metadata_setup()
- self.test_router_remove_interface_wrong_subnet_returns_400()
- self._metadata_teardown()
-
- def test_router_delete_with_metadata_access(self):
- self._metadata_setup()
- self.test_router_delete()
- self._metadata_teardown()
-
- def test_router_delete_with_port_existed_returns_409_with_metadata(self):
- self._metadata_setup()
- self.test_router_delete_with_port_existed_returns_409()
- self._metadata_teardown()
-
- def test_metadatata_network_created_with_router_interface_add(self):
- self._metadata_setup()
- with mock.patch.object(self._plugin_class, 'schedule_network') as f:
- with self.router() as r:
- with self.subnet() as s:
- self._router_interface_action('add',
- r['router']['id'],
- s['subnet']['id'],
- None)
- r_ports = self._list('ports')['ports']
- self.assertEqual(len(r_ports), 2)
- ips = []
- for port in r_ports:
- ips.extend([netaddr.IPAddress(fixed_ip['ip_address'])
- for fixed_ip in port['fixed_ips']])
- meta_cidr = netaddr.IPNetwork('169.254.0.0/16')
- self.assertTrue(any([ip in meta_cidr for ip in ips]))
- # Needed to avoid 409
- self._router_interface_action('remove',
- r['router']['id'],
- s['subnet']['id'],
- None)
- # Verify that the metadata network gets scheduled first, so that
- # an active dhcp agent can pick it up
- expected_meta_net = {
- 'status': 'ACTIVE',
- 'subnets': [],
- 'name': 'meta-%s' % r['router']['id'],
- 'admin_state_up': True,
- 'tenant_id': '',
- 'port_security_enabled': False,
- 'shared': False,
- 'id': mock.ANY
- }
- f.assert_called_once_with(mock.ANY, expected_meta_net)
- self._metadata_teardown()
-
- def test_metadata_network_create_rollback_on_create_subnet_failure(self):
- self._metadata_setup()
- with self.router() as r:
- with self.subnet() as s:
- # Raise a NeutronException (eg: NotFound)
- with mock.patch.object(self._plugin_class,
- 'create_subnet',
- side_effect=ntn_exc.NotFound):
- self._router_interface_action(
- 'add', r['router']['id'], s['subnet']['id'], None)
- # Ensure metadata network was removed
- nets = self._list('networks')['networks']
- self.assertEqual(len(nets), 1)
- # Needed to avoid 409
- self._router_interface_action('remove',
- r['router']['id'],
- s['subnet']['id'],
- None)
- self._metadata_teardown()
-
- def test_metadata_network_create_rollback_on_add_rtr_iface_failure(self):
- self._metadata_setup()
- with self.router() as r:
- with self.subnet() as s:
- # Raise a NeutronException when adding metadata subnet
- # to router
- # save function being mocked
- real_func = self._plugin_class.add_router_interface
- plugin_instance = manager.NeutronManager.get_plugin()
-
- def side_effect(*args):
- if args[-1]['subnet_id'] == s['subnet']['id']:
- # do the real thing
- return real_func(plugin_instance, *args)
- # otherwise raise
- raise api_exc.NsxApiException()
-
- with mock.patch.object(self._plugin_class,
- 'add_router_interface',
- side_effect=side_effect):
- self._router_interface_action(
- 'add', r['router']['id'], s['subnet']['id'], None)
- # Ensure metadata network was removed
- nets = self._list('networks')['networks']
- self.assertEqual(len(nets), 1)
- # Needed to avoid 409
- self._router_interface_action('remove',
- r['router']['id'],
- s['subnet']['id'],
- None)
- self._metadata_teardown()
-
- def test_metadata_network_removed_with_router_interface_remove(self):
- self._metadata_setup()
- with self.router() as r:
- with self.subnet() as s:
- self._router_interface_action('add', r['router']['id'],
- s['subnet']['id'], None)
- subnets = self._list('subnets')['subnets']
- self.assertEqual(len(subnets), 2)
- meta_cidr = netaddr.IPNetwork('169.254.0.0/16')
- for subnet in subnets:
- cidr = netaddr.IPNetwork(subnet['cidr'])
- if meta_cidr == cidr or meta_cidr in cidr.supernet(16):
- meta_sub_id = subnet['id']
- meta_net_id = subnet['network_id']
- ports = self._list(
- 'ports',
- query_params='network_id=%s' % meta_net_id)['ports']
- self.assertEqual(len(ports), 1)
- meta_port_id = ports[0]['id']
- self._router_interface_action('remove', r['router']['id'],
- s['subnet']['id'], None)
- self._show('networks', meta_net_id,
- webob.exc.HTTPNotFound.code)
- self._show('ports', meta_port_id,
- webob.exc.HTTPNotFound.code)
- self._show('subnets', meta_sub_id,
- webob.exc.HTTPNotFound.code)
- self._metadata_teardown()
-
- def test_metadata_network_remove_rollback_on_failure(self):
- self._metadata_setup()
- with self.router() as r:
- with self.subnet() as s:
- self._router_interface_action('add', r['router']['id'],
- s['subnet']['id'], None)
- networks = self._list('networks')['networks']
- for network in networks:
- if network['id'] != s['subnet']['network_id']:
- meta_net_id = network['id']
- ports = self._list(
- 'ports',
- query_params='network_id=%s' % meta_net_id)['ports']
- meta_port_id = ports[0]['id']
- # Raise a NeutronException when removing
- # metadata subnet from router
- # save function being mocked
- real_func = self._plugin_class.remove_router_interface
- plugin_instance = manager.NeutronManager.get_plugin()
-
- def side_effect(*args):
- if args[-1].get('subnet_id') == s['subnet']['id']:
- # do the real thing
- return real_func(plugin_instance, *args)
- # otherwise raise
- raise api_exc.NsxApiException()
-
- with mock.patch.object(self._plugin_class,
- 'remove_router_interface',
- side_effect=side_effect):
- self._router_interface_action('remove', r['router']['id'],
- s['subnet']['id'], None)
- # Metadata network and subnet should still be there
- self._show('networks', meta_net_id,
- webob.exc.HTTPOk.code)
- self._show('ports', meta_port_id,
- webob.exc.HTTPOk.code)
- self._metadata_teardown()
-
- def test_metadata_dhcp_host_route(self):
- cfg.CONF.set_override('metadata_mode', 'dhcp_host_route', 'NSX')
- subnets = self._list('subnets')['subnets']
- with self.subnet() as s:
- with self.port(subnet=s, device_id='1234',
- device_owner=constants.DEVICE_OWNER_DHCP) as port:
- subnets = self._list('subnets')['subnets']
- self.assertEqual(len(subnets), 1)
- self.assertEqual(subnets[0]['host_routes'][0]['nexthop'],
- '10.0.0.2')
- self.assertEqual(subnets[0]['host_routes'][0]['destination'],
- '169.254.169.254/32')
- self._delete('ports', port['port']['id'])
- subnets = self._list('subnets')['subnets']
- # Test that route is deleted after dhcp port is removed
- self.assertEqual(len(subnets[0]['host_routes']), 0)
-
- def _test_floatingip_update(self, expected_status):
- super(TestL3NatTestCase, self).test_floatingip_update(
- expected_status)
-
- def test_floatingip_update(self):
- self._test_floatingip_update(constants.FLOATINGIP_STATUS_DOWN)
-
- def test_floatingip_disassociate(self):
- with self.port() as p:
- private_sub = {'subnet': {'id':
- p['port']['fixed_ips'][0]['subnet_id']}}
- plugin = manager.NeutronManager.get_plugin()
- with mock.patch.object(plugin, 'notify_routers_updated') as notify:
- with self.floatingip_no_assoc(private_sub) as fip:
- port_id = p['port']['id']
- body = self._update('floatingips', fip['floatingip']['id'],
- {'floatingip': {'port_id': port_id}})
- self.assertEqual(body['floatingip']['port_id'], port_id)
- # Floating IP status should be active
- self.assertEqual(constants.FLOATINGIP_STATUS_ACTIVE,
- body['floatingip']['status'])
- # Disassociate
- body = self._update('floatingips', fip['floatingip']['id'],
- {'floatingip': {'port_id': None}})
- body = self._show('floatingips', fip['floatingip']['id'])
- self.assertIsNone(body['floatingip']['port_id'])
- self.assertIsNone(body['floatingip']['fixed_ip_address'])
- # Floating IP status should be down
- self.assertEqual(constants.FLOATINGIP_STATUS_DOWN,
- body['floatingip']['status'])
-
- # check that notification was not requested
- self.assertFalse(notify.called)
-
- def test_create_router_maintenance_returns_503(self):
- with self._create_l3_ext_network() as net:
- with self.subnet(network=net) as s:
- with mock.patch.object(
- nsxlib,
- 'do_request',
- side_effect=nsx_exc.MaintenanceInProgress):
- data = {'router': {'tenant_id': 'whatever'}}
- data['router']['name'] = 'router1'
- data['router']['external_gateway_info'] = {
- 'network_id': s['subnet']['network_id']}
- router_req = self.new_create_request(
- 'routers', data, self.fmt)
- res = router_req.get_response(self.ext_api)
- self.assertEqual(webob.exc.HTTPServiceUnavailable.code,
- res.status_int)
-
- def test_router_add_interface_port_removes_security_group(self):
- with self.router() as r:
- with self.port() as p:
- body = self._router_interface_action('add',
- r['router']['id'],
- None,
- p['port']['id'])
- self.assertIn('port_id', body)
- self.assertEqual(body['port_id'], p['port']['id'])
-
- # fetch port and confirm no security-group on it.
- body = self._show('ports', p['port']['id'])
- self.assertEqual(body['port']['security_groups'], [])
- self.assertFalse(body['port']['port_security_enabled'])
- # clean-up
- self._router_interface_action('remove',
- r['router']['id'],
- None,
- p['port']['id'])
-
-
-class ExtGwModeTestCase(NsxPluginV2TestCase,
- test_ext_gw_mode.ExtGwModeIntTestCase):
- pass
-
-
-class NeutronNsxOutOfSync(NsxPluginV2TestCase,
- test_l3_plugin.L3NatTestCaseMixin,
- ext_sg.SecurityGroupsTestCase):
-
- def setUp(self):
- l3_attribute_map_bk = backup_l3_attribute_map()
- self.addCleanup(restore_l3_attribute_map, l3_attribute_map_bk)
- super(NeutronNsxOutOfSync, self).setUp(
- ext_mgr=TestL3SecGrpExtensionManager())
-
- def test_delete_network_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net1 = self.deserialize('json', res)
- self.fc._fake_lswitch_dict.clear()
- req = self.new_delete_request('networks', net1['network']['id'])
- res = req.get_response(self.api)
- self.assertEqual(res.status_int, 204)
-
- def test_show_network_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net = self.deserialize('json', res)
- self.fc._fake_lswitch_dict.clear()
- req = self.new_show_request('networks', net['network']['id'],
- fields=['id', 'status'])
- net = self.deserialize('json', req.get_response(self.api))
- self.assertEqual(net['network']['status'],
- constants.NET_STATUS_ERROR)
-
- def test_delete_port_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net1 = self.deserialize('json', res)
- res = self._create_port('json', net1['network']['id'])
- port = self.deserialize('json', res)
- self.fc._fake_lswitch_lport_dict.clear()
- req = self.new_delete_request('ports', port['port']['id'])
- res = req.get_response(self.api)
- self.assertEqual(res.status_int, 204)
-
- def test_show_port_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net1 = self.deserialize('json', res)
- res = self._create_port('json', net1['network']['id'])
- port = self.deserialize('json', res)
- self.fc._fake_lswitch_lport_dict.clear()
- self.fc._fake_lswitch_lportstatus_dict.clear()
- req = self.new_show_request('ports', port['port']['id'],
- fields=['id', 'status'])
- net = self.deserialize('json', req.get_response(self.api))
- self.assertEqual(net['port']['status'],
- constants.PORT_STATUS_ERROR)
-
- def test_create_port_on_network_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net1 = self.deserialize('json', res)
- self.fc._fake_lswitch_dict.clear()
- res = self._create_port('json', net1['network']['id'])
- port = self.deserialize('json', res)
- self.assertEqual(port['port']['status'], constants.PORT_STATUS_ERROR)
-
- def test_update_port_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net1 = self.deserialize('json', res)
- res = self._create_port('json', net1['network']['id'])
- port = self.deserialize('json', res)
- self.fc._fake_lswitch_lport_dict.clear()
- data = {'port': {'name': 'error_port'}}
- req = self.new_update_request('ports', data, port['port']['id'])
- port = self.deserialize('json', req.get_response(self.api))
- self.assertEqual(port['port']['status'], constants.PORT_STATUS_ERROR)
- self.assertEqual(port['port']['name'], 'error_port')
-
- def test_delete_port_and_network_not_in_nsx(self):
- res = self._create_network('json', 'net1', True)
- net1 = self.deserialize('json', res)
- res = self._create_port('json', net1['network']['id'])
- port = self.deserialize('json', res)
- self.fc._fake_lswitch_dict.clear()
- self.fc._fake_lswitch_lport_dict.clear()
- req = self.new_delete_request('ports', port['port']['id'])
- res = req.get_response(self.api)
- self.assertEqual(res.status_int, 204)
- req = self.new_delete_request('networks', net1['network']['id'])
- res = req.get_response(self.api)
- self.assertEqual(res.status_int, 204)
-
- def test_delete_router_not_in_nsx(self):
- res = self._create_router('json', 'tenant')
- router = self.deserialize('json', res)
- self.fc._fake_lrouter_dict.clear()
- req = self.new_delete_request('routers', router['router']['id'])
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 204)
-
- def test_show_router_not_in_nsx(self):
- res = self._create_router('json', 'tenant')
- router = self.deserialize('json', res)
- self.fc._fake_lrouter_dict.clear()
- req = self.new_show_request('routers', router['router']['id'],
- fields=['id', 'status'])
- router = self.deserialize('json', req.get_response(self.ext_api))
- self.assertEqual(router['router']['status'],
- constants.NET_STATUS_ERROR)
-
- def _create_network_and_subnet(self, cidr, external=False):
- net_res = self._create_network('json', 'ext_net', True)
- net = self.deserialize('json', net_res)
- net_id = net['network']['id']
- if external:
- self._update('networks', net_id,
- {'network': {external_net.EXTERNAL: True}})
- sub_res = self._create_subnet('json', net_id, cidr)
- sub = self.deserialize('json', sub_res)
- return net_id, sub['subnet']['id']
-
- def test_clear_gateway_nat_rule_not_in_nsx(self):
- # Create external network and subnet
- ext_net_id = self._create_network_and_subnet('1.1.1.0/24', True)[0]
- # Create internal network and subnet
- int_sub_id = self._create_network_and_subnet('10.0.0.0/24')[1]
- res = self._create_router('json', 'tenant')
- router = self.deserialize('json', res)
- # Add interface to router (needed to generate NAT rule)
- req = self.new_action_request(
- 'routers',
- {'subnet_id': int_sub_id},
- router['router']['id'],
- "add_router_interface")
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 200)
- # Set gateway for router
- req = self.new_update_request(
- 'routers',
- {'router': {'external_gateway_info':
- {'network_id': ext_net_id}}},
- router['router']['id'])
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 200)
- # Delete NAT rule from NSX, clear gateway
- # and verify operation still succeeds
- self.fc._fake_lrouter_nat_dict.clear()
- req = self.new_update_request(
- 'routers',
- {'router': {'external_gateway_info': {}}},
- router['router']['id'])
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 200)
-
- def _test_remove_router_interface_nsx_out_of_sync(self, unsync_action):
- # Create external network and subnet
- ext_net_id = self._create_network_and_subnet('1.1.1.0/24', True)[0]
- # Create internal network and subnet
- int_sub_id = self._create_network_and_subnet('10.0.0.0/24')[1]
- res = self._create_router('json', 'tenant')
- router = self.deserialize('json', res)
- # Set gateway and add interface to router (needed to generate NAT rule)
- req = self.new_update_request(
- 'routers',
- {'router': {'external_gateway_info':
- {'network_id': ext_net_id}}},
- router['router']['id'])
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 200)
- req = self.new_action_request(
- 'routers',
- {'subnet_id': int_sub_id},
- router['router']['id'],
- "add_router_interface")
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 200)
- unsync_action()
- req = self.new_action_request(
- 'routers',
- {'subnet_id': int_sub_id},
- router['router']['id'],
- "remove_router_interface")
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 200)
-
- def test_remove_router_interface_not_in_nsx(self):
-
- def unsync_action():
- self.fc._fake_lrouter_dict.clear()
- self.fc._fake_lrouter_nat_dict.clear()
-
- self._test_remove_router_interface_nsx_out_of_sync(unsync_action)
-
- def test_remove_router_interface_nat_rule_not_in_nsx(self):
- self._test_remove_router_interface_nsx_out_of_sync(
- self.fc._fake_lrouter_nat_dict.clear)
-
- def test_remove_router_interface_duplicate_nat_rules_in_nsx(self):
-
- def unsync_action():
- # duplicate every entry in the nat rule dict
- for (_rule_id, rule) in self.fc._fake_lrouter_nat_dict.items():
- self.fc._fake_lrouter_nat_dict[uuid.uuid4()] = rule
-
- self._test_remove_router_interface_nsx_out_of_sync(unsync_action)
-
- def test_update_router_not_in_nsx(self):
- res = self._create_router('json', 'tenant')
- router = self.deserialize('json', res)
- self.fc._fake_lrouter_dict.clear()
- req = self.new_update_request(
- 'routers',
- {'router': {'name': 'goo'}},
- router['router']['id'])
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 500)
- req = self.new_show_request('routers', router['router']['id'])
- router = self.deserialize('json', req.get_response(self.ext_api))
- self.assertEqual(router['router']['status'],
- constants.NET_STATUS_ERROR)
-
- def test_delete_security_group_not_in_nsx(self):
- res = self._create_security_group('json', 'name', 'desc')
- sec_group = self.deserialize('json', res)
- self.fc._fake_securityprofile_dict.clear()
- req = self.new_delete_request(
- 'security-groups',
- sec_group['security_group']['id'])
- res = req.get_response(self.ext_api)
- self.assertEqual(res.status_int, 204)
+++ /dev/null
-# Copyright 2013 VMware, Inc.
-# 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 contextlib
-import time
-
-import mock
-from oslo_config import cfg
-from oslo_serialization import jsonutils
-
-from neutron.api.v2 import attributes as attr
-from neutron.common import constants
-from neutron.common import exceptions as n_exc
-from neutron import context
-from neutron.extensions import l3
-from neutron.openstack.common import log
-from neutron.plugins.vmware.api_client import client
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.api_client import version
-from neutron.plugins.vmware.common import sync
-from neutron.plugins.vmware.dbexts import db
-from neutron.plugins.vmware import nsx_cluster as cluster
-from neutron.plugins.vmware import nsxlib
-from neutron.plugins.vmware import plugin
-from neutron.tests import base
-from neutron.tests.unit import test_api_v2
-from neutron.tests.unit import testlib_api
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.apiclient import fake
-
-LOG = log.getLogger(__name__)
-
-_uuid = test_api_v2._uuid
-LSWITCHES = [{'uuid': _uuid(), 'name': 'ls-1'},
- {'uuid': _uuid(), 'name': 'ls-2'}]
-LSWITCHPORTS = [{'uuid': _uuid(), 'name': 'lp-1'},
- {'uuid': _uuid(), 'name': 'lp-2'}]
-LROUTERS = [{'uuid': _uuid(), 'name': 'lr-1'},
- {'uuid': _uuid(), 'name': 'lr-2'}]
-
-
-class CacheTestCase(base.BaseTestCase):
- """Test suite providing coverage for the Cache class."""
-
- def setUp(self):
- self.nsx_cache = sync.NsxCache()
- for lswitch in LSWITCHES:
- self.nsx_cache._uuid_dict_mappings[lswitch['uuid']] = (
- self.nsx_cache._lswitches)
- self.nsx_cache._lswitches[lswitch['uuid']] = (
- {'data': lswitch,
- 'hash': hash(jsonutils.dumps(lswitch))})
- for lswitchport in LSWITCHPORTS:
- self.nsx_cache._uuid_dict_mappings[lswitchport['uuid']] = (
- self.nsx_cache._lswitchports)
- self.nsx_cache._lswitchports[lswitchport['uuid']] = (
- {'data': lswitchport,
- 'hash': hash(jsonutils.dumps(lswitchport))})
- for lrouter in LROUTERS:
- self.nsx_cache._uuid_dict_mappings[lrouter['uuid']] = (
- self.nsx_cache._lrouters)
- self.nsx_cache._lrouters[lrouter['uuid']] = (
- {'data': lrouter,
- 'hash': hash(jsonutils.dumps(lrouter))})
- super(CacheTestCase, self).setUp()
-
- def test_get_lswitches(self):
- ls_uuids = self.nsx_cache.get_lswitches()
- self.assertEqual(set(ls_uuids),
- set([ls['uuid'] for ls in LSWITCHES]))
-
- def test_get_lswitchports(self):
- lp_uuids = self.nsx_cache.get_lswitchports()
- self.assertEqual(set(lp_uuids),
- set([lp['uuid'] for lp in LSWITCHPORTS]))
-
- def test_get_lrouters(self):
- lr_uuids = self.nsx_cache.get_lrouters()
- self.assertEqual(set(lr_uuids),
- set([lr['uuid'] for lr in LROUTERS]))
-
- def test_get_lswitches_changed_only(self):
- ls_uuids = self.nsx_cache.get_lswitches(changed_only=True)
- self.assertEqual(0, len(ls_uuids))
-
- def test_get_lswitchports_changed_only(self):
- lp_uuids = self.nsx_cache.get_lswitchports(changed_only=True)
- self.assertEqual(0, len(lp_uuids))
-
- def test_get_lrouters_changed_only(self):
- lr_uuids = self.nsx_cache.get_lrouters(changed_only=True)
- self.assertEqual(0, len(lr_uuids))
-
- def _verify_update(self, new_resource, changed=True, hit=True):
- cached_resource = self.nsx_cache[new_resource['uuid']]
- self.assertEqual(new_resource, cached_resource['data'])
- self.assertEqual(hit, cached_resource.get('hit', False))
- self.assertEqual(changed,
- cached_resource.get('changed', False))
-
- def test_update_lswitch_new_item(self):
- new_switch_uuid = _uuid()
- new_switch = {'uuid': new_switch_uuid, 'name': 'new_switch'}
- self.nsx_cache.update_lswitch(new_switch)
- self.assertIn(new_switch_uuid, self.nsx_cache._lswitches.keys())
- self._verify_update(new_switch)
-
- def test_update_lswitch_existing_item(self):
- switch = LSWITCHES[0]
- switch['name'] = 'new_name'
- self.nsx_cache.update_lswitch(switch)
- self.assertIn(switch['uuid'], self.nsx_cache._lswitches.keys())
- self._verify_update(switch)
-
- def test_update_lswitchport_new_item(self):
- new_switchport_uuid = _uuid()
- new_switchport = {'uuid': new_switchport_uuid,
- 'name': 'new_switchport'}
- self.nsx_cache.update_lswitchport(new_switchport)
- self.assertIn(new_switchport_uuid,
- self.nsx_cache._lswitchports.keys())
- self._verify_update(new_switchport)
-
- def test_update_lswitchport_existing_item(self):
- switchport = LSWITCHPORTS[0]
- switchport['name'] = 'new_name'
- self.nsx_cache.update_lswitchport(switchport)
- self.assertIn(switchport['uuid'],
- self.nsx_cache._lswitchports.keys())
- self._verify_update(switchport)
-
- def test_update_lrouter_new_item(self):
- new_router_uuid = _uuid()
- new_router = {'uuid': new_router_uuid,
- 'name': 'new_router'}
- self.nsx_cache.update_lrouter(new_router)
- self.assertIn(new_router_uuid,
- self.nsx_cache._lrouters.keys())
- self._verify_update(new_router)
-
- def test_update_lrouter_existing_item(self):
- router = LROUTERS[0]
- router['name'] = 'new_name'
- self.nsx_cache.update_lrouter(router)
- self.assertIn(router['uuid'],
- self.nsx_cache._lrouters.keys())
- self._verify_update(router)
-
- def test_process_updates_initial(self):
- # Clear cache content to simulate first-time filling
- self.nsx_cache._lswitches.clear()
- self.nsx_cache._lswitchports.clear()
- self.nsx_cache._lrouters.clear()
- self.nsx_cache.process_updates(LSWITCHES, LROUTERS, LSWITCHPORTS)
- for resource in LSWITCHES + LROUTERS + LSWITCHPORTS:
- self._verify_update(resource)
-
- def test_process_updates_no_change(self):
- self.nsx_cache.process_updates(LSWITCHES, LROUTERS, LSWITCHPORTS)
- for resource in LSWITCHES + LROUTERS + LSWITCHPORTS:
- self._verify_update(resource, changed=False)
-
- def test_process_updates_with_changes(self):
- LSWITCHES[0]['name'] = 'altered'
- self.nsx_cache.process_updates(LSWITCHES, LROUTERS, LSWITCHPORTS)
- for resource in LSWITCHES + LROUTERS + LSWITCHPORTS:
- changed = (True if resource['uuid'] == LSWITCHES[0]['uuid']
- else False)
- self._verify_update(resource, changed=changed)
-
- def _test_process_updates_with_removals(self):
- lswitches = LSWITCHES[:]
- lswitch = lswitches.pop()
- self.nsx_cache.process_updates(lswitches, LROUTERS, LSWITCHPORTS)
- for resource in LSWITCHES + LROUTERS + LSWITCHPORTS:
- hit = (False if resource['uuid'] == lswitch['uuid']
- else True)
- self._verify_update(resource, changed=False, hit=hit)
- return (lswitch, lswitches)
-
- def test_process_updates_with_removals(self):
- self._test_process_updates_with_removals()
-
- def test_process_updates_cleanup_after_delete(self):
- deleted_lswitch, lswitches = self._test_process_updates_with_removals()
- self.nsx_cache.process_deletes()
- self.nsx_cache.process_updates(lswitches, LROUTERS, LSWITCHPORTS)
- self.assertNotIn(deleted_lswitch['uuid'], self.nsx_cache._lswitches)
-
- def test_update_resource_does_not_cleanup_deleted_resources(self):
- deleted_lswitch, lswitches = self._test_process_updates_with_removals()
- self.nsx_cache.process_deletes()
- self.nsx_cache.update_lswitch(deleted_lswitch)
- self.assertIn(deleted_lswitch['uuid'], self.nsx_cache._lswitches)
-
- def _verify_delete(self, resource, deleted=True, hit=True):
- cached_resource = self.nsx_cache[resource['uuid']]
- data_field = 'data_bk' if deleted else 'data'
- self.assertEqual(resource, cached_resource[data_field])
- self.assertEqual(hit, cached_resource.get('hit', False))
- self.assertEqual(deleted,
- cached_resource.get('changed', False))
-
- def _set_hit(self, resources, uuid_to_delete=None):
- for resource in resources:
- if resource['data']['uuid'] != uuid_to_delete:
- resource['hit'] = True
-
- def test_process_deletes_no_change(self):
- # Mark all resources as hit
- self._set_hit(self.nsx_cache._lswitches.values())
- self._set_hit(self.nsx_cache._lswitchports.values())
- self._set_hit(self.nsx_cache._lrouters.values())
- self.nsx_cache.process_deletes()
- for resource in LSWITCHES + LROUTERS + LSWITCHPORTS:
- self._verify_delete(resource, hit=False, deleted=False)
-
- def test_process_deletes_with_removals(self):
- # Mark all resources but one as hit
- uuid_to_delete = LSWITCHPORTS[0]['uuid']
- self._set_hit(self.nsx_cache._lswitches.values(),
- uuid_to_delete)
- self._set_hit(self.nsx_cache._lswitchports.values(),
- uuid_to_delete)
- self._set_hit(self.nsx_cache._lrouters.values(),
- uuid_to_delete)
- self.nsx_cache.process_deletes()
- for resource in LSWITCHES + LROUTERS + LSWITCHPORTS:
- deleted = resource['uuid'] == uuid_to_delete
- self._verify_delete(resource, hit=False, deleted=deleted)
-
-
-class SyncLoopingCallTestCase(base.BaseTestCase):
-
- def test_looping_calls(self):
- # Avoid runs of the synchronization process - just start
- # the looping call
- with mock.patch.object(
- sync.NsxSynchronizer, '_synchronize_state', return_value=0.01):
- synchronizer = sync.NsxSynchronizer(mock.ANY, mock.ANY,
- 100, 0, 0)
- time.sleep(0.03)
- # stop looping call before asserting
- synchronizer._sync_looping_call.stop()
- # Just verify the looping call has been called, trying
- # to assess the exact number of calls would be unreliable
- self.assertTrue(synchronizer._synchronize_state.call_count)
-
-
-class SyncTestCase(testlib_api.SqlTestCase):
-
- def setUp(self):
- # mock api client
- self.fc = fake.FakeClient(vmware.STUBS_PATH)
- mock_api = mock.patch(vmware.NSXAPI_NAME, autospec=True)
- # Avoid runs of the synchronizer looping call
- # These unit tests will excplicitly invoke synchronization
- patch_sync = mock.patch.object(sync, '_start_loopingcall')
- self.mock_api = mock_api.start()
- patch_sync.start()
- self.mock_api.return_value.login.return_value = "the_cookie"
- # Emulate tests against NSX 3.x
- self.mock_api.return_value.get_version.return_value = (
- version.Version("3.1"))
-
- self.mock_api.return_value.request.side_effect = self.fc.fake_request
- self.fake_cluster = cluster.NSXCluster(
- name='fake-cluster', nsx_controllers=['1.1.1.1:999'],
- default_tz_uuid=_uuid(), nsx_user='foo', nsx_password='bar')
- self.fake_cluster.api_client = client.NsxApiClient(
- ('1.1.1.1', '999', True),
- self.fake_cluster.nsx_user, self.fake_cluster.nsx_password,
- http_timeout=self.fake_cluster.http_timeout,
- retries=self.fake_cluster.retries,
- redirects=self.fake_cluster.redirects)
- # Instantiate Neutron plugin
- # and setup needed config variables
- args = ['--config-file', vmware.get_fake_conf('neutron.conf.test'),
- '--config-file', vmware.get_fake_conf('nsx.ini.test')]
- self.config_parse(args=args)
- cfg.CONF.set_override('allow_overlapping_ips', True)
- dhcp_periodic_p = mock.patch('neutron.db.agentschedulers_db.'
- 'DhcpAgentSchedulerDbMixin.'
- 'start_periodic_dhcp_agent_status_check')
- dhcp_periodic_p.start()
- self._plugin = plugin.NsxPlugin()
- # Mock neutron manager plugin load functions to speed up tests
- mock_nm_get_plugin = mock.patch('neutron.manager.NeutronManager.'
- 'get_plugin')
- mock_nm_get_service_plugins = mock.patch(
- 'neutron.manager.NeutronManager.get_service_plugins')
- self.mock_nm_get_plugin = mock_nm_get_plugin.start()
- self.mock_nm_get_plugin.return_value = self._plugin
- mock_nm_get_service_plugins.start()
- super(SyncTestCase, self).setUp()
- self.addCleanup(self.fc.reset_all)
-
- @contextlib.contextmanager
- def _populate_data(self, ctx, net_size=2, port_size=2, router_size=2):
-
- def network(idx):
- return {'network': {'name': 'net-%s' % idx,
- 'admin_state_up': True,
- 'shared': False,
- 'port_security_enabled': True,
- 'tenant_id': 'foo'}}
-
- def subnet(idx, net_id):
- return {'subnet':
- {'cidr': '10.10.%s.0/24' % idx,
- 'name': 'sub-%s' % idx,
- 'gateway_ip': attr.ATTR_NOT_SPECIFIED,
- 'allocation_pools': attr.ATTR_NOT_SPECIFIED,
- 'ip_version': 4,
- 'dns_nameservers': attr.ATTR_NOT_SPECIFIED,
- 'host_routes': attr.ATTR_NOT_SPECIFIED,
- 'enable_dhcp': True,
- 'network_id': net_id,
- 'tenant_id': 'foo'}}
-
- def port(idx, net_id):
- return {'port': {'network_id': net_id,
- 'name': 'port-%s' % idx,
- 'admin_state_up': True,
- 'device_id': 'miao',
- 'device_owner': 'bau',
- 'fixed_ips': attr.ATTR_NOT_SPECIFIED,
- 'mac_address': attr.ATTR_NOT_SPECIFIED,
- 'tenant_id': 'foo'}}
-
- def router(idx):
- # Use random uuids as names
- return {'router': {'name': 'rtr-%s' % idx,
- 'admin_state_up': True,
- 'tenant_id': 'foo'}}
-
- networks = []
- ports = []
- routers = []
- for i in range(net_size):
- net = self._plugin.create_network(ctx, network(i))
- networks.append(net)
- self._plugin.create_subnet(ctx, subnet(i, net['id']))
- for j in range(port_size):
- ports.append(self._plugin.create_port(
- ctx, port("%s-%s" % (i, j), net['id'])))
- for i in range(router_size):
- routers.append(self._plugin.create_router(ctx, router(i)))
- # Do not return anything as the user does need the actual
- # data created
- yield
-
- # Remove everything
- for router in routers:
- self._plugin.delete_router(ctx, router['id'])
- for port in ports:
- self._plugin.delete_port(ctx, port['id'])
- # This will remove networks and subnets
- for network in networks:
- self._plugin.delete_network(ctx, network['id'])
-
- def _get_tag_dict(self, tags):
- return dict((tag['scope'], tag['tag']) for tag in tags)
-
- def _test_sync(self, exp_net_status,
- exp_port_status, exp_router_status,
- action_callback=None, sp=None):
- ls_uuid = self.fc._fake_lswitch_dict.keys()[0]
- neutron_net_id = self._get_tag_dict(
- self.fc._fake_lswitch_dict[ls_uuid]['tags'])['quantum_net_id']
- lp_uuid = self.fc._fake_lswitch_lport_dict.keys()[0]
- neutron_port_id = self._get_tag_dict(
- self.fc._fake_lswitch_lport_dict[lp_uuid]['tags'])['q_port_id']
- lr_uuid = self.fc._fake_lrouter_dict.keys()[0]
- neutron_rtr_id = self._get_tag_dict(
- self.fc._fake_lrouter_dict[lr_uuid]['tags'])['q_router_id']
- if action_callback:
- action_callback(ls_uuid, lp_uuid, lr_uuid)
- # Make chunk big enough to read everything
- if not sp:
- sp = sync.SyncParameters(100)
- self._plugin._synchronizer._synchronize_state(sp)
- # Verify element is in expected status
- # TODO(salv-orlando): Verify status for all elements
- ctx = context.get_admin_context()
- neutron_net = self._plugin.get_network(ctx, neutron_net_id)
- neutron_port = self._plugin.get_port(ctx, neutron_port_id)
- neutron_rtr = self._plugin.get_router(ctx, neutron_rtr_id)
- self.assertEqual(exp_net_status, neutron_net['status'])
- self.assertEqual(exp_port_status, neutron_port['status'])
- self.assertEqual(exp_router_status, neutron_rtr['status'])
-
- def _action_callback_status_down(self, ls_uuid, lp_uuid, lr_uuid):
- self.fc._fake_lswitch_dict[ls_uuid]['status'] = 'false'
- self.fc._fake_lswitch_lport_dict[lp_uuid]['status'] = 'false'
- self.fc._fake_lrouter_dict[lr_uuid]['status'] = 'false'
-
- def test_initial_sync(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- self._test_sync(
- constants.NET_STATUS_ACTIVE,
- constants.PORT_STATUS_ACTIVE,
- constants.NET_STATUS_ACTIVE)
-
- def test_initial_sync_with_resources_down(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- self._test_sync(
- constants.NET_STATUS_DOWN, constants.PORT_STATUS_DOWN,
- constants.NET_STATUS_DOWN, self._action_callback_status_down)
-
- def test_resync_with_resources_down(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- sp = sync.SyncParameters(100)
- self._plugin._synchronizer._synchronize_state(sp)
- # Ensure the synchronizer performs a resync
- sp.init_sync_performed = True
- self._test_sync(
- constants.NET_STATUS_DOWN, constants.PORT_STATUS_DOWN,
- constants.NET_STATUS_DOWN, self._action_callback_status_down,
- sp=sp)
-
- def _action_callback_del_resource(self, ls_uuid, lp_uuid, lr_uuid):
- del self.fc._fake_lswitch_dict[ls_uuid]
- del self.fc._fake_lswitch_lport_dict[lp_uuid]
- del self.fc._fake_lrouter_dict[lr_uuid]
-
- def test_initial_sync_with_resources_removed(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- self._test_sync(
- constants.NET_STATUS_ERROR, constants.PORT_STATUS_ERROR,
- constants.NET_STATUS_ERROR, self._action_callback_del_resource)
-
- def test_resync_with_resources_removed(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- sp = sync.SyncParameters(100)
- self._plugin._synchronizer._synchronize_state(sp)
- # Ensure the synchronizer performs a resync
- sp.init_sync_performed = True
- self._test_sync(
- constants.NET_STATUS_ERROR, constants.PORT_STATUS_ERROR,
- constants.NET_STATUS_ERROR, self._action_callback_del_resource,
- sp=sp)
-
- def _test_sync_with_chunk_larger_maxpagesize(
- self, net_size, port_size, router_size, chunk_size, exp_calls):
- ctx = context.get_admin_context()
- real_func = nsxlib.get_single_query_page
- sp = sync.SyncParameters(chunk_size)
- with self._populate_data(ctx, net_size=net_size,
- port_size=port_size,
- router_size=router_size):
- with mock.patch.object(sync, 'MAX_PAGE_SIZE', 15):
- # The following mock is just for counting calls,
- # but we will still run the actual function
- with mock.patch.object(
- nsxlib, 'get_single_query_page',
- side_effect=real_func) as mock_get_page:
- self._test_sync(
- constants.NET_STATUS_ACTIVE,
- constants.PORT_STATUS_ACTIVE,
- constants.NET_STATUS_ACTIVE,
- sp=sp)
- # As each resource type does not exceed the maximum page size,
- # the method should be called once for each resource type
- self.assertEqual(exp_calls, mock_get_page.call_count)
-
- def test_sync_chunk_larger_maxpagesize_no_multiple_requests(self):
- # total resource size = 20
- # total size for each resource does not exceed max page size (15)
- self._test_sync_with_chunk_larger_maxpagesize(
- net_size=5, port_size=2, router_size=5,
- chunk_size=20, exp_calls=3)
-
- def test_sync_chunk_larger_maxpagesize_triggers_multiple_requests(self):
- # total resource size = 48
- # total size for each resource does exceed max page size (15)
- self._test_sync_with_chunk_larger_maxpagesize(
- net_size=16, port_size=1, router_size=16,
- chunk_size=48, exp_calls=6)
-
- def test_sync_multi_chunk(self):
- # The fake NSX API client cannot be used for this test
- ctx = context.get_admin_context()
- # Generate 4 networks, 1 port per network, and 4 routers
- with self._populate_data(ctx, net_size=4, port_size=1, router_size=4):
- fake_lswitches = jsonutils.loads(
- self.fc.handle_get('/ws.v1/lswitch'))['results']
- fake_lrouters = jsonutils.loads(
- self.fc.handle_get('/ws.v1/lrouter'))['results']
- fake_lswitchports = jsonutils.loads(
- self.fc.handle_get('/ws.v1/lswitch/*/lport'))['results']
- return_values = [
- # Chunk 0 - lswitches
- (fake_lswitches, None, 4),
- # Chunk 0 - lrouters
- (fake_lrouters[:2], 'xxx', 4),
- # Chunk 0 - lports (size only)
- ([], 'start', 4),
- # Chunk 1 - lrouters (2 more) (lswitches are skipped)
- (fake_lrouters[2:], None, None),
- # Chunk 1 - lports
- (fake_lswitchports, None, 4)]
-
- def fake_fetch_data(*args, **kwargs):
- return return_values.pop(0)
-
- # 2 Chunks, with 6 resources each.
- # 1st chunk lswitches and lrouters
- # 2nd chunk lrouters and lports
- # Mock _fetch_data
- with mock.patch.object(
- self._plugin._synchronizer, '_fetch_data',
- side_effect=fake_fetch_data):
- sp = sync.SyncParameters(6)
-
- def do_chunk(chunk_idx, ls_cursor, lr_cursor, lp_cursor):
- self._plugin._synchronizer._synchronize_state(sp)
- self.assertEqual(chunk_idx, sp.current_chunk)
- self.assertEqual(ls_cursor, sp.ls_cursor)
- self.assertEqual(lr_cursor, sp.lr_cursor)
- self.assertEqual(lp_cursor, sp.lp_cursor)
-
- # check 1st chunk
- do_chunk(1, None, 'xxx', 'start')
- # check 2nd chunk
- do_chunk(0, None, None, None)
- # Chunk size should have stayed the same
- self.assertEqual(sp.chunk_size, 6)
-
- def test_synchronize_network(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a network down to verify synchronization
- ls_uuid = self.fc._fake_lswitch_dict.keys()[0]
- q_net_id = self._get_tag_dict(
- self.fc._fake_lswitch_dict[ls_uuid]['tags'])['quantum_net_id']
- self.fc._fake_lswitch_dict[ls_uuid]['status'] = 'false'
- q_net_data = self._plugin._get_network(ctx, q_net_id)
- self._plugin._synchronizer.synchronize_network(ctx, q_net_data)
- # Reload from db
- q_nets = self._plugin.get_networks(ctx)
- for q_net in q_nets:
- if q_net['id'] == q_net_id:
- exp_status = constants.NET_STATUS_DOWN
- else:
- exp_status = constants.NET_STATUS_ACTIVE
- self.assertEqual(exp_status, q_net['status'])
-
- def test_synchronize_network_not_found_in_db_no_raise(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a network down to verify synchronization
- ls_uuid = self.fc._fake_lswitch_dict.keys()[0]
- q_net_id = self._get_tag_dict(
- self.fc._fake_lswitch_dict[ls_uuid]['tags'])['quantum_net_id']
- self.fc._fake_lswitch_dict[ls_uuid]['status'] = 'false'
- q_net_data = self._plugin._get_network(ctx, q_net_id)
- with mock.patch.object(self._plugin,
- '_get_network') as _get_network:
- _get_network.side_effect = n_exc.NetworkNotFound(
- net_id=q_net_data['id'])
- self._plugin._synchronizer.synchronize_network(ctx, q_net_data)
-
- def test_synchronize_network_on_get(self):
- cfg.CONF.set_override('always_read_status', True, 'NSX_SYNC')
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a network down to verify punctual synchronization
- ls_uuid = self.fc._fake_lswitch_dict.keys()[0]
- q_net_id = self._get_tag_dict(
- self.fc._fake_lswitch_dict[ls_uuid]['tags'])['quantum_net_id']
- self.fc._fake_lswitch_dict[ls_uuid]['status'] = 'false'
- q_net_data = self._plugin.get_network(ctx, q_net_id)
- self.assertEqual(constants.NET_STATUS_DOWN, q_net_data['status'])
-
- def test_synchronize_port_not_found_in_db_no_raise(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a port down to verify synchronization
- lp_uuid = self.fc._fake_lswitch_lport_dict.keys()[0]
- lport = self.fc._fake_lswitch_lport_dict[lp_uuid]
- q_port_id = self._get_tag_dict(lport['tags'])['q_port_id']
- lport['status'] = 'true'
- q_port_data = self._plugin._get_port(ctx, q_port_id)
- with mock.patch.object(self._plugin,
- '_get_port') as _get_port:
- _get_port.side_effect = n_exc.PortNotFound(
- port_id=q_port_data['id'])
- self._plugin._synchronizer.synchronize_port(ctx, q_port_data)
-
- def test_synchronize_port(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a port down to verify synchronization
- lp_uuid = self.fc._fake_lswitch_lport_dict.keys()[0]
- lport = self.fc._fake_lswitch_lport_dict[lp_uuid]
- q_port_id = self._get_tag_dict(lport['tags'])['q_port_id']
- lport['status'] = 'true'
- q_port_data = self._plugin._get_port(ctx, q_port_id)
- self._plugin._synchronizer.synchronize_port(ctx, q_port_data)
- # Reload from db
- q_ports = self._plugin.get_ports(ctx)
- for q_port in q_ports:
- if q_port['id'] == q_port_id:
- exp_status = constants.PORT_STATUS_ACTIVE
- else:
- exp_status = constants.PORT_STATUS_DOWN
- self.assertEqual(exp_status, q_port['status'])
-
- def test_synchronize_port_on_get(self):
- cfg.CONF.set_override('always_read_status', True, 'NSX_SYNC')
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a port down to verify punctual synchronization
- lp_uuid = self.fc._fake_lswitch_lport_dict.keys()[0]
- lport = self.fc._fake_lswitch_lport_dict[lp_uuid]
- q_port_id = self._get_tag_dict(lport['tags'])['q_port_id']
- lport['status'] = 'false'
- q_port_data = self._plugin.get_port(ctx, q_port_id)
- self.assertEqual(constants.PORT_STATUS_DOWN,
- q_port_data['status'])
-
- def test_synchronize_routernot_found_in_db_no_raise(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a router down to verify synchronization
- lr_uuid = self.fc._fake_lrouter_dict.keys()[0]
- q_rtr_id = self._get_tag_dict(
- self.fc._fake_lrouter_dict[lr_uuid]['tags'])['q_router_id']
- self.fc._fake_lrouter_dict[lr_uuid]['status'] = 'false'
- q_rtr_data = self._plugin._get_router(ctx, q_rtr_id)
- with mock.patch.object(self._plugin,
- '_get_router') as _get_router:
- _get_router.side_effect = l3.RouterNotFound(
- router_id=q_rtr_data['id'])
- self._plugin._synchronizer.synchronize_router(ctx, q_rtr_data)
-
- def test_synchronize_router(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a router down to verify synchronization
- lr_uuid = self.fc._fake_lrouter_dict.keys()[0]
- q_rtr_id = self._get_tag_dict(
- self.fc._fake_lrouter_dict[lr_uuid]['tags'])['q_router_id']
- self.fc._fake_lrouter_dict[lr_uuid]['status'] = 'false'
- q_rtr_data = self._plugin._get_router(ctx, q_rtr_id)
- self._plugin._synchronizer.synchronize_router(ctx, q_rtr_data)
- # Reload from db
- q_routers = self._plugin.get_routers(ctx)
- for q_rtr in q_routers:
- if q_rtr['id'] == q_rtr_id:
- exp_status = constants.NET_STATUS_DOWN
- else:
- exp_status = constants.NET_STATUS_ACTIVE
- self.assertEqual(exp_status, q_rtr['status'])
-
- def test_synchronize_router_nsx_mapping_not_found(self):
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a router down to verify synchronization
- lr_uuid = self.fc._fake_lrouter_dict.keys()[0]
- q_rtr_id = self._get_tag_dict(
- self.fc._fake_lrouter_dict[lr_uuid]['tags'])['q_router_id']
- self.fc._fake_lrouter_dict[lr_uuid]['status'] = 'false'
- q_rtr_data = self._plugin._get_router(ctx, q_rtr_id)
-
- # delete router mapping from db.
- db.delete_neutron_nsx_router_mapping(ctx.session, q_rtr_id)
- # pop router from fake nsx client
- router_data = self.fc._fake_lrouter_dict.pop(lr_uuid)
-
- self._plugin._synchronizer.synchronize_router(ctx, q_rtr_data)
- # Reload from db
- q_routers = self._plugin.get_routers(ctx)
- for q_rtr in q_routers:
- if q_rtr['id'] == q_rtr_id:
- exp_status = constants.NET_STATUS_ERROR
- else:
- exp_status = constants.NET_STATUS_ACTIVE
- self.assertEqual(exp_status, q_rtr['status'])
- # put the router database since we don't handle missing
- # router data in the fake nsx api_client
- self.fc._fake_lrouter_dict[lr_uuid] = router_data
-
- def test_synchronize_router_on_get(self):
- cfg.CONF.set_override('always_read_status', True, 'NSX_SYNC')
- ctx = context.get_admin_context()
- with self._populate_data(ctx):
- # Put a router down to verify punctual synchronization
- lr_uuid = self.fc._fake_lrouter_dict.keys()[0]
- q_rtr_id = self._get_tag_dict(
- self.fc._fake_lrouter_dict[lr_uuid]['tags'])['q_router_id']
- self.fc._fake_lrouter_dict[lr_uuid]['status'] = 'false'
- q_rtr_data = self._plugin.get_router(ctx, q_rtr_id)
- self.assertEqual(constants.NET_STATUS_DOWN, q_rtr_data['status'])
-
- def test_sync_nsx_failure_backoff(self):
- self.mock_api.return_value.request.side_effect = api_exc.RequestTimeout
- # chunk size won't matter here
- sp = sync.SyncParameters(999)
- for i in range(10):
- self.assertEqual(
- min(64, 2 ** i),
- self._plugin._synchronizer._synchronize_state(sp))
+++ /dev/null
-# Copyright (c) 2013 VMware.
-#
-# 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 mock
-
-from neutron.db import api as db_api
-from neutron.extensions import multiprovidernet as mpnet
-from neutron.extensions import providernet as pnet
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.api_client import exception as api_exc
-from neutron.plugins.vmware.common import exceptions as nsx_exc
-from neutron.plugins.vmware.common import nsx_utils
-from neutron.plugins.vmware.common import utils
-from neutron.plugins.vmware.dbexts import nsx_models
-from neutron.plugins.vmware import nsxlib
-from neutron.tests import base
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.nsxlib import base as nsx_base
-
-
-class NsxUtilsTestCase(base.BaseTestCase):
-
- def _mock_port_mapping_db_calls(self, ret_value):
- # Mock relevant db calls
- # This will allow for avoiding setting up the plugin
- # for creating db entries
- mock.patch(vmware.nsx_method('get_nsx_switch_and_port_id',
- module_name='dbexts.db'),
- return_value=ret_value).start()
- mock.patch(vmware.nsx_method('add_neutron_nsx_port_mapping',
- module_name='dbexts.db')).start()
- mock.patch(vmware.nsx_method('delete_neutron_nsx_port_mapping',
- module_name='dbexts.db')).start()
-
- def _mock_network_mapping_db_calls(self, ret_value):
- # Mock relevant db calls
- # This will allow for avoiding setting up the plugin
- # for creating db entries
- mock.patch(vmware.nsx_method('get_nsx_switch_ids',
- module_name='dbexts.db'),
- return_value=ret_value).start()
- mock.patch(vmware.nsx_method('add_neutron_nsx_network_mapping',
- module_name='dbexts.db')).start()
-
- def _mock_router_mapping_db_calls(self, ret_value):
- # Mock relevant db calls
- # This will allow for avoiding setting up the plugin
- # for creating db entries
- mock.patch(vmware.nsx_method('get_nsx_router_id',
- module_name='dbexts.db'),
- return_value=ret_value).start()
- mock.patch(vmware.nsx_method('add_neutron_nsx_router_mapping',
- module_name='dbexts.db')).start()
-
- def _verify_get_nsx_switch_and_port_id(self, exp_ls_uuid, exp_lp_uuid):
- # The nsxlib and db calls are mocked, therefore the cluster
- # and the neutron_port_id parameters can be set to None
- ls_uuid, lp_uuid = nsx_utils.get_nsx_switch_and_port_id(
- db_api.get_session(), None, None)
- self.assertEqual(exp_ls_uuid, ls_uuid)
- self.assertEqual(exp_lp_uuid, lp_uuid)
-
- def _verify_get_nsx_switch_ids(self, exp_ls_uuids):
- # The nsxlib and db calls are mocked, therefore the cluster
- # and the neutron_router_id parameters can be set to None
- ls_uuids = nsx_utils.get_nsx_switch_ids(
- db_api.get_session(), None, None)
- for ls_uuid in ls_uuids or []:
- self.assertIn(ls_uuid, exp_ls_uuids)
- exp_ls_uuids.remove(ls_uuid)
- self.assertFalse(exp_ls_uuids)
-
- def _verify_get_nsx_router_id(self, exp_lr_uuid):
- # The nsxlib and db calls are mocked, therefore the cluster
- # and the neutron_router_id parameters can be set to None
- lr_uuid = nsx_utils.get_nsx_router_id(db_api.get_session(), None, None)
- self.assertEqual(exp_lr_uuid, lr_uuid)
-
- def test_get_nsx_switch_and_port_id_from_db_mappings(self):
- # This test is representative of the 'standard' case in which both the
- # switch and the port mappings were stored in the neutron db
- exp_ls_uuid = uuidutils.generate_uuid()
- exp_lp_uuid = uuidutils.generate_uuid()
- ret_value = exp_ls_uuid, exp_lp_uuid
- self._mock_port_mapping_db_calls(ret_value)
- self._verify_get_nsx_switch_and_port_id(exp_ls_uuid, exp_lp_uuid)
-
- def test_get_nsx_switch_and_port_id_only_port_db_mapping(self):
- # This test is representative of the case in which a port with a nsx
- # db mapping in the havana db was upgraded to icehouse
- exp_ls_uuid = uuidutils.generate_uuid()
- exp_lp_uuid = uuidutils.generate_uuid()
- ret_value = None, exp_lp_uuid
- self._mock_port_mapping_db_calls(ret_value)
- with mock.patch(vmware.nsx_method('query_lswitch_lports',
- module_name='nsxlib.switch'),
- return_value=[{'uuid': exp_lp_uuid,
- '_relations': {
- 'LogicalSwitchConfig': {
- 'uuid': exp_ls_uuid}
- }}]):
- self._verify_get_nsx_switch_and_port_id(exp_ls_uuid, exp_lp_uuid)
-
- def test_get_nsx_switch_and_port_id_no_db_mapping(self):
- # This test is representative of the case where db mappings where not
- # found for a given port identifier
- exp_ls_uuid = uuidutils.generate_uuid()
- exp_lp_uuid = uuidutils.generate_uuid()
- ret_value = None, None
- self._mock_port_mapping_db_calls(ret_value)
- with mock.patch(vmware.nsx_method('query_lswitch_lports',
- module_name='nsxlib.switch'),
- return_value=[{'uuid': exp_lp_uuid,
- '_relations': {
- 'LogicalSwitchConfig': {
- 'uuid': exp_ls_uuid}
- }}]):
- self._verify_get_nsx_switch_and_port_id(exp_ls_uuid, exp_lp_uuid)
-
- def test_get_nsx_switch_and_port_id_no_mappings_returns_none(self):
- # This test verifies that the function return (None, None) if the
- # mappings are not found both in the db and the backend
- ret_value = None, None
- self._mock_port_mapping_db_calls(ret_value)
- with mock.patch(vmware.nsx_method('query_lswitch_lports',
- module_name='nsxlib.switch'),
- return_value=[]):
- self._verify_get_nsx_switch_and_port_id(None, None)
-
- def test_get_nsx_switch_ids_from_db_mappings(self):
- # This test is representative of the 'standard' case in which the
- # lswitch mappings were stored in the neutron db
- exp_ls_uuids = [uuidutils.generate_uuid()]
- self._mock_network_mapping_db_calls(exp_ls_uuids)
- self._verify_get_nsx_switch_ids(exp_ls_uuids)
-
- def test_get_nsx_switch_ids_no_db_mapping(self):
- # This test is representative of the case where db mappings where not
- # found for a given network identifier
- exp_ls_uuids = [uuidutils.generate_uuid()]
- self._mock_network_mapping_db_calls(None)
- with mock.patch(vmware.nsx_method('get_lswitches',
- module_name='nsxlib.switch'),
- return_value=[{'uuid': uuid}
- for uuid in exp_ls_uuids]):
- self._verify_get_nsx_switch_ids(exp_ls_uuids)
-
- def test_get_nsx_switch_ids_no_mapping_returns_None(self):
- # This test verifies that the function returns None if the mappings
- # are not found both in the db and in the backend
- self._mock_network_mapping_db_calls(None)
- with mock.patch(vmware.nsx_method('get_lswitches',
- module_name='nsxlib.switch'),
- return_value=[]):
- self._verify_get_nsx_switch_ids(None)
-
- def test_get_nsx_router_id_from_db_mappings(self):
- # This test is representative of the 'standard' case in which the
- # router mapping was stored in the neutron db
- exp_lr_uuid = uuidutils.generate_uuid()
- self._mock_router_mapping_db_calls(exp_lr_uuid)
- self._verify_get_nsx_router_id(exp_lr_uuid)
-
- def test_get_nsx_router_id_no_db_mapping(self):
- # This test is representative of the case where db mappings where not
- # found for a given port identifier
- exp_lr_uuid = uuidutils.generate_uuid()
- self._mock_router_mapping_db_calls(None)
- with mock.patch(vmware.nsx_method('query_lrouters',
- module_name='nsxlib.router'),
- return_value=[{'uuid': exp_lr_uuid}]):
- self._verify_get_nsx_router_id(exp_lr_uuid)
-
- def test_get_nsx_router_id_no_mapping_returns_None(self):
- # This test verifies that the function returns None if the mapping
- # are not found both in the db and in the backend
- self._mock_router_mapping_db_calls(None)
- with mock.patch(vmware.nsx_method('query_lrouters',
- module_name='nsxlib.router'),
- return_value=[]):
- self._verify_get_nsx_router_id(None)
-
- def test_check_and_truncate_name_with_none(self):
- name = None
- result = utils.check_and_truncate(name)
- self.assertEqual('', result)
-
- def test_check_and_truncate_name_with_short_name(self):
- name = 'foo_port_name'
- result = utils.check_and_truncate(name)
- self.assertEqual(name, result)
-
- def test_check_and_truncate_name_long_name(self):
- name = 'this_is_a_port_whose_name_is_longer_than_40_chars'
- result = utils.check_and_truncate(name)
- self.assertEqual(len(result), utils.MAX_DISPLAY_NAME_LEN)
-
- def test_build_uri_path_plain(self):
- result = nsxlib._build_uri_path('RESOURCE')
- self.assertEqual("%s/%s" % (nsxlib.URI_PREFIX, 'RESOURCE'), result)
-
- def test_build_uri_path_with_field(self):
- result = nsxlib._build_uri_path('RESOURCE', fields='uuid')
- expected = "%s/%s?fields=uuid" % (nsxlib.URI_PREFIX, 'RESOURCE')
- self.assertEqual(expected, result)
-
- def test_build_uri_path_with_filters(self):
- filters = {"tag": 'foo', "tag_scope": "scope_foo"}
- result = nsxlib._build_uri_path('RESOURCE', filters=filters)
- expected = (
- "%s/%s?tag=foo&tag_scope=scope_foo" %
- (nsxlib.URI_PREFIX, 'RESOURCE'))
- self.assertEqual(expected, result)
-
- def test_build_uri_path_with_resource_id(self):
- res = 'RESOURCE'
- res_id = 'resource_id'
- result = nsxlib._build_uri_path(res, resource_id=res_id)
- expected = "%s/%s/%s" % (nsxlib.URI_PREFIX, res, res_id)
- self.assertEqual(expected, result)
-
- def test_build_uri_path_with_parent_and_resource_id(self):
- parent_res = 'RESOURCE_PARENT'
- child_res = 'RESOURCE_CHILD'
- res = '%s/%s' % (child_res, parent_res)
- par_id = 'parent_resource_id'
- res_id = 'resource_id'
- result = nsxlib._build_uri_path(
- res, parent_resource_id=par_id, resource_id=res_id)
- expected = ("%s/%s/%s/%s/%s" %
- (nsxlib.URI_PREFIX, parent_res, par_id, child_res, res_id))
- self.assertEqual(expected, result)
-
- def test_build_uri_path_with_attachment(self):
- parent_res = 'RESOURCE_PARENT'
- child_res = 'RESOURCE_CHILD'
- res = '%s/%s' % (child_res, parent_res)
- par_id = 'parent_resource_id'
- res_id = 'resource_id'
- result = nsxlib._build_uri_path(res, parent_resource_id=par_id,
- resource_id=res_id, is_attachment=True)
- expected = ("%s/%s/%s/%s/%s/%s" %
- (nsxlib.URI_PREFIX, parent_res,
- par_id, child_res, res_id, 'attachment'))
- self.assertEqual(expected, result)
-
- def test_build_uri_path_with_extra_action(self):
- parent_res = 'RESOURCE_PARENT'
- child_res = 'RESOURCE_CHILD'
- res = '%s/%s' % (child_res, parent_res)
- par_id = 'parent_resource_id'
- res_id = 'resource_id'
- result = nsxlib._build_uri_path(res, parent_resource_id=par_id,
- resource_id=res_id, extra_action='doh')
- expected = ("%s/%s/%s/%s/%s/%s" %
- (nsxlib.URI_PREFIX, parent_res,
- par_id, child_res, res_id, 'doh'))
- self.assertEqual(expected, result)
-
- def _mock_sec_group_mapping_db_calls(self, ret_value):
- mock.patch(vmware.nsx_method('get_nsx_security_group_id',
- module_name='dbexts.db'),
- return_value=ret_value).start()
- mock.patch(vmware.nsx_method('add_neutron_nsx_security_group_mapping',
- module_name='dbexts.db')).start()
-
- def _verify_get_nsx_sec_profile_id(self, exp_sec_prof_uuid):
- # The nsxlib and db calls are mocked, therefore the cluster
- # and the neutron_id parameters can be set to None
- sec_prof_uuid = nsx_utils.get_nsx_security_group_id(
- db_api.get_session(), None, None)
- self.assertEqual(exp_sec_prof_uuid, sec_prof_uuid)
-
- def test_get_nsx_sec_profile_id_from_db_mappings(self):
- # This test is representative of the 'standard' case in which the
- # security group mapping was stored in the neutron db
- exp_sec_prof_uuid = uuidutils.generate_uuid()
- self._mock_sec_group_mapping_db_calls(exp_sec_prof_uuid)
- self._verify_get_nsx_sec_profile_id(exp_sec_prof_uuid)
-
- def test_get_nsx_sec_profile_id_no_db_mapping(self):
- # This test is representative of the case where db mappings where not
- # found for a given security profile identifier
- exp_sec_prof_uuid = uuidutils.generate_uuid()
- self._mock_sec_group_mapping_db_calls(None)
- with mock.patch(vmware.nsx_method('query_security_profiles',
- module_name='nsxlib.secgroup'),
- return_value=[{'uuid': exp_sec_prof_uuid}]):
- self._verify_get_nsx_sec_profile_id(exp_sec_prof_uuid)
-
- def test_get_nsx_sec_profile_id_no_mapping_returns_None(self):
- # This test verifies that the function returns None if the mapping
- # are not found both in the db and in the backend
- self._mock_sec_group_mapping_db_calls(None)
- with mock.patch(vmware.nsx_method('query_security_profiles',
- module_name='nsxlib.secgroup'),
- return_value=[]):
- self._verify_get_nsx_sec_profile_id(None)
-
- def test_convert_to_nsx_transport_zones_no_multiprovider(self):
- test_net = {'id': 'whatever'}
- results = nsx_utils.convert_to_nsx_transport_zones(
- 'meh_zone_uuid', test_net,
- default_transport_type='meh_transport_type')
- self.assertEqual(1, len(results))
- result = results[0]
- self.assertEqual('meh_zone_uuid', result['zone_uuid'])
- self.assertEqual('meh_transport_type', result['transport_type'])
-
- def _verify_nsx_transport_zones(self, results):
- self.assertEqual(2, len(results))
- result_1 = results[0]
- self.assertEqual(utils.NetworkTypes.BRIDGE,
- result_1['transport_type'])
- self.assertEqual([{'transport': 66}],
- result_1['binding_config']['vlan_translation'])
- self.assertEqual('whatever_tz_1', result_1['zone_uuid'])
- result_2 = results[1]
- self.assertEqual(utils.NetworkTypes.STT,
- result_2['transport_type'])
- self.assertNotIn('binding_config', result_2)
- self.assertEqual('whatever_tz_2', result_2['zone_uuid'])
-
- def test_convert_to_nsx_transport_zones_with_bindings(self):
- binding_1 = nsx_models.TzNetworkBinding(
- 'whatever',
- utils.NetworkTypes.VLAN,
- 'whatever_tz_1',
- 66)
- binding_2 = nsx_models.TzNetworkBinding(
- 'whatever',
- utils.NetworkTypes.STT,
- 'whatever_tz_2',
- None)
- results = nsx_utils.convert_to_nsx_transport_zones(
- 'meh_zone_uuid', None, bindings=[binding_1, binding_2])
- self._verify_nsx_transport_zones(results)
-
- def test_convert_to_nsx_transport_zones_with_multiprovider(self):
- segments = [
- {pnet.NETWORK_TYPE: utils.NetworkTypes.VLAN,
- pnet.PHYSICAL_NETWORK: 'whatever_tz_1',
- pnet.SEGMENTATION_ID: 66},
- {pnet.NETWORK_TYPE: utils.NetworkTypes.STT,
- pnet.PHYSICAL_NETWORK: 'whatever_tz_2'},
- ]
- results = nsx_utils.convert_to_nsx_transport_zones(
- 'meh_zone_uuid', {'id': 'whatever_net', mpnet.SEGMENTS: segments})
- self._verify_nsx_transport_zones(results)
-
-
-class ClusterManagementTestCase(nsx_base.NsxlibTestCase):
-
- def test_cluster_in_readonly_mode(self):
- with mock.patch.object(self.fake_cluster.api_client,
- 'request',
- side_effect=api_exc.ReadOnlyMode):
- self.assertRaises(nsx_exc.MaintenanceInProgress,
- nsxlib.do_request, cluster=self.fake_cluster)
-
- def test_cluster_method_not_implemented(self):
- self.assertRaises(api_exc.NsxApiException,
- nsxlib.do_request,
- nsxlib.HTTP_GET,
- nsxlib._build_uri_path('MY_FAKE_RESOURCE',
- resource_id='foo'),
- cluster=self.fake_cluster)
+++ /dev/null
-# Copyright 2013 VMware, 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 copy
-
-from oslo_serialization import jsonutils
-
-from neutron.openstack.common import uuidutils
-from neutron.plugins.vmware.vshield.common import exceptions
-
-
-class FakeVcns(object):
-
- errors = {
- 303: exceptions.ResourceRedirect,
- 400: exceptions.RequestBad,
- 403: exceptions.Forbidden,
- 404: exceptions.ResourceNotFound,
- 415: exceptions.MediaTypeUnsupport,
- 503: exceptions.ServiceUnavailable
- }
-
- def __init__(self, unique_router_name=True):
- self._jobs = {}
- self._job_idx = 0
- self._edges = {}
- self._edge_idx = 0
- self._lswitches = {}
- self._unique_router_name = unique_router_name
- self._fake_nsx_api = None
- self.fake_firewall_dict = {}
- self.temp_firewall = {
- "firewallRules": {
- "firewallRules": []
- }
- }
- self.fake_ipsecvpn_dict = {}
- self.temp_ipsecvpn = {
- 'featureType': "ipsec_4.0",
- 'enabled': True,
- 'sites': {'sites': []}}
- self._fake_virtualservers_dict = {}
- self._fake_pools_dict = {}
- self._fake_monitors_dict = {}
- self._fake_app_profiles_dict = {}
- self._fake_loadbalancer_config = {}
-
- def set_fake_nsx_api(self, fake_nsx_api):
- self._fake_nsx_api = fake_nsx_api
-
- def _validate_edge_name(self, name):
- for edge_id, edge in self._edges.iteritems():
- if edge['name'] == name:
- return False
- return True
-
- def deploy_edge(self, request):
- if (self._unique_router_name and
- not self._validate_edge_name(request['name'])):
- header = {
- 'status': 400
- }
- msg = ('Edge name should be unique for tenant. Edge %s '
- 'already exists for default tenant.') % request['name']
- response = {
- 'details': msg,
- 'errorCode': 10085,
- 'rootCauseString': None,
- 'moduleName': 'vShield Edge',
- 'errorData': None
- }
- return (header, jsonutils.dumps(response))
-
- self._job_idx = self._job_idx + 1
- job_id = "jobdata-%d" % self._job_idx
- self._edge_idx = self._edge_idx + 1
- edge_id = "edge-%d" % self._edge_idx
- self._jobs[job_id] = edge_id
- self._edges[edge_id] = {
- 'name': request['name'],
- 'request': request,
- 'nat_rules': None,
- 'nat_rule_id': 0
- }
- header = {
- 'status': 200,
- 'location': 'https://host/api/4.0/jobs/%s' % job_id
- }
- response = ''
- return (header, response)
-
- def get_edge_id(self, job_id):
- if job_id not in self._jobs:
- raise Exception(_("Job %s does not nexist") % job_id)
-
- header = {
- 'status': 200
- }
- response = {
- 'edgeId': self._jobs[job_id]
- }
- return (header, response)
-
- def get_edge_deploy_status(self, edge_id):
- if edge_id not in self._edges:
- raise Exception(_("Edge %s does not exist") % edge_id)
- header = {
- 'status': 200,
- }
- response = {
- 'systemStatus': 'good'
- }
- return (header, response)
-
- def delete_edge(self, edge_id):
- if edge_id not in self._edges:
- raise Exception(_("Edge %s does not exist") % edge_id)
- del self._edges[edge_id]
- header = {
- 'status': 200
- }
- response = ''
- return (header, response)
-
- def update_interface(self, edge_id, vnic):
- header = {
- 'status': 200
- }
- response = ''
- return (header, response)
-
- def get_nat_config(self, edge_id):
- if edge_id not in self._edges:
- raise Exception(_("Edge %s does not exist") % edge_id)
- edge = self._edges[edge_id]
- rules = edge['nat_rules']
- if rules is None:
- rules = {
- 'rules': {
- 'natRulesDtos': []
- },
- 'version': 1
- }
- header = {
- 'status': 200
- }
- rules['version'] = 1
- return (header, rules)
-
- def update_nat_config(self, edge_id, nat):
- if edge_id not in self._edges:
- raise Exception(_("Edge %s does not exist") % edge_id)
- edge = self._edges[edge_id]
- max_rule_id = edge['nat_rule_id']
- rules = copy.deepcopy(nat)
- for rule in rules['rules']['natRulesDtos']:
- rule_id = rule.get('ruleId', 0)
- if rule_id > max_rule_id:
- max_rule_id = rule_id
- for rule in rules['rules']['natRulesDtos']:
- if 'ruleId' not in rule:
- max_rule_id = max_rule_id + 1
- rule['ruleId'] = max_rule_id
- edge['nat_rules'] = rules
- edge['nat_rule_id'] = max_rule_id
- header = {
- 'status': 200
- }
- response = ''
- return (header, response)
-
- def delete_nat_rule(self, edge_id, rule_id):
- if edge_id not in self._edges:
- raise Exception(_("Edge %s does not exist") % edge_id)
-
- edge = self._edges[edge_id]
- rules = edge['nat_rules']
- rule_to_delete = None
- for rule in rules['rules']['natRulesDtos']:
- if rule_id == rule['ruleId']:
- rule_to_delete = rule
- break
- if rule_to_delete is None:
- raise Exception(_("Rule id %d doest not exist") % rule_id)
-
- rules['rules']['natRulesDtos'].remove(rule_to_delete)
-
- header = {
- 'status': 200
- }
- response = ''
- return (header, response)
-
- def get_edge_status(self, edge_id):
- if edge_id not in self._edges:
- raise Exception(_("Edge %s does not exist") % edge_id)
-
- header = {
- 'status': 200
- }
- response = {
- 'edgeStatus': 'GREEN'
- }
- return (header, response)
-
- def get_edges(self):
- header = {
- 'status': 200
- }
- edges = []
- for edge_id in self._edges:
- edges.append({
- 'id': edge_id,
- 'edgeStatus': 'GREEN'
- })
- response = {
- 'edgePage': {
- 'data': edges
- }
- }
- return (header, response)
-
- def update_routes(self, edge_id, routes):
- header = {
- 'status': 200
- }
- response = ''
- return (header, response)
-
- def create_lswitch(self, lsconfig):
- # The lswitch is created via VCNS API so the fake nsx_api will not
- # see it. Added to fake nsx_api here.
- if self._fake_nsx_api:
- lswitch = \
- self._fake_nsx_api._add_lswitch(jsonutils.dumps(lsconfig))
- else:
- lswitch = lsconfig
- lswitch['uuid'] = uuidutils.generate_uuid()
- self._lswitches[lswitch['uuid']] = lswitch
- header = {
- 'status': 200
- }
- lswitch['_href'] = '/api/ws.v1/lswitch/%s' % lswitch['uuid']
- return (header, lswitch)
-
- def delete_lswitch(self, id):
- if id not in self._lswitches:
- raise Exception(_("Lswitch %s does not exist") % id)
- del self._lswitches[id]
- if self._fake_nsx_api:
- # TODO(fank): fix the hack
- del self._fake_nsx_api._fake_lswitch_dict[id]
- header = {
- 'status': 200
- }
- response = ''
- return (header, response)
-
- def update_firewall(self, edge_id, fw_req):
- self.fake_firewall_dict[edge_id] = fw_req
- rules = self.fake_firewall_dict[edge_id][
- 'firewallRules']['firewallRules']
- index = 10
- for rule in rules:
- rule['ruleId'] = index
- index += 10
- header = {'status': 204}
- response = ""
- return self.return_helper(header, response)
-
- def delete_firewall(self, edge_id):
- header = {'status': 404}
- if edge_id in self.fake_firewall_dict:
- header = {'status': 204}
- del self.fake_firewall_dict[edge_id]
- response = ""
- return self.return_helper(header, response)
-
- def update_firewall_rule(self, edge_id, vcns_rule_id, fwr_req):
- if edge_id not in self.fake_firewall_dict:
- raise Exception(_("Edge %s does not exist") % edge_id)
- header = {'status': 404}
- rules = self.fake_firewall_dict[edge_id][
- 'firewallRules']['firewallRules']
- for rule in rules:
- if rule['ruleId'] == int(vcns_rule_id):
- header['status'] = 204
- rule.update(fwr_req)
- break
- response = ""
- return self.return_helper(header, response)
-
- def delete_firewall_rule(self, edge_id, vcns_rule_id):
- if edge_id not in self.fake_firewall_dict:
- raise Exception(_("Edge %s does not exist") % edge_id)
- header = {'status': 404}
- rules = self.fake_firewall_dict[edge_id][
- 'firewallRules']['firewallRules']
- for index in range(len(rules)):
- if rules[index]['ruleId'] == int(vcns_rule_id):
- header['status'] = 204
- del rules[index]
- break
- response = ""
- return self.return_helper(header, response)
-
- def add_firewall_rule_above(self, edge_id, ref_vcns_rule_id, fwr_req):
- if edge_id not in self.fake_firewall_dict:
- raise Exception(_("Edge %s does not exist") % edge_id)
- header = {'status': 404}
- rules = self.fake_firewall_dict[edge_id][
- 'firewallRules']['firewallRules']
- pre = 0
- for index in range(len(rules)):
- if rules[index]['ruleId'] == int(ref_vcns_rule_id):
- rules.insert(index, fwr_req)
- rules[index]['ruleId'] = (int(ref_vcns_rule_id) + pre) / 2
- header = {
- 'status': 204,
- 'location': "https://host/api/4.0/edges/edge_id/firewall"
- "/config/rules/%s" % rules[index]['ruleId']}
- break
- pre = int(rules[index]['ruleId'])
- response = ""
- return self.return_helper(header, response)
-
- def add_firewall_rule(self, edge_id, fwr_req):
- if edge_id not in self.fake_firewall_dict:
- self.fake_firewall_dict[edge_id] = self.temp_firewall
- rules = self.fake_firewall_dict[edge_id][
- 'firewallRules']['firewallRules']
- rules.append(fwr_req)
- index = len(rules)
- rules[index - 1]['ruleId'] = index * 10
- header = {
- 'status': 204,
- 'location': "https://host/api/4.0/edges/edge_id/firewall"
- "/config/rules/%s" % rules[index - 1]['ruleId']}
- response = ""
- return self.return_helper(header, response)
-
- def get_firewall(self, edge_id):
- if edge_id not in self.fake_firewall_dict:
- self.fake_firewall_dict[edge_id] = self.temp_firewall
- header = {'status': 204}
- response = self.fake_firewall_dict[edge_id]
- return self.return_helper(header, response)
-
- def get_firewall_rule(self, edge_id, vcns_rule_id):
- if edge_id not in self.fake_firewall_dict:
- raise Exception(_("Edge %s does not exist") % edge_id)
- header = {'status': 404}
- response = ""
- rules = self.fake_firewall_dict[edge_id][
- 'firewallRules']['firewallRules']
- for rule in rules:
- if rule['ruleId'] == int(vcns_rule_id):
- header['status'] = 204
- response = rule
- break
- return self.return_helper(header, response)
-
- def is_name_unique(self, objs_dict, name):
- return name not in [obj_dict['name']
- for obj_dict in objs_dict.values()]
-
- def create_vip(self, edge_id, vip_new):
- header = {'status': 403}
- response = ""
- if not self._fake_virtualservers_dict.get(edge_id):
- self._fake_virtualservers_dict[edge_id] = {}
- if not self.is_name_unique(self._fake_virtualservers_dict[edge_id],
- vip_new['name']):
- return self.return_helper(header, response)
- vip_vseid = uuidutils.generate_uuid()
- self._fake_virtualservers_dict[edge_id][vip_vseid] = vip_new
- header = {
- 'status': 204,
- 'location': "https://host/api/4.0/edges/edge_id"
- "/loadbalancer/config/%s" % vip_vseid}
- return self.return_helper(header, response)
-
- def get_vip(self, edge_id, vip_vseid):
- header = {'status': 404}
- response = ""
- if not self._fake_virtualservers_dict.get(edge_id) or (
- not self._fake_virtualservers_dict[edge_id].get(vip_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- response = self._fake_virtualservers_dict[edge_id][vip_vseid]
- return self.return_helper(header, response)
-
- def update_vip(self, edge_id, vip_vseid, vip_new):
- header = {'status': 404}
- response = ""
- if not self._fake_virtualservers_dict.get(edge_id) or (
- not self._fake_virtualservers_dict[edge_id].get(vip_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- self._fake_virtualservers_dict[edge_id][vip_vseid].update(
- vip_new)
- return self.return_helper(header, response)
-
- def delete_vip(self, edge_id, vip_vseid):
- header = {'status': 404}
- response = ""
- if not self._fake_virtualservers_dict.get(edge_id) or (
- not self._fake_virtualservers_dict[edge_id].get(vip_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- del self._fake_virtualservers_dict[edge_id][vip_vseid]
- return self.return_helper(header, response)
-
- def create_pool(self, edge_id, pool_new):
- header = {'status': 403}
- response = ""
- if not self._fake_pools_dict.get(edge_id):
- self._fake_pools_dict[edge_id] = {}
- if not self.is_name_unique(self._fake_pools_dict[edge_id],
- pool_new['name']):
- return self.return_helper(header, response)
- pool_vseid = uuidutils.generate_uuid()
- self._fake_pools_dict[edge_id][pool_vseid] = pool_new
- header = {
- 'status': 204,
- 'location': "https://host/api/4.0/edges/edge_id"
- "/loadbalancer/config/%s" % pool_vseid}
- return self.return_helper(header, response)
-
- def get_pool(self, edge_id, pool_vseid):
- header = {'status': 404}
- response = ""
- if not self._fake_pools_dict.get(edge_id) or (
- not self._fake_pools_dict[edge_id].get(pool_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- response = self._fake_pools_dict[edge_id][pool_vseid]
- return self.return_helper(header, response)
-
- def update_pool(self, edge_id, pool_vseid, pool_new):
- header = {'status': 404}
- response = ""
- if not self._fake_pools_dict.get(edge_id) or (
- not self._fake_pools_dict[edge_id].get(pool_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- self._fake_pools_dict[edge_id][pool_vseid].update(
- pool_new)
- return self.return_helper(header, response)
-
- def delete_pool(self, edge_id, pool_vseid):
- header = {'status': 404}
- response = ""
- if not self._fake_pools_dict.get(edge_id) or (
- not self._fake_pools_dict[edge_id].get(pool_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- del self._fake_pools_dict[edge_id][pool_vseid]
- return self.return_helper(header, response)
-
- def create_health_monitor(self, edge_id, monitor_new):
- if not self._fake_monitors_dict.get(edge_id):
- self._fake_monitors_dict[edge_id] = {}
- monitor_vseid = uuidutils.generate_uuid()
- self._fake_monitors_dict[edge_id][monitor_vseid] = monitor_new
- header = {
- 'status': 204,
- 'location': "https://host/api/4.0/edges/edge_id"
- "/loadbalancer/config/%s" % monitor_vseid}
- response = ""
- return self.return_helper(header, response)
-
- def get_health_monitor(self, edge_id, monitor_vseid):
- header = {'status': 404}
- response = ""
- if not self._fake_monitors_dict.get(edge_id) or (
- not self._fake_monitors_dict[edge_id].get(monitor_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- response = self._fake_monitors_dict[edge_id][monitor_vseid]
- return self.return_helper(header, response)
-
- def update_health_monitor(self, edge_id, monitor_vseid, monitor_new):
- header = {'status': 404}
- response = ""
- if not self._fake_monitors_dict.get(edge_id) or (
- not self._fake_monitors_dict[edge_id].get(monitor_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- self._fake_monitors_dict[edge_id][monitor_vseid].update(
- monitor_new)
- return self.return_helper(header, response)
-
- def delete_health_monitor(self, edge_id, monitor_vseid):
- header = {'status': 404}
- response = ""
- if not self._fake_monitors_dict.get(edge_id) or (
- not self._fake_monitors_dict[edge_id].get(monitor_vseid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- del self._fake_monitors_dict[edge_id][monitor_vseid]
- return self.return_helper(header, response)
-
- def create_app_profile(self, edge_id, app_profile):
- if not self._fake_app_profiles_dict.get(edge_id):
- self._fake_app_profiles_dict[edge_id] = {}
- app_profileid = uuidutils.generate_uuid()
- self._fake_app_profiles_dict[edge_id][app_profileid] = app_profile
- header = {
- 'status': 204,
- 'location': "https://host/api/4.0/edges/edge_id"
- "/loadbalancer/config/%s" % app_profileid}
- response = ""
- return self.return_helper(header, response)
-
- def update_app_profile(self, edge_id, app_profileid, app_profile):
- header = {'status': 404}
- response = ""
- if not self._fake_app_profiles_dict.get(edge_id) or (
- not self._fake_app_profiles_dict[edge_id].get(app_profileid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- self._fake_app_profiles_dict[edge_id][app_profileid].update(
- app_profile)
- return self.return_helper(header, response)
-
- def delete_app_profile(self, edge_id, app_profileid):
- header = {'status': 404}
- response = ""
- if not self._fake_app_profiles_dict.get(edge_id) or (
- not self._fake_app_profiles_dict[edge_id].get(app_profileid)):
- return self.return_helper(header, response)
- header = {'status': 204}
- del self._fake_app_profiles_dict[edge_id][app_profileid]
- return self.return_helper(header, response)
-
- def get_loadbalancer_config(self, edge_id):
- header = {'status': 204}
- response = {'config': False}
- if self._fake_loadbalancer_config[edge_id]:
- response['config'] = self._fake_loadbalancer_config[edge_id]
- return self.return_helper(header, response)
-
- def update_ipsec_config(self, edge_id, ipsec_config):
- self.fake_ipsecvpn_dict[edge_id] = ipsec_config
- header = {'status': 204}
- response = ""
- return self.return_helper(header, response)
-
- def delete_ipsec_config(self, edge_id):
- header = {'status': 404}
- if edge_id in self.fake_ipsecvpn_dict:
- header = {'status': 204}
- del self.fake_ipsecvpn_dict[edge_id]
- response = ""
- return self.return_helper(header, response)
-
- def get_ipsec_config(self, edge_id):
- if edge_id not in self.fake_ipsecvpn_dict:
- self.fake_ipsecvpn_dict[edge_id] = self.temp_ipsecvpn
- header = {'status': 204}
- response = self.fake_ipsecvpn_dict[edge_id]
- return self.return_helper(header, response)
-
- def enable_service_loadbalancer(self, edge_id, config):
- header = {'status': 204}
- response = ""
- self._fake_loadbalancer_config[edge_id] = True
- return self.return_helper(header, response)
-
- def return_helper(self, header, response):
- status = int(header['status'])
- if 200 <= status <= 300:
- return (header, response)
- if status in self.errors:
- cls = self.errors[status]
- else:
- cls = exceptions.VcnsApiException
- raise cls(
- status=status, header=header, uri='fake_url', response=response)
-
- def reset_all(self):
- self._jobs.clear()
- self._edges.clear()
- self._lswitches.clear()
- self.fake_firewall_dict = {}
- self._fake_virtualservers_dict = {}
- self._fake_pools_dict = {}
- self._fake_monitors_dict = {}
- self._fake_app_profiles_dict = {}
- self._fake_loadbalancer_config = {}
+++ /dev/null
-# Copyright 2013 OpenStack Foundation.
-#
-# 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.
-
-from eventlet import greenthread
-import mock
-
-from neutron.plugins.vmware.vshield.common import constants as vcns_const
-from neutron.plugins.vmware.vshield.tasks import constants as ts_const
-from neutron.plugins.vmware.vshield.tasks import tasks as ts
-from neutron.plugins.vmware.vshield import vcns_driver
-from neutron.tests import base
-from neutron.tests.unit import vmware
-from neutron.tests.unit.vmware.vshield import fake_vcns
-
-VCNS_CONFIG_FILE = vmware.get_fake_conf("vcns.ini.test")
-
-ts.TaskManager.set_default_interval(100)
-
-
-class VcnsDriverTaskManagerTestCase(base.BaseTestCase):
-
- def setUp(self):
- super(VcnsDriverTaskManagerTestCase, self).setUp()
- self.manager = ts.TaskManager()
- self.manager.start(100)
-
- def tearDown(self):
- self.manager.stop()
- # Task manager should not leave running threads around
- # if _thread is None it means it was killed in stop()
- self.assertIsNone(self.manager._thread)
- super(VcnsDriverTaskManagerTestCase, self).tearDown()
-
- def _test_task_manager_task_process_state(self, sync_exec=False):
- def _task_failed(task, reason):
- task.userdata['result'] = False
- task.userdata['error'] = reason
-
- def _check_state(task, exp_state):
- if not task.userdata.get('result', True):
- return False
-
- state = task.userdata['state']
- if state != exp_state:
- msg = "state %d expect %d" % (
- state, exp_state)
- _task_failed(task, msg)
- return False
-
- task.userdata['state'] = state + 1
- return True
-
- def _exec(task):
- if not _check_state(task, 1):
- return ts_const.TaskStatus.ERROR
-
- if task.userdata['sync_exec']:
- return ts_const.TaskStatus.COMPLETED
- else:
- return ts_const.TaskStatus.PENDING
-
- def _status(task):
- if task.userdata['sync_exec']:
- _task_failed(task, "_status callback triggered")
-
- state = task.userdata['state']
- if state == 3:
- _check_state(task, 3)
- return ts_const.TaskStatus.PENDING
- else:
- _check_state(task, 4)
- return ts_const.TaskStatus.COMPLETED
-
- def _result(task):
- if task.userdata['sync_exec']:
- exp_state = 3
- else:
- exp_state = 5
-
- _check_state(task, exp_state)
-
- def _start_monitor(task):
- _check_state(task, 0)
-
- def _executed_monitor(task):
- _check_state(task, 2)
-
- def _result_monitor(task):
- if task.userdata['sync_exec']:
- exp_state = 4
- else:
- exp_state = 6
-
- if _check_state(task, exp_state):
- task.userdata['result'] = True
- else:
- task.userdata['result'] = False
-
- userdata = {
- 'state': 0,
- 'sync_exec': sync_exec
- }
- task = ts.Task('name', 'res', _exec, _status, _result, userdata)
- task.add_start_monitor(_start_monitor)
- task.add_executed_monitor(_executed_monitor)
- task.add_result_monitor(_result_monitor)
-
- self.manager.add(task)
-
- task.wait(ts_const.TaskState.RESULT)
-
- self.assertTrue(userdata['result'])
-
- def test_task_manager_task_sync_exec_process_state(self):
- self._test_task_manager_task_process_state(sync_exec=True)
-
- def test_task_manager_task_async_exec_process_state(self):
- self._test_task_manager_task_process_state(sync_exec=False)
-
- def test_task_manager_task_ordered_process(self):
- def _task_failed(task, reason):
- task.userdata['result'] = False
- task.userdata['error'] = reason
-
- def _exec(task):
- task.userdata['executed'] = True
- return ts_const.TaskStatus.PENDING
-
- def _status(task):
- return ts_const.TaskStatus.COMPLETED
-
- def _result(task):
- next_task = task.userdata.get('next')
- if next_task:
- if next_task.userdata.get('executed'):
- _task_failed(next_task, "executed premature")
- if task.userdata.get('result', True):
- task.userdata['result'] = True
-
- tasks = []
- prev = None
- last_task = None
- for i in range(5):
- name = "name-%d" % i
- task = ts.Task(name, 'res', _exec, _status, _result, {})
- tasks.append(task)
- if prev:
- prev.userdata['next'] = task
- prev = task
- last_task = task
-
- for task in tasks:
- self.manager.add(task)
-
- last_task.wait(ts_const.TaskState.RESULT)
-
- for task in tasks:
- self.assertTrue(task.userdata['result'])
-
- def test_task_manager_task_parallel_process(self):
- tasks = []
-
- def _exec(task):
- task.userdata['executed'] = True
- return ts_const.TaskStatus.PENDING
-
- def _status(task):
- for t in tasks:
- if not t.userdata.get('executed'):
- t.userdata['resut'] = False
- return ts_const.TaskStatus.COMPLETED
-
- def _result(task):
- if (task.userdata.get('result') is None and
- task.status == ts_const.TaskStatus.COMPLETED):
- task.userdata['result'] = True
- else:
- task.userdata['result'] = False
-
- for i in range(5):
- name = "name-%d" % i
- res = 'resource-%d' % i
- task = ts.Task(name, res, _exec, _status, _result, {})
- tasks.append(task)
- self.manager.add(task)
-
- for task in tasks:
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(task.userdata['result'])
-
- def _test_task_manager_stop(self, exec_wait=False, result_wait=False,
- stop_wait=0):
- def _exec(task):
- if exec_wait:
- greenthread.sleep(0.01)
- return ts_const.TaskStatus.PENDING
-
- def _status(task):
- greenthread.sleep(0.01)
- return ts_const.TaskStatus.PENDING
-
- def _result(task):
- if result_wait:
- greenthread.sleep(0)
- pass
-
- manager = ts.TaskManager().start(100)
- manager.stop()
- # Task manager should not leave running threads around
- # if _thread is None it means it was killed in stop()
- self.assertIsNone(manager._thread)
- manager.start(100)
-
- alltasks = {}
- for i in range(100):
- res = 'res-%d' % i
- tasks = []
- for i in range(100):
- task = ts.Task('name', res, _exec, _status, _result)
- manager.add(task)
- tasks.append(task)
- alltasks[res] = tasks
-
- greenthread.sleep(stop_wait)
- manager.stop()
- # Task manager should not leave running threads around
- # if _thread is None it means it was killed in stop()
- self.assertIsNone(manager._thread)
-
- for res, tasks in alltasks.iteritems():
- for task in tasks:
- self.assertEqual(task.status, ts_const.TaskStatus.ABORT)
-
- def test_task_manager_stop_1(self):
- self._test_task_manager_stop(True, True, 0)
-
- def test_task_manager_stop_2(self):
- self._test_task_manager_stop(True, True, 1)
-
- def test_task_manager_stop_3(self):
- self._test_task_manager_stop(False, False, 0)
-
- def test_task_manager_stop_4(self):
- self._test_task_manager_stop(False, False, 1)
-
- def test_task_pending_task(self):
- def _exec(task):
- task.userdata['executing'] = True
- while not task.userdata['tested']:
- greenthread.sleep(0)
- task.userdata['executing'] = False
- return ts_const.TaskStatus.COMPLETED
-
- userdata = {
- 'executing': False,
- 'tested': False
- }
- manager = ts.TaskManager().start(100)
- task = ts.Task('name', 'res', _exec, userdata=userdata)
- manager.add(task)
-
- while not userdata['executing']:
- greenthread.sleep(0)
- self.assertTrue(manager.has_pending_task())
-
- userdata['tested'] = True
- while userdata['executing']:
- greenthread.sleep(0)
- self.assertFalse(manager.has_pending_task())
-
-
-class VcnsDriverTestCase(base.BaseTestCase):
-
- def vcns_patch(self):
- instance = self.mock_vcns.start()
- instance.return_value.deploy_edge.side_effect = self.fc.deploy_edge
- instance.return_value.get_edge_id.side_effect = self.fc.get_edge_id
- instance.return_value.get_edge_deploy_status.side_effect = (
- self.fc.get_edge_deploy_status)
- instance.return_value.delete_edge.side_effect = self.fc.delete_edge
- instance.return_value.update_interface.side_effect = (
- self.fc.update_interface)
- instance.return_value.get_nat_config.side_effect = (
- self.fc.get_nat_config)
- instance.return_value.update_nat_config.side_effect = (
- self.fc.update_nat_config)
- instance.return_value.delete_nat_rule.side_effect = (
- self.fc.delete_nat_rule)
- instance.return_value.get_edge_status.side_effect = (
- self.fc.get_edge_status)
- instance.return_value.get_edges.side_effect = self.fc.get_edges
- instance.return_value.update_routes.side_effect = (
- self.fc.update_routes)
- instance.return_value.create_lswitch.side_effect = (
- self.fc.create_lswitch)
- instance.return_value.delete_lswitch.side_effect = (
- self.fc.delete_lswitch)
-
- def setUp(self):
- super(VcnsDriverTestCase, self).setUp()
-
- self.config_parse(args=['--config-file', VCNS_CONFIG_FILE])
-
- self.fc = fake_vcns.FakeVcns()
- self.mock_vcns = mock.patch(vmware.VCNS_NAME, autospec=True)
- self.vcns_patch()
-
- self.addCleanup(self.fc.reset_all)
-
- self.vcns_driver = vcns_driver.VcnsDriver(self)
-
- self.edge_id = None
- self.result = None
-
- def tearDown(self):
- self.vcns_driver.task_manager.stop()
- # Task manager should not leave running threads around
- # if _thread is None it means it was killed in stop()
- self.assertIsNone(self.vcns_driver.task_manager._thread)
- super(VcnsDriverTestCase, self).tearDown()
-
- def _deploy_edge(self):
- task = self.vcns_driver.deploy_edge(
- 'router-id', 'myedge', 'internal-network', {}, wait_for_exec=True)
- self.assertEqual(self.edge_id, 'edge-1')
- task.wait(ts_const.TaskState.RESULT)
- return task
-
- def edge_deploy_started(self, task):
- self.edge_id = task.userdata['edge_id']
-
- def edge_deploy_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['edge_deploy_result'] = True
-
- def edge_delete_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['edge_delete_result'] = True
-
- def snat_create_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['snat_create_result'] = True
-
- def snat_delete_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['snat_delete_result'] = True
-
- def dnat_create_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['dnat_create_result'] = True
-
- def dnat_delete_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['dnat_delete_result'] = True
-
- def nat_update_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['nat_update_result'] = True
-
- def routes_update_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['routes_update_result'] = True
-
- def interface_update_result(self, task):
- if task.status == ts_const.TaskStatus.COMPLETED:
- task.userdata['jobdata']['interface_update_result'] = True
-
- def test_deploy_edge(self):
- jobdata = {}
- task = self.vcns_driver.deploy_edge(
- 'router-id', 'myedge', 'internal-network', jobdata=jobdata,
- wait_for_exec=True)
- self.assertEqual(self.edge_id, 'edge-1')
- task.wait(ts_const.TaskState.RESULT)
- self.assertEqual(task.status, ts_const.TaskStatus.COMPLETED)
- self.assertTrue(jobdata.get('edge_deploy_result'))
-
- def test_deploy_edge_fail(self):
- task1 = self.vcns_driver.deploy_edge(
- 'router-1', 'myedge', 'internal-network', {}, wait_for_exec=True)
- task2 = self.vcns_driver.deploy_edge(
- 'router-2', 'myedge', 'internal-network', {}, wait_for_exec=True)
- task1.wait(ts_const.TaskState.RESULT)
- task2.wait(ts_const.TaskState.RESULT)
- self.assertEqual(task2.status, ts_const.TaskStatus.ERROR)
-
- def test_get_edge_status(self):
- self._deploy_edge()
- status = self.vcns_driver.get_edge_status(self.edge_id)
- self.assertEqual(status, vcns_const.RouterStatus.ROUTER_STATUS_ACTIVE)
-
- def test_get_edges(self):
- self._deploy_edge()
- edges = self.vcns_driver.get_edges_statuses()
- found = False
- for edge_id, status in edges.iteritems():
- if edge_id == self.edge_id:
- found = True
- break
- self.assertTrue(found)
-
- def _create_nat_rule(self, edge_id, action, org, translated):
- jobdata = {}
- if action == 'snat':
- task = self.vcns_driver.create_snat_rule(
- 'router-id', edge_id, org, translated, jobdata=jobdata)
- key = 'snat_create_result'
- else:
- task = self.vcns_driver.create_dnat_rule(
- 'router-id', edge_id, org, translated, jobdata=jobdata)
- key = 'dnat_create_result'
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(jobdata.get(key))
-
- def _delete_nat_rule(self, edge_id, action, addr):
- jobdata = {}
- if action == 'snat':
- task = self.vcns_driver.delete_snat_rule(
- 'router-id', edge_id, addr, jobdata=jobdata)
- key = 'snat_delete_result'
- else:
- task = self.vcns_driver.delete_dnat_rule(
- 'router-id', edge_id, addr, jobdata=jobdata)
- key = 'dnat_delete_result'
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(jobdata.get(key))
-
- def _test_create_nat_rule(self, action):
- self._deploy_edge()
- addr = '192.168.1.1'
- translated = '10.0.0.1'
- self._create_nat_rule(self.edge_id, action, addr, translated)
-
- natcfg = self.vcns_driver.get_nat_config(self.edge_id)
- for rule in natcfg['rules']['natRulesDtos']:
- if (rule['originalAddress'] == addr and
- rule['translatedAddress'] == translated and
- rule['action'] == action):
- break
- else:
- self.assertTrue(False)
-
- def _test_delete_nat_rule(self, action):
- self._deploy_edge()
- addr = '192.168.1.1'
- translated = '10.0.0.1'
- self._create_nat_rule(self.edge_id, action, addr, translated)
- if action == 'snat':
- self._delete_nat_rule(self.edge_id, action, addr)
- else:
- self._delete_nat_rule(self.edge_id, action, translated)
- natcfg = self.vcns_driver.get_nat_config(self.edge_id)
- for rule in natcfg['rules']['natRulesDtos']:
- if (rule['originalAddress'] == addr and
- rule['translatedAddress'] == translated and
- rule['action'] == action):
- self.assertTrue(False)
- break
-
- def test_create_snat_rule(self):
- self._test_create_nat_rule('snat')
-
- def test_delete_snat_rule(self):
- self._test_delete_nat_rule('snat')
-
- def test_create_dnat_rule(self):
- self._test_create_nat_rule('dnat')
-
- def test_delete_dnat_rule(self):
- self._test_delete_nat_rule('dnat')
-
- def test_update_nat_rules(self):
- self._deploy_edge()
- jobdata = {}
- snats = [{
- 'src': '192.168.1.0/24',
- 'translated': '10.0.0.1'
- }, {
- 'src': '192.168.2.0/24',
- 'translated': '10.0.0.2'
- }, {
- 'src': '192.168.3.0/24',
- 'translated': '10.0.0.3'
- }
- ]
- dnats = [{
- 'dst': '100.0.0.4',
- 'translated': '192.168.1.1'
- }, {
- 'dst': '100.0.0.5',
- 'translated': '192.168.2.1'
- }
- ]
- task = self.vcns_driver.update_nat_rules(
- 'router-id', self.edge_id, snats, dnats, jobdata=jobdata)
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(jobdata.get('nat_update_result'))
-
- natcfg = self.vcns_driver.get_nat_config(self.edge_id)
- rules = natcfg['rules']['natRulesDtos']
- self.assertEqual(len(rules), 2 * len(dnats) + len(snats))
- self.natEquals(rules[0], dnats[0])
- self.natEquals(rules[1], self.snat_for_dnat(dnats[0]))
- self.natEquals(rules[2], dnats[1])
- self.natEquals(rules[3], self.snat_for_dnat(dnats[1]))
- self.natEquals(rules[4], snats[0])
- self.natEquals(rules[5], snats[1])
- self.natEquals(rules[6], snats[2])
-
- def snat_for_dnat(self, dnat):
- return {
- 'src': dnat['translated'],
- 'translated': dnat['dst']
- }
-
- def natEquals(self, rule, exp):
- addr = exp.get('src')
- if not addr:
- addr = exp.get('dst')
-
- self.assertEqual(rule['originalAddress'], addr)
- self.assertEqual(rule['translatedAddress'], exp['translated'])
-
- def test_update_routes(self):
- self._deploy_edge()
- jobdata = {}
- routes = [{
- 'cidr': '192.168.1.0/24',
- 'nexthop': '169.254.2.1'
- }, {
- 'cidr': '192.168.2.0/24',
- 'nexthop': '169.254.2.1'
- }, {
- 'cidr': '192.168.3.0/24',
- 'nexthop': '169.254.2.1'
- }
- ]
- task = self.vcns_driver.update_routes(
- 'router-id', self.edge_id, '10.0.0.1', routes, jobdata=jobdata)
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(jobdata.get('routes_update_result'))
-
- def test_update_interface(self):
- self._deploy_edge()
- jobdata = {}
- task = self.vcns_driver.update_interface(
- 'router-id', self.edge_id, vcns_const.EXTERNAL_VNIC_INDEX,
- 'network-id', address='100.0.0.3', netmask='255.255.255.0',
- jobdata=jobdata)
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(jobdata.get('interface_update_result'))
-
- def test_delete_edge(self):
- self._deploy_edge()
- jobdata = {}
- task = self.vcns_driver.delete_edge(
- 'router-id', self.edge_id, jobdata=jobdata)
- task.wait(ts_const.TaskState.RESULT)
- self.assertTrue(jobdata.get('edge_delete_result'))
-
- def test_create_lswitch(self):
- tz_config = [{
- 'transport_zone_uuid': 'tz-uuid'
- }]
- lswitch = self.vcns_driver.create_lswitch('lswitch', tz_config)
- self.assertEqual(lswitch['display_name'], 'lswitch')
- self.assertEqual(lswitch['type'], 'LogicalSwitchConfig')
- self.assertIn('uuid', lswitch)
-
- def test_delete_lswitch(self):
- tz_config = {
- 'transport_zone_uuid': 'tz-uuid'
- }
- lswitch = self.vcns_driver.create_lswitch('lswitch', tz_config)
- self.vcns_driver.delete_lswitch(lswitch['uuid'])
[entry_points]
console_scripts =
neutron-cisco-cfg-agent = neutron.plugins.cisco.cfg_agent.cfg_agent:main
- neutron-check-nsx-config = neutron.plugins.vmware.check_nsx_config:main
neutron-db-manage = neutron.db.migration.cli:main
neutron-debug = neutron.debug.shell:main
neutron-dhcp-agent = neutron.cmd.eventlet.agents.dhcp:main
neutron-nec-agent = neutron.plugins.nec.agent.nec_neutron_agent:main
neutron-netns-cleanup = neutron.cmd.netns_cleanup:main
neutron-ns-metadata-proxy = neutron.cmd.eventlet.agents.metadata_proxy:main
- neutron-nsx-manage = neutron.plugins.vmware.shell:main
neutron-nvsd-agent = neutron.plugins.oneconvergence.agent.nvsd_neutron_agent:main
neutron-openvswitch-agent = neutron.plugins.openvswitch.agent.ovs_neutron_agent:main
neutron-ovs-cleanup = neutron.cmd.ovs_cleanup:main
metaplugin = neutron.plugins.metaplugin.meta_neutron_plugin:MetaPluginV2
oneconvergence = neutron.plugins.oneconvergence.plugin:OneConvergencePluginV2
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
- vmware = neutron.plugins.vmware.plugin:NsxPlugin
+ vmware = neutron.plugins.vmware.plugin:NsxMhPlugin
neutron.service_plugins =
dummy = neutron.tests.unit.dummy_plugin:DummyServicePlugin
router = neutron.services.l3_router.l3_router_plugin:L3RouterPlugin