Coverage for nova/db/api/migrations/env.py: 48%
34 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
13from logging.config import fileConfig
15from alembic import context
16from sqlalchemy import engine_from_config
17from sqlalchemy import pool
19from nova.db.api import models
21# this is the Alembic Config object, which provides
22# access to the values within the .ini file in use.
23config = context.config
25# Interpret the config file for Python logging unless we're told not to.
26# This line sets up loggers basically.
27if config.attributes.get('configure_logger', True): 27 ↛ 28line 27 didn't jump to line 28 because the condition on line 27 was never true
28 fileConfig(config.config_file_name)
30# this is the MetaData object for the various models in the API database
31target_metadata = models.BASE.metadata
34def include_name(name, type_, parent_names):
35 """Determine which tables or columns to skip.
37 This is used when we decide to "delete" a table or column. In this
38 instance, we will remove the SQLAlchemy model or field but leave the
39 underlying database table or column in place for a number of releases
40 after. Once we're sure that there is no code running that contains
41 references to the old models, we can then remove the underlying table. In
42 the interim, we must track the discrepancy between models and actual
43 database data here.
44 """
45 if type_ == 'table':
46 return name not in models.REMOVED_TABLES
48 if type_ == 'column':
49 return (parent_names['table_name'], name) not in models.REMOVED_COLUMNS
51 return True
54def run_migrations_offline():
55 """Run migrations in 'offline' mode.
57 This configures the context with just a URL and not an Engine, though an
58 Engine is acceptable here as well. By skipping the Engine creation we
59 don't even need a DBAPI to be available.
61 Calls to context.execute() here emit the given string to the script output.
62 """
63 url = config.get_main_option("sqlalchemy.url")
64 context.configure(
65 url=url,
66 target_metadata=target_metadata,
67 render_as_batch=True,
68 include_name=include_name,
69 literal_binds=True,
70 dialect_opts={"paramstyle": "named"},
71 )
73 with context.begin_transaction():
74 context.run_migrations()
77def run_migrations_online():
78 """Run migrations in 'online' mode.
80 In this scenario we need to create an Engine and associate a connection
81 with the context.
83 This is modified from the default based on the below, since we want to
84 share an engine when unit testing so in-memory database testing actually
85 works.
87 https://alembic.sqlalchemy.org/en/latest/cookbook.html#connection-sharing
88 """
89 connectable = config.attributes.get('connection', None)
91 if connectable is None: 91 ↛ 93line 91 didn't jump to line 93 because the condition on line 91 was never true
92 # only create Engine if we don't have a Connection from the outside
93 connectable = engine_from_config(
94 config.get_section(config.config_ini_section),
95 prefix="sqlalchemy.",
96 poolclass=pool.NullPool,
97 )
98 with connectable.connect() as connection:
99 context.configure(
100 connection=connection,
101 target_metadata=target_metadata,
102 render_as_batch=True,
103 include_name=include_name,
104 )
106 with context.begin_transaction():
107 context.run_migrations()
108 else:
109 context.configure(
110 connection=connectable,
111 target_metadata=target_metadata,
112 render_as_batch=True,
113 include_name=include_name,
114 )
116 with context.begin_transaction():
117 context.run_migrations()
120if context.is_offline_mode(): 120 ↛ 121line 120 didn't jump to line 121 because the condition on line 120 was never true
121 run_migrations_offline()
122else:
123 run_migrations_online()