-
Notifications
You must be signed in to change notification settings - Fork 20
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
Native AppStream support #87
base: master
Are you sure you want to change the base?
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
- Feature Name: Native AppStream support | ||
- Start Date: 2024-02-19 | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
This RFC proposes native support for AppStreams repositories in Uyuni. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Following the integration of [modularity and modular repositories](https://docs.fedoraproject.org/en-US/modularity/) in RHEL and its derivatives, Uyuni initially implemented modularity through content lifecycle management and the [introduction of AppStream filters](https://github.com/uyuni-project/uyuni-rfc/blob/master/accepted/00064-modular-repos-with-clm.md). These filters effectively remove modularity features from a repository, enabling consumption through the Uyuni UI. However, this approach introduced complexity and limited functionality, prompting the need for a more comprehensive solution. | ||
|
||
The goal is to seamlessly support modularity in its native form within uyuni, ensuring a user-friendly and intuitive experience across all workflows involving modular repositories. | ||
|
||
# Detailed design | ||
[design]: #detailed-design | ||
|
||
## Overview | ||
|
||
The design encompasses core functionality, new UI operations, modifications to the existing CLM feature, and testing infrastructure. | ||
|
||
## The core design | ||
|
||
The core design involves three key components for data collection and filtering of packages for client consuption: | ||
|
||
1. **Repo-sync**: A standalone Python module that extracts module metadata from source channels using `dnf`'s `libmodulemd` library during repo-sync, serving as the source of truth for the module information. As the data gathered during this process is critical to the feature, it must be executed as a single unit with the repo-sync ([See the PoC](https://github.com/cbbayburt/uyuni/commit/ed9391e8c6e0a66d1dd7cb0f3501332b0884f2f3)). | ||
|
||
2. **Package profile update**: A Salt state that retrieves current module information from clients, storing the data in the database. The state calls `dnf module` commands to retrieve the list of enabled module streams together with their *name*, *stream*, *version*, *context*, and *arch* values ([see the PoC](https://github.com/cbbayburt/uyuni/commit/2c788f3144f5bfe8ddd904045e0a757a7a432923)). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can, I'm not fully informed on this topic. So please excuse my ignorance. Could you clarify how we currently installing/removing/updating packages—are we using yum or dnf ? If we're using yum, will we stick with it for package operations, or are we considering transitioning to DNF? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nowadays we're using the terms There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thank you! So it's safe to say that for RHEL and clones, only DNF will be used at the end. Thank you Can. |
||
|
||
3. **Package cache**: Incorporates data from repo-sync and package profile update into existing queries, ensuring proper filtering of non-enabled modular packages. The existing tables, queries and stored procedures will be updated with additional joins and proper indexing to ensure minimum performance impact. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a 4th point needed. You need to generate new metadata for the Channels including new compiled modules.yaml from the database informations. |
||
A prototype showcasing the core functionality can be found [here](https://github.com/cbbayburt/uyuni/tree/native_appstreams_poc). | ||
|
||
### ER diagram | ||
|
||
The following figure shows the proposed ER diagram for the core design. | ||
|
||
![ER diagram](images/00101-native-appstreams-er-diagram.png) | ||
|
||
## New UI operations | ||
|
||
The proposed UI includes a new page under the `System > Software` tab, visible only for clients with modular channels assigned. It displays available modules and their streams, allowing users to select and apply module changes to clients. | ||
|
||
The main workflow is as follows: | ||
|
||
1. Select an assigned modular channel. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be part of the change channels? Why we need a new place to define the assigned channels to a minions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every modular repository has its own set of modules and theoretically, a system can have more than one modular channel assigned. In such cases, the user must first pick a channel to see its modules. But after writing this, I think we don't need this step. Instead, we can put together all the modules from all the assigned modular channels and present them in a single list. I'll update this part accordingly. |
||
2. Select enabled modules and their streams. | ||
3. *Optional:* Run `mgr-libmod` for dependency resolution with real-time feedback. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, I lack knowledge here so another question. What kind of dependency issue would you expect? Do streams depend on other streams or are they self-contained? Ideally, we should have mechanism in place, so user doesn't get into bad state. Just like we do with required/recommended channels. Select all the needed stuff automagically when user select a module stream with option that experienced user can de-select. But if that's asking for too much, this optional would be super helpful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, a module may depend on other modules and they must be enabled together. If we miss this, dnf would complain about the missing dependencies. Other than that, mgr-libmod also checks for conflicting streams. If, for example the user tries to enable two streams of the same module, mgr-libmod would complain about this too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Btw, in real world, dependency relations so far only exist in RH8. RH9 has a lot less modules than 8, and we haven't seen any dependent modules in 9 yet. RH8 is kind of an edge case of modularity 😂 |
||
4. Schedule an Uyuni action to apply the selection on the client. | ||
5. The action calls `dnf` with the selection of module streams on the client via Salt. | ||
6. On job return, update the selection of modules in the database. | ||
|
||
To allow working on multiple clients at once, SSM will be used. In the SSM, the clients in the set will be first grouped by the modular channels they are assigned to. Then the user will select a group and makes a selection of modules that applies to the whole group. | ||
|
||
## Content lifecycle management | ||
|
||
The current CLM approach will be replaced with regular *ALLOW/DENY* logic in AppStream filters. During build, module filters will be translated to package filters that apply to all packages of the module. A module will only be included in the target repository if all its packages are visible. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means we would not be able to filter packages and is version inside a module? Would not make sense to have the module available if at least one package from a module is present? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In most cases, a module has multiple packages packed together to form an application. For example: Packages in the Postgresql module:
so it usually makes no sense to have a module enabled if not all the packages are there. OTOH, different versions of a module are separate module entries, so we can still implement filters to selectively filter different versions (using the module versions notation). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking of scenarios where some packages in the module could be optional, and the user decided to exclude them in a filter. In this scenario, the module would never get available. Do you think a scenario like this one makes sense? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's done by "Profiles" in AppStreams. In the example above, So maybe the best way is to give the user the freedom indeed. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible problem: what happens if a customer want to allow only security updates and apply a filter like this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also need to check how DNF behaves if some packages are missing in a module. Our strategy is to clone DNF's behavior as much as possible. |
||
|
||
During repository metadata generation, `libmodulemd` will parse and index the modular metadata from the source channels and generate the modular metadata for the target repository following the rules enforced by the attached filters. | ||
|
||
If all the modules are denied as a result of the enabled filters, no module metadata will be generated in the target repository. | ||
|
||
## Testing | ||
|
||
A "dummy" modular repository will be built in OBS for comprehensive testing in the CI environment. | ||
|
||
Below is an example of a minimal test repository: | ||
|
||
![Test repository](images/00101-native-appstreams-test-repo.png) | ||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
- Migration plan for the typical user | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I know this is in the unresolved questions section, are we roughly sure we can migrate everything we currently support in a reasonable way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new approach is fundamentally different so we won't be able to offer an automated migration at all. So what I mean here is the migration of the customer's workflow. We just need to make sure that the customers have a smooth way of switching without any disruptions with proper documentation. But in the end, the change is really just getting rid of many extra steps to achieve the same goal, so I'm sure the customers would be happy to go through the labor of migration. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I acknowledge that customers may welcome the transition to the new approach, we cannot compel them to do so by breaking stuff; it should be done at their convenience. In other words, we must ensure that their existing clm project setups remain functional. Moreover, if it helps, we could consider applying this change solely to new CLM projects, potentially easing concerns regarding existing setups. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, it's a bit tricky because we need to replace the old AppStream filters with the new functionality, but at least we can implement it so their existing projects won't be affected until they want to rebuild them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to implement it in a way that allows uses to continue using the flatten method and this one if they want? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Flattening is only possible with the old-style AppStream filters. If we include both old and the new filters, it would be too confusing for users, and also they will keep using the old way for a longer time. That means more L3s and harder maintenance for us so I wouldn't recommend it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, and sounds good to me. 👍 |
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 expand on "as a single unit"? That sounds a bit like a transaction (succeed together or fail together), which we don't have in reposync.
The PoC script, as far as I can tell, works on already synced, imported, and linked packages. Is that correct? What are the downsides of doing it this way vs. doing it at a different time in the process?
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 new data we collect at this step is critical for modular repositories to work. If we somehow miss this data, Uyuni won't know if a package is really modular or not, and will treat it as a regular package. As a result, Uyuni will suggest wrong updates to existing packages (the initial problem we have with modularity).
Because of this, we have to make sure that module metadata is properly processed when syncing a repository. If not, the reposync for this channel should fail completely.
How do we currently make sure that the repos don't end up in an invalid state during reposync?
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 seems we do it using proper exception handling and DB transactions.
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.
Maybe the module.yaml should be parsed first. I think during package import we call multiple times "commit" to solve problems with dependencies between packages which gets imported in parallel.
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 have to do it in the end because we need package IDs for the relation.