Problem/Motivation

@pwolanin raised this here #3284443-19: Enable unattended updates and @catch also mentioned something similar in #3346707: Add Alpha level Experimental Package Manager module

Basically currently this module requires the file system to be writable by the webserver. Some hosts will not support that.

But if we had a terminal command that could run cron updates then it could be set up to be triggered externally by a more privileged user for example via nix crontab.

Proposed resolution

Terminal command

For the cron merge request this would need to be a standalone script. We would have to determine how hard it would be to bootstrap drupal in a console command. \Drupal\Core\Command\ServerCommand::boot does appear to be doing this but I am not positive

So we should first try to see if this is possible via just a symphony console command.

If that is not possible right now and we would need some Drupal core changes we could add a drush script to the contrib module in the meantime. If we can only do this via drush we should add the functionality in sub-module to avoid adding things to the main module that would have to be removed for the core merge request.

CommandCronUpdater class

We would likely need to extend CronUpdater for this. At the very least we would need to override \Drupal\automatic_updates\CronUpdater::triggerPostApply

Right now at the end of \Drupal\automatic_updates\CronUpdater::performUpdate we have

// Perform a subrequest to run ::postApply(), which needs to be done in a
    // separate request.
    // @see parent::apply()
    $url = Url::fromRoute('automatic_updates.cron.post_apply', [
      'stage_id' => $stage_id,
      'installed_version' => $installed_version,
      'target_version' => $target_version,
      'key' => $this->state->get('system.cron_key'),
    ]);
    $this->triggerPostApply($url);

It probably would make sense in this issue to change this to
$this->triggerPostApply($stage_id, $installed_version, $target_version);
So we don't assume post apply happens via a http request. Then \Drupal\automatic_updates\CronUpdater::triggerPostApply could handle creating the URL and the new CommandCronUpdater::triggerPostApply would trigger post apply in some other way.

Remaining tasks

  1. As follow-up related to #3318587: Research alternatives to curl request on post apply event during cron updates we could look at we should never use the http request for post apply and see if we could always use the solution we create for CommandCronUpdater::triggerPostApply
  2. #3359727: Add new setting for how unattended updates will be run. This would just be the setting and no UI but it also other side effect so it is it's own issue
  3. Right now we have no UI to enable cron updates but in #3284443: Enable unattended updates we would add this.

User interface changes

We

API changes

Data model changes

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

tedbow created an issue. See original summary.

tedbow’s picture

Issue summary: View changes

Wim Leers credited xjm.

wim leers’s picture

Title: Add command to allow running cron updates via console » Add command to allow running cron updates via console and by a separate user, for defense-in-depth
Priority: Normal » Major
Issue tags: +Security improvements

Clarifying that this is meant to address @pwolanin's request at #3284443-19: Enable unattended updates and @xjm's request at #3352210-15: Security review of secure signing components for package manager:

We should also finish the work to allow autoupdates’ cron job to be triggered by a separate user for defense-in-depth

wim leers’s picture

dww’s picture

I’m also very keen on this part of the problem. We spent a lot of effort in Update Manager to support both writable and not-writable web server configurations. It’d be a real step backwards if all the new slickness only supported the writable case.

catch’s picture

I can see advantages for having a separate command so it can be run more frequently than cron and is guaranteed to be run from the cli, but also doesn't drush cron also cover the basic use case?

tedbow’s picture

Status: Active » Needs work

@catch yes I think drush cron would probably be fine for the basic use case. See @phenaproxima's question on #3284443-22: Enable unattended updates to see if just documenting that drush cron could be used used to unblock that issue for the the contrib case.

For the core version of Automatic Updates I would think that would be product decision as to whether we could still rely on drush for this use case or if we would have to have a solution that relied on core only.

I think if we did a need solution for the core version that relied on core alone there would be 2 options.

  1. Ship a script that that just ran Automatic Updates cron update
  2. Add a script to core independent of Automatic Updates that just ran cron. This might cover the basic use case like drush cron does for contrib

I am not sure if 2) would give us extra advantages beyond AutoUpdates. Presumably some people are relying on drush cron that could just rely on core for this.

