Skip to content
Open
Changes from 1 commit
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
175 changes: 175 additions & 0 deletions accepted/00000-snap-package-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
- Feature Name: support snap in ubuntu 22.04
- Start Date: 6/01/2025

# Summary
[summary]: #summary

Introduce Snap support in Uyuni, allowing users to:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This RFC itself details the reposync side, i.e. how do we:

  • discover snaps
  • select snaps for download
  • download snaps
  • store snaps

I'm missing the description of:

  • The API, which will respond to requests from the minion's snap execution.
  • The Salt side, which enables server to instruct clients to install/update/remove snaps.
    • For now, we can focus on using Salt directly, i.e. salt <minion-name> snap.install <snap-name> from the server means that the server reaches out to the minion, executes snap install ..., and finally minion uses the Server's new Snap API to install the snap.

We can either keep this in one RFC, of split it into smaller RFCs, that is up to you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to have the API definition.


Install, update, and remove Snap packages.

Manage Snap channels (stable, candidate, beta, edge).

Handle Snap package management in airgapped environments.

# Motivation
[motivation]: #motivation

Since Ubuntu 22.04 LTS, the Snap package technology has gained significant traction, and with the Ubuntu 24.04 LTS release, many deb packages are being migrated to Snap.

With this increasing adoption of Snap packages in Ubuntu, Uyuni lacks native support for managing Snap-based applications. This creates a gap in package management, especially as more software is distributed via Snap.


# Detailed design
[design]: #detailed-design

1 Data Analsis

Total unique packages: 6564 (6/11/2025)
Total stable packages: 6564
Architecture count in stable packages:
- amd64: 6463
- armhf: 45
- arm64: 58
- all: 101
- i386: 67
- ppc64el: 10
- s390x: 10

Total unique packages checked: 13746
- Total in 'beta': 1677
- Total in 'candidate': 1782
- Total in 'edge': 3740

Total size: 493 GB around 500GB
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the size of the compressed snaps or installed applications? 500GB for 6500 packages seems a bit high.

Average package size: 76.82 MB

At this stage, we may be able to store the beta and candidate Snap packages in the cache.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should first focus on just synchronizing the stable ones only. Other channels could be activated by the users.
At the same time, considering the size and variety of applications that are present in snap, I think it's a good idea not to synchronize all packages by default, and allow users to define which ones should be synchronized.

However, since .snap binary packages are typically two to three times larger than .deb packages, it may be more efficient to use a pre-selection strategy for the stable channel.

Proposed approach:

1. Load the full list of available packages.

2. Allow the client to select which packages they want to manage.
Comment on lines +51 to +53

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does this happen, and where?
As a user, will I see the list of packages in CLI? In UI?
Will the full list of packages refresh every time I want to select the packages?
Does this happen on the client (minion), or on the server that caches the snap packages?
Do we select only a package name and Uyuni downloads all channels that are available? (stable, beta, candidate, edge, ...) Or are we selecting a channel as well?

Later, you propose the following command to download the snaps:

spacewalk-repo-sync --channel=ubuntu_22.04_snap_stable --type=snap

Does the server already know which packages to download? If so:

  • Where and how do we store the list.
  • When and how do we ask the user for input to create the list.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot have a refresh of the available package list to synchronize. The list refresh must be done asynchronously.
The refresh should be done on the server side. On the minion side, only the packages synchronized to uyuni should be available for installation.
I would say that by default uyuni would only download the stable ones. Users should be able to enable the download of other channels if needed.
Snaps and rpm/deb channels are so different that I think we should have a new command to handle the snap download.
For me it doesn't make sense to add it to the existing spacewalk-repo-sync, which is focusing on traditional packages channels.

Copy link
Author

@Kathy0704 Kathy0704 Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does this happen, and where? As a user, will I see the list of packages in CLI? In UI? Will the full list of packages refresh every time I want to select the packages? Does this happen on the client (minion), or on the server that caches the snap packages? Do we select only a package name and Uyuni downloads all channels that are available? (stable, beta, candidate, edge, ...) Or are we selecting a channel as well?

Later, you propose the following command to download the snaps:

spacewalk-repo-sync --channel=ubuntu_22.04_snap_stable --type=snap

Does the server already know which packages to download? If so:

  • Where and how do we store the list.
  • When and how do we ask the user for input to create the list.
