[OVN] Import ovsdb related code
This patch imports ovsdb related code from networking_ovn. Previous paths in networking-ovn tree: ./networking_ovn/ovsdb/commands.py -> ./neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/commands.py ./networking_ovn/ovsdb/worker.py -> ./neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/worker.py ./networking_ovn/ovsdb/ovn_api.py -> ./neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/api.py ACL commands will be implemented when the related code is merged and could be tested properly. Related-Blueprint: neutron-ovn-merge Co-Authored-By: Reedip <rbanerje@redhat.com> Co-Authored-By: Numan Siddique <nusiddiq@redhat.com> Co-Authored-By: Flavio Fernandes <flaviof@redhat.com> Co-Authored-By: Terry Wilson <twilson@redhat.com> Co-Authored-By: Daniel Alvarez <dalvarez@redhat.com> Co-Authored-By: Changxun Zhou <zhoucx@dtdream.com> Co-Authored-By: Gal Sagie <gal.sagie@huawei.com> Co-Authored-By: Amitabha Biswas <abiswas@us.ibm.com> Co-Authored-By: Richard Theis <rtheis@us.ibm.com> Co-Authored-By: lzklibj <lzklibj@cn.ibm.com> Co-Authored-By: zhufl <zhu.fanglei@zte.com.cn> Co-Authored-By: Na <nazhu@cn.ibm.com> Co-Authored-By: Chandra S Vejendla <csvejend@us.ibm.com> Co-Authored-By: Gary Kotton <gkotton@vmware.com> Co-Authored-By: Aaron Rosen <aaronorosen@gmail.com> Co-Authored-By: Rodolfo Alonso Hernandez <ralonsoh@redhat.com> Change-Id: I9fe64f954d227efaab5e96c6150df44f36a2530achanges/96/696296/10
parent
65692127f6
commit
4b5cf9e5fb
@ -0,0 +1,702 @@
|
||||
# Copyright 2019 Red Hat, 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 abc
|
||||
|
||||
from ovsdbapp import api
|
||||
import six
|
||||
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class API(api.API):
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_lswitch_ext_ids(self, name, ext_ids, if_exists=True):
|
||||
"""Create a command to set OVN lswitch external ids
|
||||
|
||||
:param name: The name of the lswitch
|
||||
:type name: string
|
||||
:param ext_ids The external ids to set for the lswitch
|
||||
:type ext_ids: dictionary
|
||||
:param if_exists: Do not fail if lswitch does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_lswitch_port(self, lport_name, lswitch_name, may_exist=True,
|
||||
**columns):
|
||||
"""Create a command to add an OVN logical switch port
|
||||
|
||||
:param lport_name: The name of the lport
|
||||
:type lport_name: string
|
||||
:param lswitch_name: The name of the lswitch the lport is created on
|
||||
:type lswitch_name: string
|
||||
:param may_exist: Do not fail if lport already exists
|
||||
:type may_exist: bool
|
||||
:param columns: Dictionary of port columns
|
||||
Supported columns: macs, external_ids,
|
||||
parent_name, tag, enabled
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_lswitch_port(self, lport_name, if_exists=True, **columns):
|
||||
"""Create a command to set OVN logical switch port fields
|
||||
|
||||
:param lport_name: The name of the lport
|
||||
:type lport_name: string
|
||||
:param columns: Dictionary of port columns
|
||||
Supported columns: macs, external_ids,
|
||||
parent_name, tag, enabled
|
||||
:param if_exists: Do not fail if lport does not exist
|
||||
:type if_exists: bool
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_lswitch_port(self, lport_name=None, lswitch_name=None,
|
||||
ext_id=None, if_exists=True):
|
||||
"""Create a command to delete an OVN logical switch port
|
||||
|
||||
:param lport_name: The name of the lport
|
||||
:type lport_name: string
|
||||
:param lswitch_name: The name of the lswitch
|
||||
:type lswitch_name: string
|
||||
:param ext_id: The external id of the lport
|
||||
:type ext_id: pair of <ext_id_key ,ext_id_value>
|
||||
:param if_exists: Do not fail if the lport does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_lrouter(self, name, may_exist=True, **columns):
|
||||
"""Create a command to add an OVN lrouter
|
||||
|
||||
:param name: The id of the lrouter
|
||||
:type name: string
|
||||
:param may_exist: Do not fail if lrouter already exists
|
||||
:type may_exist: bool
|
||||
:param columns: Dictionary of lrouter columns
|
||||
Supported columns: external_ids, default_gw, ip
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_lrouter(self, name, if_exists=True, **columns):
|
||||
"""Update a command to add an OVN lrouter
|
||||
|
||||
:param name: The id of the lrouter
|
||||
:type name: string
|
||||
:param if_exists: Do not fail if the lrouter does not exist
|
||||
:type if_exists: bool
|
||||
:param columns: Dictionary of lrouter columns
|
||||
Supported columns: external_ids, default_gw, ip
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_lrouter(self, name, if_exists=True):
|
||||
"""Create a command to delete an OVN lrouter
|
||||
|
||||
:param name: The id of the lrouter
|
||||
:type name: string
|
||||
:param if_exists: Do not fail if the lrouter does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_lrouter_port(self, name, lrouter, may_exist=True,
|
||||
**columns):
|
||||
"""Create a command to add an OVN lrouter port
|
||||
|
||||
:param name: The unique name of the lrouter port
|
||||
:type name: string
|
||||
:param lrouter: The unique name of the lrouter
|
||||
:type lrouter: string
|
||||
:param lswitch: The unique name of the lswitch
|
||||
:type lswitch: string
|
||||
:param may_exist: If true, do not fail if lrouter port set
|
||||
already exists.
|
||||
:type may_exist: bool
|
||||
:param columns: Dictionary of lrouter columns
|
||||
Supported columns: external_ids, mac, network
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_lrouter_port(self, name, if_exists=True, **columns):
|
||||
"""Update a command to add an OVN lrouter port
|
||||
|
||||
:param name: The unique name of the lrouter port
|
||||
:type name: string
|
||||
:param if_exists: Do not fail if the lrouter port does not exist
|
||||
:type if_exists: bool
|
||||
:param columns: Dictionary of lrouter columns
|
||||
Supported columns: networks
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_lrouter_port(self, name, lrouter, if_exists=True):
|
||||
"""Create a command to delete an OVN lrouter port
|
||||
|
||||
:param name: The unique name of the lport
|
||||
:type name: string
|
||||
:param lrouter: The unique name of the lrouter
|
||||
:type lrouter: string
|
||||
:param if_exists: Do not fail if the lrouter port does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_lrouter_port_in_lswitch_port(
|
||||
self, lswitch_port, lrouter_port, is_gw_port=False, if_exists=True,
|
||||
lsp_address=ovn_const.DEFAULT_ADDR_FOR_LSP_WITH_PEER):
|
||||
"""Create a command to set lswitch_port as lrouter_port
|
||||
|
||||
:param lswitch_port: The name of logical switch port
|
||||
:type lswitch_port: string
|
||||
:param lrouter_port: The name of logical router port
|
||||
:type lrouter_port: string
|
||||
:param is_gw_port: True if logical router port is gw port
|
||||
:type is_gw_port: bool
|
||||
:param if_exists: Do not fail if the lswitch port does not exist
|
||||
:type if_exists: bool
|
||||
:param lsp_address: logical switch port's addresses to set
|
||||
:type lsp_address: string or list of strings
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_acl(self, lswitch, lport, **columns):
|
||||
"""Create an ACL for a logical port.
|
||||
|
||||
:param lswitch: The logical switch the port is attached to.
|
||||
:type lswitch: string
|
||||
:param lport: The logical port this ACL is associated with.
|
||||
:type lport: string
|
||||
:param columns: Dictionary of ACL columns
|
||||
Supported columns: see ACL table in OVN_Northbound
|
||||
:type columns: dictionary
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_acl(self, lswitch, lport, if_exists=True):
|
||||
"""Delete all ACLs for a logical port.
|
||||
|
||||
:param lswitch: The logical switch the port is attached to.
|
||||
:type lswitch: string
|
||||
:param lport: The logical port this ACL is associated with.
|
||||
:type lport: string
|
||||
:param if_exists: Do not fail if the ACL for this lport does not
|
||||
exist
|
||||
:type if_exists: bool
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_acls(self, lswitch_names, port_list, acl_new_values_dict,
|
||||
need_compare=True, is_add_acl=True):
|
||||
"""Update the list of acls on logical switches with new values.
|
||||
|
||||
:param lswitch_names: List of logical switch names
|
||||
:type lswitch_name: []
|
||||
:param port_list: Iterator of list of ports
|
||||
:type port_list: []
|
||||
:param acl_new_values_dict: Dictionary of acls indexed by port id
|
||||
:type acl_new_values_dict: {}
|
||||
:param need_compare: If acl_new_values_dict need compare
|
||||
with existing acls
|
||||
:type need_compare: bool
|
||||
:is_add_acl: If updating is caused by adding acl
|
||||
:type is_add_acl: bool
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_acl_by_id(self, acl_id):
|
||||
"""Get an ACL by its ID.
|
||||
|
||||
:param acl_id: ID of the ACL to lookup
|
||||
:type acl_id: string
|
||||
:returns The ACL row or None:
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_static_route(self, lrouter, **columns):
|
||||
"""Add static route to logical router.
|
||||
|
||||
:param lrouter: The unique name of the lrouter
|
||||
:type lrouter: string
|
||||
:param columns: Dictionary of static columns
|
||||
Supported columns: prefix, nexthop, valid
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_static_route(self, lrouter, ip_prefix, nexthop, if_exists=True):
|
||||
"""Delete static route from logical router.
|
||||
|
||||
:param lrouter: The unique name of the lrouter
|
||||
:type lrouter: string
|
||||
:param ip_prefix: The prefix of the static route
|
||||
:type ip_prefix: string
|
||||
:param nexthop: The nexthop of the static route
|
||||
:type nexthop: string
|
||||
:param if_exists: Do not fail if router does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_address_set(self, name, may_exist=True, **columns):
|
||||
"""Create an address set
|
||||
|
||||
:param name: The name of the address set
|
||||
:type name: string
|
||||
:param may_exist: Do not fail if address set already exists
|
||||
:type may_exist: bool
|
||||
:param columns: Dictionary of address set columns
|
||||
Supported columns: external_ids, addresses
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_address_set(self, name, if_exists=True):
|
||||
"""Delete an address set
|
||||
|
||||
:param name: The name of the address set
|
||||
:type name: string
|
||||
:param if_exists: Do not fail if the address set does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_address_set(self, name, addrs_add, addrs_remove,
|
||||
if_exists=True):
|
||||
"""Updates addresses in an address set
|
||||
|
||||
:param name: The name of the address set
|
||||
:type name: string
|
||||
:param addrs_add: The addresses to be added
|
||||
:type addrs_add: []
|
||||
:param addrs_remove: The addresses to be removed
|
||||
:type addrs_remove: []
|
||||
:param if_exists: Do not fail if the address set does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_address_set_ext_ids(self, name, external_ids, if_exists=True):
|
||||
"""Update external IDs for an address set
|
||||
|
||||
:param name: The name of the address set
|
||||
:type name: string
|
||||
:param external_ids: The external IDs for the address set
|
||||
:type external_ids: dict
|
||||
:param if_exists: Do not fail if the address set does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_all_chassis_gateway_bindings(self,
|
||||
chassis_candidate_list=None):
|
||||
"""Return a dictionary of chassis name:list of gateways
|
||||
|
||||
:param chassis_candidate_list: List of possible chassis candidates
|
||||
:type chassis_candidate_list: []
|
||||
:returns: {} of chassis to routers mapping
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_gateway_chassis_binding(self, gateway_id):
|
||||
"""Return the list of chassis to which the gateway is bound to
|
||||
|
||||
As one gateway can be hosted by multiple chassis, this method is
|
||||
returning a list of those chassis ordered by priority. This means
|
||||
that the first element of the list is the chassis hosting the
|
||||
gateway with the highest priority (which will likely be where
|
||||
the router port is going to be active).
|
||||
|
||||
:param gateway_id: The gateway id
|
||||
:type gateway_id: string
|
||||
:returns: a list of strings with the chassis names
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_unhosted_gateways(self, port_physnet_dict, chassis_physnets,
|
||||
gw_chassis):
|
||||
"""Return a list of gateways not hosted on chassis
|
||||
|
||||
:param port_physnet_dict: Dictionary of gateway ports and their physnet
|
||||
:param chassis_physnets: Dictionary of chassis and physnets
|
||||
:param gw_chassis: List of gateway chassis provided by admin
|
||||
through ovn-cms-options
|
||||
:returns: List of gateways not hosted on a valid
|
||||
chassis
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_dhcp_options(self, subnet_id, port_id=None, may_exist=True,
|
||||
**columns):
|
||||
"""Adds the DHCP options specified in the @columns in DHCP_Options
|
||||
|
||||
If the DHCP options already exist in the DHCP_Options table for
|
||||
the @subnet_id (and @lsp_name), updates the row, else creates a new
|
||||
row.
|
||||
|
||||
:param subnet_id: The subnet id to which the DHCP options belong
|
||||
to
|
||||
:type subnet_id: string
|
||||
:param port_id: The port id to which the DHCP options belong to
|
||||
if specified
|
||||
:type port_id: string
|
||||
:param may_exist: If true, checks if the DHCP options for
|
||||
subnet_id exists or not. If it already exists,
|
||||
it updates the row with the columns specified.
|
||||
Else creates a new row.
|
||||
:type may_exist: bool
|
||||
:type columns: Dictionary of DHCP_Options columns
|
||||
Supported columns: see DHCP_Options table in
|
||||
OVN_Northbound
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_dhcp_options(self, row_uuid, if_exists=True):
|
||||
"""Deletes the row in DHCP_Options with the @row_uuid
|
||||
|
||||
:param row_uuid: The UUID of the row to be deleted.
|
||||
:type row_uuid: string
|
||||
:param if_exists: Do not fail if the DHCP_Options row does not
|
||||
exist
|
||||
:type if_exists: bool
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_subnet_dhcp_options(self, subnet_id, with_ports=False):
|
||||
"""Returns the Subnet DHCP options as a dictionary
|
||||
|
||||
:param subnet_id: The subnet id whose DHCP options are returned
|
||||
:type subnet_id: string
|
||||
:param with_ports: If True, also returns the ports DHCP options.
|
||||
:type with_ports: bool
|
||||
:returns: Returns a dictionary containing two keys:
|
||||
subnet and ports.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_subnets_dhcp_options(self, subnet_ids):
|
||||
"""Returns the Subnets DHCP options as list of dictionary
|
||||
|
||||
:param subnet_ids: The subnet ids whose DHCP options are returned
|
||||
:type subnet_ids: list of string
|
||||
:returns: Returns the columns of the DHCP_Options as list
|
||||
of dictionary. Empty list is returned if no
|
||||
DHCP_Options matched found.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_address_sets(self):
|
||||
"""Gets all address sets in the OVN_Northbound DB
|
||||
|
||||
:returns: dictionary indexed by name, DB columns as values
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_port_groups(self):
|
||||
"""Gets all port groups in the OVN_Northbound DB
|
||||
|
||||
:returns: dictionary indexed by name, DB columns as values
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_router_port_options(self, lsp_name):
|
||||
"""Get options set for lsp of type router
|
||||
|
||||
:returns: router port options
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_nat_rule_in_lrouter(self, lrouter, **columns):
|
||||
"""Add NAT rule in logical router
|
||||
|
||||
|
||||
:param lrouter: The unique name of the lrouter
|
||||
:type lrouter: string
|
||||
:param columns: Dictionary of nat columns
|
||||
Supported columns: type, logical_ip, external_ip
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_nat_rule_in_lrouter(self, lrouter, type, logical_ip,
|
||||
external_ip, if_exists=True):
|
||||
"""Delete NAT rule in logical router
|
||||
|
||||
:param lrouter: The unique name of the lrouter
|
||||
:type lrouter: string
|
||||
:param type: Type of nat. Supported values are 'snat', 'dnat'
|
||||
and 'dnat_and_snat'
|
||||
:type type: string
|
||||
:param logical_ip: IP or network that needs to be natted
|
||||
:type logical_ip: string
|
||||
:param external_ip: External IP to be used for nat
|
||||
:type external_ip: string
|
||||
:param if_exists: Do not fail if the Logical_Router row does not
|
||||
exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_lrouter_nat_rules(self, lrouter):
|
||||
"""Returns the nat rules of a router
|
||||
|
||||
:param lrouter: The unique name of the router
|
||||
:type lrouter: string
|
||||
:returns: A list of nat rules of the router, with each item
|
||||
as a dict with the keys - 'external_ip', 'logical_ip'
|
||||
'type' and 'uuid' of the row.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_nat_rule_in_lrouter(self, lrouter, nat_rule_uuid, **columns):
|
||||
"""Sets the NAT rule fields
|
||||
|
||||
:param lrouter: The unique name of the router to which this the
|
||||
NAT rule belongs to.
|
||||
:type lrouter: string
|
||||
:param nat_rule_uuid: The uuid of the NAT rule row to be updated.
|
||||
:type nat_rule_uuid: string
|
||||
:type columns: dictionary
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_lswitch(self, lswitch_name):
|
||||
"""Returns the logical switch
|
||||
|
||||
:param lswitch_name: The unique name of the logical switch
|
||||
:type lswitch_name: string
|
||||
:returns: Returns logical switch or None
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ls_and_dns_record(self, lswitch_name):
|
||||
"""Returns the logical switch and 'dns' records
|
||||
|
||||
:param lswitch_name: The unique name of the logical switch
|
||||
:type lswitch_name: string
|
||||
:returns: Returns logical switch and dns records as a tuple
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_floatingip(self, fip_id):
|
||||
"""Get a Floating IP by its ID
|
||||
|
||||
:param fip_id: The floating IP id
|
||||
:type fip_id: string
|
||||
:returns: The NAT rule row or None
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_floatingip_by_ips(self, router_id, logical_ip, external_ip):
|
||||
"""Get a Floating IP based on it's logical and external IPs.
|
||||
|
||||
DEPRECATED. In the Rocky release of OpenStack this method can be
|
||||
removed and get_floatingip() should be used instead. This method
|
||||
is a backward compatibility layer for the Pike -> Queens release.
|
||||
|
||||
:param router_id: The ID of the router to which the FIP belongs to.
|
||||
:type lrouter: string
|
||||
:param logical_ip: The FIP's logical IP address
|
||||
:type logical_ip: string
|
||||
:param external_ip: The FIP's external IP address
|
||||
:type external_ip: string
|
||||
:returns: The NAT rule row or None
|
||||
"""
|
||||
|
||||
def check_revision_number(self, name, resource, resource_type,
|
||||
if_exists=True):
|
||||
"""Compare the revision number from Neutron and OVN.
|
||||
|
||||
Check if the revision number in OVN is lower than the one from
|
||||
the Neutron resource, otherwise raise RevisionConflict and abort
|
||||
the transaction.
|
||||
|
||||
:param name: The unique name of the resource
|
||||
:type name: string
|
||||
:param resource: The neutron resource object
|
||||
:type resource: dictionary
|
||||
:param resource_type: The resource object type
|
||||
:type resource_type: dictionary
|
||||
:param if_exists: Do not fail if resource does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
:raise: RevisionConflict if the revision number in
|
||||
OVN is equal or higher than the neutron object
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_lswitch_port(self, lsp_name):
|
||||
"""Get a Logical Switch Port by its name.
|
||||
|
||||
:param lsp_name: The Logical Switch Port name
|
||||
:type lsp_name: string
|
||||
:returns: The Logical Switch Port row or None
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_lrouter(self, lrouter_name):
|
||||
"""Get a Logical Router by its name
|
||||
|
||||
:param lrouter_name: The name of the logical router
|
||||
:type lrouter_name: string
|
||||
:returns: The Logical_Router row or None
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_lrouter_ext_gw(self, lrouter_name):
|
||||
"""Delete Logical Router external gateway.
|
||||
|
||||
:param lrouter_name: The name of the logical router
|
||||
:type lrouter_name: string
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_address_set(self, addrset_id, ip_version='ip4'):
|
||||
"""Get a Address Set by its ID.
|
||||
|
||||
:param addrset_id: The Address Set ID
|
||||
:type addrset_id: string
|
||||
:param ip_version: Either "ip4" or "ip6". Defaults to "ip4"
|
||||
:type addr_name: string
|
||||
:returns: The Address Set row or None
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_lswitch_port_to_virtual_type(self, lport_name, vip,
|
||||
virtual_parent, if_exists=True):
|
||||
"""Set the type of a given port to "virtual".
|
||||
|
||||
Set the type of a given port to "virtual" and all its related
|
||||
options.
|
||||
|
||||
:param lport_name: The name of the lport
|
||||
:type lport_name: string
|
||||
:param vip: The virtual ip
|
||||
:type vip: string
|
||||
:param virtual_parent: The name of the parent lport
|
||||
:type virtual_parent: string
|
||||
:param if_exists: Do not fail if lport does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def unset_lswitch_port_to_virtual_type(self, lport_name,
|
||||
virtual_parent, if_exists=True):
|
||||
"""Unset the type of a given port from "virtual".
|
||||
|
||||
Unset the type of a given port from "virtual" and all its related
|
||||
options.
|
||||
|
||||
:param lport_name: The name of the lport
|
||||
:type lport_name: string
|
||||
:param virtual_parent: The name of the parent lport
|
||||
:type virtual_parent: string
|
||||
:param if_exists: Do not fail if lport does not exist
|
||||
:type if_exists: bool
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class SbAPI(api.API):
|
||||
|
||||
@abc.abstractmethod
|
||||
def chassis_exists(self, hostname):
|
||||
"""Test if chassis for given hostname exists.
|
||||
|
||||
@param hostname: The hostname of the chassis
|
||||
@type hostname: string
|
||||
:returns: True if the chassis exists, else False.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_chassis_hostname_and_physnets(self):
|
||||
"""Return a dict contains hostname and physnets mapping.
|
||||
|
||||
Hostname will be dict key, and a list of physnets will be dict
|
||||
value. And hostname and physnets are related to the same host.
|
||||
"""
|
||||
|
||||
def get_gateway_chassis_from_cms_options(self):
|
||||
"""Get chassis eligible for external connectivity from CMS options.
|
||||
|
||||
When admin wants to enable router gateway on few chassis,
|
||||
he would set the external_ids as
|
||||
|
||||
ovs-vsctl set open .
|
||||
external_ids:ovn-cms-options="enable-chassis-as-gw"
|
||||
In this function, we parse ovn-cms-options and return these chassis
|
||||
:returns: List with chassis names.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_chassis_and_physnets(self):
|
||||
"""Return a dict contains chassis name and physnets mapping.
|
||||
|
||||
Chassis name will be dict key, and a list of physnets will be dict
|
||||
value. And chassis name and physnets are related to the same chassis.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_all_chassis(self, chassis_type=None):
|
||||
"""Return a list of all chassis which match the compute_type
|
||||
|
||||
:param chassis_type: The type of chassis
|
||||
:type chassis_type: string
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_chassis_data_for_ml2_bind_port(self, hostname):
|
||||
"""Return chassis data for ML2 port binding.
|
||||
|
||||
@param hostname: The hostname of the chassis
|
||||
@type hostname: string
|
||||
:returns: Tuple containing the chassis datapath type,
|
||||
iface types and physical networks for the
|
||||
OVN bridge mappings.
|
||||
:raises: RuntimeError exception if an OVN chassis
|
||||
does not exist.
|
||||
"""
|
@ -0,0 +1,973 @@
|
||||
# Copyright 2019 Red Hat, 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_utils import timeutils
|
||||
from ovsdbapp.backend.ovs_idl import command
|
||||
from ovsdbapp.backend.ovs_idl import idlutils
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
from neutron.common.ovn import exceptions as ovn_exc
|
||||
from neutron.common.ovn import utils
|
||||
|
||||
RESOURCE_TYPE_MAP = {
|
||||
ovn_const.TYPE_NETWORKS: 'Logical_Switch',
|
||||
ovn_const.TYPE_PORTS: 'Logical_Switch_Port',
|
||||
ovn_const.TYPE_ROUTERS: 'Logical_Router',
|
||||
ovn_const.TYPE_ROUTER_PORTS: 'Logical_Router_Port',
|
||||
ovn_const.TYPE_FLOATINGIPS: 'NAT',
|
||||
ovn_const.TYPE_SUBNETS: 'DHCP_Options',
|
||||
}
|
||||
|
||||
|
||||
def _addvalue_to_list(row, column, new_value):
|
||||
row.addvalue(column, new_value)
|
||||
|
||||
|
||||
def _delvalue_from_list(row, column, old_value):
|
||||
row.delvalue(column, old_value)
|
||||
|
||||
|
||||
def _updatevalues_in_list(row, column, new_values=None, old_values=None):
|
||||
new_values = new_values or []
|
||||
old_values = old_values or []
|
||||
|
||||
for new_value in new_values:
|
||||
row.addvalue(column, new_value)
|
||||
for old_value in old_values:
|
||||
row.delvalue(column, old_value)
|
||||
|
||||
|
||||
def get_lsp_dhcp_options_uuids(lsp, lsp_name):
|
||||
# Get dhcpv4_options and dhcpv6_options uuids from Logical_Switch_Port,
|
||||
# which are references of port dhcp options in DHCP_Options table.
|
||||
uuids = set()
|
||||
for dhcp_opts in getattr(lsp, 'dhcpv4_options', []):
|
||||
external_ids = getattr(dhcp_opts, 'external_ids', {})
|
||||
if external_ids.get('port_id') == lsp_name:
|
||||
uuids.add(dhcp_opts.uuid)
|
||||
for dhcp_opts in getattr(lsp, 'dhcpv6_options', []):
|
||||
external_ids = getattr(dhcp_opts, 'external_ids', {})
|
||||
if external_ids.get('port_id') == lsp_name:
|
||||
uuids.add(dhcp_opts.uuid)
|
||||
return uuids
|
||||
|
||||
|
||||
def _add_gateway_chassis(api, txn, lrp_name, val):
|
||||
gateway_chassis = api._tables.get('Gateway_Chassis')
|
||||
if gateway_chassis:
|
||||
prio = len(val)
|
||||
uuid_list = []
|
||||
for chassis in val:
|
||||
gwc_name = '%s_%s' % (lrp_name, chassis)
|
||||
try:
|
||||
gwc = idlutils.row_by_value(api.idl,
|
||||
'Gateway_Chassis',
|
||||
'name', gwc_name)
|
||||
except idlutils.RowNotFound:
|
||||
gwc = txn.insert(gateway_chassis)
|
||||
gwc.name = gwc_name
|
||||
gwc.chassis_name = chassis
|
||||
gwc.priority = prio
|
||||
prio = prio - 1
|
||||
uuid_list.append(gwc.uuid)
|
||||
return 'gateway_chassis', uuid_list
|
||||
else:
|
||||
chassis = {ovn_const.OVN_GATEWAY_CHASSIS_KEY: val[0]}
|
||||
return 'options', chassis
|
||||
|
||||
|
||||
class CheckLivenessCommand(command.BaseCommand):
|
||||
def __init__(self, api):
|
||||
super(CheckLivenessCommand, self).__init__(api)
|
||||
|
||||
def run_idl(self, txn):
|
||||
# txn.pre_commit responsible for updating nb_global.nb_cfg, but
|
||||
# python-ovs will not update nb_cfg if no other changes are made
|
||||
self.api.nb_global.setkey('external_ids',
|
||||
ovn_const.OVN_LIVENESS_CHECK_EXT_ID_KEY,
|
||||
str(timeutils.utcnow(with_timezone=True)))
|
||||
self.result = self.api.nb_global.nb_cfg
|
||||
|
||||
|
||||
class LSwitchSetExternalIdsCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, ext_ids, if_exists):
|
||||
super(LSwitchSetExternalIdsCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.ext_ids = ext_ids
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lswitch = idlutils.row_by_value(self.api.idl, 'Logical_Switch',
|
||||
'name', self.name)
|
||||
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Switch %s does not exist") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
lswitch.verify('external_ids')
|
||||
external_ids = getattr(lswitch, 'external_ids', {})
|
||||
for key, value in self.ext_ids.items():
|
||||
external_ids[key] = value
|
||||
lswitch.external_ids = external_ids
|
||||
|
||||
|
||||
class AddLSwitchPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, lport, lswitch, may_exist, **columns):
|
||||
super(AddLSwitchPortCommand, self).__init__(api)
|
||||
self.lport = lport
|
||||
self.lswitch = lswitch
|
||||
self.may_exist = may_exist
|
||||
self.columns = columns
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lswitch = idlutils.row_by_value(self.api.idl, 'Logical_Switch',
|
||||
'name', self.lswitch)
|
||||
except idlutils.RowNotFound:
|
||||
msg = _("Logical Switch %s does not exist") % self.lswitch
|
||||
raise RuntimeError(msg)
|
||||
if self.may_exist:
|
||||
port = idlutils.row_by_value(self.api.idl,
|
||||
'Logical_Switch_Port', 'name',
|
||||
self.lport, None)
|
||||
if port:
|
||||
return
|
||||
|
||||
port = txn.insert(self.api._tables['Logical_Switch_Port'])
|
||||
port.name = self.lport
|
||||
dhcpv4_options = self.columns.pop('dhcpv4_options', [])
|
||||
if isinstance(dhcpv4_options, list):
|
||||
port.dhcpv4_options = dhcpv4_options
|
||||
else:
|
||||
port.dhcpv4_options = [dhcpv4_options.result]
|
||||
dhcpv6_options = self.columns.pop('dhcpv6_options', [])
|
||||
if isinstance(dhcpv6_options, list):
|
||||
port.dhcpv6_options = dhcpv6_options
|
||||
else:
|
||||
port.dhcpv6_options = [dhcpv6_options.result]
|
||||
for col, val in self.columns.items():
|
||||
setattr(port, col, val)
|
||||
# add the newly created port to existing lswitch
|
||||
_addvalue_to_list(lswitch, 'ports', port.uuid)
|
||||
self.result = port.uuid
|
||||
|
||||
def post_commit(self, txn):
|
||||
self.result = txn.get_insert_uuid(self.result)
|
||||
|
||||
|
||||
class SetLSwitchPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, lport, if_exists, **columns):
|
||||
super(SetLSwitchPortCommand, self).__init__(api)
|
||||
self.lport = lport
|
||||
self.columns = columns
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
port = idlutils.row_by_value(self.api.idl, 'Logical_Switch_Port',
|
||||
'name', self.lport)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Switch Port %s does not exist") % self.lport
|
||||
raise RuntimeError(msg)
|
||||
|
||||
# Delete DHCP_Options records no longer referred by this port.
|
||||
# The table rows should be consistent for the same transaction.
|
||||
# After we get DHCP_Options rows uuids from port dhcpv4_options
|
||||
# and dhcpv6_options references, the rows shouldn't disappear for
|
||||
# this transaction before we delete it.
|
||||
cur_port_dhcp_opts = get_lsp_dhcp_options_uuids(
|
||||
port, self.lport)
|
||||
new_port_dhcp_opts = set()
|
||||
dhcpv4_options = self.columns.pop('dhcpv4_options', None)
|
||||
if dhcpv4_options is None:
|
||||
new_port_dhcp_opts.update([option.uuid for option in
|
||||
getattr(port, 'dhcpv4_options', [])])
|
||||
elif isinstance(dhcpv4_options, list):
|
||||
new_port_dhcp_opts.update(dhcpv4_options)
|
||||
port.dhcpv4_options = dhcpv4_options
|
||||
else:
|
||||
new_port_dhcp_opts.add(dhcpv4_options.result)
|
||||
port.dhcpv4_options = [dhcpv4_options.result]
|
||||
dhcpv6_options = self.columns.pop('dhcpv6_options', None)
|
||||
if dhcpv6_options is None:
|
||||
new_port_dhcp_opts.update([option.uuid for option in
|
||||
getattr(port, 'dhcpv6_options', [])])
|
||||
elif isinstance(dhcpv6_options, list):
|
||||
new_port_dhcp_opts.update(dhcpv6_options)
|
||||
port.dhcpv6_options = dhcpv6_options
|
||||
else:
|
||||
new_port_dhcp_opts.add(dhcpv6_options.result)
|
||||
port.dhcpv6_options = [dhcpv6_options.result]
|
||||
for uuid in cur_port_dhcp_opts - new_port_dhcp_opts:
|
||||
self.api._tables['DHCP_Options'].rows[uuid].delete()
|
||||
|
||||
for col, val in self.columns.items():
|
||||
setattr(port, col, val)
|
||||
|
||||
|
||||
class DelLSwitchPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, lport, lswitch, if_exists):
|
||||
super(DelLSwitchPortCommand, self).__init__(api)
|
||||
self.lport = lport
|
||||
self.lswitch = lswitch
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lport = idlutils.row_by_value(self.api.idl, 'Logical_Switch_Port',
|
||||
'name', self.lport)
|
||||
lswitch = idlutils.row_by_value(self.api.idl, 'Logical_Switch',
|
||||
'name', self.lswitch)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Port %s does not exist") % self.lport
|
||||
raise RuntimeError(msg)
|
||||
|
||||
# Delete DHCP_Options records no longer referred by this port.
|
||||
cur_port_dhcp_opts = get_lsp_dhcp_options_uuids(
|
||||
lport, self.lport)
|
||||
for uuid in cur_port_dhcp_opts:
|
||||
self.api._tables['DHCP_Options'].rows[uuid].delete()
|
||||
|
||||
_delvalue_from_list(lswitch, 'ports', lport)
|
||||
self.api._tables['Logical_Switch_Port'].rows[lport.uuid].delete()
|
||||
|
||||
|
||||
class AddLRouterCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, may_exist, **columns):
|
||||
super(AddLRouterCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.columns = columns
|
||||
self.may_exist = may_exist
|
||||
|
||||
def run_idl(self, txn):
|
||||
if self.may_exist:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.name, None)
|
||||
if lrouter:
|
||||
return
|
||||
|
||||
row = txn.insert(self.api._tables['Logical_Router'])
|
||||
row.name = self.name
|
||||
for col, val in self.columns.items():
|
||||
setattr(row, col, val)
|
||||
|
||||
|
||||
class UpdateLRouterCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, if_exists, **columns):
|
||||
super(UpdateLRouterCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.columns = columns
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.name, None)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Router %s does not exist") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
if lrouter:
|
||||
for col, val in self.columns.items():
|
||||
setattr(lrouter, col, val)
|
||||
return
|
||||
|
||||
|
||||
class DelLRouterCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, if_exists):
|
||||
super(DelLRouterCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Router %s does not exist") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
self.api._tables['Logical_Router'].rows[lrouter.uuid].delete()
|
||||
|
||||
|
||||
class AddLRouterPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, lrouter, may_exist, **columns):
|
||||
super(AddLRouterPortCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.lrouter = lrouter
|
||||
self.may_exist = may_exist
|
||||
self.columns = columns
|
||||
|
||||
def run_idl(self, txn):
|
||||
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
try:
|
||||
idlutils.row_by_value(self.api.idl, 'Logical_Router_Port',
|
||||
'name', self.name)
|
||||
if self.may_exist:
|
||||
return
|
||||
# The LRP entry with certain name has already exist, raise an
|
||||
# exception to notice caller. It's caller's responsibility to
|
||||
# call UpdateLRouterPortCommand to get LRP entry processed
|
||||
# correctly.
|
||||
msg = _("Logical Router Port with name \"%s\" "
|
||||
"already exists.") % self.name
|
||||
raise RuntimeError(msg)
|
||||
except idlutils.RowNotFound:
|
||||
lrouter_port = txn.insert(self.api._tables['Logical_Router_Port'])
|
||||
lrouter_port.name = self.name
|
||||
for col, val in self.columns.items():
|
||||
if col == 'gateway_chassis':
|
||||
col, val = _add_gateway_chassis(self.api, txn, self.name,
|
||||
val)
|
||||
setattr(lrouter_port, col, val)
|
||||
_addvalue_to_list(lrouter, 'ports', lrouter_port)
|
||||
|
||||
|
||||
class UpdateLRouterPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, if_exists, **columns):
|
||||
super(UpdateLRouterPortCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.columns = columns
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter_port = idlutils.row_by_value(self.api.idl,
|
||||
'Logical_Router_Port',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Router Port %s does not exist") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
# TODO(lucasagomes): Remove this check once we drop the support
|
||||
# for OVS versions <= 2.8
|
||||
ipv6_ra_configs_supported = self.api.is_col_present(
|
||||
'Logical_Router_Port', 'ipv6_ra_configs')
|
||||
for col, val in self.columns.items():
|
||||
if col == 'ipv6_ra_configs' and not ipv6_ra_configs_supported:
|
||||
continue
|
||||
|
||||
if col == 'gateway_chassis':
|
||||
col, val = _add_gateway_chassis(self.api, txn, self.name,
|
||||
val)
|
||||
setattr(lrouter_port, col, val)
|
||||
|
||||
|
||||
class DelLRouterPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, lrouter, if_exists):
|
||||
super(DelLRouterPortCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.lrouter = lrouter
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter_port = idlutils.row_by_value(self.api.idl,
|
||||
'Logical_Router_Port',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Router Port %s does not exist") % self.name
|
||||
raise RuntimeError(msg)
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
|
||||
_delvalue_from_list(lrouter, 'ports', lrouter_port)
|
||||
lrouter_port.delete()
|
||||
|
||||
|
||||
class SetLRouterPortInLSwitchPortCommand(command.BaseCommand):
|
||||
def __init__(self, api, lswitch_port, lrouter_port, is_gw_port,
|
||||
if_exists, lsp_address):
|
||||
super(SetLRouterPortInLSwitchPortCommand, self).__init__(api)
|
||||
self.lswitch_port = lswitch_port
|
||||
self.lrouter_port = lrouter_port
|
||||
self.is_gw_port = is_gw_port
|
||||
self.if_exists = if_exists
|
||||
self.lsp_address = lsp_address
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
port = idlutils.row_by_value(self.api.idl, 'Logical_Switch_Port',
|
||||
'name', self.lswitch_port)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Switch Port %s does not "
|
||||
"exist") % self.lswitch_port
|
||||
raise RuntimeError(msg)
|
||||
|
||||
options = {'router-port': self.lrouter_port}
|
||||
if self.is_gw_port:
|
||||
options[ovn_const.OVN_GATEWAY_NAT_ADDRESSES_KEY] = 'router'
|
||||
setattr(port, 'options', options)
|
||||
setattr(port, 'type', 'router')
|
||||
setattr(port, 'addresses', self.lsp_address)
|
||||
|
||||
|
||||
class AddStaticRouteCommand(command.BaseCommand):
|
||||
def __init__(self, api, lrouter, **columns):
|
||||
super(AddStaticRouteCommand, self).__init__(api)
|
||||
self.lrouter = lrouter
|
||||
self.columns = columns
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
|
||||
row = txn.insert(self.api._tables['Logical_Router_Static_Route'])
|
||||
for col, val in self.columns.items():
|
||||
setattr(row, col, val)
|
||||
_addvalue_to_list(lrouter, 'static_routes', row.uuid)
|
||||
|
||||
|
||||
class DelStaticRouteCommand(command.BaseCommand):
|
||||
def __init__(self, api, lrouter, ip_prefix, nexthop, if_exists):
|
||||
super(DelStaticRouteCommand, self).__init__(api)
|
||||
self.lrouter = lrouter
|
||||
self.ip_prefix = ip_prefix
|
||||
self.nexthop = nexthop
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
|
||||
static_routes = getattr(lrouter, 'static_routes', [])
|
||||
for route in static_routes:
|
||||
ip_prefix = getattr(route, 'ip_prefix', '')
|
||||
nexthop = getattr(route, 'nexthop', '')
|
||||
if self.ip_prefix == ip_prefix and self.nexthop == nexthop:
|
||||
_delvalue_from_list(lrouter, 'static_routes', route)
|
||||
route.delete()
|
||||
break
|
||||
|
||||
|
||||
class AddAddrSetCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, may_exist, **columns):
|
||||
super(AddAddrSetCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.columns = columns
|
||||
self.may_exist = may_exist
|
||||
|
||||
def run_idl(self, txn):
|
||||
if self.may_exist:
|
||||
addrset = idlutils.row_by_value(self.api.idl, 'Address_Set',
|
||||
'name', self.name, None)
|
||||
if addrset:
|
||||
return
|
||||
row = txn.insert(self.api._tables['Address_Set'])
|
||||
row.name = self.name
|
||||
for col, val in self.columns.items():
|
||||
setattr(row, col, val)
|
||||
|
||||
|
||||
class DelAddrSetCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, if_exists):
|
||||
super(DelAddrSetCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
addrset = idlutils.row_by_value(self.api.idl, 'Address_Set',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Address set %s does not exist. "
|
||||
"Can't delete.") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
self.api._tables['Address_Set'].rows[addrset.uuid].delete()
|
||||
|
||||
|
||||
class UpdateAddrSetCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, addrs_add, addrs_remove, if_exists):
|
||||
super(UpdateAddrSetCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.addrs_add = addrs_add
|
||||
self.addrs_remove = addrs_remove
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
addrset = idlutils.row_by_value(self.api.idl, 'Address_Set',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Address set %s does not exist. "
|
||||
"Can't update addresses") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
_updatevalues_in_list(
|
||||
addrset, 'addresses',
|
||||
new_values=self.addrs_add,
|
||||
old_values=self.addrs_remove)
|
||||
|
||||
|
||||
class UpdateAddrSetExtIdsCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, external_ids, if_exists):
|
||||
super(UpdateAddrSetExtIdsCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.external_ids = external_ids
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
addrset = idlutils.row_by_value(self.api.idl, 'Address_Set',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Address set %s does not exist. "
|
||||
"Can't update external IDs") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
addrset.verify('external_ids')
|
||||
addrset_external_ids = getattr(addrset, 'external_ids', {})
|
||||
for ext_id_key, ext_id_value in self.external_ids.items():
|
||||
addrset_external_ids[ext_id_key] = ext_id_value
|
||||
addrset.external_ids = addrset_external_ids
|
||||
|
||||
|
||||
class UpdateChassisExtIdsCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, external_ids, if_exists):
|
||||
super(UpdateChassisExtIdsCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.external_ids = external_ids
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
chassis = idlutils.row_by_value(self.api.idl, 'Chassis',
|
||||
'name', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Chassis %s does not exist. "
|
||||
"Can't update external IDs") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
chassis.verify('external_ids')
|
||||
chassis_external_ids = getattr(chassis, 'external_ids', {})
|
||||
for ext_id_key, ext_id_value in self.external_ids.items():
|
||||
chassis_external_ids[ext_id_key] = ext_id_value
|
||||
chassis.external_ids = chassis_external_ids
|
||||
|
||||
|
||||
class UpdatePortBindingExtIdsCommand(command.BaseCommand):
|
||||
def __init__(self, api, name, external_ids, if_exists):
|
||||
super(UpdatePortBindingExtIdsCommand, self).__init__(api)
|
||||
self.name = name
|
||||
self.external_ids = external_ids
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
port = idlutils.row_by_value(self.api.idl, 'Port_Binding',
|
||||
'logical_port', self.name)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Port %s does not exist. "
|
||||
"Can't update external IDs") % self.name
|
||||
raise RuntimeError(msg)
|
||||
|
||||
port.verify('external_ids')
|
||||
port_external_ids = getattr(port, 'external_ids', {})
|
||||
for ext_id_key, ext_id_value in self.external_ids.items():
|
||||
port_external_ids[ext_id_key] = ext_id_value
|
||||
port.external_ids = port_external_ids
|
||||
|
||||
|
||||
class AddDHCPOptionsCommand(command.BaseCommand):
|
||||
def __init__(self, api, subnet_id, port_id=None, may_exist=True,
|
||||
**columns):
|
||||
super(AddDHCPOptionsCommand, self).__init__(api)
|
||||
self.columns = columns
|
||||
self.may_exist = may_exist
|
||||
self.subnet_id = subnet_id
|
||||
self.port_id = port_id
|
||||
self.new_insert = False
|
||||
|
||||
def _get_dhcp_options_row(self):
|
||||
for row in self.api._tables['DHCP_Options'].rows.values():
|
||||
external_ids = getattr(row, 'external_ids', {})
|
||||
port_id = external_ids.get('port_id')
|
||||
if self.subnet_id == external_ids.get('subnet_id'):
|
||||
if self.port_id == port_id:
|
||||
return row
|
||||
|
||||
def run_idl(self, txn):
|
||||
row = None
|
||||
if self.may_exist:
|
||||
row = self._get_dhcp_options_row()
|
||||
|
||||
if not row:
|
||||
row = txn.insert(self.api._tables['DHCP_Options'])
|
||||
self.new_insert = True
|
||||
for col, val in self.columns.items():
|
||||
setattr(row, col, val)
|
||||
self.result = row.uuid
|
||||
|
||||
def post_commit(self, txn):
|
||||
# Update the result with inserted uuid for new inserted row, or the
|
||||
# uuid get in run_idl should be real uuid already.
|
||||
if self.new_insert:
|
||||
self.result = txn.get_insert_uuid(self.result)
|
||||
|
||||
|
||||
class DelDHCPOptionsCommand(command.BaseCommand):
|
||||
def __init__(self, api, row_uuid, if_exists=True):
|
||||
super(DelDHCPOptionsCommand, self).__init__(api)
|
||||
self.if_exists = if_exists
|
||||
self.row_uuid = row_uuid
|
||||
|
||||
def run_idl(self, txn):
|
||||
if self.row_uuid not in self.api._tables['DHCP_Options'].rows:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("DHCP Options row %s does not exist") % self.row_uuid
|
||||
raise RuntimeError(msg)
|
||||
|
||||
self.api._tables['DHCP_Options'].rows[self.row_uuid].delete()
|
||||
|
||||
|
||||
class AddNATRuleInLRouterCommand(command.BaseCommand):
|
||||
# TODO(chandrav): Add unit tests, bug #1638715.
|
||||
def __init__(self, api, lrouter, **columns):
|
||||
super(AddNATRuleInLRouterCommand, self).__init__(api)
|
||||
self.lrouter = lrouter
|
||||
self.columns = columns
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
|
||||
row = txn.insert(self.api._tables['NAT'])
|
||||
for col, val in self.columns.items():
|
||||
setattr(row, col, val)
|
||||
# TODO(chandrav): convert this to ovs transaction mutate
|
||||
lrouter.verify('nat')
|
||||
nat = getattr(lrouter, 'nat', [])
|
||||
nat.append(row.uuid)
|
||||
setattr(lrouter, 'nat', nat)
|
||||
|
||||
|
||||
class DeleteNATRuleInLRouterCommand(command.BaseCommand):
|
||||
# TODO(chandrav): Add unit tests, bug #1638715.
|
||||
def __init__(self, api, lrouter, type, logical_ip, external_ip,
|
||||
if_exists):
|
||||
super(DeleteNATRuleInLRouterCommand, self).__init__(api)
|
||||
self.lrouter = lrouter
|
||||
self.type = type
|
||||
self.logical_ip = logical_ip
|
||||
self.external_ip = external_ip
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
if self.if_exists:
|
||||
return
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
|
||||
lrouter.verify('nat')
|
||||
# TODO(chandrav): convert this to ovs transaction mutate
|
||||
nats = getattr(lrouter, 'nat', [])
|
||||
for nat in nats:
|
||||
type = getattr(nat, 'type', '')
|
||||
external_ip = getattr(nat, 'external_ip', '')
|
||||
logical_ip = getattr(nat, 'logical_ip', '')
|
||||
if (self.type == type and
|
||||
self.external_ip == external_ip and
|
||||
self.logical_ip == logical_ip):
|
||||
nats.remove(nat)
|
||||
nat.delete()
|
||||
break
|
||||
setattr(lrouter, 'nat', nats)
|
||||
|
||||
|
||||
class SetNATRuleInLRouterCommand(command.BaseCommand):
|
||||
def __init__(self, api, lrouter, nat_rule_uuid, **columns):
|
||||
super(SetNATRuleInLRouterCommand, self).__init__(api)
|
||||
self.lrouter = lrouter
|
||||
self.nat_rule_uuid = nat_rule_uuid
|
||||
self.columns = columns
|
||||
|
||||
def run_idl(self, txn):
|
||||
try:
|
||||
lrouter = idlutils.row_by_value(self.api.idl, 'Logical_Router',
|
||||
'name', self.lrouter)
|
||||
except idlutils.RowNotFound:
|
||||
msg = _("Logical Router %s does not exist") % self.lrouter
|
||||
raise RuntimeError(msg)
|
||||
|
||||
lrouter.verify('nat')
|
||||
nat_rules = getattr(lrouter, 'nat', [])
|
||||
for nat_rule in nat_rules:
|
||||
if nat_rule.uuid == self.nat_rule_uuid:
|
||||
for col, val in self.columns.items():
|
||||
setattr(nat_rule, col, val)
|
||||
break
|
||||
|
||||
|
||||
class CheckRevisionNumberCommand(command.BaseCommand):
|
||||
|
||||
def __init__(self, api, name, resource, resource_type, if_exists):
|
||||