-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug 1889223 - Submit all files to notarization before polling #957
Conversation
d7c01e7
to
b3dc1be
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This overall logic here is fine, but I'd really prefer to see some cleanup happen that avoids the need for having completely separate paths in script.py
for the stacked notarization and other formats. Doing that would make some of the other comments irrelevant.
I'd also like to see if we can upload a single zip instead of a bunch of smaller requests (see comment further down).
filelist_dict = build_filelist_dict(context) | ||
for path, path_dict in filelist_dict.items(): | ||
if path_dict["formats"] == ["apple_notarization_stacked"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this actually function correctly if some files are not apple_notarization_stacked
? Eg: will we sign (or notarize) them correctly, and then move on and do the stacked ones correctly? If not, we should disallow apple_notarization_stacked
for only some files, and bail at a higher level here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'll disallow mixed formats when stacked is present
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did disallowing mixed formats get implemented?
@@ -54,6 +57,15 @@ async def async_main(context): | |||
copy_to_dir(os.path.join(work_dir, source), context.config["artifact_dir"], target=source) | |||
if "gpg" in path_dict["formats"] or "autograph_gpg" in path_dict["formats"]: | |||
copy_to_dir(context.config["gpg_pubkey"], context.config["artifact_dir"], target="public/build/KEY") | |||
|
|||
# notarization_stacked is a special format that takes in all files at once instead of sequentially like other formats | |||
notarization_dict = {path: path_dict for path, path_dict in filelist_dict.items() if "apple_notarization_stacked" in path_dict["formats"]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is using a new format for this just to make it safer to roll out? If so, what are the plans for apple_notarization
and apple_notarization_geckodriver
after we switch to stacked? (Ideally, it seems like we ought to move everything to stacked.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I initially replaced apple_notarization
but decided against it to allow for the feature to ride the train.
I'll add deprecation notices on the old functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave geckodriver alone for now, and refactor that as we move things around later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get an issue on file to remove this later, too.
if extension == ".pkg": | ||
path = os.path.join(notarization_workdir, relpath) | ||
utils.copy_to_dir(path_dict["full_path"], notarization_workdir, target=relpath) | ||
submissions_map[path] = await retry_async( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many files will we be notarization in parallel? We may want to limit how many we do at once. Especially spread over all of the iscript machines, this could end up doing a lot at once, and potentially hitting a rate limit or other problems.
(Note: if we end up making a single request with a big zip file, this is not an issue.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's why I called it stacked
and not parallel
.
It's still submitting each file sequentially, but it doesn't start polling for results until all files have been submitted.
That way the max parallel submissions are controlled by our chunking still.
Hopefully this won't hit a limit on apple's end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I'm wrong, but we're still going to have more files in the process of being notarized at the same time, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want to highlight this one last time. We're submitted the files synchronously, but we're not waiting on one to finish notarizating before we submit the next one - which means more will be in Apple's system at any given time than before. I have no issue with this, but please keep an eye on notarization tasks when this is activated to see if we start to hit more timeouts or intermittents. If we do, we should add some limits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ultimately I think this gets us closer to the previous behaviour where one task was submitting files to apple, and then a separate task was polling the service to get the notarized artifact back and staple it?
relpath_index_map = {} | ||
task_index = 0 | ||
# Submit to notarization one by one | ||
for relpath, path_dict in filelist_dict.items(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I'm wrong, but I seem to recall that we can upload a zipfile with multiple files we want notarized inside. Assuming that's true, I suggest we construct a new zipfile and make a single request rather than making a bunch of smaller ones. (This would avoid potential issues with rate limiting or similar problems.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what I've gathered it's supported - but on the apple side it will check the apps sequentially, making things slower.
With the current setup we're making the exact same amount of parallel requests, so not much of a risk to be rate-limited - unless they could by requests per ~minute(?), which would be weird.
|
||
|
||
@time_async_function | ||
async def apple_notarize_stacked(context, filelist_dict): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of overlap between this function and _notarize_all
. If we're planning to keep the latter, some refactoring to avoid all of the duplication would be nice.
workdir_files = os.listdir(notarization_workdir) | ||
supported_files = [filename for filename in workdir_files if _can_notarize(filename, (".app", ".pkg"))] | ||
if not supported_files: | ||
raise SigningScriptError("No supported files found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be preferable to do this sort of sanity checking prior to submitting anything - otherwise we're making notarization requests that will never be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're mostly handling multiple l10n versions of the same app, this should only only happen if something is broken upstream, and likely would be missing for all packages. It's a rare enough case that there's no point in optimizing for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is about optimization, it's about being defensive, not trusting your inputs, and failing early.
@@ -1633,8 +1633,7 @@ async def apple_notarize(context, path, *args, **kwargs): | |||
""" | |||
# Setup workdir | |||
notarization_workdir = os.path.join(context.config["work_dir"], "apple_notarize") | |||
shutil.rmtree(notarization_workdir, ignore_errors=True) | |||
utils.mkdir(notarization_workdir) | |||
utils.mkdir(notarization_workdir, delete_before_create=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is delete_before_create
necessary now? Especially for the existing notarization functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's more of a safeguard. I don't see why we wouldn't want that..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess what I'm wondering is: why is it getting added? Did you run into something? (I don't really have a problem with it...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be fair, this is more relevant for local testing to ensure we don't have anything in the workdir. AIUI In CI scriptworker takes care of deleting everything after each task is complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think something called mkdir should be doing rmtree. Since this seems to be a no-op (we were calling rmtree + mkdir, now we're calling mkdir which itself calls rmtree before re-creating the dir), I'd rather this was reverted.
025be75
to
d9a2d13
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving unapproved for the moment for the question about disallowing mixed formats - I'm OK with what's here though.
if not context.config.get("apple_notarization_configs", False): | ||
raise Exception("Apple notarization is enabled but apple_notarization_configs is not defined") | ||
setup_apple_notarization_credentials(context) | ||
|
||
context.session = session | ||
context.autograph_configs = load_autograph_configs(context.config["autograph_configs"]) | ||
|
||
work_dir = context.config["work_dir"] | ||
# TODO: Make task.sign take in the whole filelist_dict and return a dict of output files. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get an issue on file for this, please.
filelist_dict = build_filelist_dict(context) | ||
for path, path_dict in filelist_dict.items(): | ||
if path_dict["formats"] == ["apple_notarization_stacked"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did disallowing mixed formats get implemented?
@@ -54,6 +57,15 @@ async def async_main(context): | |||
copy_to_dir(os.path.join(work_dir, source), context.config["artifact_dir"], target=source) | |||
if "gpg" in path_dict["formats"] or "autograph_gpg" in path_dict["formats"]: | |||
copy_to_dir(context.config["gpg_pubkey"], context.config["artifact_dir"], target="public/build/KEY") | |||
|
|||
# notarization_stacked is a special format that takes in all files at once instead of sequentially like other formats | |||
notarization_dict = {path: path_dict for path, path_dict in filelist_dict.items() if "apple_notarization_stacked" in path_dict["formats"]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get an issue on file to remove this later, too.
if extension == ".pkg": | ||
path = os.path.join(notarization_workdir, relpath) | ||
utils.copy_to_dir(path_dict["full_path"], notarization_workdir, target=relpath) | ||
submissions_map[path] = await retry_async( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want to highlight this one last time. We're submitted the files synchronously, but we're not waiting on one to finish notarizating before we submit the next one - which means more will be in Apple's system at any given time than before. I have no issue with this, but please keep an eye on notarization tasks when this is activated to see if we start to hit more timeouts or intermittents. If we do, we should add some limits.
@@ -56,6 +58,8 @@ | |||
"autograph_rsa": sign_file_detached, | |||
"apple_notarization": apple_notarize, | |||
"apple_notarization_geckodriver": apple_notarize_geckodriver, | |||
# This format is handled in script.py | |||
# "apple_notarization_stacked": apple_notarize_stacked, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to map this format to a function once the first todo above (about sign
) is addressed. When you file that issue, please reference it here as well.
58686e6
to
8f86c0d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for filing #980!
Please add a comment near the relevant code before merging this.
fee69f8
to
3babb54
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requesting changes for the mkdir bits, I'm fine with the rest of this, thanks.
@@ -1633,8 +1633,7 @@ async def apple_notarize(context, path, *args, **kwargs): | |||
""" | |||
# Setup workdir | |||
notarization_workdir = os.path.join(context.config["work_dir"], "apple_notarize") | |||
shutil.rmtree(notarization_workdir, ignore_errors=True) | |||
utils.mkdir(notarization_workdir) | |||
utils.mkdir(notarization_workdir, delete_before_create=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think something called mkdir should be doing rmtree. Since this seems to be a no-op (we were calling rmtree + mkdir, now we're calling mkdir which itself calls rmtree before re-creating the dir), I'd rather this was reverted.
if extension == ".pkg": | ||
path = os.path.join(notarization_workdir, relpath) | ||
utils.copy_to_dir(path_dict["full_path"], notarization_workdir, target=relpath) | ||
submissions_map[path] = await retry_async( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ultimately I think this gets us closer to the previous behaviour where one task was submitting files to apple, and then a separate task was polling the service to get the notarized artifact back and staple it?
workdir_files = os.listdir(notarization_workdir) | ||
supported_files = [filename for filename in workdir_files if _can_notarize(filename, (".app", ".pkg"))] | ||
if not supported_files: | ||
raise SigningScriptError("No supported files found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is about optimization, it's about being defensive, not trusting your inputs, and failing early.
This is the first behavior that consumes all files at once, so it's a bit odd how it's being handled in script.py
Removed noop sign sign in tasks.py since we don't allow for mixed formats anymore
3babb54
to
7925b96
Compare
Removed
At a high level, yes!
This feels like we're over-engineering for a red herring case, but I've updated the code to check everything before submitting. |
This is the first behavior that consumes all files at once, so it's a bit odd how it's being handled in script.py