uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead

https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948
this can do it nicely.

Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
Anton Arapov 2021-04-03 12:58:10 +02:00 committed by Alan Daniels
commit 56de2bcd43
30691 changed files with 3076956 additions and 0 deletions

View file

@ -0,0 +1,192 @@
{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
# provide an option name, as a string literal.
, testOption ? null
# provide a list of option names, as string literals.
, testOptions ? [ ]
}:
# This file is made to be used as follow:
#
# $ nix-instantiate ./option-usage.nix --argstr testOption service.xserver.enable -A txtContent --eval
#
# or
#
# $ nix-build ./option-usage.nix --argstr testOption service.xserver.enable -A txt -o service.xserver.enable._txt
#
# Other targets exists such as `dotContent`, `dot`, and `pdf`. If you are
# looking for the option usage of multiple options, you can provide a list
# as argument.
#
# $ nix-build ./option-usage.nix --arg testOptions \
# '["boot.loader.gummiboot.enable" "boot.loader.gummiboot.timeout"]' \
# -A txt -o gummiboot.list
#
# Note, this script is slow as it has to evaluate all options of the system
# once per queried option.
#
# This nix expression works by doing a first evaluation, which evaluates the
# result of every option.
#
# Then, for each queried option, we evaluate the NixOS modules a second
# time, except that we replace the `config` argument of all the modules with
# the result of the original evaluation, except for the tested option which
# value is replaced by a `throw` statement which is caught by the `tryEval`
# evaluation of each option value.
#
# We then compare the result of the evaluation of the original module, with
# the result of the second evaluation, and consider that the new failures are
# caused by our mutation of the `config` argument.
#
# Doing so returns all option results which are directly using the
# tested option result.
with import ../../lib;
let
evalFun = {
specialArgs ? {}
}: import ../lib/eval-config.nix {
modules = [ configuration ];
inherit specialArgs;
};
eval = evalFun {};
inherit (eval) pkgs;
excludedTestOptions = [
# We cannot evluate _module.args, as it is used during the computation
# of the modules list.
"_module.args"
# For some reasons which we yet have to investigate, some options cannot
# be replaced by a throw without causing a non-catchable failure.
"networking.bonds"
"networking.bridges"
"networking.interfaces"
"networking.macvlans"
"networking.sits"
"networking.vlans"
"services.openssh.startWhenNeeded"
];
# for some reasons which we yet have to investigate, some options are
# time-consuming to compute, thus we filter them out at the moment.
excludedOptions = [
"boot.systemd.services"
"systemd.services"
"kde.extraPackages"
];
excludeOptions = list:
filter (opt: !(elem (showOption opt.loc) excludedOptions)) list;
reportNewFailures = old: new:
let
filterChanges =
filter ({fst, snd}:
!(fst.success -> snd.success)
);
keepNames =
map ({fst, snd}:
/* assert fst.name == snd.name; */ snd.name
);
# Use tryEval (strict ...) to know if there is any failure while
# evaluating the option value.
#
# Note, the `strict` function is not strict enough, but using toXML
# builtins multiply by 4 the memory usage and the time used to compute
# each options.
tryCollectOptions = moduleResult:
forEach (excludeOptions (collect isOption moduleResult)) (opt:
{ name = showOption opt.loc; } // builtins.tryEval (strict opt.value));
in
keepNames (
filterChanges (
zipLists (tryCollectOptions old) (tryCollectOptions new)
)
);
# Create a list of modules where each module contains only one failling
# options.
introspectionModules =
let
setIntrospection = opt: rec {
name = showOption opt.loc;
path = opt.loc;
config = setAttrByPath path
(throw "Usage introspection of '${name}' by forced failure.");
};
in
map setIntrospection (collect isOption eval.options);
overrideConfig = thrower:
recursiveUpdateUntil (path: old: new:
path == thrower.path
) eval.config thrower.config;
graph =
map (thrower: {
option = thrower.name;
usedBy = assert __trace "Investigate ${thrower.name}" true;
reportNewFailures eval.options (evalFun {
specialArgs = {
config = overrideConfig thrower;
};
}).options;
}) introspectionModules;
displayOptionsGraph =
let
checkList =
if testOption != null then [ testOption ]
else testOptions;
checkAll = checkList == [];
in
flip filter graph ({option, ...}:
(checkAll || elem option checkList)
&& !(elem option excludedTestOptions)
);
graphToDot = graph: ''
digraph "Option Usages" {
${concatMapStrings ({option, usedBy}:
concatMapStrings (user: ''
"${option}" -> "${user}"''
) usedBy
) displayOptionsGraph}
}
'';
graphToText = graph:
concatMapStrings ({usedBy, ...}:
concatMapStrings (user: ''
${user}
'') usedBy
) displayOptionsGraph;
in
rec {
dotContent = graphToDot graph;
dot = pkgs.writeTextFile {
name = "option_usages.dot";
text = dotContent;
};
pdf = pkgs.texFunctions.dot2pdf {
dotGraph = dot;
};
txtContent = graphToText graph;
txt = pkgs.writeTextFile {
name = "option_usages.txt";
text = txtContent;
};
}

View file

@ -0,0 +1 @@
azure

View file

@ -0,0 +1,42 @@
# azure
## Demo
Here's a demo of this being used: https://asciinema.org/a/euXb9dIeUybE3VkstLWLbvhmp
## Usage
This is meant to be an example image that you can copy into your own
project and modify to your own needs. Notice that the example image
includes a built-in test user account, which by default uses your
`~/.ssh/id_ed25519.pub` as an `authorized_key`.
Build and upload the image
```shell
$ ./upload-image.sh ./examples/basic/image.nix
...
+ attr=azbasic
+ nix-build ./examples/basic/image.nix --out-link azure
/nix/store/qdpzknpskzw30vba92mb24xzll1dqsmd-azure-image
...
95.5 %, 0 Done, 0 Failed, 1 Pending, 0 Skipped, 1 Total, 2-sec Throughput (Mb/s): 932.9565
...
/subscriptions/aff271ee-e9be-4441-b9bb-42f5af4cbaeb/resourceGroups/nixos-images/providers/Microsoft.Compute/images/azure-image-todo-makethisbetter
```
Take the output, boot an Azure VM:
```
img="/subscriptions/.../..." # use output from last command
./boot-vm.sh "${img}"
...
=> booted
```
## Future Work
1. If the user specifies a hard-coded user, then the agent could be removed.
Probably has security benefits; definitely has closure-size benefits.
(It's likely the VM will need to be booted with a special flag. See:
https://github.com/Azure/azure-cli/issues/12775 for details.)

View file

@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
set -x
image="${1}"
location="westus2"
group="nixos-test-vm"
vm_size="Standard_D2s_v3"; os_size=42;
# ensure group
az group create --location "westus2" --name "${group}"
group_id="$(az group show --name "${group}" -o tsv --query "[id]")"
# (optional) identity
if ! az identity show -n "${group}-identity" -g "${group}" &>/dev/stderr; then
az identity create --name "${group}-identity" --resource-group "${group}"
fi
# (optional) role assignment, to the resource group, bad but not really great alternatives
identity_id="$(az identity show --name "${group}-identity" --resource-group "${group}" -o tsv --query "[id]")"
principal_id="$(az identity show --name "${group}-identity" --resource-group "${group}" -o tsv --query "[principalId]")"
until az role assignment create --assignee "${principal_id}" --role "Owner" --scope "${group_id}"; do sleep 1; done
# boot vm
az vm create \
--name "${group}-vm" \
--resource-group "${group}" \
--assign-identity "${identity_id}" \
--size "${vm_size}" \
--os-disk-size-gb "${os_size}" \
--image "${image}" \
--admin-username "${USER}" \
--location "westus2" \
--storage-sku "Premium_LRS" \
--ssh-key-values "$(ssh-add -L)"

View file

@ -0,0 +1,7 @@
export group="${AZURE_RESOURCE_GROUP:-"azure"}"
export location="${AZURE_LOCATION:-"westus2"}"
img_file=$(echo azure/*.vhd)
img_name="$(basename "${img_file}")"
img_name="${img_name%".vhd"}"
export img_name="${img_name//[._]/-}"

View file

@ -0,0 +1,10 @@
let
pkgs = (import ../../../../../../default.nix {});
machine = import (pkgs.path + "/nixos/lib/eval-config.nix") {
system = "x86_64-linux";
modules = [
({config, ...}: { imports = [ ./system.nix ]; })
];
};
in
machine.config.system.build.azureImage

View file

@ -0,0 +1,34 @@
{ pkgs, modulesPath, ... }:
let username = "azurenixosuser";
in
{
imports = [
"${modulesPath}/virtualisation/azure-common.nix"
"${modulesPath}/virtualisation/azure-image.nix"
];
## NOTE: This is just an example of how to hard-code a user.
## The normal Azure agent IS included and DOES provision a user based
## on the information passed at VM creation time.
users.users."${username}" = {
isNormalUser = true;
home = "/home/${username}";
description = "Azure NixOS Test User";
openssh.authorizedKeys.keys = [ (builtins.readFile ~/.ssh/id_ed25519.pub) ];
};
nix.settings.trusted-users = [ username ];
virtualisation.azureImage.diskSize = 2500;
system.stateVersion = "20.03";
boot.kernelPackages = pkgs.linuxPackages_latest;
# test user doesn't have a password
services.openssh.passwordAuthentication = false;
security.sudo.wheelNeedsPassword = false;
environment.systemPackages = with pkgs; [
git file htop wget curl
];
}

View file

@ -0,0 +1,13 @@
with (import ../../../../default.nix {});
stdenv.mkDerivation {
name = "nixcfg-azure-devenv";
nativeBuildInputs = [
azure-cli
bash
cacert
azure-storage-azcopy
];
AZURE_CONFIG_DIR="/tmp/azure-cli/.azure";
}

View file

@ -0,0 +1,58 @@
#!/usr/bin/env bash
set -euo pipefail
set -x
image_nix="${1:-"./examples/basic/image.nix"}"
nix-build "${image_nix}" --out-link "azure"
group="nixos-images"
location="westus2"
img_name="nixos-image"
img_file="$(readlink -f ./azure/disk.vhd)"
if ! az group show -n "${group}" &>/dev/null; then
az group create --name "${group}" --location "${location}"
fi
# note: the disk access token song/dance is tedious
# but allows us to upload direct to a disk image
# thereby avoid storage accounts (and naming them) entirely!
if ! az disk show -g "${group}" -n "${img_name}" &>/dev/null; then
bytes="$(stat -c %s ${img_file})"
size="30"
az disk create \
--resource-group "${group}" \
--name "${img_name}" \
--for-upload true --upload-size-bytes "${bytes}"
timeout=$(( 60 * 60 )) # disk access token timeout
sasurl="$(\
az disk grant-access \
--access-level Write \
--resource-group "${group}" \
--name "${img_name}" \
--duration-in-seconds ${timeout} \
| jq -r '.accessSas'
)"
azcopy copy "${img_file}" "${sasurl}" \
--blob-type PageBlob
az disk revoke-access \
--resource-group "${group}" \
--name "${img_name}"
fi
if ! az image show -g "${group}" -n "${img_name}" &>/dev/null; then
diskid="$(az disk show -g "${group}" -n "${img_name}" -o json | jq -r .id)"
az image create \
--resource-group "${group}" \
--name "${img_name}" \
--source "${diskid}" \
--os-type "linux" >/dev/null
fi
imageid="$(az image show -g "${group}" -n "${img_name}" -o json | jq -r .id)"
echo "${imageid}"

View file

@ -0,0 +1,8 @@
#! /bin/sh -eu
export NIX_PATH=nixpkgs=$(dirname $(readlink -f $0))/../../../..
export NIXOS_CONFIG=$(dirname $(readlink -f $0))/../../../modules/virtualisation/azure-image.nix
export TIMESTAMP=$(date +%Y%m%d%H%M)
nix-build '<nixpkgs/nixos>' \
-A config.system.build.azureImage --argstr system x86_64-linux -o azure -j 10

View file

@ -0,0 +1,22 @@
#! /bin/sh -e
export STORAGE=${STORAGE:-nixos}
export THREADS=${THREADS:-8}
azure-vhd-utils-for-go upload --localvhdpath azure/disk.vhd --stgaccountname "$STORAGE" --stgaccountkey "$KEY" \
--containername images --blobname nixos-unstable-nixops-updated.vhd --parallelism "$THREADS" --overwrite

View file

@ -0,0 +1,22 @@
# nix-build '<nixpkgs/nixos>' -A config.system.build.cloudstackImage --arg configuration "{ imports = [ ./nixos/maintainers/scripts/cloudstack/cloudstack-image.nix ]; }"
{ config, lib, pkgs, ... }:
with lib;
{
imports =
[ ../../../modules/virtualisation/cloudstack-config.nix ];
system.build.cloudstackImage = import ../../../lib/make-disk-image.nix {
inherit lib config pkgs;
format = "qcow2";
configFile = pkgs.writeText "configuration.nix"
''
{
imports = [ <nixpkgs/nixos/modules/virtualisation/cloudstack-config.nix> ];
}
'';
};
}

View file

@ -0,0 +1,12 @@
{
imports = [ ./amazon-image.nix ];
ec2.zfs = {
enable = true;
datasets = {
"tank/system/root".mount = "/";
"tank/system/var".mount = "/var";
"tank/local/nix".mount = "/nix";
"tank/user/home".mount = "/home";
};
};
}

View file

@ -0,0 +1,165 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.amazonImage;
amiBootMode = if config.ec2.efi then "uefi" else "legacy-bios";
in {
imports = [ ../../../modules/virtualisation/amazon-image.nix ];
# Amazon recomments setting this to the highest possible value for a good EBS
# experience, which prior to 4.15 was 255.
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html#timeout-nvme-ebs-volumes
config.boot.kernelParams =
let timeout =
if pkgs.lib.versionAtLeast config.boot.kernelPackages.kernel.version "4.15"
then "4294967295"
else "255";
in [ "nvme_core.io_timeout=${timeout}" ];
options.amazonImage = {
name = mkOption {
type = types.str;
description = "The name of the generated derivation";
default = "nixos-amazon-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}";
};
contents = mkOption {
example = literalExpression ''
[ { source = pkgs.memtest86 + "/memtest.bin";
target = "boot/memtest.bin";
}
]
'';
default = [];
description = ''
This option lists files to be copied to fixed locations in the
generated image. Glob patterns work.
'';
};
sizeMB = mkOption {
type = with types; either (enum [ "auto" ]) int;
default = if config.ec2.hvm then 2048 else 8192;
example = 8192;
description = "The size in MB of the image";
};
format = mkOption {
type = types.enum [ "raw" "qcow2" "vpc" ];
default = "vpc";
description = "The image format to output";
};
};
config.system.build.amazonImage = let
configFile = pkgs.writeText "configuration.nix"
''
{ modulesPath, ... }: {
imports = [ "''${modulesPath}/virtualisation/amazon-image.nix" ];
${optionalString config.ec2.hvm ''
ec2.hvm = true;
''}
${optionalString config.ec2.efi ''
ec2.efi = true;
''}
${optionalString config.ec2.zfs.enable ''
ec2.zfs.enable = true;
networking.hostId = "${config.networking.hostId}";
''}
}
'';
zfsBuilder = import ../../../lib/make-multi-disk-zfs-image.nix {
inherit lib config configFile;
inherit (cfg) contents format name;
pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
includeChannel = true;
bootSize = 1000; # 1G is the minimum EBS volume
rootSize = cfg.sizeMB;
rootPoolProperties = {
ashift = 12;
autoexpand = "on";
};
datasets = config.ec2.zfs.datasets;
postVM = ''
extension=''${rootDiskImage##*.}
friendlyName=$out/${cfg.name}
rootDisk="$friendlyName.root.$extension"
bootDisk="$friendlyName.boot.$extension"
mv "$rootDiskImage" "$rootDisk"
mv "$bootDiskImage" "$bootDisk"
mkdir -p $out/nix-support
echo "file ${cfg.format} $bootDisk" >> $out/nix-support/hydra-build-products
echo "file ${cfg.format} $rootDisk" >> $out/nix-support/hydra-build-products
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg root_logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$bootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
--arg root "$rootDisk" \
--arg boot "$bootDisk" \
'{}
| .label = $system_label
| .boot_mode = $boot_mode
| .system = $system
| .disks.boot.logical_bytes = $boot_logical_bytes
| .disks.boot.file = $boot
| .disks.root.logical_bytes = $root_logical_bytes
| .disks.root.file = $root
' > $out/nix-support/image-info.json
'';
};
extBuilder = import ../../../lib/make-disk-image.nix {
inherit lib config configFile;
inherit (cfg) contents format name;
pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
fsType = "ext4";
partitionTableType = if config.ec2.efi then "efi"
else if config.ec2.hvm then "legacy+gpt"
else "none";
diskSize = cfg.sizeMB;
postVM = ''
extension=''${diskImage##*.}
friendlyName=$out/${cfg.name}.$extension
mv "$diskImage" "$friendlyName"
diskImage=$friendlyName
mkdir -p $out/nix-support
echo "file ${cfg.format} $diskImage" >> $out/nix-support/hydra-build-products
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
--arg file "$diskImage" \
'{}
| .label = $system_label
| .boot_mode = $boot_mode
| .system = $system
| .logical_bytes = $logical_bytes
| .file = $file
| .disks.root.logical_bytes = $logical_bytes
| .disks.root.file = $file
' > $out/nix-support/image-info.json
'';
};
in if config.ec2.zfs.enable then zfsBuilder else extBuilder;
}

View file

@ -0,0 +1,362 @@
#!/usr/bin/env nix-shell
#!nix-shell -p awscli -p jq -p qemu -i bash
# shellcheck shell=bash
#
# Future Deprecation?
# This entire thing should probably be replaced with a generic terraform config
# Uploads and registers NixOS images built from the
# <nixos/release.nix> amazonImage attribute. Images are uploaded and
# registered via a home region, and then copied to other regions.
# The home region requires an s3 bucket, and an IAM role named "vmimport"
# (by default) with access to the S3 bucket. The name can be
# configured with the "service_role_name" variable. Configuration of the
# vmimport role is documented in
# https://docs.aws.amazon.com/vm-import/latest/userguide/vmimport-image-import.html
# set -x
set -euo pipefail
var () { true; }
# configuration
var ${state_dir:=$HOME/amis/ec2-images}
var ${home_region:=eu-west-1}
var ${bucket:=nixos-amis}
var ${service_role_name:=vmimport}
# Output of the command:
# > aws ec2 describe-regions --all-regions --query "Regions[].{Name:RegionName}" --output text | sort
var ${regions:=
af-south-1
ap-east-1
ap-northeast-1
ap-northeast-2
ap-northeast-3
ap-south-1
ap-southeast-1
ap-southeast-2
ap-southeast-3
ca-central-1
eu-central-1
eu-north-1
eu-south-1
eu-west-1
eu-west-2
eu-west-3
me-south-1
sa-east-1
us-east-1
us-east-2
us-west-1
us-west-2
}
regions=($regions)
log() {
echo "$@" >&2
}
if [ "$#" -ne 1 ]; then
log "Usage: ./upload-amazon-image.sh IMAGE_OUTPUT"
exit 1
fi
# result of the amazon-image from nixos/release.nix
store_path=$1
if [ ! -e "$store_path" ]; then
log "Store path: $store_path does not exist, fetching..."
nix-store --realise "$store_path"
fi
if [ ! -d "$store_path" ]; then
log "store_path: $store_path is not a directory. aborting"
exit 1
fi
read_image_info() {
if [ ! -e "$store_path/nix-support/image-info.json" ]; then
log "Image missing metadata"
exit 1
fi
jq -r "$1" "$store_path/nix-support/image-info.json"
}
# We handle a single image per invocation, store all attributes in
# globals for convenience.
zfs_disks=$(read_image_info .disks)
is_zfs_image=
if jq -e .boot <<< "$zfs_disks"; then
is_zfs_image=1
zfs_boot=".disks.boot"
fi
image_label="$(read_image_info .label)${is_zfs_image:+-ZFS}"
image_system=$(read_image_info .system)
image_files=( $(read_image_info ".disks.root.file") )
image_logical_bytes=$(read_image_info "${zfs_boot:-.disks.root}.logical_bytes")
if [[ -n "$is_zfs_image" ]]; then
image_files+=( $(read_image_info .disks.boot.file) )
fi
# Derived attributes
image_logical_gigabytes=$(((image_logical_bytes-1)/1024/1024/1024+1)) # Round to the next GB
case "$image_system" in
aarch64-linux)
amazon_arch=arm64
;;
x86_64-linux)
amazon_arch=x86_64
;;
*)
log "Unknown system: $image_system"
exit 1
esac
image_name="NixOS-${image_label}-${image_system}"
image_description="NixOS ${image_label} ${image_system}"
log "Image Details:"
log " Name: $image_name"
log " Description: $image_description"
log " Size (gigabytes): $image_logical_gigabytes"
log " System: $image_system"
log " Amazon Arch: $amazon_arch"
read_state() {
local state_key=$1
local type=$2
cat "$state_dir/$state_key.$type" 2>/dev/null || true
}
write_state() {
local state_key=$1
local type=$2
local val=$3
mkdir -p "$state_dir"
echo "$val" > "$state_dir/$state_key.$type"
}
wait_for_import() {
local region=$1
local task_id=$2
local state snapshot_id
log "Waiting for import task $task_id to be completed"
while true; do
read -r state message snapshot_id < <(
aws ec2 describe-import-snapshot-tasks --region "$region" --import-task-ids "$task_id" | \
jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail | "\(.Status) \(.StatusMessage) \(.SnapshotId)"'
)
log " ... state=$state message=$message snapshot_id=$snapshot_id"
case "$state" in
active)
sleep 10
;;
completed)
echo "$snapshot_id"
return
;;
*)
log "Unexpected snapshot import state: '${state}'"
log "Full response: "
aws ec2 describe-import-snapshot-tasks --region "$region" --import-task-ids "$task_id" >&2
exit 1
;;
esac
done
}
wait_for_image() {
local region=$1
local ami_id=$2
local state
log "Waiting for image $ami_id to be available"
while true; do
read -r state < <(
aws ec2 describe-images --image-ids "$ami_id" --region "$region" | \
jq -r ".Images[].State"
)
log " ... state=$state"
case "$state" in
pending)
sleep 10
;;
available)
return
;;
*)
log "Unexpected AMI state: '${state}'"
exit 1
;;
esac
done
}
make_image_public() {
local region=$1
local ami_id=$2
wait_for_image "$region" "$ami_id"
log "Making image $ami_id public"
aws ec2 modify-image-attribute \
--image-id "$ami_id" --region "$region" --launch-permission 'Add={Group=all}' >&2
}
upload_image() {
local region=$1
for image_file in "${image_files[@]}"; do
local aws_path=${image_file#/}
if [[ -n "$is_zfs_image" ]]; then
local suffix=${image_file%.*}
suffix=${suffix##*.}
fi
local state_key="$region.$image_label${suffix:+.${suffix}}.$image_system"
local task_id
task_id=$(read_state "$state_key" task_id)
local snapshot_id
snapshot_id=$(read_state "$state_key" snapshot_id)
local ami_id
ami_id=$(read_state "$state_key" ami_id)
if [ -z "$task_id" ]; then
log "Checking for image on S3"
if ! aws s3 ls --region "$region" "s3://${bucket}/${aws_path}" >&2; then
log "Image missing from aws, uploading"
aws s3 cp --region "$region" "$image_file" "s3://${bucket}/${aws_path}" >&2
fi
log "Importing image from S3 path s3://$bucket/$aws_path"
task_id=$(aws ec2 import-snapshot --role-name "$service_role_name" --disk-container "{
\"Description\": \"nixos-image-${image_label}-${image_system}\",
\"Format\": \"vhd\",
\"UserBucket\": {
\"S3Bucket\": \"$bucket\",
\"S3Key\": \"$aws_path\"
}
}" --region "$region" | jq -r '.ImportTaskId')
write_state "$state_key" task_id "$task_id"
fi
if [ -z "$snapshot_id" ]; then
snapshot_id=$(wait_for_import "$region" "$task_id")
write_state "$state_key" snapshot_id "$snapshot_id"
fi
done
if [ -z "$ami_id" ]; then
log "Registering snapshot $snapshot_id as AMI"
local block_device_mappings=(
"DeviceName=/dev/xvda,Ebs={SnapshotId=$snapshot_id,VolumeSize=$image_logical_gigabytes,DeleteOnTermination=true,VolumeType=gp3}"
)
if [[ -n "$is_zfs_image" ]]; then
local root_snapshot_id=$(read_state "$region.$image_label.root.$image_system" snapshot_id)
local root_image_logical_bytes=$(read_image_info ".disks.root.logical_bytes")
local root_image_logical_gigabytes=$(((root_image_logical_bytes-1)/1024/1024/1024+1)) # Round to the next GB
block_device_mappings+=(
"DeviceName=/dev/xvdb,Ebs={SnapshotId=$root_snapshot_id,VolumeSize=$root_image_logical_gigabytes,DeleteOnTermination=true,VolumeType=gp3}"
)
fi
local extra_flags=(
--root-device-name /dev/xvda
--sriov-net-support simple
--ena-support
--virtualization-type hvm
)
block_device_mappings+=("DeviceName=/dev/sdb,VirtualName=ephemeral0")
block_device_mappings+=("DeviceName=/dev/sdc,VirtualName=ephemeral1")
block_device_mappings+=("DeviceName=/dev/sdd,VirtualName=ephemeral2")
block_device_mappings+=("DeviceName=/dev/sde,VirtualName=ephemeral3")
ami_id=$(
aws ec2 register-image \
--name "$image_name" \
--description "$image_description" \
--region "$region" \
--architecture $amazon_arch \
--block-device-mappings "${block_device_mappings[@]}" \
--boot-mode $(read_image_info .boot_mode) \
"${extra_flags[@]}" \
| jq -r '.ImageId'
)
write_state "$state_key" ami_id "$ami_id"
fi
[[ -v PRIVATE ]] || make_image_public "$region" "$ami_id"
echo "$ami_id"
}
copy_to_region() {
local region=$1
local from_region=$2
local from_ami_id=$3
state_key="$region.$image_label.$image_system"
ami_id=$(read_state "$state_key" ami_id)
if [ -z "$ami_id" ]; then
log "Copying $from_ami_id to $region"
ami_id=$(
aws ec2 copy-image \
--region "$region" \
--source-region "$from_region" \
--source-image-id "$from_ami_id" \
--name "$image_name" \
--description "$image_description" \
| jq -r '.ImageId'
)
write_state "$state_key" ami_id "$ami_id"
fi
[[ -v PRIVATE ]] || make_image_public "$region" "$ami_id"
echo "$ami_id"
}
upload_all() {
home_image_id=$(upload_image "$home_region")
jq -n \
--arg key "$home_region.$image_system" \
--arg value "$home_image_id" \
'$ARGS.named'
for region in "${regions[@]}"; do
if [ "$region" = "$home_region" ]; then
continue
fi
copied_image_id=$(copy_to_region "$region" "$home_region" "$home_image_id")
jq -n \
--arg key "$region.$image_system" \
--arg value "$copied_image_id" \
'$ARGS.named'
done
}
upload_all | jq --slurp from_entries

View file

@ -0,0 +1,35 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p google-cloud-sdk
set -euo pipefail
BUCKET_NAME="${BUCKET_NAME:-nixos-cloud-images}"
TIMESTAMP="$(date +%Y%m%d%H%M)"
export TIMESTAMP
nix-build '<nixpkgs/nixos/lib/eval-config.nix>' \
-A config.system.build.googleComputeImage \
--arg modules "[ <nixpkgs/nixos/modules/virtualisation/google-compute-image.nix> ]" \
--argstr system x86_64-linux \
-o gce \
-j 10
img_path=$(echo gce/*.tar.gz)
img_name=${IMAGE_NAME:-$(basename "$img_path")}
img_id=$(echo "$img_name" | sed 's|.raw.tar.gz$||;s|\.|-|g;s|_|-|g')
img_family=$(echo "$img_id" | cut -d - -f1-4)
if ! gsutil ls "gs://${BUCKET_NAME}/$img_name"; then
gsutil cp "$img_path" "gs://${BUCKET_NAME}/$img_name"
gsutil acl ch -u AllUsers:R "gs://${BUCKET_NAME}/$img_name"
gcloud compute images create \
"$img_id" \
--source-uri "gs://${BUCKET_NAME}/$img_name" \
--family="$img_family"
gcloud compute images add-iam-policy-binding \
"$img_id" \
--member='allAuthenticatedUsers' \
--role='roles/compute.imageUser'
fi

View file

@ -0,0 +1,102 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{ config, pkgs, lib, ... }:
with lib;
{
imports =
[ # Include the default lxd configuration.
../../../modules/virtualisation/lxc-container.nix
# Include the container-specific autogenerated configuration.
./lxd.nix
];
# networking.hostName = mkForce "nixos"; # Overwrite the hostname.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
# Set your time zone.
# time.timeZone = "Europe/Amsterdam";
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
# Per-interface useDHCP will be mandatory in the future, so this generated config
# replicates the default behaviour.
networking.useDHCP = false;
networking.interfaces.eth0.useDHCP = true;
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
# Select internationalisation properties.
# i18n.defaultLocale = "en_US.UTF-8";
# console = {
# font = "Lat2-Terminus16";
# keyMap = "us";
# };
# Enable the X11 windowing system.
# services.xserver.enable = true;
# Configure keymap in X11
# services.xserver.layout = "us";
# services.xserver.xkbOptions = "eurosign:e";
# Enable CUPS to print documents.
# services.printing.enable = true;
# Enable sound.
# sound.enable = true;
# hardware.pulseaudio.enable = true;
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;
# Define a user account. Don't forget to set a password with passwd.
# users.users.jane = {
# isNormalUser = true;
# extraGroups = [ "wheel" ]; # Enable sudo for the user.
# };
# List packages installed in system profile. To search, run:
# $ nix search wget
# environment.systemPackages = with pkgs; [
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
# wget
# firefox
# ];
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
# Enable the OpenSSH daemon.
# services.openssh.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "21.05"; # Did you read the comment?
# As this is intended as a stadalone image, undo some of the minimal profile stuff
documentation.enable = true;
documentation.nixos.enable = true;
environment.noXlibs = false;
}

View file

@ -0,0 +1,34 @@
{ lib, config, pkgs, ... }:
with lib;
{
imports = [
../../../modules/virtualisation/lxc-container.nix
];
virtualisation.lxc.templates.nix = {
enable = true;
target = "/etc/nixos/lxd.nix";
template = ./nix.tpl;
when = [ "create" "copy" ];
};
# copy the config for nixos-rebuild
system.activationScripts.config = ''
if [ ! -e /etc/nixos/configuration.nix ]; then
mkdir -p /etc/nixos
cat ${./lxd-image-inner.nix} > /etc/nixos/configuration.nix
sed 's|../../../modules/virtualisation/lxc-container.nix|<nixpkgs/nixos/modules/virtualisation/lxc-container.nix>|g' -i /etc/nixos/configuration.nix
fi
'';
# Network
networking.useDHCP = false;
networking.interfaces.eth0.useDHCP = true;
# As this is intended as a standalone image, undo some of the minimal profile stuff
documentation.enable = true;
documentation.nixos.enable = true;
environment.noXlibs = false;
}

View file

@ -0,0 +1,9 @@
{ lib, config, pkgs, ... }:
with lib;
# WARNING: THIS CONFIGURATION IS AUTOGENERATED AND WILL BE OVERWRITTEN AUTOMATICALLY
{
networking.hostName = "{{ container.name }}";
}

View file

@ -0,0 +1,101 @@
# nix-build '<nixpkgs/nixos>' -A config.system.build.openstackImage --arg configuration "{ imports = [ ./nixos/maintainers/scripts/openstack/openstack-image.nix ]; }"
{ config, lib, pkgs, ... }:
let
inherit (lib) mkOption types;
copyChannel = true;
cfg = config.openstackImage;
imageBootMode = if config.openstack.efi then "uefi" else "legacy-bios";
in
{
imports = [
../../../modules/virtualisation/openstack-config.nix
] ++ (lib.optional copyChannel ../../../modules/installer/cd-dvd/channel.nix);
options.openstackImage = {
name = mkOption {
type = types.str;
description = "The name of the generated derivation";
default = "nixos-openstack-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}";
};
sizeMB = mkOption {
type = types.int;
default = 8192;
description = "The size in MB of the image";
};
format = mkOption {
type = types.enum [ "raw" "qcow2" ];
default = "qcow2";
description = "The image format to output";
};
};
config = {
documentation.enable = copyChannel;
openstack = {
efi = true;
zfs = {
enable = true;
datasets = {
"tank/system/root".mount = "/";
"tank/system/var".mount = "/var";
"tank/local/nix".mount = "/nix";
"tank/user/home".mount = "/home";
};
};
};
system.build.openstackImage = import ../../../lib/make-single-disk-zfs-image.nix {
inherit lib config;
inherit (cfg) contents format name;
pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
configFile = pkgs.writeText "configuration.nix"
''
{ modulesPath, ... }: {
imports = [ "''${modulesPath}/virtualisation/openstack-config.nix" ];
openstack.zfs.enable = true;
}
'';
includeChannel = copyChannel;
bootSize = 1000;
rootSize = cfg.sizeMB;
rootPoolProperties = {
ashift = 12;
autoexpand = "on";
};
datasets = config.openstack.zfs.datasets;
postVM = ''
extension=''${rootDiskImage##*.}
friendlyName=$out/${cfg.name}
rootDisk="$friendlyName.root.$extension"
mv "$rootDiskImage" "$rootDisk"
mkdir -p $out/nix-support
echo "file ${cfg.format} $rootDisk" >> $out/nix-support/hydra-build-products
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg root_logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${imageBootMode}" \
--arg root "$rootDisk" \
'{}
| .label = $system_label
| .boot_mode = $boot_mode
| .system = $system
| .disks.root.logical_bytes = $root_logical_bytes
| .disks.root.file = $root
' > $out/nix-support/image-info.json
'';
};
};
}

View file

@ -0,0 +1,27 @@
# nix-build '<nixpkgs/nixos>' -A config.system.build.openstackImage --arg configuration "{ imports = [ ./nixos/maintainers/scripts/openstack/openstack-image.nix ]; }"
{ config, lib, pkgs, ... }:
let
copyChannel = true;
in
{
imports = [
../../../modules/virtualisation/openstack-config.nix
] ++ (lib.optional copyChannel ../../../modules/installer/cd-dvd/channel.nix);
documentation.enable = copyChannel;
system.build.openstackImage = import ../../../lib/make-disk-image.nix {
inherit lib config copyChannel;
additionalSpace = "1024M";
pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
format = "qcow2";
configFile = pkgs.writeText "configuration.nix"
''
{
imports = [ <nixpkgs/nixos/modules/virtualisation/openstack-config.nix> ];
}
'';
};
}