~ubuntu-branches/ubuntu/trusty/cinder/trusty

« back to all changes in this revision

Viewing changes to cinder/db/sqlalchemy/models.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-22 09:57:46 UTC
  • Revision ID: package-import@ubuntu.com-20120522095746-9lm71yvzltjybk4b
Tags: upstream-2012.2~f1~20120503.2
ImportĀ upstreamĀ versionĀ 2012.2~f1~20120503.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
 
4
# Copyright 2010 United States Government as represented by the
 
5
# Administrator of the National Aeronautics and Space Administration.
 
6
# Copyright 2011 Piston Cloud Computing, Inc.
 
7
# All Rights Reserved.
 
8
#
 
9
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
10
#    not use this file except in compliance with the License. You may obtain
 
11
#    a copy of the License at
 
12
#
 
13
#         http://www.apache.org/licenses/LICENSE-2.0
 
14
#
 
15
#    Unless required by applicable law or agreed to in writing, software
 
16
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
17
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
18
#    License for the specific language governing permissions and limitations
 
19
#    under the License.
 
20
"""
 
21
SQLAlchemy models for cinder data.
 
22
"""
 
23
 
 
24
from sqlalchemy.orm import relationship, backref, object_mapper
 
25
from sqlalchemy import Column, Integer, BigInteger, String, schema
 
26
from sqlalchemy import ForeignKey, DateTime, Boolean, Text, Float
 
27
from sqlalchemy.exc import IntegrityError
 
28
from sqlalchemy.ext.declarative import declarative_base
 
29
from sqlalchemy.schema import ForeignKeyConstraint
 
30
 
 
31
from cinder.db.sqlalchemy.session import get_session
 
32
 
 
33
from cinder import exception
 
34
from cinder import flags
 
35
from cinder import utils
 
36
 
 
37
 
 
38
FLAGS = flags.FLAGS
 
39
BASE = declarative_base()
 
40
 
 
41
 
 
42
class CinderBase(object):
 
43
    """Base class for Cinder Models."""
 
44
    __table_args__ = {'mysql_engine': 'InnoDB'}
 
45
    __table_initialized__ = False
 
46
    created_at = Column(DateTime, default=utils.utcnow)
 
47
    updated_at = Column(DateTime, onupdate=utils.utcnow)
 
48
    deleted_at = Column(DateTime)
 
49
    deleted = Column(Boolean, default=False)
 
50
    metadata = None
 
51
 
 
52
    def save(self, session=None):
 
53
        """Save this object."""
 
54
        if not session:
 
55
            session = get_session()
 
56
        session.add(self)
 
57
        try:
 
58
            session.flush()
 
59
        except IntegrityError, e:
 
60
            if str(e).endswith('is not unique'):
 
61
                raise exception.Duplicate(str(e))
 
62
            else:
 
63
                raise
 
64
 
 
65
    def delete(self, session=None):
 
66
        """Delete this object."""
 
67
        self.deleted = True
 
68
        self.deleted_at = utils.utcnow()
 
69
        self.save(session=session)
 
70
 
 
71
    def __setitem__(self, key, value):
 
72
        setattr(self, key, value)
 
73
 
 
74
    def __getitem__(self, key):
 
75
        return getattr(self, key)
 
76
 
 
77
    def get(self, key, default=None):
 
78
        return getattr(self, key, default)
 
79
 
 
80
    def __iter__(self):
 
81
        self._i = iter(object_mapper(self).columns)
 
82
        return self
 
83
 
 
84
    def next(self):
 
85
        n = self._i.next().name
 
86
        return n, getattr(self, n)
 
87
 
 
88
    def update(self, values):
 
89
        """Make the model object behave like a dict"""
 
90
        for k, v in values.iteritems():
 
91
            setattr(self, k, v)
 
92
 
 
93
    def iteritems(self):
 
94
        """Make the model object behave like a dict.
 
95
 
 
96
        Includes attributes from joins."""
 
97
        local = dict(self)
 
98
        joined = dict([(k, v) for k, v in self.__dict__.iteritems()
 
99
                      if not k[0] == '_'])
 
100
        local.update(joined)
 
101
        return local.iteritems()
 
102
 
 
103
 
 
104
class Service(BASE, CinderBase):
 
105
    """Represents a running service on a host."""
 
106
 
 
107
    __tablename__ = 'services'
 
108
    id = Column(Integer, primary_key=True)
 
109
    host = Column(String(255))  # , ForeignKey('hosts.id'))
 
110
    binary = Column(String(255))
 
111
    topic = Column(String(255))
 
112
    report_count = Column(Integer, nullable=False, default=0)
 
113
    disabled = Column(Boolean, default=False)
 
114
    availability_zone = Column(String(255), default='cinder')
 
115
 
 
116
 
 
117
class ComputeNode(BASE, CinderBase):
 
118
    """Represents a running compute service on a host."""
 
119
 
 
120
    __tablename__ = 'compute_nodes'
 
121
    id = Column(Integer, primary_key=True)
 
122
    service_id = Column(Integer, ForeignKey('services.id'), nullable=True)
 
123
    service = relationship(Service,
 
124
                           backref=backref('compute_node'),
 
125
                           foreign_keys=service_id,
 
126
                           primaryjoin='and_('
 
127
                                'ComputeNode.service_id == Service.id,'
 
128
                                'ComputeNode.deleted == False)')
 
129
 
 
130
    vcpus = Column(Integer)
 
131
    memory_mb = Column(Integer)
 
132
    local_gb = Column(Integer)
 
133
    vcpus_used = Column(Integer)
 
134
    memory_mb_used = Column(Integer)
 
135
    local_gb_used = Column(Integer)
 
136
    hypervisor_type = Column(Text)
 
137
    hypervisor_version = Column(Integer)
 
138
    hypervisor_hostname = Column(String(255))
 
139
 
 
140
    # Free Ram, amount of activity (resize, migration, boot, etc) and
 