[Scheduled Task: Cron Job]                      [User Workflow]
+----------------------------------------+       +-----------------------------+
| Every week (or on a schedule):         |       | User opens Uyuni Web UI    |
| - Call Snap search API (a to z)        |       +-----------------------------+
| - Fetch snap_id, publisher_id, etc.    |                   |
| - Store into preloaded metadata table  |                   v
+----------------------------------------+       +-----------------------------+
               |                                      | Create Snap Channel        |
               |                                      +-----------------------------+
               v                                                  |
     +--------------------------------+                           v
     |   Snap Metadata DB (preloaded) |              +-----------------------------+
     +--------------------------------+              | Create Snap Repo            |
               |                                     | - Select Snap package       |
               `-----------------------------------> |   from preloaded DB table   |
                                                     | - Bind repo to a channel    |
                                                     +-----------------------------+
                                                                 |
                                                                 v
                                                     +-----------------------------+
                                                     | Download Files (on demand): |
                                                     | - .snap binary              |
                                                     | - snap-revision.assert      |
                                                     | - account-key.assert        |
                                                     | - snap-declaration.assert   |
                                                     +-----------------------------+
                                                                 |
                                                                 v
                                                     +-----------------------------+
                                                     |     Repo Ready to Serve     |
                                                     +-----------------------------+

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: When does load the full list of available packages.
, and where?
This occurs on the Uyuni Server as a scheduled background task (e.g., via cron). Periodically (e.g., weekly), the server queries the Snap Store API (using queries from a to z) to fetch metadata for available Snap packages. The collected data (e.g., snap_id, publisher_id, sha3-384) is stored in a preloaded metadata table in the Uyuni database.

Q: As a user, will I see the list of packages in CLI? In UI?
The preloaded Snap package metadata will be visible in the Web UI, during the “Create Snap Repo” workflow. Users will be able to:

Browse the package list via dropdown or search bar.

View package name, publisher, description, etc.

Select desired Snap packages.

also i think CLI should add --snaplist, --add snap packages two options

Q: Will the full list of packages refresh every time I want to select the packages?
No. To avoid performance and API rate issues, the Snap package list is not fetched on demand.

Instead, it's refreshed periodically in the background via a scheduled job (e.g., every week).

This keeps the user experience responsive and avoids repeated API calls to Snapcraft.

Q: Does this happen on the client (minion), or on the server that caches the snap packages?
It happens on the Uyuni Server, which:

Maintains the metadata DB table.

Provides the UI for package selection.

Triggers the download of Snap packages and assertions.
Clients (minions) do not participate in this process — they will consume packages only when instructed via Salt commands.

Q: You propose this command to download snaps:
spacewalk-repo-sync --channel=ubuntu_22.04_snap_stable --type=snap
Does the server already know which packages to download?

Yes — before this command runs:

The user must create a Snap repo and bind it to a Snap channel.

During repo creation, the user selects which Snap packages (and their channels) to manage.

Q: Where and how do we store the list?
The selected packages for each repo are stored in Uyuni's database.
Suggested schema:

Column Description
repo_id Associated repo ID
snap_id Unique Snap ID
snap_name Human-readable name (e.g. htop)
channel Channel (e.g. stable, edge)
publisher_id Publisher fingerprint
Specific revision (optional)
sha3_384 Binary integrity hash

Q: When and how do we ask the user for input to create the list?
The package selection occurs when creating or editing a Snap Repo in the UI.
Users:

Open the "Create Snap Repo" UI.

Choose from the preloaded metadata.

Select Snap(s) and their channel(s).

Bind them to a specific repo and channel.

This setup allows Uyuni to know exactly what to download when spacewalk-repo-sync is invoked.


3. Download only the selected packages to the repository cache. (by this way support part of airgap environment)

2 Snap Repository Synchronization Workflow

```text
┌────────────────────────────────────────────┐
│ spacewalk-repo-sync CLI │
│ $ spacewalk-repo-sync --channel= │
│ ubuntu_22.04_snap_stable --type=snap │
Copy link

@m-czernek m-czernek Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to focus on Ubuntu 22.04?

Can't I install any snap on any OS that has the snapd service installed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, one can install snap on any OS that snapd is available. So we should allow it on uyuni also.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it should not focus on the ubuntu 22.04, snap is mainly used by the ubuntu, but another minion whose OS enable to use the snap also can use this feature

└────────────┬───────────────────────────────┘
│ Note: Snap packages do not have a public URL,
│ so no URL is required in CLI.
┌────────────────────────────────────────────┐
│ reposync.py (main logic) │
│ - Selects plugin by repo_type │
└────────────┬───────────────────────────────┘
┌────────────────────────────────────────────┐
│ snap_src.py (Snap plugin) │
│ - Creates ContentSource │
│ - Wraps SnapRepo │
└────────────┬───────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ SnapRepo.get_all_package_list() │
│ - Calls: https://api.snapcraft.io/api/v1/snaps/search?q={query}&limit={limit} │
│ - Creates SnapPackage objects (name, path, etc.) │

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like we want to first call the api.snapcraft.io URL to list all of the packages for user selection (step that happens presumably before we call spacewalk-repo-sync), and then do the same thing again inside of spacewalk-repo-sync?