Also if we did 2) it might be possible as follow-up to set an option flag to only run particular module. For instance core/scripts/drupal cron --module=automatic_updates. This would allow running Automatic Updates more frequently that other modules' cron jobs

wim leers’s picture

First round of review posted. I have some questions 😊

tedbow’s picture

Issue tags: +Needs manual testing

This is failing for me with manual testing. The composer update appear to work but I get "Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup."

Also the UX is not great because I guessing there is message from Composer STager I am not seeing. I need to check if that is case from the UI too.

wim leers’s picture

Also the UX is not great because I guessing there is message from Composer STager I am not seeing. I need to check if that is case from the UI too.

Given this, should we block this on #3354701: Ensure exceptions thrown by event subscribers are logged, which should be trivial to do and would make the testing here simpler?

wim leers’s picture

You linked to this issue 😅 Which did you mean to link to?

tedbow’s picture

🫢Whoops, fixed

tedbow’s picture

So I manually tested this with the changes in #3355074: Failure marker message does not contain exception message + backtrace if available and the message change to a much more meaningful

Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup. Caused by : Failed to copy "/tmp/.package_managerff2a5e14-d9a4-4e06-b0c4-59070929c370/8wDnJ-H-KtVd8_feJmTRN9Fzk7VI5PGep_xeF7qIGns/web/modules/contrib/automatic_updates/.git/objects/pack/pack-ee29fcbd4b76af52c22f4bfd60176f21b3f2391b.idx" to "/Users/ted.bowman/sites/au-drush-update3/web/modules/contrib/automatic_updates/.git/objects/pack/pack-ee29fcbd4b76af52c22f4bfd60176f21b3f2391b.idx"

The actual problem here of trying to copy the .git files I think is an existing issue but I will search the issue queue.

I will probably manually test by just deleting the .git directory first as I am pretty sure this error has nothing to with it being a drush command. Usually when I manually test I am not using a Composer vcs repo. So need to confirm but I think this would happen via the Update form also.

wim leers’s picture

#18: wonderful news!

wim leers’s picture

Title: Add command to allow running cron updates via console and by a separate user, for defense-in-depth » [PP-1] Add command to allow running cron updates via console and by a separate user, for defense-in-depth
Status: Needs work » Postponed
tedbow’s picture

Status: Postponed » Needs review

I don't think we need to block on #3355074: Failure marker message does not contain exception message + backtrace if available. It is an existing issue I just happen to find in this issue it would happen in any case where you had the marker file

tedbow’s picture

Title: [PP-1] Add command to allow running cron updates via console and by a separate user, for defense-in-depth » Add command to allow running cron updates via console and by a separate user, for defense-in-depth
tedbow’s picture

Assigned: Unassigned » phenaproxima

@phenaproxima was going to change the drush command to have only 1 command and have a --post-apply=[STAGE_KEY] option.

tedbow’s picture

I manually tested and it updated from 10.0.8 to 10.0.9. I actually had to manually change StagedDatabaseUpdateValidator because it flagged a change to system_requirments has a DB update when it was not. But that is known issue and comment on #3253828: Use static analysis to detect new update functions, to reduce false positives in StagedDBUpdateValidator with not about this case

I think we still don't want to run DB updates in this drush command as MVP because we intended it to be run in server crontab in an unattended way. But we may want a follow-up that would allowing running DB updates.

I will manually test again once @phenaproxima has made further changes

phenaproxima made their first commit to this issue’s fork.

wim leers’s picture

@tedbow in #21: sure — but your comment in #18 made it sound like it was a hard blocker to continue here. So I was just trying to be helpful 😅🙈

@tedbow in #24: EXCITING!!!!!!! 😄

Also, this MR is starting to look great!

One thing I'm missing is documentation that says you MUST run two commands: drush auto-update followed by drush auto-update --post-apply=…. AFAICT the post-apply gets called automatically thanks to ConsoleCronUpdateStage::handleCron() calling \Drupal\automatic_updates\CronUpdateStage::handleCron() which calls \Drupal\automatic_updates\CronUpdateStage::performUpdate() which calls $this->triggerPostApply() all the way at the end? 🤔 What am I missing?

wim leers’s picture

Status: Needs review » Needs work
phenaproxima’s picture

