~zulcss/ubuntu/precise/quantum/trunk

« back to all changes in this revision

Viewing changes to quantum/plugins/ryu/db/api_v2.py

  • Committer: Chuck Short
  • Date: 2012-11-26 19:51:11 UTC
  • mfrom: (26.1.1 raring-proposed)
  • Revision ID: zulcss@ubuntu.com-20121126195111-jnz2cr4xi6whemw2
* New upstream release for the Ubuntu Cloud Archive.
* debian/patches/*: Refreshed for opening of Grizzly.
* New upstream release.
* debian/rules: FTFBS if there is missing binaries.
* debian/quantum-server.install: Add quantum-debug.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
#    License for the specific language governing permissions and limitations
15
15
#    under the License.
16
16
 
 
17
from sqlalchemy import exc as sa_exc
 
18
from sqlalchemy import func
 
19
from sqlalchemy.orm import exc as orm_exc
 
20
 
 
21
from quantum.common import exceptions as q_exc
17
22
import quantum.db.api as db
18
 
from quantum.db.models_v2 import Network
19
 
from quantum.plugins.ryu.db import models_v2
 
23
from quantum.db import models_v2
 
24
from quantum.openstack.common import log as logging
 
25
from quantum.plugins.ryu.db import models_v2 as ryu_models_v2
 
26
 
 
27
 
 
28
LOG = logging.getLogger(__name__)
20
29
 
21
30
 
22
31
def set_ofp_servers(hosts):
23
32
    session = db.get_session()
24
 
    session.query(models_v2.OFPServer).delete()
 
33
    session.query(ryu_models_v2.OFPServer).delete()
25
34
    for (host_address, host_type) in hosts:
26
 
        host = models_v2.OFPServer(host_address, host_type)
 
35
        host = ryu_models_v2.OFPServer(address=host_address,
 
36
                                       host_type=host_type)
27
37
        session.add(host)
28
38
    session.flush()
29
39
 
30
40
 
31
41
def network_all_tenant_list():
32
42
    session = db.get_session()
33
 
    return session.query(Network).all()
 
43
    return session.query(models_v2.Network).all()
 
44
 
 
45
 
 
46
class TunnelKey(object):
 
47
    # VLAN: 12 bits
 
48
    # GRE, VXLAN: 24bits
 
49
    # TODO(yamahata): STT: 64bits
 
50
    _KEY_MIN_HARD = 1
 
51
    _KEY_MAX_HARD = 0xffffffff
 
52
 
 
53
    def __init__(self, key_min=_KEY_MIN_HARD, key_max=_KEY_MAX_HARD):
 
54
        self.key_min = key_min
 
55
        self.key_max = key_max
 
56
 
 
57
        if (key_min < self._KEY_MIN_HARD or key_max > self._KEY_MAX_HARD or
 
58
                key_min > key_max):
 
59
            raise ValueError(_('Invalid tunnel key options '
 
60
                               'tunnel_key_min: %(key_min)d '
 
61
                               'tunnel_key_max: %(key_max)d. '
 
62
                               'Using default value') % {'key_min': key_min,
 
63
                                                         'key_max': key_max})
 
64
 
 
65
    def _last_key(self, session):
 
66
        try:
 
67
            return session.query(ryu_models_v2.TunnelKeyLast).one()
 
68
        except orm_exc.MultipleResultsFound:
 
69
            max_key = session.query(
 
70
                func.max(ryu_models_v2.TunnelKeyLast.last_key))
 
71
            if max_key > self.key_max:
 
72
                max_key = self.key_min
 
73
 
 
74
            session.query(ryu_models_v2.TunnelKeyLast).delete()
 
75
            last_key = ryu_models_v2.TunnelKeyLast(last_key=max_key)
 
76
        except orm_exc.NoResultFound:
 
77
            last_key = ryu_models_v2.TunnelKeyLast(last_key=self.key_min)
 
78
 
 
79
        session.add(last_key)
 
80
        session.flush()
 
81
        return session.query(ryu_models_v2.TunnelKeyLast).one()
 
82
 
 
83
    def _find_key(self, session, last_key):
 
84
        """
 
85
        Try to find unused tunnel key in TunnelKey table starting
 
86
        from last_key + 1.
 
87
        When all keys are used, raise sqlalchemy.orm.exc.NoResultFound
 
88
        """
 
89
        # key 0 is used for special meanings. So don't allocate 0.
 
90
 
 
91
        # sqlite doesn't support
 
92
        # '(select order by limit) union all (select order by limit) '
 
93
        # 'order by limit'
 
94
        # So do it manually
 
95
        # new_key = session.query("new_key").from_statement(
 
96
        #     # If last_key + 1 isn't used, it's the result
 
97
        #     'SELECT new_key '
 
98
        #     'FROM (SELECT :last_key + 1 AS new_key) q1 '
 
99
        #     'WHERE NOT EXISTS '
 
100
        #     '(SELECT 1 FROM tunnelkeys WHERE tunnel_key = :last_key + 1) '
 
101
        #
 
102
        #     'UNION ALL '
 
103
        #
 
104
        #     # if last_key + 1 used,
 
105
        #     # find the least unused key from last_key + 1
 
106
        #     '(SELECT t.tunnel_key + 1 AS new_key '
 
107
        #     'FROM tunnelkeys t '
 
108
        #     'WHERE NOT EXISTS '
 
109
        #     '(SELECT 1 FROM tunnelkeys ti '
 
110
        #     ' WHERE ti.tunnel_key = t.tunnel_key + 1) '
 
111
        #     'AND t.tunnel_key >= :last_key '
 
112
        #     'ORDER BY new_key LIMIT 1) '
 
113
        #
 
114
        #     'ORDER BY new_key LIMIT 1'
 
115
        # ).params(last_key=last_key).one()
 
116
        try:
 
117
            new_key = session.query("new_key").from_statement(
 
118
                # If last_key + 1 isn't used, it's the result
 
119
                'SELECT new_key '
 
120
                'FROM (SELECT :last_key + 1 AS new_key) q1 '
 
121
                'WHERE NOT EXISTS '
 
122
                '(SELECT 1 FROM tunnelkeys WHERE tunnel_key = :last_key + 1) '
 
123
            ).params(last_key=last_key).one()
 
124
        except orm_exc.NoResultFound:
 
125
            new_key = session.query("new_key").from_statement(
 
126
                # if last_key + 1 used,
 
127
                # find the least unused key from last_key + 1
 
128
                '(SELECT t.tunnel_key + 1 AS new_key '
 
129
                'FROM tunnelkeys t '
 
130
                'WHERE NOT EXISTS '
 
131
                '(SELECT 1 FROM tunnelkeys ti '
 
132
                ' WHERE ti.tunnel_key = t.tunnel_key + 1) '
 
133
                'AND t.tunnel_key >= :last_key '
 
134
                'ORDER BY new_key LIMIT 1) '
 
135
            ).params(last_key=last_key).one()
 
136
 
 
137
        new_key = new_key[0]  # the result is tuple.
 
138
        LOG.debug(_("last_key %(last_key)s new_key %(new_key)s") %
 
139
                  {"last_key": last_key, "new_key": new_key})
 
140
        if new_key > self.key_max:
 
141
            LOG.debug(_("no key found"))
 
142
            raise orm_exc.NoResultFound()
 
143
        return new_key
 
144
 
 
145
    def _allocate(self, session, network_id):
 
146
        last_key = self._last_key(session)
 
147
        try:
 
148
            new_key = self._find_key(session, last_key.last_key)
 
149
        except orm_exc.NoResultFound:
 
150
            new_key = self._find_key(session, self.key_min)
 
151
 
 
152
        tunnel_key = ryu_models_v2.TunnelKey(network_id=network_id,
 
153
                                             tunnel_key=new_key)
 
154
        last_key.last_key = new_key
 
155
        session.add(tunnel_key)
 
156
        return new_key
 
157
 
 
158
    _TRANSACTION_RETRY_MAX = 16
 
159
 
 
160
    def allocate(self, session, network_id):
 
161
        count = 0
 
162
        while True:
 
163
            session.begin(subtransactions=True)
 
164
            try:
 
165
                new_key = self._allocate(session, network_id)
 
166
                session.commit()
 
167
                break
 
168
            except sa_exc.SQLAlchemyError:
 
169
                session.rollback()
 
170
 
 
171
            count += 1
 
172
            if count > self._TRANSACTION_RETRY_MAX:
 
173
                # if this happens too often, increase _TRANSACTION_RETRY_MAX
 
174
                LOG.warn(_("Transaction retry reaches to %d. "
 
175
                           "abandan to allocate tunnel key."), count)
 
176
                raise q_exc.ResourceExhausted()
 
177
 
 
178
        return new_key
 
179
 
 
180
    def delete(self, session, network_id):
 
181
        session.query(ryu_models_v2.TunnelKey).filter_by(
 
182
            network_id=network_id).delete()
 
183
        session.flush()
 
184
 
 
185
    def all_list(self):
 
186
        session = db.get_session()
 
187
        return session.query(ryu_models_v2.TunnelKey).all()
 
188
 
 
189
 
 
190
def port_binding_create(port_id, net_id, dpid, port_no):
 
191
    session = db.get_session()
 
192
    session.query(models_v2.Port).filter(
 
193
        models_v2.Port.network_id == net_id).filter(
 
194
            models_v2.Port.id == port_id).one()  # confirm port exists
 
195
    with session.begin():
 
196
        port_binding = ryu_models_v2.PortBinding(net_id, port_id,
 
197
                                                 dpid, port_no)
 
198
        session.add(port_binding)
 
199
        session.flush()
 
200
        return port_binding
 
201
 
 
202
 
 
203
def port_binding_get(port_id, net_id):
 
204
    session = db.get_session()
 
205
    session.query(models_v2.Port).filter(
 
206
        models_v2.Port.network_id == net_id).filter(
 
207
            models_v2.Port.id == port_id).one()  # confirm port exists
 
208
    return session.query(ryu_models_v2.PortBinding).filter_by(
 
209
        network_id=net_id).filter_by(port_id=port_id).one()
 
210
 
 
211
 
 
212
def port_binding_destroy(session, port_id, net_id):
 
213
    try:
 
214
        session.query(models_v2.Port).filter(
 
215
            models_v2.Port.network_id == net_id).filter(
 
216
                models_v2.Port.id == port_id).one()  # confirm port exists
 
217
        port_binding = session.query(ryu_models_v2.PortBinding).filter_by(
 
218
            network_id=net_id).filter_by(port_id=port_id).one()
 
219
        session.delete(port_binding)
 
220
        session.flush()
 
221
        return port_binding
 
222
    except orm_exc.NoResultFound:
 
223
        raise q_exc.PortNotFound(port_id=port_id, net_id=net_id)
 
224
 
 
225
 
 
226
def port_binding_all_list(session):
 
227
    return session.query(ryu_models_v2.PortBinding).all()
 
228
 
 
229
 
 
230
def set_port_status(session, port_id, status):
 
231
    try:
 
232
        port = session.query(models_v2.Port).filter_by(id=port_id).one()
 
233
        port['status'] = status
 
234
        session.merge(port)
 
235
        session.flush()
 
236
    except orm_exc.NoResultFound:
 
237
        raise q_exc.PortNotFound(port_id=port_id, net_id=None)