└────────────┬───────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ SnapRepo.get_select_package_list() │
│ - Filters selected packages │
│ - Creates SnapPackage objects (name, path, etc.) │
└────────────┬───────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ SnapRepo._download(url) │
│ - Performs HTTP download of selected .snap file │
│ - GET https://api.snapcraft.io/v2/snaps/info/<snap_name> │
└────────────┬───────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ reposync.py → import_packages() │
│ - Imports metadata into the database │
│ - Saves .snap files under /var/spacewalk/packages/ │
└────────────┬───────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ Minions can now use Uyuni as a Snap repository │
│ (served through Uyuni-hosted channels) │
│ e.g. `sudo snap install <pkg>` from Uyuni server │
└────────────────────────────────────────────────────────────┘
```

Fake URL Design for Snap Repositories

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I understand why we need this correctly. It seems to me that you're modelling a repo type here, and you want to model one repository per snap channel.

What will this be used for? Why do we need to model repos when we know there's only one repo for snaps, and that's snapcraft.io?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to documentation one can produce snaps from github or even locally and make it available.
Considering that the snap support is so different from repositories, and that they can be generically assigned to any systems, I don't think we should re-use the current channel infrastructure to support snaps.
In my opinion we should create an independent code and database structure to support it, the same way we maid it for configuration channels.
We should have a dedicated snap channel feature in place, where we could manage the data and minion assignement.


Snap packages are distributed via the Snap Store using dynamic APIs rather than static URLs. To maintain consistency with other repository types (e.g., YUM, DEB), introduce a Fake URL format to represent Snap sources uniformly in the database.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to maintain consistency with other YUM/DEB repositories, we can have a separated database structure.
Present data/packages in the webUI is a different story, and we can decided if we present them in the same UI table or in a dedicated page for snaps.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Ricardo,

Thanks a lot for your comment. It was very helpful.

Here’s my current idea for creating a local Snap repository in Uyuni:

Users first create a Snap channel.

Then, they bind a repository to that channel, following the traditional Debian/YUM model used in Uyuni.

The repository will present a selectable list of Snap packages (via a search bar or dropdown UI), and unlike deb or yum, it doesn't require a fake URL.

Alternatively, we could simplify the workflow by allowing users to add Snap packages directly to the channel without creating a separate repository.

From a business standpoint, I’m not sure which approach would be more appropriate, so I’d love to hear your thoughts.

I've also included more technical details in the RFC draft—such as how the Snap package list is refreshed and what the database structure looks like. Please take a look whenever you have time.

Sincerely,
Kathy


Fake URL Format:
```
snap://<repo label>/<stable/edge/candidate/beta>
```


These URLs are not used for actual downloads. Instead, they serve as unique identifiers stored in the rhnContentSource.source_url field. The real package fetching will be handled through the Snap API.

This approach keeps the database structure consistent, simplifies repository logic, and supports multiple Snap channels (managed through the rhnSnapChannel table).

When a client creates a Snap repository through the UI, they do not need to enter a URL—only the channel (stable, edge, candidate, or beta) and a repository label are required. The API will automatically generate a fake URL internally.

However, when creating a Snap repository using spacemd, the user may manually specify a fake URL, for example:
```
repo_create --name="Snap Store Repo" --url="https://fake.url" --type=snap
```


3 DB DESIGN

rhnChannel stores basic channel information, such as label, org_id
rhnContentSource stores the actual repo URL
rhnChannelContentSource channel and content source mapping table (channel ↔ repo)

Uyuni’s current database schema (rhnContentSource, rhnContentSourceType, rhnChannel) is designed for repositories like YUM or DEB, which use a static URL and do not have multi-channel semantics.

However, Snap packages are distributed via multiple dynamic channels (e.g., stable, beta, candidate, edge) under a track (e.g., latest). The existing schema does not provide a way to associate a Snap repository with multiple channels, nor a place to store their metadata.
``` text
CREATE TABLE rhnSnapChannel (
id SERIAL PRIMARY KEY,
content_source_id INTEGER REFERENCES rhnContentSource(id) ON DELETE CASCADE,
channel VARCHAR(64) NOT NULL,
created TIMESTAMP WITH TIME ZONE DEFAULT now(),
modified TIMESTAMP WITH TIME ZONE DEFAULT now()
);

-- Insert 'snap' repo type
insert into rhnContentSourceType (id, label) values
(sequence_nextval('rhn_content_source_type_id_seq'), 'snap');

-- Register supported channels for the repo
INSERT INTO rhnSnapChannel (content_source_id, channel) VALUES
(600, 'stable'),
(600, 'beta'),
(600, 'candidate'),
(600, 'edge');
```



4 UI design

To be continue