зеркало из https://github.com/microsoft/CCF.git
LTS compatibility test latest tweaks (#2693)
This commit is contained in:
Родитель
ab7d8c0728
Коммит
1ae488dea6
|
@ -45,14 +45,9 @@ def is_main_branch(branch_name):
|
|||
return branch_name == MAIN_BRANCH_NAME
|
||||
|
||||
|
||||
def strip_branch_name_suffix(branch_name):
|
||||
return branch_name.split("_")[0]
|
||||
|
||||
|
||||
def strip_release_branch_name(branch_name):
|
||||
assert is_release_branch(branch_name), branch_name
|
||||
# Also discard "_suffix" if there is one
|
||||
return strip_branch_name_suffix(branch_name[len(BRANCH_RELEASE_PREFIX) :])
|
||||
return branch_name[len(BRANCH_RELEASE_PREFIX) :]
|
||||
|
||||
|
||||
def get_major_version_from_release_branch_name(full_branch_name):
|
||||
|
@ -64,6 +59,21 @@ def get_version_from_tag_name(tag_name):
|
|||
return Version(tag_name[len(TAG_RELEASE_PREFIX) :])
|
||||
|
||||
|
||||
def get_release_branch_from_branch_name(branch_name):
|
||||
# E.g. returns "release/1.x" for "release/1.0.4" or "release/1.x_test"
|
||||
assert is_release_branch(branch_name), branch_name
|
||||
return branch_name.split(".")[0] + ".x"
|
||||
|
||||
|
||||
def get_major_version_from_branch_name(branch_name):
|
||||
# Returns major version number from branch name, or None if the branch isn't a release branch
|
||||
return (
|
||||
get_major_version_from_release_branch_name(branch_name)
|
||||
if is_release_branch(branch_name)
|
||||
else None
|
||||
)
|
||||
|
||||
|
||||
class Repository:
|
||||
"""
|
||||
Helper class to verify CCF operations compatibility described at
|
||||
|
@ -101,13 +111,19 @@ class Repository:
|
|||
def get_next_release_branch(self, release_branch_name):
|
||||
release_branches = self.get_release_branches_names()
|
||||
assert (
|
||||
strip_branch_name_suffix(release_branch_name) in release_branches
|
||||
release_branch_name in release_branches
|
||||
), f"{release_branch_name} branch is not a valid release branch"
|
||||
after_index = release_branches.index(release_branch_name) + 1
|
||||
if after_index >= len(release_branches):
|
||||
raise ValueError(f"No release branch after {release_branch_name}")
|
||||
return release_branches[after_index]
|
||||
|
||||
def get_tags_with_releases(self):
|
||||
# Only consider tags that have releases as perhaps a release is in progress
|
||||
# (i.e. tag exists but hasn't got a release just yet)
|
||||
all_released_tags = [r.tag_name for r in self.repo.get_releases()]
|
||||
return [t for t in self.repo.get_tags() if t.name in all_released_tags]
|
||||
|
||||
def get_release_for_tag(self, tag):
|
||||
releases = [r for r in self.repo.get_releases() if r.tag_name == tag.name]
|
||||
if not releases:
|
||||
|
@ -127,7 +143,11 @@ class Repository:
|
|||
TAG_RELEASE_PREFIX, release_branch_name.replace(".x", "([.\\d+]+)")
|
||||
)
|
||||
return sorted(
|
||||
[tag for tag in self.repo.get_tags() if re.match(release_re, tag.name)],
|
||||
[
|
||||
tag
|
||||
for tag in self.get_tags_with_releases()
|
||||
if re.match(release_re, tag.name)
|
||||
],
|
||||
key=cmp_to_key(
|
||||
lambda t1, t2: get_version_from_tag_name(t1.name)
|
||||
< get_version_from_tag_name(t2.name)
|
||||
|
@ -187,7 +207,9 @@ class Repository:
|
|||
"""
|
||||
if is_release_branch(branch):
|
||||
LOG.debug(f"{branch} is release branch")
|
||||
tags = self.get_tags_for_release_branch(branch)
|
||||
tags = self.get_tags_for_release_branch(
|
||||
get_release_branch_from_branch_name(branch)
|
||||
)
|
||||
if tags:
|
||||
return tags[0]
|
||||
else:
|
||||
|
@ -211,7 +233,9 @@ class Repository:
|
|||
if is_release_branch(branch):
|
||||
LOG.debug(f"{branch} is release branch")
|
||||
try:
|
||||
next_release_branch = self.get_next_release_branch(branch)
|
||||
next_release_branch = self.get_next_release_branch(
|
||||
get_release_branch_from_branch_name(branch)
|
||||
)
|
||||
LOG.debug(f"{next_release_branch} is next release branch")
|
||||
return self.get_tags_for_release_branch(next_release_branch)[-1]
|
||||
except ValueError as e: # No release branch after target branch
|
||||
|
|
|
@ -212,14 +212,18 @@ def run_live_compatibility_with_latest(args, repo, local_branch):
|
|||
lts_version, lts_install_path = repo.install_latest_lts_for_branch(
|
||||
os.getenv(ENV_VAR_LATEST_LTS_BRANCH_NAME, local_branch)
|
||||
)
|
||||
LOG.info(f'From LTS {lts_version} to local "{local_branch}" branch')
|
||||
run_code_upgrade_from(
|
||||
args,
|
||||
from_install_path=lts_install_path,
|
||||
to_install_path=LOCAL_CHECKOUT_DIRECTORY,
|
||||
from_major_version=Version(lts_version).release[0],
|
||||
to_major_version=None,
|
||||
local_major_version = infra.github.get_major_version_from_branch_name(local_branch)
|
||||
LOG.info(
|
||||
f'From LTS {lts_version} to local "{local_branch}" branch (version: {local_major_version})'
|
||||
)
|
||||
if not args.dry_run:
|
||||
run_code_upgrade_from(
|
||||
args,
|
||||
from_install_path=lts_install_path,
|
||||
to_install_path=LOCAL_CHECKOUT_DIRECTORY,
|
||||
from_major_version=Version(lts_version).release[0],
|
||||
to_major_version=local_major_version,
|
||||
)
|
||||
return lts_version
|
||||
|
||||
|
||||
|
@ -234,19 +238,23 @@ def run_live_compatibility_with_following(args, repo, local_branch):
|
|||
LOG.warning(f"No next LTS for local {local_branch} branch")
|
||||
return None
|
||||
|
||||
LOG.info(f'From local "{local_branch}" branch to LTS {lts_version}')
|
||||
run_code_upgrade_from(
|
||||
args,
|
||||
from_install_path=LOCAL_CHECKOUT_DIRECTORY,
|
||||
to_install_path=lts_install_path,
|
||||
from_major_version=None,
|
||||
to_major_version=Version(lts_version).release[0],
|
||||
local_major_version = infra.github.get_major_version_from_branch_name(local_branch)
|
||||
LOG.info(
|
||||
f'From local "{local_branch}" branch (version: {local_major_version}) to LTS {lts_version}'
|
||||
)
|
||||
if not args.dry_run:
|
||||
run_code_upgrade_from(
|
||||
args,
|
||||
from_install_path=LOCAL_CHECKOUT_DIRECTORY,
|
||||
to_install_path=lts_install_path,
|
||||
from_major_version=local_major_version,
|
||||
to_major_version=Version(lts_version).release[0],
|
||||
)
|
||||
return lts_version
|
||||
|
||||
|
||||
@reqs.description("Run ledger compatibility since first LTS")
|
||||
def run_ledger_compatibility_since_first(args, use_snapshot):
|
||||
def run_ledger_compatibility_since_first(args, local_branch, use_snapshot):
|
||||
"""
|
||||
Tests that a service from the very first LTS can be recovered
|
||||
to the next LTS, and so forth, until the version of the local checkout.
|
||||
|
@ -283,69 +291,74 @@ def run_ledger_compatibility_since_first(args, use_snapshot):
|
|||
version = args.ccf_version
|
||||
binary_dir = LOCAL_CHECKOUT_DIRECTORY
|
||||
library_dir = LOCAL_CHECKOUT_DIRECTORY
|
||||
major_version = None
|
||||
|
||||
network_args = {
|
||||
"hosts": args.nodes,
|
||||
"binary_dir": binary_dir,
|
||||
"library_dir": library_dir,
|
||||
"txs": txs,
|
||||
"jwt_issuer": jwt_issuer,
|
||||
"version": major_version,
|
||||
}
|
||||
if idx == 0:
|
||||
LOG.info(f"Starting new service (version: {version})")
|
||||
network = infra.network.Network(**network_args)
|
||||
network.start_and_join(args)
|
||||
else:
|
||||
LOG.info(f"Recovering service (new version: {version})")
|
||||
network = infra.network.Network(
|
||||
**network_args, existing_network=network
|
||||
major_version = infra.github.get_major_version_from_branch_name(
|
||||
local_branch
|
||||
)
|
||||
network.start_in_recovery(
|
||||
args,
|
||||
ledger_dir,
|
||||
committed_ledger_dir,
|
||||
snapshot_dir=snapshot_dir,
|
||||
|
||||
if not args.dry_run:
|
||||
network_args = {
|
||||
"hosts": args.nodes,
|
||||
"binary_dir": binary_dir,
|
||||
"library_dir": library_dir,
|
||||
"txs": txs,
|
||||
"jwt_issuer": jwt_issuer,
|
||||
"version": major_version,
|
||||
}
|
||||
if idx == 0:
|
||||
LOG.info(f"Starting new service (version: {version})")
|
||||
network = infra.network.Network(**network_args)
|
||||
network.start_and_join(args)
|
||||
else:
|
||||
LOG.info(f"Recovering service (new version: {version})")
|
||||
network = infra.network.Network(
|
||||
**network_args, existing_network=network
|
||||
)
|
||||
network.start_in_recovery(
|
||||
args,
|
||||
ledger_dir,
|
||||
committed_ledger_dir,
|
||||
snapshot_dir=snapshot_dir,
|
||||
)
|
||||
network.recover(args)
|
||||
|
||||
nodes = network.get_joined_nodes()
|
||||
primary, _ = network.find_primary()
|
||||
|
||||
# Verify that all nodes run the expected CCF version
|
||||
for node in nodes:
|
||||
# Note: /node/version endpoint was added in 2.x
|
||||
if not node.version or node.version > 1:
|
||||
with node.client() as c:
|
||||
r = c.get("/node/version")
|
||||
expected_version = node.version or args.ccf_version
|
||||
version = r.body.json()["ccf_version"]
|
||||
assert (
|
||||
r.body.json()["ccf_version"] == expected_version
|
||||
), f"Node version is not {expected_version}"
|
||||
|
||||
# Rollover JWKS so that new primary must read historical CA bundle table
|
||||
# and retrieve new keys via auto refresh
|
||||
jwt_issuer.refresh_keys()
|
||||
jwt_issuer.wait_for_refresh(network)
|
||||
|
||||
issue_activity_on_live_service(network, args)
|
||||
|
||||
snapshot_dir = (
|
||||
network.get_committed_snapshots(primary) if use_snapshot else None
|
||||
)
|
||||
network.recover(args)
|
||||
ledger_dir, committed_ledger_dir = primary.get_ledger(
|
||||
include_read_only_dirs=True
|
||||
)
|
||||
network.stop_all_nodes(verbose_verification=False)
|
||||
|
||||
nodes = network.get_joined_nodes()
|
||||
primary, _ = network.find_primary()
|
||||
|
||||
# Verify that all nodes run the expected CCF version
|
||||
for node in nodes:
|
||||
# Note: /node/version endpoint was added in 2.x
|
||||
if not node.version or node.version > 1:
|
||||
with node.client() as c:
|
||||
r = c.get("/node/version")
|
||||
expected_version = node.version or args.ccf_version
|
||||
version = r.body.json()["ccf_version"]
|
||||
assert (
|
||||
r.body.json()["ccf_version"] == expected_version
|
||||
), f"Node version is not {expected_version}"
|
||||
|
||||
# Rollover JWKS so that new primary must read historical CA bundle table
|
||||
# and retrieve new keys via auto refresh
|
||||
jwt_issuer.refresh_keys()
|
||||
jwt_issuer.wait_for_refresh(network)
|
||||
|
||||
issue_activity_on_live_service(network, args)
|
||||
|
||||
snapshot_dir = (
|
||||
network.get_committed_snapshots(primary) if use_snapshot else None
|
||||
)
|
||||
ledger_dir, committed_ledger_dir = primary.get_ledger(
|
||||
include_read_only_dirs=True
|
||||
)
|
||||
network.stop_all_nodes(verbose_verification=False)
|
||||
|
||||
# Check that ledger and snapshots can be parsed
|
||||
ccf.ledger.Ledger([committed_ledger_dir]).get_latest_public_state()
|
||||
if snapshot_dir:
|
||||
for s in os.listdir(snapshot_dir):
|
||||
with ccf.ledger.Snapshot(os.path.join(snapshot_dir, s)) as snapshot:
|
||||
snapshot.get_public_domain()
|
||||
# Check that ledger and snapshots can be parsed
|
||||
ccf.ledger.Ledger([committed_ledger_dir]).get_latest_public_state()
|
||||
if snapshot_dir:
|
||||
for s in os.listdir(snapshot_dir):
|
||||
with ccf.ledger.Snapshot(
|
||||
os.path.join(snapshot_dir, s)
|
||||
) as snapshot:
|
||||
snapshot.get_public_domain()
|
||||
|
||||
return lts_versions
|
||||
|
||||
|
@ -357,6 +370,7 @@ if __name__ == "__main__":
|
|||
parser.add_argument(
|
||||
"--compatibility-report-file", type=str, default="compatibility_report.json"
|
||||
)
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
|
||||
args = infra.e2e_args.cli_args(add)
|
||||
|
||||
|
@ -373,6 +387,9 @@ if __name__ == "__main__":
|
|||
# current branch on any environment (either local checkout or CI run)
|
||||
env = cimetrics.env.get_env()
|
||||
|
||||
if args.dry_run:
|
||||
LOG.warning("Dry run: no compatibility check")
|
||||
|
||||
compatibility_report = {}
|
||||
compatibility_report["version"] = args.ccf_version
|
||||
compatibility_report["live compatibility"] = {}
|
||||
|
@ -389,17 +406,24 @@ if __name__ == "__main__":
|
|||
|
||||
if args.check_ledger_compatibility:
|
||||
compatibility_report["data compatibility"] = {}
|
||||
lts_versions = run_ledger_compatibility_since_first(args, use_snapshot=False)
|
||||
lts_versions = run_ledger_compatibility_since_first(
|
||||
args, env.branch, use_snapshot=False
|
||||
)
|
||||
compatibility_report["data compatibility"].update(
|
||||
{"with previous ledger": lts_versions}
|
||||
)
|
||||
lts_versions = run_ledger_compatibility_since_first(args, use_snapshot=True)
|
||||
lts_versions = run_ledger_compatibility_since_first(
|
||||
args, env.branch, use_snapshot=True
|
||||
)
|
||||
compatibility_report["data compatibility"].update(
|
||||
{"with previous snapshots": lts_versions}
|
||||
)
|
||||
|
||||
with open(args.compatibility_report_file, "w") as f:
|
||||
json.dump(compatibility_report, f, indent=2)
|
||||
LOG.info(f"Compatibility report written to {args.compatibility_report_file}")
|
||||
if not args.dry_run:
|
||||
with open(args.compatibility_report_file, "w") as f:
|
||||
json.dump(compatibility_report, f, indent=2)
|
||||
LOG.info(
|
||||
f"Compatibility report written to {args.compatibility_report_file}"
|
||||
)
|
||||
|
||||
LOG.success(f"Compatibility report:\n {json.dumps(compatibility_report, indent=2)}")
|
||||
|
|
Загрузка…
Ссылка в новой задаче