-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Add repair step to load missing apps before upgrade #27711
Conversation
lib/private/Repair/Apps.php
Outdated
if ($isMarketEnabled){ | ||
$this->loadApp('market'); | ||
foreach ($missingApps as $app) { | ||
$output->info("Repairing missing app: $app"); |
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 wouldn't call it "repairing" because it sounds like it's broken.
Migrating from 9.1 to 10.0 it is an expected step to migrate the app.
Maybe call this "Fetching app from market"
lib/private/Repair/Apps.php
Outdated
IRepairStep::class . '::repairAppStoreApps', | ||
new GenericEvent($app) | ||
); | ||
$this->appManager->enableApp($app); |
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.
Not sure if this is safe, I'd suggest to first fetch all apps and only enable them all at the end ?
Just in case one app in the middle breaks everything...
Code makes sense so far |
lib/private/Repair/Apps.php
Outdated
foreach ($missingApps as $app) { | ||
$output->info("Repairing missing app: $app"); | ||
$this->eventDispatcher->dispatch( | ||
IRepairStep::class . '::repairAppStoreApps', |
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.
Hmmm, what if it fails ? Does it abort correctly ?
Also need to display the error to the admin so they can find if it's a connectivity issue or maybe they're unlucky and the app doesn't exist on the market.
In case the app doesn't exist on the market then it's the situation from #27047 where someone deleted the code of a third party app and is trying to upgrade.
@PVince81 Regarding your question "do you pull the app from the market before the DB update ?"
Detecting an exact error requires additional exception subclassing in the market app |
lib/private/Repair/Apps.php
Outdated
IRepairStep::class . '::repairAppStoreApps', | ||
new GenericEvent($app) | ||
); | ||
$this->appManager->enableApp($app); |
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'm not sure whether it's the right time to enable the app here. From what I remember the update process has a specific moment where it enables all apps, maybe as part of upgrading apps, not sure. Can you verify that this fits in the workflow ? Ideal is to have the exact same workflow as before and not enable apps too early or too late which has a risk of influencing / modifying update behavior.
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.
@PVince81 Update tries to enable only apps that were disabled by update (3rd party or incompatible)
I haven't managed to find the reason but the app code is restored as disabled otherwise.
|
Tests: Marketplace unavailable / offline
Marketplace available but app does not exist there
Marketplace available, app exists but no new version
Marketplace available, app exists and new version available
Other
|
|
lib/private/Repair/Apps.php
Outdated
|
||
throw new RepairException('Upgrade is not possible'); | ||
} elseif ($hasNotUpdatedCompatibleApps) { | ||
// warn? |
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'd say yes, warn. Then the admin should be able to upgrade these apps inside the market app later on (or update these manually in case of offline mode).
|
My steps:
Expected result:Update aborts. Actual result:Update goes through. @VicDeo not sure if my testing is wrong. Edit: I tested this wrong. Need to set version.php version to 10.1 for better results. |
lib/private/Repair/Apps.php
Outdated
); | ||
|
||
foreach ($appsToEnable as $app){ | ||
$this->appManager->enableApp($app); |
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 suggest we don't enable anything here. Why ? Because these apps were already enabled before, else we wouldn't do any updating of them.
I think this loop is anyway a no-op, it will see the app is already enabled and skip. So better remove 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.
@PVince81 in case of missing code app is going into a disabled state after the code is restored. I haven't found the reason, this is a fixup.
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.
Can you add a code comment then to prevent future devs to wonder about the same question ?
Looks good so far apart from the one bug. I'll continue testing with the planned user_ldap case: user_ldap 10.0 caseSetup LDAP in 9.1 then upgrade to 10.0:
|
I did all tests with |
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 think the logic can be improved to prevent the output not reflecting that apps have been updated.
lib/private/Repair/Apps.php
Outdated
'reinstallAppStoreApp' | ||
); | ||
$hasNotUpdatedCompatibleApps = count($failedCompatibleApps); | ||
|
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.
Hm, so the current implementation will try to enable apps that have been updated.
core/lib/private/App/AppManager.php
Line 218 in 2d000d9
throw new \Exception("$appId can't be enabled since it is not installed."); |
- I think it should throw an AppNotInstalledException instead.
- That still allows the foreach to be escaped if the exception is thrown. I'd rather move 98-105 out of the try catch. If we try to enable an app that wasn't installed in the first place something has gone wrong and I think it is ok to fail early in that case.
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 clarification: if an app's code is missing but the DB contains an entry about an enabled app, do we call this "app is installed but missing code" in the logic ? @VicDeo
From my understanding this code only runs for apps that either are pending updates or where the code has disappeared (so it was installed at some point, like our future "user_ldap" case).
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.
@PVince81 this PR works with enabled
apps only
there are three kinds of them:
- enabled, but no code
- enabled, but incompatible
- enabled and compatible
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.
these lines (reenabling the apps) can be safely removed once #27730 is merged.
lib/private/Repair/Apps.php
Outdated
} | ||
|
||
// Do not put this in else | ||
if (!$isMarketEnabled) { |
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.
The current code will overwite the $failedIncompatibleApps
if 90 throws an AppManagerException exception. Incompatible apps might actually have been updated. If we move the initialization to the top this should work correctly. How about initializing $hasNotUpdatedCompatibleApps
, $failedMissingApps
and $failedIncompatibleApps
in 73-75 instead of checking $isMarketEnabled
here. Then you can introduce a new function that does all the error handling in 120-134 and call it from the catch as well.
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.
@butonic This catch means that marketplace is not available. Code starting from this line is executed both for disabled market app and when market app had any issue with connection to marketplace
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.
yup, and $this->getAppsFromMarket() for failedIncompatibleApps and failedMissingApps might have succeeded ... than internet dies and $this->getAppsFromMarket() for failedCompatibleApps throws the Exception ... this would overwrite the failedIncompatibleApps and failedMissingApps arrays, with the initial value. Thats wrong, isn't it?
|
|
@PVince81 regaring your testcase #27711 (comment) But it is going to disabled state just as an app with missing code. :( |
@PVince81 regrading output #27711 (comment) I'm limited with
|
If the version from the market is the same it shouldn't try and pull it. |
Rebased to get the "don't disable third party app" improvement. Talked with @VicDeo and he said there are only cosmetic changes left to do. So I'm going to redo the test plan and hope all goes well now. |
Tests: Marketplace unavailable / offline
Marketplace available but app does not exist there
Marketplace available, app exists but no new version
Marketplace available, app exists and new version available
|
To be raised separately. |
Basically when only a single app has a new version in info.xml, one needs to run occ upgrade to proceed with the DB upgrade. When this happens we must not attempt to update the app codes. Need to add a check for "is core upgrade needed", if yes then also update app codes Edit: fixed in 446cb08 |
@VicDeo #27711 (comment) still doesn't work correctly. It seems it decides to disable the outdated app automatically and moves forward. This is very bad because it could disable an important app. This is the case where the app exists in app store but the platform was updated to a more recent incompatible version. You need to only accept the market version if it is strictly bigger than the current version from info.xml. |
|
If doing an app-only upgrade then it's not about updating the code but about updating the database. Still keep the logic about missing app code and incompatible apps.
@VicDeo ok you were right. The fact that the old app got reinstalled even if it had the same version was a side-effect of my testing. Now when testing this case I increase the core version to "10.1" and then it refetches the market app and sees that it's incompatible. The sad part is that it refetches the app needlessly, but we can live with this for now and optimize this separately. |
It is likely that the app versions are cached somewhere and used by the old code that disabled incompatible apps. Edit: fix is here f3607c0 |
|
Fixed issue with incompatible app getting autodisabled even after updating to a compatible one: f3607c0 |
I fixed the repeated Guzzle issues by properly catching |
@PVince81 Additionally fixed: update to the same version. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Description
Before update repair step
Related Issue
owncloud/market#39
#26227
Motivation and Context
Allow seamless app unbundling for the next releases
How Has This Been Tested?
Testing in progress
Screenshots (if appropriate):
Types of changes
Checklist: