a8feddcefa9367812ebe1709a2025b19b32b3408
[openstack-build/neutron-build.git] / neutron / db / portbindings_db.py
1 # Copyright 2013 IBM Corp.
2 # All Rights Reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15
16 import sqlalchemy as sa
17 from sqlalchemy import orm
18
19 from neutron.api.v2 import attributes
20 from neutron.db import db_base_plugin_v2
21 from neutron.db import model_base
22 from neutron.db import models_v2
23 from neutron.db import portbindings_base
24 from neutron.extensions import portbindings
25
26
27 class PortBindingPort(model_base.BASEV2):
28     port_id = sa.Column(sa.String(36),
29                         sa.ForeignKey('ports.id', ondelete="CASCADE"),
30                         primary_key=True)
31     host = sa.Column(sa.String(255), nullable=False)
32     port = orm.relationship(
33         models_v2.Port,
34         backref=orm.backref("portbinding",
35                             lazy='joined', uselist=False,
36                             cascade='delete'))
37
38
39 class PortBindingMixin(portbindings_base.PortBindingBaseMixin):
40     extra_binding_dict = None
41
42     def _port_model_hook(self, context, original_model, query):
43         query = query.outerjoin(PortBindingPort,
44                                 (original_model.id ==
45                                  PortBindingPort.port_id))
46         return query
47
48     def _port_result_filter_hook(self, query, filters):
49         values = filters and filters.get(portbindings.HOST_ID, [])
50         if not values:
51             return query
52         query = query.filter(PortBindingPort.host.in_(values))
53         return query
54
55     db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook(
56         models_v2.Port,
57         "portbindings_port",
58         '_port_model_hook',
59         None,
60         '_port_result_filter_hook')
61
62     def _process_portbindings_create_and_update(self, context, port_data,
63                                                 port):
64         binding_profile = port.get(portbindings.PROFILE)
65         binding_profile_set = attributes.is_attr_set(binding_profile)
66         if not binding_profile_set and binding_profile is not None:
67             del port[portbindings.PROFILE]
68
69         binding_vnic = port.get(portbindings.VNIC_TYPE)
70         binding_vnic_set = attributes.is_attr_set(binding_vnic)
71         if not binding_vnic_set and binding_vnic is not None:
72             del port[portbindings.VNIC_TYPE]
73         # REVISIT(irenab) Add support for vnic_type for plugins that
74         # can handle more than one type.
75         # Currently implemented for ML2 plugin that does not use
76         # PortBindingMixin.
77
78         host = port_data.get(portbindings.HOST_ID)
79         host_set = attributes.is_attr_set(host)
80         with context.session.begin(subtransactions=True):
81             bind_port = context.session.query(
82                 PortBindingPort).filter_by(port_id=port['id']).first()
83             if host_set:
84                 if not bind_port:
85                     context.session.add(PortBindingPort(port_id=port['id'],
86                                                         host=host))
87                 else:
88                     bind_port.host = host
89             else:
90                 host = bind_port.host if bind_port else None
91         self._extend_port_dict_binding_host(port, host)
92
93     def get_port_host(self, context, port_id):
94         with context.session.begin(subtransactions=True):
95             bind_port = context.session.query(
96                 PortBindingPort).filter_by(port_id=port_id).first()
97             return bind_port.host if bind_port else None
98
99     def _extend_port_dict_binding_host(self, port_res, host):
100         super(PortBindingMixin, self).extend_port_dict_binding(
101             port_res, None)
102         port_res[portbindings.HOST_ID] = host
103
104     def extend_port_dict_binding(self, port_res, port_db):
105         host = port_db.portbinding.host if port_db.portbinding else None
106         self._extend_port_dict_binding_host(port_res, host)
107
108
109 def _extend_port_dict_binding(plugin, port_res, port_db):
110     if not isinstance(plugin, PortBindingMixin):
111         return
112     plugin.extend_port_dict_binding(port_res, port_db)
113
114
115 # Register dict extend functions for ports
116 db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
117     attributes.PORTS, [_extend_port_dict_binding])