141
    # the number of running VM's are a good starting point for what's
 
142
    # important when making scheduling decisions.
 
143
    #
 
144
    # NOTE(sandy): We'll need to make this extensible for other schedulers.
 
145
    free_ram_mb = Column(Integer)
 
146
    free_disk_gb = Column(Integer)
 
147
    current_workload = Column(Integer)
 
148
    running_vms = Column(Integer)
 
149
 
 
150
    # Note(masumotok): Expected Strings example:
 
151
    #
 
152
    # '{"arch":"x86_64",
 
153
    #   "model":"Nehalem",
 
154
    #   "topology":{"sockets":1, "threads":2, "cores":3},
 
155
    #   "features":["tdtscp", "xtpr"]}'
 
156
    #
 
157
    # Points are "json translatable" and it must have all dictionary keys
 
158
    # above, since it is copied from <cpu> tag of getCapabilities()
 
159
    # (See libvirt.virtConnection).
 
160
    cpu_info = Column(Text, nullable=True)
 
161
    disk_available_least = Column(Integer)
 
162
 
 
163
 
 
164
class Certificate(BASE, CinderBase):
 
165
    """Represents a an x509 certificate"""
 
166
    __tablename__ = 'certificates'
 
167
    id = Column(Integer, primary_key=True)
 
168
 
 
169
    user_id = Column(String(255))
 
170
    project_id = Column(String(255))
 
171
    file_name = Column(String(255))
 
172
 
 
173
 
 
174
class Instance(BASE, CinderBase):
 
175
    """Represents a guest vm."""
 
176
    __tablename__ = 'instances'
 
177
    injected_files = []
 
178
 
 
179
    id = Column(Integer, primary_key=True, autoincrement=True)
 
180
 
 
181
    @property
 
182
    def name(self):
 
183
        try:
 
184
            base_name = FLAGS.instance_name_template % self.id
 
185
        except TypeError:
 
186
            # Support templates like "uuid-%(uuid)s", etc.
 
187
            info = {}
 
188
            for key, value in self.iteritems():
 
189
                # prevent recursion if someone specifies %(name)s
 
190
                # %(name)s will not be valid.
 
191
                if key == 'name':
 
192
                    continue
 
193
                info[key] = value
 
194
            try:
 
195
                base_name = FLAGS.instance_name_template % info
 
196
            except KeyError:
 
197
                base_name = self.uuid
 
198
        if getattr(self, '_rescue', False):
 
199
            base_name += "-rescue"
 
200
        return base_name
 
201
 
 
202
    user_id = Column(String(255))
 
203
    project_id = Column(String(255))
 
204
 
 
205
    image_ref = Column(String(255))
 
206
    kernel_id = Column(String(255))
 
207
    ramdisk_id = Column(String(255))
 
208
    server_name = Column(String(255))
 
209
 
 
210
#    image_ref = Column(Integer, ForeignKey('images.id'), nullable=True)
 
211
#    kernel_id = Column(Integer, ForeignKey('images.id'), nullable=True)
 
212
#    ramdisk_id = Column(Integer, ForeignKey('images.id'), nullable=True)
 
213
#    ramdisk = relationship(Ramdisk, backref=backref('instances', order_by=id))
 
214
#    kernel = relationship(Kernel, backref=backref('instances', order_by=id))
 
215
#    project = relationship(Project, backref=backref('instances', order_by=id))
 
216
 
 
217
    launch_index = Column(Integer)
 
218
    key_name = Column(String(255))
 
219
    key_data = Column(Text)
 
220
 
 
221
    power_state = Column(Integer)
 
222
    vm_state = Column(String(255))
 
223
    task_state = Column(String(255))
 
224
 
 
225
    memory_mb = Column(Integer)
 
226
    vcpus = Column(Integer)
 
227
    root_gb = Column(Integer)
 
228
    ephemeral_gb = Column(Integer)
 
229
 
 
230
    hostname = Column(String(255))
 
231
    host = Column(String(255))  # , ForeignKey('hosts.id'))
 
232
 
 
233
    # *not* flavor_id
 
234
    instance_type_id = Column(Integer)
 
235
 
 
236
    user_data = Column(Text)
 
237
 
 
238
    reservation_id = Column(String(255))
 
239
 
 
240
    scheduled_at = Column(DateTime)
 
241
    launched_at = Column(DateTime)
 
242
    terminated_at = Column(DateTime)
 
243
 
 
244
    availability_zone = Column(String(255))
 
245
 
 
246
    # User editable field for display in user-facing UIs
 
247
    display_name = Column(String(255))
 
248
    display_description = Column(String(255))
 
249
 
 
250
    # To remember on which host a instance booted.
 
251
    # An instance may have moved to another host by live migraiton.
 
252
    launched_on = Column(Text)
 
253
    locked = Column(Boolean)
 
254
 
 
255
    os_type = Column(String(255))
 
256
    architecture = Column(String(255))
 
257
    vm_mode = Column(String(255))
 
258
    uuid = Column(String(36))
 
259
 
 
260
    root_device_name = Column(String(255))
 
261
    default_ephemeral_device = Column(String(255), nullable=True)
 
262
    default_swap_device = Column(String(255), nullable=True)
 
263
    config_drive = Column(String(255))
 
264
 
 
265
    # User editable field meant to represent what ip should be used
 
266
    # to connect to the instance
 
267
    access_ip_v4 = Column(String(255))
 
268
    access_ip_v6 = Column(String(255))
 
269
 
 
270
    auto_disk_config = Column(Boolean())
 
271
    progress = Column(Integer)
 
272
 
 
273
    # EC2 instance_initiated_shutdown_teminate
 
274
    # True: -> 'terminate'
 
275
    # False: -> 'stop'
 
276
    shutdown_terminate = Column(Boolean(), default=True, nullable=False)
 
277
 
 
278
    # EC2 disable_api_termination
 
279
    disable_terminate = Column(Boolean(), default=False, nullable=False)
 
