core: Also refresh confext extensions when reloading notify-reload service (#33995)
`ExtensionImages=` and `ExtensionDirectories=` now let you specify vpick-named extensions; however, since they just get set up once when the service is started, you can't see newer versions without restarting the service entirely. Here, also reload confext extensions when you reload a service. This allows you to deploy a new version of some configuration and have it picked up at reload time without interruption to your workload. Right now, we would only reload confext extensions and leave the sysext ones behind, since it didn't seem prudent to swap out what is likely program code at reload. This is made possible by only going for the `SYSTEMD_CONFEXT_HIERARCHIES` overlays (which only contains `/etc`). This PR: - Adjusts `service.c` to also refresh extensions when needed. - Adds integration tests to check that a confext reload actually occurred. - Adds to the `systemd.exec` man pages to document this behavior. This is a follow up to #24864 and #31364. Thank you to @bluca and @goenkam for help in getting this up.
This commit is contained in:
+22
-15
@@ -4289,6 +4289,7 @@ int verity_dissect_and_mount(
|
||||
const ImagePolicy *image_policy,
|
||||
const ImageFilter *image_filter,
|
||||
const ExtensionReleaseData *extension_release_data,
|
||||
ImageClass required_class,
|
||||
VeritySettings *verity,
|
||||
DissectedImage **ret_image) {
|
||||
|
||||
@@ -4400,15 +4401,19 @@ int verity_dissect_and_mount(
|
||||
* extension-release.d/ content. Return -EINVAL if there's any mismatch.
|
||||
* First, check the distro ID. If that matches, then check the new SYSEXT_LEVEL value if
|
||||
* available, or else fallback to VERSION_ID. If neither is present (eg: rolling release),
|
||||
* then a simple match on the ID will be performed. */
|
||||
if (extension_release_data && extension_release_data->os_release_id) {
|
||||
* then a simple match on the ID will be performed. Also if an extension class was specified,
|
||||
* check that it matches or return ENOCSI (which looks like error-no-class if one squints enough). */
|
||||
if ((extension_release_data && extension_release_data->os_release_id) || required_class >= 0) {
|
||||
_cleanup_strv_free_ char **extension_release = NULL;
|
||||
ImageClass class = IMAGE_SYSEXT;
|
||||
|
||||
assert(!isempty(extension_release_data->os_release_id));
|
||||
|
||||
r = load_extension_release_pairs(dest, IMAGE_SYSEXT, dissected_image->image_name, relax_extension_release_check, &extension_release);
|
||||
r = load_extension_release_pairs(dest, required_class >= 0 ? required_class : IMAGE_SYSEXT, dissected_image->image_name, relax_extension_release_check, &extension_release);
|
||||
if (r == -ENOENT) {
|
||||
if (required_class >= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOCSI), "Image %s extension-release metadata does not match the expected class", dissected_image->image_name);
|
||||
|
||||
r = load_extension_release_pairs(dest, IMAGE_CONFEXT, dissected_image->image_name, relax_extension_release_check, &extension_release);
|
||||
if (r >= 0)
|
||||
class = IMAGE_CONFEXT;
|
||||
@@ -4416,18 +4421,20 @@ int verity_dissect_and_mount(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse image %s extension-release metadata: %m", dissected_image->image_name);
|
||||
|
||||
r = extension_release_validate(
|
||||
dissected_image->image_name,
|
||||
extension_release_data->os_release_id,
|
||||
extension_release_data->os_release_version_id,
|
||||
class == IMAGE_SYSEXT ? extension_release_data->os_release_sysext_level : extension_release_data->os_release_confext_level,
|
||||
extension_release_data->os_release_extension_scope,
|
||||
extension_release,
|
||||
class);
|
||||
if (r == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", dissected_image->image_name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", dissected_image->image_name);
|
||||
if (extension_release_data && !isempty(extension_release_data->os_release_id)) {
|
||||
r = extension_release_validate(
|
||||
dissected_image->image_name,
|
||||
extension_release_data->os_release_id,
|
||||
extension_release_data->os_release_version_id,
|
||||
class == IMAGE_SYSEXT ? extension_release_data->os_release_sysext_level : extension_release_data->os_release_confext_level,
|
||||
extension_release_data->os_release_extension_scope,
|
||||
extension_release,
|
||||
class);
|
||||
if (r == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", dissected_image->image_name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", dissected_image->image_name);
|
||||
}
|
||||
}
|
||||
|
||||
r = dissected_image_relinquish(dissected_image);
|
||||
|
||||
@@ -255,7 +255,7 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi
|
||||
|
||||
int mount_image_privately_interactively(const char *path, const ImagePolicy *image_policy, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, LoopDevice **ret_loop_device);
|
||||
|
||||
int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const ImageFilter *image_filter, const ExtensionReleaseData *required_release_data, VeritySettings *verity, DissectedImage **ret_image);
|
||||
int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const ImageFilter *image_filter, const ExtensionReleaseData *required_release_data, ImageClass required_class, VeritySettings *verity, DissectedImage **ret_image);
|
||||
|
||||
int dissect_fstype_ok(const char *fstype);
|
||||
|
||||
|
||||
+15
-4
@@ -972,6 +972,7 @@ static int mount_in_namespace_legacy(
|
||||
image_policy,
|
||||
/* image_filter= */ NULL,
|
||||
/* extension_release_data= */ NULL,
|
||||
/* required_class= */ _IMAGE_CLASS_INVALID,
|
||||
/* verity= */ NULL,
|
||||
/* ret_image= */ NULL);
|
||||
else
|
||||
@@ -1193,6 +1194,7 @@ static int mount_in_namespace(
|
||||
image_policy,
|
||||
/* image_filter= */ NULL,
|
||||
/* extension_release_data= */ NULL,
|
||||
/* required_class= */ _IMAGE_CLASS_INVALID,
|
||||
/* verity= */ NULL,
|
||||
&img);
|
||||
if (r < 0)
|
||||
@@ -1881,11 +1883,12 @@ char* umount_and_unlink_and_free(char *p) {
|
||||
return mfree(p);
|
||||
}
|
||||
|
||||
static int path_get_mount_info_at(
|
||||
int path_get_mount_info_at(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
char **ret_fstype,
|
||||
char **ret_options) {
|
||||
char **ret_options,
|
||||
char **ret_source) {
|
||||
|
||||
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
|
||||
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
|
||||
@@ -1918,7 +1921,7 @@ static int path_get_mount_info_at(
|
||||
if (mnt_fs_get_id(fs) != mnt_id)
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char *fstype = NULL, *options = NULL;
|
||||
_cleanup_free_ char *fstype = NULL, *options = NULL, *source = NULL;
|
||||
|
||||
if (ret_fstype) {
|
||||
fstype = strdup(strempty(mnt_fs_get_fstype(fs)));
|
||||
@@ -1932,10 +1935,18 @@ static int path_get_mount_info_at(
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
if (ret_source) {
|
||||
source = strdup(strempty(mnt_fs_get_source(fs)));
|
||||
if (!source)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
if (ret_fstype)
|
||||
*ret_fstype = TAKE_PTR(fstype);
|
||||
if (ret_options)
|
||||
*ret_options = TAKE_PTR(options);
|
||||
if (ret_source)
|
||||
*ret_source = TAKE_PTR(source);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1958,7 +1969,7 @@ int path_is_network_fs_harder_at(int dir_fd, const char *path) {
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *fstype = NULL, *options = NULL;
|
||||
r = path_get_mount_info_at(fd, /* path = */ NULL, &fstype, &options);
|
||||
r = path_get_mount_info_at(fd, /* path = */ NULL, &fstype, &options, /* source = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -189,6 +189,11 @@ int mount_credentials_fs(const char *path, size_t size, bool ro);
|
||||
|
||||
int make_fsmount(int error_log_level, const char *what, const char *type, unsigned long flags, const char *options, int userns_fd);
|
||||
|
||||
int path_get_mount_info_at(int dir_fd, const char *path, char **ret_fstype, char **ret_options, char **ret_source);
|
||||
static inline int path_get_mount_info(const char *path, char **ret_fstype, char **ret_options, char **ret_source) {
|
||||
return path_get_mount_info_at(AT_FDCWD, path, ret_fstype, ret_options, ret_source);
|
||||
}
|
||||
|
||||
int path_is_network_fs_harder_at(int dir_fd, const char *path);
|
||||
static inline int path_is_network_fs_harder(const char *path) {
|
||||
return path_is_network_fs_harder_at(AT_FDCWD, path);
|
||||
|
||||
@@ -691,6 +691,41 @@ int path_pick_update_warn(
|
||||
return 1;
|
||||
}
|
||||
|
||||
int path_uses_vpick(const char *path) {
|
||||
_cleanup_free_ char *dir = NULL, *parent = NULL, *fname = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
r = path_extract_filename(path, &fname);
|
||||
if (r == -EADDRNOTAVAIL)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* ...PATH/NAME.SUFFIX.v */
|
||||
if (endswith(fname, ".v"))
|
||||
return 1;
|
||||
|
||||
/* ...PATH.v/NAME___.SUFFIX */
|
||||
if (!strrstr(fname, "___"))
|
||||
return 0;
|
||||
|
||||
r = path_extract_directory(path, &dir);
|
||||
if (IN_SET(r, -EDESTADDRREQ, -EADDRNOTAVAIL)) /* only filename specified (no dir), or root or "." */
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_filename(dir, &parent);
|
||||
if (r == -EADDRNOTAVAIL)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return !!endswith(parent, ".v");
|
||||
}
|
||||
|
||||
const PickFilter pick_filter_image_raw = {
|
||||
.type_mask = (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK),
|
||||
.architecture = _ARCHITECTURE_INVALID,
|
||||
|
||||
@@ -57,6 +57,8 @@ int path_pick_update_warn(
|
||||
PickFlags flags,
|
||||
PickResult *ret);
|
||||
|
||||
int path_uses_vpick(const char *path);
|
||||
|
||||
extern const PickFilter pick_filter_image_raw;
|
||||
extern const PickFilter pick_filter_image_dir;
|
||||
extern const PickFilter pick_filter_image_any;
|
||||
|
||||
Reference in New Issue
Block a user