Assigned: phenaproxima » tedbow
Status: Needs work » Needs review
tedbow’s picture

Status: Needs review » Needs work

Looking good! Just a few suggestions

phenaproxima’s picture

Status: Needs work » Needs review
tedbow’s picture

Issue tags: +Needs follow-up

Needs follow-up for timeout issue in the MR discussions

tedbow’s picture

Issue tags: -Needs follow-up

I think this issue is good. We already have #3357969: For web server dependent unattended updates run the entire life cycle in a separate process that will not be affected by hosting time limits which researching the different places the code can time out.

I am going to manually test this again

tedbow’s picture

Status: Needs review » Needs work

Manual testing didn't work

tedbow’s picture

Got a different error manually testing

 [error]  Update applied successfully but failed in post-apply: The command """ 'auto-update' '--post-apply' '--stage-id=gqDxp7iWi8LDO3vkqYDESoeNS53Aa1oFLLIfBH_LPpI' '--from-version=10.0.8' '--to-version=10.0.9'" failed.

Exit Code: 127(Command not found)

Working directory: /Users/ted.bowman/sites/au-drush/web

Output:
================


Error Output:
================
sh: line 0: exec: : not found
 

guessing $command[0] = $this->fileSystem->realpath($command[0]);
didn't work. Maybe `$command[0]` just is "drush"?

Maybe we need the standard drush way for firing off another command. I think maybe Drush::drush(Drush::aliasManager()->getSelf(), $command, $args);

phenaproxima’s picture

Maybe we need the standard drush way for firing off another command

I agree, but that means we should probably pass the fully built-out Process object to Stage::triggerPostApply(), which I'm not entirely sure how to do...

phenaproxima’s picture

Status: Needs work » Needs review
tedbow’s picture

I manually tested if from /web/sites/default and it worked update it but the only messages I saw was

[INFO] Updating Drupal core to 10.0.9. This may take a while.

So it seems like the io is still not coming back from post apply.

I have an idea on this

tedbow’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs manual testing

Looks good to me if tests pass!

  • phenaproxima committed 4b6cef8d on 3.0.x authored by tedbow
    Issue #3351895 by tedbow, phenaproxima, pwolanin, xjm: Add command to...
phenaproxima’s picture

Status: Reviewed & tested by the community » Fixed

🚢

wim leers’s picture

🥳

I'm pleasantly surprised this landed yesterday! 🤩

But … it seems a bunch of threads were either left open or closed without explanation? 🙈 That makes it difficult for me (or anybody else) to understand the decision making process…

I've noticed that at least one of the remarks in the threads which did not get resolved/explained did start being addressed in another issue: #3357969: For web server dependent unattended updates run the entire life cycle in a separate process that will not be affected by hosting time limits. Hence linking that.

  1. We'll need to update \Drupal\automatic_updates\Development\Converter to avoid adding
    • drush.services.yml
    • src/Commands/AutomaticUpdatesCommands.php
    • src/DrushUpdateStage.php

    to the core MR. Feels like that's easiest to do here? Patch attached.

  2. This still needs a follow-up to make this work as a generic Symfony console command. This is a great first step, and we were able to leverage Drush to handle the bootstrapping for us. But Drupal core never includes any Drush commands, so we do need to do that second step too 😅
  3. There's information in the Remaining tasks section that is missing from the follow-ups that are referenced there. We should move that into those existing issues to avoid it being forgotten.

  • phenaproxima committed e94377d7 on 3.0.x
    Issue #3351895 follow-up by Wim Leers: Do not include Drush-related code...
tedbow’s picture

wim leers’s picture

I identified 3 follow-ups when I reopened this in #41:

  1. ✅ update core MR converter → @phenaproxima did this in #42
  2. ❌ follow-up to make this work as a generic Symfony console command
  3. ✅ update issues listed in "remaining tasks"

Or am I just overlooking an already existing issue for making this work as a Symfony console command? 🤔

tedbow’s picture

Title: Add command to allow running cron updates via console and by a separate user, for defense-in-depth » Add Drush command to allow running cron updates via console and by a separate user, for defense-in-depth
Status: Needs review » Fixed
Issue tags: -Needs followup
wim leers’s picture

Assigned: tedbow » Unassigned

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.