280
 
 
281
    # OpenStack compute cell name
 
282
    cell_name = Column(String(255))
 
283
 
 
284
 
 
285
class InstanceInfoCache(BASE, CinderBase):
 
286
    """
 
287
    Represents a cache of information about an instance
 
288
    """
 
289
    __tablename__ = 'instance_info_caches'
 
290
    id = Column(Integer, primary_key=True, autoincrement=True)
 
291
 
 
292
    # text column used for storing a json object of network data for api
 
293
    network_info = Column(Text)
 
294
 
 
295
    instance_id = Column(String(36), ForeignKey('instances.uuid'),
 
296
                                     nullable=False, unique=True)
 
297
    instance = relationship(Instance,
 
298
                            backref=backref('info_cache', uselist=False),
 
299
                            foreign_keys=instance_id,
 
300
                            primaryjoin=instance_id == Instance.uuid)
 
301
 
 
302
 
 
303
class InstanceActions(BASE, CinderBase):
 
304
    """Represents a guest VM's actions and results"""
 
305
    __tablename__ = "instance_actions"
 
306
    id = Column(Integer, primary_key=True)
 
307
    instance_uuid = Column(String(36), ForeignKey('instances.uuid'))
 
308
    action = Column(String(255))
 
309
    error = Column(Text)
 
310
 
 
311
 
 
312
class InstanceTypes(BASE, CinderBase):
 
313
    """Represent possible instance_types or flavor of VM offered"""
 
314
    __tablename__ = "instance_types"
 
315
    id = Column(Integer, primary_key=True)
 
316
    name = Column(String(255))
 
317
    memory_mb = Column(Integer)
 
318
    vcpus = Column(Integer)
 
319
    root_gb = Column(Integer)
 
320
    ephemeral_gb = Column(Integer)
 
321
    flavorid = Column(String(255))
 
322
    swap = Column(Integer, nullable=False, default=0)
 
323
    rxtx_factor = Column(Float, nullable=False, default=1)
 
324
    vcpu_weight = Column(Integer, nullable=True)
 
325
 
 
326
    instances = relationship(Instance,
 
327
                           backref=backref('instance_type', uselist=False),
 
328
                           foreign_keys=id,
 
329
                           primaryjoin='and_('
 
330
                               'Instance.instance_type_id == '
 
331
                               'InstanceTypes.id, '
 
332
                               'InstanceTypes.deleted == False)')
 
333
 
 
334
 
 
335
class Volume(BASE, CinderBase):
 
336
    """Represents a block storage device that can be attached to a vm."""
 
337
    __tablename__ = 'volumes'
 
338
    id = Column(String(36), primary_key=True)
 
339
 
 
340
    @property
 
341
    def name(self):
 
342
        return FLAGS.volume_name_template % self.id
 
343
 
 
344
    ec2_id = Column(Integer)
 
345
    user_id = Column(String(255))
 
346
    project_id = Column(String(255))
 
347
 
 
348
    snapshot_id = Column(String(36))
 
349
 
 
350
    host = Column(String(255))  # , ForeignKey('hosts.id'))
 
351
    size = Column(Integer)
 
352
    availability_zone = Column(String(255))  # TODO(vish): foreign key?
 
353
    instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
 
354
    instance = relationship(Instance,
 
355
                            backref=backref('volumes'),
 
356
                            foreign_keys=instance_id,
 
357
                            primaryjoin='and_(Volume.instance_id==Instance.id,'
 
358
                                             'Volume.deleted==False)')
 
359
    mountpoint = Column(String(255))
 
360
    attach_time = Column(String(255))  # TODO(vish): datetime
 
361
    status = Column(String(255))  # TODO(vish): enum?
 
362
    attach_status = Column(String(255))  # TODO(vish): enum
 
363
 
 
364
    scheduled_at = Column(DateTime)
 
365
    launched_at = Column(DateTime)
 
366
    terminated_at = Column(DateTime)
 
367
 
 
368
    display_name = Column(String(255))
 
369
    display_description = Column(String(255))
 
370
 
 
371
    provider_location = Column(String(255))
 
372
    provider_auth = Column(String(255))
 
373
 
 
374
    volume_type_id = Column(Integer)
 
375
 
 
376
 
 
377
class VolumeMetadata(BASE, CinderBase):
 
378
    """Represents a metadata key/value pair for a volume"""
 
379
    __tablename__ = 'volume_metadata'
 
380
    id = Column(Integer, primary_key=True)
 
381
    key = Column(String(255))
 
382
    value = Column(String(255))
 
383
    volume_id = Column(String(36), ForeignKey('volumes.id'), nullable=False)
 
384
    volume = relationship(Volume, backref="volume_metadata",
 
385
                            foreign_keys=volume_id,
 
386
                            primaryjoin='and_('
 
387
                                'VolumeMetadata.volume_id == Volume.id,'
 
388
                                'VolumeMetadata.deleted == False)')
 
389
 
 
390
 
 
391
class VolumeTypes(BASE, CinderBase):
 
392
    """Represent possible volume_types of volumes offered"""
 
393
    __tablename__ = "volume_types"
 
394
    id = Column(Integer, primary_key=True)
 
395
    name = Column(String(255))
 
396
 
 
397
    volumes = relationship(Volume,
 
398
                           backref=backref('volume_type', uselist=False),
 
399
                           foreign_keys=id,
 
400
                           primaryjoin='and_('
 
401
                               'Volume.volume_type_id == VolumeTypes.id, '
 
402
                               'VolumeTypes.deleted == False)')
 
403
 
 
404
 
 
405
class VolumeTypeExtraSpecs(BASE, CinderBase):
 
406
    """Represents additional specs as key/value pairs for a volume_type"""
 
407
    __tablename__ = 'volume_type_extra_specs'
 
408
    id = Column(Integer, primary_key=True)
 
409
    key = Column(String(255))
 
410
    value = Column(String(255))
 
