Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions release-controller/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@ py_binary(
deps = ["release_notes_composer", "commit_annotation_recreator"],
)

py_binary(
name = "dry-run",
main = "dryrun.py",
srcs = ["dryrun.py"],
env = env,
deps = ["dre_cli", "git_repo", "google_docs", "release_notes_composer", "release_index", "forum"],
)

genrule(
name = "ic_repo_clone",
outs = ["ic.git.tar"],
Expand Down
30 changes: 27 additions & 3 deletions release-controller/dre_cli.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import json
import sys
import logging
import subprocess
import typing
from util import resolve_binary
import os
from pathlib import Path
import tempfile

from const import OsKind, HOSTOS
from const import OsKind, HOSTOS, GUESTOS


class Auth(typing.TypedDict):
Expand Down Expand Up @@ -178,6 +181,7 @@ def propose_to_revise_elected_os_versions(
unelect_versions: list[str],
package_checksum: str,
package_urls: list[str],
launch_measurements: typing.Optional[bytes],
dry_run: bool = False,
) -> int:
x = "hostos" if os_kind == HOSTOS else "guestos"
Expand All @@ -187,8 +191,7 @@ def propose_to_revise_elected_os_versions(
if len(unelect_versions) > 0
else []
)
self._logger.info("Submitting proposal for version %s", version)
text = self._run(
args = [
"propose",
*_mode_flags(dry_run),
"--proposal-url",
Expand All @@ -205,7 +208,27 @@ def propose_to_revise_elected_os_versions(
f"--{y}-version-to-elect",
version,
*unelect_versions_args,
]

temp_measurements = tempfile.NamedTemporaryFile()

# TODO: generalize when the HOSTOS launch measurements are
# supported in the ic-admin.
if os_kind == GUESTOS:
if launch_measurements is None:
raise ValueError("Guest launch measurements missing. Cannot proceed.")

temp_measurements.write(launch_measurements)
temp_measurements.flush()

args.extend(["--guest-launch-measurements-path", temp_measurements.name])

self._logger.info(
"Submitting proposal for version %s using args: %s",
version,
" ".join(args),
)
text = self._run(*args)
if not dry_run:
try:
return int(text.rstrip().splitlines()[-1].split()[1])
Expand All @@ -217,6 +240,7 @@ def propose_to_revise_elected_os_versions(
else:
# We will not parse the text here. We dry-ran the thing, after all,
# so there will be no proposal ID to parse.
print(text, file=sys.stderr)
return 0


Expand Down
16 changes: 16 additions & 0 deletions release-controller/dryrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def propose_to_revise_elected_os_versions(
unelect_versions: list[str],
package_checksum: str,
package_urls: list[str],
launch_measurements: typing.Optional[bytes],
dry_run: bool = False,
) -> int:
super().propose_to_revise_elected_os_versions(
Expand All @@ -260,6 +261,7 @@ def propose_to_revise_elected_os_versions(
unelect_versions,
package_checksum,
package_urls,
launch_measurements,
dry_run=True,
)
# Now mock the proposal ID using an integer derived from the version.
Expand All @@ -285,6 +287,19 @@ def announce_release(
def oneoff_dre_place_proposal() -> None:
changelog = "Fake changelog"
dre = DRECli()
measurements = {
"guest_launch_measurements": [
{
"measurement": list(os.urandom(48)),
"metadata": {
"kernel_cmdline": "some command line that is linked to this measaurement",
},
}
]
}

measurementbytes = json.dumps(measurements).encode()

dre.propose_to_revise_elected_os_versions(
changelog=changelog,
version="0" * 40,
Expand All @@ -293,6 +308,7 @@ def oneoff_dre_place_proposal() -> None:
unelect_versions=[],
package_checksum="0" * 40,
package_urls=["https://doesntmatter.com/"],
launch_measurements=measurementbytes,
)


Expand Down
33 changes: 33 additions & 0 deletions release-controller/reconciler.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,17 @@ def version_package_urls(version: str, os_kind: OsKind) -> list[str]:
]


def version_launch_measurements(version: str, os_kind: OsKind) -> str:
if os_kind is not GUESTOS:
raise ValueError("Host OS launch measurements still not supported.")

v = "guest-os"

# TODO: should have some rotation between dfinity.systems and dfinity.network
# in case one or the other isn't reachable.
return f"https://download.dfinity.systems/ic/{version}/{v}/update-img/launch-measurements.json"


def version_package_checksum(version: str, os_kind: OsKind) -> str:
v = "host-os" if os_kind == HOSTOS else "guest-os"
hashurl = f"https://download.dfinity.systems/ic/{version}/{v}/update-img/SHA256SUMS"
Expand Down Expand Up @@ -218,6 +229,18 @@ def version_package_checksum(version: str, os_kind: OsKind) -> str:
return checksum


def fetch_launch_measurements(version: str, os_kind: OsKind) -> bytes:
url = version_launch_measurements(version, os_kind)

logger = LOGGER.getChild("fetch_launch_measurements")
logger.debug("fetching launch measurements from %s", url)

response = requests.get(url, timeout=10)
response.raise_for_status()

return response.content


class ActiveVersionProvider(typing.Protocol):
def active_guestos_versions(self) -> list[str]: ...
def active_hostos_versions(self) -> list[str]: ...
Expand Down Expand Up @@ -698,6 +721,11 @@ def reconcile(self) -> None:
revlogger.info(
"Currently elected GuestOS versions: %s", blessed
)

measurements = fetch_launch_measurements(
release_commit, v.os_kind
)

elif v.os_kind == HOSTOS:
active = list(
# Use the versions of HostOS registered as active on nodes
Expand All @@ -720,6 +748,9 @@ def reconcile(self) -> None:
revlogger.info(
"Currently elected HostOS versions: %s", blessed
)
# TODO: support this once the HOSTOS launch measurements
# are added to ic-admin.
launch_measurements = None

unelect_versions.extend(
versions_to_unelect(
Expand All @@ -742,6 +773,7 @@ def reconcile(self) -> None:
unelect_versions=unelect_versions,
package_checksum=checksum,
package_urls=urls,
launch_measurements=measurements,
)
success = prop.record_submission(proposal_id)
revlogger.info("%s", success)
Expand Down Expand Up @@ -989,6 +1021,7 @@ def oneoff() -> None:
unelect_versions=[],
package_checksum=version_package_checksum(version, GUESTOS),
package_urls=version_package_urls(version, GUESTOS),
launch_measurements=None,
)


Expand Down
Loading