Skip to content

Commit

Permalink
feat: Allow use of akmods module (#71)
Browse files Browse the repository at this point in the history
The akmods module require having the /rpms directory put into /tmp/rpms.
By default we will mount the akmods image with the `main-{{ os_version
}}` tag.

If a user supplies `base` for the akmods module in their recipe, it will
pull that image tag instead and mount the resulting /rpms.

```yaml
modules:
- type: akmods
  base: surface
  install:
  - openrazer
```

This would pull the image `ghcr.io/ublue-os/akmods:surface-39`.

A user can also supply `nvidia-version` with the numerical version of
the driver you would like to use. Doing so will mount the appropriate
`akmods-nvidia` image with the version of the driver you want in the
tag.

```yaml
modules:
- type: akmods
  nvidia-version: 545
  install:
  - nvidia
```

This would pull the image `ghcr.io/ublue-os/akmods-nvidia:main-39-545`
and `ghcr.io/ublue-os/akmods:main-39`.

This uses bind mount like all the other modules so these files will not
persist into the final image.
  • Loading branch information
gmpinder authored Feb 22, 2024
1 parent ee2a834 commit 8931a22
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 14 deletions.
11 changes: 10 additions & 1 deletion integration-tests/test-repo/config/recipe.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ name: template
description: This is my personal OS image.

# the base image to build on top of (FROM) and the version tag to use
base-image: ghcr.io/ublue-os/silverblue-main
base-image: ghcr.io/ublue-os/silverblue-surface
image-version: 39 # latest is also supported if you want new updates ASAP

# module configuration, executed in order
# you can include multiple instances of the same module
modules:
- type: akmods
base: surface
nvidia-version: 545
install:
- nvidia
- openrazer
- type: akmods
install:
- openrgb
- type: files
files:
- usr: /usr # copies config/files/usr into your image's /usr.
Expand Down
58 changes: 56 additions & 2 deletions src/commands/template.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
collections::HashSet,
env, fs,
path::{Path, PathBuf},
process,
Expand All @@ -13,7 +14,7 @@ use uuid::Uuid;

use crate::{
constants::*,
module_recipe::{Module, Recipe},
module_recipe::{Module, ModuleExt, Recipe},
};

use super::BlueBuildCommand;
Expand Down Expand Up @@ -166,7 +167,7 @@ fn get_containerfile_snippets(module: &Module) -> Option<Vec<String>> {

#[must_use]
fn print_containerfile(containerfile: &str) -> String {
debug!("print_containerfile({containerfile})");
trace!("print_containerfile({containerfile})");
debug!("Loading containerfile contents for {containerfile}");

let path = format!("config/containerfiles/{containerfile}/Containerfile");
Expand Down Expand Up @@ -222,3 +223,56 @@ fn get_gitlab_registry_path() -> Option<String> {
.to_lowercase(),
)
}

#[derive(Debug, Clone, TypedBuilder, PartialEq, Eq, Hash)]
struct AkmodsInfo {
images: (String, Option<String>),
stage_name: String,
}

fn get_akmods_info_list(module_ext: &ModuleExt, os_version: &str) -> Vec<AkmodsInfo> {
trace!("get_akmods_image_list({module_ext:#?}, {os_version})");

let mut seen = HashSet::new();

module_ext
.modules
.iter()
.filter(|module| module.module_type.as_ref().is_some_and(|t| t == "akmods"))
.map(|module| generate_akmods_info(module, os_version))
.filter(|image| seen.insert(image.clone()))
.collect()
}

fn generate_akmods_info(module: &Module, os_version: &str) -> AkmodsInfo {
trace!("generate_akmods_base({module:#?}, {os_version})");

let base = module
.config
.get("base")
.map(|b| b.as_str().unwrap_or_default());
let nvidia_version = module
.config
.get("nvidia-version")
.map(|v| v.as_u64().unwrap_or_default());

AkmodsInfo::builder()
.images(match (base, nvidia_version) {
(Some(b), Some(nv)) if !b.is_empty() && nv > 0 => (
format!("akmods:{b}-{os_version}"),
Some(format!("akmods-nvidia:{b}-{os_version}-{nv}")),
),
(Some(b), _) if !b.is_empty() => (format!("akmods:{b}-{os_version}"), None),
(_, Some(nv)) if nv > 0 => (
format!("akmods:main-{os_version}"),
Some(format!("akmods-nvidia:main-{os_version}")),
),
_ => (format!("akmods:main-{os_version}"), None),
})
.stage_name(format!(
"{}{}",
base.unwrap_or("main"),
nvidia_version.map_or_else(String::default, |nv| format!("-{nv}"))
))
.build()
}
2 changes: 1 addition & 1 deletion src/module_recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ impl<'a> Recipe<'a> {
Ok(recipe)
}

fn get_os_version(&self) -> String {
pub fn get_os_version(&self) -> String {
trace!("Recipe::get_os_version()");

if check_command_exists("skopeo").is_err() {
Expand Down
31 changes: 21 additions & 10 deletions templates/Containerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{%- let os_version = recipe.get_os_version() %}
# This stage is responsible for holding onto
# your config without copying it directly into
# the final image
Expand All @@ -11,6 +12,14 @@ FROM scratch as stage-modules
COPY --from=ghcr.io/ublue-os/bling:latest /modules /modules
COPY ./modules /modules

{%- for info in self::get_akmods_info_list(recipe.modules_ext, os_version) %}
FROM scratch as stage-akmods-{{ info.stage_name }}
COPY --from=ghcr.io/ublue-os/{{ info.images.0 }} /rpms /rpms
{%- if let Some(nv_image) = info.images.1 %}
COPY --from=ghcr.io/ublue-os/{{ nv_image }} /rpms /rpms
{%- endif %}
{%- endfor %}

# This stage is responsible for holding onto
# exports like the exports.sh
FROM docker.io/alpine as stage-exports
Expand All @@ -37,16 +46,6 @@ ARG IMAGE_REGISTRY=localhost
COPY cosign.pub /usr/share/ublue-os/cosign.pub
{%- endif %}

COPY --from=docker.io/mikefarah/yq /usr/bin/yq /usr/bin/yq
COPY --from=gcr.io/projectsigstore/cosign /ko-app/cosign /usr/bin/cosign

COPY --from=ghcr.io/blue-build/cli:
{%- if let Some(tag) = recipe.blue_build_tag -%}
{{ tag }}
{%- else -%}
latest-installer
{%- endif %} /out/bluebuild /usr/bin/bluebuild

ARG CONFIG_DIRECTORY="/tmp/config"
ARG IMAGE_NAME="{{ recipe.name }}"
ARG BASE_IMAGE="{{ recipe.base_image }}"
Expand Down Expand Up @@ -74,12 +73,16 @@ COPY {{ src }} {{ dest }}
RUN \
--mount=type=tmpfs,target=/tmp \
--mount=type=tmpfs,target=/var \
--mount=type=bind,from=docker.io/mikefarah/yq,src=/usr/bin/yq,dst=/usr/bin/yq \
--mount=type=bind,from=stage-config,src=/config,dst=/tmp/config,rw \
{%- if let Some(source) = module.source %}
--mount=type=bind,from={{ source }},src=/modules,dst=/tmp/modules,rw \
{%- else %}
--mount=type=bind,from=stage-modules,src=/modules,dst=/tmp/modules,rw \
{%- endif %}
{%- if type == "akmods" %}
--mount=type=bind,from=stage-akmods-{{ self::generate_akmods_info(module, os_version).stage_name }},src=/rpms,dst=/tmp/rpms,rw \
{%- endif %}
--mount=type=bind,from=stage-exports,src=/exports.sh,dst=/tmp/exports.sh \
--mount=type=cache,dst=/var/cache/rpm-ostree,id=rpm-ostree-cache-{{ recipe.name }}-{{ recipe.image_version }},sharing=locked \
chmod +x /tmp/modules/{{ type }}/{{ type }}.sh \
Expand All @@ -88,4 +91,12 @@ RUN \
{%- endif %}
{%- endfor %}

COPY --from=gcr.io/projectsigstore/cosign /ko-app/cosign /usr/bin/cosign
COPY --from=ghcr.io/blue-build/cli:
{%- if let Some(tag) = recipe.blue_build_tag -%}
{{ tag }}
{%- else -%}
latest-installer
{%- endif %} /out/bluebuild /usr/bin/bluebuild

RUN ostree container commit

0 comments on commit 8931a22

Please sign in to comment.