411
    volume_type_id = Column(Integer, ForeignKey('volume_types.id'),
 
412
                              nullable=False)
 
413
    volume_type = relationship(VolumeTypes, backref="extra_specs",
 
414
                 foreign_keys=volume_type_id,
 
415
                 primaryjoin='and_('
 
416
                 'VolumeTypeExtraSpecs.volume_type_id == VolumeTypes.id,'
 
417
                 'VolumeTypeExtraSpecs.deleted == False)')
 
418
 
 
419
 
 
420
class Quota(BASE, CinderBase):
 
421
    """Represents a single quota override for a project.
 
422
 
 
423
    If there is no row for a given project id and resource, then the
 
424
    default for the quota class is used.  If there is no row for a
 
425
    given quota class and resource, then the default for the
 
426
    deployment is used. If the row is present but the hard limit is
 
427
    Null, then the resource is unlimited.
 
428
    """
 
429
 
 
430
    __tablename__ = 'quotas'
 
431
    id = Column(Integer, primary_key=True)
 
432
 
 
433
    project_id = Column(String(255), index=True)
 
434
 
 
435
    resource = Column(String(255))
 
436
    hard_limit = Column(Integer, nullable=True)
 
437
 
 
438
 
 
439
class QuotaClass(BASE, CinderBase):
 
440
    """Represents a single quota override for a quota class.
 
441
 
 
442
    If there is no row for a given quota class and resource, then the
 
443
    default for the deployment is used.  If the row is present but the
 
444
    hard limit is Null, then the resource is unlimited.
 
445
    """
 
446
 
 
447
    __tablename__ = 'quota_classes'
 
448
    id = Column(Integer, primary_key=True)
 
449
 
 
450
    class_name = Column(String(255), index=True)
 
451
 
 
452
    resource = Column(String(255))
 
453
    hard_limit = Column(Integer, nullable=True)
 
454
 
 
455
 
 
456
class Snapshot(BASE, CinderBase):
 
457
    """Represents a block storage device that can be attached to a vm."""
 
458
    __tablename__ = 'snapshots'
 
459
    id = Column(String(36), primary_key=True)
 
460
 
 
461
    @property
 
462
    def name(self):
 
463
        return FLAGS.snapshot_name_template % self.id
 
464
 
 
465
    @property
 
466
    def volume_name(self):
 
467
        return FLAGS.volume_name_template % self.volume_id
 
468
 
 
469
    user_id = Column(String(255))
 
470
    project_id = Column(String(255))
 
471
 
 
472
    volume_id = Column(String(36))
 
473
    status = Column(String(255))
 
474
    progress = Column(String(255))
 
475
    volume_size = Column(Integer)
 
476
 
 
477
    display_name = Column(String(255))
 
478
    display_description = Column(String(255))
 
479
 
 
480
 
 
481
class BlockDeviceMapping(BASE, CinderBase):
 
482
    """Represents block device mapping that is defined by EC2"""
 
483
    __tablename__ = "block_device_mapping"
 
484
    id = Column(Integer, primary_key=True, autoincrement=True)
 
485
 
 
486
    instance_uuid = Column(Integer, ForeignKey('instances.uuid'),
 
487
                           nullable=False)
 
488
    instance = relationship(Instance,
 
489
                            backref=backref('balock_device_mapping'),
 
490
                            foreign_keys=instance_uuid,
 
491
                            primaryjoin='and_(BlockDeviceMapping.'
 
492
                                              'instance_uuid=='
 
493
                                              'Instance.uuid,'
 
494
                                              'BlockDeviceMapping.deleted=='
 
495
                                              'False)')
 
496
    device_name = Column(String(255), nullable=False)
 
497
 
 
498
    # default=False for compatibility of the existing code.
 
499
    # With EC2 API,
 
500
    # default True for ami specified device.
 
501
    # default False for created with other timing.
 
502
    delete_on_termination = Column(Boolean, default=False)
 
503
 
 
504
    # for ephemeral device
 
505
    virtual_name = Column(String(255), nullable=True)
 
506
 
 
507
    # for snapshot or volume
 
508
    snapshot_id = Column(String(36), ForeignKey('snapshots.id'))
 
509
    # outer join
 
510
    snapshot = relationship(Snapshot,
 
511
                            foreign_keys=snapshot_id)
 
512
 
 
513
    volume_id = Column(String(36), ForeignKey('volumes.id'), nullable=True)
 
514
    volume = relationship(Volume,
 
515
                          foreign_keys=volume_id)
 
516
    volume_size = Column(Integer, nullable=True)
 
517
 
 
518
    # for no device to suppress devices.
 
519
    no_device = Column(Boolean, nullable=True)
 
520
 
 
521
    connection_info = Column(Text, nullable=True)
 
522
 
 
523
 
 
524
class IscsiTarget(BASE, CinderBase):
 
525
    """Represates an iscsi target for a given host"""
 
526
    __tablename__ = 'iscsi_targets'
 
527
    __table_args__ = (schema.UniqueConstraint("target_num", "host"),
 
528
                      {'mysql_engine': 'InnoDB'})
 
529
    id = Column(Integer, primary_key=True)
 
530
    target_num = Column(Integer)
 
531
    host = Column(String(255))
 
532
    volume_id = Column(String(36), ForeignKey('volumes.id'), nullable=True)
 
533
    volume = relationship(Volume,
 
534
                          backref=backref('iscsi_target', uselist=False),
 
535
                          foreign_keys=volume_id,
 
536
                          primaryjoin='and_(IscsiTarget.volume_id==Volume.id,'
 
537
                                           'IscsiTarget.deleted==False)')
 
538
 
 
539
 
 
540
class SecurityGroupInstanceAssociation(BASE, CinderBase):
 
541
    __tablename__ = 'security_group_instance_association'
 
542
    id = Column(Integer, primary_key=True)
 
543
    security_group_id = Column(Integer, ForeignKey('security_groups.id'))
 
544
    instance_id = Column(Integer, ForeignKey('instances.id'))
 
