Module materialize.checks.scenarios_upgrade
Expand source code Browse git
# Copyright Materialize, Inc. and contributors. All rights reserved.
#
# Use of this software is governed by the Business Source License
# included in the LICENSE file at the root of this repository.
#
# As of the Change Date specified in that file, in accordance with
# the Business Source License, use of this software will be governed
# by the Apache License, Version 2.0.
from materialize.checks.actions import Action, Initialize, Manipulate, Sleep, Validate
from materialize.checks.all_checks.statement_logging import StatementLogging
from materialize.checks.checks import Check
from materialize.checks.executors import Executor
from materialize.checks.mzcompose_actions import (
KillClusterdCompute,
KillMz,
PromoteMz,
StartClusterdCompute,
StartMz,
UseClusterdCompute,
WaitReadyMz,
)
from materialize.checks.scenarios import Scenario
from materialize.mz_version import MzVersion
from materialize.version_list import get_published_minor_mz_versions
# late initialization
_minor_versions: list[MzVersion] | None = None
_last_version: MzVersion | None = None
_previous_version: MzVersion | None = None
def get_minor_versions() -> list[MzVersion]:
global _minor_versions
if _minor_versions is None:
_minor_versions = get_published_minor_mz_versions(
limit=4, exclude_current_minor_version=True
)
return _minor_versions
def get_last_version() -> MzVersion:
global _last_version
if _last_version is None:
_last_version = get_minor_versions()[0]
return _last_version
def get_previous_version() -> MzVersion:
global _previous_version
if _previous_version is None:
_previous_version = get_minor_versions()[1]
return _previous_version
class UpgradeEntireMz(Scenario):
"""Upgrade the entire Mz instance from the last released version."""
def base_version(self) -> MzVersion:
return get_last_version()
def actions(self) -> list[Action]:
print(f"Upgrading from tag {self.base_version()}")
return [
StartMz(self, tag=self.base_version()),
Initialize(self),
Manipulate(self, phase=1),
KillMz(
capture_logs=True
), # We always use True here otherwise docker-compose will lose the pre-upgrade logs
StartMz(self, tag=None),
Manipulate(self, phase=2),
Validate(self),
# A second restart while already on the new version
KillMz(capture_logs=True),
StartMz(self, tag=None),
Validate(self),
]
class UpgradeEntireMzTwoVersions(Scenario):
"""Upgrade the entire Mz instance starting from the previous
released version and passing through the last released version."""
def base_version(self) -> MzVersion:
return get_previous_version()
def actions(self) -> list[Action]:
print(f"Upgrade path: {self.base_version()} -> {get_last_version()} -> current")
return [
# Start with previous_version
StartMz(self, tag=self.base_version()),
Initialize(self),
# Upgrade to last_version
KillMz(capture_logs=True),
StartMz(self, tag=get_last_version()),
Manipulate(self, phase=1),
# Upgrade to current source
KillMz(capture_logs=True),
StartMz(self, tag=None),
Manipulate(self, phase=2),
Validate(self),
# A second restart while already on the current source
KillMz(),
StartMz(self, tag=None),
Validate(self),
]
class UpgradeEntireMzFourVersions(Scenario):
"""Test upgrade X-4 -> X-3 -> X-2 -> X-1 -> X"""
def __init__(
self, checks: list[type[Check]], executor: Executor, seed: str | None = None
):
self.minor_versions = get_minor_versions()
super().__init__(checks, executor, seed)
def base_version(self) -> MzVersion:
return self.minor_versions[3]
def actions(self) -> list[Action]:
print(
f"Upgrade path: {self.minor_versions[3]} -> {self.minor_versions[2]} -> {get_previous_version()} -> {get_last_version()} -> current"
)
return [
StartMz(self, tag=self.minor_versions[3]),
Initialize(self),
KillMz(capture_logs=True),
StartMz(self, tag=self.minor_versions[2]),
Manipulate(self, phase=1),
KillMz(capture_logs=True),
StartMz(self, tag=get_previous_version()),
Manipulate(self, phase=2),
KillMz(capture_logs=True),
StartMz(self, tag=get_last_version()),
KillMz(capture_logs=True),
StartMz(self, tag=None),
Validate(self),
KillMz(),
StartMz(self, tag=None),
Validate(self),
]
#
# We are limited with respect to the different orders in which stuff can be upgraded:
# - some sequences of events are invalid
# - environmentd and storage clusterds are located in the same container
#
# Still, we would like to try as many scenarios as we can
#
class UpgradeClusterdComputeLast(Scenario):
"""Upgrade compute's clusterd separately after upgrading environmentd"""
def base_version(self) -> MzVersion:
return get_last_version()
def actions(self) -> list[Action]:
return [
StartMz(self, tag=self.base_version()),
StartClusterdCompute(tag=self.base_version()),
UseClusterdCompute(self),
Initialize(self),
Manipulate(self, phase=1),
KillMz(capture_logs=True),
StartMz(self, tag=None),
# No useful work can be done while clusterd is old-version
# and environmentd is new-version. So we proceed
# to upgrade clusterd as well.
# We sleep here to allow some period of coexistence, even
# though we are not issuing queries during that time.
Sleep(10),
KillClusterdCompute(capture_logs=True),
StartClusterdCompute(tag=None),
Manipulate(self, phase=2),
Validate(self),
# A second restart while already on the new version
KillMz(),
StartMz(self, tag=None),
Validate(self),
]
class UpgradeClusterdComputeFirst(Scenario):
"""Upgrade compute's clusterd separately before environmentd"""
def base_version(self) -> MzVersion:
return get_last_version()
def actions(self) -> list[Action]:
return [
StartMz(self, tag=self.base_version()),
StartClusterdCompute(tag=self.base_version()),
UseClusterdCompute(self),
Initialize(self),
Manipulate(self, phase=1),
KillClusterdCompute(capture_logs=True),
StartClusterdCompute(tag=None),
# No useful work can be done while clusterd is new-version
# and environmentd is old-version. So we
# proceed to upgrade them as well.
# We sleep here to allow some period of coexistence, even
# though we are not issuing queries during that time.
Sleep(10),
KillMz(),
StartMz(self, tag=None),
Manipulate(self, phase=2),
Validate(self),
KillMz(),
StartMz(self, tag=None),
Validate(self),
]
class PreflightCheckContinue(Scenario):
"""Preflight check, then upgrade"""
def base_version(self) -> MzVersion:
return get_last_version()
def _include_check_class(self, check_class: type[Check]) -> bool:
if not super()._include_check_class(check_class):
return False
if (
check_class == StatementLogging
and self.base_version() == MzVersion.parse_mz("v0.89.2")
):
# mz_version column was added to mz_statement_execution_history, history will be lost when a new column is added to the objects
return False
return True
def actions(self) -> list[Action]:
print(f"Upgrading from tag {self.base_version()}")
return [
StartMz(self, tag=self.base_version()),
Initialize(self),
Manipulate(self, phase=1),
KillMz(
capture_logs=True
), # We always use True here otherwise docker-compose will lose the pre-upgrade logs
StartMz(
self,
tag=None,
environment_extra=["MZ_DEPLOY_GENERATION=1"],
healthcheck=[
"CMD",
"curl",
"-f",
"localhost:6878/api/leader/status",
],
),
WaitReadyMz(),
PromoteMz(),
Manipulate(self, phase=2),
Validate(self),
# A second restart while already on the new version
KillMz(),
StartMz(self, tag=None),
Validate(self),
]
class PreflightCheckRollback(Scenario):
"""Preflight check, then roll back"""
def base_version(self) -> MzVersion:
return get_last_version()
def actions(self) -> list[Action]:
print(f"Upgrading from tag {self.base_version()}")
return [
StartMz(self, tag=self.base_version()),
Initialize(self),
Manipulate(self, phase=1),
KillMz(
capture_logs=True
), # We always use True here otherwise docker-compose will lose the pre-upgrade logs
StartMz(
self,
tag=None,
environment_extra=["MZ_DEPLOY_GENERATION=1"],
healthcheck=[
"CMD",
"curl",
"-f",
"localhost:6878/api/leader/status",
],
),
WaitReadyMz(),
KillMz(capture_logs=True),
StartMz(self, tag=self.base_version()),
Manipulate(self, phase=2),
Validate(self),
# A second restart while still on old version
KillMz(capture_logs=True),
StartMz(
self,
tag=self.base_version(),
),
Validate(self),
]
Functions
def get_last_version() ‑> MzVersion
-
Expand source code Browse git
def get_last_version() -> MzVersion: global _last_version if _last_version is None: _last_version = get_minor_versions()[0] return _last_version
def get_minor_versions() ‑> list[MzVersion]
-
Expand source code Browse git
def get_minor_versions() -> list[MzVersion]: global _minor_versions if _minor_versions is None: _minor_versions = get_published_minor_mz_versions( limit=4, exclude_current_minor_version=True ) return _minor_versions
def get_previous_version() ‑> MzVersion
-
Expand source code Browse git
def get_previous_version() -> MzVersion: global _previous_version if _previous_version is None: _previous_version = get_minor_versions()[1] return _previous_version
Classes
class PreflightCheckContinue (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Preflight check, then upgrade
Expand source code Browse git
class PreflightCheckContinue(Scenario): """Preflight check, then upgrade""" def base_version(self) -> MzVersion: return get_last_version() def _include_check_class(self, check_class: type[Check]) -> bool: if not super()._include_check_class(check_class): return False if ( check_class == StatementLogging and self.base_version() == MzVersion.parse_mz("v0.89.2") ): # mz_version column was added to mz_statement_execution_history, history will be lost when a new column is added to the objects return False return True def actions(self) -> list[Action]: print(f"Upgrading from tag {self.base_version()}") return [ StartMz(self, tag=self.base_version()), Initialize(self), Manipulate(self, phase=1), KillMz( capture_logs=True ), # We always use True here otherwise docker-compose will lose the pre-upgrade logs StartMz( self, tag=None, environment_extra=["MZ_DEPLOY_GENERATION=1"], healthcheck=[ "CMD", "curl", "-f", "localhost:6878/api/leader/status", ], ), WaitReadyMz(), PromoteMz(), Manipulate(self, phase=2), Validate(self), # A second restart while already on the new version KillMz(), StartMz(self, tag=None), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: print(f"Upgrading from tag {self.base_version()}") return [ StartMz(self, tag=self.base_version()), Initialize(self), Manipulate(self, phase=1), KillMz( capture_logs=True ), # We always use True here otherwise docker-compose will lose the pre-upgrade logs StartMz( self, tag=None, environment_extra=["MZ_DEPLOY_GENERATION=1"], healthcheck=[ "CMD", "curl", "-f", "localhost:6878/api/leader/status", ], ), WaitReadyMz(), PromoteMz(), Manipulate(self, phase=2), Validate(self), # A second restart while already on the new version KillMz(), StartMz(self, tag=None), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return get_last_version()
class PreflightCheckRollback (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Preflight check, then roll back
Expand source code Browse git
class PreflightCheckRollback(Scenario): """Preflight check, then roll back""" def base_version(self) -> MzVersion: return get_last_version() def actions(self) -> list[Action]: print(f"Upgrading from tag {self.base_version()}") return [ StartMz(self, tag=self.base_version()), Initialize(self), Manipulate(self, phase=1), KillMz( capture_logs=True ), # We always use True here otherwise docker-compose will lose the pre-upgrade logs StartMz( self, tag=None, environment_extra=["MZ_DEPLOY_GENERATION=1"], healthcheck=[ "CMD", "curl", "-f", "localhost:6878/api/leader/status", ], ), WaitReadyMz(), KillMz(capture_logs=True), StartMz(self, tag=self.base_version()), Manipulate(self, phase=2), Validate(self), # A second restart while still on old version KillMz(capture_logs=True), StartMz( self, tag=self.base_version(), ), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: print(f"Upgrading from tag {self.base_version()}") return [ StartMz(self, tag=self.base_version()), Initialize(self), Manipulate(self, phase=1), KillMz( capture_logs=True ), # We always use True here otherwise docker-compose will lose the pre-upgrade logs StartMz( self, tag=None, environment_extra=["MZ_DEPLOY_GENERATION=1"], healthcheck=[ "CMD", "curl", "-f", "localhost:6878/api/leader/status", ], ), WaitReadyMz(), KillMz(capture_logs=True), StartMz(self, tag=self.base_version()), Manipulate(self, phase=2), Validate(self), # A second restart while still on old version KillMz(capture_logs=True), StartMz( self, tag=self.base_version(), ), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return get_last_version()
class UpgradeClusterdComputeFirst (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Upgrade compute's clusterd separately before environmentd
Expand source code Browse git
class UpgradeClusterdComputeFirst(Scenario): """Upgrade compute's clusterd separately before environmentd""" def base_version(self) -> MzVersion: return get_last_version() def actions(self) -> list[Action]: return [ StartMz(self, tag=self.base_version()), StartClusterdCompute(tag=self.base_version()), UseClusterdCompute(self), Initialize(self), Manipulate(self, phase=1), KillClusterdCompute(capture_logs=True), StartClusterdCompute(tag=None), # No useful work can be done while clusterd is new-version # and environmentd is old-version. So we # proceed to upgrade them as well. # We sleep here to allow some period of coexistence, even # though we are not issuing queries during that time. Sleep(10), KillMz(), StartMz(self, tag=None), Manipulate(self, phase=2), Validate(self), KillMz(), StartMz(self, tag=None), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: return [ StartMz(self, tag=self.base_version()), StartClusterdCompute(tag=self.base_version()), UseClusterdCompute(self), Initialize(self), Manipulate(self, phase=1), KillClusterdCompute(capture_logs=True), StartClusterdCompute(tag=None), # No useful work can be done while clusterd is new-version # and environmentd is old-version. So we # proceed to upgrade them as well. # We sleep here to allow some period of coexistence, even # though we are not issuing queries during that time. Sleep(10), KillMz(), StartMz(self, tag=None), Manipulate(self, phase=2), Validate(self), KillMz(), StartMz(self, tag=None), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return get_last_version()
class UpgradeClusterdComputeLast (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Upgrade compute's clusterd separately after upgrading environmentd
Expand source code Browse git
class UpgradeClusterdComputeLast(Scenario): """Upgrade compute's clusterd separately after upgrading environmentd""" def base_version(self) -> MzVersion: return get_last_version() def actions(self) -> list[Action]: return [ StartMz(self, tag=self.base_version()), StartClusterdCompute(tag=self.base_version()), UseClusterdCompute(self), Initialize(self), Manipulate(self, phase=1), KillMz(capture_logs=True), StartMz(self, tag=None), # No useful work can be done while clusterd is old-version # and environmentd is new-version. So we proceed # to upgrade clusterd as well. # We sleep here to allow some period of coexistence, even # though we are not issuing queries during that time. Sleep(10), KillClusterdCompute(capture_logs=True), StartClusterdCompute(tag=None), Manipulate(self, phase=2), Validate(self), # A second restart while already on the new version KillMz(), StartMz(self, tag=None), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: return [ StartMz(self, tag=self.base_version()), StartClusterdCompute(tag=self.base_version()), UseClusterdCompute(self), Initialize(self), Manipulate(self, phase=1), KillMz(capture_logs=True), StartMz(self, tag=None), # No useful work can be done while clusterd is old-version # and environmentd is new-version. So we proceed # to upgrade clusterd as well. # We sleep here to allow some period of coexistence, even # though we are not issuing queries during that time. Sleep(10), KillClusterdCompute(capture_logs=True), StartClusterdCompute(tag=None), Manipulate(self, phase=2), Validate(self), # A second restart while already on the new version KillMz(), StartMz(self, tag=None), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return get_last_version()
class UpgradeEntireMz (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Upgrade the entire Mz instance from the last released version.
Expand source code Browse git
class UpgradeEntireMz(Scenario): """Upgrade the entire Mz instance from the last released version.""" def base_version(self) -> MzVersion: return get_last_version() def actions(self) -> list[Action]: print(f"Upgrading from tag {self.base_version()}") return [ StartMz(self, tag=self.base_version()), Initialize(self), Manipulate(self, phase=1), KillMz( capture_logs=True ), # We always use True here otherwise docker-compose will lose the pre-upgrade logs StartMz(self, tag=None), Manipulate(self, phase=2), Validate(self), # A second restart while already on the new version KillMz(capture_logs=True), StartMz(self, tag=None), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: print(f"Upgrading from tag {self.base_version()}") return [ StartMz(self, tag=self.base_version()), Initialize(self), Manipulate(self, phase=1), KillMz( capture_logs=True ), # We always use True here otherwise docker-compose will lose the pre-upgrade logs StartMz(self, tag=None), Manipulate(self, phase=2), Validate(self), # A second restart while already on the new version KillMz(capture_logs=True), StartMz(self, tag=None), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return get_last_version()
class UpgradeEntireMzFourVersions (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Test upgrade X-4 -> X-3 -> X-2 -> X-1 -> X
Expand source code Browse git
class UpgradeEntireMzFourVersions(Scenario): """Test upgrade X-4 -> X-3 -> X-2 -> X-1 -> X""" def __init__( self, checks: list[type[Check]], executor: Executor, seed: str | None = None ): self.minor_versions = get_minor_versions() super().__init__(checks, executor, seed) def base_version(self) -> MzVersion: return self.minor_versions[3] def actions(self) -> list[Action]: print( f"Upgrade path: {self.minor_versions[3]} -> {self.minor_versions[2]} -> {get_previous_version()} -> {get_last_version()} -> current" ) return [ StartMz(self, tag=self.minor_versions[3]), Initialize(self), KillMz(capture_logs=True), StartMz(self, tag=self.minor_versions[2]), Manipulate(self, phase=1), KillMz(capture_logs=True), StartMz(self, tag=get_previous_version()), Manipulate(self, phase=2), KillMz(capture_logs=True), StartMz(self, tag=get_last_version()), KillMz(capture_logs=True), StartMz(self, tag=None), Validate(self), KillMz(), StartMz(self, tag=None), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: print( f"Upgrade path: {self.minor_versions[3]} -> {self.minor_versions[2]} -> {get_previous_version()} -> {get_last_version()} -> current" ) return [ StartMz(self, tag=self.minor_versions[3]), Initialize(self), KillMz(capture_logs=True), StartMz(self, tag=self.minor_versions[2]), Manipulate(self, phase=1), KillMz(capture_logs=True), StartMz(self, tag=get_previous_version()), Manipulate(self, phase=2), KillMz(capture_logs=True), StartMz(self, tag=get_last_version()), KillMz(capture_logs=True), StartMz(self, tag=None), Validate(self), KillMz(), StartMz(self, tag=None), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return self.minor_versions[3]
class UpgradeEntireMzTwoVersions (checks: list[type[Check]], executor: Executor, seed: str | None = None)
-
Upgrade the entire Mz instance starting from the previous released version and passing through the last released version.
Expand source code Browse git
class UpgradeEntireMzTwoVersions(Scenario): """Upgrade the entire Mz instance starting from the previous released version and passing through the last released version.""" def base_version(self) -> MzVersion: return get_previous_version() def actions(self) -> list[Action]: print(f"Upgrade path: {self.base_version()} -> {get_last_version()} -> current") return [ # Start with previous_version StartMz(self, tag=self.base_version()), Initialize(self), # Upgrade to last_version KillMz(capture_logs=True), StartMz(self, tag=get_last_version()), Manipulate(self, phase=1), # Upgrade to current source KillMz(capture_logs=True), StartMz(self, tag=None), Manipulate(self, phase=2), Validate(self), # A second restart while already on the current source KillMz(), StartMz(self, tag=None), Validate(self), ]
Ancestors
Methods
def actions(self) ‑> list[Action]
-
Expand source code Browse git
def actions(self) -> list[Action]: print(f"Upgrade path: {self.base_version()} -> {get_last_version()} -> current") return [ # Start with previous_version StartMz(self, tag=self.base_version()), Initialize(self), # Upgrade to last_version KillMz(capture_logs=True), StartMz(self, tag=get_last_version()), Manipulate(self, phase=1), # Upgrade to current source KillMz(capture_logs=True), StartMz(self, tag=None), Manipulate(self, phase=2), Validate(self), # A second restart while already on the current source KillMz(), StartMz(self, tag=None), Validate(self), ]
def base_version(self) ‑> MzVersion
-
Expand source code Browse git
def base_version(self) -> MzVersion: return get_previous_version()