Skip to content

Commit a819c6e

Browse files
authored
[3rd-party images] Retrieve Debian and Fedora images (#4293)
Several notables changes presented here: 1. Debian and Fedora images presented in `multipass find`: Details for 3rd-party cloud images are located in `data/distributions/distribution-info.json` and roughly follow the format of `VMImageInfo` and `simplestreams`. Once this PR is merged in, the `CustomVMImageHost` will fetch this file from the Multipass GitHub repository. For local developer testing, the environment variable `MULTIPASS_DISTRIBUTIONS_URL` can be set to a local directory, i.e. `file:///Users/you/path/to/your/manifest.json`. Reported images are sorted in descending order by their `remote_name` placing 3rd-party images at the bottom of the list, since the remote name is empty. 2. Ubuntu Core images are now fetched via the `UbuntuVMImageHost` class: Ubuntu Core images utilize [simplestreams](https://cdimage.ubuntu.com/ubuntu-core/streams/v1/com.ubuntu.cdimage:ubuntu-core.json) for distribution. Several tweaks were made to `simple_streams_manifest.cpp` to accommodate them. As a result, core images are also now reported on ARM64 CPU architectures. 3. Golden files extracted out of `test_output_formatter.cpp`: Test files for the formatters are now located under `tests/test_data/formatters/<formatter>/`. This eliminates the need for escaping characters, line length linting, and translating text output from the command line into C++ strings. 4. Removed hardcoded "Ubuntu" strings within formatters, installers, and CLI - remove hardcoded "Ubuntu" strings from `info` and `list` formatters - retroactively populate the image vault with new `OS` field - fix bug where query type was not being loaded from the DB correctly - this function will need to be removed in a future release of Multipass, although the function is idempotent - all pre-existing instances will have the field populated with "Ubuntu" - remove specific references to Ubuntu within the CLI and installer in favour of more generic "cloud VMs/instances" 5. Fedora compatible disk info fetching - Include BTRFS filesystems when counting disk info - Filter out filesystems that are mounted on multiple directories 6. Drive-by fixes: - Determining the location of `test_data` is now done at compile time rather than runtime allowing the use of the location in objects that are constructed at compile time. - Moved image host classes to their own subdirectory and renamed some classes to follow the established inheritance format of `virtual` -> `base` -> implementation. - `test_data` persistence optimization: - When templated test files, i.e. `*\.in$`, are edited or new files are added to `test_data`, a reconfigure is triggered by cmake. - Non-templated test files are persisted into the build directory at compile time if they have been edited. - New exception type; `ImageNotFoundException`, created for when an image is not found. - Optimized sending of `remote_name` in the `FindReply` `protobuf` message type. Fixes #3541 --- MULTI-2048 MULTI-2074 MULTI-2151 MULTI-2153
2 parents 1198313 + 72ae08a commit a819c6e

File tree

188 files changed

+3033
-2243
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

188 files changed

+3033
-2243
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tests/test_data/formatters/** -text

.github/workflows/lint.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ jobs:
3636
uses: ./.github/actions/whitespace
3737
with:
3838
exclude: >-
39-
'3rd-party/' `# third-party submodules`
40-
'data/' `# data files`
41-
'docs/.sphinx/' `# vendored starter pack`
39+
'3rd-party/' `# third-party submodules`
40+
'data/' `# data files`
41+
'docs/.sphinx/' `# vendored starter pack`
42+
'tests/test_data/' `# test data`
4243
4344
- name: Install clang-format
4445
shell: bash
@@ -51,7 +52,11 @@ jobs:
5152
clang-format-16 --dump-config > /dev/null
5253
5354
# On pull requests, HEAD^1 will always be the merge base, so consider that diff for formatting.
54-
git diff -U0 --no-color HEAD^1 | clang-format-diff-16 -p1 | tee ${HOME}/clang-diff
55+
git diff -U0 --no-color HEAD^1 \
56+
| grep -vE '^\+\+\+ b/tests/test_data/formatters/' \
57+
| clang-format-diff-16 -p1 \
58+
| tee ${HOME}/clang-diff
59+
5560
if [ "$( stat --printf='%s' ${HOME}/clang-diff )" -ne 0 ]; then
5661
echo "##[error] Please apply the above diff to correct formatting"
5762
exit 1

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ if("${HOST_OS_NAME}" STREQUAL "macOS")
3333
if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
3434
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0")
3535
else()
36-
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0")
36+
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3")
3737
endif()
3838
elseif("${HOST_OS_NAME}" STREQUAL "Windows")
3939
set(VCPKG_HOST_OS "windows-static-md")
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"Debian": {
3+
"aliases": "debian, trixie",
4+
"items": {
5+
"arm64": {
6+
"id": "sha512:b24a431a9b2664ebd0ce3a1fe28ec48885ae4803a8f6f238a5aeda1ab3d223ed76525f7cd2c7ffc264ea879ee9d26c533c6c4a1951950580aaaf2a42b7f003f5",
7+
"image_location": "https://cloud.debian.org/images/cloud/trixie/20250814-2204/debian-13-generic-arm64-20250814-2204.qcow2",
8+
"size": 425984000,
9+
"version": "20250814"
10+
},
11+
"x86_64": {
12+
"id": "sha512:8f5c54d654b53951430b404efc3043b425cf2214467d5bf33d6c5157fa47c8fe4a1a2abf603050dafc7e54f57e9685f0d59a6c0d09d0cb2b7fcec75561c0df6f",
13+
"image_location": "https://cloud.debian.org/images/cloud/trixie/20250814-2204/debian-13-generic-amd64-20250814-2204.qcow2",
14+
"size": 432472064,
15+
"version": "20250814"
16+
}
17+
},
18+
"os": "Debian",
19+
"release": "trixie",
20+
"release_codename": "Trixie",
21+
"release_title": "13"
22+
},
23+
"Fedora": {
24+
"aliases": "fedora",
25+
"items": {
26+
"arm64": {
27+
"id": "e10658419a8d50231037dc781c3155aa94180a8c7a74e5cac2a6b09eaa9342b7",
28+
"image_location": "https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/aarch64/images/Fedora-Cloud-Base-Generic-42-1.1.aarch64.qcow2",
29+
"size": 533069824,
30+
"version": "20250409"
31+
},
32+
"x86_64": {
33+
"id": "e401a4db2e5e04d1967b6729774faa96da629bcf3ba90b67d8d9cce9906bec0f",
34+
"image_location": "https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2",
35+
"size": 532217856,
36+
"version": "20250409"
37+
}
38+
},
39+
"os": "Fedora",
40+
"release": "",
41+
"release_codename": "42",
42+
"release_title": "42"
43+
}
44+
}

include/multipass/cli/format_utils.h

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ namespace format
3838
static constexpr int col_buffer = 3;
3939

4040
std::string status_string_for(const InstanceStatus& status);
41-
std::string image_string_for(const multipass::FindReply_AliasInfo& alias);
41+
std::string image_string_for(const std::string& remote_name, const std::string& alias);
4242
Formatter* formatter_for(const std::string& format);
4343

4444
template <typename Container>
4545
Container sorted(const Container& items);
4646

47-
void filter_aliases(google::protobuf::RepeatedPtrField<multipass::FindReply_AliasInfo>& aliases);
47+
void filter_aliases(google::protobuf::RepeatedPtrField<std::string>& aliases);
4848

4949
// Computes the column width needed to display all the elements of a range [begin, end). get_width
5050
// is a function which takes as input the element in the range and returns its width in columns.
@@ -135,22 +135,3 @@ Container multipass::format::sorted(const Container& items)
135135

136136
return ret;
137137
}
138-
139-
namespace fmt
140-
{
141-
template <>
142-
struct formatter<multipass::FindReply_AliasInfo>
143-
{
144-
template <typename ParseContext>
145-
constexpr auto parse(ParseContext& ctx)
146-
{
147-
return ctx.begin();
148-
}
149-
150-
template <typename FormatContext>
151-
auto format(const multipass::FindReply_AliasInfo& a, FormatContext& ctx) const
152-
{
153-
return format_to(ctx.out(), "{}", a.alias());
154-
}
155-
};
156-
} // namespace fmt

include/multipass/constants.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ namespace multipass
2727
constexpr auto client_name = "multipass";
2828
constexpr auto daemon_name = "multipassd";
2929

30+
constexpr auto release_remote = "release";
31+
constexpr auto daily_remote = "daily";
3032
constexpr auto snapcraft_remote = "snapcraft";
33+
constexpr auto core_remote = "core";
3134

3235
constexpr auto min_memory_size = "128M";
3336
constexpr auto min_disk_size = "512M";
@@ -44,6 +47,7 @@ constexpr auto home_automount_dir = "Home";
4447

4548
constexpr auto multipass_storage_env_var = "MULTIPASS_STORAGE";
4649
constexpr auto driver_env_var = "MULTIPASS_VM_DRIVER";
50+
constexpr auto distributions_url_env_var = "MULTIPASS_DISTRIBUTIONS_URL";
4751

4852
constexpr auto winterm_profile_guid =
4953
"{aaaa9e6d-1e09-4be6-b76c-82b4ba1885fb}"; // identifies the primary Multipass profile in Windows
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (C) Canonical, Ltd.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; version 3.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
18+
#pragma once
19+
20+
#include <stdexcept>
21+
#include <string>
22+
23+
#include <multipass/format.h>
24+
25+
namespace multipass
26+
{
27+
class ImageNotFoundException : public std::runtime_error
28+
{
29+
public:
30+
ImageNotFoundException(const std::string& hash)
31+
: std::runtime_error{fmt::format("Image with hash \"{}\" not found", hash)}
32+
{
33+
}
34+
};
35+
} // namespace multipass

src/daemon/common_image_host.h renamed to include/multipass/image_host/base_image_host.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818
#pragma once
1919

20-
#include "multipass/vm_image_host.h"
20+
#include <multipass/image_host/vm_image_host.h>
21+
#include <multipass/url_downloader.h>
2122

2223
#include <QStringList>
2324
#include <QTimer>
@@ -27,12 +28,14 @@
2728
namespace multipass
2829
{
2930

30-
class CommonVMImageHost : public VMImageHost
31+
class BaseVMImageHost : public VMImageHost
3132
{
3233
public:
34+
BaseVMImageHost(URLDownloader* downloader);
35+
3336
void for_each_entry_do(const Action& action) final;
3437
VMImageInfo info_for_full_hash(const std::string& full_hash) final;
35-
void update_manifests(const bool is_force_update_from_network);
38+
void update_manifests(const bool force_update);
3639

3740
protected:
3841
void on_manifest_update_failure(const std::string& details);
@@ -41,7 +44,9 @@ class CommonVMImageHost : public VMImageHost
4144
virtual void for_each_entry_do_impl(const Action& action) = 0;
4245
virtual VMImageInfo info_for_full_hash_impl(const std::string& full_hash) = 0;
4346
virtual void clear() = 0;
44-
virtual void fetch_manifests(const bool is_force_update_from_network) = 0;
47+
virtual void fetch_manifests(const bool force_update) = 0;
48+
49+
URLDownloader* const url_downloader;
4550
};
4651

4752
} // namespace multipass

src/daemon/custom_image_host.h renamed to include/multipass/image_host/custom_image_host.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@
1717

1818
#pragma once
1919

20-
#include "common_image_host.h"
20+
#include <multipass/image_host/base_image_host.h>
21+
#include <multipass/vm_image_info.h>
2122

2223
#include <QString>
2324

24-
#include <memory>
2525
#include <string>
26-
#include <unordered_map>
27-
#include <utility>
2826
#include <vector>
2927

3028
namespace multipass
@@ -39,10 +37,10 @@ struct CustomManifest
3937
CustomManifest(std::vector<VMImageInfo>&& images);
4038
};
4139

42-
class CustomVMImageHost final : public CommonVMImageHost
40+
class CustomVMImageHost final : public BaseVMImageHost
4341
{
4442
public:
45-
CustomVMImageHost(const QString& arch, URLDownloader* downloader);
43+
CustomVMImageHost(URLDownloader* downloader);
4644

4745
std::optional<VMImageInfo> info_for(const Query& query) override;
4846
std::vector<std::pair<std::string, VMImageInfo>> all_info_for(const Query& query) override;
@@ -53,13 +51,12 @@ class CustomVMImageHost final : public CommonVMImageHost
5351
private:
5452
void for_each_entry_do_impl(const Action& action) override;
5553
VMImageInfo info_for_full_hash_impl(const std::string& full_hash) override;
56-
void fetch_manifests(const bool is_force_update_from_network) override;
54+
void fetch_manifests(const bool force_update) override;
5755
void clear() override;
5856
CustomManifest* manifest_from(const std::string& remote_name);
5957

6058
const QString arch;
61-
URLDownloader* const url_downloader;
62-
std::unordered_map<std::string, std::unique_ptr<CustomManifest>> custom_image_info;
63-
std::vector<std::string> remotes;
59+
std::pair<std::string, std::unique_ptr<CustomManifest>> manifest;
60+
std::string remote;
6461
};
6562
} // namespace multipass
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) Canonical, Ltd.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; version 3.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
*/
17+
18+
#pragma once
19+
20+
#include <multipass/vm_image_info.h>
21+
22+
namespace multipass::image_mutators
23+
{
24+
bool snapcraft_mutator(VMImageInfo& info);
25+
bool core_mutator(VMImageInfo& info);
26+
bool release_mutator(VMImageInfo& info);
27+
} // namespace multipass::image_mutators

0 commit comments

Comments
 (0)