545
 
 
546
 
 
547
class SecurityGroup(BASE, CinderBase):
 
548
    """Represents a security group."""
 
549
    __tablename__ = 'security_groups'
 
550
    id = Column(Integer, primary_key=True)
 
551
 
 
552
    name = Column(String(255))
 
553
    description = Column(String(255))
 
554
    user_id = Column(String(255))
 
555
    project_id = Column(String(255))
 
556
 
 
557
    instances = relationship(Instance,
 
558
                             secondary="security_group_instance_association",
 
559
                             primaryjoin='and_('
 
560
        'SecurityGroup.id == '
 
561
        'SecurityGroupInstanceAssociation.security_group_id,'
 
562
        'SecurityGroupInstanceAssociation.deleted == False,'
 
563
        'SecurityGroup.deleted == False)',
 
564
                             secondaryjoin='and_('
 
565
        'SecurityGroupInstanceAssociation.instance_id == Instance.id,'
 
566
        # (anthony) the condition below shouldn't be necessary now that the
 
567
        # association is being marked as deleted.  However, removing this
 
568
        # may cause existing deployments to choke, so I'm leaving it
 
569
        'Instance.deleted == False)',
 
570
                             backref='security_groups')
 
571
 
 
572
 
 
573
class SecurityGroupIngressRule(BASE, CinderBase):
 
574
    """Represents a rule in a security group."""
 
575
    __tablename__ = 'security_group_rules'
 
576
    id = Column(Integer, primary_key=True)
 
577
 
 
578
    parent_group_id = Column(Integer, ForeignKey('security_groups.id'))
 
579
    parent_group = relationship("SecurityGroup", backref="rules",
 
580
                                foreign_keys=parent_group_id,
 
581
                                primaryjoin='and_('
 
582
        'SecurityGroupIngressRule.parent_group_id == SecurityGroup.id,'
 
583
        'SecurityGroupIngressRule.deleted == False)')
 
584
 
 
585
    protocol = Column(String(5))  # "tcp", "udp", or "icmp"
 
586
    from_port = Column(Integer)
 
587
    to_port = Column(Integer)
 
588
    cidr = Column(String(255))
 
589
 
 
590
    # Note: This is not the parent SecurityGroup. It's SecurityGroup we're
 
591
    # granting access for.
 
592
    group_id = Column(Integer, ForeignKey('security_groups.id'))
 
593
    grantee_group = relationship("SecurityGroup",
 
594
                                 foreign_keys=group_id,
 
595
                                 primaryjoin='and_('
 
596
        'SecurityGroupIngressRule.group_id == SecurityGroup.id,'
 
597
        'SecurityGroupIngressRule.deleted == False)')
 
598
 
 
599
 
 
600
class ProviderFirewallRule(BASE, CinderBase):
 
601
    """Represents a rule in a security group."""
 
602
    __tablename__ = 'provider_fw_rules'
 
603
    id = Column(Integer, primary_key=True)
 
604
 
 
605
    protocol = Column(String(5))  # "tcp", "udp", or "icmp"
 
606
    from_port = Column(Integer)
 
607
    to_port = Column(Integer)
 
608
    cidr = Column(String(255))
 
609
 
 
610
 
 
611
class KeyPair(BASE, CinderBase):
 
612
    """Represents a public key pair for ssh."""
 
613
    __tablename__ = 'key_pairs'
 
614
    id = Column(Integer, primary_key=True)
 
615
 
 
616
    name = Column(String(255))
 
617
 
 
618
    user_id = Column(String(255))
 
619
 
 
620
    fingerprint = Column(String(255))
 
621
    public_key = Column(Text)
 
622
 
 
623
 
 
624
class Migration(BASE, CinderBase):
 
625
    """Represents a running host-to-host migration."""
 
626
    __tablename__ = 'migrations'
 
627
    id = Column(Integer, primary_key=True, nullable=False)
 
628
    # NOTE(tr3buchet): the ____compute variables are instance['host']
 
629
    source_compute = Column(String(255))
 
630
    dest_compute = Column(String(255))
 
631
    # NOTE(tr3buchet): dest_host, btw, is an ip address
 
632
    dest_host = Column(String(255))
 
633
    old_instance_type_id = Column(Integer())
 
634
    new_instance_type_id = Column(Integer())
 
635
    instance_uuid = Column(String(255), ForeignKey('instances.uuid'),
 
636
            nullable=True)
 
637
    #TODO(_cerberus_): enum
 
638
    status = Column(String(255))
 
639
 
 
640
 
 
641
class Network(BASE, CinderBase):
 
642
    """Represents a network."""
 
643
    __tablename__ = 'networks'
 
644
    __table_args__ = (schema.UniqueConstraint("vpn_public_address",
 
645
                                              "vpn_public_port"),
 
646
                      {'mysql_engine': 'InnoDB'})
 
647
    id = Column(Integer, primary_key=True)
 
648
    label = Column(String(255))
 
649
 
 
650
    injected = Column(Boolean, default=False)
 
651
    cidr = Column(String(255), unique=True)
 
652
    cidr_v6 = Column(String(255), unique=True)
 
653
    multi_host = Column(Boolean, default=False)
 
654
 
 
655
    gateway_v6 = Column(String(255))
 
656
    netmask_v6 = Column(String(255))
 
657
    netmask = Column(String(255))
 
658
    bridge = Column(String(255))
 
659
    bridge_interface = Column(String(255))
 
660
    gateway = Column(String(255))
 
661
    broadcast = Column(String(255))
 
662
    dns1 = Column(String(255))
 
663
    dns2 = Column(String(255))
 
664
 
 
665
    vlan = Column(Integer)
 
666
    vpn_public_address = Column(String(255))
 
667
    vpn_public_port = Column(Integer)
 
668
    vpn_private_address = Column(String(255))
 
669
    dhcp_start = Column(String(255))
 
670
 
 
671
    rxtx_base = Column(Integer)
 
