LTS compatibility test latest tweaks (#2693)

This commit is contained in:
Julien Maffre 2021-06-18 16:02:54 +01:00 коммит произвёл GitHub
Родитель ab7d8c0728
Коммит 1ae488dea6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 138 добавлений и 90 удалений

Просмотреть файл

@ -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)}")