fn handle_host_container()

in sources/api/host-containers/src/main.rs [361:451]


fn handle_host_container<S>(name: S, image_details: &model::HostContainer) -> Result<()>
where
    S: AsRef<str>,
{
    // Get basic settings, as retrieved from API.
    let name = name.as_ref();
    let source = image_details.source.as_ref().context(error::MissingField {
        name,
        field: "source",
    })?;
    let enabled = image_details.enabled.unwrap_or(false);
    let superpowered = image_details.superpowered.unwrap_or(false);

    info!(
        "Host container '{}' is enabled: {}, superpowered: {}, with source: {}",
        name, enabled, superpowered, source
    );

    // Create the directory regardless if user data was provided for the container
    let dir = Path::new(PERSISTENT_STORAGE_BASE_DIR).join(name);
    fs::create_dir_all(&dir).context(error::Mkdir { dir: &dir })?;
    fs::set_permissions(&dir, fs::Permissions::from_mode(0o700))
        .context(error::SetPermissions { name })?;

    // If user data was specified, unencode it and write it out before we start the container.
    if let Some(user_data) = &image_details.user_data {
        let decoded_bytes =
            base64::decode(user_data.as_bytes()).context(error::Base64Decode { name })?;

        let path = dir.join("user-data");
        fs::write(path, decoded_bytes).context(error::UserDataWrite { name })?;
    }

    // Write the environment file needed for the systemd service to have details about this
    // specific host container
    write_env_file(name, source, enabled, superpowered)?;

    // Now start/stop the container according to the 'enabled' setting
    let unit_name = format!("host-containers@{}.service", name);
    let systemd_unit = SystemdUnit::new(&unit_name);
    let host_containerd_unit = SystemdUnit::new("host-containerd.service");

    if enabled {
        // If this particular host-container was previously disabled. Let's make sure there's no
        // lingering container tasks left over previously that host-ctr might bind to.
        // We want to ensure we're running the host-container with the latest configuration.
        //
        // We only attempt to do this only if host-containerd is active and running
        if host_containerd_unit.is_active()? && !systemd_unit.is_enabled()? {
            command(
                constants::HOST_CTR_BIN,
                &["clean-up", "--container-id", name],
            )?;
        }

        // Only start the host container if the systemd target is 'multi-user', otherwise
        // it will start before the system is fully configured
        match command(constants::SYSTEMCTL_BIN, &["get-default"])?
            .trim()
            .as_ref()
        {
            "multi-user.target" => {
                if systemd_unit.is_active()? {
                    debug!("Stopping and starting host container: '{}'", unit_name);
                    systemd_unit.try_reload_or_restart()?
                } else {
                    debug!("Enabling and starting container: '{}'", unit_name);
                    systemd_unit.enable_and_start()?
                }
            }
            _ => {
                debug!("Enabling: '{}'", unit_name);
                systemd_unit.enable()?
            }
        };
    } else {
        systemd_unit.disable_and_stop()?;

        // Ensure there's no lingering host-container after it's been disabled.
        //
        // We only attempt to do this only if host-containerd is active and running
        if host_containerd_unit.is_active()? {
            command(
                constants::HOST_CTR_BIN,
                &["clean-up", "--container-id", name],
            )?;
        }
    }

    Ok(())
}