672
 
 
673
    project_id = Column(String(255))
 
674
    priority = Column(Integer)
 
675
    host = Column(String(255))  # , ForeignKey('hosts.id'))
 
676
    uuid = Column(String(36))
 
677
 
 
678
 
 
679
class VirtualInterface(BASE, CinderBase):
 
680
    """Represents a virtual interface on an instance."""
 
681
    __tablename__ = 'virtual_interfaces'
 
682
    id = Column(Integer, primary_key=True)
 
683
    address = Column(String(255), unique=True)
 
684
    network_id = Column(Integer, nullable=False)
 
685
    instance_id = Column(Integer, nullable=False)
 
686
    uuid = Column(String(36))
 
687
 
 
688
 
 
689
# TODO(vish): can these both come from the same baseclass?
 
690
class FixedIp(BASE, CinderBase):
 
691
    """Represents a fixed ip for an instance."""
 
692
    __tablename__ = 'fixed_ips'
 
693
    id = Column(Integer, primary_key=True)
 
694
    address = Column(String(255))
 
695
    network_id = Column(Integer, nullable=True)
 
696
    virtual_interface_id = Column(Integer, nullable=True)
 
697
    instance_id = Column(Integer, nullable=True)
 
698
    # associated means that a fixed_ip has its instance_id column set
 
699
    # allocated means that a fixed_ip has a its virtual_interface_id column set
 
700
    allocated = Column(Boolean, default=False)
 
701
    # leased means dhcp bridge has leased the ip
 
702
    leased = Column(Boolean, default=False)
 
703
    reserved = Column(Boolean, default=False)
 
704
    host = Column(String(255))
 
705
 
 
706
 
 
707
class FloatingIp(BASE, CinderBase):
 
708
    """Represents a floating ip that dynamically forwards to a fixed ip."""
 
709
    __tablename__ = 'floating_ips'
 
710
    id = Column(Integer, primary_key=True)
 
711
    address = Column(String(255))
 
712
    fixed_ip_id = Column(Integer, nullable=True)
 
713
    project_id = Column(String(255))
 
714
    host = Column(String(255))  # , ForeignKey('hosts.id'))
 
715
    auto_assigned = Column(Boolean, default=False, nullable=False)
 
716
    pool = Column(String(255))
 
717
    interface = Column(String(255))
 
718
 
 
719
 
 
720
class AuthToken(BASE, CinderBase):
 
721
    """Represents an authorization token for all API transactions.
 
722
 
 
723
    Fields are a string representing the actual token and a user id for
 
724
    mapping to the actual user
 
725
 
 
726
    """
 
727
    __tablename__ = 'auth_tokens'
 
728
    token_hash = Column(String(255), primary_key=True)
 
729
    user_id = Column(String(255))
 
730
    server_management_url = Column(String(255))
 
731
    storage_url = Column(String(255))
 
732
    cdn_management_url = Column(String(255))
 
733
 
 
734
 
 
735
class User(BASE, CinderBase):
 
736
    """Represents a user."""
 
737
    __tablename__ = 'users'
 
738
    id = Column(String(255), primary_key=True)
 
739
 
 
740
    name = Column(String(255))
 
741
    access_key = Column(String(255))
 
742
    secret_key = Column(String(255))
 
743
 
 
744
    is_admin = Column(Boolean)
 
745
 
 
746
 
 
747
class Project(BASE, CinderBase):
 
748
    """Represents a project."""
 
749
    __tablename__ = 'projects'
 
750
    id = Column(String(255), primary_key=True)
 
751
    name = Column(String(255))
 
752
    description = Column(String(255))
 
753
 
 
754
    project_manager = Column(String(255), ForeignKey(User.id))
 
755
 
 
756
    members = relationship(User,
 
757
                           secondary='user_project_association',
 
758
                           backref='projects')
 
759
 
 
760
 
 
761
class DNSDomain(BASE, CinderBase):
 
762
    """Represents a DNS domain with availability zone or project info."""
 
763
    __tablename__ = 'dns_domains'
 
764
    domain = Column(String(512), primary_key=True)
 
765
    scope = Column(String(255))
 
766
    availability_zone = Column(String(255))
 
767
    project_id = Column(String(255))
 
768
    project = relationship(Project,
 
769
                           primaryjoin=project_id == Project.id,
 
770
                           foreign_keys=[Project.id],
 
771
                           uselist=False)
 
772
 
 
773
 
 
774
class UserProjectRoleAssociation(BASE, CinderBase):
 
775
    __tablename__ = 'user_project_role_association'
 
776
    user_id = Column(String(255), primary_key=True)
 
777
    user = relationship(User,
 
778
                        primaryjoin=user_id == User.id,
 
779
                        foreign_keys=[User.id],
 
780
                        uselist=False)
 
781
 
 
782
    project_id = Column(String(255), primary_key=True)
 
783
    project = relationship(Project,
 
784
                           primaryjoin=project_id == Project.id,
 
785
                           foreign_keys=[Project.id],
 
786
                           uselist=False)
 
787
 
 
788
    role = Column(String(255), primary_key=True)
 
789
    ForeignKeyConstraint(['user_id',
 
790
                          'project_id'],
 
791
                         ['user_project_association.user_id',
 
792
                          'user_project_association.project_id'])
 
793
 
 
794
 
 
795
class UserRoleAssociation(BASE, CinderBase):
 
796
    __tablename__ = 'user_role_association'
 
797
    user_id = Column(String(255), ForeignKey('users.id'), primary_key=True)
 
798
    user = relationship(User, backref='roles')
 
799
    role = Column(String(255), primary_key=True)
 
800
 
 
801
 
 
802
class UserProjectAssociation(BASE, CinderBase):
 
803
    __tablename__ = 'user_project_association'
 
804
    user_id = Column(String(255), ForeignKey(User.id), primary_key=True)
 
805
    project_id = Column(String(255), ForeignKey(Project.id), primary_key=True)
 
