~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to nova/db/sqlalchemy/migrate_repo/versions/016_make_quotas_key_and_value.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-24 13:12:53 UTC
  • mfrom: (1.1.55)
  • Revision ID: package-import@ubuntu.com-20120524131253-ommql08fg1en06ut
Tags: 2012.2~f1-0ubuntu1
* New upstream release.
* Prepare for quantal:
  - Dropped debian/patches/upstream/0006-Use-project_id-in-ec2.cloud._format_image.patch
  - Dropped debian/patches/upstream/0005-Populate-image-properties-with-project_id-again.patch
  - Dropped debian/patches/upstream/0004-Fixed-bug-962840-added-a-test-case.patch
  - Dropped debian/patches/upstream/0003-Allow-unprivileged-RADOS-users-to-access-rbd-volumes.patch
  - Dropped debian/patches/upstream/0002-Stop-libvirt-test-from-deleting-instances-dir.patch
  - Dropped debian/patches/upstream/0001-fix-bug-where-nova-ignores-glance-host-in-imageref.patch 
  - Dropped debian/patches/0001-fix-useexisting-deprecation-warnings.patch
* debian/control: Add python-keystone as a dependency. (LP: #907197)
* debian/patches/kombu_tests_timeout.patch: Refreshed.
* debian/nova.conf, debian/nova-common.postinst: Convert to new ini
  file configuration
* debian/patches/nova-manage_flagfile_location.patch: Refreshed

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
 
 
3
 
# Copyright 2011 OpenStack LLC.
4
 
#
5
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
 
#    not use this file except in compliance with the License. You may obtain
7
 
#    a copy of the License at
8
 
#
9
 
#         http://www.apache.org/licenses/LICENSE-2.0
10
 
#
11
 
#    Unless required by applicable law or agreed to in writing, software
12
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
 
#    License for the specific language governing permissions and limitations
15
 
#    under the License.
16
 
 
17
 
from sqlalchemy import Boolean, Column, DateTime, Integer
18
 
from sqlalchemy import MetaData, String, Table
19
 
 
20
 
from nova import utils
21
 
 
22
 
resources = [
23
 
    'instances',
24
 
    'cores',
25
 
    'volumes',
26
 
    'gigabytes',
27
 
    'floating_ips',
28
 
    'metadata_items',
29
 
]
30
 
 
31
 
 
32
 
def old_style_quotas_table(meta, name):
33
 
    return Table(name, meta,
34
 
                 Column('id', Integer(), primary_key=True),
35
 
                 Column('created_at', DateTime(),
36
 
                        default=utils.utcnow),
37
 
                 Column('updated_at', DateTime(),
38
 
                        onupdate=utils.utcnow),
39
 
                 Column('deleted_at', DateTime()),
40
 
                 Column('deleted', Boolean(), default=False),
41
 
                 Column('project_id',
42
 
                        String(length=255, convert_unicode=False,
43
 
                               assert_unicode=None, unicode_error=None,
44
 
                               _warn_on_bytestring=False)),
45
 
                 Column('instances', Integer()),
46
 
                 Column('cores', Integer()),
47
 
                 Column('volumes', Integer()),
48
 
                 Column('gigabytes', Integer()),
49
 
                 Column('floating_ips', Integer()),
50
 
                 Column('metadata_items', Integer()),
51
 
                )
52
 
 
53
 
 
54
 
def new_style_quotas_table(meta, name):
55
 
    return Table(name, meta,
56
 
                 Column('id', Integer(), primary_key=True),
57
 
                 Column('created_at', DateTime(),
58
 
                        default=utils.utcnow),
59
 
                 Column('updated_at', DateTime(),
60
 
                        onupdate=utils.utcnow),
61
 
                 Column('deleted_at', DateTime()),
62
 
                 Column('deleted', Boolean(), default=False),
63
 
                 Column('project_id',
64
 
                        String(length=255, convert_unicode=False,
65
 
                               assert_unicode=None, unicode_error=None,
66
 
                               _warn_on_bytestring=False)),
67
 
                 Column('resource',
68
 
                        String(length=255, convert_unicode=False,
69
 
                               assert_unicode=None, unicode_error=None,
70
 
                               _warn_on_bytestring=False),
71
 
                        nullable=False),
72
 
                 Column('hard_limit', Integer(), nullable=True),
73
 
                )
74
 
 
75
 
 
76
 
def quotas_table(meta, name='quotas'):
77
 
    return Table(name, meta, autoload=True)
78
 
 
79
 
 
80
 
def _assert_no_duplicate_project_ids(quotas):
81
 
    project_ids = set()
82
 
    message = ('There are multiple active quotas for project "%s" '
83
 
               '(among others, possibly). '
84
 
               'Please resolve all ambiguous quotas before '
85
 
               'reattempting the migration.')
86
 
    for quota in quotas:
87
 
        assert quota.project_id not in project_ids, message % quota.project_id
88
 
        project_ids.add(quota.project_id)
89
 
 
90
 
 
91
 
def assert_old_quotas_have_no_active_duplicates(migrate_engine, quotas):
92
 
    """Ensure that there are no duplicate non-deleted quota entries."""
93
 
    select = quotas.select().where(quotas.c.deleted == False)
94
 
    results = migrate_engine.execute(select)
95
 
    _assert_no_duplicate_project_ids(list(results))
96
 
 
97
 
 
98
 
def assert_new_quotas_have_no_active_duplicates(migrate_engine, quotas):
99
 
    """Ensure that there are no duplicate non-deleted quota entries."""
100
 
    for resource in resources:
101
 
        select = quotas.select().\
102
 
                where(quotas.c.deleted == False).\
103
 
                where(quotas.c.resource == resource)
104
 
        results = migrate_engine.execute(select)
105
 
        _assert_no_duplicate_project_ids(list(results))
106
 
 
107
 
 
108
 
def convert_forward(migrate_engine, old_quotas, new_quotas):
109
 
    quotas = list(migrate_engine.execute(old_quotas.select()))
110
 
    for quota in quotas:
111
 
        for resource in resources:
112
 
            hard_limit = getattr(quota, resource)
113
 
            if hard_limit is None:
114
 
                continue
115
 
            insert = new_quotas.insert().values(
116
 
                created_at=quota.created_at,
117
 
                updated_at=quota.updated_at,
118
 
                deleted_at=quota.deleted_at,
119
 
                deleted=quota.deleted,
120
 
                project_id=quota.project_id,
121
 
                resource=resource,
122
 
                hard_limit=hard_limit)
123
 
            migrate_engine.execute(insert)
124
 
 
125
 
 
126
 
def earliest(date1, date2):
127
 
    if date1 is None and date2 is None:
128
 
        return None
129
 
    if date1 is None:
130
 
        return date2
131
 
    if date2 is None:
132
 
        return date1
133
 
    if date1 < date2:
134
 
        return date1
135
 
    return date2
136
 
 
137
 
 
138
 
def latest(date1, date2):
139
 
    if date1 is None and date2 is None:
140
 
        return None
141
 
    if date1 is None:
142
 
        return date2
143
 
    if date2 is None:
144
 
        return date1
145
 
    if date1 > date2:
146
 
        return date1
147
 
    return date2
148
 
 
149
 
 
150
 
def convert_backward(migrate_engine, old_quotas, new_quotas):
151
 
    quotas = {}
152
 
    for quota in migrate_engine.execute(new_quotas.select()):
153
 
        if (quota.resource not in resources
154
 
            or quota.hard_limit is None or quota.deleted):
155
 
            continue
156
 
        if not quota.project_id in quotas:
157
 
            quotas[quota.project_id] = {
158
 
                'project_id': quota.project_id,
159
 
                'created_at': quota.created_at,
160
 
                'updated_at': quota.updated_at,
161
 
                quota.resource: quota.hard_limit,
162
 
            }
163
 
        else:
164
 
            quotas[quota.project_id]['created_at'] = earliest(
165
 
                quota.created_at, quotas[quota.project_id]['created_at'])
166
 
            quotas[quota.project_id]['updated_at'] = latest(
167
 
                quota.updated_at, quotas[quota.project_id]['updated_at'])
168
 
            quotas[quota.project_id][quota.resource] = quota.hard_limit
169
 
 
170
 
    for quota in quotas.itervalues():
171
 
        insert = old_quotas.insert().values(**quota)
172
 
        migrate_engine.execute(insert)
173
 
 
174
 
 
175
 
def upgrade(migrate_engine):
176
 
    # Upgrade operations go here. Don't create your own engine;
177
 
    # bind migrate_engine to your metadata
178
 
    meta = MetaData()
179
 
    meta.bind = migrate_engine
180
 
 
181
 
    old_quotas = quotas_table(meta)
182
 
    assert_old_quotas_have_no_active_duplicates(migrate_engine, old_quotas)
183
 
 
184
 
    new_quotas = new_style_quotas_table(meta, 'quotas_new')
185
 
    new_quotas.create()
186
 
    convert_forward(migrate_engine, old_quotas, new_quotas)
187
 
    old_quotas.drop()
188
 
 
189
 
    # clear metadata to work around this:
190
 
    # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=128
191
 
    meta.clear()
192
 
    new_quotas = quotas_table(meta, 'quotas_new')
193
 
    new_quotas.rename('quotas')
194
 
 
195
 
 
196
 
def downgrade(migrate_engine):
197
 
    # Operations to reverse the above upgrade go here.
198
 
    meta = MetaData()
199
 
    meta.bind = migrate_engine
200
 
 
201
 
    new_quotas = quotas_table(meta)
202
 
    assert_new_quotas_have_no_active_duplicates(migrate_engine, new_quotas)
203
 
 
204
 
    old_quotas = old_style_quotas_table(meta, 'quotas_old')
205
 
    old_quotas.create()
206
 
    convert_backward(migrate_engine, old_quotas, new_quotas)
207
 
    new_quotas.drop()
208
 
 
209
 
    # clear metadata to work around this:
210
 
    # http://code.google.com/p/sqlalchemy-migrate/issues/detail?id=128
211
 
    meta.clear()
212
 
    old_quotas = quotas_table(meta, 'quotas_old')
213
 
    old_quotas.rename('quotas')