1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
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.
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
13
# http://www.apache.org/licenses/LICENSE-2.0
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
21
SQLAlchemy models for cinder data.
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
31
from cinder.db.sqlalchemy.session import get_session
33
from cinder import exception
34
from cinder import flags
35
from cinder import utils
39
BASE = declarative_base()
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)
52
def save(self, session=None):
53
"""Save this object."""
55
session = get_session()
59
except IntegrityError, e:
60
if str(e).endswith('is not unique'):
61
raise exception.Duplicate(str(e))
65
def delete(self, session=None):
66
"""Delete this object."""
68
self.deleted_at = utils.utcnow()
69
self.save(session=session)
71
def __setitem__(self, key, value):
72
setattr(self, key, value)
74
def __getitem__(self, key):
75
return getattr(self, key)
77
def get(self, key, default=None):
78
return getattr(self, key, default)
81
self._i = iter(object_mapper(self).columns)
85
n = self._i.next().name
86
return n, getattr(self, n)
88
def update(self, values):
89
"""Make the model object behave like a dict"""
90
for k, v in values.iteritems():
94
"""Make the model object behave like a dict.
96
Includes attributes from joins."""
98
joined = dict([(k, v) for k, v in self.__dict__.iteritems()
101
return local.iteritems()
104
class Service(BASE, CinderBase):
105
"""Represents a running service on a host."""
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')
117
class ComputeNode(BASE, CinderBase):
118
"""Represents a running compute service on a host."""
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,
127
'ComputeNode.service_id == Service.id,'
128
'ComputeNode.deleted == False)')
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))
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.
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)
150
# Note(masumotok): Expected Strings example:
154
# "topology":{"sockets":1, "threads":2, "cores":3},
155
# "features":["tdtscp", "xtpr"]}'
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)
164
class Certificate(BASE, CinderBase):
165
"""Represents a an x509 certificate"""
166
__tablename__ = 'certificates'
167
id = Column(Integer, primary_key=True)
169
user_id = Column(String(255))
170
project_id = Column(String(255))
171
file_name = Column(String(255))
174
class Instance(BASE, CinderBase):
175
"""Represents a guest vm."""
176
__tablename__ = 'instances'
179
id = Column(Integer, primary_key=True, autoincrement=True)
184
base_name = FLAGS.instance_name_template % self.id
186
# Support templates like "uuid-%(uuid)s", etc.
188
for key, value in self.iteritems():
189
# prevent recursion if someone specifies %(name)s
190
# %(name)s will not be valid.
195
base_name = FLAGS.instance_name_template % info
197
base_name = self.uuid
198
if getattr(self, '_rescue', False):
199
base_name += "-rescue"
202
user_id = Column(String(255))
203
project_id = Column(String(255))
205
image_ref = Column(String(255))
206
kernel_id = Column(String(255))
207
ramdisk_id = Column(String(255))
208
server_name = Column(String(255))
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))
217
launch_index = Column(Integer)
218
key_name = Column(String(255))
219
key_data = Column(Text)
221
power_state = Column(Integer)
222
vm_state = Column(String(255))
223
task_state = Column(String(255))
225
memory_mb = Column(Integer)
226
vcpus = Column(Integer)
227
root_gb = Column(Integer)
228
ephemeral_gb = Column(Integer)
230
hostname = Column(String(255))
231
host = Column(String(255)) # , ForeignKey('hosts.id'))
234
instance_type_id = Column(Integer)
236
user_data = Column(Text)
238
reservation_id = Column(String(255))
240
scheduled_at = Column(DateTime)
241
launched_at = Column(DateTime)
242
terminated_at = Column(DateTime)
244
availability_zone = Column(String(255))
246
# User editable field for display in user-facing UIs
247
display_name = Column(String(255))
248
display_description = Column(String(255))
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)
255
os_type = Column(String(255))
256
architecture = Column(String(255))
257
vm_mode = Column(String(255))
258
uuid = Column(String(36))
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))
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))
270
auto_disk_config = Column(Boolean())
271
progress = Column(Integer)
273
# EC2 instance_initiated_shutdown_teminate
274
# True: -> 'terminate'
276
shutdown_terminate = Column(Boolean(), default=True, nullable=False)
278
# EC2 disable_api_termination
279
disable_terminate = Column(Boolean(), default=False, nullable=False)
281
# OpenStack compute cell name
282
cell_name = Column(String(255))
285
class InstanceInfoCache(BASE, CinderBase):
287
Represents a cache of information about an instance
289
__tablename__ = 'instance_info_caches'
290
id = Column(Integer, primary_key=True, autoincrement=True)
292
# text column used for storing a json object of network data for api
293
network_info = Column(Text)
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)
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))
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)
326
instances = relationship(Instance,
327
backref=backref('instance_type', uselist=False),
330
'Instance.instance_type_id == '
332
'InstanceTypes.deleted == False)')
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)
342
return FLAGS.volume_name_template % self.id
344
ec2_id = Column(Integer)
345
user_id = Column(String(255))
346
project_id = Column(String(255))
348
snapshot_id = Column(String(36))
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
364
scheduled_at = Column(DateTime)
365
launched_at = Column(DateTime)
366
terminated_at = Column(DateTime)
368
display_name = Column(String(255))
369
display_description = Column(String(255))
371
provider_location = Column(String(255))
372
provider_auth = Column(String(255))
374
volume_type_id = Column(Integer)
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,
387
'VolumeMetadata.volume_id == Volume.id,'
388
'VolumeMetadata.deleted == False)')
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))
397
volumes = relationship(Volume,
398
backref=backref('volume_type', uselist=False),
401
'Volume.volume_type_id == VolumeTypes.id, '
402
'VolumeTypes.deleted == False)')
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'),
413
volume_type = relationship(VolumeTypes, backref="extra_specs",
414
foreign_keys=volume_type_id,
416
'VolumeTypeExtraSpecs.volume_type_id == VolumeTypes.id,'
417
'VolumeTypeExtraSpecs.deleted == False)')
420
class Quota(BASE, CinderBase):
421
"""Represents a single quota override for a project.
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.
430
__tablename__ = 'quotas'
431
id = Column(Integer, primary_key=True)
433
project_id = Column(String(255), index=True)
435
resource = Column(String(255))
436
hard_limit = Column(Integer, nullable=True)
439
class QuotaClass(BASE, CinderBase):
440
"""Represents a single quota override for a quota class.
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.
447
__tablename__ = 'quota_classes'
448
id = Column(Integer, primary_key=True)
450
class_name = Column(String(255), index=True)
452
resource = Column(String(255))
453
hard_limit = Column(Integer, nullable=True)
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)
463
return FLAGS.snapshot_name_template % self.id
466
def volume_name(self):
467
return FLAGS.volume_name_template % self.volume_id
469
user_id = Column(String(255))
470
project_id = Column(String(255))
472
volume_id = Column(String(36))
473
status = Column(String(255))
474
progress = Column(String(255))
475
volume_size = Column(Integer)
477
display_name = Column(String(255))
478
display_description = Column(String(255))
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)
486
instance_uuid = Column(Integer, ForeignKey('instances.uuid'),
488
instance = relationship(Instance,
489
backref=backref('balock_device_mapping'),
490
foreign_keys=instance_uuid,
491
primaryjoin='and_(BlockDeviceMapping.'
494
'BlockDeviceMapping.deleted=='
496
device_name = Column(String(255), nullable=False)
498
# default=False for compatibility of the existing code.
500
# default True for ami specified device.
501
# default False for created with other timing.
502
delete_on_termination = Column(Boolean, default=False)
504
# for ephemeral device
505
virtual_name = Column(String(255), nullable=True)
507
# for snapshot or volume
508
snapshot_id = Column(String(36), ForeignKey('snapshots.id'))
510
snapshot = relationship(Snapshot,
511
foreign_keys=snapshot_id)
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)
518
# for no device to suppress devices.
519
no_device = Column(Boolean, nullable=True)
521
connection_info = Column(Text, nullable=True)
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)')
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'))
547
class SecurityGroup(BASE, CinderBase):
548
"""Represents a security group."""
549
__tablename__ = 'security_groups'
550
id = Column(Integer, primary_key=True)
552
name = Column(String(255))
553
description = Column(String(255))
554
user_id = Column(String(255))
555
project_id = Column(String(255))
557
instances = relationship(Instance,
558
secondary="security_group_instance_association",
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')
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)
578
parent_group_id = Column(Integer, ForeignKey('security_groups.id'))
579
parent_group = relationship("SecurityGroup", backref="rules",
580
foreign_keys=parent_group_id,
582
'SecurityGroupIngressRule.parent_group_id == SecurityGroup.id,'
583
'SecurityGroupIngressRule.deleted == False)')
585
protocol = Column(String(5)) # "tcp", "udp", or "icmp"
586
from_port = Column(Integer)
587
to_port = Column(Integer)
588
cidr = Column(String(255))
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,
596
'SecurityGroupIngressRule.group_id == SecurityGroup.id,'
597
'SecurityGroupIngressRule.deleted == False)')
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)
605
protocol = Column(String(5)) # "tcp", "udp", or "icmp"
606
from_port = Column(Integer)
607
to_port = Column(Integer)
608
cidr = Column(String(255))
611
class KeyPair(BASE, CinderBase):
612
"""Represents a public key pair for ssh."""
613
__tablename__ = 'key_pairs'
614
id = Column(Integer, primary_key=True)
616
name = Column(String(255))
618
user_id = Column(String(255))
620
fingerprint = Column(String(255))
621
public_key = Column(Text)
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'),
637
#TODO(_cerberus_): enum
638
status = Column(String(255))
641
class Network(BASE, CinderBase):
642
"""Represents a network."""
643
__tablename__ = 'networks'
644
__table_args__ = (schema.UniqueConstraint("vpn_public_address",
646
{'mysql_engine': 'InnoDB'})
647
id = Column(Integer, primary_key=True)
648
label = Column(String(255))
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)
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))
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))
671
rxtx_base = Column(Integer)
673
project_id = Column(String(255))
674
priority = Column(Integer)
675
host = Column(String(255)) # , ForeignKey('hosts.id'))
676
uuid = Column(String(36))
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))
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))
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))
720
class AuthToken(BASE, CinderBase):
721
"""Represents an authorization token for all API transactions.
723
Fields are a string representing the actual token and a user id for
724
mapping to the actual user
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))
735
class User(BASE, CinderBase):
736
"""Represents a user."""
737
__tablename__ = 'users'
738
id = Column(String(255), primary_key=True)
740
name = Column(String(255))
741
access_key = Column(String(255))
742
secret_key = Column(String(255))
744
is_admin = Column(Boolean)
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))
754
project_manager = Column(String(255), ForeignKey(User.id))
756
members = relationship(User,
757
secondary='user_project_association',
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],
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],
782
project_id = Column(String(255), primary_key=True)
783
project = relationship(Project,
784
primaryjoin=project_id == Project.id,
785
foreign_keys=[Project.id],
788
role = Column(String(255), primary_key=True)
789
ForeignKeyConstraint(['user_id',
791
['user_project_association.user_id',
792
'user_project_association.project_id'])
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)
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)
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))
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'))
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,
843
'InstanceMetadata.instance_id == Instance.id,'
844
'InstanceMetadata.deleted == False)')
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'),
855
instance_type = relationship(InstanceTypes, backref="extra_specs",
856
foreign_keys=instance_type_id,
858
'InstanceTypeExtraSpecs.instance_type_id == InstanceTypes.id,'
859
'InstanceTypeExtraSpecs.deleted == False)')
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))
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)
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)
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",
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')
914
_metadata = relationship(AggregateMetadata,
915
secondary="aggregate_metadata",
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')
928
return [h.host for h in self._hosts]
931
def metadetails(self):
932
return dict([(m.key, m.value) for m in self._metadata])
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))
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)
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)
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)
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)
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))
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))
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'),
1003
vdi_uuid = Column(String(255))
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'),
1012
code = Column(Integer(), nullable=False)
1013
message = Column(String(255))
1014
details = Column(Text)
1017
def register_models():
1018
"""Register Models and create metadata.
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.
1024
from sqlalchemy import create_engine
1025
models = (AgentBuild,
1040
InstanceTypeExtraSpecs,
1047
SecurityGroupIngressRule,
1048
SecurityGroupInstanceAssociation,
1056
VolumeTypeExtraSpecs,
1061
engine = create_engine(FLAGS.sql_connection, echo=False)
1062
for model in models:
1063
model.metadata.create_all(engine)