Jun 26 MT-2 phase fixes migration script error
This commit is contained in:
@@ -46,6 +46,9 @@ _DEFAULT_VERSION_LOCATIONS = os.path.join(_REPO_ROOT, 'migrations', 'versions')
|
||||
# Everything except a deleted tenant should be kept schema-current.
|
||||
MIGRATABLE_STATUSES = ('provisioning', 'active', 'suspended')
|
||||
|
||||
# Squashed baseline that builds the full schema (migrations/versions root).
|
||||
BASELINE_REVISION = '0003_add_user_active'
|
||||
|
||||
TenantRef = namedtuple('TenantRef', ['id', 'slug', 'db_uri'])
|
||||
|
||||
|
||||
@@ -125,7 +128,56 @@ def upgrade_tenant(tenant, script_location=None, version_locations=None, record_
|
||||
raise
|
||||
|
||||
|
||||
# ── CLI ────────────────────────────────────────────────────────────────────
|
||||
def bootstrap_tenant(tenant, script_location=None, version_locations=None,
|
||||
baseline_rev=BASELINE_REVISION, record_job=True):
|
||||
"""Build a FRESH tenant database, then mark it current.
|
||||
|
||||
Runs the squashed baseline (full schema) only, then `stamp head` — the
|
||||
historical phase migrations are NOT replayed (several are not idempotent and
|
||||
would conflict with the full-schema baseline). Use this for brand-new tenant
|
||||
databases; use upgrade_tenant() for ongoing incremental migrations.
|
||||
|
||||
Returns the stamped head revision.
|
||||
"""
|
||||
db_uri = tenant.db_uri
|
||||
cfg = _make_config(db_uri, script_location, version_locations)
|
||||
|
||||
job_id = None
|
||||
if record_job:
|
||||
with control_session() as s:
|
||||
job = ProvisioningJob(tenant_id=tenant.id, action='migrate',
|
||||
status='running', created_at=now_eastern())
|
||||
s.add(job)
|
||||
s.flush()
|
||||
job_id = job.id
|
||||
|
||||
try:
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
command.upgrade(cfg, baseline_rev) # build full schema (baseline only)
|
||||
command.stamp(cfg, 'head') # mark at head without replaying phases
|
||||
applied = current_revision(db_uri)
|
||||
|
||||
with control_session() as s:
|
||||
t = s.get(Tenant, tenant.id)
|
||||
if t is not None:
|
||||
t.alembic_head = applied
|
||||
if job_id is not None:
|
||||
j = s.get(ProvisioningJob, job_id)
|
||||
if j is not None:
|
||||
j.status = 'ok'
|
||||
j.finished_at = now_eastern()
|
||||
j.log = f'bootstrapped (baseline {baseline_rev}) + stamped {applied}'
|
||||
return applied
|
||||
|
||||
except Exception as e:
|
||||
if job_id is not None:
|
||||
with control_session() as s:
|
||||
j = s.get(ProvisioningJob, job_id)
|
||||
if j is not None:
|
||||
j.status = 'failed'
|
||||
j.finished_at = now_eastern()
|
||||
j.log = f'{type(e).__name__}: {e}'
|
||||
raise
|
||||
|
||||
def _select_tenants(selector):
|
||||
with control_session() as s:
|
||||
@@ -174,6 +226,22 @@ def _cmd_current(args):
|
||||
return 0
|
||||
|
||||
|
||||
def _cmd_bootstrap(args):
|
||||
tenants = _select_tenants(args.tenant)
|
||||
if not tenants:
|
||||
print(f'No matching tenants for --tenant {args.tenant}.')
|
||||
return 0
|
||||
failures = 0
|
||||
for t in tenants:
|
||||
try:
|
||||
applied = bootstrap_tenant(t)
|
||||
print(f' [ok] {t.slug} (id={t.id}) bootstrapped -> {applied}')
|
||||
except Exception as e:
|
||||
failures += 1
|
||||
print(f' [FAIL] {t.slug} (id={t.id}): {type(e).__name__}: {e}')
|
||||
return 1 if failures else 0
|
||||
|
||||
|
||||
def _cmd_heads(_args):
|
||||
print(chain_head())
|
||||
return 0
|
||||
@@ -192,6 +260,11 @@ def main(argv=None):
|
||||
p_cur.add_argument('--tenant', default='all', help="'all', or a tenant id or slug")
|
||||
p_cur.set_defaults(func=_cmd_current)
|
||||
|
||||
p_boot = sub.add_parser('bootstrap',
|
||||
help='Build a FRESH tenant DB (baseline + stamp head)')
|
||||
p_boot.add_argument('--tenant', required=True, help="'all', or a tenant id or slug")
|
||||
p_boot.set_defaults(func=_cmd_bootstrap)
|
||||
|
||||
sub.add_parser('heads', help='Show the chain head revision').set_defaults(func=_cmd_heads)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
Reference in New Issue
Block a user