806
 
 
807
 
 
808
class ConsolePool(BASE, CinderBase):
 
809
    """Represents pool of consoles on the same physical node."""
 
810
    __tablename__ = 'console_pools'
 
811
    id = Column(Integer, primary_key=True)
 
812
    address = Column(String(255))
 
813
    username = Column(String(255))
 
814
    password = Column(String(255))
 
815
    console_type = Column(String(255))
 
816
    public_hostname = Column(String(255))
 
817
    host = Column(String(255))
 
818
    compute_host = Column(String(255))
 
819
 
 
820
 
 
821
class Console(BASE, CinderBase):
 
822
    """Represents a console session for an instance."""
 
823
    __tablename__ = 'consoles'
 
824
    id = Column(Integer, primary_key=True)
 
825
    instance_name = Column(String(255))
 
826
    instance_id = Column(Integer)
 
827
    password = Column(String(255))
 
828
    port = Column(Integer, nullable=True)
 
829
    pool_id = Column(Integer, ForeignKey('console_pools.id'))
 
830
    pool = relationship(ConsolePool, backref=backref('consoles'))
 
831
 
 
832
 
 
833
class InstanceMetadata(BASE, CinderBase):
 
834
    """Represents a metadata key/value pair for an instance"""
 
835
    __tablename__ = 'instance_metadata'
 
836
    id = Column(Integer, primary_key=True)
 
837
    key = Column(String(255))
 
838
    value = Column(String(255))
 
839
    instance_id = Column(Integer, ForeignKey('instances.id'), nullable=False)
 
840
    instance = relationship(Instance, backref="metadata",
 
841
                            foreign_keys=instance_id,
 
842
                            primaryjoin='and_('
 
843
                                'InstanceMetadata.instance_id == Instance.id,'
 
844
                                'InstanceMetadata.deleted == False)')
 
845
 
 
846
 
 
847
class InstanceTypeExtraSpecs(BASE, CinderBase):
 
848
    """Represents additional specs as key/value pairs for an instance_type"""
 
849
    __tablename__ = 'instance_type_extra_specs'
 
850
    id = Column(Integer, primary_key=True)
 
851
    key = Column(String(255))
 
852
    value = Column(String(255))
 
853
    instance_type_id = Column(Integer, ForeignKey('instance_types.id'),
 
854
                              nullable=False)
 
855
    instance_type = relationship(InstanceTypes, backref="extra_specs",
 
856
                 foreign_keys=instance_type_id,
 
857
                 primaryjoin='and_('
 
858
                 'InstanceTypeExtraSpecs.instance_type_id == InstanceTypes.id,'
 
859
                 'InstanceTypeExtraSpecs.deleted == False)')
 
860
 
 
861
 
 
862
class Cell(BASE, CinderBase):
 
863
    """Represents parent and child cells of this cell."""
 
864
    __tablename__ = 'cells'
 
865
    id = Column(Integer, primary_key=True)
 
866
    name = Column(String(255))
 
867
    api_url = Column(String(255))
 
868
    username = Column(String(255))
 
869
    password = Column(String(255))
 
870
    weight_offset = Column(Float(), default=0.0)
 
871
    weight_scale = Column(Float(), default=1.0)
 
872
    is_parent = Column(Boolean())
 
873
    rpc_host = Column(String(255))
 
874
    rpc_port = Column(Integer())
 
875
    rpc_virtual_host = Column(String(255))
 
876
 
 
877
 
 
878
class AggregateHost(BASE, CinderBase):
 
879
    """Represents a host that is member of an aggregate."""
 
880
    __tablename__ = 'aggregate_hosts'
 
881
    id = Column(Integer, primary_key=True, autoincrement=True)
 
882
    host = Column(String(255), unique=True)
 
883
    aggregate_id = Column(Integer, ForeignKey('aggregates.id'), nullable=False)
 
884
 
 
885
 
 
886
class AggregateMetadata(BASE, CinderBase):
 
887
    """Represents a metadata key/value pair for an aggregate."""
 
888
    __tablename__ = 'aggregate_metadata'
 
889
    id = Column(Integer, primary_key=True)
 
890
    key = Column(String(255), nullable=False)
 
891
    value = Column(String(255), nullable=False)
 
892
    aggregate_id = Column(Integer, ForeignKey('aggregates.id'), nullable=False)
 
893
 
 
894
 
 
895
class Aggregate(BASE, CinderBase):
 
896
    """Represents a cluster of hosts that exists in this zone."""
 
897
    __tablename__ = 'aggregates'
 
898
    id = Column(Integer, primary_key=True, autoincrement=True)
 
899
    name = Column(String(255), unique=True)
 
900
    operational_state = Column(String(255), nullable=False)
 
901
    availability_zone = Column(String(255), nullable=False)
 
902
    _hosts = relationship(AggregateHost,
 
903
                          secondary="aggregate_hosts",
 
904
                          primaryjoin='and_('
 
905
                                 'Aggregate.id == AggregateHost.aggregate_id,'
 
906
                                 'AggregateHost.deleted == False,'
 
907
                                 'Aggregate.deleted == False)',
 
908
                         secondaryjoin='and_('
 
909
                                'AggregateHost.aggregate_id == Aggregate.id, '
 
910
                                'AggregateHost.deleted == False,'
 
911
                                'Aggregate.deleted == False)',
 
912
                         backref='aggregates')
 
913
 
 
914
    _metadata = relationship(AggregateMetadata,
 
915
                         secondary="aggregate_metadata",
 
916
                         primaryjoin='and_('
 
917
                             'Aggregate.id == AggregateMetadata.aggregate_id,'
 
918
                             'AggregateMetadata.deleted == False,'
 
919
                             'Aggregate.deleted == False)',
 
920
                         secondaryjoin='and_('
 
921
                             'AggregateMetadata.aggregate_id == Aggregate.id, '
 
922
                             'AggregateMetadata.deleted == False,'
 
923
                             'Aggregate.deleted == False)',
 
924
                         backref='aggregates')
 
925
 
 
926
    @property
 
927
    def hosts(self):
 
928
        return [h.host for h in self._hosts]
 
929
 
 
930
    @property
 
931
    def metadetails(self):
 
932
        return dict([(m.key, m.value) for m in self._metadata])
 
933
 
 
934
 
 
935
class AgentBuild(BASE, CinderBase):
 
936
    """Represents an agent build."""
 
937
    __tablename__ = 'agent_builds'
 
938
    id = Column(Integer, primary_key=True)
 
939
    hypervisor = Column(String(255))
 
940
    os = Column(String(255))
 
941
    architecture = Column(String(255))
 
942
    version = Column(String(255))
 
943
    url = Column(String(255))
 
944
    md5hash = Column(String(255))
 
945
 
 
946
 
 
947
class BandwidthUsage(BASE, CinderBase):
 
948
    """Cache for instance bandwidth usage data pulled from the hypervisor"""
 
949
    __tablename__ = 'bw_usage_cache'
 
950
    id = Column(Integer, primary_key=True, nullable=False)
 
951
    uuid = Column(String(36), nullable=False)
 
952
    mac = Column(String(255), nullable=False)
 
953
    start_period = Column(DateTime, nullable=False)
 
954
    last_refreshed = Column(DateTime)
 
955
    bw_in = Column(BigInteger)
 
956
    bw_out = Column(BigInteger)
 
957
 
 
958
 
 
959
class S3Image(BASE, CinderBase):
 
960
    """Compatibility layer for the S3 image service talking to Glance"""
 
961
    __tablename__ = 's3_images'
 
962
    id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
 
963
    uuid = Column(String(36), nullable=False)
 
964
 
 
965
 
 
966
class VolumeIdMapping(BASE, CinderBase):
 
967
    """Compatability layer for the EC2 volume service"""
 
968
    __tablename__ = 'volume_id_mappings'
 
969
    id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
 
970
    uuid = Column(String(36), nullable=False)
 
971
 
 
972
 
 
973
class SnapshotIdMapping(BASE, CinderBase):
 
974
    """Compatability layer for the EC2 snapshot service"""
 
975
    __tablename__ = 'snapshot_id_mappings'
 
976
    id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
 
977
    uuid = Column(String(36), nullable=False)
 
978
 
 
979
 
 
980
class SMFlavors(BASE, CinderBase):
 
981
    """Represents a flavor for SM volumes."""
 
982
    __tablename__ = 'sm_flavors'
 
983
    id = Column(Integer(), primary_key=True)
 
984
    label = Column(String(255))
 
985
    description = Column(String(255))
 
986
 
 
987
 
 
988
class SMBackendConf(BASE, CinderBase):
 
989
    """Represents the connection to the backend for SM."""
 
990
    __tablename__ = 'sm_backend_config'
 
991
    id = Column(Integer(), primary_key=True)
 
992
    flavor_id = Column(Integer, ForeignKey('sm_flavors.id'), nullable=False)
 
993
    sr_uuid = Column(String(255))
 
994
    sr_type = Column(String(255))
 
995
    config_params = Column(String(2047))
 
996
 
 
997
 
 
998
class SMVolume(BASE, CinderBase):
 
999
    __tablename__ = 'sm_volume'
 
1000
    id = Column(String(36), ForeignKey(Volume.id), primary_key=True)
 
1001
    backend_id = Column(Integer, ForeignKey('sm_backend_config.id'),
 
1002
                        nullable=False)
 
1003
    vdi_uuid = Column(String(255))
 
1004
 
 
1005
 
 
1006
class InstanceFault(BASE, CinderBase):
 
1007
    __tablename__ = 'instance_faults'
 
1008
    id = Column(Integer(), primary_key=True, autoincrement=True)
 
1009
    instance_uuid = Column(String(36),
 
1010
                           ForeignKey('instances.uuid'),
 
1011
                           nullable=False)
 
1012
    code = Column(Integer(), nullable=False)
 
1013
    message = Column(String(255))
 
1014
    details = Column(Text)
 
1015
 
 
1016
 
 
1017
def register_models():
 
1018
    """Register Models and create metadata.
 
1019
 
 
1020
    Called from cinder.db.sqlalchemy.__init__ as part of loading the driver,
 
1021
    it will never need to be called explicitly elsewhere unless the
 
1022
    connection is lost and needs to be reestablished.
 
1023
    """
 
1024
    from sqlalchemy import create_engine
 
1025
    models = (AgentBuild,
 
1026
              Aggregate,
 
1027
              AggregateHost,
 
1028
              AggregateMetadata,
 
1029
              AuthToken,
 
1030
              Certificate,
 
1031
              Cell,
 
1032
              Console,
 
1033
              ConsolePool,
 
1034
              FixedIp,
 
1035
              FloatingIp,
 
1036
              Instance,
 
1037
              InstanceActions,
 
1038
              InstanceFault,
 
1039
              InstanceMetadata,
 
1040
              InstanceTypeExtraSpecs,
 
1041
              InstanceTypes,
 
1042
              IscsiTarget,
 
1043
              Migration,
 
1044
              Network,
 
1045
              Project,
 
1046
              SecurityGroup,
 
1047
              SecurityGroupIngressRule,
 
1048
              SecurityGroupInstanceAssociation,
 
1049
              Service,
 
1050
              SMBackendConf,
 
1051
              SMFlavors,
 
1052
              SMVolume,
 
1053
              User,
 
1054
              Volume,
 
1055
              VolumeMetadata,
 
1056
              VolumeTypeExtraSpecs,
 
1057
              VolumeTypes,
 
1058
              VolumeIdMapping,
 
1059
              SnapshotIdMapping,
 
1060
              )
 
1061
    engine = create_engine(FLAGS.sql_connection, echo=False)
 
1062
    for model in models:
 
1063
        model.metadata.create_all(engine)