[
  {
    "path": ".dockerignore",
    "content": "/.git\n/.gomodcache\n/build/*\n!/build/rpms/\n/build/rpms/*\n!/build/rpms/*.rpm\n/build/rpms/*-debuginfo-*.rpm\n/build/rpms/*-debugsource-*.rpm\n**/target/*\n/sbkeys\n/tests\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/build.md",
    "content": "---\nname: Bug report - build process\nabout: Let us know about a problem with the build process\nlabels: status/needs-triage, type/bug\n---\n\n<!--\nTips:\n- Please search for similar issues, including closed issues.\n- Please include details about the environment you're running in.\n- Please include any error messages you received, with any required context.\n-->\n\n**Platform I'm building on:**\n\n\n\n**What I expected to happen:**\n\n\n\n**What actually happened:**\n\n\n\n**How to reproduce the problem:**\n\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature.md",
    "content": "---\nname: Feature request\nabout: Request a change to to the project\nlabels: status/needs-triage, type/enhancement\n---\n\n<!--\nTips:\n- Please search for similar requests, including closed issues.\n- Please include details about the environment you're running in.\n-->\n\n**What I'd like:**\n\n\n\n**Any alternatives you've considered:**\n\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/image.md",
    "content": "---\nname: Bug report - Bottlerocket image\nabout: Let us know about a problem with Bottlerocket\nlabels: status/needs-triage, type/bug\n---\n\n<!--\nTips:\n- Please search for similar issues, including closed issues.\n- Please include details about the environment you're running in.\n- Please include any error messages you received, with any required context.\n-->\n\n**Image I'm using:**\n\n\n\n**What I expected to happen:**\n\n\n\n**What actually happened:**\n\n\n\n**How to reproduce the problem:**\n\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/metal_driver.md",
    "content": "---\nname: bare metal variant - driver request\nabout: Request a driver to be added to the metal variant of Bottlerocket\nlabels: status/needs-triage, area/metal, type/enhancement\n---\n\n<!--\nTips:\n- Please search for similar requests, including closed issues.\n- Please include details about the hardware you want supported\n- Please provide the in-kernel driver name used for the device (if you know).\n- Please read [SUPPORTED-HARDWARE.md](https://github.com/bottlerocket-os/bottlerocket/blob/develop/SUPPORTED-HARDWARE.md).\n-->\n\n**What I'd like:**\n\n**Device type (e.g. network interface, disk controller):**\n\n**Device vendor:**\n\n**Device model:**\n\n**Driver used on other Linux distribition:**\n\n**Any alternatives you've considered:**\n\n"
  },
  {
    "path": ".github/actions/setup-node/action.yml",
    "content": "name: \"Node setup\"\ndescription: \"Performs setup for caching and other common needs.\"\ninputs:\n  perform-cache-cleanup:\n    description: \"Whether to perform cache cleanup\"\n    required: false\n    default: false\n    type: boolean\nruns:\n  using: \"composite\"\n  steps:\n    - run: |\n        echo \"OS_ARCH=`uname -m`\" >> $GITHUB_ENV\n        sudo apt -y install build-essential openssl libssl-dev pkg-config liblz4-tool\n      shell: bash\n    - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf\n      # Cache `cargo-make`, `cargo-cache`\n      with:\n        path: |\n          ~/.cargo\n        key: ${{ hashFiles('.github/workflows/cache.yml') }}-${{ runner.os }}-${{ env.OS_ARCH }}\n    - uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf\n      # Cache first-party code dependencies\n      with:\n        path: |\n          .cargo\n        key: ${{ hashFiles('.github/workflows/cache.yml') }}-${{ runner.os }}-${{ env.OS_ARCH }}-${{ hashFiles('sources/Cargo.lock') }}\n    - run: cargo install cargo-make\n      shell: bash\n    - if: ${{ inputs.perform-cache-cleanup }}\n      run: cargo install --no-default-features --features ci-autoclean cargo-cache\n      shell: bash\n"
  },
  {
    "path": ".github/dependabot.yaml",
    "content": "version: 2\nupdates:\n\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"area/dependencies\"\n\n  # We maintain updates for most dependencies. This disables updates other than\n  # security ones.\n  - package-ecosystem: \"cargo\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    labels:\n      - \"area/dependencies\"\n    open-pull-requests-limit: 0\n\n  - package-ecosystem: \"gomod\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    labels:\n      - \"area/dependencies\"\n    open-pull-requests-limit: 0\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!--\nTips:\n- Please read CONTRIBUTING.md to understand our process and our requests for PRs.\n- Please file an issue before creating a PR so we can discuss the change and confirm it's not already being worked on.\n-->\n\n**Issue number:**\n\nCloses #\n\n**Description of changes:**\n\n\n\n**Testing done:**\n\n\n\n**Terms of contribution:**\n\nBy submitting this pull request, I agree that this contribution is dual-licensed under the terms of both the Apache License, version 2.0, and the MIT license.\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non:\n  pull_request:\n    branches: [develop]\n    # Here we list file types that don't affect the build and don't need to use\n    # up our Actions runners.\n    paths-ignore:\n      # draw.io (diagrams.net) files, the source of png images for docs\n      - '**.drawio'\n      # Example configuration files\n      - '**.example'\n      # Markdown documentation\n      - '**.md'\n      # Images for documentation\n      - '**.png'\n      # Templates for README files\n      - '**.tpl'\n      # Sample config files and OpenAPI docs\n      - '**.yaml'\n      # Mailmap\n      - '.mailmap'\n\nconcurrency:\n  group: ${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    if: github.repository == 'bottlerocket-os/bottlerocket'\n    runs-on:\n      group: bottlerocket\n      labels: bottlerocket_ubuntu-latest_32-core\n    continue-on-error: true\n    strategy:\n      matrix:\n        arch: [x86_64, aarch64]\n      fail-fast: false\n    name: \"Build ${{ matrix.arch }}\"\n    steps:\n      - name: Random delay\n        run: |\n          delay=$((1 + $RANDOM % 32))\n          echo \"Waiting ${delay} seconds before execution\"\n          sleep $delay\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683\n      - name: Preflight step to set up the runner\n        uses: ./.github/actions/setup-node\n      - run: rustup component add rustfmt\n      - run: cargo make check\n      - run: |\n          cargo make \\\n            -e BUILDSYS_ARCH=${{ matrix.arch }} \\\n            -e BUILDSYS_JOBS=12 \\\n            build-all\n"
  },
  {
    "path": ".github/workflows/cache.yml",
    "content": "# This workflow caches crate dependencies and build artifacts for tools (except 'test-tools' since we don't use them in build workflows).\n# The cache is only usable by workflows started from pull requests against the develop branch.\nname: CacheDepsAndTools\non:\n  push:\n    branches: [develop]\n    paths:\n      - '.github/**'\n      - 'sources/Cargo.lock'\n      - 'tools/pubsys*/**'\n      - '!tools/pubsys/policies/**'\n      - '!tools/pubsys/**.example'\njobs:\n  cache:\n    if: github.repository == 'bottlerocket-os/bottlerocket'\n    runs-on:\n      group: bottlerocket\n      labels: bottlerocket_ubuntu-latest_8-core\n    continue-on-error: true\n    steps:\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683\n      - name: Preflight step to set up the runner\n        uses: ./.github/actions/setup-node\n        with:\n          perform-cache-cleanup: true\n      - run: cargo make install-twoliter\n      # This cleans the cargo cache in ~/.cargo\n      - run: cargo-cache\n"
  },
  {
    "path": ".github/workflows/weekly.yml",
    "content": "# This is basically a duplicate of the main \"build\" workflow, but uses GOPROXY=direct\n# to try to catch errors close to their introduction due to yanked Go modules. These\n# could otherwise be covered up by caching and not discovered until much later when\n# bypassing the main cache.\nname: Weekly\non:\n  schedule:\n    # Run Monday at 02:15 UTC. Randomly chosen as a \"quiet\" time for this to run.\n    # See syntax for format details: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onschedule\n    - cron: '15 2 * * 1'\n\nenv:\n  # When Go packages are built, buildsys will vendor in dependent Go code for\n  # that package and bundle it up in a tarball. This env variable is consumed\n  # and used to configure Go to directly download code from its upstream source.\n  # This is a useful early signal during GitHub actions to see if there are\n  # upstream Go code problems.\n  GOPROXY: direct\n\njobs:\n  build:\n    if: github.repository == 'bottlerocket-os/bottlerocket'\n    runs-on:\n      group: bottlerocket\n      labels: bottlerocket_ubuntu-latest_32-core\n    continue-on-error: false\n    strategy:\n      matrix:\n        arch: [x86_64, aarch64]\n      fail-fast: false\n    name: \"Build ${{ matrix.arch }}\"\n    steps:\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683\n      - name: Preflight step to set up the runner\n        uses: ./.github/actions/setup-node\n      - run: |\n          cargo make \\\n            -e BUILDSYS_ARCH=${{ matrix.arch }} \\\n            -e BUILDSYS_JOBS=12 \\\n            build-all\n"
  },
  {
    "path": ".gitignore",
    "content": "/build\n*.tar.*\n*.tgz\n**/target/\n**/vendor/\n/.cargo\n/.gomodcache\n/html\n/Infra.toml\n/Test.toml\n/testsys.kubeconfig\n/*.pem\n/keys\n/roles\n/sbkeys/**/\n/Licenses.toml\n/licenses\n*.run\n/tests\nTwoliter.override\n"
  },
  {
    "path": ".golangci.yaml",
    "content": "linters:\n  enable:\n    - errcheck\n    - goimports\n    - ineffassign\n    - misspell\n    - revive\n    - staticcheck\n    - unconvert\n    - unused\n    - govet\n\nrun:\n  timeout: 3m\nissues:\n  exclude-dirs:\n    - vendor\n    - .gomodcache\n"
  },
  {
    "path": ".mailmap",
    "content": "Jacob Peddicord <peddicor@amazon.com> <jpeddicord@users.noreply.github.com>\nJacob Vallejo <jakeev@amazon.com>\nJamie Anderson <jamieand@amazon.com> <32437770+jamieand@users.noreply.github.com>\nMichael Patraw <patraw@amazon.com> <52084153+patraw@users.noreply.github.com>\nSamuel Mendoza-Jonas <samjonas@amazon.com> <53018225+sam-aws@users.noreply.github.com>\nTom Kirchner <tjk@amazon.com> <tjkirch@users.noreply.github.com>\nZac Mrowicki <mrowicki@amazon.com>\nZac Mrowicki <mrowicki@amazon.com> <zmrowicki@hotmail.com>\nMahdi Chaker <mmchaker@amazon.com> M <mchaker@users.noreply.github.com>\nArnaldo Garcia Rincon <agarrcia@amazon.com>\nArnaldo Garcia Rincon <agarrcia@amazon.com> <asgar.2792@gmail.com>\nBen Cressey <bcressey@amazon.com> <ben@cressey.org>\nErikson Tung <etung@amazon.com>\nJacob Vallejo <jakeev@amazon.com> <jake@jahkeup.com>\nJohn McBride <jpmmcb@amazon.com> <jpmmcbride@gmail.com>\nKyle J. Davis <halldirector@gmail.com> <kyledvs@amazon.com>\nMarkus Boehme <markubo@amazon.com> <markusboehme@users.noreply.github.com>\nMatthew James Briggs <brigmatt@amazon.com>\nMatthew James Briggs <brigmatt@amazon.com> <6260372+webern@users.noreply.github.com>\nMatthew James Briggs <brigmatt@amazon.com> <matthew.james.briggs@gmail.com>\nMatthew James Briggs <brigmatt@amazon.com> Matt Briggs <mjb@bitflip.software>\nMatthew Yeazel <yeazelm@amazon.com> <67169369+yeazelm@users.noreply.github.com>\nMatthias Sterckx <msterckx@amazon.com>\nSamuel Karp <skarp@amazon.com> <samuelkarp@users.noreply.github.com>\nSanika Shah <shasanik@amazon.com> <sanikashah1110@gmail.com>\nSean Kelly <seankell@amazon.com> <sean.kelly.2992@gmail.com>\nSean McGinnis <stmcg@amazon.com> <sean.mcginnis@gmail.com>\nSean P. Kelly <seankell@amazon.com> <sean.kelly.2992@gmail.com>\nShailesh Gothi <gothisg@amazon.com> <shaileshgothiece@gmail.com>\nTianhao Geng <tianhg@amazon.com> <gthao313@gmail.com>\nTianhao Geng <tianhg@amazon.com> <45469883+gthao313@users.noreply.github.com>\nEthan Pullen <pullenep@amazon.com>\nEthan Pullen <pullenep@amazon.com> <ecpullen@aol.com>\nShikha Vyaghra <vyaghras@amazon.com> <107685805+vyaghras@users.noreply.github.com>\nPatrick J.P. Culp <jpculp@amazon.com>\nPatrick J.P. Culp <jpculp@amazon.com> <jpculp@gmail.com>\nPiyush Jena <jepiyush@amazon.com> <piyushjena1996@gmail.com>\nMartin Harriman <mharrimn@amazon.com> <larvacea@mac.com>\nVighnesh Maheshwari <vighmah@amazon.com> <vighnesh.maheshwari@gmail.com>\nVighnesh Maheshwari <vighmah@amazon.com> <21048293+vigh-m@users.noreply.github.com>\nKyle Sessions <kssessio@amazon.com>\nKyle Sessions <kssessio@amazon.com> <KyleC.Sessions1@gmail.com>\nGaurav Sharma <mgsharm@amazon> <168583863+mgsharm@users.noreply.github.com>\nGavin Inglis <giinglis@amazon.com> <43075615+ginglis13@users.noreply.github.com>\nSam Berning <bernings@amazon.com> <113054166+sam-berning@users.noreply.github.com>\nSparks Song <shijiao@amazon.com> <sparkssj14@gmail.com>\nSparks Song <shijiao@amazon.com> Sparks <56856447+Sparksssj@users.noreply.github.com>\nCezar Rata <ceradev@amazon.com> cezar-r <59450965+cezar-r@users.noreply.github.com>\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"rust-analyzer.linkedProjects\": [\n        \"sources/Cargo.toml\"\n    ],\n    \"files.insertFinalNewline\": true\n}\n"
  },
  {
    "path": "BUILDING.md",
    "content": "# Building Bottlerocket\n\nIf you'd like to build your own image instead of relying on an Amazon-provided image, follow these steps.\nYou can skip to the [setup guide for Kubernetes](QUICKSTART-EKS.md) or the [setup guide for Amazon ECS](QUICKSTART-ECS.md) to use an existing image in Amazon EC2.\n(We're still working on other use cases!)\n\n## Build an image\n\n### Dependencies\n\n#### System Requirements\n\nThe build process artifacts and resulting images can consume in excess of 80GB in the local directory.\n\nThe build process is also fairly demanding on your CPU, since we build all included software from scratch.\n(The first time.  Package builds are cached, and only changes are built afterward.)\nThe build scales well to 32+ cores.\nThe first time you build, the fastest machines can take about 12 minutes while slower machines with only a couple cores can take 3-4 hours.\n\n#### Linux\n\nThe build system requires certain operating system packages to be installed.\n\nEnsure the following OS packages are installed:\n\n##### Ubuntu\n\n```shell\napt install build-essential openssl libssl-dev pkg-config liblz4-tool\n```\n\n##### Fedora\n\n```shell\nyum install make automake gcc openssl openssl-devel pkg-config lz4 perl-FindBin perl-lib\n```\n\n\n#### Rust\n\nThe build system is based on the Rust language.\nWe recommend you install the latest stable Rust using [rustup](https://rustup.rs/), either from the official site or your development host's package manager.\nRust 1.51.0 or higher is required.\n\nTo organize build tasks, we use [cargo-make](https://sagiegurari.github.io/cargo-make/).\nTo get it, run:\n\n```shell\ncargo install cargo-make\n```\n\n#### Docker\n\nBottlerocket uses [Docker](https://docs.docker.com/install/#supported-platforms) to orchestrate package and image builds.\n\nWe recommend Docker 20.10.10 or later.\nBuilds rely on Docker's integrated BuildKit support, which has received many fixes and improvements in newer versions.\nThe default seccomp policy of older versions of Docker do not support the `clone3` syscall in recent versions of Fedora or Ubuntu, on which the Bottlerocket SDK is based.\n\nYou'll need to have Docker installed and running, with your user account added to the `docker` group.\nDocker's [post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/) will walk you through that.\n\n> Note: If you're on a newer Linux distribution using the unified cgroup hierarchy with cgroups v2, you may need to disable it to work with current versions of runc.\n> You'll know this is the case if you see an error like `docker: Error response from daemon: OCI runtime create failed: this version of runc doesn't work on cgroups v2: unknown.`\n> Set the kernel parameter `systemd.unified_cgroup_hierarchy=0` in your boot configuration (e.g. GRUB) and reboot.\n\n### Build process\n\nTo build an image, run:\n\n```shell\ncargo make\n```\n\nThis will build an image for the default variant (a recent `aws-k8s-*`, see the `BUILDSYS_VARIANT` variable in [Makefile.toml](Makefile.toml) to find the current default variant).\nAll packages will be built in turn, and then compiled into an `img` file in the `build/images/` directory.\n\nThe version number in [Release.toml](Release.toml) will be used in naming the file, and will be used inside the image as the release version.\nIf you're planning on [publishing your build](PUBLISHING.md), you may want to change the version.\n\nTo build an image for a different variant, run:\n\n```shell\ncargo make -e BUILDSYS_VARIANT=my-variant-here\n```\n\nTo build an image for a different architecture, run:\n\n```shell\ncargo make -e BUILDSYS_ARCH=my-arch-here\n```\n\nIf you want to limit the build concurrency, set `BUILDSYS_JOBS` (the default is `8`):\n\n```shell\ncargo make -e BUILDSYS_JOBS=4\n```\n\n(You can use variant and arch arguments together, too.)\n\n#### Package licenses\n\nMost packages will include license files extracted from upstream source archives.\nHowever, in some rare cases there are multiple licenses that could apply to a package.\nBottlerocket's build system uses the `Licenses.toml` file in conjunction with the `licenses` directory to configure the licenses used for such special packages.\nHere is an example of a simple `Licenses.toml` configuration file:\n\n```toml\n[package]\nspdx-id = \"SPDX-ID\"\nlicenses = [\n  { path = \"the-license.txt\" }\n]\n```\n\nIn the previous example, it is expected that the file `the-license.txt` is present in `licenses`.\nYou can retrieve the licenses from a remote endpoint, or the local filesystem if you specify the `license-url` field:\n\n```toml\n[package]\nspdx-id = \"SPDX-ID AND SPDX-ID-2\" # Package with multiple licenses\nlicenses = [\n  # This file is copied from a file system, and will be saved as `path`\n  { license-url = \"file:///path/to/spdx-id-license.txt\", path = \"spdx-id-license.txt\" },\n  # This file is fetched from an https endpoint, and will be saved as `path`\n  { license-url = \"https://localhost/spdx-id-license-v2.txt\", path = \"spdx-id-license-2.txt\" }\n]\n```\n\n#### NVIDIA variants\n\nIf you want to build any of the NVIDIA variants, you can follow these steps to prepare a `Licenses.toml` file using the [License for customer use of NVIDIA software](https://www.nvidia.com/en-us/drivers/nvidia-license/):\n\n1. Create a `Licenses.toml` file in your Bottlerocket root directory, with the following content:\n\n```toml\n[nvidia]\nspdx-id = \"LicensesRef-NVIDIA-Customer-Use\"\nlicenses = [\n  { path = \"LICENSE\", license-url = \"https://www.nvidia.com/en-us/drivers/nvidia-license/\" }\n]\n```\n\n2. Fetch the licenses with this command:\n\n```shell\ncargo make -e BUILDSYS_UPSTREAM_LICENSE_FETCH=true fetch-licenses\n```\n\n3. Build your image, setting the `BUILDSYS_UPSTREAM_SOURCE_FALLBACK` flag to `true`, if you haven't cached the driver's sources:\n\n```shell\nK8S_VERSION=1.32\ncargo make \\\n  -e BUILDSYS_VARIANT=aws-k8s-${K8S_VERSION}-nvidia \\\n  -e BUILDSYS_UPSTREAM_SOURCE_FALLBACK=\"true\"\n```\n\n### Register an AMI\n\nTo use the image in Amazon EC2, we need to register the image as an AMI.\n\nTo do this, you'll need to have your AWS account credentials setup on your system.\nThere are lots of ways to do this; one method is using [the `aws` CLI](https://aws.amazon.com/cli/) via its `configure` command with your user's access and secret keys.\nIf you're using an EC2 instance, the [EC2 instance's IAM role](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) will be used automatically if available.\n\nFor a simple start, pick an [EC2 region](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions), then run:\n\n```shell\ncargo make -e PUBLISH_REGIONS=your-region-here ami\n```\n\nNote that the task (\"ami\") must come **after** the arguments to `cargo make` that are specified with `-e`.\n\nYour new AMI ID will be printed after it's registered.\n\nIf you built your image for a different architecture or variant, just use the same arguments here:\n\n```shell\ncargo make -e PUBLISH_REGIONS=your-region-here -e BUILDSYS_VARIANT=my-variant-here ami\n```\n\n(There's a lot more detail on building and managing AMIs in the [PUBLISHING](PUBLISHING.md) guide.)\n\n## Use your image\n\nSee any of the setup guides tailored to the various execution environments for information on running Bottlerocket images:\n\n* [Setup guide for Kubernetes](QUICKSTART-EKS.md)\n* [Setup guide for Amazon ECS](QUICKSTART-ECS.md)\n* [Setup guide for VMware](QUICKSTART-VMWARE.md)\n* [Setup guide for QEMU/KVM](QUICKSTART-LOCAL.md)\n\n## Publish your image\n\nSee the [PUBLISHING](PUBLISHING.md) guide for information on deploying Bottlerocket images and repositories.\n\n## Building out-of-tree kernel modules\n\nTo further extend Bottlerocket, you may want to build extra kernel modules.\nThe specifics of building an out-of-tree module will vary by project, but the first step is to download the \"kmod kit\" that contains the kernel headers and toolchain you'll need to use.\n\n### Downloading the kmod kit\n\nkmod kits are included in the official Bottlerocket repos starting with Bottlerocket v1.0.6.\nLet's say you want to download the kit for building x86_64 modules for v1.31.0 and variant aws-k8s-1.32.\n\nFirst, you need tuftool:\n```shell\ncargo install tuftool\n```\n\nNext, you need the Bottlerocket root role, which is used by tuftool to verify the kmod kit.\nThis will download and verify the root role itself:\n```shell\ncurl -O \"https://cache.bottlerocket.aws/root.json\"\nsha512sum -c <<<\"4fcb272345fd6adb94d4c04834400548178fecb57407ca79bc2c3d20e0428fc9ed3a82cea268d7f9c667b5803524a4f465acd701a86953d5d732bf6ecb064888  root.json\"\n```\n\nNext, set your desired parameters, and download the kmod kit:\n```shell\nARCH=x86_64\nVERSION=v1.31.0\nVARIANT=aws-k8s-1.32\nOUTDIR=\"${VARIANT}-${VERSION}\"\n\ntuftool download \"${OUTDIR}\" --target-name ${VARIANT}-${ARCH}-kmod-kit-${VERSION}.tar.xz \\\n   --root ./root.json \\\n   --metadata-url \"https://updates.bottlerocket.aws/2020-07-07/${VARIANT}/${ARCH}/\" \\\n   --targets-url \"https://updates.bottlerocket.aws/targets/\"\n```\n\n### Using the kmod kit\n\nTo use the kmod kit, extract it, and update your PATH to use its toolchain:\n```shell\ntar xf \"${VARIANT}-${ARCH}-kmod-kit-${VERSION}.tar.xz\"\n\nexport CROSS_COMPILE=\"${ARCH}-bottlerocket-linux-musl-\"\nexport KERNELDIR=\"${PWD}/${VARIANT}-${ARCH}-kmod-kit-${VERSION}/kernel-devel\"\nexport PATH=\"${PWD}/${VARIANT}-${ARCH}-kmod-kit-${VERSION}/toolchain/usr/bin:${PATH}\"\n```\n\nNow you can compile modules against the kernel headers in `${KERNELDIR}`.\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# v1.57.0 (2026-03-18)\n\n## Release Highlights\n* Update `glibc` to 2.43 and `runc` to 1.3.4 ([bottlerocket-core-kit#865], [bottlerocket-core-kit#854])\n* Add `kubelet-env-nvidia` template for `kubernetes-1.35` ([#4784], [bottlerocket-core-kit#860])\n* Reserve EKS add-on ports ([bottlerocket-core-kit#864]) - Thanks @Shreyank031!\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 13.1.0 to 13.3.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1330-2026-03-18) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v13.1.0...v13.3.0)) ([#4789], [#4791])\n* Update `bottlerocket-kernel-kit` from 5.0.1 to 5.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v520-2026-03-18) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v5.0.1...v5.2.0)) ([#4789], [#4791])\n* Update `admin-container` from 0.20.3 to 0.20.4 ([#4780])\n* Update `control-container` from 0.20.3 to 0.20.4 ([#4780])\n* Update `bootstrap-container` from 0.2.13 to 0.2.14 ([#4780])\n\n## Build Changes\n* Update `twoliter` from 0.16.0 to 0.17.0 ([#4776])\n* Update `bottlerocket-sdk` from 0.70.0 to 0.72.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.70.0...v0.72.0)) ([#4789], [#4791])\n\n[#4776]: https://github.com/bottlerocket-os/bottlerocket/pull/4776\n[#4780]: https://github.com/bottlerocket-os/bottlerocket/pull/4780\n[#4784]: https://github.com/bottlerocket-os/bottlerocket/pull/4784\n[#4789]: https://github.com/bottlerocket-os/bottlerocket/pull/4789\n[#4791]: https://github.com/bottlerocket-os/bottlerocket/pull/4791\n[bottlerocket-core-kit#854]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/854\n[bottlerocket-core-kit#860]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/860\n[bottlerocket-core-kit#864]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/864\n[bottlerocket-core-kit#865]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/865\n\n# v1.56.0 (2026-02-24)\n\n## Release Highlights\n* Add support to render `settings.container-registry` into containerd supported `hosts.toml` ([bottlerocket-core-kit#819], [#4767])\n* Expand image verifier support with a new helper to render trust policies for all image verifier plugins ([bottlerocket-core-kit#820], [#4766])\n* Suppress IPv6 on interfaces with no IPv6 intent in `net.toml` ([bottlerocket-core-kit#826])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.8.2 to 5.0.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v501-2026-02-26) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.8.2...v5.0.1)) ([#4764], [#4775])\n* Update `bottlerocket-core-kit` from 13.0.0 to 13.1.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1310-2026-02-25) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v13.0.0...v13.1.0)) ([#4770])\n\n## Build Changes\n* Update Rust dependencies ([#4763])\n* Update `bottlerocket-settings-models` to v0.21.0 ([#4773])\n\n[#4763]: https://github.com/bottlerocket-os/bottlerocket/pull/4763\n[#4764]: https://github.com/bottlerocket-os/bottlerocket/pull/4764\n[#4766]: https://github.com/bottlerocket-os/bottlerocket/pull/4766\n[#4767]: https://github.com/bottlerocket-os/bottlerocket/pull/4767\n[#4770]: https://github.com/bottlerocket-os/bottlerocket/pull/4770\n[#4773]: https://github.com/bottlerocket-os/bottlerocket/pull/4773\n[#4775]: https://github.com/bottlerocket-os/bottlerocket/pull/4775\n[bottlerocket-core-kit#819]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/819\n[bottlerocket-core-kit#820]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/820\n[bottlerocket-core-kit#826]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/826\n\n# v1.55.0 (2026-02-11)\n\n## Release Highlights\n* Add URI resolver support to `apiclient apply` and `apiclient network configure` ([bottlerocket-core-kit#554])\n  * `s3://` - S3 bucket objects\n  * `secretsmanager://` - AWS Secrets Manager secrets\n  * `ssm://` - AWS SSM Parameter Store parameters\n  * `arn:aws:secretsmanager:` and `arn:aws:ssm:` - cross-region access via full ARN\n  * `base64:` - inline encoded content\n* Remove separate FIPS binaries from Go packages in favor of Go built-in FIPS support ([bottlerocket-core-kit#813])\n* Remove hugepages from `reservedMemory` in kubelet config ([bottlerocket-core-kit#821])\n* Update SELinux policy to allow container communication with MPS daemon ([bottlerocket-core-kit#831])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.8.0 to 4.8.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v482-2026-02-07) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.8.0...v4.8.2)) ([#4757])\n* Update `bottlerocket-core-kit` from 12.3.0 to 13.0.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1300-2026-02-11) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v12.3.0...v13.0.0)) ([#4761])\n* Update `admin-container` from 0.20.1 to 0.20.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0203) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.20.1...v0.20.3)) ([#4759])\n* Update `control-container` from 0.20.1 to 0.20.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#0203) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.20.1...v0.20.3)) ([#4759])\n* Update `bootstrap-container` from 0.2.11 to 0.2.13 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#0213) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.11...v0.2.13)) ([#4759])\n\n[#4757]: https://github.com/bottlerocket-os/bottlerocket/pull/4757\n[#4759]: https://github.com/bottlerocket-os/bottlerocket/pull/4759\n[#4761]: https://github.com/bottlerocket-os/bottlerocket/pull/4761\n[bottlerocket-core-kit#554]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/554\n[bottlerocket-core-kit#813]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/813\n[bottlerocket-core-kit#821]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/821\n[bottlerocket-core-kit#823]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/823\n[bottlerocket-core-kit#831]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/831\n\n# v1.54.0 (2026-01-22)\n\n## Release Highlights\n* Migrate to Go's native FIPS 140-3 runtime support for all FIPS variants ([bottlerocket-core-kit#783])\n* Add NVIDIA Multi-Process Service (MPS) support ([#4744], [bottlerocket-core-kit#789])\n* Add `trn3` device IDs to `pciclient` ([bottlerocket-core-kit#800])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.7.1 to 4.8.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v480-2026-01-21) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.7.1...v4.8.0)) ([#4744])\n* Update `bottlerocket-core-kit` from 12.2.0 to 12.3.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1230-2026-01-21) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v12.2.0...v12.3.0)) ([#4744])\n* Update `admin-container` from 0.20.0 to 0.20.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0201) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.20.0...v0.20.1)) ([#4749])\n* Update `control-container` from 0.20.0 to 0.20.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#0201) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.20.0...v0.20.1)) ([#4749])\n* Update `bootstrap-container` from 0.2.10 to 0.2.11 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#0211) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.10...v0.2.11)) ([#4749])\n\n## Build Changes\n* Update `bottlerocket-sdk` from 0.66.0 to 0.70.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.66.0...v0.70.0)) ([#4744])\n* Update `bottlerocket-settings-models` to v0.20.0 ([#4744])\n\n[#4744]: https://github.com/bottlerocket-os/bottlerocket/pull/4744\n[#4749]: https://github.com/bottlerocket-os/bottlerocket/pull/4749\n[bottlerocket-core-kit#783]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/783\n[bottlerocket-core-kit#789]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/789\n[bottlerocket-core-kit#800]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/800\n\n# v1.53.0 (2026-01-13)\n\n## Release Highlights\n* Add new kubernetes 1.35 variants ([#4735]):\n  * Add `aws-k8s-1.35`, `aws-k8s-1.35-nvidia`, `aws-k8s-1.35-fips`, `aws-k8s-1.35-nvidia-fips`, `vmware-k8s-1.35`, and `vmware-k8s-1.35-fips` variants\n  * All k8s-1.35 variants use the following:\n    * `kernel-6.12`\n    * `systemd-257`\n    * `nftables`\n    * `containerd-2.1`\n    * `whippet`\n    * `release-swap` - Enable **zram-backed** swap device to improve system stability in low-memory situations  ([bottlerocket-core-kit#590])\n* Migrate all nvidia variants to use nvidia R580 drivers ([#4733])\n* Migrate `admin-container` and `control-container` to AL2023 ([#4740])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.7.0 to 4.7.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v471-2026-01-07) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.7.0...v4.7.1)) ([#4736])\n* Update `bottlerocket-core-kit` from 12.0.1 to 12.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1220-2026-01-08) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v12.0.1...v12.2.0)) ([#4735])\n* Enable `erofs` root partition in all variants ([#4728])\n* Use `whippet` in all variants ([#4738])\n* Update `admin-container` from 0.12.5 to 0.20.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0200) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.12.5...v0.20.0)) ([#4740])\n* Update `bootstrap-container` from 0.2.9 to 0.2.10 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#0210) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.9...v0.2.10)) ([#4740])\n* Update `control-container` from 0.8.11 to 0.20.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#0200) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.11...v0.20.0)) ([#4740])\n\n### Twoliter\n* Update `twoliter` from v0.15.0 to v0.16.0 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0160---2026-01-06) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.15.0...v0.16.0)) ([#4726], [#4734])\n\n## Documentation Changes\n* Remove stale settings extension design documents ([#4716])\n\n[#4716]: https://github.com/bottlerocket-os/bottlerocket/pull/4716\n[#4726]: https://github.com/bottlerocket-os/bottlerocket/pull/4726\n[#4728]: https://github.com/bottlerocket-os/bottlerocket/pull/4728\n[#4733]: https://github.com/bottlerocket-os/bottlerocket/pull/4733\n[#4734]: https://github.com/bottlerocket-os/bottlerocket/pull/4734\n[#4735]: https://github.com/bottlerocket-os/bottlerocket/pull/4735\n[#4736]: https://github.com/bottlerocket-os/bottlerocket/pull/4736\n[#4738]: https://github.com/bottlerocket-os/bottlerocket/pull/4738\n[#4740]: https://github.com/bottlerocket-os/bottlerocket/pull/4740\n[bottlerocket-core-kit#590]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/590\n\n# v1.52.0 (2025-12-16)\n\n## Release Highlights\n* Remove `aws-k8s-1.28` variants ([#4717])\n* Disable concurrent layer fetch by default in `containerd-2.1` ([bottlerocket-core-kit#764])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.5.1 to 4.7.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v470-2025-12-10) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.5.1...v4.7.0)) ([#4719])\n* Update `bottlerocket-core-kit` from 11.0.1 to 12.0.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1201-2025-12-12) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v11.0.1...v12.0.1)) ([#4719], [#4724])\n* Update `admin-container` from 0.12.4 to 0.12.5 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0125) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.12.4...v0.12.5)) ([#4712])\n* Update `bootstrap-container` from 0.2.8 to 0.2.9 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#029) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.8...v0.2.9)) ([#4712])\n* Update `control-container` from 0.8.10 to 0.8.11 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#0811) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.10...v0.8.11)) ([#4712])\n* Update `aws-dev` and `vmware-dev` variants with the latest Bottlerocket features([#4705])\n\n## Build Changes\n* Update `bottlerocket-sdk` from 0.65.1 to 0.66.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.65.1...v0.66.0)) ([#4719])\n\n### Twoliter\n* Update `twoliter` from v0.13.0 to v0.15.0 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0150---2025-12-11) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.13.0...v0.15.0))([#4718], [#4722])\n\n[#4705]: https://github.com/bottlerocket-os/bottlerocket/pull/4705\n[#4711]: https://github.com/bottlerocket-os/bottlerocket/pull/4711\n[#4712]: https://github.com/bottlerocket-os/bottlerocket/pull/4712\n[#4717]: https://github.com/bottlerocket-os/bottlerocket/pull/4717\n[#4718]: https://github.com/bottlerocket-os/bottlerocket/pull/4718\n[#4719]: https://github.com/bottlerocket-os/bottlerocket/pull/4719\n[#4722]: https://github.com/bottlerocket-os/bottlerocket/pull/4722\n[#4724]: https://github.com/bottlerocket-os/bottlerocket/pull/4724\n[bottlerocket-core-kit#764]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/764\n\n# v1.51.0 (2025-11-17)\n## Release Highlights\n* New ecs-3 variants are now available as a preview ([#4685])\n  * Add `aws-ecs-3`, `aws-ecs-3-nvidia`, `aws-ecs-3-fips`, and `aws-ecs-3-nvidia-fips` variants\n  * All ecs-3 variants use the following:\n    * `kernel-6.12`\n    * `containerd-2.1`\n    * `systemd-257`\n    * `nftables`\n    * `whippet` ([bottlerocket-core-kit#720])\n    * `docker-engine-29` ([bottlerocket-core-kit#711])\n    * `docker-cli-29` ([bottlerocket-core-kit#711])\n  * Use EROFS for root filesystem\n  * Use EBS volume gp3 for all variants\n  * Require IMDSv2 by default\n  * `aws-ecs-3-nvidia` and `aws-ecs-nvidia-fips` variants use NVIDIA R580 drivers\n  * Enable support for image verification\n  * Enable support for encrypted storage\n* Add NVIDIA FIPS variants for Kubernetes 1.29-1.34 and ECS-2 ([#4671])\n* Add support for new Kubernetes settings, `image-minimum-gc-age`, `image-maximum-gc-age`, `max-parallel-image-pulls`, `ids-per-pod`, and Beta options for `cpu-manager-policy-options` ([#4690], [bottlerocket-core-kit#689])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.4.2 to 4.5.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v451-2025-11-12) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.4.2...v4.5.1)) ([#4693], [#4698])\n* Update `bottlerocket-core-kit` from 10.9.0 to 11.0.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1101-2025-11-12) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v10.9.0...v11.0.1)) ([#4699])\n* Bump `containerd` from 2.0 to 2.1 on all `aws-k8s-1.33` variants ([#4687])\n* Drop `socat` from `aws-dev` variant ([#4699])\n* Update ECR credential provider image patterns to include EUSC image formats ([#4689])\n* Use `whippet` in `aws-ecs-2`, `aws-k8s-1.34`, and `vmware-k8s-1.34` variants ([#4701])\n\n### Twoliter\n* Update `twoliter` from v0.12.0 to v0.13.0 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0130---2025-11-10) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.12.0...v0.13.0)) ([#4691])\n\n### Settings Extensions\n* Update `bottlerocket-settings-models` to v0.17.0 ([#4690])\n\n[#4671]: https://github.com/bottlerocket-os/bottlerocket/pull/4671\n[#4685]: https://github.com/bottlerocket-os/bottlerocket/pull/4685\n[#4687]: https://github.com/bottlerocket-os/bottlerocket/pull/4687\n[#4689]: https://github.com/bottlerocket-os/bottlerocket/pull/4689\n[#4690]: https://github.com/bottlerocket-os/bottlerocket/pull/4690\n[#4691]: https://github.com/bottlerocket-os/bottlerocket/pull/4691\n[#4693]: https://github.com/bottlerocket-os/bottlerocket/pull/4693\n[#4697]: https://github.com/bottlerocket-os/bottlerocket/pull/4697\n[#4698]: https://github.com/bottlerocket-os/bottlerocket/pull/4698\n[#4699]: https://github.com/bottlerocket-os/bottlerocket/pull/4699\n[#4701]: https://github.com/bottlerocket-os/bottlerocket/pull/4701\n[bottlerocket-core-kit#689]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/689\n[bottlerocket-core-kit#711]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/711\n[bottlerocket-core-kit#720]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/720\n\n# v1.50.0 (2025-11-05)\n\n## Release Highlights\n* Add support for new kubernetes setting `kube-reserved.pid` and `system-reserved.pid` ([#4661], [bottlerocket-core-kit#646])\n* Allow multiple sequential calls of `apiclient ephemeral-storage bind` ([bottlerocket-core-kit#679])\n* Patch `containerd-2.1` to fix image pull when range-get is ignored by the registry ([bottlerocket-core-kit#702])\n\n## Security Fixes\n* Patch `runc` to mitigate CVE-2025-31133, CVE-2025-52565, and CVE-2025-52881 ([bottlerocket-core-kit#6e3d3e2e])\n\n## OS Changes\n\n* Update `bottlerocket-sdk` from 0.64.0 to 0.65.1 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.64.0...v0.65.1))([#4664], [#4667])\n* Update `bottlerocket-kernel-kit` from 4.3.3 to 4.4.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v442-2025-10-27) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.3.3...v4.4.2)) ([#4664], [#4667], [#4672])\n* Update `bottlerocket-core-kit` from 10.6.0 to 10.9.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1082-2025-11-05) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v10.6.0...v10.9.0)) ([#4661], [#4664], [#4667], [#07b40823])\n* Update `admin-container` from 0.12.3 to 0.12.4 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0124) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.12.3...v0.12.4)) ([#4669])\n* Update `bootstrap-container` from 0.2.6 to 0.2.8 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#028) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.6...v0.2.8)) ([#4664], [#4669])\n* Update `control-container` from 0.8.8 to 0.8.10 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#0810) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.8...v0.8.10)) ([#4664], [#4669])\n\n### Settings Extensions\n* Update bottlerocket-settings-models to v0.16.0 ([#4661])\n\n[#4661]: https://github.com/bottlerocket-os/bottlerocket/pull/4661\n[#4664]: https://github.com/bottlerocket-os/bottlerocket/pull/4664\n[#4667]: https://github.com/bottlerocket-os/bottlerocket/pull/4667\n[#4669]: https://github.com/bottlerocket-os/bottlerocket/pull/4669\n[#4672]: https://github.com/bottlerocket-os/bottlerocket/pull/4672\n[bottlerocket-core-kit#646]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/646\n[bottlerocket-core-kit#679]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/679\n[bottlerocket-core-kit#702]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/702\n[#07b40823]: https://github.com/bottlerocket-os/bottlerocket/commit/07b408232df3a5c47b93b7ba086ddebca5677703\n[bottlerocket-core-kit#6e3d3e2e]: https://github.com/bottlerocket-os/bottlerocket-core-kit/commit/6e3d3e2e563ec556b9fc51eb495a180b69bcf43b\n\n# v1.49.0 (2025-10-09)\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.3.1 to 4.3.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v433-2025-10-03) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.3.1...v4.3.3)) ([#4657])\n\n[#4657]: https://github.com/bottlerocket-os/bottlerocket/pull/4657\n\n# v1.48.0 (2025-09-29)\n\n## Release Highlights\n* Support passing arguments to `apiclient exec` subcommand with a `--` separator ([bottlerocket-core-kit#647])\n* Install `driverdog` for all variants ([bottlerocket-core-kit#656]) - Thanks @fletcherw!\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.3.0 to 4.3.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v431-2025-09-15) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.3.0...v4.3.1)) ([#4644])\n* Update `bottlerocket-core-kit` from 10.4.1 to 10.6.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1060-2025-09-23) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v10.4.1...v10.6.0)) ([#4649])\n* Update `admin-container` from 0.12.2 to 0.12.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0123) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.12.2...v0.12.3)) ([#4647])\n* Update `bootstrap-container` from 0.2.5 to 0.2.6 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#026) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.5...v0.2.6)) ([#4647])\n* Update `control-container` from 0.8.7 to 0.8.8 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#088) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.7...v0.8.8)) ([#4647])\n\n[#4644]: https://github.com/bottlerocket-os/bottlerocket/pull/4644\n[#4647]: https://github.com/bottlerocket-os/bottlerocket/pull/4647\n[#4649]: https://github.com/bottlerocket-os/bottlerocket/pull/4649\n[bottlerocket-core-kit#647]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/647\n[bottlerocket-core-kit#656]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/656\n\n# v1.47.0 (2025-09-15)\n\n## Release Highlights\n* Add new kubernetes 1.34 variants ([#4631]):\n  * Add `aws-k8s-1.34`, `aws-k8s-1.34-nvidia`, `aws-k8s-1.34-fips`, `vmware-k8s-1.34`, and `vmware-k8s-1.34-fips` variants\n  * All k8s-1.34 variants use the following:\n    * Kernel 6.12\n    * `systemd-257` ([bottlerocket-core-kit#581], [bottlerocket-core-kit#636])\n    * `nftables` for managing network filter rules ([bottlerocket-core-kit#549])\n    * `containerd-2.1` ([bottlerocket-core-kit#621])\n      * Default `concurrent-download-chunk-size` setting is set at `8mib`\n      * Remove the support for Schema 1 images\n    * Update defaults for the `shutdown-grace-period` to 2 minutes and 30 seconds with the last 30 seconds reserved for critical pods for aws variants.\n  * Default device list strategy is set to `cdi-cri` for nvidia k8s device plugin\n  * `aws-k8s-1.34-nvidia` variant uses NVIDIA R580 drivers\n* Add `command` field to override default entrypoint for host and bootstrap containers ([#4636], [bottlerocket-core-kit#594]) - Thanks @kasimeka!\n* Add `containerd-2.1` setting for `concurrent-download-chunk-size` ([#4638], [bottlerocket-core-kit#645])\n\n## OS Changes\n* Update `bottlerocket-kernel-kit` from 4.2.0 to 4.3.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v430-2025-09-08) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.2.0...v4.3.0)) ([#4637])\n* Update `bottlerocket-core-kit` from 10.3.0 to 10.4.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1041-2025-09-11) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v10.3.0...v10.4.1)) ([#4639], [#4642])\n\n[#4631]: https://github.com/bottlerocket-os/bottlerocket/pull/4631\n[#4636]: https://github.com/bottlerocket-os/bottlerocket/pull/4636\n[#4637]: https://github.com/bottlerocket-os/bottlerocket/pull/4637\n[#4638]: https://github.com/bottlerocket-os/bottlerocket/pull/4638\n[#4639]: https://github.com/bottlerocket-os/bottlerocket/pull/4639\n[#4642]: https://github.com/bottlerocket-os/bottlerocket/pull/4642\n[bottlerocket-core-kit#549]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/549\n[bottlerocket-core-kit#581]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/581\n[bottlerocket-core-kit#594]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/594\n[bottlerocket-core-kit#621]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/621\n[bottlerocket-core-kit#636]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/636\n[bottlerocket-core-kit#645]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/645\n\n# v1.46.0 (2025-09-02)\n\n## Release Highlights\n* Add support for new Kubernetes setting `static-pods-enabled` ([bottlerocket-core-kit#641])\n* Add default bind directories for ephemeral storage ([bottlerocket-core-kit#632])\n\n## OS Changes\n* Update `bottlerocket-sdk` from 0.63.0 to 0.64.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.63.0...v0.64.0))([#4623])\n* Update `bottlerocket-core-kit` from 10.1.2 to 10.3.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1030-2025-08-26) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v10.1.2...v10.3.0)) ([#4623], [#4628])\n* Update `bottlerocket-kernel-kit` from 4.0.1 to 4.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v420-2025-08-25) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v4.0.1...v4.2.0)) ([#4623], [#4626])\n\n## Build Changes\n### Twoliter\n* Update `twoliter` from 0.11.0 to 0.12.0 and schema-version to 2 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0120---2025-08-21) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.11.0...v0.12.0)) ([#4624])\n\n[#4623]: https://github.com/bottlerocket-os/bottlerocket/pull/4623\n[#4624]: https://github.com/bottlerocket-os/bottlerocket/pull/4624\n[#4626]: https://github.com/bottlerocket-os/bottlerocket/pull/4626\n[#4628]: https://github.com/bottlerocket-os/bottlerocket/pull/4628\n[bottlerocket-core-kit#632]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/632\n[bottlerocket-core-kit#641]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/641\n\n# v1.45.0 (2025-08-18)\n\n## Release Highlights\n* Fix `containerd-2.0` settings for `max_concurrent_downloads` ([bottlerocket-core-kit#623])\n\n## OS Changes\n* Restrict kubelet's exec-start file permission to 0600 ([#4574])\n* Restrict kubelet-server.key file permission to 0600 ([#4599])\n* Update admin container from 0.12.1 to 0.12.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0122) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.12.1...v0.12.2)) ([#4612])\n* Update bootstrap container from 0.2.4 to 0.2.5 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#025) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.4...v0.2.5)) ([#4612])\n* Update control container from 0.8.6 to 0.8.7 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#087) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.6...v0.8.7)) ([#4612])\n* Update `bottlerocket-kernel-kit` from 3.3.1 to 4.0.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v401-2025-08-11) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v3.3.1...v4.0.1))([#4613])\n* Update `bottlerocket-core-kit` from 10.0.1 to 10.1.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1012-2025-08-14) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v10.0.1...v10.1.2))([#4615], [#4616], [#4619])\n\n[#4574]: https://github.com/bottlerocket-os/bottlerocket/pull/4574\n[#4599]: https://github.com/bottlerocket-os/bottlerocket/pull/4599\n[#4612]: https://github.com/bottlerocket-os/bottlerocket/pull/4612\n[#4613]: https://github.com/bottlerocket-os/bottlerocket/pull/4613\n[#4615]: https://github.com/bottlerocket-os/bottlerocket/pull/4615\n[#4616]: https://github.com/bottlerocket-os/bottlerocket/pull/4616\n[#4619]: https://github.com/bottlerocket-os/bottlerocket/pull/4619\n[bottlerocket-core-kit#623]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/623\n\n# v1.44.0 (2025-08-04)\n\n## Release Highlights\n* Remove `aws-k8s-1.27` and `aws-ecs-1` variants ([#4598])\n* Fix file descriptor leak in `apiserver exec` ([bottlerocket-core-kit#595])\n* Add `soci-snapshotter` support to kubernetes variants ([#4593])\n  * Configure `soci-snapshotter` for parallel pull unpack feature ([bottlerocket-core-kit#569])\n  * Optionally configure containerd and kubelet with `soci-snapshotter` via drop-in configuration files ([bottlerocket-core-kit#576])\n  * Extend selinux-policy to cover `soci-snapshotter` ([bottlerocket-core-kit#579])\n  * Add `configure-snapshotter.service` to reset state directories of snapshotters on boot when selected snapshotter changes ([bottlerocket-core-kit#582])\n  * Apply upstream patches to `soci-snapshotter` ([bottlerocket-core-kit#599])\n  * Drop CLI from `soci-snapshotter` ([bottlerocket-core-kit#569])\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 9.2.1 to 10.0.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v1001-2025-07-31) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v9.2.1...v10.0.1)) ([#4605], [#4609])\n* Update `bottlerocket-kernel-kit` from 3.2.1 to 3.3.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v331-2025-07-25) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v3.2.1...v3.3.1)) ([#4604])\n\n## Build Changes\n*  Add `reset-single-test` testsys command ([#4581])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Add `soci-snapshotter` support to kubernetes variants ([#4593])\n* Remove `aws-k8s-1.27` variants ([#4598])\n\n### ECS\n* Remove `aws-ecs-1` variants ([#4598])\n\n[#4581]: https://github.com/bottlerocket-os/bottlerocket/pull/4581\n[#4593]: https://github.com/bottlerocket-os/bottlerocket/pull/4593\n[#4598]: https://github.com/bottlerocket-os/bottlerocket/pull/4598\n[#4604]: https://github.com/bottlerocket-os/bottlerocket/pull/4604\n[#4605]: https://github.com/bottlerocket-os/bottlerocket/pull/4605\n[#4609]: https://github.com/bottlerocket-os/bottlerocket/pull/4609\n[bottlerocket-core-kit#569]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/569\n[bottlerocket-core-kit#576]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/576\n[bottlerocket-core-kit#579]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/579\n[bottlerocket-core-kit#582]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/582\n[bottlerocket-core-kit#595]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/595\n[bottlerocket-core-kit#599]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/599\n\n# v1.43.0 (2025-07-24)\n## OS Changes\n* Update `bottlerocket-core-kit` from 9.1.0 to 9.2.1 ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v9.1.0...v9.2.1))([#dee811f6])\n* Update `bottlerocket-kernel-kit` from 3.1.1 to 3.2.1 ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v3.1.1...v3.2.1))([#d6d31d6c])\n* Update admin container from 0.12.0 to 0.12.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0121) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.12.0...v0.12.1)) ([#4590])\n* Update bootstrap container from 0.2.3 to 0.2.4 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#024) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.3...v0.2.4)) ([#4590])\n* Update control container from 0.8.5 to 0.8.6 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#086) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.5...v0.8.6)) ([#4590])\n\n## Build Changes\n* Update `bottlerocket-sdk` from 0.62.0 to 0.63.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.62.0...v0.63.0)) ([#4592])\n### Twoliter\n* Update `twoliter` from 0.10.1 to 0.11.0 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0110---2024-07-17) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.10.1...v0.11.0)) ([#4594])\n\n[#4590]: https://github.com/bottlerocket-os/bottlerocket/pull/4590\n[#4592]: https://github.com/bottlerocket-os/bottlerocket/pull/4592\n[#4594]: https://github.com/bottlerocket-os/bottlerocket/pull/4594\n[#dee811f6]: https://github.com/bottlerocket-os/bottlerocket/commit/dee811f63f7da043fb1caea2f54815bdb05da697\n[#d6d31d6c]: https://github.com/bottlerocket-os/bottlerocket/commit/d6d31d6cc322454f3b5738075af805e3f388f966\n\n# v1.42.0 (2025-06-30)\n\n## Release Highlights\n* Add support for kubernetes `memory-swap-behavior` ([#4566], [bottlerocket-core-kit#541], [bottlerocket-settings-sdk#88]) - Thanks @teskje!\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 9.0.0 to 9.1.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v910-2025-06-23) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v9.0.0...v9.1.0)) ([#4569])\n* Update `bottlerocket-kernel-kit` from 3.1.0 to 3.1.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v311-2025-07-24) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v3.1.0...v3.1.1)) ([#4570])\n* Update admin container from 0.11.20 to 0.12.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#0120) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.11.20...v0.12.0)) ([#4565])\n* Update bootstrap container from 0.2.2 to 0.2.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#023) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.2...v0.2.3)) ([#4565])\n* Update control container from 0.8.4 to 0.8.5 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#085) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.4...v0.8.5)) ([#4565])\n\n## Orchestrator Changes\n### Kubernetes\n* Support kubernetes `memory-swap-behavior` setting [#4566] - Thanks @teskje!\n\n[#4565]: https://github.com/bottlerocket-os/bottlerocket/pull/4565\n[#4566]: https://github.com/bottlerocket-os/bottlerocket/pull/4566\n[#4569]: https://github.com/bottlerocket-os/bottlerocket/pull/4569\n[#4570]: https://github.com/bottlerocket-os/bottlerocket/pull/4570\n[bottlerocket-settings-sdk#88]:https://github.com/bottlerocket-os/bottlerocket-settings-sdk/pull/88\n[bottlerocket-core-kit#541]:https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/541\n\n# v1.41.0 (2025-06-17)\n\n## Release Highlights\n* Remove aws-k8s-1.26 variants ([#4519], [#4536])\n* Add `zramctl` to `util-linux` package ([bottlerocket-core-kit#543])\n* Enable LTO and arch-specific optimizations ([bottlerocket-sdk#276], [bottlerocket-core-kit#526])\n* Provide Vulkan ICD configuration files for variants using the 6.1 and 6.12 kernels ([bottlerocket-kernel-kit#138]) - Thanks, @iterion!\n* Build GRUB with optimizations ([bottlerocket-kernel-kit#163])\n* Provide `libnvidia-gpucomp.so` ([bottlerocket-kernel-kit#181]) - Thanks, @tzmtl!\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 8.2.0 to 9.0.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v900-2025-06-10) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v8.2.0...v9.0.0)) ([#4561])\n* Update `bottlerocket-kernel-kit` from 2.5.1 to 3.1.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v310-2025-06-11) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v2.5.1...v3.1.0)) ([#4561])\n* Drop setting generator for hugepages ([#4411])\n\n## Build Changes\n* Update `bottlerocket-sdk` from 0.61.0 to 0.62.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.61.0...v0.62.0)) ([#4561])\n\n## Orchestrator Changes\n### Kubernetes\n* Remove aws-k8s-1.26 variants ([#4519], [#4536])\n* Fix image patterns for ECR dual-stack endpoint ([#4518]) - Thanks @rxnew, @cartermckinnon!\n\n[#4411]: https://github.com/bottlerocket-os/bottlerocket/pull/4411\n[#4518]: https://github.com/bottlerocket-os/bottlerocket/pull/4518\n[#4519]: https://github.com/bottlerocket-os/bottlerocket/issues/4519\n[#4536]: https://github.com/bottlerocket-os/bottlerocket/pull/4536\n[#4561]: https://github.com/bottlerocket-os/bottlerocket/pull/4561\n[bottlerocket-core-kit#526]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/526\n[bottlerocket-core-kit#543]: https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/543\n[bottlerocket-sdk#276]: https://github.com/bottlerocket-os/bottlerocket-sdk/pull/276\n[bottlerocket-kernel-kit#138]: https://github.com/bottlerocket-os/bottlerocket-kernel-kit/pull/138\n[bottlerocket-kernel-kit#163]: https://github.com/bottlerocket-os/bottlerocket-kernel-kit/pull/163\n[bottlerocket-kernel-kit#181]: https://github.com/bottlerocket-os/bottlerocket-kernel-kit/pull/181\n\n# v1.40.0 (2025-05-22)\n\n## Release Highlights\n* Migrate ECS to use CDI ([bottlerocket-core-kit#482](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/482))\n* Support CDI and legacy NVIDIA Container Runtime modes ([#4475])\n* Add NVLink Subnet Manager to support NVIDIA B200 ([bottlerocket-core-kit#499](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/499), [bottlerocket-kernel-kit#142](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/pull/142))\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 8.1.1 to 8.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v820-2025-05-20) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v8.1.1...v8.2.0)) ([#4532])\n* Update `bottlerocket-kernel-kit` from 2.3.3 to 2.5.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v251-2025-05-22) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v2.3.3...v2.5.1)) ([#4537])\n* Update bootstrap container from 0.2.1 to 0.2.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#022) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.1...v0.2.2)) ([#4535])\n* Update control container from 0.8.3 to 0.8.4 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#084) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.3...v0.8.4)) ([#4535])\n\n[#4475]: https://github.com/bottlerocket-os/bottlerocket/pull/4475\n[#4532]: https://github.com/bottlerocket-os/bottlerocket/pull/4532\n[#4535]: https://github.com/bottlerocket-os/bottlerocket/pull/4535\n[#4537]: https://github.com/bottlerocket-os/bottlerocket/pull/4537\n\n# v1.39.1 (2025-05-19)\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 8.1.0 to 8.1.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v811-2025-05-14) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v8.1.0...v8.1.1)) ([#4522])\n\n## Build Changes\n\n### Twoliter\n* Update `twoliter` from 0.10.0 to 0.10.1 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0101---2025-05-14) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.10.0...v0.10.1)) ([#4523])\n\n[#4522]: https://github.com/bottlerocket-os/bottlerocket/pull/4522\n[#4523]: https://github.com/bottlerocket-os/bottlerocket/pull/4523\n\n# v1.39.0 (2025-05-06)\n\n## Release Highlights\n* Provide `containerd-2.0` and `containerd-1.7` ([bottlerocket-core-kit#485](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/485))\n* Add new k8s 1.33 variants ([#4507], [#4513]):\n  * Add `aws-k8s-1.33`, `aws-k8s-1.33-nvidia`, `aws-k8s-1.33-fips`, `vmware-k8s-1.33`, and `vmware-k8s-1.33-fips`variants\n  * FIPS variants use 6.1 kernel, all others use 6.12 kernel\n  * Use EROFS for root filesystem on Kernel 6.12 variants\n  * Use `containerd-2.0` on all k8s 1.33 variants\n  * Use EBS volume `gp3` for all AWS k8s 1.33 variant AMIs\n  * Require IMDSv2 by default for new k8s 1.33 variant AMIs. For applications not yet compatible\n    with IMDSv2, this can be disabled at the instance or account level. See\n    [the AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html#instance-metadata-options-order-of-precedence)\n    for more details.\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 8.0.0 to 8.1.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v810-2025-05-05) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v8.0.0...v8.1.0)) ([#4510])\n* Update `bottlerocket-kernel-kit` from 2.3.0 to 2.3.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v233-2025-05-01) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v2.3.0...v2.3.3)) ([#4508])\n* Update admin container from 0.11.19 to 0.11.20 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#01120) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.11.19...v0.11.20)) ([#4509])\n* Update bootstrap container from 0.2.0 to 0.2.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#021) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.2.0...v0.2.1)) ([#4509])\n* Update control container from 0.8.2 to 0.8.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#083) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.2...v0.8.3)) ([#4509])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Add `aws-k8s-1.33`, `aws-k8s-1.33-nvidia`, `aws-k8s-1.33-fips`, `vmware-k8s-1.33`, and `vmware-k8s-1.33-fips`variants ([#4507])\n* Add new Kubernetes settings ([#4506])\n  * `containerLogMaxWorkers`\n  * `containerLogMonitorInterval`\n  * `singleProcessOOMKill`\n\n## Build Changes\n* Use GP3 volumes and require IMDSv2 by default for AWS k8s 1.33 variant AMIs. ([#4513])\n\n### Twoliter\n* Update `twoliter` from 0.9.0 to 0.10.0 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#0100---2025-05-06) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.9.0...v0.10.0)) ([#4512])\n\n[#4506]: https://github.com/bottlerocket-os/bottlerocket/pull/4506\n[#4507]: https://github.com/bottlerocket-os/bottlerocket/pull/4507\n[#4508]: https://github.com/bottlerocket-os/bottlerocket/pull/4508\n[#4509]: https://github.com/bottlerocket-os/bottlerocket/pull/4509\n[#4510]: https://github.com/bottlerocket-os/bottlerocket/pull/4510\n[#4512]: https://github.com/bottlerocket-os/bottlerocket/pull/4512\n[#4513]: https://github.com/bottlerocket-os/bottlerocket/pull/4513\n\n# v1.38.0 (2025-04-29)\n\n## Release Highlights\n* Move aws-ecs-2-nvidia, aws-k8s-1.28-nvidia, aws-k8s-1.29-nvidia, aws-k8s-1.30-nvidia, aws-k8s-1.31-nvidia, and aws-k8s-1.32-nvidia variants from NVIDIA r535 driver to r570 driver ([#4499], [#4441])\n* Remove aws-k8s-1.25 variants ([#4497], [#4496])\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 7.0.1 to 8.0.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v800-2025-04-28) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v7.0.1...v8.0.0)) ([#4501])\n* Update `bottlerocket-kernel-kit` from 2.2.2 to 2.3.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v230-2025-04-28) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v2.2.2...v2.3.0)) ([#4498])\n\n## Build Changes\n* Pass missing vars to sbkeys script ([#4493])\n\n[#4493]: https://github.com/bottlerocket-os/bottlerocket/pull/4493\n[#4496]: https://github.com/bottlerocket-os/bottlerocket/issues/4496\n[#4497]: https://github.com/bottlerocket-os/bottlerocket/pull/4497\n[#4498]: https://github.com/bottlerocket-os/bottlerocket/pull/4498\n[#4499]: https://github.com/bottlerocket-os/bottlerocket/pull/4499\n[#4441]: https://github.com/bottlerocket-os/bottlerocket/issues/4441\n[#4501]: https://github.com/bottlerocket-os/bottlerocket/pull/4501\n\n# v1.37.0 (2025-04-21)\n\n## Release Highlights\n* Add `brush` to enable `aws-signing-helper` and IAM Roles Anywhere usage ([bottlerocket-core-kit#451](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/451))\n* Clear configuration-files and services on upgrades ([bottlerocket-core-kit#456](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/456))\n* Remove `shimpei` and `oci-add-hooks` ([bottlerocket-core-kit#458](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/458))\n* Use the NVIDIA Container Runtime to configure GPUs for containers ([bottlerocket-core-kit#458](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/458))\n* Update `runc` from 1.1.15 to 1.2.6 ([bottlerocket-core-kit#463](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/463))\n* Allow lookups of .local domains using unicast DNS  ([bottlerocket-core-kit#464](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/464)) - Thanks @tzneal!\n* Let `kubelet` start when swap is on ([bottlerocket-core-kit#473](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/473))\n\n## OS Changes\n* Remove unnecessary settings for OCI Hooks API  ([#4474])\n* Update migrations to delete configuration-files and services on downgrade ([#4478])\n* Update `bottlerocket-core-kit` from 6.2.0 to 7.0.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v701-2025-04-22) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v6.3.0...v7.0.1)) ([#4471], [#4485], [#4490])\n* Update `bottlerocket-kernel-kit` from 2.1.0 to 2.2.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v222-2025-04-18) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v2.1.0...v2.2.2)) ([#4485], [#4489])\n* Update admin container from 0.11.18 to 0.11.19 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#01119) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.11.18...v0.11.19)) ([#4476])\n* Update bootstrap container from 0.1.3 to 0.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#020) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.1.3...v0.2.0)) ([#4476])\n* Update control container from 0.8.1 to 0.8.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#082) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.8.1...v0.8.2)) ([#4476])\n\n## Build Changes\n* Update Rust dependencies ([#4468], [#4469])\n* Update secure boot keys to include aws-partition & ca-signing-algo arguments ([#4450])\n* Update `bottlerocket-sdk` from 0.60.0 to 0.61.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.60.0...v0.61.0)) ([#4485])\n\n### Twoliter\n* Update `twoliter` from 0.8.1 to 0.9.0 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#090---2025-04-16) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.8.1...v0.9.0)) ([#4484])\n\n[#4450]: https://github.com/bottlerocket-os/bottlerocket/pull/4450\n[#4468]: https://github.com/bottlerocket-os/bottlerocket/pull/4468\n[#4469]: https://github.com/bottlerocket-os/bottlerocket/pull/4469\n[#4471]: https://github.com/bottlerocket-os/bottlerocket/pull/4471\n[#4474]: https://github.com/bottlerocket-os/bottlerocket/pull/4474\n[#4476]: https://github.com/bottlerocket-os/bottlerocket/pull/4476\n[#4478]: https://github.com/bottlerocket-os/bottlerocket/pull/4478\n[#4484]: https://github.com/bottlerocket-os/bottlerocket/pull/4484\n[#4485]: https://github.com/bottlerocket-os/bottlerocket/pull/4485\n[#4489]: https://github.com/bottlerocket-os/bottlerocket/pull/4489\n[#4490]: https://github.com/bottlerocket-os/bottlerocket/pull/4490\n\n# v1.36.0 (2025-04-07)\n\n## Release Highlights\n* Switch to igzip (x86_64) or pigz with zlib-ng (aarch64) to decompress container images ([bottlerocket-core-kit#443](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/443))\n* Add support for more AWS regions in schnauzer and host-ctr ([bottlerocket-core-kit#454](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/454))\n\n## OS Changes\n* Update `bottlerocket-core-kit` from 6.1.0 to 6.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v620-2025-04-01) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v6.1.0...v6.2.0)) ([#4460], [#4452])\n* Update `bottlerocket-kernel-kit` from 1.3.0 to 2.1.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v210-2024-04-02) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v1.3.0...v2.1.0)) ([#4461])\n\n## Orchestrator Changes\n### Kubernetes\n* Authenticate with ECR public to avoid rate limits ([#4419]) - Thanks @MarkIannucci!\n* Support ECR credential provider in more ISO partitions ([#4459])\n\n## Build Changes\n* Remove redundant metadata migration helpers ([#4459])\n* Archive migrations prior to v1.34.0 ([#4459])\n* Remove schnauzer and apiclient dependencies from bottlerocket repo ([#4459])\n\n### Documentation Changes\n* Fix links to `./packages` to point to the `bottlerocket-core-kit/packages` ([#4446])\n\n[#4419]: https://github.com/bottlerocket-os/bottlerocket/pull/4419\n[#4446]: https://github.com/bottlerocket-os/bottlerocket/pull/4446\n[#4452]: https://github.com/bottlerocket-os/bottlerocket/pull/4452\n[#4459]: https://github.com/bottlerocket-os/bottlerocket/pull/4459\n[#4460]: https://github.com/bottlerocket-os/bottlerocket/pull/4460\n[#4461]: https://github.com/bottlerocket-os/bottlerocket/pull/4461\n\n# v1.35.0 (2025-03-24)\n\n## Release Highlights\n* Move the `aws-ecs-1` kernel from 5.10 to 5.15 ([#4434])\n* Persist sysctl setting changes to /etc/sysctl.d ([bottlerocket-core-kit#333](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/333)) - Thanks @aetimmes\n* Updated cis report to account for formatting change in iptables ([bottlerocket-core-kit#390](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/390))\n* Include SHA-256 and SHA-512 CPU routines in the ARM kernel image ([bottlerocket-kernel-kit#67](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/pull/67))\n\n## OS Changes\n* Update admin container from 0.11.16 to 0.11.18 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-admin-container/blob/develop/CHANGELOG.md#01118) ([commits](https://github.com/bottlerocket-os/bottlerocket-admin-container/compare/v0.11.16...v0.11.18)) ([#4431], [#4443])\n* Update bootstrap container from 0.1.1 to 0.1.3 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/blob/develop/CHANGELOG.md#013) ([commits](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container/compare/v0.1.1...v0.1.3)) ([#4432], [#4443])\n* Update control container from 0.7.20 to 0.8.1 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-control-container/blob/develop/CHANGELOG.md#081) ([commits](https://github.com/bottlerocket-os/bottlerocket-control-container/compare/v0.7.20...v0.8.1)) ([#4431], [#4443])\n\n## Build Changes\n* Update `bottlerocket-core-kit` from 6.0.2 to 6.1.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v610-2025-03-14) ([commits](https://github.com/bottlerocket-os/bottlerocket-core-kit/compare/v6.0.2...v6.1.0)) ([#4439])\n* Update `bottlerocket-kernel-kit` from 1.2.0 to 1.3.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v130-2024-03-06) ([commits](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/compare/v1.2.0...v1.3.0)) ([#4439])\n* Update `bottlerocket-sdk` from 0.50.1 to 0.60.0 ([commits](https://github.com/bottlerocket-os/bottlerocket-sdk/compare/v0.50.1...v0.60.0)) ([#4439])\n* Bump `ring` from 0.17.8 to 0.17.13 ([#4430])\n\n### Twoliter\n* Update `twoliter` from 0.7.3 to 0.8.1 [CHANGELOG](https://github.com/bottlerocket-os/twoliter/blob/develop/CHANGELOG.md#081---2025-03-13) ([commits](https://github.com/bottlerocket-os/twoliter/compare/v0.7.3...v0.8.1)) ([#4433], [#4438])\n\n[#4430]: https://github.com/bottlerocket-os/bottlerocket/pull/4430\n[#4431]: https://github.com/bottlerocket-os/bottlerocket/pull/4431\n[#4432]: https://github.com/bottlerocket-os/bottlerocket/pull/4432\n[#4433]: https://github.com/bottlerocket-os/bottlerocket/pull/4433\n[#4434]: https://github.com/bottlerocket-os/bottlerocket/pull/4434\n[#4438]: https://github.com/bottlerocket-os/bottlerocket/pull/4438\n[#4439]: https://github.com/bottlerocket-os/bottlerocket/pull/4439\n[#4443]: https://github.com/bottlerocket-os/bottlerocket/pull/4443\n\n# v1.34.0 (2025-03-03)\n\n## OS Changes\n\n* Add support for NVIDIA Multi-Instance GPU (MIG) ([#4418])\n\n## Build Changes\n* Update bottlerocket-core-kit from 6.0.1 to 6.0.2 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/CHANGELOG.md#v602-2025-02-26) ([#4416])\n* Update bottlerocket-kernel-kit from 1.1.2 to 1.2.0 [CHANGELOG](https://github.com/bottlerocket-os/bottlerocket-kernel-kit/blob/develop/CHANGELOG.md#v120-2024-02-26) ([#4416])\n\n### Twoliter\n\n* Update Twoliter to 0.7.3 ([#4416])\n\n[#4416]: https://github.com/bottlerocket-os/bottlerocket/pull/4416\n[#4418]: https://github.com/bottlerocket-os/bottlerocket/pull/4418\n\n# v1.33.0 (2025-02-26)\n\n## Release Highlights\n* Remove aws-k8s-1.24 variants ([#4359])\n\n## OS Changes\n* Allow default host containers to be changed without a migration ([#4324])\n* Add default managed Bootstrap container ([#4349])\n* Correct migrations for public control containers. ([#4388])\n\n## Build Changes\n* Update bottlerocket-kernel-kit to 1.1.2 ([#4383], [#4386], [#4394], [#4408])\n* Update bottlerocket-core-kit to 6.0.1 ([#4387], [#4403])\n\n### Twoliter\n* Update Twoliter to 0.7.2 ([#4384])\n\n## Orchestrator Changes\n### Kubernetes\n* Deprecate Kubernetes 1.24 AWS variants ([#4379])\n\n[#4324]: https://github.com/bottlerocket-os/bottlerocket/pull/4324\n[#4349]: https://github.com/bottlerocket-os/bottlerocket/pull/4349\n[#4359]: https://github.com/bottlerocket-os/bottlerocket/issues/4359\n[#4379]: https://github.com/bottlerocket-os/bottlerocket/pull/4379\n[#4383]: https://github.com/bottlerocket-os/bottlerocket/pull/4383\n[#4384]: https://github.com/bottlerocket-os/bottlerocket/pull/4384\n[#4386]: https://github.com/bottlerocket-os/bottlerocket/pull/4386\n[#4387]: https://github.com/bottlerocket-os/bottlerocket/pull/4387\n[#4388]: https://github.com/bottlerocket-os/bottlerocket/pull/4388\n[#4394]: https://github.com/bottlerocket-os/bottlerocket/pull/4394\n[#4403]: https://github.com/bottlerocket-os/bottlerocket/pull/4403\n[#4408]: https://github.com/bottlerocket-os/bottlerocket/pull/4408\n\n# v1.32.0 (2025-01-24)\n\n## Build Changes\n* Update bottlerocket-core-kit to 5.4.2 ([#4374])\n* Update bottlerocket-kernel-kit to 1.0.6 ([#4374])\n* Update bottlerocket-sdk to 0.50.1 ([#4374])\n\n### Twoliter\n\n* Update Twoliter to 0.7.1 ([#4373])\n\n[#4373]: https://github.com/bottlerocket-os/bottlerocket/pull/4373\n[#4374]: https://github.com/bottlerocket-os/bottlerocket/pull/4374\n\n# v1.31.0 (2025-01-21)\n\n## OS Changes\n\n* Update host containers ([#4360])\n\n## Build Changes\n* Update bottlerocket-core-kit to 5.4.1 ([#4365])\n* Update bottlerocket-kernel-kit to 1.0.4 ([#4366])\n\n### Twoliter\n\n* Update Twoliter to 0.7.0 ([#4362])\n\n[#4360]: https://github.com/bottlerocket-os/bottlerocket/pull/4360\n[#4362]: https://github.com/bottlerocket-os/bottlerocket/pull/4362\n[#4365]: https://github.com/bottlerocket-os/bottlerocket/pull/4365\n[#4366]: https://github.com/bottlerocket-os/bottlerocket/pull/4366\n\n# v1.30.0 (2025-01-07)\n\n## OS Changes\n* Update host containers ([#4353])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Add Kubernetes 1.32 variants ([#4320])\n* Add device-ownership-from-security-context setting (default to true on aws-k8s-1.32) ([#4345])\n\n## Build Changes\n* Update bottlerocket-core-kit to 5.3.0 ([#4351])\n* Update bottlerocket-kernel-kit to 1.0.2 ([#4344])\n\n[#4320]: https://github.com/bottlerocket-os/bottlerocket/pull/4320\n[#4344]: https://github.com/bottlerocket-os/bottlerocket/pull/4344\n[#4345]: https://github.com/bottlerocket-os/bottlerocket/pull/4345\n[#4351]: https://github.com/bottlerocket-os/bottlerocket/pull/4351\n[#4353]: https://github.com/bottlerocket-os/bottlerocket/pull/4353\n\n# v1.29.0 (2024-12-17)\n\n## Build Changes\n* Add bottlerocket-kernel-kit 1.0.0 ([#4332])\n* Update bottlerocket-core-kit to 5.0.0 ([#4332])\n* Update bottlerocket-sdk to 0.50.0 ([#4332])\n\n## OS Changes\n* Enable plugins and detailed EBS volume stats for `nvme-cli` ([bottlerocket-core-kit#269](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/269))\n* Set `LoaderTimeInitUSec` and `LoaderTimeExecUSec` in GRUB ([bottlerocket-core-kit#273](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/273))\n\n[#4332]: https://github.com/bottlerocket-os/bottlerocket/pull/4332\n\n# v1.28.0 (2024-12-08)\n\n## Release Highlights\n* Enable EFA support to Bottlerocket AMIs ([#4290])\n* Fix `io_uring` regression in 6.1 kernel ([bottlerocket-core-kit#284](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/284))\n* Allow overriding the max-pods file with one from your variant ([bottlerocket-core-kit#279](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/279)) - thanks @tzneal\n\n## Build Changes\n* Update bottlerocket-core-kit to 4.0.1 ([#4322])\n\n### OS Changes\n* Update host containers ([#4312])\n* Update Twoliter to 0.6.0 ([#4323])\n\n### Documentation Changes\n* Update models README references ([#4138])\n\n[#4138]: https://github.com/bottlerocket-os/bottlerocket/pull/4138\n[#4290]: https://github.com/bottlerocket-os/bottlerocket/pull/4290\n[#4312]: https://github.com/bottlerocket-os/bottlerocket/pull/4312\n[#4322]: https://github.com/bottlerocket-os/bottlerocket/pull/4322\n[#4323]: https://github.com/bottlerocket-os/bottlerocket/pull/4323\n\n# v1.27.1 (2024-11-16)\n\n## Release Highlights\n* Add patch for kernel-5.15 to fix issues when using IPv6 ([bottlerocket-core-kit#266](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/266))\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to 3.3.2 ([#4301])\n\n[#4301]: https://github.com/bottlerocket-os/bottlerocket/pull/4301\n\n# v1.27.0 (2024-11-12)\n\n## Release Highlights\n* Add FIPS variants ([#4274], [#1667], [#4267])\n* Drop k8s 1.28 and k8s 1.29 metal variants ([#4287])\n\n## OS Changes\n* Add aws-creds settings defaults to all AWS variants ([#4285])\n* Add support for migrations to modify aws-config setting generators ([#4271])\n\n## Build Changes\n* Update bottlerocket-core-kit to 3.3.0 ([#4292])\n* Update bottlerocket-sdk to 0.47.0 ([#4286])\n\n[#1667]: https://github.com/bottlerocket-os/bottlerocket/pull/1667\n[#4267]: https://github.com/bottlerocket-os/bottlerocket/pull/4267\n[#4271]: https://github.com/bottlerocket-os/bottlerocket/pull/4271\n[#4274]: https://github.com/bottlerocket-os/bottlerocket/pull/4274\n[#4285]: https://github.com/bottlerocket-os/bottlerocket/pull/4285\n[#4286]: https://github.com/bottlerocket-os/bottlerocket/pull/4286\n[#4287]: https://github.com/bottlerocket-os/bottlerocket/pull/4287\n[#4292]: https://github.com/bottlerocket-os/bottlerocket/pull/4292\n\n# v1.26.2 (2024-11-04)\n\n## Release Highlights\n* Wait for kubelet device-manager socket before starting nvidia-k8s-device-plugin ([bottlerocket-core-kit#238](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/238))\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to 3.1.5 ([#4280])\n\n[#4280]: https://github.com/bottlerocket-os/bottlerocket/pull/4280\n\n# v1.26.1 (2024-10-24)\n\n## Release Highlights\n* Revert system-wide configuration to block writeable/executable memory in systemd services ([bottlerocket-core-kit#215](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/215))\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to 3.1.1 ([#4264])\n\n[#4264]: https://github.com/bottlerocket-os/bottlerocket/pull/4264\n\n# v1.26.0 (2024-10-23)\n\n## Release Highlights\n* Update NVIDIA driver to 535.216.01 ([#4254])\n* Move kmod-5.10-nvidia tesla package for aws-ecs-1-nvidia variant from branch R470 to R535 ([#4251])\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to 3.1.0 ([#4254], [#4251])\n* Update NVIDIA driver to 535.216.01 ([#4254])\n* Update twoliter to 0.5.0 ([#4251])\n* Update bottlerocket-sdk to 0.46 ([#4251])\n* Standardize RPM release fields for RPM packages ([#4244])\n\n## Orchestrator Changes\n\n### ECS\n* Move kmod-5.10-nvidia tesla package for aws-ecs-1-nvidia variant from branch R470 to R535 ([#4251])\n\n### Documentation Changes\n* Add link to bootstrap-commands documentation ([#4247])\n\n[#4244]: https://github.com/bottlerocket-os/bottlerocket/pull/4244\n[#4247]: https://github.com/bottlerocket-os/bottlerocket/pull/4247\n[#4251]: https://github.com/bottlerocket-os/bottlerocket/pull/4251\n[#4254]: https://github.com/bottlerocket-os/bottlerocket/pull/4254\n\n# v1.25.0 (2024-10-15)\n\n## Release Highlights\n* Remove aws-k8s-1.23 variants (https://github.com/bottlerocket-os/bottlerocket/issues/4083)\n* Add support for NVIDIA GPU time slicing (closes https://github.com/bottlerocket-os/bottlerocket/issues/2347)\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to 2.9.0 ([#4242])\n* Update host containers ([#4241])\n* Update twoliter to v0.4.7 ([#4236])\n* Fix permissions for kubelet-exec-start-conf file ([#4199])\n* Add support for NVIDIA GPU time slicing ([#4230])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Drop Kubernetes 1.23 AWS variants ([#4227], [#4237])\n\n### Documentation Changes\n* Add security guidance for NVIDIA GPU time-slicing ([#4240])\n\n[#4199]: https://github.com/bottlerocket-os/bottlerocket/pull/4199\n[#4227]: https://github.com/bottlerocket-os/bottlerocket/pull/4227\n[#4230]: https://github.com/bottlerocket-os/bottlerocket/pull/4230\n[#4236]: https://github.com/bottlerocket-os/bottlerocket/pull/4236\n[#4237]: https://github.com/bottlerocket-os/bottlerocket/pull/4237\n[#4240]: https://github.com/bottlerocket-os/bottlerocket/pull/4240\n[#4241]: https://github.com/bottlerocket-os/bottlerocket/pull/4241\n[#4242]: https://github.com/bottlerocket-os/bottlerocket/pull/4242\n\n# v1.24.1 (2024-10-04)\n\n## Release Highlights\n* Update ecs-agent to 1.86.3 ([bottlerocket-core-kit#168](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/168)) - Closes issue [#4186](https://github.com/bottlerocket-os/bottlerocket/issues/4186)\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to 2.8.4 ([#4231])\n* Update host containers ([#4233])\n\n### Documentation Changes\n* Update QUICKSTART-EKS.md ([#4228]) - Thanks @bryanhsu00 for the suggested fix!\n\n[#4228]: https://github.com/bottlerocket-os/bottlerocket/pull/4228\n[#4231]: https://github.com/bottlerocket-os/bottlerocket/pull/4231\n[#4233]: https://github.com/bottlerocket-os/bottlerocket/pull/4233\n\n# v1.24.0 (2024-09-27)\n\n## Release Highlights\n* Use open GPU drivers on P4 and P5 instances automatically [bottlerocket-core-kit#114](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/114)\n* Update to nvidia-container-toolkit 1.16.2 [bottlerocket-core-kit#161](https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/161)\n\n## Build Changes\n\n### OS Changes\n* Update bottlerocket-core-kit to v2.8.1 ([#4222])\n\n### Settings Extensions\n* Drop dependency on glibc-devel ([#4213])\n\n### Documentation Changes\n* Update QUICKSTART-ECS.md and QUICKSTART-EKS.md ([#4169])  Thanks @bryantbiggs!\n\n[#4169]: https://github.com/bottlerocket-os/bottlerocket/pull/4169\n[#4213]: https://github.com/bottlerocket-os/bottlerocket/pull/4213\n[#4222]: https://github.com/bottlerocket-os/bottlerocket/pull/4222\n\n# v1.23.0 (2024-09-19)\n\n## Orchestrator Changes\n\n### Kubernetes\n* Support Kubernetes NVIDIA Device Plugin configurations through API ([#4182])\n* Support NVIDIA Container Toolkit configurations through API ([#4182])\n\n## Build Changes\n* Update bottlerocket-sdk to 0.45 ([#4189])\n* Add `Twoliter.override` to `.gitignore` ([#4202])\n\n### Twoliter\n* Update bottlerocket-core-kit ([#4189], [#4203], [#4211])\n* Perform binary checksum validation ([#4192])\n* Update Twoliter to v0.4.6 ([#4200])\n\n### Settings Extensions\n* Update bottlerocket-settings-models to v0.4.0 ([#4182])\n\n### Documentation Changes\n* Add NVIDIA Device Plugin and NVIDIA Container Toolkit notes to SECURITY_GUIDANCE.md ([#4205])\n\n[#4182]: https://github.com/bottlerocket-os/bottlerocket/pull/4182\n[#4189]: https://github.com/bottlerocket-os/bottlerocket/pull/4189\n[#4192]: https://github.com/bottlerocket-os/bottlerocket/pull/4192\n[#4200]: https://github.com/bottlerocket-os/bottlerocket/pull/4200\n[#4202]: https://github.com/bottlerocket-os/bottlerocket/pull/4202\n[#4203]: https://github.com/bottlerocket-os/bottlerocket/pull/4203\n[#4205]: https://github.com/bottlerocket-os/bottlerocket/pull/4205\n[#4211]: https://github.com/bottlerocket-os/bottlerocket/pull/4211\n\n# v1.22.0 (2024-09-10)\n\n## Orchestrator Changes\n\n### Kubernetes\n* Add Kubernetes 1.31 variants ([#4142])\n\n## OS Changes\n* Update host containers ([#4171])\n* Add support for bootstrap commands ([#4131])\n\n## Build Changes\n\n### Twoliter\n* Update bottlerocket-core-kit to v2.4.1 ([#4183], [#4177], [#4168])\n\n### Settings Extensions\n* Update bottlerocket-settings-models to v0.4.0 ([#4131])\n\n[#4131]: https://github.com/bottlerocket-os/bottlerocket/pull/4131\n[#4142]: https://github.com/bottlerocket-os/bottlerocket/pull/4142\n[#4168]: https://github.com/bottlerocket-os/bottlerocket/pull/4168\n[#4171]: https://github.com/bottlerocket-os/bottlerocket/pull/4171\n[#4177]: https://github.com/bottlerocket-os/bottlerocket/pull/4177\n[#4183]: https://github.com/bottlerocket-os/bottlerocket/pull/4183\n\n# v1.21.1 (2024-08-21)\n\n## OS Changes\n\n* Update host containers ([#4153])\n\n## Build Changes\n* Use workspace dependencies for all dependencies ([#4132])\n\n### Twoliter\n* Update bottlerocket-core-kit to v2.3.5 ([#4156], [#4152], [#4143], [#4139])\n* Update Twoliter to v0.4.5 ([#4159])\n\n### Settings Extensions\n* Update bottlerocket-settings-models to v0.3.0 ([#4145])\n\n## README changes\n* Update command for SSM Start session on host container ([#4129]) - Thanks @Veronica4036!\n\n[#4129]: https://github.com/bottlerocket-os/bottlerocket/pull/4129\n[#4132]: https://github.com/bottlerocket-os/bottlerocket/pull/4132\n[#4139]: https://github.com/bottlerocket-os/bottlerocket/pull/4139\n[#4143]: https://github.com/bottlerocket-os/bottlerocket/pull/4143\n[#4145]: https://github.com/bottlerocket-os/bottlerocket/pull/4145\n[#4152]: https://github.com/bottlerocket-os/bottlerocket/pull/4152\n[#4153]: https://github.com/bottlerocket-os/bottlerocket/pull/4153\n[#4156]: https://github.com/bottlerocket-os/bottlerocket/pull/4156\n[#4159]: https://github.com/bottlerocket-os/bottlerocket/pull/4159\n\n# v1.21.0 (2024-08-06)\n\n## OS Changes\n\n* Update host containers ([#4117])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Enable k8s reserved cpus ([#3964])\n* Drop k8s 1.27 metal and VMware variants ([#4079])\n* Drop k8s 1.26 metal and VMware variants ([#4018])\n* Build the pause image from upstream ([#3940]) - Thanks @tzneal!\n\n### ECS\n\n* Port to the ECS settings extension ([#3984])\n\n## Build Changes\n\n* Archive previous release migrations ([#4014])\n* Update Go dependencies ([#3999])\n\n### Twoliter\n\n* Migrate to core kit ([#4060])\n* Remove leftover vendor section ([#4071])\n* Update Twoliter to 0.4.4 ([#4008], [#4086], [#4093], [#4123])\n* Update bottlerocket-core-kit to v2.3.1 ([#4122])\n* Update bottlerocket-sdk to 0.43 ([#4122])\n\n### Settings Extensions\n\n* Use settings models vended by bottlerocket-settings-sdk ([#4057])\n* Migrate to settings plugins and eliminate variant-based conditional compilation ([#4038])\n* Enable settings extensions ([#4050])\n* Update to bottlerocket-settings-models v0.2.0 ([#4118])\n\n\n## Platform Changes\n\n### AWS\n\n* Add udev rule to create symlinks using EBS volumes’ device names ([#3977])\n\n## Package changes\n\n* Add Neuron kmod for 6.1 kernel ([#3982])\n* Update containerd to 1.7.20 ([#4122])\n\n## README changes\n\n* Fix OpenAPI spec link ([#4062])\n* Fix NVIDIA variants in SSM parameters ([#4047])\n* Add k8s command to retrieve log archive ([#3993])\n* Fix netdog reference link ([#3974]) - Thanks @emmanuel-ferdman!\n* Update BUILDING.md with the latest Docker requirements ([#4098])\n\n[#3940]: https://github.com/bottlerocket-os/bottlerocket/pull/3940\n[#3964]: https://github.com/bottlerocket-os/bottlerocket/pull/3964\n[#3974]: https://github.com/bottlerocket-os/bottlerocket/pull/3974\n[#3977]: https://github.com/bottlerocket-os/bottlerocket/pull/3977\n[#3982]: https://github.com/bottlerocket-os/bottlerocket/pull/3982\n[#3984]: https://github.com/bottlerocket-os/bottlerocket/pull/3984\n[#3993]: https://github.com/bottlerocket-os/bottlerocket/pull/3993\n[#3999]: https://github.com/bottlerocket-os/bottlerocket/pull/3999\n[#4008]: https://github.com/bottlerocket-os/bottlerocket/pull/4008\n[#4014]: https://github.com/bottlerocket-os/bottlerocket/pull/4014\n[#4018]: https://github.com/bottlerocket-os/bottlerocket/pull/4018\n[#4027]: https://github.com/bottlerocket-os/bottlerocket/pull/4027\n[#4038]: https://github.com/bottlerocket-os/bottlerocket/pull/4038\n[#4047]: https://github.com/bottlerocket-os/bottlerocket/pull/4047\n[#4050]: https://github.com/bottlerocket-os/bottlerocket/pull/4050\n[#4057]: https://github.com/bottlerocket-os/bottlerocket/pull/4057\n[#4060]: https://github.com/bottlerocket-os/bottlerocket/pull/4060\n[#4062]: https://github.com/bottlerocket-os/bottlerocket/pull/4062\n[#4071]: https://github.com/bottlerocket-os/bottlerocket/pull/4071\n[#4079]: https://github.com/bottlerocket-os/bottlerocket/pull/4079\n[#4086]: https://github.com/bottlerocket-os/bottlerocket/pull/4086\n[#4093]: https://github.com/bottlerocket-os/bottlerocket/pull/4093\n[#4098]: https://github.com/bottlerocket-os/bottlerocket/pull/4098\n[#4117]: https://github.com/bottlerocket-os/bottlerocket/pull/4117\n[#4118]: https://github.com/bottlerocket-os/bottlerocket/pull/4118\n[#4122]: https://github.com/bottlerocket-os/bottlerocket/pull/4122\n[#4123]: https://github.com/bottlerocket-os/bottlerocket/pull/4123\n\n# v1.20.5 (2024-07-30)\n\n## OS Changes\n\n* Update docker-engine to v25.0.6 ([#4111])\n* Update containerd to 1.6.34 ([#4113])\n* Update kernels: 5.10.220, 5.15.162, and 6.1.97 ([#4104])\n* Update host containers ([#4110])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Add latest instance types to eni-max-pods mapping ([#4108])\n\n[#4104]: https://github.com/bottlerocket-os/bottlerocket/pull/4104\n[#4108]: https://github.com/bottlerocket-os/bottlerocket/pull/4108\n[#4110]: https://github.com/bottlerocket-os/bottlerocket/pull/4110\n[#4111]: https://github.com/bottlerocket-os/bottlerocket/pull/4111\n[#4113]: https://github.com/bottlerocket-os/bottlerocket/pull/4113\n\n# v1.20.4 (2024-07-15)\n\n## OS Changes\n* Update kernels: 5.10.219 and 6.1.94 ([#4080])\n* Update docker-engine and docker-cli to v25.0.5 ([#4091])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Update patches for kubernetes 1.23, 1.24, 1.25, and 1.26 ([#4084])\n* Update sources for kubernetes 1.27, 1.28, 1.29, and 1.30 ([#4089])\n\n[#4080]: https://github.com/bottlerocket-os/bottlerocket/pull/4080\n[#4084]: https://github.com/bottlerocket-os/bottlerocket/pull/4084\n[#4089]: https://github.com/bottlerocket-os/bottlerocket/pull/4089\n[#4091]: https://github.com/bottlerocket-os/bottlerocket/pull/4091\n\n# v1.20.3 (2024-06-26)\n\n## OS Changes\n* Update kernels: 5.10.218, 5.15.160, and 6.1.92 ([#4064], [#4066])\n\n[#4064]: https://github.com/bottlerocket-os/bottlerocket/pull/4064\n[#4066]: https://github.com/bottlerocket-os/bottlerocket/pull/4066\n\n# v1.20.2 (2024-06-12)\n\n## OS Changes\n* Update kernel to 5.10.217 [#4039]\n* Mount static kmod as /usr/local/sbin/modprobe [#4037]\n\n[#4037]: https://github.com/bottlerocket-os/bottlerocket/pull/4037\n[#4039]: https://github.com/bottlerocket-os/bottlerocket/pull/4039\n\n# v1.20.1 (2024-06-04)\n\n## OS Changes\n* Update kernels to 6.1.90, 5.15.158, and 5.10.216 ([#3976], [#3972])\n* Include statically linked version of kmod ([#3981])\n* Specify AWS EULA as license for kmod-*-nvidia packages ([#3991])\n* Update source for Fabric Manager binaries ([#4015])\n* Update NVIDIA driver versions to 470.256.02 and 535.183.01 ([#4029])\n\n[#3972]: https://github.com/bottlerocket-os/bottlerocket/pull/3972\n[#3976]: https://github.com/bottlerocket-os/bottlerocket/pull/3976\n[#3981]: https://github.com/bottlerocket-os/bottlerocket/pull/3981\n[#3991]: https://github.com/bottlerocket-os/bottlerocket/pull/3991\n[#4015]: https://github.com/bottlerocket-os/bottlerocket/pull/4015\n[#4029]: https://github.com/bottlerocket-os/bottlerocket/pull/4029\n\n# v1.20.0 (2024-05-13)\n\n## OS Changes\n* Update third party packages ([#3939])\n* Enable file system encryption in 5.15 and 6.1 kernels ([#3906], [#3908])\n* Backport fix for loading SELinux modules ([#3907])\n* Add Fabric Manager support ([#3873])\n* Update host containers ([#3947])\n* Add setting to configure ntp options ([#3852] thanks @domgoodwin)\n* Include swap utilities ([#3829])\n* Update kernels to 6.1.87, 5.15.156, 5.10.215 ([#3934], [#3930])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Drop Kubernetes 1.25 Metal and VMware variants ([#3896])\n* Add Kubernetes 1.30 variants ([#3859], [#3936])\n* Add container-runtime settings to `aws-k8s-*-nvidia` variants ([#3945])\n\n### ECS\n* Update ecs-agent to 1.82.3 ([#3939])\n* Use systemd drop-ins to configure the ECS agent ([#3834])\n\n## Build Changes\n* Update twoliter and the SDK ([#3938], [#3885])\n* Remove liblzma and libbzip2 ([#3861], [#3944])\n* Pessimize Rust builds that require the AWS SDK ([#3892])\n* Reduce variant matrix in CI/CD ([#3863])\n* Document package build tools for go dependencies ([#3882])\n* Update Go lints in CI/CD ([#3884])\n* Out-of-tree build enablement\n  * systemd: use build defaults and kernel parameters for unified cgroups ([#3886], [#3935])\n  * early-boot-config: Use standalone provider binaries to fetch user data ([#3637], [#3890])\n  * logdog: retrieve settings via API client ([#3946])\n  * netdog: remove conditional compilation, add hostname helpers ([#3700], [#3898])\n  * schnauzer: add if_not_null template helper ([#3838])\n  * static-pods: remove conditional compilation, switch to config file ([#3891], [#3927], [#3913])\n  * host-containers: switch to config file ([#3777], [#3842])\n  * bootstrap-containers: switch to config file ([#3724])\n  * corndog: switch to config file ([#3715])\n  * prairiedog: switch to config file ([#3713], [#3814], [#3836])\n  * thar-be-updates: switch to config file ([#3721])\n  * updog: use modeled types ([#3901])\n  * kernel: remove variant sensitivity ([#3897], [#3905], [#3932])\n* FIPS enablement\n  * add FIPS report to the API ([#3894])\n  * add release-fips package for FIPS functionality ([#3893])\n  * build Go binaries for FIPS and non-FIPS ([#3887])\n\n[#3637]: https://github.com/bottlerocket-os/bottlerocket/pull/3637\n[#3700]: https://github.com/bottlerocket-os/bottlerocket/pull/3700\n[#3713]: https://github.com/bottlerocket-os/bottlerocket/pull/3713\n[#3715]: https://github.com/bottlerocket-os/bottlerocket/pull/3715\n[#3721]: https://github.com/bottlerocket-os/bottlerocket/pull/3721\n[#3724]: https://github.com/bottlerocket-os/bottlerocket/pull/3724\n[#3777]: https://github.com/bottlerocket-os/bottlerocket/pull/3777\n[#3814]: https://github.com/bottlerocket-os/bottlerocket/pull/3814\n[#3829]: https://github.com/bottlerocket-os/bottlerocket/pull/3829\n[#3834]: https://github.com/bottlerocket-os/bottlerocket/pull/3834\n[#3836]: https://github.com/bottlerocket-os/bottlerocket/pull/3836\n[#3838]: https://github.com/bottlerocket-os/bottlerocket/pull/3838\n[#3842]: https://github.com/bottlerocket-os/bottlerocket/pull/3842\n[#3852]: https://github.com/bottlerocket-os/bottlerocket/pull/3852\n[#3859]: https://github.com/bottlerocket-os/bottlerocket/pull/3859\n[#3861]: https://github.com/bottlerocket-os/bottlerocket/pull/3861\n[#3863]: https://github.com/bottlerocket-os/bottlerocket/pull/3863\n[#3873]: https://github.com/bottlerocket-os/bottlerocket/pull/3873\n[#3882]: https://github.com/bottlerocket-os/bottlerocket/pull/3882\n[#3884]: https://github.com/bottlerocket-os/bottlerocket/pull/3884\n[#3885]: https://github.com/bottlerocket-os/bottlerocket/pull/3885\n[#3886]: https://github.com/bottlerocket-os/bottlerocket/pull/3886\n[#3887]: https://github.com/bottlerocket-os/bottlerocket/pull/3887\n[#3890]: https://github.com/bottlerocket-os/bottlerocket/pull/3890\n[#3891]: https://github.com/bottlerocket-os/bottlerocket/pull/3891\n[#3892]: https://github.com/bottlerocket-os/bottlerocket/pull/3892\n[#3893]: https://github.com/bottlerocket-os/bottlerocket/pull/3893\n[#3894]: https://github.com/bottlerocket-os/bottlerocket/pull/3894\n[#3896]: https://github.com/bottlerocket-os/bottlerocket/pull/3896\n[#3897]: https://github.com/bottlerocket-os/bottlerocket/pull/3897\n[#3898]: https://github.com/bottlerocket-os/bottlerocket/pull/3898\n[#3901]: https://github.com/bottlerocket-os/bottlerocket/pull/3901\n[#3905]: https://github.com/bottlerocket-os/bottlerocket/pull/3905\n[#3906]: https://github.com/bottlerocket-os/bottlerocket/pull/3906\n[#3907]: https://github.com/bottlerocket-os/bottlerocket/pull/3907\n[#3908]: https://github.com/bottlerocket-os/bottlerocket/pull/3908\n[#3913]: https://github.com/bottlerocket-os/bottlerocket/pull/3913\n[#3927]: https://github.com/bottlerocket-os/bottlerocket/pull/3927\n[#3930]: https://github.com/bottlerocket-os/bottlerocket/pull/3930\n[#3932]: https://github.com/bottlerocket-os/bottlerocket/pull/3932\n[#3934]: https://github.com/bottlerocket-os/bottlerocket/pull/3934\n[#3935]: https://github.com/bottlerocket-os/bottlerocket/pull/3935\n[#3936]: https://github.com/bottlerocket-os/bottlerocket/pull/3936\n[#3938]: https://github.com/bottlerocket-os/bottlerocket/pull/3938\n[#3939]: https://github.com/bottlerocket-os/bottlerocket/pull/3939\n[#3944]: https://github.com/bottlerocket-os/bottlerocket/pull/3944\n[#3945]: https://github.com/bottlerocket-os/bottlerocket/pull/3945\n[#3946]: https://github.com/bottlerocket-os/bottlerocket/pull/3946\n[#3947]: https://github.com/bottlerocket-os/bottlerocket/pull/3947\n\n\n# v1.19.5 (2024-05-01)\n\n## OS Changes\n* Update kernel to 5.10.214, 5.15.153, 6.1.84 [#3906]\n* Update third party packages ([#3910], [#3914])\n* Update host containers (#[3911])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Provide runtime cgroup to kubelet ([#3804])\n\n## Build Changes\n* Update twoliter to v0.1.1 ([#3880], [#3900])\n* Update ecs-gpu-init, amazon-ssm-agent, and nvidia-k8s-device-plugin builds for new SDK ([#3920], [#3921], [#3924])\n\n[#3804]: https://github.com/bottlerocket-os/bottlerocket/pull/3804\n[#3880]: https://github.com/bottlerocket-os/bottlerocket/pull/3880\n[#3900]: https://github.com/bottlerocket-os/bottlerocket/pull/3900\n[#3906]: https://github.com/bottlerocket-os/bottlerocket/pull/3906\n[#3910]: https://github.com/bottlerocket-os/bottlerocket/pull/3910\n[#3911]: https://github.com/bottlerocket-os/bottlerocket/pull/3911\n[#3914]: https://github.com/bottlerocket-os/bottlerocket/pull/3914\n[#3920]: https://github.com/bottlerocket-os/bottlerocket/pull/3920\n[#3921]: https://github.com/bottlerocket-os/bottlerocket/pull/3921\n[#3924]: https://github.com/bottlerocket-os/bottlerocket/pull/3924\n\n# v1.19.4 (2024-04-06)\n\n## OS Changes\n* Update kernel to 5.10.213, 5.15.152, 6.1.82 ([#3865])\n* Update containerd to 1.6.31 ([#3869])\n\n[#3865]: https://github.com/bottlerocket-os/bottlerocket/pull/3865\n[#3869]: https://github.com/bottlerocket-os/bottlerocket/pull/3869\n\n# v1.19.3 (2024-03-26)\n\n## OS Changes\n* Update kernel to 5.10.210, 5.15.149, 6.1.79 ([#3853])\n* Update third party packages ([#3793], [#3832])\n* Update host containers ([#3837])\n* Support auditctl in bootstrap containers ([#3831])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Add latest instance types to eni-max-pods mapping ([#3824])\n\n### ECS\n\n## Build Changes\n* Update Rust dependencies ([#3830])\n* Update Go dependencies ([#3830])\n* twoliter updated to v0.0.7 ([#3839])\n\n[#3793]: https://github.com/bottlerocket-os/bottlerocket/pull/3793\n[#3824]: https://github.com/bottlerocket-os/bottlerocket/pull/3824\n[#3832]: https://github.com/bottlerocket-os/bottlerocket/pull/3832\n[#3830]: https://github.com/bottlerocket-os/bottlerocket/pull/3830\n[#3831]: https://github.com/bottlerocket-os/bottlerocket/pull/3831\n[#3837]: https://github.com/bottlerocket-os/bottlerocket/pull/3837\n[#3839]: https://github.com/bottlerocket-os/bottlerocket/pull/3839\n[#3853]: https://github.com/bottlerocket-os/bottlerocket/pull/3853\n\n# v1.19.2 (2024-02-26)\n\n## OS Changes\n* Update third party packages ([#3789])\n* Update kernel to 5.10.209, 5.15.148, 6.1.77 ([#3797])\n* Add AWS settings extension ([#3738], [#3770])\n* Allow CSI helpers in the SELinux policy ([#3779])\n* Update to latest NVIDIA drivers ([#3798])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Enable NVIDIA GPU isolation using volume mounts ([#3718] thanks @chiragjn , [#3790])\n* Clean up CNI results cache on boot ([#3792])\n\n### ECS\n* Add `settings.ecs.enable-container-metadata` ([#3782])\n\n## Build Changes\n* Adjust certdog to utilize a configuration file instead of the API server ([#3706], [#3778], [#3787])\n* Don't use parallel make for shim package ([#3771])\n* Renumber unit files in release package ([#3769])\n* Ignore EKS patches for k8s-1.23 in Git ([#3774])\n\n[#3706]: https://github.com/bottlerocket-os/bottlerocket/pull/3706\n[#3718]: https://github.com/bottlerocket-os/bottlerocket/pull/3718\n[#3738]: https://github.com/bottlerocket-os/bottlerocket/pull/3738\n[#3769]: https://github.com/bottlerocket-os/bottlerocket/pull/3769\n[#3770]: https://github.com/bottlerocket-os/bottlerocket/pull/3770\n[#3771]: https://github.com/bottlerocket-os/bottlerocket/pull/3771\n[#3774]: https://github.com/bottlerocket-os/bottlerocket/pull/3774\n[#3778]: https://github.com/bottlerocket-os/bottlerocket/pull/3778\n[#3779]: https://github.com/bottlerocket-os/bottlerocket/pull/3779\n[#3782]: https://github.com/bottlerocket-os/bottlerocket/pull/3782\n[#3787]: https://github.com/bottlerocket-os/bottlerocket/pull/3787\n[#3789]: https://github.com/bottlerocket-os/bottlerocket/pull/3789\n[#3790]: https://github.com/bottlerocket-os/bottlerocket/pull/3790\n[#3792]: https://github.com/bottlerocket-os/bottlerocket/pull/3792\n[#3797]: https://github.com/bottlerocket-os/bottlerocket/pull/3797\n[#3798]: https://github.com/bottlerocket-os/bottlerocket/pull/3798\n\n# v1.19.1 (2024-02-06)\n\n## OS Changes\n* Update kernel to 5.10.209, 5.15.148 ([#3765])\n* Update host containers ([#3763])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Mark pause container image as \"pinned\" to prevent garbage collection ([#3757])\n\n### ECS\n* Update Docker engine and Docker CLI to v25.0.2 ([#3759])\n* Update ECS agent to 1.81.0 ([#3759])\n* Update AWS SSM agent to 3.2.2222.0 ([#3762])\n\n[#3765]: https://github.com/bottlerocket-os/bottlerocket/pull/3765\n[#3763]: https://github.com/bottlerocket-os/bottlerocket/pull/3763\n[#3757]: https://github.com/bottlerocket-os/bottlerocket/pull/3757\n[#3759]: https://github.com/bottlerocket-os/bottlerocket/pull/3759\n[#3762]: https://github.com/bottlerocket-os/bottlerocket/pull/3762\n\n# v1.19.0 (2024-02-01)\n\n## OS Changes\n* Adjust unit dependencies for systemd-sysusers ([#3720])\n* Update third party packages ([#3722], [#3750])\n* Add kernel settings extension ([#3727])\n* Update kernel to 5.10.205, 5.15.145, 6.1.72 ([#3734])\n* Update runc to 1.1.12 and containerd to 1.6.28 ([#3751])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Add latest instance types to eni-max-pods mapping ([#3741])\n* Drop Kubernetes 1.24 Metal and VMware variants ([#3742])\n\n### ECS\n* Add additional ECS settings for ECS_BACKEND_HOST and ECS_AWSVPC_BLOCK_IMDS ([#3749])\n\n## Build Changes\n* twoliter updated to v0.0.6 ([#3744])\n\n[#3720]: https://github.com/bottlerocket-os/bottlerocket/pull/3720\n[#3722]: https://github.com/bottlerocket-os/bottlerocket/pull/3722\n[#3727]: https://github.com/bottlerocket-os/bottlerocket/pull/3727\n[#3734]: https://github.com/bottlerocket-os/bottlerocket/pull/3734\n[#3741]: https://github.com/bottlerocket-os/bottlerocket/pull/3741\n[#3742]: https://github.com/bottlerocket-os/bottlerocket/pull/3742\n[#3744]: https://github.com/bottlerocket-os/bottlerocket/pull/3744\n[#3749]: https://github.com/bottlerocket-os/bottlerocket/pull/3749\n[#3750]: https://github.com/bottlerocket-os/bottlerocket/pull/3750\n[#3751]: https://github.com/bottlerocket-os/bottlerocket/pull/3751\n\n# v1.18.0 (2024-01-16)\n\n## OS Changes\n\n* Remove unused runc SELinux policy rule ([#3673])\n* Update third party packages ([#3692])\n* Fix creation of kprobes using unqualified names ([#3699], [#3708])\n* Update host containers ([#3704])\n* Update kernel to 5.10.205, 5.15.145, 6.1.66 ([#3686], [#3708])\n* Add container-registry settings extension ([#3674])\n* Add updates settings extension ([#3689])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Add Kubernetes 1.29 variants ([#3628])\n* Update Kubernetes 1.23 to release 33 ([#3692])\n* Add latest instance types to eni-max-pods mapping ([#3695])\n\n### ECS\n\n* Update ecs-agent to 1.79.2 ([#3692])\n\n## Build Changes\n\n* Export symbols for packages that include dynamically linked Go binaries ([#3680])\n* Update to Bottlerocket SDK v0.37.0 ([#3690])\n  + Upgrades to Go 1.21.5\n\n[#3628]: https://github.com/bottlerocket-os/bottlerocket/pull/3628\n[#3673]: https://github.com/bottlerocket-os/bottlerocket/pull/3673\n[#3674]: https://github.com/bottlerocket-os/bottlerocket/pull/3674\n[#3680]: https://github.com/bottlerocket-os/bottlerocket/pull/3680\n[#3686]: https://github.com/bottlerocket-os/bottlerocket/pull/3686\n[#3689]: https://github.com/bottlerocket-os/bottlerocket/pull/3689\n[#3690]: https://github.com/bottlerocket-os/bottlerocket/pull/3690\n[#3692]: https://github.com/bottlerocket-os/bottlerocket/pull/3692\n[#3695]: https://github.com/bottlerocket-os/bottlerocket/pull/3695\n[#3699]: https://github.com/bottlerocket-os/bottlerocket/pull/3699\n[#3704]: https://github.com/bottlerocket-os/bottlerocket/pull/3704\n[#3708]: https://github.com/bottlerocket-os/bottlerocket/pull/3708\n\n# v1.17.0 (2023-12-12)\n\n## OS Changes\n\n* Generate valid hostname when IPv6 reverse lookup fails ([#3592])\n* Avoid mounting the EFI system partition at `/boot` ([#3591])\n* Update kernel to 5.10.201, 5.15.139, 6.1.61 ([#3611], [#3643])\n* Switch to async `tough` ([#3566])\n* Update host containers ([#3646])\n* Move template migrations to `schnauzer` v2 ([#3633])\n* Handle proxy credentials properly in `pluto` ([#3639], [#3667])\n* Update third party packages ([#3612], [#3642])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Update `nvidia-k8s-device-plugin` to address CVEs ([#3612])\n* Update to Kubernetes 1.28.4 ([#3612])\n* Update to Kubernetes 1.27.8 ([#3612])\n* Update to Kubernetes 1.26.11 ([#3612])\n* Update to Kubernetes 1.25.16 ([#3612])\n\n\n### ECS\n\n* Update `ecs-agent` to address CVEs ([#3612])\n\n## Build Changes\n\n* Update to Bottlerocket SDK v0.36.1 ([#3640], [#3670])\n\n[#3566]: https://github.com/bottlerocket-os/bottlerocket/pull/3566\n[#3591]: https://github.com/bottlerocket-os/bottlerocket/pull/3591\n[#3592]: https://github.com/bottlerocket-os/bottlerocket/pull/3592\n[#3611]: https://github.com/bottlerocket-os/bottlerocket/pull/3611\n[#3612]: https://github.com/bottlerocket-os/bottlerocket/pull/3612\n[#3633]: https://github.com/bottlerocket-os/bottlerocket/pull/3633\n[#3639]: https://github.com/bottlerocket-os/bottlerocket/pull/3639\n[#3640]: https://github.com/bottlerocket-os/bottlerocket/pull/3640\n[#3642]: https://github.com/bottlerocket-os/bottlerocket/pull/3642\n[#3643]: https://github.com/bottlerocket-os/bottlerocket/pull/3643\n[#3646]: https://github.com/bottlerocket-os/bottlerocket/pull/3646\n[#3667]: https://github.com/bottlerocket-os/bottlerocket/pull/3667\n[#3670]: https://github.com/bottlerocket-os/bottlerocket/pull/3670\n\n# v1.16.1 (2023-11-13)\n\n## OS Changes\n\n* Update open-vm-tools to 12.3.5 to address CVE-2023-34058 and CVE-2023-34059 ([#3553])\n* Update NVIDIA drivers to 470.223.02 and 535.129.03 to address CVE‑2023‑31022 and CVE‑2023‑31018 ([#3561])\n* Improvements to Bottlerocket CIS benchmark checks ([#3552] [#3562] [#3564])\n* Regenerate updog proxy configuration when settings.network.proxy gets updated ([#3578])\n* kernel: Update to 5.10.198, 5.15.136, and 6.1.59 ([#3572])\n\n## Orchestrator Changes\n\n### Kubernetes\n* Update Kubernetes versions to address HTTP v2 x/net CVE-2023-39325 ([#3581])\n* Avoid specifying `hostname-override` kubelet option if `cloud-provider` is set to `aws` ([#3582])\n\n[#3552]: https://github.com/bottlerocket-os/bottlerocket/pull/3552\n[#3553]: https://github.com/bottlerocket-os/bottlerocket/pull/3553\n[#3561]: https://github.com/bottlerocket-os/bottlerocket/pull/3561\n[#3562]: https://github.com/bottlerocket-os/bottlerocket/pull/3562\n[#3564]: https://github.com/bottlerocket-os/bottlerocket/pull/3564\n[#3572]: https://github.com/bottlerocket-os/bottlerocket/pull/3572\n[#3578]: https://github.com/bottlerocket-os/bottlerocket/pull/3578\n[#3581]: https://github.com/bottlerocket-os/bottlerocket/pull/3581\n[#3582]: https://github.com/bottlerocket-os/bottlerocket/pull/3582\n\n# v1.16.0 (2023-10-25)\n\n## OS Changes\n\n* Adjust netlink timeout to prevent interfaces from entering a failed state ([#3520])\n* Update third-party packages ([#3535])\n* Add XFS CLI utilities for managing XFS-formatted storage ([#3444])\n* Add facilities to auto-load kernel modules ([#3460])\n* Update to kernels 5.10.197, 5.15.134, and 6.1.55 ([#3509] [#3542])\n* Fix reporting for Bottlerocket CIS Benchmark 4.1.2 ([#3547])\n* Update systemd to 252.18 ([#3533])\n* Allow fanotify permission events for trusted subjects in SELinux policy ([#3540])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Drop Kubernetes 1.23 Metal and VMware variants ([#3531])\n\n### ECS\n\n* Update ecs-agent ([#3535])\n\n## Build Changes\n\n* Update to Bottlerocket SDK v0.35.0 ([#3528])\n\n[#3444]: https://github.com/bottlerocket-os/bottlerocket/pull/3444\n[#3460]: https://github.com/bottlerocket-os/bottlerocket/pull/3460\n[#3509]: https://github.com/bottlerocket-os/bottlerocket/pull/3509\n[#3520]: https://github.com/bottlerocket-os/bottlerocket/pull/3520\n[#3528]: https://github.com/bottlerocket-os/bottlerocket/pull/3528\n[#3531]: https://github.com/bottlerocket-os/bottlerocket/pull/3531\n[#3533]: https://github.com/bottlerocket-os/bottlerocket/pull/3533\n[#3535]: https://github.com/bottlerocket-os/bottlerocket/pull/3535\n[#3540]: https://github.com/bottlerocket-os/bottlerocket/pull/3540\n[#3542]: https://github.com/bottlerocket-os/bottlerocket/pull/3542\n[#3547]: https://github.com/bottlerocket-os/bottlerocket/pull/3547\n\n# v1.15.1 (2023-10-9)\n\n## OS Changes\n\n* Allow older ext4 snapshot volumes to be mounted in newer variants that default to xfs ([#3499])\n* Update `apiclient` Rust dependencies ([#3491])\n* Update `pluto` Rust dependencies ([#3439])\n* Patch glibc to address CVE-2023-4806, CVE-2023-4911, and CVE-2023-5156 ([#3501])\n* Update open-vm-tools to 12.3.0 to address CVE-2023-20900 ([#3500])\n\n## Build Changes\n\n* Update `twoliter` to v0.0.4 ([#3480])\n\n[#3439]: https://github.com/bottlerocket-os/bottlerocket/pull/3439\n[#3480]: https://github.com/bottlerocket-os/bottlerocket/pull/3480\n[#3491]: https://github.com/bottlerocket-os/bottlerocket/pull/3491\n[#3499]: https://github.com/bottlerocket-os/bottlerocket/pull/3499\n[#3500]: https://github.com/bottlerocket-os/bottlerocket/pull/3500\n[#3501]: https://github.com/bottlerocket-os/bottlerocket/pull/3501\n\n# v1.15.0 (2023-09-18)\n\n## Major Features\n\nThis release brings support for Secure Boot on platforms using UEFI boot; the Linux 6.1 kernel; systemd-networkd and systemd-resolved for host networking; and XFS as the filesystem for local storage.\n\nThese features are enabled by default in the new variants. Existing variants will continue to use earlier kernels, `wicked` for host networking, and EXT4 as the filesystem for local storage.\n\n## Known Incompatibilities\n\n* Variants using the 6.1 kernel (`aws-ecs-2`/`aws-ecs-2-nvidia`, `aws-k8s-1.28`/`aws-k8s-1.28-nvidia`, `vmware-k8s-1.28`, and `metal-k8s-1.28`) do not support [LustreFS](https://aws.amazon.com/fsx/lustre/) ([#3459])\n\n## Deprecation Notice\n\nThe functionality to apply a hotpatch for log4j CVE-2021-44228 has been removed. The corresponding setting, `settings.oci-hooks.log4j-hotpatch-enabled`, is still available for backwards compatibility. However, it has no effect beyond printing a deprecation warning to the system logs. ([#3401])\n\n## OS Changes\n\n* Add kernel 6.1 ([#3121], [#3441])\n* Update admin and control containers ([#3368])\n* Update third party packages and dependencies ([#3362], [#3369], [#3330], [#3339], [#3355], [#3441], [#3456])\n* Updated to systemd 252 ([#3290])\n* Add support for Secure Boot ([#3097])\n* Add support for XFS ([#3198])\n* Add `apiclient report` command ([#3258]) and Bottlerocket CIS benchmark report ([#2881])\n* Add resource-limit settings for OCI defaults ([#3206])\n* Use `systemd-networkd` and `systemd-resolved` instead of `wicked` for `aws-k8s-1.28`, `aws-ecs-2`, and `*-dev` variants ([#3134], [#3232], [#3266], [#3311], [#3394], [#3395], [#3451], [#3455])\n\n## Orchestrator Changes\n\n### ECS\n\n* Add `aws-ecs-2` variants ([#3273])\n  * Enables Secure Boot, systemd-networkd, and XFS for the data partition\n* Add support for AppMesh ([#3267])\n\n### Kubernetes\n\n* Add Kubernetes 1.28 variants ([#3329])\n  * Enables Secure Boot, systemd-networkd, and XFS for the data partition\n* Drop Kubernetes 1.22 variants ([#2988])\n* Update to Kubernetes 1.27.4 ([#3319])\n* Update to Kubernetes 1.26.7 ([#3320])\n* Update to Kubernetes 1.25.12 ([#3321])\n* Update to Kubernetes 1.24.16 ([#3322])\n* Add support for SeccompDefault setting for k8s 1.25+ ([#3334])\n* Add Kubernetes CIS benchmark report ([#3239])\n\n## Platform Changes\n\n### AWS\n* Retry on empty PrivateDnsName from EC2 ([#3364])\n\n### Metal\n* Enable Intel VMD driver ([#3419])\n* Add linux-firmware ([#3296], [#3418])\n* Add aws-iam-authenticator to k8s variants ([#3357])\n\n## Build Changes\n\n* Upgrade to Bottlerocket SDK v0.34.1 ([#3445])\n* Use [Twoliter] to enable work on [out-of-tree builds]. Most `tools` have moved to [Twoliter] ([#3379], [#3429], [#3392], [#3342])\n* Only limit concurrency while building RPMs ([#3343])\n\n\n[Twoliter]: https://github.com/bottlerocket-os/twoliter\n[out-of-tree builds]: https://github.com/bottlerocket-os/bottlerocket/issues/2669\n[#2881]: https://github.com/bottlerocket-os/bottlerocket/pull/2881\n[#2988]: https://github.com/bottlerocket-os/bottlerocket/pull/2988\n[#3075]: https://github.com/bottlerocket-os/bottlerocket/pull/3075\n[#3097]: https://github.com/bottlerocket-os/bottlerocket/pull/3097\n[#3121]: https://github.com/bottlerocket-os/bottlerocket/pull/3121\n[#3134]: https://github.com/bottlerocket-os/bottlerocket/pull/3134\n[#3198]: https://github.com/bottlerocket-os/bottlerocket/pull/3198\n[#3206]: https://github.com/bottlerocket-os/bottlerocket/pull/3206\n[#3232]: https://github.com/bottlerocket-os/bottlerocket/pull/3232\n[#3239]: https://github.com/bottlerocket-os/bottlerocket/pull/3239\n[#3258]: https://github.com/bottlerocket-os/bottlerocket/pull/3258\n[#3266]: https://github.com/bottlerocket-os/bottlerocket/pull/3266\n[#3267]: https://github.com/bottlerocket-os/bottlerocket/pull/3267\n[#3273]: https://github.com/bottlerocket-os/bottlerocket/pull/3273\n[#3290]: https://github.com/bottlerocket-os/bottlerocket/pull/3290\n[#3296]: https://github.com/bottlerocket-os/bottlerocket/pull/3296\n[#3311]: https://github.com/bottlerocket-os/bottlerocket/pull/3311\n[#3319]: https://github.com/bottlerocket-os/bottlerocket/pull/3319\n[#3320]: https://github.com/bottlerocket-os/bottlerocket/pull/3320\n[#3321]: https://github.com/bottlerocket-os/bottlerocket/pull/3321\n[#3322]: https://github.com/bottlerocket-os/bottlerocket/pull/3322\n[#3329]: https://github.com/bottlerocket-os/bottlerocket/pull/3329\n[#3330]: https://github.com/bottlerocket-os/bottlerocket/pull/3330\n[#3334]: https://github.com/bottlerocket-os/bottlerocket/pull/3334\n[#3339]: https://github.com/bottlerocket-os/bottlerocket/pull/3339\n[#3342]: https://github.com/bottlerocket-os/bottlerocket/pull/3342\n[#3342]: https://github.com/bottlerocket-os/bottlerocket/pull/3342\n[#3343]: https://github.com/bottlerocket-os/bottlerocket/pull/3343\n[#3355]: https://github.com/bottlerocket-os/bottlerocket/pull/3355\n[#3357]: https://github.com/bottlerocket-os/bottlerocket/pull/3357\n[#3362]: https://github.com/bottlerocket-os/bottlerocket/pull/3362\n[#3364]: https://github.com/bottlerocket-os/bottlerocket/pull/3364\n[#3366]: https://github.com/bottlerocket-os/bottlerocket/pull/3366\n[#3368]: https://github.com/bottlerocket-os/bottlerocket/pull/3368\n[#3369]: https://github.com/bottlerocket-os/bottlerocket/pull/3369\n[#3379]: https://github.com/bottlerocket-os/bottlerocket/pull/3379\n[#3392]: https://github.com/bottlerocket-os/bottlerocket/pull/3392\n[#3394]: https://github.com/bottlerocket-os/bottlerocket/pull/3394\n[#3395]: https://github.com/bottlerocket-os/bottlerocket/pull/3395\n[#3401]: https://github.com/bottlerocket-os/bottlerocket/pull/3401\n[#3418]: https://github.com/bottlerocket-os/bottlerocket/pull/3418\n[#3419]: https://github.com/bottlerocket-os/bottlerocket/pull/3419\n[#3429]: https://github.com/bottlerocket-os/bottlerocket/pull/3429\n[#3441]: https://github.com/bottlerocket-os/bottlerocket/pull/3441\n[#3445]: https://github.com/bottlerocket-os/bottlerocket/pull/3445\n[#3451]: https://github.com/bottlerocket-os/bottlerocket/pull/3451\n[#3455]: https://github.com/bottlerocket-os/bottlerocket/pull/3455\n[#3456]: https://github.com/bottlerocket-os/bottlerocket/pull/3456\n[#3459]: https://github.com/bottlerocket-os/bottlerocket/issues/3459\n\n# v1.14.3 (2023-08-10)\n\n## OS Changes\n\n* Apply patches to 5.10 and 5.15 kernels to address CVE-2023-20593 ([#3300])\n* Update admin and control containers ([#3307])\n* Update eni-max-pods with new instance types ([#3324])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Update Kubernetes v1.23.17 to include latest EKS-D patches ([#3323])\n\n[#3300]: https://github.com/bottlerocket-os/bottlerocket/pull/3300\n[#3307]: https://github.com/bottlerocket-os/bottlerocket/pull/3307\n[#3323]: https://github.com/bottlerocket-os/bottlerocket/pull/3323\n[#3324]: https://github.com/bottlerocket-os/bottlerocket/pull/3324\n\n# v1.14.2 (2023-07-06)\n\n## OS Changes\n\n* Improve the reliability of acquiring a DHCPv6 lease ([#3211], [#3212])\n* Update kernel-5.10 to 5.10.184 and kernel-5.15 to 5.15.117 ([#3238])\n* Update eni-max-pods with new instance types ([#3193])\n* Make `pluto` outbound API requests more resilient to intermittent network errors ([#3214])\n* Update runc to 1.1.6 ([#3249])\n\n## Orchestrator Changes\n\n### ECS\n\n* Add image cleanup settings to control task image cleanup frequency ([#3231])\n\n### Kubernetes\n\n* Update to Kubernetes v1.24.15 ([#3234])\n* Update to Kubernetes v1.25.11 ([#3235])\n* Update to Kubernetes v1.26.6 ([#3236])\n* Update to Kubernetes v1.27.3 ([#3237])\n\n## Build Changes\n\n* Updated Bottlerocket SDK version to v0.33.0 ([#3213])\n\n[#3211]: https://github.com/bottlerocket-os/bottlerocket/pull/3211\n[#3212]: https://github.com/bottlerocket-os/bottlerocket/pull/3212\n[#3213]: https://github.com/bottlerocket-os/bottlerocket/pull/3213\n[#3214]: https://github.com/bottlerocket-os/bottlerocket/pull/3214\n[#3231]: https://github.com/bottlerocket-os/bottlerocket/pull/3231\n[#3234]: https://github.com/bottlerocket-os/bottlerocket/pull/3234\n[#3235]: https://github.com/bottlerocket-os/bottlerocket/pull/3235\n[#3236]: https://github.com/bottlerocket-os/bottlerocket/pull/3236\n[#3237]: https://github.com/bottlerocket-os/bottlerocket/pull/3237\n[#3238]: https://github.com/bottlerocket-os/bottlerocket/pull/3238\n[#3193]: https://github.com/bottlerocket-os/bottlerocket/pull/3193\n[#3249]: https://github.com/bottlerocket-os/bottlerocket/pull/3249\n\n# v1.14.1 (2023-05-31)\n\n## OS Changes\n\n* Apply patches to 5.10 and 5.15 kernels to address CVE-2023-32233 ([#3128])\n* Add fallback container image source parsing for regions not yet supported by the `aws-go-sdk` in `host-ctr` ([#3138])\n* Increase default `max_dgram_qlen` sysctl value to `512` for both 5.10 and 5.15 kernels ([#3139])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Kubernetes package updates\n  * Update Kubernetes v1.22.17 to include latest EKS-D patches ([#3108])\n  * Update Kubernetes v1.23.17 to include latest EKS-D patches ([#3119])\n  * Update to Kubernetes v1.24.14 ([#3119])\n  * Update to Kubernetes v1.25.9 ([#3119])\n  * Update to Kubernetes v1.26.4 ([#3119])\n  * Update Kubernetes v1.27.1 to include latest EKS-D patches ([#3119])\n* Change `nvidia-k8s-device-plugin` service dependency on `kubelet` ([#3141])\n\n## Build Changes\n\n* Fix `pubsys` bug preventing multiple SSM parameter promotions in `promote-ssm` Makefile target ([#3137])\n\n[#3108]: https://github.com/bottlerocket-os/bottlerocket/pull/3108\n[#3119]: https://github.com/bottlerocket-os/bottlerocket/pull/3119\n[#3128]: https://github.com/bottlerocket-os/bottlerocket/pull/3128\n[#3137]: https://github.com/bottlerocket-os/bottlerocket/pull/3137\n[#3138]: https://github.com/bottlerocket-os/bottlerocket/pull/3138\n[#3139]: https://github.com/bottlerocket-os/bottlerocket/pull/3139\n[#3141]: https://github.com/bottlerocket-os/bottlerocket/pull/3141\n\n# v1.14.0 (2023-05-11)\n\n## OS Changes\n\n* Update kernel-5.10 to 5.10.178 and kernel-5.15 to 5.15.108 ([#3077])\n* Update admin and control containers ([#3090])\n* Update third party packages and dependencies ([#2991], [#3082])\n* Enable `SCSI_VIRTIO` driver for better hypervisor support ([#3047])\n* Disable panic on hung task for kernel 5.15 ([#3091])\n* Create symlink to `inventory` path using Storewolf ([#3035])\n\n## Orchestrator Changes\n\n### ECS\n\n* Add support for ECS Exec ([#3075])\n\n### Kubernetes\n\n* Add Kubernetes 1.27 variants ([#3046])\n  * Switch to using Kubernetes default values for `kube-api-burst` and `kube-api-qps` ([#3094])\n* Add more Kubernetes settings ([#2930], [#2986])\n  * Soft eviction policy\n  * Graceful shutdown\n  * CPU quota enforcement\n  * Memory manager policy\n  * CPU manager policy\n* Fix Kubernetes 1.26 credential provider apiVersion ([#3070])\n* Add ability to pass environment variables to image credential providers ([#2934])\n\n## Build Changes\n\n* Upgrade to Bottlerocket SDK v0.32.0 ([#3071])\n* Add AMI validation to PubSys ([#3020])\n* Add SSM parameter validation to PubSys ([#2969])\n* Add `validate-ami` and `validate-ssm` Makefile targets ([#3043])\n* Add `check-migrations` Makefile target to check for common migration problems ([#3051])\n\n## Testing Changes\n\n* Update testsys to v0.0.7 ([#3065])\n* Add support for node provisioning with Karpenter ([#3067])\n* Enable using custom Sonobuoy images ([#3068])\n\n[#3077]: https://github.com/bottlerocket-os/bottlerocket/pull/3077\n[#3090]: https://github.com/bottlerocket-os/bottlerocket/pull/3090\n[#2991]: https://github.com/bottlerocket-os/bottlerocket/pull/2991\n[#3082]: https://github.com/bottlerocket-os/bottlerocket/pull/3082\n[#3047]: https://github.com/bottlerocket-os/bottlerocket/pull/3047\n[#3091]: https://github.com/bottlerocket-os/bottlerocket/pull/3091\n[#3071]: https://github.com/bottlerocket-os/bottlerocket/pull/3071\n[#3035]: https://github.com/bottlerocket-os/bottlerocket/pull/3035\n[#3075]: https://github.com/bottlerocket-os/bottlerocket/pull/3075\n[#3046]: https://github.com/bottlerocket-os/bottlerocket/pull/3046\n[#3094]: https://github.com/bottlerocket-os/bottlerocket/pull/3094\n[#2930]: https://github.com/bottlerocket-os/bottlerocket/pull/2930\n[#2986]: https://github.com/bottlerocket-os/bottlerocket/pull/2986\n[#3070]: https://github.com/bottlerocket-os/bottlerocket/pull/3070\n[#2934]: https://github.com/bottlerocket-os/bottlerocket/pull/2934\n[#3051]: https://github.com/bottlerocket-os/bottlerocket/pull/3051\n[#3020]: https://github.com/bottlerocket-os/bottlerocket/pull/3020\n[#2969]: https://github.com/bottlerocket-os/bottlerocket/pull/2969\n[#3043]: https://github.com/bottlerocket-os/bottlerocket/pull/3043\n[#3065]: https://github.com/bottlerocket-os/bottlerocket/pull/3065\n[#3067]: https://github.com/bottlerocket-os/bottlerocket/pull/3067\n[#3068]: https://github.com/bottlerocket-os/bottlerocket/pull/3068\n\n# v1.13.5 (2023-05-01)\n\n## OS Changes\n\n* Revert `runc` update to move back to 1.1.5 ([#3054])\n\n[#3054]: https://github.com/bottlerocket-os/bottlerocket/pull/3054\n\n# v1.13.4 (2023-04-24)\n\n## OS Changes\n\n* Ensure the first hostname is used when a VPC DHCP option set has multiple domains ([#3032])\n* Update `runc` to version 1.1.6 ([#3037])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Generate and pass `--hostname-override` flag to kubelet in `aws-k8s-1.26` variants ([#3033])\n\n[#3032]: https://github.com/bottlerocket-os/bottlerocket/pull/3032\n[#3033]: https://github.com/bottlerocket-os/bottlerocket/pull/3033\n[#3037]: https://github.com/bottlerocket-os/bottlerocket/pull/3037\n\n# v1.13.3 (2023-04-17)\n\n## OS Changes\n\n* Update kernel-5.10 to 5.10.173 and kernel-5.15 to 5.15.102 ([#2948], [#3002])\n* Fix check for rule existence in ip6tables v1.8.9  ([#3001])\n* Backport systemd fixes for skipped udevd events ([#2999])\n* Check platform-specific mechanisms for hostname first ([#3021])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Generate 'provider-id' setting for aws-k8s variants ([#3026])\n\n[#2948]: https://github.com/bottlerocket-os/bottlerocket/pull/2948\n[#2999]: https://github.com/bottlerocket-os/bottlerocket/pull/2999\n[#3001]: https://github.com/bottlerocket-os/bottlerocket/pull/3001\n[#3002]: https://github.com/bottlerocket-os/bottlerocket/pull/3002\n[#3021]: https://github.com/bottlerocket-os/bottlerocket/pull/3021\n[#3026]: https://github.com/bottlerocket-os/bottlerocket/pull/3026\n\n# v1.13.2 (2023-04-04)\n\n## OS Changes\n\n* Update `runc` to version 1.1.5 ([#2946])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Update to Kubernetes v1.26.2 ([#2929])\n* Update `aws-iam-authenticator` package to v0.6.8 ([#2965])\n\n[#2946]: https://github.com/bottlerocket-os/bottlerocket/pull/2946\n[#2929]: https://github.com/bottlerocket-os/bottlerocket/pull/2929\n[#2965]: https://github.com/bottlerocket-os/bottlerocket/pull/2965\n\n# v1.13.1 (2023-03-23)\n\n## OS Changes\n\n* Improve logic around repartitioning and disk expansion by using symlinks to differentiate \"fallback\" and \"preferred\" data partitions ([#2935])\n* Add `keyutils` package to enable mounting CIFS shares ([#2907])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Fix AWS profile rendering in credential provider ([#2904])\n* Change CredentialProviderConfig api version to `v1beta1` for Kubernetes 1.25 variants ([#2906])\n\n[#2904]: https://github.com/bottlerocket-os/bottlerocket/pull/2904\n[#2906]: https://github.com/bottlerocket-os/bottlerocket/pull/2906\n[#2907]: https://github.com/bottlerocket-os/bottlerocket/pull/2907\n[#2935]: https://github.com/bottlerocket-os/bottlerocket/pull/2935\n\n# v1.13.0 (2023-03-15)\n\n## OS Changes\n\n* Add `ethtool` to Bottlerocket ([#2829])\n* Improve logging in `migrator` to track ongoing migrations ([#2751])\n* Improve random-access read performance of root volume on some devices ([#2863])\n* Add `CAP_SYS_MODULE` and `CAP_CHROOT` to bootstrap containers ([#2772])\n* Add support for cgroup v2 ([#2875], [#2802])\n* Disable IA and SafeSetID LSM for kernel-5.15 ([#2789])\n* Update kernel-5.10 to 5.10.165 and kernel-5.15 to 5.15.90 ([#2795])\n* Allow `=` in bootconfig values ([#2806])\n* Include `systemd-analyze plot` for `logdog` ([#2880])\n* Update host containers ([#2864])\n* Update third party packages ([#2825], [#2842])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* **Remove Kubernetes 1.21 variants ([#2700])**\n* Add Kubernetes 1.26 variants ([#2771], ([#2876])\n* Change `kubelet` service to have restart policy `always` ([#2774])\n* Update to Kubernetes v1.25.6 ([#2782])\n* Update to Kubernetes v1.24.10 ([#2790])\n* Update to Kubernetes v1.23.16 ([#2791])\n* Update Kubernetes 1.22.17 to include latest EKS-D patches ([#2792])\n\n### ECS\n\n* Enable FireLens capability in `aws-ecs-1` variant ([#2819])\n\n## Platform Changes\n\n### AWS\n\n* Set NVMe IO request timeouts for EBS according to AWS recommendations ([#2820])\n* Support an alternate data partition on EC2 instances launched with a single volume ([#2807], [#2879], [#2873])\n* Update `eni-max-pod` mappings to include the latest AWS instance types ([#2818])\n\n### VMware\n\n* Remove `k8s.gcr.io` in favor of `public.ecr.aws` ([#2861], ([#2786])\n* Disable UDP offload for primary interface ([#2850])\n\n## Build Changes\n\n* Ensure empty build/rpms directory is included in build context ([#2784])\n* Add image feature flag for cgroup v2 ([#2845])\n* Enable `systemd-networkd` development via build flag ([#2741], [#2832], [#2750])\n* Fix `clippy` linter warnings in source files and add `clippy` CI coverage ([#2745])\n* Use `clippy` provided in SDK image ([#2793]) ([#2868])\n* Remove unnecessary `time` 0.1.x dependency ([#2748], [#2851])\n* Remove unnecessary patch from `containerd` ([#2755])\n* Update Bottlerocket SDK to v0.30.2 ([#2866], [#2857], [#2836])\n* Remove outdated `rust_2018_idioms` enforcement ([#2837])\n* Update Rust edition to `2021` ([#2835])\n* Upgraded Rust code dependencies ([#2816], [#2869], [#2851], [#2736], [#2895])\n* Upgraded Go code dependencies ([#2828], [#2826], [#2813])\n* Rename `ncurses` to `libncurses` ([#2769])\n* Update schnauzer's registry map ([#2867])\n\n## Testing Changes\n\n* Add support for Kubernetes workloads in `testsys` ([#2830])\n* Add support for a `tests` directory ([#2737], [#2775])\n* Provide advanced config controls to `testsys` ([#2799])\n* Fix incorrect migration starting image for VMware testing in `testsys` ([#2804])\n* Use testsys v0.0.6 ([#2865])\n\n## Documentation Changes\n\n* Add boot sequence documentation ([#2735])\n* Update Bottlerocket version in provisioning step in `PROVISIONING-METAL.md` ([#2785])\n* Add user-data example for setting container registry credentials in `README.md` ([#2803])\n* Fix missing trailing backslashes on `ami` commands in `TESTING.md` ([#2838])\n\n[#2700]: https://github.com/bottlerocket-os/bottlerocket/pull/2700\n[#2735]: https://github.com/bottlerocket-os/bottlerocket/pull/2735\n[#2736]: https://github.com/bottlerocket-os/bottlerocket/pull/2736\n[#2737]: https://github.com/bottlerocket-os/bottlerocket/pull/2737\n[#2741]: https://github.com/bottlerocket-os/bottlerocket/pull/2741\n[#2745]: https://github.com/bottlerocket-os/bottlerocket/pull/2745\n[#2748]: https://github.com/bottlerocket-os/bottlerocket/pull/2748\n[#2749]: https://github.com/bottlerocket-os/bottlerocket/pull/2749\n[#2750]: https://github.com/bottlerocket-os/bottlerocket/pull/2750\n[#2751]: https://github.com/bottlerocket-os/bottlerocket/pull/2751\n[#2755]: https://github.com/bottlerocket-os/bottlerocket/pull/2755\n[#2769]: https://github.com/bottlerocket-os/bottlerocket/pull/2769\n[#2771]: https://github.com/bottlerocket-os/bottlerocket/pull/2771\n[#2772]: https://github.com/bottlerocket-os/bottlerocket/pull/2772\n[#2774]: https://github.com/bottlerocket-os/bottlerocket/pull/2774\n[#2775]: https://github.com/bottlerocket-os/bottlerocket/pull/2775\n[#2782]: https://github.com/bottlerocket-os/bottlerocket/pull/2782\n[#2784]: https://github.com/bottlerocket-os/bottlerocket/pull/2784\n[#2785]: https://github.com/bottlerocket-os/bottlerocket/pull/2785\n[#2786]: https://github.com/bottlerocket-os/bottlerocket/pull/2786\n[#2789]: https://github.com/bottlerocket-os/bottlerocket/pull/2789\n[#2790]: https://github.com/bottlerocket-os/bottlerocket/pull/2790\n[#2791]: https://github.com/bottlerocket-os/bottlerocket/pull/2791\n[#2792]: https://github.com/bottlerocket-os/bottlerocket/pull/2792\n[#2793]: https://github.com/bottlerocket-os/bottlerocket/pull/2793\n[#2795]: https://github.com/bottlerocket-os/bottlerocket/pull/2795\n[#2797]: https://github.com/bottlerocket-os/bottlerocket/pull/2797\n[#2799]: https://github.com/bottlerocket-os/bottlerocket/pull/2799\n[#2802]: https://github.com/bottlerocket-os/bottlerocket/pull/2802\n[#2803]: https://github.com/bottlerocket-os/bottlerocket/pull/2803\n[#2804]: https://github.com/bottlerocket-os/bottlerocket/pull/2804\n[#2806]: https://github.com/bottlerocket-os/bottlerocket/pull/2806\n[#2807]: https://github.com/bottlerocket-os/bottlerocket/pull/2807\n[#2813]: https://github.com/bottlerocket-os/bottlerocket/pull/2813\n[#2816]: https://github.com/bottlerocket-os/bottlerocket/pull/2816\n[#2818]: https://github.com/bottlerocket-os/bottlerocket/pull/2818\n[#2819]: https://github.com/bottlerocket-os/bottlerocket/pull/2819\n[#2820]: https://github.com/bottlerocket-os/bottlerocket/pull/2820\n[#2825]: https://github.com/bottlerocket-os/bottlerocket/pull/2825\n[#2826]: https://github.com/bottlerocket-os/bottlerocket/pull/2826\n[#2828]: https://github.com/bottlerocket-os/bottlerocket/pull/2828\n[#2829]: https://github.com/bottlerocket-os/bottlerocket/pull/2829\n[#2830]: https://github.com/bottlerocket-os/bottlerocket/pull/2830\n[#2832]: https://github.com/bottlerocket-os/bottlerocket/pull/2832\n[#2835]: https://github.com/bottlerocket-os/bottlerocket/pull/2835\n[#2836]: https://github.com/bottlerocket-os/bottlerocket/pull/2836\n[#2837]: https://github.com/bottlerocket-os/bottlerocket/pull/2837\n[#2838]: https://github.com/bottlerocket-os/bottlerocket/pull/2838\n[#2842]: https://github.com/bottlerocket-os/bottlerocket/pull/2842\n[#2845]: https://github.com/bottlerocket-os/bottlerocket/pull/2845\n[#2846]: https://github.com/bottlerocket-os/bottlerocket/pull/2846\n[#2850]: https://github.com/bottlerocket-os/bottlerocket/pull/2850\n[#2851]: https://github.com/bottlerocket-os/bottlerocket/pull/2851\n[#2857]: https://github.com/bottlerocket-os/bottlerocket/pull/2857\n[#2861]: https://github.com/bottlerocket-os/bottlerocket/pull/2861\n[#2863]: https://github.com/bottlerocket-os/bottlerocket/pull/2863\n[#2864]: https://github.com/bottlerocket-os/bottlerocket/pull/2864\n[#2865]: https://github.com/bottlerocket-os/bottlerocket/pull/2865\n[#2866]: https://github.com/bottlerocket-os/bottlerocket/pull/2866\n[#2867]: https://github.com/bottlerocket-os/bottlerocket/pull/2867\n[#2868]: https://github.com/bottlerocket-os/bottlerocket/pull/2868\n[#2869]: https://github.com/bottlerocket-os/bottlerocket/pull/2869\n[#2873]: https://github.com/bottlerocket-os/bottlerocket/pull/2873\n[#2875]: https://github.com/bottlerocket-os/bottlerocket/pull/2875\n[#2876]: https://github.com/bottlerocket-os/bottlerocket/pull/2876\n[#2879]: https://github.com/bottlerocket-os/bottlerocket/pull/2879\n[#2880]: https://github.com/bottlerocket-os/bottlerocket/pull/2880\n[#2895]: https://github.com/bottlerocket-os/bottlerocket/pull/2895\n\n# v 1.12.0 (2023-01-24)\n\n## OS Changes\n\n* Disable strict aliasing for c-utf-8 library strict aliasing in dbus-broker ([#2730])\n* Add `/sys/firmware` to privileged mounts in host-ctr ([#2714])\n* Use user-provided registry credentials for public.ecr.aws in host-ctr ([#2676])\n* Build masked paths list dynamically in host-ctr ([#2637])\n* Enable EFI option in systemd ([#2714])\n* Allow simple enums as map keys in datastore ([#2687])\n* Improve reliability of `settings.network.hostname` generator ([#2647])\n* Add support for bonding and VLANS in `net.toml` ([#2596])\n* Keep only one intermediate datastore during migration ([#2589])\n* Widen access to filesystem relabel in SELinux policy ([#2738])\n* Update hotdog to 1.05 ([#2728])\n* Update systemd to 250.9 ([#2718])\n* Update third party packages and dependencies ([#2588], [#2717])\n* Update host containers ([#2739])\n* Update eksd ([#2690], [#2693], [#2694], thanks @rcrozean)\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Add support for Kubernetes 1.25 variants ([#2699])\n* Allow access to public kubelet certificates ([#2639])\n* During kubelet prestart, skip pause image pull if image exists ([#2587])\n* Delay kubelet.service until after warm-pool-wait service runs ([#2562])\n* Add OCI default spec and settings to containerd ([#2697])\n\n## Platform Changes\n\n### VMware\n\n* Downgrade iopl warning when fetching guestinfo in `early-boot-config` ([#2732])\n\n## Build Changes\n\n* Treat alias warning as errors ([#2730])\n* Suppress \"missing changelog\" warning in build ([#2730])\n* Update Bottlerocket SDK version to 0.29.0 ([#2730])\n* Improve error messages for publish-ami command ([#2695])\n* Disallow private AMIs in public SSM parameters ([#2680])\n* Rework `start-local-vm` image selection to use `latest` symlink ([#2696])\n* Improve integration testing through `cargo make test` ([#2560], [#2592], [#2618], [#2646], [#2653], [#2683], [#2674], [#2723], [#2724], [#2725])\n\n\n[#2560]: https://github.com/bottlerocket-os/bottlerocket/pull/2560\n[#2562]: https://github.com/bottlerocket-os/bottlerocket/pull/2562\n[#2587]: https://github.com/bottlerocket-os/bottlerocket/pull/2587\n[#2589]: https://github.com/bottlerocket-os/bottlerocket/pull/2589\n[#2592]: https://github.com/bottlerocket-os/bottlerocket/pull/2592\n[#2596]: https://github.com/bottlerocket-os/bottlerocket/pull/2596\n[#2618]: https://github.com/bottlerocket-os/bottlerocket/pull/2618\n[#2637]: https://github.com/bottlerocket-os/bottlerocket/pull/2637\n[#2639]: https://github.com/bottlerocket-os/bottlerocket/pull/2639\n[#2646]: https://github.com/bottlerocket-os/bottlerocket/pull/2646\n[#2647]: https://github.com/bottlerocket-os/bottlerocket/pull/2647\n[#2650]: https://github.com/bottlerocket-os/bottlerocket/pull/2650\n[#2653]: https://github.com/bottlerocket-os/bottlerocket/pull/2653\n[#2674]: https://github.com/bottlerocket-os/bottlerocket/pull/2674\n[#2676]: https://github.com/bottlerocket-os/bottlerocket/pull/2676\n[#2680]: https://github.com/bottlerocket-os/bottlerocket/pull/2680\n[#2683]: https://github.com/bottlerocket-os/bottlerocket/pull/2683\n[#2687]: https://github.com/bottlerocket-os/bottlerocket/pull/2687\n[#2690]: https://github.com/bottlerocket-os/bottlerocket/pull/2690\n[#2693]: https://github.com/bottlerocket-os/bottlerocket/pull/2693\n[#2694]: https://github.com/bottlerocket-os/bottlerocket/pull/2694\n[#2695]: https://github.com/bottlerocket-os/bottlerocket/pull/2695\n[#2696]: https://github.com/bottlerocket-os/bottlerocket/pull/2696\n[#2697]: https://github.com/bottlerocket-os/bottlerocket/pull/2697\n[#2699]: https://github.com/bottlerocket-os/bottlerocket/pull/2699\n[#2714]: https://github.com/bottlerocket-os/bottlerocket/pull/2714\n[#2717]: https://github.com/bottlerocket-os/bottlerocket/pull/2717\n[#2718]: https://github.com/bottlerocket-os/bottlerocket/pull/2718\n[#2723]: https://github.com/bottlerocket-os/bottlerocket/pull/2723\n[#2724]: https://github.com/bottlerocket-os/bottlerocket/pull/2724\n[#2725]: https://github.com/bottlerocket-os/bottlerocket/pull/2725\n[#2728]: https://github.com/bottlerocket-os/bottlerocket/pull/2728\n[#2730]: https://github.com/bottlerocket-os/bottlerocket/pull/2730\n[#2732]: https://github.com/bottlerocket-os/bottlerocket/pull/2732\n[#2738]: https://github.com/bottlerocket-os/bottlerocket/pull/2738\n[#2739]: https://github.com/bottlerocket-os/bottlerocket/pull/2739\n\n# v1.11.1 (2022-11-28)\n\n## Security Fixes\n\n* Update NVIDIA driver for 5.10 and 5.15 to include recent security fixes ([74d2c5c13ab0][64f3967373a5])\n* Apply patch to systemd for CVE-2022-3821 ([#2611])\n\n[74d2c5c13ab0]: https://github.com/bottlerocket-os/bottlerocket/commit/74d2c5c13ab0f6839b9849a9f058a70e82f6ffb8\n[64f3967373a5]: https://github.com/bottlerocket-os/bottlerocket/commit/64f3967373a53096219a73580fd81409c846266c\n[#2611]: https://github.com/bottlerocket-os/bottlerocket/pull/2611\n\n# v1.11.0 (2022-11-15)\n\n## OS Changes\n\n* Prevent a panic in `early-boot-config` when there is no IMDS region ([#2493])\n* Update grub to 2.06-42 ([#2503])\n* Bring back wicked support for matching interfaces via hardware address ([#2519])\n* Allow bootstrap containers to manage swap ([#2537])\n* Add `systemd-analyze` commands to troubleshooting log collection tool ([#2550])\n* Allow bootstrap containers to manage network configuration ([#2558])\n* Serialize bootconfig values correctly when the value is empty ([#2565])\n* Update zlib, libexpat, libdbus, docker-cli ([#2583])\n* Update host containers ([#2574])\n* Unmask /sys/firmware from host containers ([#2573])\n\n## Orchestrator Changes\n\n### ECS\n\n* Add additional ECS API configurations ([#2527])\n  * `ECS_CONTAINER_STOP_TIMEOUT`\n  * `ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION`\n  * `ECS_TASK_METADATA_RPS_LIMIT`\n  * `ECS_RESERVED_MEMORY`\n\n### Kubernetes\n\n* Add a timeout when calling EKS for configuration values ([#2566])\n* Enable IAM Roles Anywhere with the k8s `ecr-credential-provider` plugin ([#2377], [#2553])\n* Kubernetes EKS-D updates\n  * v1.24.6 ([#2582])\n  * v1.23.13 ([#2578])\n  * v1.22.15 ([#2580], [#2490])\n\n## Platform Changes\n\n### AWS\n\n* Add driver support for AWS variants in hybrid environments ([#2554])\n\n## Build Changes\n\n* Add support for publishing to AWS organizations ([#2484])\n* Remove unnecessary dependencies when building grub ([#2495])\n* Switch to the latest Dockerfile frontend for builds ([#2496])\n* Prepare foundations for Secure Boot and image re-signing ([#2505])\n* Fix EFI file system to fit partition size ([#2528])\n* Add ShellCheck to `check-lints` for build scripts ([#2532])\n* Update the SDK to v0.28.0 ([#2543])\n* Use `rustls-native-certs` instead of `webpki-roots` ([#2551])\n* Handle absolute paths for output directory in kernel build script ([#2563])\n\n## Documentation Changes\n\n* Add a Roadmap markdown file ([#2549])\n\n[#2377]: https://github.com/bottlerocket-os/bottlerocket/pull/2377\n[#2484]: https://github.com/bottlerocket-os/bottlerocket/pull/2484\n[#2488]: https://github.com/bottlerocket-os/bottlerocket/pull/2488\n[#2490]: https://github.com/bottlerocket-os/bottlerocket/pull/2490\n[#2493]: https://github.com/bottlerocket-os/bottlerocket/pull/2493\n[#2495]: https://github.com/bottlerocket-os/bottlerocket/pull/2495\n[#2496]: https://github.com/bottlerocket-os/bottlerocket/pull/2496\n[#2503]: https://github.com/bottlerocket-os/bottlerocket/pull/2503\n[#2505]: https://github.com/bottlerocket-os/bottlerocket/pull/2505\n[#2519]: https://github.com/bottlerocket-os/bottlerocket/pull/2519\n[#2523]: https://github.com/bottlerocket-os/bottlerocket/pull/2523\n[#2527]: https://github.com/bottlerocket-os/bottlerocket/pull/2527\n[#2528]: https://github.com/bottlerocket-os/bottlerocket/pull/2528\n[#2532]: https://github.com/bottlerocket-os/bottlerocket/pull/2532\n[#2536]: https://github.com/bottlerocket-os/bottlerocket/pull/2536\n[#2537]: https://github.com/bottlerocket-os/bottlerocket/pull/2537\n[#2540]: https://github.com/bottlerocket-os/bottlerocket/pull/2540\n[#2541]: https://github.com/bottlerocket-os/bottlerocket/pull/2541\n[#2542]: https://github.com/bottlerocket-os/bottlerocket/pull/2542\n[#2543]: https://github.com/bottlerocket-os/bottlerocket/pull/2543\n[#2547]: https://github.com/bottlerocket-os/bottlerocket/pull/2547\n[#2549]: https://github.com/bottlerocket-os/bottlerocket/pull/2549\n[#2550]: https://github.com/bottlerocket-os/bottlerocket/pull/2550\n[#2551]: https://github.com/bottlerocket-os/bottlerocket/pull/2551\n[#2553]: https://github.com/bottlerocket-os/bottlerocket/pull/2553\n[#2554]: https://github.com/bottlerocket-os/bottlerocket/pull/2554\n[#2558]: https://github.com/bottlerocket-os/bottlerocket/pull/2558\n[#2563]: https://github.com/bottlerocket-os/bottlerocket/pull/2563\n[#2565]: https://github.com/bottlerocket-os/bottlerocket/pull/2565\n[#2566]: https://github.com/bottlerocket-os/bottlerocket/pull/2566\n[#2574]: https://github.com/bottlerocket-os/bottlerocket/pull/2574\n[#2573]: https://github.com/bottlerocket-os/bottlerocket/pull/2573\n[#2578]: https://github.com/bottlerocket-os/bottlerocket/pull/2578\n[#2580]: https://github.com/bottlerocket-os/bottlerocket/pull/2580\n[#2582]: https://github.com/bottlerocket-os/bottlerocket/pull/2582\n[#2583]: https://github.com/bottlerocket-os/bottlerocket/pull/2583\n\n# v1.10.1 (2022-10-19)\n\n## OS Changes\n* Support container runtime settings: enable-unprivileged-icmp, enable-unprivileged-ports, max-concurrent-downloads, max-container-log-line-size ([#2494])\n* Update EKS-D to 1.22-11 ([#2490])\n* Update EKS-D to 1.23-6 ([#2488])\n\n[#2488]: https://github.com/bottlerocket-os/bottlerocket/pull/2488\n[#2490]: https://github.com/bottlerocket-os/bottlerocket/pull/2490\n[#2494]: https://github.com/bottlerocket-os/bottlerocket/pull/2494\n\n# v1.10.0 (2022-10-10)\n\n## OS Changes\n* Add optional settings to reboot into new kernel command line parameters ([#2375])\n* Support for static IP addressing ([#2204], [#2330], [#2445])\n* Add support for NVIDIA driver version 515 ([#2455])\n* Set mode for tmpfs mounts ([#2473])\n* Increase inotify default limits ([#2335])\n* Align `vm.max_map_count` with the EKS Optimized AMI ([#2344])\n* Add support for configuring DNS settings ([#2353])\n* Migrate `netdog` from `serde_xml_rs` to `quick-xml` ([#2311])\n* Support versioning for `net.toml` ([#2281])\n* Update admin and control container ([#2471], [#2472])\n\n## Orchestrator Changes\n\n### ECS\n* Add `cargo make` tasks for testing ECS variants ([#2348])\n\n### Kubernetes\n\n* Add support for Kubernetes 1.24 variants ([#2437])\n* Remove Kubernetes aws-k8s-1.19 variants ([#2316])\n* Increase the kube-api-server QPS from 5/10 to 10/20 ([#2436], thanks @tzneal)\n* Update eni-max-pods with new instance types ([#2416])\n* Add setting to change `kubelet`'s log level ([#2460], [#2470])\n* Add `cargo make` tasks to perform migration testing for Kubernetes variants in AWS ([#2273])\n\n## Platform Changes\n\n### AWS\n* Disable drivers for USB-attached network interfaces ([#2328])\n\n### Metal\n* Add driver support for Solarflare, Pensando, Myricom, Huawei, Emulex, Chelsio, Broadcom, AMD and Intel 10G+ network cards ([#2379])\n\n## Build Changes\n* Extend `external-files` to vendor go modules ([#2378], [#2403], [#2430])\n* Make `net_config` unit tests reusable across versions ([#2385])\n* Add `diff-kernel-config` to identify kernel config changes ([#2368])\n* Extended support for variants in buildsys ([#2339])\n* Clarify crossbeam license ([#2447])\n* Honor `BUILDSYS_ARCH` and `BUILDSYS_VARIANT` env variables when set ([#2425])\n* Use architecture specific json payloads in unit tests ([#2367], [#2363])\n* Add unified `check` target in `Makefile.toml` for review readiness ([#2384])\n* Update Go dependencies of first-party go projects ([#2424], [#2440], [#2450], [#2452], [#2456])\n* Update Rust dependencies ([#2458], [#2476])\n* Update third-party packages ([#2397], [#2398], [#2464], [#2465], thanks @kschumy)\n* Update Bottlerocket SDK to 0.27.0 ([#2428])\n* Migrate `pubsys` and `infrasys` to the AWS SDK for Rust ([#2414], [#2415], [#2454])\n* Update `testsys` dependencies ([#2392])\n* Fix `hotdog`'s spec URL to the correct upstream link ([#2326])\n* Fix clippy warnings and enable lints on pull requests ([#2337], [#2346], [#2443])\n* Format issue field in PR template ([#2314])\n\n## Documentation Changes\n* Update checksum for new `root.json` ([#2405])\n* Mention that boot settings are available in Kubernetes 1.23 variants ([#2358])\n* Mention the need for AWS credentials in BUILDING.md and PUBLISHING-AWS.md ([#2334])\n* Add China to supported regions lists ([#2315])\n* Add community section to README.md ([#2305], [#2383])\n* Standardize `userdata.toml` as the filename used in different docs ([#2446])\n* Remove commit from image name in PROVISIONING-METAL.md ([#2312])\n* Add note to CONTRIBUTING.md that outlines filenames' casing ([#2306])\n* Fix typos in `Makefile.toml`, QUICKSTART-ECS.md, QUICKSTART-EKS.md, `netdog` and `prairiedog` ([#2318], thanks @kianmeng)\n* Fix casing for GitHub and VMware in CHANGELOG.md ([#2329])\n* Fix typo in test setup command ([#2477])\n* Fix TESTING.md link typo ([#2438])\n* Fix positional `fetch-license` argument ([#2457])\n\n[#2204]: https://github.com/bottlerocket-os/bottlerocket/pull/2204\n[#2273]: https://github.com/bottlerocket-os/bottlerocket/pull/2273\n[#2281]: https://github.com/bottlerocket-os/bottlerocket/pull/2281\n[#2305]: https://github.com/bottlerocket-os/bottlerocket/pull/2305\n[#2306]: https://github.com/bottlerocket-os/bottlerocket/pull/2306\n[#2311]: https://github.com/bottlerocket-os/bottlerocket/pull/2311\n[#2312]: https://github.com/bottlerocket-os/bottlerocket/pull/2312\n[#2314]: https://github.com/bottlerocket-os/bottlerocket/pull/2314\n[#2315]: https://github.com/bottlerocket-os/bottlerocket/pull/2315\n[#2316]: https://github.com/bottlerocket-os/bottlerocket/pull/2316\n[#2318]: https://github.com/bottlerocket-os/bottlerocket/pull/2318\n[#2326]: https://github.com/bottlerocket-os/bottlerocket/pull/2326\n[#2328]: https://github.com/bottlerocket-os/bottlerocket/pull/2328\n[#2329]: https://github.com/bottlerocket-os/bottlerocket/pull/2329\n[#2330]: https://github.com/bottlerocket-os/bottlerocket/pull/2330\n[#2334]: https://github.com/bottlerocket-os/bottlerocket/pull/2334\n[#2335]: https://github.com/bottlerocket-os/bottlerocket/pull/2335\n[#2337]: https://github.com/bottlerocket-os/bottlerocket/pull/2337\n[#2339]: https://github.com/bottlerocket-os/bottlerocket/pull/2339\n[#2344]: https://github.com/bottlerocket-os/bottlerocket/pull/2344\n[#2346]: https://github.com/bottlerocket-os/bottlerocket/pull/2346\n[#2348]: https://github.com/bottlerocket-os/bottlerocket/pull/2348\n[#2353]: https://github.com/bottlerocket-os/bottlerocket/pull/2353\n[#2358]: https://github.com/bottlerocket-os/bottlerocket/pull/2358\n[#2363]: https://github.com/bottlerocket-os/bottlerocket/pull/2363\n[#2367]: https://github.com/bottlerocket-os/bottlerocket/pull/2367\n[#2368]: https://github.com/bottlerocket-os/bottlerocket/pull/2368\n[#2375]: https://github.com/bottlerocket-os/bottlerocket/pull/2375\n[#2378]: https://github.com/bottlerocket-os/bottlerocket/pull/2378\n[#2379]: https://github.com/bottlerocket-os/bottlerocket/pull/2379\n[#2383]: https://github.com/bottlerocket-os/bottlerocket/pull/2383\n[#2384]: https://github.com/bottlerocket-os/bottlerocket/pull/2384\n[#2385]: https://github.com/bottlerocket-os/bottlerocket/pull/2385\n[#2392]: https://github.com/bottlerocket-os/bottlerocket/pull/2392\n[#2397]: https://github.com/bottlerocket-os/bottlerocket/pull/2397\n[#2398]: https://github.com/bottlerocket-os/bottlerocket/pull/2398\n[#2403]: https://github.com/bottlerocket-os/bottlerocket/pull/2403\n[#2405]: https://github.com/bottlerocket-os/bottlerocket/pull/2405\n[#2414]: https://github.com/bottlerocket-os/bottlerocket/pull/2414\n[#2415]: https://github.com/bottlerocket-os/bottlerocket/pull/2415\n[#2416]: https://github.com/bottlerocket-os/bottlerocket/pull/2416\n[#2424]: https://github.com/bottlerocket-os/bottlerocket/pull/2424\n[#2425]: https://github.com/bottlerocket-os/bottlerocket/pull/2425\n[#2428]: https://github.com/bottlerocket-os/bottlerocket/pull/2428\n[#2430]: https://github.com/bottlerocket-os/bottlerocket/pull/2430\n[#2436]: https://github.com/bottlerocket-os/bottlerocket/pull/2436\n[#2437]: https://github.com/bottlerocket-os/bottlerocket/pull/2437\n[#2438]: https://github.com/bottlerocket-os/bottlerocket/pull/2438\n[#2440]: https://github.com/bottlerocket-os/bottlerocket/pull/2440\n[#2443]: https://github.com/bottlerocket-os/bottlerocket/pull/2443\n[#2445]: https://github.com/bottlerocket-os/bottlerocket/pull/2445\n[#2446]: https://github.com/bottlerocket-os/bottlerocket/pull/2446\n[#2447]: https://github.com/bottlerocket-os/bottlerocket/pull/2447\n[#2450]: https://github.com/bottlerocket-os/bottlerocket/pull/2450\n[#2452]: https://github.com/bottlerocket-os/bottlerocket/pull/2452\n[#2454]: https://github.com/bottlerocket-os/bottlerocket/pull/2454\n[#2455]: https://github.com/bottlerocket-os/bottlerocket/pull/2455\n[#2456]: https://github.com/bottlerocket-os/bottlerocket/pull/2456\n[#2457]: https://github.com/bottlerocket-os/bottlerocket/pull/2457\n[#2458]: https://github.com/bottlerocket-os/bottlerocket/pull/2458\n[#2460]: https://github.com/bottlerocket-os/bottlerocket/pull/2460\n[#2464]: https://github.com/bottlerocket-os/bottlerocket/pull/2464\n[#2465]: https://github.com/bottlerocket-os/bottlerocket/pull/2465\n[#2470]: https://github.com/bottlerocket-os/bottlerocket/pull/2470\n[#2471]: https://github.com/bottlerocket-os/bottlerocket/pull/2471\n[#2472]: https://github.com/bottlerocket-os/bottlerocket/pull/2472\n[#2473]: https://github.com/bottlerocket-os/bottlerocket/pull/2473\n[#2476]: https://github.com/bottlerocket-os/bottlerocket/pull/2476\n[#2477]: https://github.com/bottlerocket-os/bottlerocket/pull/2477\n\n# v1.9.2 (2022-08-31)\n\n## Build Changes\n\n* Archive old migrations ([#2357])\n* Update `runc` to version 1.1.4 ([#2380])\n\n[#2357]: https://github.com/bottlerocket-os/bottlerocket/pull/2357\n[#2380]: https://github.com/bottlerocket-os/bottlerocket/pull/2380\n\n# v1.9.1 (2022-08-17)\n\n## OS Changes\n\n* Change kernel module compression from zstd to xz ([#2323])\n* Update ECR registry map for new AWS regions ([#2336])\n* Add new regions to pause registry map ([#2349])\n* Update `tough` to v0.8.1 ([#2338])\n\n[#2323]: https://github.com/bottlerocket-os/bottlerocket/pull/2323\n[#2336]: https://github.com/bottlerocket-os/bottlerocket/pull/2336\n[#2338]: https://github.com/bottlerocket-os/bottlerocket/pull/2338\n[#2349]: https://github.com/bottlerocket-os/bottlerocket/pull/2349\n\n# v1.9.0 (2022-07-28)\n\n## OS Changes\n\n* SELinux policy now suppresses audit for tmpfs relabels ([#2222])\n* Restrict permissions for `/boot` and `System.map` ([#2223])\n* Remove unused crates `growpart` and `servicedog` ([#2238])\n* New mount in host containers for system logs ([#2295])\n* Apply strict mount options and enforce execution rules ([#2239])\n* Switch to a more commonly used syntax for disabling kernel config settings ([#2290])\n* Respect proxy settings when running setting generators ([#2227])\n* Add `NET_CAP_ADMIN` to bootstrap containers ([#2266])\n* Reduce log output for DHCP services ([#2260])\n* Fix invalid kernel config options ([#2269])\n* Improve support for container storage mounts ([#2240])\n* Disable uncommon filesystems and network protocols ([#2255])\n* Add support for blocking kernel modules ([#2274])\n* Fix `ntp` service restart when settings change ([#2270])\n* Add kernel 5.15 sources ([#2226])\n* Defer `squashfs` mounts to later in the boot process ([#2276])\n* Improve boot speed and rootfs size ([#2296])\n* Add \"quiet\" kernel parameter for some variants ([#2277])\n\n## Orchestrator Changes\n\n### Kubernetes\n\n* Make new instance types available ([#2221] , thanks @cablespaghetti)\n* Update Kubernetes versions ([#2230], [#2232], [#2262], [#2263], thanks @kschumy)\n* Add kubelet image GC threshold settings ([#2219])\n\n### ECS\n\n* Add iptables rules for ECS introspection server ([#2267])\n\n## Platform Changes\n\n### AWS\n\n* Add support for AWS China regions ([#2224], [#2242], [#2247], [#2285])\n* Migrate to using `aws-sdk-rust` for first-party OS Rust packages ([#2300])\n\n### VMware\n\n* Remove `console=ttyS0` from kernel params ([#2248])\n\n### Metal\n\n* Enable Mellanox modules in 5.10 kernel ([#2241])\n* Add bnxt module for Broadcom 10/25Gb network adapters in 5.10 kernel ([#2243])\n* Split out baremetal specific config options ([#2264])\n* Add driver support for Cisco UCS platforms ([#2271])\n* Only build baremetal variant specific drivers for baremetal variants ([#2279])\n* Enable the metal-dev build for the ARM architecture ([#2272])\n\n## Build Changes\n\n* Add Makefile targets to create and validate Boot Configuration ([#2189])\n* Create symlinks to images with friendly names ([#2215])\n* Add `start-local-vm` script ([#2194])\n* Add the testsys CLI and new cargo make tasks for testing aws-k8s variants ([#2165])\n* Update Rust and Go dependencies ([#2303], [#2299])\n* Update third-party packages ([#2309])\n\n## Documentation Changes\n\n* Add NVIDIA ECS variant to README ([#2244])\n* Add documentation for metal variants ([#2205])\n* Add missing step in building packages guide ([#2259])\n* Add quickstart for running Bottlerocket in QEMU/KVM VMs ([#2280])\n* Address lints in README markdown caught by `markdownlint` ([#2283])\n\n[#2165]: https://github.com/bottlerocket-os/bottlerocket/pull/2165\n[#2189]: https://github.com/bottlerocket-os/bottlerocket/pull/2189\n[#2194]: https://github.com/bottlerocket-os/bottlerocket/pull/2194\n[#2205]: https://github.com/bottlerocket-os/bottlerocket/pull/2205\n[#2215]: https://github.com/bottlerocket-os/bottlerocket/pull/2215\n[#2219]: https://github.com/bottlerocket-os/bottlerocket/pull/2219\n[#2221]: https://github.com/bottlerocket-os/bottlerocket/pull/2221\n[#2222]: https://github.com/bottlerocket-os/bottlerocket/pull/2222\n[#2223]: https://github.com/bottlerocket-os/bottlerocket/pull/2223\n[#2224]: https://github.com/bottlerocket-os/bottlerocket/pull/2224\n[#2226]: https://github.com/bottlerocket-os/bottlerocket/pull/2226\n[#2227]: https://github.com/bottlerocket-os/bottlerocket/pull/2227\n[#2230]: https://github.com/bottlerocket-os/bottlerocket/pull/2230\n[#2232]: https://github.com/bottlerocket-os/bottlerocket/pull/2232\n[#2238]: https://github.com/bottlerocket-os/bottlerocket/pull/2238\n[#2239]: https://github.com/bottlerocket-os/bottlerocket/pull/2239\n[#2240]: https://github.com/bottlerocket-os/bottlerocket/pull/2240\n[#2241]: https://github.com/bottlerocket-os/bottlerocket/pull/2241\n[#2242]: https://github.com/bottlerocket-os/bottlerocket/pull/2242\n[#2243]: https://github.com/bottlerocket-os/bottlerocket/pull/2243\n[#2244]: https://github.com/bottlerocket-os/bottlerocket/pull/2244\n[#2247]: https://github.com/bottlerocket-os/bottlerocket/pull/2247\n[#2248]: https://github.com/bottlerocket-os/bottlerocket/pull/2248\n[#2255]: https://github.com/bottlerocket-os/bottlerocket/pull/2255\n[#2259]: https://github.com/bottlerocket-os/bottlerocket/pull/2259\n[#2260]: https://github.com/bottlerocket-os/bottlerocket/pull/2260\n[#2262]: https://github.com/bottlerocket-os/bottlerocket/pull/2262\n[#2263]: https://github.com/bottlerocket-os/bottlerocket/pull/2263\n[#2264]: https://github.com/bottlerocket-os/bottlerocket/pull/2264\n[#2266]: https://github.com/bottlerocket-os/bottlerocket/pull/2266\n[#2267]: https://github.com/bottlerocket-os/bottlerocket/pull/2267\n[#2269]: https://github.com/bottlerocket-os/bottlerocket/pull/2269\n[#2270]: https://github.com/bottlerocket-os/bottlerocket/pull/2270\n[#2271]: https://github.com/bottlerocket-os/bottlerocket/pull/2271\n[#2272]: https://github.com/bottlerocket-os/bottlerocket/pull/2272\n[#2274]: https://github.com/bottlerocket-os/bottlerocket/pull/2274\n[#2276]: https://github.com/bottlerocket-os/bottlerocket/pull/2276\n[#2277]: https://github.com/bottlerocket-os/bottlerocket/pull/2277\n[#2279]: https://github.com/bottlerocket-os/bottlerocket/pull/2279\n[#2280]: https://github.com/bottlerocket-os/bottlerocket/pull/2280\n[#2283]: https://github.com/bottlerocket-os/bottlerocket/pull/2283\n[#2285]: https://github.com/bottlerocket-os/bottlerocket/pull/2285\n[#2290]: https://github.com/bottlerocket-os/bottlerocket/pull/2290\n[#2295]: https://github.com/bottlerocket-os/bottlerocket/pull/2295\n[#2296]: https://github.com/bottlerocket-os/bottlerocket/pull/2296\n[#2299]: https://github.com/bottlerocket-os/bottlerocket/pull/2299\n[#2300]: https://github.com/bottlerocket-os/bottlerocket/pull/2300\n[#2303]: https://github.com/bottlerocket-os/bottlerocket/pull/2303\n[#2309]: https://github.com/bottlerocket-os/bottlerocket/pull/2309\n\n# v1.8.0 (2022-06-08)\n\n## OS Changes\n\n### General\n* Update admin and control containers ([#2191])\n* Update to containerd 1.6.x ([#2158])\n* Restart container runtimes when certificates store changes ([#2076])\n* Add support for providing kernel parameters via Boot Configuration ([#1980])\n* Restart long-running systemd services on exit ([#2162])\n* Ignore zero blocks on dm-verity root ([#2169])\n* Add support for static DNS mappings in `/etc/hosts` ([#2129])\n* Enable network configuration generation via `netdog` ([#2066])\n* Add support for non-`eth0` default interfaces ([#2144])\n* Update to IMDS schema `2021-07-15` ([#2190])\n\n### Kubernetes\n* Add support for Kubernetes 1.23 variants ([#2188])\n* Improve Kubernetes pod start times by unsetting `configMapAndSecretChangeDetectionStrategy` in kubelet config ([#2166])\n* Add new setting for configuring kubelet's `provider-id` configuration ([#2192])\n* Add new setting for configuring kubelet's `podPidsLimit` configuration ([#2138])\n* Allow a list of IP addresses in `settings.kubernetes.cluster-dns-ip` ([#2176])\n* Set the default for `settings.kubernetes.cloud-provider` on metal variants to an empty string ([#2188])\n* Add c7g instance data for max pods calculation in AWS variants ([#2107], thanks, @lizthegrey!)\n\n### ECS\n* Add aws-ecs-1-nvidia variant with Nvidia driver support ([#2128], [#2100], [#2098], [#2167], [#2097], [#2090], [#2099])\n* Add support for ECS ImagePullBehavior and WarmPoolsSupport ([#2063], thanks, @mello7tre!)\n\n### Hardware\n* Build smartpqi driver for Microchip Smart Storage devices into 5.10 kernel ([#2184])\n* Add support for Broadcom ethernet cards in 5.10 kernel ([#2143])\n* Add support for MegaRAID SAS in 5.10 kernel ([#2133])\n\n## Build Changes\n* Remove aws-k8s-1.18 variant ([#2044], [#2092])\n* Update third-party packages ([#2178], [#2187], [#2145])\n* Update Rust and Go dependencies ([#2183], [#2181], [#2180], [#2085], [#2110], [#2068], [#2075], [#2074], [#2048], [#2059], [#2049], [#2036], [#2033])\n* Update Bottlerocket SDK to 0.26.0 ([#2157])\n* Speed up kernel builds by installing headers and modules in parallel ([#2185])\n* Removed unused patch from Docker CLI ([#2030], thanks, @thaJeztah!)\n\n## Documentation Changes\n* Standardize README generation in buildsys ([#2134])\n* Clarify migration README ([#2141])\n* Fix typos in BUILDING.md and QUICKSTART-VMWARE.md ([#2159], thanks, @ryanrussell!)\n* Add additional documentation for using GPUs with Kubernetes variants ([#2078])\n* Document examples for using `enter-admin-container` ([#2028])\n\n[#1980]: https://github.com/bottlerocket-os/bottlerocket/pull/1980\n[#2028]: https://github.com/bottlerocket-os/bottlerocket/pull/2028\n[#2030]: https://github.com/bottlerocket-os/bottlerocket/pull/2030\n[#2033]: https://github.com/bottlerocket-os/bottlerocket/pull/2033\n[#2036]: https://github.com/bottlerocket-os/bottlerocket/pull/2036\n[#2044]: https://github.com/bottlerocket-os/bottlerocket/pull/2044\n[#2048]: https://github.com/bottlerocket-os/bottlerocket/pull/2048\n[#2049]: https://github.com/bottlerocket-os/bottlerocket/pull/2049\n[#2059]: https://github.com/bottlerocket-os/bottlerocket/pull/2059\n[#2063]: https://github.com/bottlerocket-os/bottlerocket/pull/2063\n[#2066]: https://github.com/bottlerocket-os/bottlerocket/pull/2066\n[#2068]: https://github.com/bottlerocket-os/bottlerocket/pull/2068\n[#2074]: https://github.com/bottlerocket-os/bottlerocket/pull/2074\n[#2075]: https://github.com/bottlerocket-os/bottlerocket/pull/2075\n[#2076]: https://github.com/bottlerocket-os/bottlerocket/pull/2076\n[#2078]: https://github.com/bottlerocket-os/bottlerocket/pull/2078\n[#2085]: https://github.com/bottlerocket-os/bottlerocket/pull/2085\n[#2090]: https://github.com/bottlerocket-os/bottlerocket/pull/2090\n[#2092]: https://github.com/bottlerocket-os/bottlerocket/pull/2092\n[#2097]: https://github.com/bottlerocket-os/bottlerocket/pull/2097\n[#2098]: https://github.com/bottlerocket-os/bottlerocket/pull/2098\n[#2099]: https://github.com/bottlerocket-os/bottlerocket/pull/2099\n[#2100]: https://github.com/bottlerocket-os/bottlerocket/pull/2100\n[#2107]: https://github.com/bottlerocket-os/bottlerocket/pull/2107\n[#2110]: https://github.com/bottlerocket-os/bottlerocket/pull/2110\n[#2128]: https://github.com/bottlerocket-os/bottlerocket/pull/2128\n[#2129]: https://github.com/bottlerocket-os/bottlerocket/pull/2129\n[#2133]: https://github.com/bottlerocket-os/bottlerocket/pull/2133\n[#2134]: https://github.com/bottlerocket-os/bottlerocket/pull/2134\n[#2138]: https://github.com/bottlerocket-os/bottlerocket/pull/2138\n[#2141]: https://github.com/bottlerocket-os/bottlerocket/pull/2141\n[#2142]: https://github.com/bottlerocket-os/bottlerocket/pull/2142\n[#2143]: https://github.com/bottlerocket-os/bottlerocket/pull/2143\n[#2144]: https://github.com/bottlerocket-os/bottlerocket/pull/2144\n[#2145]: https://github.com/bottlerocket-os/bottlerocket/pull/2145\n[#2146]: https://github.com/bottlerocket-os/bottlerocket/pull/2146\n[#2157]: https://github.com/bottlerocket-os/bottlerocket/pull/2157\n[#2158]: https://github.com/bottlerocket-os/bottlerocket/pull/2158\n[#2159]: https://github.com/bottlerocket-os/bottlerocket/pull/2159\n[#2162]: https://github.com/bottlerocket-os/bottlerocket/pull/2162\n[#2166]: https://github.com/bottlerocket-os/bottlerocket/pull/2166\n[#2167]: https://github.com/bottlerocket-os/bottlerocket/pull/2167\n[#2169]: https://github.com/bottlerocket-os/bottlerocket/pull/2169\n[#2176]: https://github.com/bottlerocket-os/bottlerocket/pull/2176\n[#2178]: https://github.com/bottlerocket-os/bottlerocket/pull/2178\n[#2180]: https://github.com/bottlerocket-os/bottlerocket/pull/2180\n[#2181]: https://github.com/bottlerocket-os/bottlerocket/pull/2181\n[#2183]: https://github.com/bottlerocket-os/bottlerocket/pull/2183\n[#2184]: https://github.com/bottlerocket-os/bottlerocket/pull/2184\n[#2185]: https://github.com/bottlerocket-os/bottlerocket/pull/2185\n[#2187]: https://github.com/bottlerocket-os/bottlerocket/pull/2187\n[#2188]: https://github.com/bottlerocket-os/bottlerocket/pull/2188\n[#2190]: https://github.com/bottlerocket-os/bottlerocket/pull/2190\n[#2191]: https://github.com/bottlerocket-os/bottlerocket/pull/2191\n[#2192]: https://github.com/bottlerocket-os/bottlerocket/pull/2192\n\n# v1.7.2 (2022-04-22)\n\n## Security Fixes\n\n* Update kernel-5.4 to patch CVE-2022-1015, CVE-2022-1016, CVE-2022-25636, CVE-2022-26490, CVE-2022-27666, CVE-2022-28356 ([a3b4674f7108][a3b4674f7108])\n* Update kernel-5.10 to patch CVE-2022-1015, CVE-2022-1016, CVE-2022-25636, CVE-2022-1048, CVE-2022-26490, CVE-2022-27666, CVE-2022-28356 ([37095415bab6][37095415bab6])\n\n## OS Changes\n\n* Update eni-max-pods with new instance types ([#2079])\n* Add support for AWS region ap-southeast-3: Jakarta ([#2080])\n\n[a3b4674f7108]: https://github.com/bottlerocket-os/bottlerocket/commit/a3b4674f7108a7f69f108a011042be2a5b91e563\n[37095415bab6]: https://github.com/bottlerocket-os/bottlerocket/commit/37095415bab67a24240d95b59c7bf20a112d7ae1\n[#2079]: https://github.com/bottlerocket-os/bottlerocket/pull/2079\n[#2080]: https://github.com/bottlerocket-os/bottlerocket/pull/2080\n\n# v1.7.1 (2022-04-05)\n\n## Security Fixes\n\n* Apply patch to hotdog for CVE-2022-0071 ([1a3f35b2fe8e][1a3f35b2fe8e])\n\n## OS Changes\n\n* Enable checkpoint restore (`CONFIG_CHECKPOINT_RESTORE`) for aarch64 ([6e3d6ed4b83e][6e3d6ed4b83e])\n\n[1a3f35b2fe8e]: https://github.com/bottlerocket-os/bottlerocket/commit/1a3f35b2fe8ed9a7078e43940545dc941c5de99f\n[6e3d6ed4b83e]: https://github.com/bottlerocket-os/bottlerocket/commit/6e3d6ed4b83ecefa5de5885f8c4a30cd9df8b689\n\n# v1.7.0 (2022-03-30)\n\nWith this release, an inventory of software installed in Bottlerocket will now be reported to SSM if the control container is in use and inventorying has been enabled.\n\n## OS Changes\n\n* Generate host software inventory and make it available to host containers ([#1996])\n* Update admin and control containers ([#2014])\n\n## Build Changes\n\n* Update third-party packages ([#1977], [#1983], [#1987], [#1992], [#2022])\n* Update Rust and Go dependencies ([#2016], [#2019])\n* Makefile: lock tuftool version ([#2009])\n* Fix tmpfilesd configuration for kmod-5.10-nvidia ([#2020])\n\n## Documentation Changes\n\n* Fix tuftool download instruction in VMware Quickstart ([#1994])\n* Explain data partition extension ([#2013])\n\n[#1977]: https://github.com/bottlerocket-os/bottlerocket/pull/1977\n[#1983]: https://github.com/bottlerocket-os/bottlerocket/pull/1983\n[#1987]: https://github.com/bottlerocket-os/bottlerocket/pull/1987\n[#1992]: https://github.com/bottlerocket-os/bottlerocket/pull/1992\n[#1994]: https://github.com/bottlerocket-os/bottlerocket/pull/1994\n[#1996]: https://github.com/bottlerocket-os/bottlerocket/pull/1996\n[#2009]: https://github.com/bottlerocket-os/bottlerocket/pull/2009\n[#2013]: https://github.com/bottlerocket-os/bottlerocket/pull/2013\n[#2014]: https://github.com/bottlerocket-os/bottlerocket/pull/2014\n[#2016]: https://github.com/bottlerocket-os/bottlerocket/pull/2016\n[#2019]: https://github.com/bottlerocket-os/bottlerocket/pull/2019\n[#2020]: https://github.com/bottlerocket-os/bottlerocket/pull/2020\n[#2022]: https://github.com/bottlerocket-os/bottlerocket/pull/2022\n\n# v1.6.2 (2022-03-08)\n\nWith this release, the vmware-k8s variants have graduated from preview status and are now generally available.\n:tada:\n\n## Security Fixes\n\n* Update kernel-5.4 and kernel-5.10 to include recent security fixes ([a8e4a20ca7d1][a8e4a20ca7d1], [3d0c10abeecb][3d0c10abeecb])\n\n## OS Changes\n\n* Add support for Kubernetes 1.22 variants ([#1962])\n* Add settings support for registry credentials ([#1955])\n* Add support for AWS CloudFormation signaling ([#1728], thanks, @mello7tre!)\n* Add TCMU support to the kernel ([#1953], thanks, @cvlc!)\n* Fix issue with closing frame construction in apiserver ([#1948])\n\n## Build Changes\n\n* Fix dead code warning during build in netdog ([#1949])\n\n## Documentation Changes\n\n* Correct variable name in bootstrap-containers/README.md ([#1959], thanks, @dangen-effy!)\n* Add art to the console ([#1970])\n\n[a8e4a20ca7d1]: https://github.com/bottlerocket-os/bottlerocket/commit/a8e4a20ca7d1dde4e8b5f679e4e11d9687b6ef09\n[3d0c10abeecb]: https://github.com/bottlerocket-os/bottlerocket/commit/3d0c10abeecb9f69b6ec598fd5137cb146a46b6e\n[#1728]: https://github.com/bottlerocket-os/bottlerocket/pull/1728\n[#1948]: https://github.com/bottlerocket-os/bottlerocket/pull/1948\n[#1949]: https://github.com/bottlerocket-os/bottlerocket/pull/1949\n[#1953]: https://github.com/bottlerocket-os/bottlerocket/pull/1953\n[#1955]: https://github.com/bottlerocket-os/bottlerocket/pull/1955\n[#1959]: https://github.com/bottlerocket-os/bottlerocket/pull/1959\n[#1962]: https://github.com/bottlerocket-os/bottlerocket/pull/1962\n[#1970]: https://github.com/bottlerocket-os/bottlerocket/pull/1970\n\n# v1.6.1 (2022-03-02)\n\n## Security Fixes\n\n* Apply patch to containerd for CVE-2022-23648 ([0de1b39efa64][0de1b39efa64])\n* Update kernel-5.4 and kernel-5.10 to include recent security fixes ([#1973])\n\n[0de1b39efa64]: https://github.com/bottlerocket-os/bottlerocket/commit/0de1b39efa6437fa57388918e1554174ca2f02e4\n[#1973]: https://github.com/bottlerocket-os/bottlerocket/pull/1973\n\n# v1.6.0 (2022-02-07)\n\n## Deprecation Notice\n\nThe Kubernetes 1.18 variant, `aws-k8s-1.18`, will lose support in March 2022.\nKubernetes 1.18 is no longer receiving support upstream.\nWe recommend replacing `aws-k8s-1.18` nodes with a later variant, preferably `aws-k8s-1.21` if your cluster supports it.\nSee [this issue](https://github.com/bottlerocket-os/bottlerocket/issues/1942) for more details.\n\n## Security Fixes\n\n* Apply patch to the kernel for CVE-2022-0492 ([#1943])\n\n## OS Changes\n* Add aws-k8s-1.21-nvidia variant with Nvidia driver support ([#1859], [#1860], [#1861], [#1862], [#1900], [#1912], [#1915], [#1916], [#1928])\n* Add metal-k8s-1.21 variant with support for running on bare metal ([#1904])\n* Update host containers to the latest version ([#1939])\n* Add driverdog, a configuration-driven utility for linking kernel modules at runtime ([#1867])\n* Kubernetes: Fix a potential inconsistency with IPv6 node-ip comparisons ([#1932])\n* Allow setting multiple Kubernetes node taints with the same key ([#1906])\n* Fix a bug which would prevent Bottlerocket from booting when setting `container-registry` to an empty table ([#1910])\n* Add `/etc/bottlerocket-release` to host containers ([#1883])\n* Send grub output to the local console on BIOS systems ([#1894])\n* Fix minor issues with systemd units ([#1889])\n\n## Build Changes\n* Update third-party packages ([#1936])\n* Update Rust dependencies ([#1940])\n* Update Go dependencies of `host-ctr` ([#1938])\n* Add the ability to fetch licenses at build time ([#1901])\n* Pin tuftool to a specific version ([#1940])\n\n## Documentation Changes\n* Add a no-proxy setting example to the README ([#1765] thanks, @mrajashree!)\n* Document variant `image-layout` options in the README ([#1896])\n\n\n[#1765]: https://github.com/bottlerocket-os/bottlerocket/pull/1765\n[#1859]: https://github.com/bottlerocket-os/bottlerocket/pull/1859\n[#1860]: https://github.com/bottlerocket-os/bottlerocket/pull/1860\n[#1861]: https://github.com/bottlerocket-os/bottlerocket/pull/1861\n[#1862]: https://github.com/bottlerocket-os/bottlerocket/pull/1862\n[#1867]: https://github.com/bottlerocket-os/bottlerocket/pull/1867\n[#1883]: https://github.com/bottlerocket-os/bottlerocket/pull/1883\n[#1889]: https://github.com/bottlerocket-os/bottlerocket/pull/1889\n[#1894]: https://github.com/bottlerocket-os/bottlerocket/pull/1894\n[#1896]: https://github.com/bottlerocket-os/bottlerocket/pull/1896\n[#1900]: https://github.com/bottlerocket-os/bottlerocket/pull/1900\n[#1901]: https://github.com/bottlerocket-os/bottlerocket/pull/1901\n[#1904]: https://github.com/bottlerocket-os/bottlerocket/pull/1904\n[#1906]: https://github.com/bottlerocket-os/bottlerocket/pull/1906\n[#1910]: https://github.com/bottlerocket-os/bottlerocket/pull/1910\n[#1912]: https://github.com/bottlerocket-os/bottlerocket/pull/1912\n[#1915]: https://github.com/bottlerocket-os/bottlerocket/pull/1915\n[#1916]: https://github.com/bottlerocket-os/bottlerocket/pull/1916\n[#1928]: https://github.com/bottlerocket-os/bottlerocket/pull/1928\n[#1932]: https://github.com/bottlerocket-os/bottlerocket/pull/1932\n[#1936]: https://github.com/bottlerocket-os/bottlerocket/pull/1936\n[#1938]: https://github.com/bottlerocket-os/bottlerocket/pull/1938\n[#1939]: https://github.com/bottlerocket-os/bottlerocket/pull/1939\n[#1940]: https://github.com/bottlerocket-os/bottlerocket/pull/1940\n[#1943]: https://github.com/bottlerocket-os/bottlerocket/pull/1943\n\n# v1.5.3 (2022-01-25)\n\n## Security Fixes\n* Update Bottlerocket SDK to 0.25.1 for Rust 1.58.1 ([#1918])\n* Update kernel-5.4 and kernel-5.10 to include recent security fixes ([#1921])\n* Migrate host-container to the latest version for vmware variants ([#1898])\n\n## OS Changes\n* Fix an issue which could impair nodes in Kubernetes 1.21 IPv6 clusters ([#1925])\n\n[#1898]: https://github.com/bottlerocket-os/bottlerocket/pull/1898\n[#1918]: https://github.com/bottlerocket-os/bottlerocket/pull/1918\n[#1921]: https://github.com/bottlerocket-os/bottlerocket/pull/1921\n[#1925]: https://github.com/bottlerocket-os/bottlerocket/pull/1925\n\n# v1.5.2 (2022-01-05)\n\n## Security Fixes\n* Update containerd for CVE-2021-43816 ([8f085929588a][8f085929588a])\n\n[8f085929588a]: https://github.com/bottlerocket-os/bottlerocket/commit/8f085929588a3f0cd575f865dd6f04f96a97e923\n\n# v1.5.1 (2021-12-23)\n\n## Security Fixes\n* Update hotdog to the latest release. Hotdog now mimics the permissions of the target JVM process ([#1884])\n\n## OS Changes\n* Updated host containers to the latest version ([#1881], [#1882])\n\n[#1881]: https://github.com/bottlerocket-os/bottlerocket/pull/1881\n[#1882]: https://github.com/bottlerocket-os/bottlerocket/pull/1882\n[#1884]: https://github.com/bottlerocket-os/bottlerocket/pull/1884\n\n# v1.5.0 (2021-12-17)\n\n## Security Enhancements\n* Add the ability to hotpatch log4j for CVE-2021-44228 in running containers ([#1872], [#1871], [#1869])\n\n## OS Changes\n* Enable configuration for OCI hooks in the container lifecycle ([#1868])\n* Retry all failed requests to IMDS ([#1841])\n* Enable node feature discovery for Kubernetes device plugins ([#1863])\n* Add `apiclient get` subcommand for simple API retrieval ([#1836])\n* Add support for CPU microcode updates ([#1827])\n* Consistently support API prefix queries ([#1835])\n\n## Build Changes\n* Add support for custom image sizes ([#1826])\n* Add support for unifying the OS and data partitions on a single disk ([#1870])\n\n## Documentation Changes\n* Fixed typo in the README ([#1847] thanks, PascalBourdier!)\n\n[#1826]:https://github.com/bottlerocket-os/bottlerocket/pull/1826\n[#1827]:https://github.com/bottlerocket-os/bottlerocket/pull/1827\n[#1835]:https://github.com/bottlerocket-os/bottlerocket/pull/1835\n[#1836]:https://github.com/bottlerocket-os/bottlerocket/pull/1836\n[#1841]:https://github.com/bottlerocket-os/bottlerocket/pull/1841\n[#1847]:https://github.com/bottlerocket-os/bottlerocket/pull/1847\n[#1863]:https://github.com/bottlerocket-os/bottlerocket/pull/1863\n[#1868]:https://github.com/bottlerocket-os/bottlerocket/pull/1868\n[#1869]:https://github.com/bottlerocket-os/bottlerocket/pull/1869\n[#1870]:https://github.com/bottlerocket-os/bottlerocket/pull/1870\n[#1871]:https://github.com/bottlerocket-os/bottlerocket/pull/1871\n[#1872]:https://github.com/bottlerocket-os/bottlerocket/pull/1872\n\n# v1.4.2 (2021-12-02)\n\n## Security Fixes\n\n* Update default [admin](https://github.com/bottlerocket-os/bottlerocket-admin-container/releases/tag/v0.7.3) and [control](https://github.com/bottlerocket-os/bottlerocket-control-container/releases/tag/v0.5.3) host containers to address CVE-2021-43527 ([#1852])\n* Update kernel-5.4 and kernel-5.10 to include recent security fixes. ([#1851])\n\n## Build Changes\n\n* Update containerd (to v1.5.8) and Docker (to v20.10.11) ([#1851])\n\n[#1851]: https://github.com/bottlerocket-os/bottlerocket/pull/1851\n[#1852]: https://github.com/bottlerocket-os/bottlerocket/pull/1852\n\n# v1.4.1 (2021-11-18)\n\n## Security Fixes\n\n* Apply patches to docker and containerd for CVE-2021-41190 ([#1832], [#1833])\n\n## Build Changes\n\n* Update Bottlerocket SDK to 0.23.1 ([#1831])\n\n[#1831]: https://github.com/bottlerocket-os/bottlerocket/pull/1831\n[#1832]: https://github.com/bottlerocket-os/bottlerocket/pull/1832\n[#1833]: https://github.com/bottlerocket-os/bottlerocket/pull/1833\n\n\n# v1.4.0 (2021-11-12)\n\n## OS Changes\n\n* Add 'apiclient exec' for running commands in host containers ([#1802], [#1790])\n* Improve boot performance ([#1809])\n* Add support for wildcard container registry mirrors ([#1791], [#1818])\n* Wait up to 300s for a DHCP lease at boot ([#1800])\n* Retry if fetching the IMDS session token fails ([#1801])\n* Add ECR account IDs for pulling host containers in GovCloud ([#1793])\n* Filter sensitive API settings from `logdog` dump ([#1777])\n* Fix kubelet standalone mode ([#1783])\n\n## Build Changes\n\n* Remove aws-k8s-1.17 variant ([#1807])\n* Update Bottlerocket SDK to 0.23 ([#1779])\n* Update third-party packages ([#1816])\n* Update Rust dependencies ([#1810])\n* Update Go dependencies of `host-ctr` ([#1775], [#1774])\n* Prevent spurious rebuilds of the model package ([#1808])\n* Add disk image files to TUF repo ([#1787])\n* Vendor wicked service units ([#1798])\n* Add CI check for Rust code formatting ([#1782])\n* Allow overriding the AMI data file suffix ([#1784])\n\n## Documentation Changes\n\n* Update cargo-make commands to work with newest cargo-make ([#1797])\n\n[#1774]: https://github.com/bottlerocket-os/bottlerocket/pull/1774\n[#1775]: https://github.com/bottlerocket-os/bottlerocket/pull/1775\n[#1777]: https://github.com/bottlerocket-os/bottlerocket/pull/1777\n[#1779]: https://github.com/bottlerocket-os/bottlerocket/pull/1779\n[#1782]: https://github.com/bottlerocket-os/bottlerocket/pull/1782\n[#1783]: https://github.com/bottlerocket-os/bottlerocket/pull/1783\n[#1784]: https://github.com/bottlerocket-os/bottlerocket/pull/1784\n[#1787]: https://github.com/bottlerocket-os/bottlerocket/pull/1787\n[#1790]: https://github.com/bottlerocket-os/bottlerocket/pull/1790\n[#1791]: https://github.com/bottlerocket-os/bottlerocket/pull/1791\n[#1793]: https://github.com/bottlerocket-os/bottlerocket/pull/1793\n[#1797]: https://github.com/bottlerocket-os/bottlerocket/pull/1797\n[#1798]: https://github.com/bottlerocket-os/bottlerocket/pull/1798\n[#1800]: https://github.com/bottlerocket-os/bottlerocket/pull/1800\n[#1801]: https://github.com/bottlerocket-os/bottlerocket/pull/1801\n[#1802]: https://github.com/bottlerocket-os/bottlerocket/pull/1802\n[#1807]: https://github.com/bottlerocket-os/bottlerocket/pull/1807\n[#1808]: https://github.com/bottlerocket-os/bottlerocket/pull/1808\n[#1809]: https://github.com/bottlerocket-os/bottlerocket/pull/1809\n[#1810]: https://github.com/bottlerocket-os/bottlerocket/pull/1810\n[#1816]: https://github.com/bottlerocket-os/bottlerocket/pull/1816\n[#1818]: https://github.com/bottlerocket-os/bottlerocket/pull/1818\n\n# v1.3.0 (2021-10-06)\n\n## Deprecation Notice\n\nThe Kubernetes 1.17 variant, `aws-k8s-1.17`, will lose support in November, 2021.\nKubernetes 1.17 is no longer receiving support upstream.\nWe recommend replacing `aws-k8s-1.17` nodes with a later variant, preferably `aws-k8s-1.21` if your cluster supports it.\nSee [this issue](https://github.com/bottlerocket-os/bottlerocket/issues/1772) for more details.\n\n## Security Fixes\n\n* Apply patches to docker and containerd for CVE-2021-41089, CVE-2021-41091, CVE-2021-41092, and CVE-2021-41103 ([#1769])\n\n## OS Changes\n\n* Add MCS constraints to the SELinux policy ([#1733])\n* Support IPv6 in kubelet and pluto ([#1710])\n* Add region flag to aws-iam-authenticator command ([#1762])\n* Restart modified host containers ([#1722])\n* Add more detail to /etc/os-release ([#1749])\n* Add an entry to `/etc/hosts` for the current hostname ([#1713], [#1746])\n* Update default control container to v0.5.2 ([#1730])\n* Fix various SELinux policy issues ([#1729])\n* Update eni-max-pods with new instance types ([#1724], thanks @samjo-nyang!)\n* Add cilium device filters to open-vm-tools ([#1718])\n* Implement hybrid boot support for x86_64 ([#1701])\n* Include `/var/log/kdump` in logdog tarballs ([#1695])\n* Use runtime.slice and system.slice cgroup settings in k8s variants ([#1684], thanks @cyrus-mc!)\n\n## Build Changes\n\n* Update third-party packages ([#1701], [#1716], [#1732], [#1755], [#1763], [#1767])\n* Update Rust dependencies ([#1707], [#1750], [#1751])\n* Add wave definition for slow deployment ([#1734])\n* Add 'infrasys' for creating TUF infra in AWS ([#1723])\n* Make OVF file first in the OVA bundle ([#1719])\n* Raise pubsys messages to 'warn' if AMI exists or repo doesn't ([#1708])\n* Add constants crate ([#1709])\n* Add release URLs to package definitions ([#1748])\n* Add *.src.rpm to packages/.gitignore ([#1768])\n* Archive old migrations ([#1699])\n\n## Documentation Changes\n\n* Mention static pods in the security guidance around API access ([#1766])\n* Fix link to issue labels ([#1764], thanks @andrewhsu!)\n* Fix broken link for TLS bootstrapping ([#1758])\n* Update hash for v3 root.json ([#1757])\n* Update example version to v1.2.0 in QUICKSTART-VMWARE ([#1741], thanks @yuvalk!)\n* Clarify default kernel lockdown settings per variant ([#1704])\n\n[#1684]: https://github.com/bottlerocket-os/bottlerocket/pull/1684\n[#1695]: https://github.com/bottlerocket-os/bottlerocket/pull/1695\n[#1699]: https://github.com/bottlerocket-os/bottlerocket/pull/1699\n[#1701]: https://github.com/bottlerocket-os/bottlerocket/pull/1701\n[#1701]: https://github.com/bottlerocket-os/bottlerocket/pull/1701\n[#1704]: https://github.com/bottlerocket-os/bottlerocket/pull/1704\n[#1707]: https://github.com/bottlerocket-os/bottlerocket/pull/1707\n[#1708]: https://github.com/bottlerocket-os/bottlerocket/pull/1708\n[#1709]: https://github.com/bottlerocket-os/bottlerocket/pull/1709\n[#1710]: https://github.com/bottlerocket-os/bottlerocket/pull/1710\n[#1713]: https://github.com/bottlerocket-os/bottlerocket/pull/1713\n[#1716]: https://github.com/bottlerocket-os/bottlerocket/pull/1716\n[#1718]: https://github.com/bottlerocket-os/bottlerocket/pull/1718\n[#1719]: https://github.com/bottlerocket-os/bottlerocket/pull/1719\n[#1722]: https://github.com/bottlerocket-os/bottlerocket/pull/1722\n[#1723]: https://github.com/bottlerocket-os/bottlerocket/pull/1723\n[#1724]: https://github.com/bottlerocket-os/bottlerocket/pull/1724\n[#1729]: https://github.com/bottlerocket-os/bottlerocket/pull/1729\n[#1730]: https://github.com/bottlerocket-os/bottlerocket/pull/1730\n[#1732]: https://github.com/bottlerocket-os/bottlerocket/pull/1732\n[#1733]: https://github.com/bottlerocket-os/bottlerocket/pull/1733\n[#1734]: https://github.com/bottlerocket-os/bottlerocket/pull/1734\n[#1741]: https://github.com/bottlerocket-os/bottlerocket/pull/1741\n[#1746]: https://github.com/bottlerocket-os/bottlerocket/pull/1746\n[#1748]: https://github.com/bottlerocket-os/bottlerocket/pull/1748\n[#1749]: https://github.com/bottlerocket-os/bottlerocket/pull/1749\n[#1750]: https://github.com/bottlerocket-os/bottlerocket/pull/1750\n[#1751]: https://github.com/bottlerocket-os/bottlerocket/pull/1751\n[#1755]: https://github.com/bottlerocket-os/bottlerocket/pull/1755\n[#1757]: https://github.com/bottlerocket-os/bottlerocket/pull/1757\n[#1758]: https://github.com/bottlerocket-os/bottlerocket/pull/1758\n[#1762]: https://github.com/bottlerocket-os/bottlerocket/pull/1762\n[#1763]: https://github.com/bottlerocket-os/bottlerocket/pull/1763\n[#1764]: https://github.com/bottlerocket-os/bottlerocket/pull/1764\n[#1766]: https://github.com/bottlerocket-os/bottlerocket/pull/1766\n[#1767]: https://github.com/bottlerocket-os/bottlerocket/pull/1767\n[#1768]: https://github.com/bottlerocket-os/bottlerocket/pull/1768\n[#1769]: https://github.com/bottlerocket-os/bottlerocket/pull/1769\n\n# v1.2.1 (2021-09-16)\n\n## Security fixes\n\n* Update Kubernetes for CVE-2021-25741 ([#1753])\n\n[#1753]: https://github.com/bottlerocket-os/bottlerocket/pull/1753\n\n# v1.2.0 (2021-08-06)\n\n## OS Changes\n\n* Add settings for kubelet topologyManagerPolicy and topologyManagerScope ([#1659])\n* Add support for container image registry mirrors ([#1629])\n* Add support for custom CA certificates ([#1654])\n* Add a setting for configuring hostname ([#1664], [#1680], [#1693])\n* Avoid wildcard for applying rp_filter to interfaces ([#1677])\n* Update default admin container to v0.7.2 ([#1685])\n\n## Build Changes\n\n* Add support for zstd compressed kernel ([#1668], [#1689])\n* Add support for uploading OVAs to VMware ([#1622])\n* Update default built variant to aws-k8s-1.21 ([#1686])\n* Remove aws-k8s-1.16 variant ([#1658])\n* Move migrations from v1.1.5 to v1.2.0 ([#1682])\n* Update third-party packages ([#1676])\n* Update host-ctr dependencies ([#1669])\n* Update Rust dependencies ([#1655], [#1683], [#1687])\n\n## Documentation Changes\n\n* Fix typo in README ([#1652], **thanks @faultymonk!**)\n\n[#1622]: https://github.com/bottlerocket-os/bottlerocket/pull/1622\n[#1629]: https://github.com/bottlerocket-os/bottlerocket/pull/1629\n[#1652]: https://github.com/bottlerocket-os/bottlerocket/pull/1652\n[#1654]: https://github.com/bottlerocket-os/bottlerocket/pull/1654\n[#1655]: https://github.com/bottlerocket-os/bottlerocket/pull/1655\n[#1658]: https://github.com/bottlerocket-os/bottlerocket/pull/1658\n[#1659]: https://github.com/bottlerocket-os/bottlerocket/pull/1659\n[#1664]: https://github.com/bottlerocket-os/bottlerocket/pull/1664\n[#1668]: https://github.com/bottlerocket-os/bottlerocket/pull/1668\n[#1669]: https://github.com/bottlerocket-os/bottlerocket/pull/1669\n[#1676]: https://github.com/bottlerocket-os/bottlerocket/pull/1676\n[#1677]: https://github.com/bottlerocket-os/bottlerocket/pull/1677\n[#1680]: https://github.com/bottlerocket-os/bottlerocket/pull/1680\n[#1682]: https://github.com/bottlerocket-os/bottlerocket/pull/1682\n[#1683]: https://github.com/bottlerocket-os/bottlerocket/pull/1683\n[#1685]: https://github.com/bottlerocket-os/bottlerocket/pull/1685\n[#1686]: https://github.com/bottlerocket-os/bottlerocket/pull/1686\n[#1687]: https://github.com/bottlerocket-os/bottlerocket/pull/1687\n[#1689]: https://github.com/bottlerocket-os/bottlerocket/pull/1689\n[#1693]: https://github.com/bottlerocket-os/bottlerocket/pull/1693\n\n# v1.1.4 (2021-07-23)\n\n## Security fixes\n\n* Update containerd to 1.4.8 ([#1661])\n* Update systemd to 247.8 ([#1662])\n* Update 5.4 and 5.10 kernels ([#1665])\n* Set permissions to root-only for /var/lib/systemd/random-seed ([#1656])\n\n[#1656]: https://github.com/bottlerocket-os/bottlerocket/pull/1656\n[#1661]: https://github.com/bottlerocket-os/bottlerocket/pull/1661\n[#1662]: https://github.com/bottlerocket-os/bottlerocket/pull/1662\n[#1665]: https://github.com/bottlerocket-os/bottlerocket/pull/1665\n\n# v1.1.3 (2021-07-12)\n\nNote: in the Bottlerocket v1.0.8 release, for the aws-k8s-1.20 and aws-k8s-1.21 variants, we set the default Kubernetes CPU manager policy to \"static\".\nWe heard from several users that this breaks usage of the Fluent Bit log processor.\nIn Bottlerocket v1.1.3, we've changed the default back to \"none\", but have added a setting so you can use the \"static\" policy if desired.\nTo do so, set `settings.kubernetes.cpu-manager-policy` to \"static\".\nTo do this in user data, for example, pass the following:\n\n```toml\n[settings.kubernetes]\ncpu-manager-policy = \"static\"\n```\n\n## OS Changes\n\n* Fix parsing of lists of values in domain name search field of DHCP option sets ([#1646], **thanks @hypnoce!**)\n* Add setting for configuring Kubernetes CPU manager policy and reconcile policy  ([#1638])\n\n## Build Changes\n\n* Update SDK to 0.22.0 ([#1640])\n* Store build artifacts per architecture ([#1630])\n\n## Documentation Changes\n\n* Update references to the ECS variant for GA release ([#1637])\n\n[#1630]: https://github.com/bottlerocket-os/bottlerocket/pull/1630\n[#1637]: https://github.com/bottlerocket-os/bottlerocket/pull/1637\n[#1638]: https://github.com/bottlerocket-os/bottlerocket/pull/1638\n[#1640]: https://github.com/bottlerocket-os/bottlerocket/pull/1640\n[#1646]: https://github.com/bottlerocket-os/bottlerocket/pull/1646\n\n# v1.1.2 (2021-06-25)\n\nWith this release, the aws-ecs-1 variant has graduated from preview status and is now generally available.\nIt's been updated to include Docker 20.10.\nThe new [Bottlerocket ECS Updater](https://github.com/bottlerocket-os/bottlerocket-ecs-updater/) is available to help provide automated updates.\n:tada:\n\n## OS Changes\n\n* Add aws-k8s-1.21 variant with Kubernetes 1.21 support ([#1612])\n* Add settings for configuring kubelet containerLogMaxFiles and containerLogMaxSize ([#1589]) (Thanks, @samjo-nyang!)\n* Add settings for configuring kubelet systemReserved ([#1606])\n* Add kdump support, enabled by default in VMware variants ([#1596])\n* In host containers, allow mount propagations from privileged containers ([#1601])\n* Mark ipv6 lease as optional for eth0 ([#1602])\n* Add recommended device filters to open-vm-tools ([#1603])\n* In host container definitions, default \"enabled\" and \"superpowered\" to false ([#1580])\n* Allow pubsys refresh-repo to use default key path ([#1575])\n* Update default host containers ([#1609])\n\n## Build Changes\n\n* Add grep package to all variants ([#1562])\n* Update Rust dependencies ([#1623], [#1574])\n* Update third-party packages ([#1619], [#1616], [#1625])\n* In GitHub Actions, pin rust toolchain to match version in SDK ([#1621])\n* Add imdsclient library for querying IMDS ([#1372], [#1598], [#1610])\n* Remove reqwest proxy workaround in metricdog and updog ([#1592])\n* Simplify conditional compilation in early-boot-config ([#1576])\n* Only build shibaken for aws variants ([#1591])\n* Silence tokio mut warning in thar-be-settings ([#1593])\n* Refactor package and variant dependencies ([#1549])\n* Add derive attributes at start of list in model-derive ([#1572])\n* Limit threads during pubsys validate-repo ([#1564])\n\n## Documentation Changes\n\n* Document the deprecation of the aws-k8s-1.16 variant ([#1600])\n* Update README for VMware and add a QUICKSTART-VMWARE ([#1559])\n* Add ap-northeast-3 to supported region list ([#1566])\n* Add details about the two default Bottlerocket volumes to README ([#1588])\n* Document webpki-roots version in webpki-roots-shim ([#1565])\n\n[#1372]: https://github.com/bottlerocket-os/bottlerocket/pull/1372\n[#1549]: https://github.com/bottlerocket-os/bottlerocket/pull/1549\n[#1559]: https://github.com/bottlerocket-os/bottlerocket/pull/1559\n[#1562]: https://github.com/bottlerocket-os/bottlerocket/pull/1562\n[#1564]: https://github.com/bottlerocket-os/bottlerocket/pull/1564\n[#1565]: https://github.com/bottlerocket-os/bottlerocket/pull/1565\n[#1566]: https://github.com/bottlerocket-os/bottlerocket/pull/1566\n[#1572]: https://github.com/bottlerocket-os/bottlerocket/pull/1572\n[#1574]: https://github.com/bottlerocket-os/bottlerocket/pull/1574\n[#1575]: https://github.com/bottlerocket-os/bottlerocket/pull/1575\n[#1576]: https://github.com/bottlerocket-os/bottlerocket/pull/1576\n[#1580]: https://github.com/bottlerocket-os/bottlerocket/pull/1580\n[#1588]: https://github.com/bottlerocket-os/bottlerocket/pull/1588\n[#1589]: https://github.com/bottlerocket-os/bottlerocket/pull/1589\n[#1591]: https://github.com/bottlerocket-os/bottlerocket/pull/1591\n[#1592]: https://github.com/bottlerocket-os/bottlerocket/pull/1592\n[#1593]: https://github.com/bottlerocket-os/bottlerocket/pull/1593\n[#1596]: https://github.com/bottlerocket-os/bottlerocket/pull/1596\n[#1598]: https://github.com/bottlerocket-os/bottlerocket/pull/1598\n[#1600]: https://github.com/bottlerocket-os/bottlerocket/pull/1600\n[#1601]: https://github.com/bottlerocket-os/bottlerocket/pull/1601\n[#1602]: https://github.com/bottlerocket-os/bottlerocket/pull/1602\n[#1603]: https://github.com/bottlerocket-os/bottlerocket/pull/1603\n[#1606]: https://github.com/bottlerocket-os/bottlerocket/pull/1606\n[#1609]: https://github.com/bottlerocket-os/bottlerocket/pull/1609\n[#1610]: https://github.com/bottlerocket-os/bottlerocket/pull/1610\n[#1612]: https://github.com/bottlerocket-os/bottlerocket/pull/1612\n[#1616]: https://github.com/bottlerocket-os/bottlerocket/pull/1616\n[#1619]: https://github.com/bottlerocket-os/bottlerocket/pull/1619\n[#1621]: https://github.com/bottlerocket-os/bottlerocket/pull/1621\n[#1623]: https://github.com/bottlerocket-os/bottlerocket/pull/1623\n[#1625]: https://github.com/bottlerocket-os/bottlerocket/pull/1625\n\n# v1.1.1 (2021-05-19)\n\n## Security fixes\n\n* Patch runc for CVE-2021-30465 ([232c5741ecec][232c5741ecec])\n\n[232c5741ecec]: https://github.com/bottlerocket-os/bottlerocket/commit/232c5741ecec1b903df3e56922bda03eecb2c02a\n\n# v1.1.0 (2021-05-07)\n\n## Deprecation Notice\n\nThe Kubernetes 1.16 variant, `aws-k8s-1.16`, will lose support in July, 2021.\nKubernetes 1.16 is no longer receiving support upstream.\nWe recommend replacing `aws-k8s-1.16` nodes with a later variant, preferably `aws-k8s-1.19` if your cluster supports it.\nSee [this issue](https://github.com/bottlerocket-os/bottlerocket/issues/1552) for more details.\n\n## Important Notes\n\n### New variants with new defaults\n\nThis release introduces two new variants, `aws-k8s-1.20` and `vmware-k8s-1.20`.\nWe plan for all new variants, including these, to contain the following changes:\n* The kernel is Linux 5.10 rather than 5.4.\n* The kernel lockdown mode is set to \"integrity\" rather than \"none\".\n\nThe ECS preview variant, `aws-ecs-1`, has also been updated with these changes.\n\nExisting `aws-k8s` variants will not receive these changes as they could affect existing workloads.\n\n### ECS task networking\n\nThe `aws-ecs-1` variant now supports the `awsvpc` mode of [ECS task networking](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html).\nThis allocates an elastic network interface and private IP address to each task.\n\n## OS Changes\n\n* Add Linux kernel 5.10 for use in new variants ([#1526])\n* Add aws-k8s-1.20 variant with Kubernetes 1.20 support ([#1437], [#1533])\n* Add vmware-k8s-1.20 variant with Kubernetes 1.20 for VMware ([#1511], [#1529], [#1523], [#1502], [#1554])\n* Remove aws-k8s-1.15 variant ([#1487], [#1492])\n* Constrain ephemeral port range ([#1560])\n* Support awsvpc networking mode in ECS ([#1246])\n* Add settings for QPS and burst limits of Kubernetes registry pulls, event records, and API ([#1527], [#1532], [#1541])\n* Add setting to allow configuration of Kubernetes TLS bootstrap ([#1485])\n* Add setting for configuring Kubernetes cloudProvider to allow usage outside AWS ([#1494])\n* Make Kubernetes cluster-dns-ip optional to support usage outside of AWS ([#1482])\n* Change parameters to support healthy CIS scan ([#1295]) (Thanks, @felipeac!)\n* Generate stable machine IDs for VMware and ARM KVM guests ([#1506], [#1537])\n* Enable \"integrity\" kernel lockdown mode for aws-ecs-1 preview variant ([#1530])\n* Remove override for default service start timeout ([#1483])\n* Restrict access to bootstrap container user data with SELinux ([#1496])\n* Split SELinux policy rules for trusted subjects ([#1558])\n* Add symlink to allow usage of secrets store CSI drivers ([#1544])\n* Prevent bootstrap containers from restarting ([#1508])\n* Add udev rules to mount CD-ROM only when media is present ([#1516])\n* Add resize2fs binary to sbin ([#1519]) (Thanks, @samjo-nyang!)\n* Only restart a host container if affected by settings change ([#1480])\n* Support file patterns when specifying log files in logdog ([#1509])\n* Daemonize thar-be-settings to avoid zombie processes ([#1507])\n* Add support for AWS region ap-northeast-3: Osaka ([#1504])\n* Generate pause container URI with standard template variables ([#1551])\n* Get cluster DNS IP from cluster when available ([#1547])\n\n## Build Changes\n\n* Use kernel 5.10 in aws-ecs-1 variant ([#1555])\n* Build only the packages needed for the current variant ([#1408], [#1520])\n* Use a friendly name for VMware OVA files in build outputs ([#1535])\n* Update SDK to 0.21.0 ([#1497], [#1529])\n* Allow variants to specify extra kernel parameters ([#1491])\n* Move kernel console settings to variant definitions ([#1513])\n* Update vmw_backdoor dependency ([#1498]) (Thanks, @lucab!)\n* Archive old migrations ([#1540])\n* Refactor default settings and containerd configs to shared files ([#1538], [#1542])\n* Check cargo version at start of build so we have a clear error when it's too low ([#1503])\n* Fix concurrency issue in validate-repo that led to hangs ([#1521])\n* Update third-party package dependencies ([#1543], [#1556])\n* Update Rust dependencies in the tools/ workspace ([#1548])\n* Update tokio-related Rust dependencies in the sources/ workspace ([#1479])\n* Add upstream runc patches addressing container scheduling failure ([#1546])\n* Retry builds on known BuildKit internal errors ([#1557], [#1561])\n\n## Documentation Changes\n\n* Document the deprecation of the aws-k8s-1.15 variant ([#1476])\n* Document the need to quote most Kubernetes labels/taints ([#1550]) (Thanks, @ellistarn!)\n* Fix VMware spelling and document user data sources ([#1534])\n\n[#1246]: https://github.com/bottlerocket-os/bottlerocket/pull/1246\n[#1295]: https://github.com/bottlerocket-os/bottlerocket/pull/1295\n[#1408]: https://github.com/bottlerocket-os/bottlerocket/pull/1408\n[#1437]: https://github.com/bottlerocket-os/bottlerocket/pull/1437\n[#1476]: https://github.com/bottlerocket-os/bottlerocket/pull/1476\n[#1477]: https://github.com/bottlerocket-os/bottlerocket/pull/1477\n[#1479]: https://github.com/bottlerocket-os/bottlerocket/pull/1479\n[#1480]: https://github.com/bottlerocket-os/bottlerocket/pull/1480\n[#1482]: https://github.com/bottlerocket-os/bottlerocket/pull/1482\n[#1483]: https://github.com/bottlerocket-os/bottlerocket/pull/1483\n[#1485]: https://github.com/bottlerocket-os/bottlerocket/pull/1485\n[#1486]: https://github.com/bottlerocket-os/bottlerocket/pull/1486\n[#1487]: https://github.com/bottlerocket-os/bottlerocket/pull/1487\n[#1491]: https://github.com/bottlerocket-os/bottlerocket/pull/1491\n[#1492]: https://github.com/bottlerocket-os/bottlerocket/pull/1492\n[#1494]: https://github.com/bottlerocket-os/bottlerocket/pull/1494\n[#1496]: https://github.com/bottlerocket-os/bottlerocket/pull/1496\n[#1497]: https://github.com/bottlerocket-os/bottlerocket/pull/1497\n[#1498]: https://github.com/bottlerocket-os/bottlerocket/pull/1498\n[#1502]: https://github.com/bottlerocket-os/bottlerocket/pull/1502\n[#1503]: https://github.com/bottlerocket-os/bottlerocket/pull/1503\n[#1504]: https://github.com/bottlerocket-os/bottlerocket/pull/1504\n[#1506]: https://github.com/bottlerocket-os/bottlerocket/pull/1506\n[#1507]: https://github.com/bottlerocket-os/bottlerocket/pull/1507\n[#1508]: https://github.com/bottlerocket-os/bottlerocket/pull/1508\n[#1509]: https://github.com/bottlerocket-os/bottlerocket/pull/1509\n[#1511]: https://github.com/bottlerocket-os/bottlerocket/pull/1511\n[#1513]: https://github.com/bottlerocket-os/bottlerocket/pull/1513\n[#1516]: https://github.com/bottlerocket-os/bottlerocket/pull/1516\n[#1519]: https://github.com/bottlerocket-os/bottlerocket/pull/1519\n[#1520]: https://github.com/bottlerocket-os/bottlerocket/pull/1520\n[#1521]: https://github.com/bottlerocket-os/bottlerocket/pull/1521\n[#1523]: https://github.com/bottlerocket-os/bottlerocket/pull/1523\n[#1526]: https://github.com/bottlerocket-os/bottlerocket/pull/1526\n[#1527]: https://github.com/bottlerocket-os/bottlerocket/pull/1527\n[#1529]: https://github.com/bottlerocket-os/bottlerocket/pull/1529\n[#1530]: https://github.com/bottlerocket-os/bottlerocket/pull/1530\n[#1532]: https://github.com/bottlerocket-os/bottlerocket/pull/1532\n[#1533]: https://github.com/bottlerocket-os/bottlerocket/pull/1533\n[#1534]: https://github.com/bottlerocket-os/bottlerocket/pull/1534\n[#1535]: https://github.com/bottlerocket-os/bottlerocket/pull/1535\n[#1537]: https://github.com/bottlerocket-os/bottlerocket/pull/1537\n[#1538]: https://github.com/bottlerocket-os/bottlerocket/pull/1538\n[#1540]: https://github.com/bottlerocket-os/bottlerocket/pull/1540\n[#1541]: https://github.com/bottlerocket-os/bottlerocket/pull/1541\n[#1542]: https://github.com/bottlerocket-os/bottlerocket/pull/1542\n[#1543]: https://github.com/bottlerocket-os/bottlerocket/pull/1543\n[#1544]: https://github.com/bottlerocket-os/bottlerocket/pull/1544\n[#1546]: https://github.com/bottlerocket-os/bottlerocket/pull/1546\n[#1547]: https://github.com/bottlerocket-os/bottlerocket/pull/1547\n[#1548]: https://github.com/bottlerocket-os/bottlerocket/pull/1548\n[#1550]: https://github.com/bottlerocket-os/bottlerocket/pull/1550\n[#1551]: https://github.com/bottlerocket-os/bottlerocket/pull/1551\n[#1554]: https://github.com/bottlerocket-os/bottlerocket/pull/1554\n[#1555]: https://github.com/bottlerocket-os/bottlerocket/pull/1555\n[#1556]: https://github.com/bottlerocket-os/bottlerocket/pull/1556\n[#1557]: https://github.com/bottlerocket-os/bottlerocket/pull/1557\n[#1558]: https://github.com/bottlerocket-os/bottlerocket/pull/1558\n[#1560]: https://github.com/bottlerocket-os/bottlerocket/pull/1560\n[#1561]: https://github.com/bottlerocket-os/bottlerocket/pull/1561\n\n# v1.0.8 (2021-04-12)\n\n## Deprecation Notice\n\nBottlerocket 1.0.8 is the last release where we plan to support the Kubernetes 1.15 variant, `aws-k8s-1.15`.\nKubernetes 1.15 is no longer receiving support upstream.\nWe recommend replacing `aws-k8s-1.15` nodes with a later variant, preferably `aws-k8s-1.19` if your cluster supports it.\nSee [this issue](https://github.com/bottlerocket-os/bottlerocket/issues/1478) for more details.\n\n## OS Changes\n\n* Support additional kubelet arguments: kube-reserved, eviction-hard, cpu-manager-policy, and allow-unsafe-sysctls ([#1388], [#1472], [#1465])\n* Expand file and process restrictions in the SELinux policy ([#1464])\n* Add support for bootstrap containers ([#1387], [#1423])\n* Make host containers inherit proxy env vars ([#1432])\n* Allow gzip compression of user data ([#1366])\n* Add 'apply' mode to apiclient for applying settings from URIs ([#1391])\n* Add compat symlink for kubelet volume plugins ([#1417])\n* Remove bottlerocket.version attribute from ECS agent settings ([#1395])\n* Make Kubernetes taint values optional ([#1406])\n* Add guestinfo to available VMware user data retrieval methods ([#1393])\n* Include source of invalid base64 data in error messages ([#1469])\n* Update eni-max-pods data file ([#1468])\n* Update default host container versions ([#1443], [#1441], [#1466])\n* Fix avc denial for dbus-broker ([#1434])\n* Fix case of outputted JSON keys in host container user data ([#1439])\n* Set mode of host container persistent storage directory after creation ([#1463])\n* Add \"current\" persistent storage location for host containers ([#1416])\n* Write static-pods manifest to tempfile before persisting it ([#1409])\n\n## Build Changes\n\n* Update default variant to aws-k8s-1.19 ([#1394])\n* Update third-party packages ([#1460])\n* Update Rust dependencies ([#1461], [#1462])\n* Update dependencies of host-ctr ([#1371])\n* Add support for specifying a variant's supported architectures ([#1431])\n* Build OVA packages and include them in repos ([#1428])\n* Add support for qcow2 as an image format ([#1425]) (Thanks, @mikalstill!)\n* Prevent unneeded artifacts from being copied through build process ([#1426])\n* Change image format for vmware-dev variant to vmdk ([#1397])\n* Remove tough dependency from update_metadata ([#1390])\n* Remove generate_constants logic from build.rs of parse-datetime ([#1376])\n* In the tools workspace, update to tokio v1, reqwest v0.11, and tough v0.11 ([#1370])\n* Run static and non-static Rust builds in parallel ([#1368])\n* Disable CMDLINE_EXTEND kernel configuration ([#1473])\n\n## Documentation Changes\n\n* Document metrics settings in README ([#1449])\n* Fix broken links for symlinked files in models README ([#1444])\n* Document `apiclient update` as primary CLI update method ([#1421])\n* Use `apiclient set` in introductory documentation, explain raw mode separately ([#1418])\n* Prefer resolve:ssm: parameters for simplicity in QUICKSTART ([#1363])\n* Update quickstart guides to have arm64 examples ([#1360])\n* Document the deprecation of the aws-k8s-1.15 variant ([#1476])\n\n[#1360]: https://github.com/bottlerocket-os/bottlerocket/pull/1360\n[#1363]: https://github.com/bottlerocket-os/bottlerocket/pull/1363\n[#1366]: https://github.com/bottlerocket-os/bottlerocket/pull/1366\n[#1368]: https://github.com/bottlerocket-os/bottlerocket/pull/1368\n[#1370]: https://github.com/bottlerocket-os/bottlerocket/pull/1370\n[#1371]: https://github.com/bottlerocket-os/bottlerocket/pull/1371\n[#1376]: https://github.com/bottlerocket-os/bottlerocket/pull/1376\n[#1387]: https://github.com/bottlerocket-os/bottlerocket/pull/1387\n[#1388]: https://github.com/bottlerocket-os/bottlerocket/pull/1388\n[#1390]: https://github.com/bottlerocket-os/bottlerocket/pull/1390\n[#1391]: https://github.com/bottlerocket-os/bottlerocket/pull/1391\n[#1393]: https://github.com/bottlerocket-os/bottlerocket/pull/1393\n[#1394]: https://github.com/bottlerocket-os/bottlerocket/pull/1394\n[#1395]: https://github.com/bottlerocket-os/bottlerocket/pull/1395\n[#1397]: https://github.com/bottlerocket-os/bottlerocket/pull/1397\n[#1406]: https://github.com/bottlerocket-os/bottlerocket/pull/1406\n[#1409]: https://github.com/bottlerocket-os/bottlerocket/pull/1409\n[#1416]: https://github.com/bottlerocket-os/bottlerocket/pull/1416\n[#1417]: https://github.com/bottlerocket-os/bottlerocket/pull/1417\n[#1418]: https://github.com/bottlerocket-os/bottlerocket/pull/1418\n[#1421]: https://github.com/bottlerocket-os/bottlerocket/pull/1421\n[#1423]: https://github.com/bottlerocket-os/bottlerocket/pull/1423\n[#1425]: https://github.com/bottlerocket-os/bottlerocket/pull/1425\n[#1426]: https://github.com/bottlerocket-os/bottlerocket/pull/1426\n[#1428]: https://github.com/bottlerocket-os/bottlerocket/pull/1428\n[#1431]: https://github.com/bottlerocket-os/bottlerocket/pull/1431\n[#1432]: https://github.com/bottlerocket-os/bottlerocket/pull/1432\n[#1434]: https://github.com/bottlerocket-os/bottlerocket/pull/1434\n[#1439]: https://github.com/bottlerocket-os/bottlerocket/pull/1439\n[#1441]: https://github.com/bottlerocket-os/bottlerocket/pull/1441\n[#1443]: https://github.com/bottlerocket-os/bottlerocket/pull/1443\n[#1444]: https://github.com/bottlerocket-os/bottlerocket/pull/1444\n[#1449]: https://github.com/bottlerocket-os/bottlerocket/pull/1449\n[#1460]: https://github.com/bottlerocket-os/bottlerocket/pull/1460\n[#1461]: https://github.com/bottlerocket-os/bottlerocket/pull/1461\n[#1462]: https://github.com/bottlerocket-os/bottlerocket/pull/1462\n[#1463]: https://github.com/bottlerocket-os/bottlerocket/pull/1463\n[#1464]: https://github.com/bottlerocket-os/bottlerocket/pull/1464\n[#1465]: https://github.com/bottlerocket-os/bottlerocket/pull/1465\n[#1466]: https://github.com/bottlerocket-os/bottlerocket/pull/1466\n[#1468]: https://github.com/bottlerocket-os/bottlerocket/pull/1468\n[#1469]: https://github.com/bottlerocket-os/bottlerocket/pull/1469\n[#1472]: https://github.com/bottlerocket-os/bottlerocket/pull/1472\n[#1473]: https://github.com/bottlerocket-os/bottlerocket/pull/1473\n[#1476]: https://github.com/bottlerocket-os/bottlerocket/pull/1476\n\n# v1.0.7 (2021-03-17)\n\n## Security fixes\n\n* containerd: update to 1.4.4 ([#1401])\n\n## OS Changes\n\n* systemd: update to 247.4 to fix segfault in some cases ([#1400])\n* apiserver: reap exited child processes ([#1384])\n* host-ctr: specify non-colliding runc root ([#1359])\n* updog: update signal-hook dependency ([#1328])\n\n[#1328]: https://github.com/bottlerocket-os/bottlerocket/pull/1328\n[#1359]: https://github.com/bottlerocket-os/bottlerocket/pull/1359\n[#1384]: https://github.com/bottlerocket-os/bottlerocket/pull/1384\n[#1400]: https://github.com/bottlerocket-os/bottlerocket/pull/1400\n[#1401]: https://github.com/bottlerocket-os/bottlerocket/pull/1401\n\n# v1.0.6 (2021-03-02)\n\n## OS Changes\n\n* Add metricdog to support sending anonymous metrics ([#1006], [#1322])\n* Add a vmware-dev variant ([#1292], [#1288], [#1290])\n* Add Kubernetes static pods support ([#1317])\n* Add high-level 'set' subcommand for changing settings using apiclient ([#1278])\n* Allow admin container to use SSH public keys from user data ([#1331], [#1358], [#19])\n* Add support for kubelet in standalone mode and TLS auth ([#1338])\n* Add https-proxy and no-proxy settings to updog ([#1324])\n* Add support for pulling host-containers from ECR Public ([#1296])\n* Add network proxy support to aws-k8s-1.19 ([#1337])\n* Modify default SELinux label for containers to align with upstream ([#1318])\n* Add aliases for container-selinux types to align with community ([#1316])\n* Update default versions of admin and control containers ([#1347], [#1344])\n* Update ecs-agent to 1.50.2 ([#1353])\n* logdog: Add eni logs for Kubernetes ([#1327])\n\n## Build Changes\n\n* Add the ability to output vmdk via qemu-img ([#1289])\n* Add support for kmod kits to ease building of third-party kernel modules ([#1287], [#1286], [#1285], [#1357])\n* storewolf: Declare dependencies on model and defaults files ([#1319])\n* storewolf: Refactor default settings files to allow sharing ([#1303], [#1329])\n* Switch from TermLogger to SimpleLogger ([#1282], **thanks @hencrice!**)\n* Allow overriding the \"pretty\" name of the OS inside the image ([#1330])\n* Specify bash in link-variant task for use of bash features ([#1323])\n* Fix invalid symlinks when the BUILDSYS_NAME variable is set ([#1312])\n* Track and clean output files for builds ([#1291])\n* Update third-party software packages ([#1340], [#1336], [#1334], [#1333], [#1335], [#1190], [#1265], [#1315], [#1352], [#1356])\n\n## Documentation Changes\n\n* Add lockdown notes to SECURITY_GUIDANCE.md ([#1281])\n* Clarify use case for update repos ([#1339])\n* Fix broken link from API docs to top-level docs ([#1306])\n\n[#1006]: https://github.com/bottlerocket-os/bottlerocket/pull/1006\n[#1190]: https://github.com/bottlerocket-os/bottlerocket/pull/1190\n[#1265]: https://github.com/bottlerocket-os/bottlerocket/pull/1265\n[#1278]: https://github.com/bottlerocket-os/bottlerocket/pull/1278\n[#1281]: https://github.com/bottlerocket-os/bottlerocket/pull/1281\n[#1282]: https://github.com/bottlerocket-os/bottlerocket/pull/1282\n[#1285]: https://github.com/bottlerocket-os/bottlerocket/pull/1285\n[#1286]: https://github.com/bottlerocket-os/bottlerocket/pull/1286\n[#1287]: https://github.com/bottlerocket-os/bottlerocket/pull/1287\n[#1288]: https://github.com/bottlerocket-os/bottlerocket/pull/1288\n[#1289]: https://github.com/bottlerocket-os/bottlerocket/pull/1289\n[#1290]: https://github.com/bottlerocket-os/bottlerocket/pull/1290\n[#1291]: https://github.com/bottlerocket-os/bottlerocket/pull/1291\n[#1292]: https://github.com/bottlerocket-os/bottlerocket/pull/1292\n[#1296]: https://github.com/bottlerocket-os/bottlerocket/pull/1296\n[#1303]: https://github.com/bottlerocket-os/bottlerocket/pull/1303\n[#1306]: https://github.com/bottlerocket-os/bottlerocket/pull/1306\n[#1312]: https://github.com/bottlerocket-os/bottlerocket/pull/1312\n[#1315]: https://github.com/bottlerocket-os/bottlerocket/pull/1315\n[#1316]: https://github.com/bottlerocket-os/bottlerocket/pull/1316\n[#1317]: https://github.com/bottlerocket-os/bottlerocket/pull/1317\n[#1318]: https://github.com/bottlerocket-os/bottlerocket/pull/1318\n[#1319]: https://github.com/bottlerocket-os/bottlerocket/pull/1319\n[#1322]: https://github.com/bottlerocket-os/bottlerocket/pull/1322\n[#1323]: https://github.com/bottlerocket-os/bottlerocket/pull/1323\n[#1324]: https://github.com/bottlerocket-os/bottlerocket/pull/1324\n[#1327]: https://github.com/bottlerocket-os/bottlerocket/pull/1327\n[#1329]: https://github.com/bottlerocket-os/bottlerocket/pull/1329\n[#1330]: https://github.com/bottlerocket-os/bottlerocket/pull/1330\n[#1331]: https://github.com/bottlerocket-os/bottlerocket/pull/1331\n[#1333]: https://github.com/bottlerocket-os/bottlerocket/pull/1333\n[#1334]: https://github.com/bottlerocket-os/bottlerocket/pull/1334\n[#1335]: https://github.com/bottlerocket-os/bottlerocket/pull/1335\n[#1336]: https://github.com/bottlerocket-os/bottlerocket/pull/1336\n[#1337]: https://github.com/bottlerocket-os/bottlerocket/pull/1337\n[#1338]: https://github.com/bottlerocket-os/bottlerocket/pull/1338\n[#1339]: https://github.com/bottlerocket-os/bottlerocket/pull/1339\n[#1340]: https://github.com/bottlerocket-os/bottlerocket/pull/1340\n[#1344]: https://github.com/bottlerocket-os/bottlerocket/pull/1344\n[#1347]: https://github.com/bottlerocket-os/bottlerocket/pull/1347\n[#1352]: https://github.com/bottlerocket-os/bottlerocket/pull/1352\n[#1353]: https://github.com/bottlerocket-os/bottlerocket/pull/1353\n[#1356]: https://github.com/bottlerocket-os/bottlerocket/pull/1356\n[#1357]: https://github.com/bottlerocket-os/bottlerocket/pull/1357\n[#1358]: https://github.com/bottlerocket-os/bottlerocket/pull/1358\n[#19]: https://github.com/bottlerocket-os/bottlerocket-admin-container/pull/19\n\n# v1.0.5 (2021-01-15)\n\n**Note for aws-ecs-1 variant**: due to a change in the ECS agent's data store schema, the aws-ecs-1 variant cannot be downgraded after updating to v1.0.5.\nAttempts to downgrade may result in inconsistencies between ECS and the Bottlerocket container instance.\n\n## OS Changes\n\n* Add aws-k8s-1.19 variant with Kubernetes 1.19 ([#1256])\n* Update ecs-agent to 1.48.1 ([#1201])\n* Add high-level update subcommands to apiclient ([#1219], [#1232])\n* Add kernel lockdown settings ([#1223], [#1279])\n* Add restart-commands for docker, kubelet, containerd ([#1231], [#1262], [#1258])\n* Add proper restarts for host-containers ([#1230], [#1235], [#1242], [#1258])\n* Fix SELinux policy ([#1236])\n* Set version and revision strings for containerd ([#1248])\n* Add host-container user-data setting ([#1244], [#1247])\n* Add network proxy settings ([#1204], [#1262], [#1258])\n* Update kernel to 5.4.80-40.140 ([#1257])\n* Update third-party software packages ([#1264])\n* Update Rust dependencies ([#1267])\n\n## Build Changes\n\n* Improve support for out-of-tree kernel modules ([#1220])\n* Fix message in partition size check condition ([#1233], **thanks @pranavek!**)\n* Split the datastore module into its own crate ([#1249])\n* Update SDK to v0.15.0 ([#1263])\n* Update GitHub Actions to ignore changes that only include .md files ([#1274])\n\n## Documentation Changes\n\n* Add documentation comments to Dockerfile ([#1254])\n* Add a note about CPU usage during builds ([#1266])\n* Update README to point to discussions ([#1273])\n\n[#1201]: https://github.com/bottlerocket-os/bottlerocket/pull/1201\n[#1204]: https://github.com/bottlerocket-os/bottlerocket/pull/1204\n[#1219]: https://github.com/bottlerocket-os/bottlerocket/pull/1219\n[#1220]: https://github.com/bottlerocket-os/bottlerocket/pull/1220\n[#1223]: https://github.com/bottlerocket-os/bottlerocket/pull/1223\n[#1230]: https://github.com/bottlerocket-os/bottlerocket/pull/1230\n[#1231]: https://github.com/bottlerocket-os/bottlerocket/pull/1231\n[#1232]: https://github.com/bottlerocket-os/bottlerocket/pull/1232\n[#1233]: https://github.com/bottlerocket-os/bottlerocket/pull/1233\n[#1235]: https://github.com/bottlerocket-os/bottlerocket/pull/1235\n[#1236]: https://github.com/bottlerocket-os/bottlerocket/pull/1236\n[#1242]: https://github.com/bottlerocket-os/bottlerocket/pull/1242\n[#1244]: https://github.com/bottlerocket-os/bottlerocket/pull/1244\n[#1247]: https://github.com/bottlerocket-os/bottlerocket/pull/1247\n[#1248]: https://github.com/bottlerocket-os/bottlerocket/pull/1248\n[#1249]: https://github.com/bottlerocket-os/bottlerocket/pull/1249\n[#1254]: https://github.com/bottlerocket-os/bottlerocket/pull/1254\n[#1256]: https://github.com/bottlerocket-os/bottlerocket/pull/1256\n[#1257]: https://github.com/bottlerocket-os/bottlerocket/pull/1257\n[#1258]: https://github.com/bottlerocket-os/bottlerocket/pull/1258\n[#1259]: https://github.com/bottlerocket-os/bottlerocket/pull/1259\n[#1262]: https://github.com/bottlerocket-os/bottlerocket/pull/1262\n[#1263]: https://github.com/bottlerocket-os/bottlerocket/pull/1263\n[#1264]: https://github.com/bottlerocket-os/bottlerocket/pull/1264\n[#1266]: https://github.com/bottlerocket-os/bottlerocket/pull/1266\n[#1267]: https://github.com/bottlerocket-os/bottlerocket/pull/1267\n[#1273]: https://github.com/bottlerocket-os/bottlerocket/pull/1273\n[#1274]: https://github.com/bottlerocket-os/bottlerocket/pull/1274\n[#1279]: https://github.com/bottlerocket-os/bottlerocket/pull/1279\n\n# v1.0.4 (2020-11-30)\n\n## Security fixes\n\n* Patch containerd for CVE-2020-15257 ([f3677c1406][f3677c1406])\n\n[f3677c1406]: https://github.com/bottlerocket-os/bottlerocket/commit/f3677c1406139240d2bca6b275799953ced5a5f\n\n# v1.0.3 (2020-11-19)\n\n## OS Changes\n* Support setting Linux kernel parameters (sysctl) via settings (see README) ([#1158], [#1171])\n* Create links under `/dev/disk/ephemeral` for ephemeral storage devices ([#1173])\n* Set default RLIMIT_NOFILE in CRI to 65536 soft limit and a 1048576 hard limit ([#1180])\n* Add rtcsync directive to chrony config file ([#1184], **thanks @errm!**)\n* Add `/etc/ssl/certs` symlink to the CA certificate bundle for compatibility with the cluster autoscaler ([#1207])\n* Add procps dependency to docker-engine so that `docker top` works ([#1210])\n\n## Build Changes\n* Align optimization level for crate and dependency builds ([#1155])\n* pubsys no longer requires an Infra.toml file for basic usage ([#1166])\n* Makefile: Check that $BUILDSYS_ARCH has a supported value ([#1167])\n* Build migrations in parallel ([#1192])\n* Allow file URLs for role in pubsys-setup ([#1194])\n* Update Rust dependencies ([#1196])\n* Update SDK to v0.14.0 ([#1198])\n* Fix an occasional issue with KMS signing in pubsys ([#1205])\n* Backport selected fixes from containerd 1.4 ([#1216])\n* Update third-party package dependencies ([#1176], [#1195])\n* Switch to SDK v0.14.0 ([#1198])\n\n## Documentation Changes\n* Nits and fixes ([#1170], [#1179])\n* Add missing prerequisites for building Bottlerocket ([#1191])\n\n[#1158]: https://github.com/bottlerocket-os/bottlerocket/pull/1158\n[#1171]: https://github.com/bottlerocket-os/bottlerocket/pull/1171\n[#1173]: https://github.com/bottlerocket-os/bottlerocket/pull/1173\n[#1176]: https://github.com/bottlerocket-os/bottlerocket/pull/1176\n[#1180]: https://github.com/bottlerocket-os/bottlerocket/pull/1180\n[#1184]: https://github.com/bottlerocket-os/bottlerocket/pull/1184\n[#1195]: https://github.com/bottlerocket-os/bottlerocket/pull/1195\n[#1207]: https://github.com/bottlerocket-os/bottlerocket/pull/1207\n[#1155]: https://github.com/bottlerocket-os/bottlerocket/pull/1155\n[#1166]: https://github.com/bottlerocket-os/bottlerocket/pull/1166\n[#1167]: https://github.com/bottlerocket-os/bottlerocket/pull/1167\n[#1192]: https://github.com/bottlerocket-os/bottlerocket/pull/1192\n[#1194]: https://github.com/bottlerocket-os/bottlerocket/pull/1194\n[#1196]: https://github.com/bottlerocket-os/bottlerocket/pull/1196\n[#1198]: https://github.com/bottlerocket-os/bottlerocket/pull/1198\n[#1205]: https://github.com/bottlerocket-os/bottlerocket/pull/1205\n[#1170]: https://github.com/bottlerocket-os/bottlerocket/pull/1170\n[#1179]: https://github.com/bottlerocket-os/bottlerocket/pull/1179\n[#1191]: https://github.com/bottlerocket-os/bottlerocket/pull/1191\n[#1210]: https://github.com/bottlerocket-os/bottlerocket/pull/1210\n[#1216]: https://github.com/bottlerocket-os/bottlerocket/pull/1216\n[#1198]: https://github.com/bottlerocket-os/bottlerocket/pull/1198\n\n# v1.0.2 (2020-10-13)\n\n## Breaking changes (for build process only)\n\n* pubsys: automate setup of role and key ([#1133], [#1146])\n* Store repos under repo name so you can build multiple ([#1135])\n\n**Note:** these changes do not impact users of Bottlerocket AMIs or repos, only those who build Bottlerocket themselves.\nIf you use an `Infra.toml` file to automate publishing, you'll need to update the format of the file.\nThe root role and signing key definitions now live inside a repo definition, rather than at the top level of the file.\nPlease see the updated [Infra.toml.example](tools/pubsys/Infra.toml.example) file for a commented explanation of the new role and key configuration.\n\n## OS changes\n\n* Add aws-k8s-1.18 variant with Kubernetes 1.18 ([#1150])\n* Update kernel to 5.4.50-25.83 ([#1148])\n* Update glibc to 2.32 ([#1092])\n* Add e2fsprogs ([#1147])\n* pluto: add regional map of pause container source accounts ([#1142])\n* Add option to enable spot instance draining ([#1100], **thanks @mkulke!**)\n* Add 2.root.json + pubsys KMS support ([#1122])\n* docker: add default nofiles ulimits for containers ([#1119])\n* Fix AVC denial for`docker run --init` ([#1085])\n\n## Build changes\n\n* Pass Go module proxy variables through docker-go ([#1121])\n* Set buildmode to pie and drop pie and debuginfo patches for Kubernetes ([#1103], **thanks @bnrjee!**)\n* pubsys: use requested size for volume, keeping snapshot to minimum size ([#1118])\n* Switch to SDK v0.13.0 ([#1092])\n* Add `cargo make grant-ami` and `revoke-ami` tasks ([#1087])\n* Allow specifying AMI name with PUBLISH_AMI_NAME ([#1091])\n* Makefile.toml: clean up clean actions ([#1089])\n* pubsys: check for copied AMIs in parallel ([#1086])\n\n## Documentation changes\n\n* Add PUBLISHING.md guide explaining pubsys and related tools ([#1138])\n* README: relocate update API instructions and example ([#1124], [#1127])\n* Fix grammar issues in README.md ([#1098], **thanks @jweissig!**)\n* Add documentation for the aws-ecs-1 variant ([#1053])\n* Update suggested Kubernetes version in sample eksctl config files ([#1090])\n* Update BUILDING.md to incorporate dependencies ([#1107], **thanks @troyaws!**)\n\n\n[#1053]: https://github.com/bottlerocket-os/bottlerocket/pull/1053\n[#1084]: https://github.com/bottlerocket-os/bottlerocket/pull/1084\n[#1085]: https://github.com/bottlerocket-os/bottlerocket/pull/1085\n[#1086]: https://github.com/bottlerocket-os/bottlerocket/pull/1086\n[#1087]: https://github.com/bottlerocket-os/bottlerocket/pull/1087\n[#1089]: https://github.com/bottlerocket-os/bottlerocket/pull/1089\n[#1090]: https://github.com/bottlerocket-os/bottlerocket/pull/1090\n[#1091]: https://github.com/bottlerocket-os/bottlerocket/pull/1091\n[#1092]: https://github.com/bottlerocket-os/bottlerocket/pull/1092\n[#1094]: https://github.com/bottlerocket-os/bottlerocket/pull/1094\n[#1098]: https://github.com/bottlerocket-os/bottlerocket/pull/1098\n[#1100]: https://github.com/bottlerocket-os/bottlerocket/pull/1100\n[#1103]: https://github.com/bottlerocket-os/bottlerocket/pull/1103\n[#1107]: https://github.com/bottlerocket-os/bottlerocket/pull/1107\n[#1109]: https://github.com/bottlerocket-os/bottlerocket/pull/1109\n[#1118]: https://github.com/bottlerocket-os/bottlerocket/pull/1118\n[#1119]: https://github.com/bottlerocket-os/bottlerocket/pull/1119\n[#1121]: https://github.com/bottlerocket-os/bottlerocket/pull/1121\n[#1122]: https://github.com/bottlerocket-os/bottlerocket/pull/1122\n[#1124]: https://github.com/bottlerocket-os/bottlerocket/pull/1124\n[#1127]: https://github.com/bottlerocket-os/bottlerocket/pull/1127\n[#1133]: https://github.com/bottlerocket-os/bottlerocket/pull/1133\n[#1135]: https://github.com/bottlerocket-os/bottlerocket/pull/1135\n[#1138]: https://github.com/bottlerocket-os/bottlerocket/pull/1138\n[#1142]: https://github.com/bottlerocket-os/bottlerocket/pull/1142\n[#1146]: https://github.com/bottlerocket-os/bottlerocket/pull/1146\n[#1147]: https://github.com/bottlerocket-os/bottlerocket/pull/1147\n[#1148]: https://github.com/bottlerocket-os/bottlerocket/pull/1148\n[#1149]: https://github.com/bottlerocket-os/bottlerocket/pull/1149\n[#1150]: https://github.com/bottlerocket-os/bottlerocket/pull/1150\n\n# v1.0.1 (2020-09-03)\n\n## Security fixes\n\n* Patch kernel for CVE-2020-14386 ([#1108])\n\n[#1108]: https://github.com/bottlerocket-os/bottlerocket/pull/1108\n\n# v1.0.0 (2020-08-31)\n\nWelcome to Bottlerocket 1.0!\nSince the first public preview, we've added new variants for Amazon ECS and Kubernetes 1.16 and 1.17, support for ARM instances and more EC2 regions, along with many new features and security improvements.\nWe appreciate all the feedback and contributions so far and look forward to working with the community on even wider support.\n\n:partying_face: :smile_cat:\n\n## Security fixes\n\n* Update to chrony 3.5.1 ([#1057])\n* Isolate host containers and limit access to API socket ([#1056])\n\n## OS changes\n\n* The `aws-ecs-1` variant is now available as a preview.\n   * ecs-agent: upgrade to v1.43.0 ([#1043])\n   * aws-ecs-1: add ecs.loglevel setting ([#1062])\n   * aws-ecs-1: remove unsupported capabilities ([#1052])\n   * aws-ecs-1: constrain ephemeral port range ([#1051])\n   * aws-ecs-1: enable awslogs execution role support ([#1044])\n   * ecs-agent: don't start if not configured ([#1049])\n   * ecs-agent: bind introspection to localhost ([#1071])\n   * Update logdog to pull ECS-related log files ([#1054])\n   * Add documentation for the aws-ecs-1 variant ([#1053])\n* apiclient: accept -s for --socket-path, as per usage message ([#1069])\n* Fix growpart to avoid race in partition table reload ([#1058])\n* Added patch for EC2 IMDSv2 support in Docker ([#1055])\n* schnauzer: add a helper for ecr repos ([#1032])\n\n## Build changes\n\n* Add `cargo make ami-public` and `ami-private` targets ([#1033], [#1065], [#1064])\n* Add `cargo make ssm` and `promote-ssm` targets for publishing parameters ([#1060], [#1070], [#1067], [#1066])\n* Use per-checkout cache directories for builds ([#1050])\n* Fix rust build caching and tune rpm compression ([#1045])\n* Add official builds in 16 more EC2 regions. ([aws/containers-roadmap#827](https://github.com/aws/containers-roadmap/issues/827))\n\n## Documentation changes\n\n* Revise security guidance ([#1072])\n* README: add supported architectures ([#1048])\n* Update supported region list after 0.5.0 release ([#1046])\n* Removed aws-cli v1 requirement in docs ([#1073])\n* Update BUILDING.md for new coldsnap-based amiize.sh ([#1047])\n\n\n[#1073]: https://github.com/bottlerocket-os/bottlerocket/pull/1073\n[#1072]: https://github.com/bottlerocket-os/bottlerocket/pull/1072\n[#1071]: https://github.com/bottlerocket-os/bottlerocket/pull/1071\n[#1070]: https://github.com/bottlerocket-os/bottlerocket/pull/1070\n[#1069]: https://github.com/bottlerocket-os/bottlerocket/pull/1069\n[#1067]: https://github.com/bottlerocket-os/bottlerocket/pull/1067\n[#1066]: https://github.com/bottlerocket-os/bottlerocket/pull/1066\n[#1065]: https://github.com/bottlerocket-os/bottlerocket/pull/1065\n[#1064]: https://github.com/bottlerocket-os/bottlerocket/pull/1064\n[#1062]: https://github.com/bottlerocket-os/bottlerocket/pull/1062\n[#1060]: https://github.com/bottlerocket-os/bottlerocket/pull/1060\n[#1058]: https://github.com/bottlerocket-os/bottlerocket/pull/1058\n[#1057]: https://github.com/bottlerocket-os/bottlerocket/pull/1057\n[#1056]: https://github.com/bottlerocket-os/bottlerocket/pull/1056\n[#1055]: https://github.com/bottlerocket-os/bottlerocket/pull/1055\n[#1054]: https://github.com/bottlerocket-os/bottlerocket/pull/1054\n[#1053]: https://github.com/bottlerocket-os/bottlerocket/pull/1053\n[#1052]: https://github.com/bottlerocket-os/bottlerocket/pull/1052\n[#1051]: https://github.com/bottlerocket-os/bottlerocket/pull/1051\n[#1050]: https://github.com/bottlerocket-os/bottlerocket/pull/1050\n[#1049]: https://github.com/bottlerocket-os/bottlerocket/pull/1049\n[#1048]: https://github.com/bottlerocket-os/bottlerocket/pull/1048\n[#1047]: https://github.com/bottlerocket-os/bottlerocket/pull/1047\n[#1046]: https://github.com/bottlerocket-os/bottlerocket/pull/1046\n[#1045]: https://github.com/bottlerocket-os/bottlerocket/pull/1045\n[#1044]: https://github.com/bottlerocket-os/bottlerocket/pull/1044\n[#1043]: https://github.com/bottlerocket-os/bottlerocket/pull/1043\n[#1033]: https://github.com/bottlerocket-os/bottlerocket/pull/1033\n[#1032]: https://github.com/bottlerocket-os/bottlerocket/pull/1032\n\n\n# v0.5.0 (2020-08-14)\n\nSpecial thanks to first-time contributor @spoonofpower ([#988])!\n\n## Breaking changes\n\n* Remove support for unsigned datastore migrations ([#976])\n\n## OS changes\n\n* Add `aws-ecs-1` variant prototype for running containers in ECS clusters ([#946], [#1005], [#1007], [#1008], [#1009], [#1017])\n* Configurable `clusterDomain` kubelet setting via `settings.kubernetes.cluster-domain` ([#988], [#1036])\n* Make update position within waves consistent ([#993])\n* Fix kubelet configuration for `MaxPods` ([#994])\n* Update `eni-max-pods` with new instance types ([#994])\n* Fix `max_versions` unit test in `updata` ([#998])\n* Remove injection of `label:disable` option for privileged containers in Docker ([#1013])\n* Add `policycoreutils` and related tools ([#1016])\n* Update third-party software packages ([#1018], [#1023], [#1025], [#1026])\n* Update Rust dependencies ([#1019], [#1021])\n* Update `host-ctr`'s dependencies ([#1020])\n* Update the host-containers' default versions ([#1030], [#1040])\n* Allow access to all device nodes for superpowered host-containers ([#1037])\n\n## Build changes\n\n* Add `pubsys` (`cargo make repo`, `cargo make ami`) for repo and AMI creation ([#964], [#1010], [#1028], [#1034])\n* Require `updata init` before creating a new repo manifest ([#991])\n* Exclude README.md files from cargo change tracking ([#995], [#996])\n* Build `aws-k8s-1.17` variant by default with `cargo make` ([#1002])\n* Update comments to be more accurate in Infra.toml ([#1004])\n* Update `amiize` to use `coldsnap` ([#1012])\n* Update Bottlerocket SDK to v0.12.0 ([#1014])\n* Fix warnings for use of deprecated items in `common_migrations` ([#1022])\n\n## Documentation changes\n\n* Removed instructions to manually apply the manifest for aws-vpc-cni-k8s ([#1029])\n\n[#946]: https://github.com/bottlerocket-os/bottlerocket/pull/946\n[#964]: https://github.com/bottlerocket-os/bottlerocket/pull/964\n[#976]: https://github.com/bottlerocket-os/bottlerocket/pull/976\n[#988]: https://github.com/bottlerocket-os/bottlerocket/pull/988\n[#991]: https://github.com/bottlerocket-os/bottlerocket/pull/991\n[#993]: https://github.com/bottlerocket-os/bottlerocket/pull/993\n[#994]: https://github.com/bottlerocket-os/bottlerocket/pull/994\n[#995]: https://github.com/bottlerocket-os/bottlerocket/pull/995\n[#996]: https://github.com/bottlerocket-os/bottlerocket/pull/996\n[#998]: https://github.com/bottlerocket-os/bottlerocket/pull/998\n[#1002]: https://github.com/bottlerocket-os/bottlerocket/pull/1002\n[#1004]: https://github.com/bottlerocket-os/bottlerocket/pull/1004\n[#1005]: https://github.com/bottlerocket-os/bottlerocket/pull/1005\n[#1007]: https://github.com/bottlerocket-os/bottlerocket/pull/1007\n[#1008]: https://github.com/bottlerocket-os/bottlerocket/pull/1008\n[#1009]: https://github.com/bottlerocket-os/bottlerocket/pull/1009\n[#1010]: https://github.com/bottlerocket-os/bottlerocket/pull/1010\n[#1012]: https://github.com/bottlerocket-os/bottlerocket/pull/1012\n[#1013]: https://github.com/bottlerocket-os/bottlerocket/pull/1013\n[#1014]: https://github.com/bottlerocket-os/bottlerocket/pull/1014\n[#1016]: https://github.com/bottlerocket-os/bottlerocket/pull/1016\n[#1017]: https://github.com/bottlerocket-os/bottlerocket/pull/1017\n[#1018]: https://github.com/bottlerocket-os/bottlerocket/pull/1018\n[#1019]: https://github.com/bottlerocket-os/bottlerocket/pull/1019\n[#1020]: https://github.com/bottlerocket-os/bottlerocket/pull/1020\n[#1021]: https://github.com/bottlerocket-os/bottlerocket/pull/1021\n[#1022]: https://github.com/bottlerocket-os/bottlerocket/pull/1022\n[#1023]: https://github.com/bottlerocket-os/bottlerocket/pull/1023\n[#1025]: https://github.com/bottlerocket-os/bottlerocket/pull/1025\n[#1026]: https://github.com/bottlerocket-os/bottlerocket/pull/1026\n[#1028]: https://github.com/bottlerocket-os/bottlerocket/pull/1028\n[#1029]: https://github.com/bottlerocket-os/bottlerocket/pull/1029\n[#1030]: https://github.com/bottlerocket-os/bottlerocket/pull/1030\n[#1034]: https://github.com/bottlerocket-os/bottlerocket/pull/1034\n[#1036]: https://github.com/bottlerocket-os/bottlerocket/pull/1036\n[#1037]: https://github.com/bottlerocket-os/bottlerocket/pull/1037\n[#1040]: https://github.com/bottlerocket-os/bottlerocket/pull/1040\n\n# v0.4.1 (2020-07-13)\n\n## Security fixes\n\n* Patch Kubernetes for CVE-2020-8558 ([#977])\n* Update `tough` to 0.7.1 to patch CVE-2020-15093 ([#979])\n\n## OS changes\n\n* Add a new `aws-k8s-1.17` variant for Kubernetes 1.17 ([#973])\n* Confine `chrony`, `wicked`, and `dbus-broker` via SELinux, and persist their state to disk ([#970])\n* Persist `systemd` journal to disk ([#970])\n* Add an API for OS updates ([#942], [#959], [#986])\n* Add migration helpers to add / remove multiple settings at once ([#958])\n* Fix SELinux policy to allow CSI driver mounts and transition used by Kaniko ([#983])\n* Update to new repo URL via migration to ensure signed migration support ([#980])\n\n## Build changes\n\n* Fix environment variable override for build output directory ([#963])\n* Update `.dockerignore` to account for the new build output directory structure ([#967])\n* Remove the `preview-docs` task from `Makefile` ([#969])\n\n## Documentation changes\n\n* Document new update APIs and add associated diagrams ([#962])\n* Add `ap-south-1` to supported regions ([#965])\n* Fix `storewolf`'s documentation and usage message as it expects a semver value ([#957])\n\n[#942]: https://github.com/bottlerocket-os/bottlerocket/pull/942\n[#957]: https://github.com/bottlerocket-os/bottlerocket/pull/957\n[#958]: https://github.com/bottlerocket-os/bottlerocket/pull/958\n[#959]: https://github.com/bottlerocket-os/bottlerocket/pull/959\n[#962]: https://github.com/bottlerocket-os/bottlerocket/pull/962\n[#963]: https://github.com/bottlerocket-os/bottlerocket/pull/963\n[#965]: https://github.com/bottlerocket-os/bottlerocket/pull/965\n[#967]: https://github.com/bottlerocket-os/bottlerocket/pull/967\n[#969]: https://github.com/bottlerocket-os/bottlerocket/pull/969\n[#970]: https://github.com/bottlerocket-os/bottlerocket/pull/970\n[#973]: https://github.com/bottlerocket-os/bottlerocket/pull/973\n[#977]: https://github.com/bottlerocket-os/bottlerocket/pull/977\n[#979]: https://github.com/bottlerocket-os/bottlerocket/pull/979\n[#980]: https://github.com/bottlerocket-os/bottlerocket/pull/980\n[#983]: https://github.com/bottlerocket-os/bottlerocket/pull/983\n[#986]: https://github.com/bottlerocket-os/bottlerocket/pull/986\n\n# v0.4.0 (2020-06-25)\n\n## Breaking changes\n\n* Remove all permissive types from the SELinux policy ([#945]). Actions that were not allowed by the SELinux policy now fail instead of only being logged.\n\n## OS changes\n\n* Use update repository metadata and signatures to run settings migrations ([#930])\n* Mount debugfs in superpowered host containers, such as the admin container, to support tools like `bcc` and `bpftrace` ([#934])\n* Protect container snapshot layers in SELinux policy ([#935])\n* Add `POST /actions/reboot` API path ([#936])\n* Update `tough` to v0.6.0 ([#944])\n* Fix behavior of `signpost cancel-upgrade` ([#950])\n* Update to kernel 5.4.46 ([#953])\n\n## Build changes\n\n* Canonicalize architecture names in amiize.sh ([#932])\n* Split build output directories by variant and architecture ([#948])\n* Move intermediate RPM output from `build/packages` to `build/rpms` ([#948])\n* Fix `chmod` usage for building on macOS ([#951])\n\n## Documentation changes\n\n* Document platform-specific settings in README.md ([#941])\n\n[#930]: https://github.com/bottlerocket-os/bottlerocket/pull/930\n[#932]: https://github.com/bottlerocket-os/bottlerocket/pull/932\n[#934]: https://github.com/bottlerocket-os/bottlerocket/pull/934\n[#935]: https://github.com/bottlerocket-os/bottlerocket/pull/935\n[#936]: https://github.com/bottlerocket-os/bottlerocket/pull/936\n[#941]: https://github.com/bottlerocket-os/bottlerocket/pull/941\n[#944]: https://github.com/bottlerocket-os/bottlerocket/pull/944\n[#945]: https://github.com/bottlerocket-os/bottlerocket/pull/945\n[#948]: https://github.com/bottlerocket-os/bottlerocket/pull/948\n[#950]: https://github.com/bottlerocket-os/bottlerocket/pull/950\n[#951]: https://github.com/bottlerocket-os/bottlerocket/pull/951\n[#953]: https://github.com/bottlerocket-os/bottlerocket/pull/953\n\n# v0.3.4 (2020-05-27)\n\n## OS changes\n\n* Add a new Kubernetes 1.16 variant ([#919])\n* Use SELinux to restrict datastore modifications ([#917])\n* Add variant override to updog arguments ([#923])\n\n## Build changes\n\n* Update systemd to v245 ([#916])\n* Update build SDK to v0.11.0 ([#926])\n* Allow specifying a start time for waves in updata ([#927])\n* Update `tough` dependencies to v0.5.0 ([#928])\n\n[#916]: https://github.com/bottlerocket-os/bottlerocket/pull/916\n[#917]: https://github.com/bottlerocket-os/bottlerocket/pull/917\n[#919]: https://github.com/bottlerocket-os/bottlerocket/pull/919\n[#923]: https://github.com/bottlerocket-os/bottlerocket/pull/923\n[#926]: https://github.com/bottlerocket-os/bottlerocket/pull/926\n[#927]: https://github.com/bottlerocket-os/bottlerocket/pull/927\n[#928]: https://github.com/bottlerocket-os/bottlerocket/pull/928\n\n# v0.3.3 (2020-05-14)\n\n## OS changes\n\n* Security: update kernel to 5.4.38 ([#924])\n\n[#924]: https://github.com/bottlerocket-os/bottlerocket/pull/924\n\n# v0.3.2 (2020-04-20)\n\nSpecial thanks to our first contributors, @inductor ([#853]), @smoser ([#871]), and @gliptak ([#870])!\n\n## OS changes\n\n* Update kernel to 5.4.20 ([#898])\n* Expand SELinux policy to include all classes and actions in 5.4 kernel ([#888])\n* Include error messages in apiserver error responses ([#897])\n* Add \"logdog\" to help users collect debug logs ([#880])\n* Include objtool in kernel-devel for compiling external modules ([#874])\n* Ignore termination signals in updog right before initiating reboot ([#869])\n* Pass `--containerd` flag to kubelet to specify containerd socket path, fixing some cAdvisor metrics ([#868])\n* Fix delay on reboot or power off ([#859])\n* Add `systemd.log_color=0` to remove ANSI color escapes from console log ([#836])\n* Reduce containerd logging when no errors have occurred ([#886])\n* Update admin container to v0.5.0 ([#903])\n\n## Build changes\n\n* Set up GitHub Actions to test OS builds for PRs ([#837])\n* Update SDK to v0.10.1 ([#866])\n* Move built RPMs to `build/packages` ([#863])\n* Bump cargo-make to 0.30.0 ([#870])\n* Pass proxy environment variables through to docker containers ([#871])\n* Add parse-datetime crate ([#875])\n* Update third-party software packages ([#895])\n* Update Rust dependencies ([#896])\n* Remove unused Rust dependencies ([#894])\n* Add upstream fix for arm64 in coreutils ([#879])\n* Add ability to add waves using TOML files ([#883])\n* Add default wave files ([#881])\n* Fix migrations builds ([#906])\n\n## Documentation changes\n\n* QUICKSTART: Clarify which setup is optional ([#902])\n* QUICKSTART: add easier setup instructions using new eksctl release ([#849])\n* QUICKSTART: add note about allowing SSH access ([#839])\n* QUICKSTART: add section on finding AMIs through SSM parameters ([#838])\n* QUICKSTART: Add supported region list ([73d120c9])\n* QUICKSTART: Add info about persistent volume CSI plugin ([#899])\n* QUICKSTART and README: Add appropriate ECR policy guidance ([#856])\n* README: Fix feedback link to point at existing section ([#833])\n* README: Add sentence about preview phase with feedback link ([#832])\n* README: Fixes and updates ([#831])\n* Update name of early-boot-config in API system diagram ([#840])\n* Fix updater README's reference to data store version ([#844])\n* Fix example wave files ([#908])\n\n[#831]: https://github.com/bottlerocket-os/bottlerocket/pull/831\n[#832]: https://github.com/bottlerocket-os/bottlerocket/pull/832\n[#833]: https://github.com/bottlerocket-os/bottlerocket/pull/833\n[#836]: https://github.com/bottlerocket-os/bottlerocket/pull/836\n[#837]: https://github.com/bottlerocket-os/bottlerocket/pull/837\n[#838]: https://github.com/bottlerocket-os/bottlerocket/pull/838\n[#839]: https://github.com/bottlerocket-os/bottlerocket/pull/839\n[#840]: https://github.com/bottlerocket-os/bottlerocket/pull/840\n[#844]: https://github.com/bottlerocket-os/bottlerocket/pull/844\n[#849]: https://github.com/bottlerocket-os/bottlerocket/pull/849\n[#853]: https://github.com/bottlerocket-os/bottlerocket/pull/853\n[#856]: https://github.com/bottlerocket-os/bottlerocket/pull/856\n[#859]: https://github.com/bottlerocket-os/bottlerocket/pull/859\n[#860]: https://github.com/bottlerocket-os/bottlerocket/pull/860\n[#863]: https://github.com/bottlerocket-os/bottlerocket/pull/863\n[#866]: https://github.com/bottlerocket-os/bottlerocket/pull/866\n[#868]: https://github.com/bottlerocket-os/bottlerocket/pull/868\n[#869]: https://github.com/bottlerocket-os/bottlerocket/pull/869\n[#870]: https://github.com/bottlerocket-os/bottlerocket/pull/870\n[#871]: https://github.com/bottlerocket-os/bottlerocket/pull/871\n[#874]: https://github.com/bottlerocket-os/bottlerocket/pull/874\n[#875]: https://github.com/bottlerocket-os/bottlerocket/pull/875\n[#879]: https://github.com/bottlerocket-os/bottlerocket/pull/879\n[#880]: https://github.com/bottlerocket-os/bottlerocket/pull/880\n[#881]: https://github.com/bottlerocket-os/bottlerocket/pull/881\n[#883]: https://github.com/bottlerocket-os/bottlerocket/pull/883\n[#886]: https://github.com/bottlerocket-os/bottlerocket/pull/886\n[#888]: https://github.com/bottlerocket-os/bottlerocket/pull/888\n[#894]: https://github.com/bottlerocket-os/bottlerocket/pull/894\n[#895]: https://github.com/bottlerocket-os/bottlerocket/pull/895\n[#896]: https://github.com/bottlerocket-os/bottlerocket/pull/896\n[#897]: https://github.com/bottlerocket-os/bottlerocket/pull/897\n[#898]: https://github.com/bottlerocket-os/bottlerocket/pull/898\n[#899]: https://github.com/bottlerocket-os/bottlerocket/pull/899\n[#902]: https://github.com/bottlerocket-os/bottlerocket/pull/902\n[#903]: https://github.com/bottlerocket-os/bottlerocket/pull/903\n[#906]: https://github.com/bottlerocket-os/bottlerocket/pull/906\n[#908]: https://github.com/bottlerocket-os/bottlerocket/pull/908\n[73d120c9]: https://github.com/bottlerocket-os/bottlerocket/commit/73d120c9\n\n# v0.3.1 (2020-03-10)\n\n## OS changes\n\n* Log migration errors to console ([#795])\n* Enable BTF debug info (`CONFIG_DEBUG_INFO_BTF`) ([#799])\n* Move migrations from private partition to data partition ([#818])\n* Add top-level model struct ([#824])\n* Update ca-certificates, cni-plugins, coreutils, dbus-broker, iproute, kmod, libcap, libxcrypt, ncurses, socat, and wicked ([#826])\n\n## Build changes\n\n* Update Rust dependencies ([#798], [#806], [#809], [#810])\n* Add additional cleanup steps to amiize.sh ([#804])\n* Work around warnings for unused licenses ([#827])\n\n## Documentation changes\n\n* Add [GLOSSARY.md](GLOSSARY.md), [SECURITY_FEATURES.md](SECURITY_FEATURES.md), and [SECURITY_GUIDANCE.md](SECURITY_GUIDANCE.md) ([#800], [#807], [#821])\n* Add additional information to top section of [README.md](README.md) ([#802])\n* Add license information to OpenAPI specification ([#803])\n* Add description of source mirroring ([#817])\n* Update [CHARTER.md](CHARTER.md) wording ([#823])\n\n[#795]: https://github.com/bottlerocket-os/bottlerocket/pull/795\n[#798]: https://github.com/bottlerocket-os/bottlerocket/pull/798\n[#799]: https://github.com/bottlerocket-os/bottlerocket/pull/799\n[#800]: https://github.com/bottlerocket-os/bottlerocket/pull/800\n[#802]: https://github.com/bottlerocket-os/bottlerocket/pull/802\n[#803]: https://github.com/bottlerocket-os/bottlerocket/pull/803\n[#804]: https://github.com/bottlerocket-os/bottlerocket/pull/804\n[#806]: https://github.com/bottlerocket-os/bottlerocket/pull/806\n[#807]: https://github.com/bottlerocket-os/bottlerocket/pull/807\n[#809]: https://github.com/bottlerocket-os/bottlerocket/pull/809\n[#810]: https://github.com/bottlerocket-os/bottlerocket/pull/810\n[#817]: https://github.com/bottlerocket-os/bottlerocket/pull/817\n[#818]: https://github.com/bottlerocket-os/bottlerocket/pull/818\n[#821]: https://github.com/bottlerocket-os/bottlerocket/pull/821\n[#823]: https://github.com/bottlerocket-os/bottlerocket/pull/823\n[#824]: https://github.com/bottlerocket-os/bottlerocket/pull/824\n[#826]: https://github.com/bottlerocket-os/bottlerocket/pull/826\n[#827]: https://github.com/bottlerocket-os/bottlerocket/pull/827\n\n# v0.3.0 (2020-02-27)\n\nWelcome to Bottlerocket!\nBottlerocket is the new name for the OS.\n\nIn preparation for public preview, v0.3.0 includes a number of breaking changes that mean upgrades from previous versions are not possible.\nThis is not done lightly, but had to be done to accommodate all we've learned during private preview.\n\n## Breaking Changes\n\n* Rename to Bottlerocket ([#722], [#740]).\n* Change partition labels to `BOTTLEROCKET-*` ([#726]).\n* Switch to new updates repository URIs under `updates.bottlerocket.aws` ([#778]).\n* Update Kubernetes to 1.15 ([#749]).\n* Rename aws-k8s variant to aws-k8s-1.15 to enable versioning ([#785]).\n* Update Linux kernel to 5.4.16-8.72.amzn2 ([#731]).\n* Rename `settings.target-base-url` to `settings.targets-base-url` ([#788]).\n\n## OS Changes\n\n* Mount kernel modules and development headers into containers from a squashfs file on the host ([#701]).\n* Include third-party licenses at `/usr/share/licenses` ([#723]).\n* Add initial implementation of SELinux ([#683], [#724]).\n* Support transactions in the API ([#715], [#727]).\n* Add support for platform-specific settings like AWS region ([#636]).\n* Support templated settings with new tool 'schnauzer' ([#637]).\n* Generate container image URIs with parameterized regions using schnauzer ([#638]).\n* Respect update release waves when using `updog check-updates` ([#615]).\n* Fix an issue with failed updates through certain https connections ([#730]).\n* Add support for EC2 IMDSv2 ([#705], [#706], [#709]).\n* Remove update-checking boot service ([#772]).\n* Remove old migrations and mitigations that no longer apply ([#774]).\n* Add /os API to expose variant, arch, version, etc. ([#777]).\n* Update host container packages ([#707]).\n* Allow removing settings in migrations ([#644]).\n* Create abstractions for creating common migrations ([#712], [#717]).\n* Remove the datastore version, instead use Bottlerocket version ([#760]).\n* Improve datastore migration naming convention and build migrations during cargo make ([#704], [#716]).\n* Update dependencies of third-party packages in base OS ([#691], [#696], [#698], [#699], [#700], [#708], [#728], [#786]).\n* Update dependencies of Rust packages ([#738], [#730]).\n* Rename `moondog` to `early-boot-config` ([#757]).\n* Update admin and control containers to v0.4.0 ([#789]).\n* Update container runtime socket path to more common `/run/dockershim.sock` ([#796])\n\n## Documentation\n\n* Add copyright statement and Bottlerocket license ([#746]).\n* General documentation improvements ([#681], [#693], [#736], [#761], [#762]).\n* Added READMEs for [packages](packages/) and [variants](variants/) ([#773]).\n* Split INSTALL guide into BUILDING and QUICKSTART ([#780]).\n* Update CNI plugin in documentation and conformance test scripts ([#739]).\n\n## Build Changes\n\n* General improvements to third-party license scanning ([#686], [#719], [#768]).\n* Add policycoreutils, secilc, and squashfs-tools to SDK ([#678], [#690]).\n* Update to Rust 1.41 and Go 1.13.8 ([#711], [#733]).\n* Disallow upstream source fallback by default ([#735]).\n* Move host, operator, and SDK containers to their own git repos ([#743], [#751], [#775]).\n  * [SDK Container](https://github.com/bottlerocket-os/bottlerocket-sdk)\n  * [Admin Container](https://github.com/bottlerocket-os/bottlerocket-admin-container)\n  * [Control Container](https://github.com/bottlerocket-os/bottlerocket-control-container)\n  * [Bottlerocket Update Operator](https://github.com/bottlerocket-os/bottlerocket-update-operator)\n* Improve the syntax of migrations listed in Release.toml ([#687]).\n* Add arm64 builds for host-containers ([#694]).\n* Build stable image paths using symlinks in `build/latest/` ([#767]).\n* Add a `set-migrations` subcommand to the `updata` tool ([#756]).\n* Remove `rpm_crashtraceback` tag from go builds ([#779]).\n* Rename built artifacts to specify variant before arch ([#776]).\n* Update SDK to v0.9.0 ([#790]).\n* Fix architecture conditional in glibc spec ([#787]).\n* Rename the `workspaces` directory to `sources` and the `workspaces` package to `os`. ([#770]).\n\n[#615]: https://github.com/bottlerocket-os/bottlerocket/pull/615\n[#636]: https://github.com/bottlerocket-os/bottlerocket/pull/636\n[#637]: https://github.com/bottlerocket-os/bottlerocket/pull/637\n[#638]: https://github.com/bottlerocket-os/bottlerocket/pull/638\n[#644]: https://github.com/bottlerocket-os/bottlerocket/pull/644\n[#678]: https://github.com/bottlerocket-os/bottlerocket/pull/678\n[#681]: https://github.com/bottlerocket-os/bottlerocket/pull/681\n[#683]: https://github.com/bottlerocket-os/bottlerocket/pull/683\n[#686]: https://github.com/bottlerocket-os/bottlerocket/pull/686\n[#687]: https://github.com/bottlerocket-os/bottlerocket/pull/687\n[#690]: https://github.com/bottlerocket-os/bottlerocket/pull/690\n[#691]: https://github.com/bottlerocket-os/bottlerocket/pull/691\n[#693]: https://github.com/bottlerocket-os/bottlerocket/pull/693\n[#694]: https://github.com/bottlerocket-os/bottlerocket/pull/694\n[#696]: https://github.com/bottlerocket-os/bottlerocket/pull/696\n[#698]: https://github.com/bottlerocket-os/bottlerocket/pull/698\n[#699]: https://github.com/bottlerocket-os/bottlerocket/pull/699\n[#700]: https://github.com/bottlerocket-os/bottlerocket/pull/700\n[#701]: https://github.com/bottlerocket-os/bottlerocket/pull/701\n[#704]: https://github.com/bottlerocket-os/bottlerocket/pull/704\n[#705]: https://github.com/bottlerocket-os/bottlerocket/pull/705\n[#706]: https://github.com/bottlerocket-os/bottlerocket/pull/706\n[#707]: https://github.com/bottlerocket-os/bottlerocket/pull/707\n[#708]: https://github.com/bottlerocket-os/bottlerocket/pull/708\n[#709]: https://github.com/bottlerocket-os/bottlerocket/pull/709\n[#711]: https://github.com/bottlerocket-os/bottlerocket/pull/711\n[#712]: https://github.com/bottlerocket-os/bottlerocket/pull/712\n[#715]: https://github.com/bottlerocket-os/bottlerocket/pull/715\n[#716]: https://github.com/bottlerocket-os/bottlerocket/pull/716\n[#717]: https://github.com/bottlerocket-os/bottlerocket/pull/717\n[#719]: https://github.com/bottlerocket-os/bottlerocket/pull/719\n[#722]: https://github.com/bottlerocket-os/bottlerocket/pull/722\n[#723]: https://github.com/bottlerocket-os/bottlerocket/pull/723\n[#724]: https://github.com/bottlerocket-os/bottlerocket/pull/724\n[#726]: https://github.com/bottlerocket-os/bottlerocket/pull/726\n[#727]: https://github.com/bottlerocket-os/bottlerocket/pull/727\n[#728]: https://github.com/bottlerocket-os/bottlerocket/pull/728\n[#730]: https://github.com/bottlerocket-os/bottlerocket/pull/730\n[#731]: https://github.com/bottlerocket-os/bottlerocket/pull/731\n[#733]: https://github.com/bottlerocket-os/bottlerocket/pull/733\n[#735]: https://github.com/bottlerocket-os/bottlerocket/pull/735\n[#736]: https://github.com/bottlerocket-os/bottlerocket/pull/736\n[#738]: https://github.com/bottlerocket-os/bottlerocket/pull/738\n[#739]: https://github.com/bottlerocket-os/bottlerocket/pull/739\n[#740]: https://github.com/bottlerocket-os/bottlerocket/pull/740\n[#743]: https://github.com/bottlerocket-os/bottlerocket/pull/743\n[#746]: https://github.com/bottlerocket-os/bottlerocket/pull/746\n[#749]: https://github.com/bottlerocket-os/bottlerocket/pull/749\n[#751]: https://github.com/bottlerocket-os/bottlerocket/pull/751\n[#756]: https://github.com/bottlerocket-os/bottlerocket/pull/756\n[#757]: https://github.com/bottlerocket-os/bottlerocket/pull/757\n[#758]: https://github.com/bottlerocket-os/bottlerocket/pull/758\n[#760]: https://github.com/bottlerocket-os/bottlerocket/pull/760\n[#761]: https://github.com/bottlerocket-os/bottlerocket/pull/761\n[#762]: https://github.com/bottlerocket-os/bottlerocket/pull/762\n[#767]: https://github.com/bottlerocket-os/bottlerocket/pull/767\n[#768]: https://github.com/bottlerocket-os/bottlerocket/pull/768\n[#770]: https://github.com/bottlerocket-os/bottlerocket/pull/770\n[#772]: https://github.com/bottlerocket-os/bottlerocket/pull/772\n[#773]: https://github.com/bottlerocket-os/bottlerocket/pull/773\n[#774]: https://github.com/bottlerocket-os/bottlerocket/pull/774\n[#775]: https://github.com/bottlerocket-os/bottlerocket/pull/775\n[#776]: https://github.com/bottlerocket-os/bottlerocket/pull/776\n[#777]: https://github.com/bottlerocket-os/bottlerocket/pull/777\n[#778]: https://github.com/bottlerocket-os/bottlerocket/pull/778\n[#779]: https://github.com/bottlerocket-os/bottlerocket/pull/779\n[#780]: https://github.com/bottlerocket-os/bottlerocket/pull/780\n[#782]: https://github.com/bottlerocket-os/bottlerocket/pull/782\n[#785]: https://github.com/bottlerocket-os/bottlerocket/pull/785\n[#786]: https://github.com/bottlerocket-os/bottlerocket/pull/786\n[#787]: https://github.com/bottlerocket-os/bottlerocket/pull/787\n[#788]: https://github.com/bottlerocket-os/bottlerocket/pull/788\n[#789]: https://github.com/bottlerocket-os/bottlerocket/pull/789\n[#790]: https://github.com/bottlerocket-os/bottlerocket/pull/790\n[#796]: https://github.com/bottlerocket-os/bottlerocket/pull/796\n\n# v0.2.1 (2020-01-20)\n\n## OS changes\n\n* Make `signpost` usage clearer to avoid updating into empty partition ([#444]).\n* Fix handling of wave bounds in `updog` that could result in seeing an update but not accepting it ([#539]).\n* Add support for query parameters in repo requests to allow for basic telemetry ([#542]).\n* Enable support for SELinux in OS packages (not yet enforcing) ([#579]).\n* Make grub reboot when config or kernel loading fails so it can try other partition sets ([#585]).\n* Add support for image \"variants\" with separate API models ([#578], [#588], [#589], [#591], [#597], [#613], [#625], [#626], [#627], [#653]).\n  The default variant is \"aws-k8s\" for Kubernetes usage, and an \"aws-dev\" variant can be built that has a local Docker daemon and debug tools.\n* Remove unused cri-tools package ([#602]).\n* Update Linux kernel to 4.19.75-28.73.amzn2 ([#622]).\n* Make containerd.service stop containerd-shims to fix shutdown/reboot delay ([#652]).\n* Ensure `updog` only removes known extensions from migration filenames ([#662]).\n* Add OS version to \"pretty name\" so it's visible in console log ([#663]).\n\n## Documentation changes\n\n* Reorganize \"getting started\" documentation for clarity ([#581]).\n* Fix formatting of kube-proxy options in install guide ([#584]).\n* Specify compatible cargo-deny version in install guide ([#631]).\n* Fix typos and improve clarity of install guide ([#639]).\n\n## Build changes\n\n* Add scripts to ease Kubernetes conformance testing through Sonobuoy ([#530]).\n* Add release metadata file to be used in future automation ([#556], [#594]).\n* Update dependencies of third-party packages in base OS ([#595]).\n* Update dependencies of Rust packages ([#598]).\n* Update SDK container to include Rust 1.40.0, GCC 9.2, and other small fixes ([#603], [#628]).\n* Fix aarch64 build failure for libcap ([#621]).\n* Add initial container definitions and scripts for CI process ([#619], [#624], [#633], [#646], [#647], [#651], [#654], [#658]).\n\n[#444]: ../../pull/444\n[#530]: ../../pull/530\n[#539]: ../../pull/539\n[#542]: ../../pull/542\n[#556]: ../../pull/556\n[#578]: ../../pull/578\n[#579]: ../../pull/579\n[#581]: ../../pull/581\n[#584]: ../../pull/584\n[#585]: ../../pull/585\n[#588]: ../../pull/588\n[#589]: ../../pull/589\n[#591]: ../../pull/591\n[#594]: ../../pull/594\n[#595]: ../../pull/595\n[#597]: ../../pull/597\n[#598]: ../../pull/598\n[#602]: ../../pull/602\n[#603]: ../../pull/603\n[#613]: ../../pull/613\n[#619]: ../../pull/619\n[#621]: ../../pull/621\n[#622]: ../../pull/622\n[#624]: ../../pull/624\n[#625]: ../../pull/625\n[#626]: ../../pull/626\n[#627]: ../../pull/627\n[#628]: ../../pull/628\n[#631]: ../../pull/631\n[#633]: ../../pull/633\n[#639]: ../../pull/639\n[#646]: ../../pull/646\n[#647]: ../../pull/647\n[#651]: ../../pull/651\n[#652]: ../../pull/652\n[#653]: ../../pull/653\n[#654]: ../../pull/654\n[#658]: ../../pull/658\n[#662]: ../../pull/662\n[#663]: ../../pull/663\n\n# v0.2.0 (2019-12-09)\n\n## Breaking changes\n\n* Several settings now have added validation for their contents.  Upgrades from v0.1 that use invalid settings values will result in a broken system.\n  * Host container names (e.g. `admin` in `settings.host-containers.admin`) are restricted to ASCII alphanumeric characters and hyphens ([#450]).\n  * `settings.kubernetes.api-server`, `settings.updates.metadata-base-url` and `target-base-url`, `settings.host-containers.*.sources`, and `settings.ntp.time-servers` are now validated to be URIs ([#549]).\n  * `settings.kubernetes.cluster_name`, `settings.kubernetes.node-labels`, and `settings.kubernetes.node-taints` are now verified to fit Kubernetes naming conventions ([#549]).\n  * Most settings values disallow multi-line strings ([#453], [#483]).\n* Additional characters are permitted in API keys; for example, dots and slashes in Kubernetes labels. Downgrades from v0.2 that use dots and slashes in API keys will result in a broken system ([#511]).\n\n## OS changes\n\n* Add `dogswatch`, a Kubernetes operator for managing OS upgrades ([#239]).\n* More accurately represent data type of update seed ([#430]).\n* Retry host container pulls with exponential backoff ([#433]).\n* Better model startup dependencies in systemd units ([#442]).\n* Enable panic on disk corruption detected with dm_verity ([#445]).\n* Add persistent storage for host containers, mapped to `/.bottlerocket/host-containers/[CONTAINER_NAME]` ([#450], [#555]).\n* Persist SSH host keys for admin container ([#450]).\n* Use admin container v0.2 by default ([#450], [#536]).\n* Use control container v0.2 by default ([#472], [#536]).\n* Print most critical errors to the console to aid debugging ([#476], [#479], [#546]).\n* Update Linux kernel to 4.19.75-27.58.amzn2 ([#478]).\n* Updated partitions are marked `successful` after services start ([#481]).\n* Kernel config is available at `/proc/config.gz` ([#482]).\n* Prepare `tough` for separate release, including:\n  * Allow library consumers to override the transport mechanism ([#488]).\n  * Merge `tough_schema` back into `tough` ([#496]).\n  * Add locking around tough datastore write operations ([#497]).\n* Simplify representation of default metadata ([#491]).\n* `apiclient` (available via the host containers) exits non-zero on HTTP response errors ([#498]).\n* `apiclient` builds as a static binary ([#552]).\n* `/proc/kheaders.tar.xz` is enabled in the kernel ([#557]).\n* `settings-committer` no longer errors at boot when there are no changes to commit ([#559]).\n* `migrator` and `updog` set migrations executable before running to work around a v0.1.6 bug ([#561], [#567]).\n\n## Documentation changes\n\n* Document how to use Bottlerocket's default for the `nf_conntrack_max` kernel parameter when using `kube-proxy` ([#391]).\n* Fix example user data for enabling admin container ([#448]).\n* Update build documentation for using Docker instead of `buildkitd` ([#506]).\n* Update recommended CNI plugin version ([#507]).\n* Document `settings.ntp.time-servers` ([#550]).\n* Update INSTALL.md to use the instance role created by `eksctl` instead of creating a new one ([#569]).\n\n## Build changes\n\n* Add `updata` tool, which builds update repository metadata ([#265]).\n* Create versioned symlinks to output images ([#434]).\n* Add code and CloudFormation template for TUF repository canary ([#490]).\n* Move the TUF client library, `tough`, to [its own repository](https://github.com/awslabs/tough) and [crates.io packages](https://crates.io/crates/tough) ([#499]).\n* Remove build dependency on the BuildKit daemon ([#506]).\n* Switch to SDK container as toolchain for builds, rather than requiring local build of toolchain ([#525]).\n* Turn `buildsys` into a binary and remove the `cascade` feature ([#562]).\n\n[#239]: ../../pull/239\n[#265]: ../../pull/265\n[#391]: ../../pull/391\n[#430]: ../../pull/430\n[#433]: ../../pull/433\n[#434]: ../../pull/434\n[#442]: ../../pull/442\n[#445]: ../../pull/445\n[#448]: ../../pull/448\n[#450]: ../../pull/450\n[#453]: ../../pull/453\n[#472]: ../../pull/472\n[#476]: ../../pull/476\n[#478]: ../../pull/478\n[#479]: ../../pull/479\n[#481]: ../../pull/481\n[#482]: ../../pull/482\n[#483]: ../../pull/483\n[#488]: ../../pull/488\n[#490]: ../../pull/490\n[#491]: ../../pull/491\n[#496]: ../../pull/496\n[#497]: ../../pull/497\n[#498]: ../../pull/498\n[#499]: ../../pull/499\n[#506]: ../../pull/506\n[#507]: ../../pull/507\n[#511]: ../../pull/511\n[#525]: ../../pull/525\n[#536]: ../../pull/536\n[#546]: ../../pull/546\n[#549]: ../../pull/549\n[#550]: ../../pull/550\n[#552]: ../../pull/552\n[#555]: ../../pull/555\n[#557]: ../../pull/557\n[#559]: ../../pull/559\n[#561]: ../../pull/561\n[#562]: ../../pull/562\n[#567]: ../../pull/567\n[#569]: ../../pull/569\n\n# v0.1.6 (2019-10-21)\n\n## OS changes\n\n* The system fetches the pause container from ECR before starting `kubelet` ([#382]).\n* New settings: `settings.kubernetes.node-labels` and `settings.kubernetes.node-taints` ([#390], [#408]).\n* The control container has an `enable-admin-container` helper ([#405], [#413]). Made default in v0.2.0 ([#472]).\n* Rust dependencies updated ([#410]).\n* `thar-be-settings` added trace-level messages in the client module ([#411]).\n* `updog` no longer checks for migrations from new root images ([#416]).\n* `pluto` was cleaned up to create an HTTP connection more consistently ([#419]).\n* Settings that are usually generated may have defaults, and `settings.kubernetes.max-pods` defaults to `110` if the EC2 instance type cannot be determined ([#420]).\n* The admin container MOTD is clearer about where the host's filesystem is mounted ([#424]).\n* `block-party` (used in `growpart` and `signpost`) errors are better structured ([#425]).\n* `thar-be-settings` logs render errors when running in `--all` mode ([#427]).\n* [Recommended `sysctl` settings from the Kernel Self Protection Project](https://kernsec.org/wiki/index.php/Kernel_Self_Protection_Project/Recommended_Settings#sysctls) are now used ([#435]).\n* `acpid` is enabled by default to handle power button signals sent by EC2 on stop/restart/terminate events ([#437]).\n* `host-ctr` correctly fetches images from non-ECR registries ([#439]; this regression occurred after v0.1.5).\n\n## Build changes\n\n* amiize uses a short connection timeout when testing SSH connectivity ([#409]).\n* `tuftool` only downloads an arbitrary `root.json` with `--allow-root-download` ([#421]).\n* BuildKit updated to v0.6.2 ([#423], [#429]).\n* First-party Rust code is built in the same `rpmbuild` invocation to improve build times ([#428]).\n* `tuftool` correctly uses the `--timestamp-{version,expires}` arguments instead of the `--snapshot-{version,expires}` arguments in the timestamp role ([#438]).\n* `tuftool` accepts relative dates ([#438]).\n\n## Documentation changes\n\n* The `sources/updater` crates are better documented ([#381]).\n* INSTALL.md's subnet selection documentation is improved ([#422]).\n\n[#381]: ../../pull/381\n[#382]: ../../pull/382\n[#390]: ../../pull/390\n[#405]: ../../pull/405\n[#408]: ../../pull/408\n[#409]: ../../pull/409\n[#410]: ../../pull/410\n[#411]: ../../pull/411\n[#413]: ../../pull/413\n[#416]: ../../pull/416\n[#419]: ../../pull/419\n[#420]: ../../pull/420\n[#421]: ../../pull/421\n[#422]: ../../pull/422\n[#423]: ../../pull/423\n[#424]: ../../pull/424\n[#425]: ../../pull/425\n[#427]: ../../pull/427\n[#428]: ../../pull/428\n[#429]: ../../pull/429\n[#435]: ../../pull/435\n[#437]: ../../pull/437\n[#438]: ../../pull/438\n[#439]: ../../pull/439\n"
  },
  {
    "path": "CHARTER.md",
    "content": "# Bottlerocket Charter\n\n## Tenets (unless you know better ones)\n\nThese tenets guide Bottlerocket's development.\nThey let you know what we value and what we're working toward, even if not every feature is ready yet.\n\n### Secure\n\nBottlerocket is **secure** so it can become a quiet piece of a platform you trust.\nIt uses a variety of mechanisms to provide defense-in-depth, and enables automatic updates by default.\nIt protects itself from persistent threats.\nIt enables kernel features that allow users to assert their own policies for locking down workloads.\n\n### Open\n\nBottlerocket is **open** because the best OS can only be built through collaboration.\nIt is developed in full view of the world using open source tools and public infrastructure services.\nIt is not a Kubernetes distro, nor an Amazon distro.\nWe obsess over shared components like the kernel, and work within the community to support new orchestrators and platforms.\n\n### Small\n\nBottlerocket is **small** because a few big ideas scale better than many small ones.\nIt includes only the core set of components needed for development and for use at runtime.\nAnything we ship, we must be prepared to fix, so our goal is to ship as little as possible while staying useful.\n\n### Simple\n\nBottlerocket is **simple** because simple lasts.\nUsers can pick the image they want, tweak a handful of settings, and then forget about it.\nWe favor settings that convey high-level intent over those that provide low-level control over specific details, because it is easier to preserve intent across months and years of automatic updates.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "## Code of Conduct\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).\nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact\nopensource-codeofconduct@amazon.com with any additional questions or comments.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nThank you for your interest in contributing to our project.\nWhether it's a bug report, new feature, correction, or additional documentation, we greatly value feedback and contributions from our community.\n\nPlease read through this document before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution.\n\n\n## Reporting Bugs/Feature Requests\n\nWe welcome you to use the GitHub issue tracker to report bugs or suggest features.\n\nWhen filing an issue, please check [existing open](https://github.com/bottlerocket-os/bottlerocket/issues) and [closed](https://github.com/bottlerocket-os/bottlerocket/issues?q=is%3Aissue+is%3Aclosed) issues to make sure somebody else hasn't already reported the issue.\nPlease try to include as much information as you can.\nDetails like these are incredibly useful:\n\n* A reproducible test case or series of steps\n* The version of our code being used\n* Any modifications you've made relevant to the bug\n* Anything unusual about your environment or deployment\n\n\n## Contributing via Pull Requests\nContributions via pull requests are much appreciated.\nBefore starting a pull request, please ensure that:\n\n1. You open an issue first to discuss any significant work - we would hate for your time to be wasted.\n2. You are working against the latest source on the *develop* branch.\n3. You check existing [open](https://github.com/bottlerocket-os/bottlerocket/pulls) and [merged](https://github.com/bottlerocket-os/bottlerocket/pulls?q=is%3Apr+is%3Aclosed) pull requests to make sure someone else hasn't addressed the problem already.\n\nTo send us a pull request, please:\n\n1. Fork the repository.\n2. Modify the source; please focus on the specific change you are contributing. If you also reformat the code, it will be hard for us to focus on your change.\n3. Ensure local tests pass.\n4. Commit to your fork using clear commit messages.\n5. Send us a pull request, answering any default questions in the pull request interface.\n6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.\n\nGitHub provides additional documentation on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).\n\n## Repo branch and tag structure\n\nActive development occurs under the `develop` branch.\n\nBottlerocket uses both tags and branches for release alignment. Numbered releases are always associated with [tags that mirror the full SemVer 3-digit version number](https://github.com/bottlerocket-os/bottlerocket/tags) (e.g. `1.7.2`). [Branches are for patching only](https://github.com/bottlerocket-os/bottlerocket/branches/all): if a patch is required, a branch will be cut for that minor release line (e.g. `1.7.x`). As a consequence, some previous minor versions may not have a branch if they never required a subsequent patch.\n\n## Filename case conventions\n\nBottlerocket follows a few basic filename case conventions:\n\n- All extensions are lowercase,\n- Build related configuration files always start with a capital letter (e.g. `Infra.toml`, `Release.toml`),\n- All caps is used for documents and licenses (e.g. `PUBLISHING.md`, `TRADEMARKS.md`),\n- All lower case is used for all other files (e.g. `sample-eksctl.yaml`, `main.rs`).\n\n\n## Finding contributions to work on\nLooking at the existing issues is a great way to find something to contribute on.\nAs this repository uses GitHub issue [labels](https://github.com/bottlerocket-os/bottlerocket/labels), looking through issues labeled ['good first issue'](https://github.com/bottlerocket-os/bottlerocket/labels/good%20first%20issue) or ['help wanted'](https://github.com/bottlerocket-os/bottlerocket/labels/help%20wanted) is a great place to start.\n\n\n## Code of Conduct\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).\nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact opensource-codeofconduct@amazon.com with any additional questions or comments.\n\n\n## Security issue notifications\nIf you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/).\nPlease do **not** create a public GitHub issue.\n\n\n## Licensing\n\nSee the [COPYRIGHT](COPYRIGHT) file for our project's licensing.\nWe will ask you to confirm the licensing of your contribution.\n"
  },
  {
    "path": "COPYRIGHT",
    "content": "Copyright Amazon.com, Inc., its affiliates, or other contributors. All Rights Reserved.\n\nExcept as otherwise noted (below and/or in individual files), Bottlerocket is dual-licensed under\nthe Apache License, version 2.0 <LICENSE-APACHE> or the MIT license <LICENSE-MIT>, at your option.\n\nCopyrights in Bottlerocket are retained by their contributors. No copyright assignment is required\nto contribute to Bottlerocket. Contributions to Bottlerocket are explicitly made under both the\nApache License, version 2.0, and the MIT license. For full authorship information, see the version\ncontrol history.\n\nBottlerocket operating system images include packages written by third parties, which may carry\ntheir own copyright notices and license terms. These are available in /usr/share/licenses on the\noperating system images.\n\n=^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\nContains modified hyper-proxy files [mod.rs, stream.rs, tunnel.rs] from\nhttps://github.com/tafia/hyper-proxy 2021-09-20.\nCopyright (c) 2017 Johann Tuffe. Licensed under the MIT License.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nresolver = \"1\"\nmembers = [\n    \"packages/settings-defaults\",\n    \"packages/settings-plugins\",\n\n    \"variants/aws-dev\",\n    \"variants/aws-ecs-2\",\n    \"variants/aws-ecs-2-fips\",\n    \"variants/aws-ecs-2-nvidia\",\n    \"variants/aws-ecs-2-nvidia-fips\",\n    \"variants/aws-ecs-3\",\n    \"variants/aws-ecs-3-fips\",\n    \"variants/aws-ecs-3-nvidia\",\n    \"variants/aws-ecs-3-nvidia-fips\",\n    \"variants/aws-k8s-1.29\",\n    \"variants/aws-k8s-1.29-fips\",\n    \"variants/aws-k8s-1.30\",\n    \"variants/aws-k8s-1.30-fips\",\n    \"variants/aws-k8s-1.31\",\n    \"variants/aws-k8s-1.31-fips\",\n    \"variants/aws-k8s-1.32\",\n    \"variants/aws-k8s-1.32-fips\",\n    \"variants/aws-k8s-1.33\",\n    \"variants/aws-k8s-1.33-fips\",\n    \"variants/aws-k8s-1.34\",\n    \"variants/aws-k8s-1.34-fips\",\n    \"variants/aws-k8s-1.35\",\n    \"variants/aws-k8s-1.35-fips\",\n    \"variants/aws-k8s-1.29-nvidia\",\n    \"variants/aws-k8s-1.29-nvidia-fips\",\n    \"variants/aws-k8s-1.30-nvidia\",\n    \"variants/aws-k8s-1.30-nvidia-fips\",\n    \"variants/aws-k8s-1.31-nvidia\",\n    \"variants/aws-k8s-1.31-nvidia-fips\",\n    \"variants/aws-k8s-1.32-nvidia\",\n    \"variants/aws-k8s-1.32-nvidia-fips\",\n    \"variants/aws-k8s-1.33-nvidia\",\n    \"variants/aws-k8s-1.33-nvidia-fips\",\n    \"variants/aws-k8s-1.34-nvidia\",\n    \"variants/aws-k8s-1.34-nvidia-fips\",\n    \"variants/aws-k8s-1.35-nvidia\",\n    \"variants/aws-k8s-1.35-nvidia-fips\",\n    \"variants/metal-dev\",\n    \"variants/vmware-dev\",\n    \"variants/vmware-k8s-1.29\",\n    \"variants/vmware-k8s-1.29-fips\",\n    \"variants/vmware-k8s-1.30\",\n    \"variants/vmware-k8s-1.30-fips\",\n    \"variants/vmware-k8s-1.31\",\n    \"variants/vmware-k8s-1.31-fips\",\n    \"variants/vmware-k8s-1.32\",\n    \"variants/vmware-k8s-1.32-fips\",\n    \"variants/vmware-k8s-1.33\",\n    \"variants/vmware-k8s-1.33-fips\",\n    \"variants/vmware-k8s-1.34\",\n    \"variants/vmware-k8s-1.34-fips\",\n    \"variants/vmware-k8s-1.35\",\n    \"variants/vmware-k8s-1.35-fips\",\n]\n\n[profile.dev]\ndebug = false\nopt-level = 'z'\n\n[profile.dev.build-override]\nopt-level = 'z'\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "MIT License\nCopyright Amazon.com, Inc., its affiliates, or other contributors. All Rights Reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including  without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to  the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN  NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile.toml",
    "content": "[config]\nskip_core_tasks = true\ndefault_to_workspace = false\n\n[env]\nBUILDSYS_ROOT_DIR = \"${CARGO_MAKE_WORKING_DIRECTORY}\"\n\n# For binary installation, this should be a released version (prefixed with a v,\n# for example v0.1.0). For the git sourcecode installation method, this can be\n# any git rev, e.g. a tag, sha, or branch name.\nTWOLITER_VERSION = \"v0.17.0\"\nTWOLITER_SHA256_AARCH64 = \"474b6dce0ddd993e926065baee55c8a06167615cb2c0513c2c9f4f02876a7011\"\nTWOLITER_SHA256_X86_64 = \"f7239b329ae71f75e5f3262e6b83c0a96bf36bfed1dda225fc3998316b5a92d9\"\n\n# For binary installation, this is the GitHub repository that has binary release artifacts attached\n# to it, for example https://github.com/bottlerocket-os/twoliter. For git sourcecode installation,\n# this is any URI that can be used in a git clone command.\nTWOLITER_REPO = \"https://github.com/bottlerocket-os/twoliter\"\n\n# Skip installing Twoliter if it is already installed and its version\n# matches the requested version.\nTWOLITER_REUSE_EXISTING_INSTALL=\"true\"\n\n# Allow Twoliter to be installed from a binary distribution if binaries are expected to exist for\n# the host OS and architecture.\nTWOLITER_ALLOW_BINARY_INSTALL=\"true\"\n\n# Allow Twoliter to be installed by building from sourcecode.\nTWOLITER_ALLOW_SOURCE_INSTALL=\"true\"\n\n# If you know the version string returned by Twoliter will not match TWOLITER_VERSION (e.g. when you\n# are testing changes to Twoliter itself), set this to true to prevent re-installation.\nTWOLITER_SKIP_VERSION_CHECK=\"false\"\n\n# Where Twoliter will be installed.\nTWOLITER_INSTALL_DIR = \"${BUILDSYS_ROOT_DIR}/tools/twoliter\"\n\n# The logging verbosity for Twoliter: error, warn, info, debug, trace\nTWOLITER_LOG_LEVEL = \"info\"\n\n# The project file that configures Twoliter.\nTWOLITER_PROJECT = \"${BUILDSYS_ROOT_DIR}/Twoliter.toml\"\n\nUNAME_ARCH = { script = ['uname -m'] }\nBUILDSYS_ARCH = { script = ['echo \"${BUILDSYS_ARCH:-${UNAME_ARCH}}\"'] }\nBUILDSYS_BUILD_DIR = \"${BUILDSYS_ROOT_DIR}/build\"\nBUILDSYS_PACKAGES_DIR = \"${BUILDSYS_BUILD_DIR}/rpms\"\nBUILDSYS_STATE_DIR = \"${BUILDSYS_BUILD_DIR}/state\"\nBUILDSYS_IMAGES_DIR = \"${BUILDSYS_BUILD_DIR}/images\"\nBUILDSYS_TOOLS_DIR = \"${BUILDSYS_ROOT_DIR}/tools\"\nBUILDSYS_SOURCES_DIR = \"${BUILDSYS_ROOT_DIR}/sources\"\nBUILDSYS_SBKEYS_DIR = \"${BUILDSYS_ROOT_DIR}/sbkeys\"\nBUILDSYS_SBKEYS_PROFILE = { script = ['echo \"${BUILDSYS_SBKEYS_PROFILE:-local}\"'] }\nBUILDSYS_TIMESTAMP = { script = [\"date +%s\"] }\nBUILDSYS_VERSION_BUILD = { script = [\"git describe --always --dirty --exclude '*' || echo 00000000\"] }\n# For now, release config path can't be overridden with -e, because it's used\n# later in this section.  You have to edit the path here in Makefile.toml to\n# use a different Release.toml.\nBUILDSYS_RELEASE_CONFIG_PATH = \"${BUILDSYS_ROOT_DIR}/Release.toml\"\nBUILDSYS_VERSION_IMAGE = { script = [\"awk -F '[ =\\\"]+' '$1 == \\\"version\\\" {print $2}' ${BUILDSYS_RELEASE_CONFIG_PATH}\"] }\n# This can be overridden with -e to build a different variant from the variants/ directory\nBUILDSYS_VARIANT = { script = ['echo \"${BUILDSYS_VARIANT:-aws-k8s-1.32}\"'] }\n# Product name used for file and directory naming\nBUILDSYS_NAME = \"bottlerocket\"\n# \"Pretty\" name used to identify OS in os-release, bootloader, etc.\n# If you're building a Bottlerocket remix, you'd want to set this to something like\n# \"Bottlerocket Remix by ${CORP}\" or \"${CORP}'s Bottlerocket Remix\"\nBUILDSYS_PRETTY_NAME = \"Bottlerocket OS\"\n\n# These can be overridden with -e to change configuration for pubsys (`cargo\n# make repo`).  In addition, you can set RELEASE_START_TIME to determine when\n# update waves and repo metadata expiration times will start, instead of\n# starting now.  (This can be an RFC3339 date, or an offset like \"in X\n# hours/days/weeks\".)\nPUBLISH_EXPIRATION_POLICY_PATH = \"${BUILDSYS_ROOT_DIR}/tools/pubsys/policies/repo-expiration/2w-2w-1w.toml\"\nPUBLISH_WAVE_POLICY_PATH = \"${BUILDSYS_BUILD_DIR}/tools/waves/default-waves.toml\"\nPUBLISH_INFRA_CONFIG_PATH = \"${BUILDSYS_ROOT_DIR}/Infra.toml\"\n# Default repo to read from PUBLISH_INFRA_CONFIG_PATH\nPUBLISH_REPO = \"default\"\n# The version of tuftool (without the 'v') that we will install and use for\n# publishing-related steps\nPUBLISH_TUFTOOL_VERSION=\"0.10.0\"\n\n# This can be overridden with -e to change the path to the file containing SSM\n# parameter templates.  This file determines the parameter names and values\n# that will be published to SSM when you run `cargo make ssm`.  See\n# tools/pubsys/policies/ssm/README.md for more information.\nPUBLISH_SSM_TEMPLATES_PATH = \"${BUILDSYS_ROOT_DIR}/tools/pubsys/policies/ssm/defaults.toml\"\n\n# This can be overridden with -e to change the source path\n# for the Licenses.toml file\nBUILDSYS_LICENSES_CONFIG_PATH = \"${BUILDSYS_ROOT_DIR}/Licenses.toml\"\n\n# Specifies whether to validate all targets when validating TUF repositories\nREPO_VALIDATE_TARGETS = \"true\"\n# Specifies the timeframe to look for upcoming repository metadata expirations\nREPO_METADATA_EXPIRING_WITHIN = \"3 days\"\n# When refreshing repositories, you can set REPO_UNSAFE_REFRESH=true to refresh repositories that have expired metadata files.\n\n# You can also set PUBLISH_REGIONS to override the list of regions from\n# Infra.toml for AMI and SSM commands; it's a comma-separated list like\n# \"us-west-2,us-east-1\".\n# You can set NO_PROGRESS=true to not print progress bars during snapshot upload.\n# You can use ALLOW_CLOBBER=true with the `ssm` task to make it overwrite existing values.\n# (This is not required with `promote-ssm` because the intent of promotion is overwriting.)\n\n# This can be overridden to provide a custom import spec for a VMware OVA.\n# Using configuration from Infra.toml, we substitute the correct value for\n# network, and whether or not to mark a VM as a template\nVMWARE_IMPORT_SPEC_PATH = \"${BUILDSYS_ROOT_DIR}/tools/pubsys/support/vmware/import_spec.template\"\n\n# You can set VMWARE_DATACENTERS to override the list of datacenters from\n# Infra.toml for VMware commands; it's a comma-separated list like\n# \"datacenter1,datacenter2\"\n\n# Disallow pulling directly Upstream URLs when lookaside cache results in MISSes as a fallback.\n# To use the upstream source as fallback, override this on the command line and set it to 'true'\nBUILDSYS_UPSTREAM_SOURCE_FALLBACK = \"false\"\n\n# We require license checks to pass to build an image.  If you're working on a\n# local change and don't have license information yet, you can run with `-e\n# BUILDSYS_ALLOW_FAILED_LICENSE_CHECK=true` to allow the build to continue even\n# if the license check fails.\nBUILDSYS_ALLOW_FAILED_LICENSE_CHECK = \"false\"\n\n# Disallow pulling licenses from Upstream URLs. To fetch licenses from the upstream source,\n# override this on the command line and set it to 'true'\nBUILDSYS_UPSTREAM_LICENSE_FETCH= \"false\"\n\n# This controls how many `docker build` commands we'll invoke at once.\nBUILDSYS_JOBS = \"8\"\n\nCARGO_HOME = \"${BUILDSYS_ROOT_DIR}/.cargo\"\n# This needs to end with pkg/mod so that we can mount the parent of pkg/mod as GOPATH.\nGO_MOD_CACHE = \"${BUILDSYS_ROOT_DIR}/.gomodcache/pkg/mod\"\nGO_MODULES = \"\"\nDOCKER_BUILDKIT = \"1\"\n\n# This is the filename suffix for operations that write out AMI information to\n# file.  It can be overridden with -e in situations where a user is using\n# multiple `Infra.toml` files for publishing to different places, and wants to\n# write AMI information to specifically named files.\nAMI_DATA_FILE_SUFFIX = \"amis.json\"\n\n# This is the filename suffix for operations that write out SSM parameter information\n# to file. It can be overridden with -e.\nSSM_DATA_FILE_SUFFIX = \"ssm-params.json\"\n\n# The type of testsys test that should be run.\n# `quick` will run a quick test which usually tests that the instances are reachable.\n# `conformance` will run a certified conformance test, these tests may take up to 3 hrs.\n# `migration` will run an upgrade downgrade test including:\n#    1: an initial `quick` test\n#    2: a migration from TESTSYS_STARTING_VERSION to BUILDSYS_FULL_VERSION\n#    3: a `quick` test on the migrated instances\n#    4: a migration from BUILDSYS_FULL_VERSION back to TESTSYS_STARTING_VERSION\n#    5: a final `quick` test on the downgraded instances\n# TESTSYS_STARTING_IMAGE_ID can be used to provide the correct starting image for migration tests.\nTESTSYS_TEST = \"quick\"\n# The default path to the testsys cluster's kubeconfig file. This is used for all testsys calls.\nCARGO_MAKE_DEFAULT_TESTSYS_KUBECONFIG_PATH = \"${BUILDSYS_ROOT_DIR}/testsys.kubeconfig\"\n# The last released version of bottlerocket.\nTESTSYS_STARTING_VERSION = { script = [\"git tag --list --sort=version:refname 'v*' | tail -1\"] }\n# The commit for the last release of bottlerocket.\nTESTSYS_STARTING_COMMIT = { script = [\"git describe --tag ${TESTSYS_STARTING_VERSION} --always --exclude '*' || echo 00000000\"] }\nTESTSYS_TESTS_DIR = \"${BUILDSYS_ROOT_DIR}/tests\"\nTESTSYS_TEST_CONFIG_PATH = \"${BUILDSYS_ROOT_DIR}/Test.toml\"\n\n[env.development]\n# Certain variables are defined here to allow us to override a component value\n# on the command line.\n\nTWOLITER = \"${TWOLITER_INSTALL_DIR}/twoliter\"\n\n# Depends on ${BUILDSYS_JOBS}.\nCARGO_MAKE_CARGO_LIMIT_JOBS = \"--jobs ${BUILDSYS_JOBS}\"\nCARGO_MAKE_CARGO_ARGS = \"--offline --locked\"\n\n# Depends on ${BUILDSYS_ARCH} and ${BUILDSYS_VARIANT}.\nBUILDSYS_OUTPUT_DIR = \"${BUILDSYS_IMAGES_DIR}/${BUILDSYS_ARCH}-${BUILDSYS_VARIANT}\"\n\n# Depends on a number of variables defined above, and each other.\nBUILDSYS_VERSION_FULL=\"${BUILDSYS_VERSION_IMAGE}-${BUILDSYS_VERSION_BUILD}\"\n# These names are used as prefixes for build and repo steps.\nBUILDSYS_NAME_VARIANT=\"${BUILDSYS_NAME}-${BUILDSYS_VARIANT}-${BUILDSYS_ARCH}\"\nBUILDSYS_NAME_VERSION=\"${BUILDSYS_NAME}-${BUILDSYS_VERSION_FULL}\"\nBUILDSYS_NAME_FULL=\"${BUILDSYS_NAME_VARIANT}-${BUILDSYS_VERSION_FULL}\"\n# This name does not include the build short SHA\nBUILDSYS_NAME_FRIENDLY = \"${BUILDSYS_NAME_VARIANT}-v${BUILDSYS_VERSION_IMAGE}\"\n\n# For variant build artifacts.\nBUILDSYS_VARIANT_DIR = \"${BUILDSYS_OUTPUT_DIR}/${BUILDSYS_VERSION_FULL}\"\n\n# Depends on ${BUILDSYS_SBKEYS_DIR} and ${BUILDSYS_SBKEYS_PROFILE}.\nBUILDSYS_SBKEYS_PROFILE_DIR = \"${BUILDSYS_SBKEYS_DIR}/${BUILDSYS_SBKEYS_PROFILE}\"\n\n# Path to repo-specific root role.\nPUBLISH_REPO_ROOT_JSON = \"${BUILDSYS_ROOT_DIR}/roles/${PUBLISH_REPO}.root.json\"\n# If you don't specify a signing key in Infra.toml, we generate one at this path.\nPUBLISH_REPO_KEY = \"${BUILDSYS_ROOT_DIR}/keys/${PUBLISH_REPO}.pem\"\n# Repo directories have subdirectories for variant/arch, so we only want version here.\nPUBLISH_REPO_BASE_DIR = \"${BUILDSYS_BUILD_DIR}/repos\"\nPUBLISH_REPO_OUTPUT_DIR = \"${PUBLISH_REPO_BASE_DIR}/${PUBLISH_REPO}/${BUILDSYS_NAME_VERSION}\"\n# The default name of registered AMIs; override by setting PUBLISH_AMI_NAME.\nPUBLISH_AMI_NAME_DEFAULT = \"${BUILDSYS_NAME}-${BUILDSYS_VARIANT}-${BUILDSYS_ARCH}-v${BUILDSYS_VERSION_IMAGE}-${BUILDSYS_VERSION_BUILD}\"\n\n# The name of the kmod kit archive, used to ease building out-of-tree kernel modules.\nBUILDSYS_KMOD_KIT = \"${BUILDSYS_VARIANT}-${BUILDSYS_ARCH}-kmod-kit-v${BUILDSYS_VERSION_IMAGE}.tar.xz\"\nBUILDSYS_KMOD_KIT_PATH = \"${BUILDSYS_VARIANT_DIR}/${BUILDSYS_KMOD_KIT}\"\n\n# The name of the OVA bundle that will be built if the current variant builds VMDK artifacts\nBUILDSYS_OVA = \"${BUILDSYS_NAME_VARIANT}-v${BUILDSYS_VERSION_IMAGE}.ova\"\nBUILDSYS_OVA_PATH = \"${BUILDSYS_VARIANT_DIR}/${BUILDSYS_OVA}\"\nBUILDSYS_OVF_TEMPLATE = \"${BUILDSYS_ROOT_DIR}/variants/${BUILDSYS_VARIANT}/template.ovf\"\n\n# The default name of uploaded OVAs; override by setting VMWARE_VM_NAME\nVMWARE_VM_NAME_DEFAULT = \"${BUILDSYS_NAME}-${BUILDSYS_VARIANT}-${BUILDSYS_ARCH}-v${BUILDSYS_VERSION_IMAGE}-${BUILDSYS_VERSION_BUILD}\"\n\n# Config file for Boot Configuration initrd generation\nBOOT_CONFIG_INPUT = \"${BUILDSYS_ROOT_DIR}/bootconfig-input\"\n# Boot Configuration initrd\nBOOT_CONFIG = \"${BUILDSYS_ROOT_DIR}/bootconfig.data\"\n\n# Determines the kubeconfig that should be used by testsys. If no kubeconfig was provided and the\n# default kubeconfig location does not exist, use the users default kubeconfig.\nCARGO_MAKE_TESTSYS_KUBECONFIG_ARG = {script = [\n'''\nif ! [ -n \"${TESTSYS_KUBECONFIG}\" ] && [ -s \"${TESTSYS_TESTS_DIR}/testsys.kubeconfig\" ] && [ -s \"${CARGO_MAKE_DEFAULT_TESTSYS_KUBECONFIG_PATH}\" ];then\n   echo \"No kubeconfig was specified and a kubeconfig was found in 2 possible locations: '${TESTSYS_TESTS_DIR}/testsys.kubeconfig' and '${CARGO_MAKE_DEFAULT_TESTSYS_KUBECONFIG_PATH}'\"\n   exit 1\nfi\nif [ -n \"${TESTSYS_KUBECONFIG}\" ]; then\n   # If the user provides a kubeconfig path it should be used.\n   echo \"--kubeconfig ${TESTSYS_KUBECONFIG}\"\nelif [ -s \"${TESTSYS_TESTS_DIR}/testsys.kubeconfig\" ]; then\n   # If the kubeconfig is in the TESTSYS_TESTS_DIR it should be used.\n   echo \"--kubeconfig ${TESTSYS_TESTS_DIR}/testsys.kubeconfig\"\nelif [ -s \"${CARGO_MAKE_DEFAULT_TESTSYS_KUBECONFIG_PATH}\" ]; then\n   # If the default kubeconfig exists it should be used.\n   echo \"--kubeconfig ${CARGO_MAKE_DEFAULT_TESTSYS_KUBECONFIG_PATH}\"\nfi\n'''\n]}\n\n# Args that will be passed into all testsys invocations.\nCARGO_MAKE_TESTSYS_ARGS = \"${CARGO_MAKE_TESTSYS_KUBECONFIG_ARG}\"\n\nTESTSYS_TEST_CONFIG_PATH = { script = [\n'''\nif [ -s \"${TESTSYS_TEST_CONFIG_PATH}\" ] && [ -s \"${TESTSYS_TESTS_DIR}/Test.toml\" ];then\n   echo \"There can only be 1 config file. 2 config files were found: '${TESTSYS_TEST_CONFIG_PATH}' and '${TESTSYS_TESTS_DIR}/Test.toml'\"\n   exit 1\nfi\nif [ -s \"${TESTSYS_TEST_CONFIG_PATH}\" ]; then\n   # If the config path exists\n   echo \"${TESTSYS_TEST_CONFIG_PATH}\"\nelif [ -s \"${TESTSYS_TESTS_DIR}/Test.toml\" ]; then\n   # If the test config is in the TESTSYS_TESTS_DIR it should be used.\n   echo \"${TESTSYS_TESTS_DIR}/Test.toml\"\nelse\n   echo \"${TESTSYS_TEST_CONFIG_PATH}\"\nfi\n'''\n] }\n\n[tasks.install-twoliter]\nscript_runner = \"bash\"\nscript = [\n'''\ndeclare -a flags\n\nif [ \"${TWOLITER_REUSE_EXISTING_INSTALL}\" = \"true\" ]; then\n   flags+=(\"--reuse-existing-install\")\nfi\n\nif [ \"${TWOLITER_ALLOW_BINARY_INSTALL}\" = \"true\" ]; then\n   if [ \"${UNAME_ARCH}\" = \"aarch64\" ]; then\n      flags+=(\"--allow-binary-install\" \"${TWOLITER_SHA256_AARCH64}\")\n   else\n      flags+=(\"--allow-binary-install\" \"${TWOLITER_SHA256_X86_64}\")\n   fi\nfi\n\nif [ \"${TWOLITER_ALLOW_SOURCE_INSTALL}\" = \"true\" ]; then\n   flags+=(\"--allow-from-source\")\nfi\n\nif [ \"${TWOLITER_SKIP_VERSION_CHECK}\" = \"true\" ]; then\n   flags+=(\"--skip-version-check\")\nfi\n\n\"${BUILDSYS_TOOLS_DIR}/install-twoliter.sh\" \\\n  --repo \"${TWOLITER_REPO}\" \\\n  --version \"${TWOLITER_VERSION}\" \\\n  --directory \"${TWOLITER_INSTALL_DIR}\" \\\n  \"${flags[@]}\"\n'''\n]\n\n[tasks.run-twoliter]\ndependencies = [\"install-twoliter\"]\ncommand = \"${TWOLITER}\"\nargs = [\n    \"--log-level=${TWOLITER_LOG_LEVEL}\",\n    \"make\",\n    \"${CARGO_MAKE_TASK}\",\n    \"--project-path=${TWOLITER_PROJECT}\",\n    \"--cargo-home=${CARGO_HOME}\",\n    \"--\",\n    \"${@}\",\n]\n\n[tasks.deprecated]\ndependencies = [\"install-twoliter\"]\nscript_runner = \"bash\"\nscript = [\n'''\necho \"The '${CARGO_MAKE_TASK}' task is deprecated.\"\necho \"All it does is ensure that Twoliter is installed.\"\necho \"You should do this with 'cargo make install-twoliter' instead.\",\n'''\n]\n\n[tasks.setup]\nrun_task = \"run-twoliter\"\n\n[tasks.setup-build]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-sdk]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-toolchain]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-sources]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-vendored]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-external-kits]\ndependencies = [\"install-twoliter\"]\ncommand = \"${TWOLITER}\"\nargs = [\n    \"--log-level=${TWOLITER_LOG_LEVEL}\",\n    \"fetch\",\n    \"--project-path=${TWOLITER_PROJECT}\",\n    \"--arch=${BUILDSYS_ARCH}\",\n]\n\n[tasks.unit-tests]\nrun_task = \"run-twoliter\"\n\n# A top level target for devs to ensure review and patch readiness\n[tasks.check]\nrun_task = \"run-twoliter\"\n\n[tasks.check-fmt]\nrun_task = \"run-twoliter\"\n\n[tasks.check-lints]\nrun_task = \"run-twoliter\"\n\n[tasks.check-clippy]\nrun_task = \"run-twoliter\"\n\n[tasks.check-shell]\nrun_task = \"run-twoliter\"\n\n[tasks.check-golangci-lint]\nrun_task = \"run-twoliter\"\n\n[tasks.check-migrations]\nrun_task = \"run-twoliter\"\n\n[tasks.build-tools]\nrun_task = \"deprecated\"\n\n# Note: this is separate from publish-tools because publish-tools takes a while\n# to build and isn't needed to build an image.\n[tasks.publish-setup-tools]\nrun_task = \"deprecated\"\n\n[tasks.publish-tools]\nrun_task = \"deprecated\"\n\n[tasks.build-sbkeys]\nrun_task = \"run-twoliter\"\n\n# We need Cargo version 1.51 or higher in order to build a workspace's\n# dependency during build-package\n[tasks.check-cargo-version]\nrun_task = \"run-twoliter\"\n\n[tasks.boot-config]\nrun_task = \"run-twoliter\"\n\n[tasks.validate-boot-config]\nrun_task = \"run-twoliter\"\n\n# Builds a package including its build-time and runtime dependency packages.\n[tasks.build-package]\ndependencies = [\"fetch-external-kits\"]\nrun_task = \"run-twoliter\"\n\n[tasks.build-variant]\ndependencies = [\"fetch-external-kits\"]\nrun_task = \"run-twoliter\"\n\n[tasks.build-all]\ndependencies = [\"fetch-external-kits\"]\nrun_task = \"run-twoliter\"\n\n[tasks.repack-variant]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-variant]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-friendly-variant]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-ova]\nrun_task = \"run-twoliter\"\n\n[tasks.check-licenses]\nrun_task = \"run-twoliter\"\n\n[tasks.fetch-licenses]\nrun_task = \"run-twoliter\"\n\n[tasks.build]\ndependencies = [\"fetch-external-kits\"]\nrun_task = \"run-twoliter\"\n\n[tasks.tuftool]\nrun_task = \"deprecated\"\n\n[tasks.publish-setup]\nrun_task = \"run-twoliter\"\n\n[tasks.publish-setup-without-key]\nrun_task = \"run-twoliter\"\n\n# Builds a local repository based on the 'latest' built targets.  Uses pubsys\n# to create a repo under /build/repos, named after the arch/variant/version,\n# containing subdirectories for the repo metadata and targets.\n[tasks.repo]\nrun_task = \"run-twoliter\"\n\n[tasks.validate-repo]\nrun_task = \"run-twoliter\"\n\n[tasks.check-repo-expirations]\nrun_task = \"run-twoliter\"\n\n[tasks.refresh-repo]\nrun_task = \"run-twoliter\"\n\n[tasks.ami]\nrun_task = \"run-twoliter\"\n\n[tasks.ami-public]\nrun_task = \"run-twoliter\"\n\n[tasks.ami-private]\nrun_task = \"run-twoliter\"\n\n[tasks.grant-ami]\nrun_task = \"run-twoliter\"\n\n[tasks.revoke-ami]\nrun_task = \"run-twoliter\"\n\n[tasks.validate-ami]\nrun_task = \"run-twoliter\"\n\n[tasks.ssm]\nrun_task = \"run-twoliter\"\n\n[tasks.promote-ssm]\nrun_task = \"run-twoliter\"\n\n[tasks.validate-ssm]\nrun_task = \"run-twoliter\"\n\n[tasks._upload-ova-base]\nrun_task = \"run-twoliter\"\n\n# This task runs `_upload-ova-base` which will upload the OVA and *not* mark it\n# as a template\n[tasks.upload-ova]\nrun_task = \"run-twoliter\"\n\n# This task runs `_upload-ova-base` with the environment variable\n# `MARK_OVA_AS_TEMPLATE` set, which will upload the OVA *and* mark it as a\n# template\n[tasks.vmware-template]\nrun_task = \"run-twoliter\"\n\n[tasks.clean]\nrun_task = \"run-twoliter\"\n\n[tasks.clean-sources]\nrun_task = \"run-twoliter\"\n\n[tasks.clean-packages]\nrun_task = \"run-twoliter\"\n\n[tasks.clean-images]\nrun_task = \"run-twoliter\"\n\n[tasks.clean-repos]\nrun_task = \"run-twoliter\"\n\n[tasks.clean-state]\nrun_task = \"run-twoliter\"\n\n# Deletes cached code used for Bottlerocket builds\n[tasks.purge-cache]\nrun_task = \"run-twoliter\"\n\n# This task will delete vendored Go code, primarily, the Go module cache.\n# The Go module cache is intentionally readonly and does not have writable\n# subdirectories or files. So, we first need to perform the `chmod` in order to\n# have permissions to delete it.\n# See for more context: https://github.com/golang/go/issues/27455\n[tasks.purge-go-vendor]\nrun_task = \"run-twoliter\"\n\n# This task will remove all the cached Rust code found in the cargo home dir\n[tasks.purge-cargo]\nrun_task = \"run-twoliter\"\n\n[tasks.test-tools]\nrun_task = \"deprecated\"\n\n[tasks.setup-test]\nrun_task = \"run-twoliter\"\n\n# This task is used to test bottlerocket build artifacts. By default the region first listed in Infra.toml\n# is used for testing; however, `TESTSYS_REGION` can be used to test in a different region.\n[tasks.test]\nrun_task = \"run-twoliter\"\n\n# This task will clear all tests from the testsys cluster.\n# To delete all passed tests use `cargo make clean-test --passed`\n# To delete all failed tests use `cargo make clean-test --failed`\n# To delete all incomplete tests use `cargo make clean-test --running`\n[tasks.clean-test]\nrun_task = \"run-twoliter\"\n\n# This task will clear all tests and resources from the testsys cluster.\n[tasks.reset-test]\nrun_task = \"run-twoliter\"\n\n# This task will clear a specific test and its resources from the testsys cluster.\n[tasks.reset-single-test]\nrun_task = \"run-twoliter\"\n\n# This task will clear all testsys components from the testsys cluster.\n[tasks.uninstall-test]\nrun_task = \"run-twoliter\"\n\n# This task will clear all testsys components from the testsys cluster.\n[tasks.purge-test]\nrun_task = \"run-twoliter\"\n\n# This task will call watch on the `status` testsys command to show the results of all tests.\n# To see all passed tests use `cargo make watch-test --passed`\n# To see all failed tests use `cargo make watch-test --failed`\n# To see all incomplete tests use `cargo make watch-test --running`\n[tasks.watch-test]\nrun_task = \"run-twoliter\"\n\n# This task will call watch on the `status` testsys command to show the results of all tests and\n# resources.\n# To see all incomplete crds use `cargo make watch-test-all --running`\n[tasks.watch-test-all]\nrun_task = \"run-twoliter\"\n\n# This task will retrieve testsys logs from a test. You can add `--follow` to continue to receive\n# logs as they come in.\n[tasks.log-test]\nrun_task = \"run-twoliter\"\n\n# This task is useful for using the current tree's testsys without symlinks\n[tasks.testsys]\nrun_task = \"run-twoliter\"\n\n[tasks.default]\nalias = \"build\"\n"
  },
  {
    "path": "PROVISIONING-METAL.md",
    "content": "# Provisioning Bottlerocket on metal\n\nThis guide will describe what is needed to properly provision Bottlerocket on bare metal.\nProvisioning Bottlerocket on metal is different than provisioning other general-purpose distros.\nSince Bottlerocket has a `dm-verity`-checked boot and root partition, and is immutable at runtime, a user cannot provision an image and directly write configuration files.\nBottlerocket requires a few files to be generated and written to disk at provisioning time in order to boot properly; these files are described below.\n\nFor more information about the hardware that Bottlerocket for bare metal is currently tested on, see [SUPPORTED-HARDWARE](SUPPORTED-HARDWARE.md).\n\n## High level provisioning steps\n\nThe high level steps to provision Bottlerocket images for bare metal to your host are below.\nMost provisioning systems provide methods to achieve the following:\n\n* Decompress (`unlz4`) and write the Bottlerocket image to the desired disk\n* Mount the `BOTTLEROCKET-PRIVATE` partition (partition 12)\n* Write the below files to the mounted partition (these files are further described below):\n  * (Required) [`user-data.toml`](#user-data)\n  * (Required) [`net.toml`](#network-interface-configuration)\n  * (Optional, recommended) [`bootconfig.data`](#boot-configuration)\n* Reboot\n\n### Fetch the Bottlerocket image for bare metal\n\nThe Bottlerocket image for bare metal is signed and uploaded alongside the rest of the Bottlerocket release artifacts.\n\nYou first need the Bottlerocket root role, which is used by `tuftool` to verify the image.\nThe following will download and verify the root role itself:\n\n```shell\ncurl -O \"https://cache.bottlerocket.aws/root.json\"\nsha512sum -c <<<\"4fcb272345fd6adb94d4c04834400548178fecb57407ca79bc2c3d20e0428fc9ed3a82cea268d7f9c667b5803524a4f465acd701a86953d5d732bf6ecb064888  root.json\"\n```\n\nNext, set your desired version and variant, and use `tuftool` to download the image:\nTo install `tuftool` you'll need to install Rust (via [rustup](https://rustup.rs/) or the official site), and then you can run `cargo install tuftool`.\nThe VERSION corresponds to the [Bottlerocket version](https://github.com/bottlerocket-os/bottlerocket/releases/latest), the latest release is almost always what you want.\nYou might need to install `jq` to fetch the VERSION.\n\n```shell\nARCH=\"x86_64\"\nVERSION=\"v1.26.1\" # New releases do not have metal-k8s variants\nVARIANT=\"metal-k8s-1.28\"\nIMAGE=\"bottlerocket-${VARIANT}-${ARCH}-${VERSION}.img.lz4\"\nOUTDIR=\"${VARIANT}-${VERSION}\"\n\ntuftool download \"${OUTDIR}\" --target-name \"${IMAGE}\" \\\n   --root ./root.json \\\n   --metadata-url \"https://updates.bottlerocket.aws/2020-07-07/${VARIANT}/x86_64/\" \\\n   --targets-url \"https://updates.bottlerocket.aws/targets/\"\n```\n\n### User data\n\nBottlerocket for bare metal expects a TOML-formatted file named `user-data.toml` that contains user data settings.\nAcceptable settings can be found in the [settings docs](https://github.com/bottlerocket-os/bottlerocket#settings).\n\nIf you're just getting started and want to provision a host without connecting to a Kubernetes cluster, you can use the following example user data which will start `kubelet` in standalone mode.\n\n```toml\n[settings.kubernetes]\nstandalone-mode = true\n```\n\nFor remote access to your running Bottlerocket hosts, you will need to add user data to enable host containers.\nThe Bottlerocket images for bare metal don't enable any host containers by default.\nYou can use our [admin](https://github.com/bottlerocket-os/bottlerocket-admin-container) and/or [control](https://github.com/bottlerocket-os/bottlerocket-control-container) containers, but they need to be configured first.\nFull configuration details are covered in the [admin container documentation](https://github.com/bottlerocket-os/bottlerocket-admin-container#authenticating-with-the-admin-container) and the [control container documentation](https://github.com/bottlerocket-os/bottlerocket-control-container#connecting-to-aws-systems-manager-ssm).\n\n### Network interface configuration\n\nBottlerocket for bare metal provides the means to configure the physical network interfaces in the system via TOML-formatted file `net.toml`.\n\n`net.toml` is read at boot time and generates the proper configuration files in the correct format for each interface described; no default configuration is provided.\nIf no network configuration is provided, boot-time services like host containers, `containerd`, and `kubelet` will fail to start.\nWhen these services fail, your machine will not connect to any cluster and will be unreachable via host containers.\n\n#### `net.toml` structure\n\nThe configuration file must be valid TOML and have the filename `net.toml`.\nThe first and required top level key in the file is `version`; the latest is version `3`.\nThe rest of the file is a map of interface name or MAC address to supported settings.\nInterface names are expected to be correct as per `udevd` naming, no interface naming or matching is supported.\n(See the note below regarding `udevd` interface naming.)\n\n#### Supported interface settings\n\n* `primary` (boolean): Use this interface as the primary network interface. `kubelet` will use this interface's IP when joining the cluster.  If none of the interfaces has `primary` set, the first interface in the file is used as the primary interface.\n* `dhcp4` (boolean or map): Turns on DHCP4 for the interface.  If additional DHCP4 configuration is required, the following settings are supported and may be provided as a map with the following keys:\n  * `enabled` (boolean, required): Enables DHCP4.\n  * `route-metric` (integer): Prioritizes routes by setting values for preferred interfaces.\n  * `optional` (boolean): the system will request a lease using this protocol, but will not wait for a valid lease to consider this interface configured.\n* `dhcp6` (boolean or map): Turns on DHCP6 for the interface.  If additional DHCP6 configuration is required, the following settings are supported and may be provided as a map with the following keys:\n  * `enabled` (boolean, required): Enables DHCP6.\n  * `optional` (boolean): the system will request a lease using this protocol, but will not wait for a valid lease to consider this interface configured.\n\nAs of version `2` static addressing with simple routes is supported via the below settings.\nPlease keep in mind that when using static addresses, DNS information must be supplied to the system via user data: [`settings.dns`](https://github.com/bottlerocket-os/bottlerocket#network-settings).\n\n* `static4` (map): IPv4 static address settings.\n  * `addresses` (list of quoted IPv4 address including prefix): The desired IPv4 IP addresses, including prefix i.e. `[\"192.168.14.2/24\"]`.  The first IP in the list will be used as the primary IP which `kubelet` will use when joining the cluster.  If IPv4 and IPv6 static addresses exist, the first IPv4 address is used.\n* `static6` (map): IPv6 static address settings.\n  * `addresses` (list of quoted IPv6 address including prefix): The desired IPv6 IP addresses, including prefix i.e. `[\"2001:dead:beef::2/64\"]`.  The first IP in the list will be used as the primary IP which `kubelet` will use when joining the cluster.  If IPv4 and IPv6 static addresses exist, the first IPv4 address is used.\n\n* `route` (map): Static route; multiple routes can be added. (cannot be used in conjunction with DHCP)\n  * `to` (`\"default\"` or IP address with prefix, required): Destination address.\n  * `from` (IP address): Source IP address.\n  * `via` (IP address): Gateway IP address.  If no gateway is provided, a scope of `link` is assumed.\n  * `route-metric` (integer): Relative route priority.\n\nVersion `3` adds support for bonding, vlan tagging, and the ability to use a MAC address (colon or dash separated) as the identifier for an interface.\nMAC address identification is limited to interface configuration *only* and may not be used in conjunction with bonds or vlans.\n[Bonding](https://www.kernel.org/doc/Documentation/networking/bonding.txt) support is limited to mode `1` (`active-backup`).\nFuture support may include other bonding options - pull requests are welcome!\nVersion `3` adds the concept of virtual network devices in addition to interfaces.\nThe default type of device is an interface and the syntax is the same as previous versions.\nThe name of an interface must match an existing interface on the system such as `eno1` or `enp0s16`.\nFor virtual network devices, a `kind` is required.\nIf no `kind` is specified, it is assumed to be an interface.\nCurrently, `bond` and `vlan` are the two supported `kind`s.\nVirtual network devices are created, and therefore a name has to be chosen.\n\nNames for virtual network devices must conform to kernel naming restrictions:\n* Names must not have line terminators in them\n* Names must be between 1-15 characters\n* Names must not contain `.`, `/` or whitespace\n\nBonding configuration creates a virtual network device across several other devices:\n\n* Bonding configuration (map):\n  * `kind = \"bond\"`: This setting is required to specify a bond device. Required.\n  * `interfaces` (list of quoted strings of interface names, not MAC addresses): Which interfaces should be added to the bond (i.e. `[\"eno1\"]`). The first in the list is considered the default `primary`. These interfaces are \"consumed\" so no other configuration can refer to them. Required.\n  * `mode` (string): Currently `active-backup` is the only supported option. Required.\n  * `min-links` (integer): Number of links required to bring up the device\n  * `monitoring` (map): Values m ust all be of `miimon` or `arpmon` type.\n    The user must choose one type of monitoring and configure it fully in order for the bond to properly function.\n    See [section 7](https://www.kernel.org/doc/Documentation/networking/bonding.txt) for more background on what to choose.\n    * `miimon-frequency-ms` (integer): MII Monitoring frequency in milliseconds\n    * `miimon-updelay-ms` (integer): MII Monitoring delay before the link is enabled after link is detected in milliseconds\n    * `miimon-downdelay-ms` (integer): MII Monitoring delay before the link is disabled after link is no longer detected in milliseconds\n    * `arpmon-interval-ms` (integer): Number of milliseconds between intervals to determine link status, must be greater than 0\n    * `arpmon-validate` (one of `all`, `none`, `active`, or `backup`): What packets should be used to validate link\n    * `arpmon-targets` (list of quoted IPv4 address including prefix): List of targets to use for validating ARP. Min = 1, Max = 16\n\nVlan tagging is configured as a new virtual network device stacked on another device:\n\n* Vlan configuration (map):\n  * `kind = \"vlan\"`: This setting is required to specify a vlan device.\n  * `device` (string for device name, not MAC address): Defines the device the vlan should be configured on.\n    If VLAN tagging is required, this device should receive all IP address configuration instead of the underlying device.\n  * `id` (integer): Number between 0 and 4096 specifying the vlan tag on the device\n\nExample `net.toml` version `3` with comments:\n\n```toml\nversion = 3\n\n# \"eno1\" is the interface name\n[eno1]\n# Users may turn on dhcp4 and dhcp6 via boolean\ndhcp4 = true\ndhcp6 = true\nprimary = true\n\n# \"eno2\" is the second interface in this example\n[eno2.dhcp4]\n# `enabled` is a boolean and is a required key when\n# setting up DHCP this way\nenabled = true\n# Route metric may be supplied for IPv4\nroute-metric = 200\n\n[eno2.dhcp6]\nenabled = true\noptional = true\n\n[eno3.static4]\naddresses = [\"10.0.0.10/24\", \"11.0.0.11/24\"]\n\n# Multiple routes may be configured\n[[eno3.route]]\nto = \"default\"\nvia = \"10.0.0.1\"\nroute-metric = 100\n\n[[eno3.route]]\nto = \"default\"\nvia = \"11.0.0.1\"\nroute-metric = 200\n\n[eno4.static4]\naddresses = [\"192.168.14.5/24\"]\n\n# Using a source IP and non-default route\n[[eno4.route]]\nto = \"10.10.10.0/24\"\nfrom = \"192.168.14.5\"\nvia = \"192.168.14.25\"\n\n# Interfaces may be configured using their MAC address rather than the interface name.\n# The MAC address must be quoted and colon or dash separated\n[\"0e:b3:69:44:b6:33\"]\ndhcp4 = true\n\n[\"3e:03:69:49:e6:31\".static4]\naddresses = [\"10.0.0.15/24\"]\n\n[[\"3e:03:69:49:e6:31\".route]]\nto = \"default\"\nvia = \"10.0.0.1\"\n\n# A bond is a network device that is of `kind` `bond`\n[bond0]\nkind = \"bond\"\n# Currently `active-backup` is the only supported option\nmode = \"active-backup\"\n# In this case, the vlan will have addressing, the bond is simply there for use in the vlan\ndhcp4 = false\ndhcp6 = false\n# The first interface in the array is considered `primary` by default, this list may not contain MAC addresses.\ninterfaces = [\"eno11\", \"eno12\"]\n\n[bond0.monitoring]\nmiimon-frequency-ms = 100 # 100 milliseconds\nmiimon-updelay-ms = 200 # 200 milliseconds\nmiimon-downdelay-ms = 200 # 200 milliseconds\n\n[bond1]\nkind = \"bond\"\nmode = \"active-backup\"\ninterfaces = [\"eno51\" , \"eno52\", \"eno53\"]\nmin-links = 2 # Optional min-links \ndhcp4 = true\n\n[bond1.monitoring]\narpmon-interval-ms = 200 # 200 milliseconds\narpmon-validate = \"all\"\narpmon-targets = [\"192.168.1.1\", \"10.0.0.2\"]\n\n# A vlan is a network device that is of `kind` `vlan`\n# VLAN42 is the name of the device, can be anything that is a valid network interface name\n[VLAN42]\nkind = \"vlan\"\n# `device` may not contain a MAC address.\ndevice = \"bond0\"\nid = 42\ndhcp4 = true\n\n[internal_vlan]\nkind = \"vlan\"\ndevice = \"eno2\"\nid = 1234\ndhcp6 = true\n```\n\n#### **An additional note on network device names**\n\nInterface name policies are [specified in this file](https://github.com/bottlerocket-os/bottlerocket/blob/develop/packages/release/80-release.link#L6); with name precedence in the following order: onboard, slot, path.\nTypically on-board devices are named `eno*`, hot-plug devices are named `ens*`, and if neither of those names are able to be generated, the “path” name is given, i.e `enp*s*f*`.\n\n#### Networking configuration versions and Releases\n\nOlder networking configuration versions (such as `1` or `2`) are supported in newer releases. In order to use a newer version, the following table provides guidance on what release first enabled the version.\n\n| Network Configuration Version | First Release                                                                   |\n|-------------------------------|---------------------------------------------------------------------------------|\n| Version 1                     | [v1.9.0](https://github.com/bottlerocket-os/bottlerocket/releases/tag/v1.9.0)   |\n| Version 2                     | [v1.10.0](https://github.com/bottlerocket-os/bottlerocket/releases/tag/v1.10.0) |\n| Version 3                     | [v1.12.0](https://github.com/bottlerocket-os/bottlerocket/releases/tag/v1.12.0) |\n\n### Boot Configuration\n\nBottlerocket for bare metal uses a feature of the Linux kernel called [Boot Configuration](https://www.kernel.org/doc/html/latest/admin-guide/bootconfig.html), which allows a user to pass additional arguments to the kernel command line at runtime.\nAn immediate use of this feature for most users is setting `console` settings so boot messages can be seen on the appropriate consoles.\n\nIn order to make use of this feature, an initrd is created with the desired settings encoded inside it.\nThe initrd is empty save for the encoded boot config data.\nTo create the initrd, you must first create a configuration file containing key value pairs for the settings you would like to pass to kernel / init.\nFull syntax is described in the [Boot Config documentation](https://www.kernel.org/doc/html/latest/admin-guide/bootconfig.html#config-file-syntax), but a simple example is provided below that shows the format of console settings as well as an example `systemd` parameter.\n\nThe two acceptable prefixes to settings are `kernel` and `init`.\nSettings prefixed with `kernel` are added to the beginning of the kernel command line.\nSettings prefixed with `init` are added to the kernel command line after the `--`, but before any existing init parameters.\n\nIn the example below, two console devices are set up, and `systemd`'s log level is set to `debug`.\n\nExample Boot Configuration:\n\n```\nkernel {\n    console = tty0, \"ttyS1,115200n8\"\n}\ninit {\n    systemd.log_level = debug\n}\n```\n\nThe Bottlerocket SDK provides the `bootconfig` CLI tool, which is used to create a Boot Configuration initrd.\nTo create the Boot Configuration initrd, create a config file named `bootconfig-input` containing your desired key/value pair kernel and init arguments.\n\nThen run the following (you will need Docker installed):\n\n```shell\nARCH=$(uname -m)\nSDK_VERSION=\"v0.26.0\"\nSDK_IMAGE=\"public.ecr.aws/bottlerocket/bottlerocket-sdk-${ARCH}:${SDK_VERSION}\"\n\ntouch $(pwd)/bootconfig.data\n\ndocker run --rm \\\n   --network=none \\\n   --user \"$(id -u):$(id -g)\" \\\n   --security-opt label=disable \\\n   -v $(pwd)/bootconfig-input:/tmp/bootconfig-input \\\n   -v $(pwd)/bootconfig.data:/tmp/bootconfig.data \\\n   \"${SDK_IMAGE}\" \\\n   bootconfig -a /tmp/bootconfig-input /tmp/bootconfig.data\n```\n\nThe above command will create the properly named initrd `bootconfig.data` in your current directory.\nThis is the file you will write to disk during provisioning.\n\nYou can list a `bootconfig.data`'s contents, which also validates its format, by running:\n\n```shell\nARCH=$(uname -m)\nSDK_VERSION=\"v0.26.0\"\nSDK_IMAGE=\"public.ecr.aws/bottlerocket/bottlerocket-sdk-${ARCH}:${SDK_VERSION}\"\n\ndocker run --rm \\\n   --network=none \\\n   --user \"$(id -u):$(id -g)\" \\\n   --security-opt label=disable \\\n   -v $(pwd)/bootconfig.data:/tmp/bootconfig.data \\\n   \"${SDK_IMAGE}\" \\\n   bootconfig -l /tmp/bootconfig.data\n```\n\n### Enable Secure Boot\n\nStarting with metal-k8s-1.28, the Bottlerocket images for bare metal support Secure Boot when used on a platform with UEFI firmware.\nUEFI boot mode must be used, rather than legacy BIOS boot mode, and Secure Boot must be enabled.\nThe UEFI firmware may provide a Compatibility Support Module (CSM) option to enable legacy BIOS emulation.\nThe CSM option must not be enabled.\nThese options can be set in the firmware setup menu, which can be accessed during boot by pressing a certain key (such as F2 or F12).\n\nMany Linux distros ship a copy of the [shim](https://github.com/rhboot/shim) bootloader signed by Microsoft with a key that is trusted by default.\nAlthough Bottlerocket also uses `shim`, its copy is not signed by Microsoft and will not be trusted without additional configuration.\nAfter installing Bottlerocket, the appropriate vendor certificate can be found on the EFI System Partition (ESP).\nThe firmware setup menu should provide an option to import a new vendor certificate by selecting a file on the ESP.\nEither the PEM format (`db.crt`) or DER format (`db.cer`) certificate can be imported, depending on what the firmware supports.\n\nThe firmware setup menu should be password-protected to prevent unauthorized changes to the Secure Boot configuration.\nPlease refer to the documentation from your hardware vendor for more information on this procedure.\n"
  },
  {
    "path": "PUBLISHING-AWS.md",
    "content": "# Publishing Bottlerocket on AWS\n\nThis guide will walk you through some AWS-specific details around publishing an AMI, granting access to said AMI, as well as making it easy for others to find your AMI via SSM parameters.\n\n### Register an AMI\n\nThe [BUILDING](BUILDING.md#register-an-ami) guide covers the process of making an AMI, and has you specify `PUBLISH_REGIONS` to decide where the AMI will live.\nYou can also specify this in your `Infra.toml` file:\n\n```toml\n[aws]\nregions = [\"us-west-2\", \"us-east-1\", \"us-east-2\"]\n```\n\nNote: several commands work with AWS services, so there's some shared configuration related to AWS accounts and AWS IAM roles.\nFor example, you can specify a role to assume before any API calls are made, and a role to assume before any API calls in a specific region.\nThis can be useful if you want to use roles to control access to the accounts that own AMIs, for example.\nSee the commented [example Infra.toml](tools/pubsys/Infra.toml.example) for details.\n\nIf you specify multiple regions, an AMI will be registered in the first region and then copied to the other regions.\n\nAfter putting this in `Infra.toml`, you can make an AMI more easily:\n\n```shell\ncargo make ami\n```\n\nIf you want to change the name or description of your AMI, you can add on `-e PUBLISH_AMI_NAME=my-name` or `-e PUBLISH_AMI_DESCRIPTION=my-desc`.\n\n> Note: the AMI registration process creates a JSON file describing the AMIs in a directory under `build/images/`.\n> This file is used by the steps below when granting access to the AMIs or setting parameters in SSM.\n\n### Granting access to your AMI\n\nIf you use different accounts to make and test your AMIs, you can grant access to specific accounts like this:\n\n```shell\ncargo make -e GRANT_TO_USERS=0123456789,9876543210 grant-ami\n```\n\n(Later, if you need to revoke access, you can do this:)\n\n```shell\ncargo make -e REVOKE_FROM_USERS=0123456789,9876543210 revoke-ami\n```\n\n> Note: similar to `cargo make ami`, you can specify `PUBLISH_REGIONS` on the command line if you don't want to make an `Infra.toml` config.\n\n### Making your AMIs discoverable with SSM parameters\n\nAfter you've made AMIs and a repo, you may want to make it easier to find your AMIs, particularly as you make new versions over time.\n\nOne way to do this is to store the AMI IDs in [AWS SSM Parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html).\nThese are simple names like `/my/ami/id` that you can use in many places instead of specific AMI IDs.\nFor example, you can launch EC2 instances using [RunInstances](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-ec2-aliases.html) or [in a CloudFormation stack](https://aws.amazon.com/blogs/mt/integrating-aws-cloudformation-with-aws-systems-manager-parameter-store/) using a parameter name rather than an AMI ID.\nYou can also use the same parameter names across regions, so you don't have to deal with region-specific AMI IDs.\n\n> Note: SSM parameters are private to your account.\n> They let you use consistent names instead of tracking AMI IDs, but they don't currently let you share with other accounts.\n\nThe `cargo make ssm` task can set SSM parameters based on the AMIs you built [above](#register-an-ami).\nFor this to work, you have to specify a parameter prefix in your `Infra.toml`.\nThis setting lives in the same `[aws]` section you used above to list the regions where you want to register AMIs.\n(The same region list will be used to determine where to publish SSM parameters.)\n\nHere's an example configuration for regions and the SSM prefix:\n\n```toml\n[aws]\nregions = [\"us-west-2\", \"us-east-1\", \"us-east-2\"]\nssm_prefix = \"/your/prefix/here\"\n```\n\nThis prefix forms the start of the name of each SSM parameter we set.\nThe rest of the name comes from parameter templates.\n\nParameter templates determine the name and value of each parameter we want to set for each AMI we've built.\nThe [default template](tools/pubsys/policies/ssm/defaults.toml) creates parameters that let users find the AMI ID and the image version for each of your AMIs.\nThe templates have access to the name of the current variant, architecture, etc., so they can create unique parameter names for each build.\nFor more information on how templates work, check out [their documentation](tools/pubsys/policies/ssm/).\n\nIf you're happy with the default template, you can set SSM parameters like this:\n\n```shell\ncargo make ssm\n```\n\nThis will create versioned parameters, meaning that the parameter name has the image version in it.\nThis isn't very discoverable yet, but it's useful for testing.\n\nAs an example, a parameter might look like this:\n\n```\n/your/prefix/here/aws-k8s-1.32/x86_64/1.31.0-41108b4/image_id\n```\n\nOnce you're satisfied with your image and parameters, you can promote the parameters to simpler names (for example, \"latest\") using the [instructions below](#promoting-ssm-parameters).\n\nNote: if you want to customize the SSM parameters that get set, you can copy and modify the existing template file, then point to your file like this:\n\n```shell\ncargo make -e PUBLISH_SSM_TEMPLATES_PATH=/my/template/path ssm\n```\n\n### Making your AMIs public\n\nWe talked about [granting AMI access](#granting-access-to-your-ami) to specific AWS accounts.\nThis is useful for testing, and for sharing private AMIs with specific accounts.\n\nIf you want to make your AMIs public to the world, there's a shortcut:\n\n```shell\ncargo make ami-public\n```\n\n(Later, if you need to make the AMIs private again, you can do this.\n The AMIs will then only be accessible to account IDs you've specifically granted.)\n\n```shell\ncargo make ami-private\n```\n\n### Promoting SSM parameters\n\n[Above](#making-your-amis-discoverable-with-ssm-parameters), we set SSM parameters based on our AMIs.\nThe SSM parameter names include version numbers, which is handy for testing, but makes them hard to find.\nOnce we're satisfied, we can promote the SSM parameters to simpler names.\n\n```shell\ncargo make -e SSM_TARGET=latest promote-ssm\n```\n\nThis will copy the fully versioned parameter from earlier, something like:\n\n```\n/your/prefix/here/aws-k8s-1.32/x86_64/1.31.0-41108b4/image_id\n```\n\n...to a simpler parameter name:\n\n```\n/your/prefix/here/aws-k8s-1.32/x86_64/latest/image_id\n```\n\nYou can then use this parameter name to get the latest AMI ID.\n\n> Note: if you use a custom parameter template, you need to have an `{image_version}` component in the parameter name for promotion to work.\n> The `SSM_TARGET` you specify above becomes the `image_version` in the template.\n"
  },
  {
    "path": "PUBLISHING-VMWARE.md",
    "content": "# Publishing a Bottlerocket OVA on VMware\n\nThis guide will walk through some VMware specific details around making your OVA available as a VM or VM template in one or more software defined datacenters.\n\n### Configuration details\n\nAs mentioned in the [PUBLISHING](PUBLISHING.md) guide, the process uses a configuration file called `Infra.toml`.\nFor VMware, you can specify details about your various vSphere instances and datacenters in `Infra.toml`, as well as configuration that may be common between datacenters.\n\nIt's important to note that we use [`govc`](https://github.com/vmware/govmomi/tree/master/govc) under the hood for interactions with vSphere, so at runtime **all datacenter configuration in `Infra.toml` is overridden by `GOVC_` environment variables.**\n`govc` is run in a container, so you do not need to install it on your machine.\nWe first check for environment variables, then use `Infra.toml` for datacenter specific configuration, and finally common configuration.\nThe following `GOVC_` environment variables are supported:\n* `GOVC_URL`\n* `GOVC_DATACENTER`\n* `GOVC_DATASTORE`\n* `GOVC_NETWORK`\n* `GOVC_FOLDER`\n* `GOVC_RESOURCE_POOL`\n* `GOVC_USERNAME`\n* `GOVC_PASSWORD`\n\nCredentials for your various datacenters may be stored at `~/.config/pubsys/vsphere-credentials.toml`.\nThe format of the file is below; each datacenter gets its own `[datacenter.NAME]` block, where `NAME` corresponds to a datacenter name in `Infra.toml`\nSimilar to other datacenter configuration, at runtime we first check for the environment variables `GOVC_USERNAME` and `GOVC_PASSWORD` and use one or both of them if they are set.\n\n```toml\n[datacenter.foo]\nusername = \"username\"\npassword = \"password\"\n\n[datacenter.bar]\nusername = \"bar\"\npassword = \"baz\"\n```\n\n### Uploading a Bottlerocket OVA\n\nYou can specify the datacenters to which you would like to upload your OVA in `Infra.toml`.\n\n```toml\n[vmware]\ndatacenters = [\"foo\", \"bar\"]\n```\n\nThen you can easily upload your OVA, specifying the variant you wish to upload (currently only VMware variants).\n\n```shell\ncargo make -e BUILDSYS_VARIANT=vmware-k8s-1.32 upload-ova\n```\n\nIf you would like to upload your OVA as a VM template, you can do this in a single step:\n\n```shell\ncargo make -e BUILDSYS_VARIANT=vmware-k8s-1.32 vmware-template\n```\n\nYou can override the list of datacenters to upload to by specifying `VMWARE_DATACENTERS`:\n\n```shell\ncargo make vmware-template \\\n  -e BUILDSYS_VARIANT=vmware-k8s-1.32 \\\n  -e VMWARE_DATACENTERS=\"foo,bar\"\n```\n\nIf you would like to override the name of the VM, you can add on `-e VMWARE_VM_NAME=my-name`.\n\nYou can also override the import spec used when uploading the OVA by specifying `VMWARE_IMPORT_SPEC_PATH`.\nOur [import spec template](tools/pubsys/support/vmware/import_spec.template) can be used as a starting point for further customization.\n\n```shell\ncargo make vmware-template \\\n  -e BUILDSYS_VARIANT=vmware-k8s-1.32 \\\n  -e VMWARE_IMPORT_SPEC_PATH=/path/to/my/spec.toml\n```\n"
  },
  {
    "path": "PUBLISHING.md",
    "content": "# Publishing Bottlerocket\n\nThis guide will walk you through deploying a Bottlerocket image, and if desired, sharing it with others.\nIt currently focuses on deploying to AWS and VMware, though the tooling is built to support other platforms in the future.\n\nRemember to look at the [TRADEMARKS](TRADEMARKS.md) guide to understand naming concerns.\nYou can pass `-e BUILDSYS_NAME=my-name` to `cargo make` commands to change the default \"short\" name, which is used in file and AMI names.\nYou can pass `-e BUILDSYS_PRETTY_NAME=\"My Name\"` to `cargo make` commands to change the default \"pretty\" name, which is used in the os-release file and some menus.\n\nWe'll assume you've been through the [BUILDING](BUILDING.md) guide to make an image.\n\n### Configuring the publishing process\n\nThe publishing process uses a configuration file called `Infra.toml`.\nThe relevant sections of this file will be introduced as needed below.\nYou can also see an [example file](tools/pubsys/Infra.toml.example) where each section is commented.\n\nWhen you make your own `Infra.toml`, you put it in the root of the Bottlerocket code repo, wherever you have it checked out.\n(If you want to keep it elsewhere, you can pass `-e \"PUBLISH_INFRA_CONFIG_PATH=/my/path\"` to subsequent `cargo make` commands.)\n\nNote: several commands work with AWS services, so there's some shared configuration related to AWS accounts and AWS IAM roles.\nFor example, you can specify a role to assume before any API calls are made, and a role to assume before any API calls in a specific region.\nThis can be useful if you want to use roles to control access to the accounts that own AMIs, for example.\nSee the commented [example Infra.toml](tools/pubsys/Infra.toml.example) for details.\n\n### Variants and architectures\n\nIf you [built your image](BUILDING.md) for a different variant or architecture, you can pass the same variant and architecture arguments to any of the `cargo make` commands in this document.\nFor example, if you built your image like this:\n\n```shell\ncargo make -e BUILDSYS_VARIANT=my-variant -e BUILDSYS_ARCH=my-arch\n```\n\n...then you can then build a repo for it like this:\n\n```shell\ncargo make -e BUILDSYS_VARIANT=my-variant -e BUILDSYS_ARCH=my-arch repo\n```\n\n## Publishing your image\n\nFor details on publishing your image on AWS or VMware, please see the respective [PUBLISHING-AWS](PUBLISHING-AWS.md) or [PUBLISHING-VMWARE](PUBLISHING-VMWARE.md) guides.\n\n## Build a repo\n\n> NOTE: If you intend to replace hosts rather than update them, you don't need to build an update repository.\n\nBottlerocket uses [TUF repositories](https://theupdateframework.io/overview/) to make system updates available to hosts.\nYou can read more about how Bottlerocket uses TUF in the [updater README](sources/updater/README.md#tuf-and-tough).\n\nInitially, the repo will only contain the image you just built.\nLater, when you build updates, you can [add them to the repo](#configuring-your-repo-location), which allows your hosts to update to new versions.\n(If you don't have an `Infra.toml` file, it will always try to build a brand new repo.)\n\n### Build process\n\nTo build a repo, run:\n\n```shell\ncargo make repo\n```\n\n#### Picking a release time\n\nIf you're preparing the release of a new version in advance (see [waves](#waves) for why you may want to) you can specify the start time for the release.\nYou'll need the time in ISO 8601 format.\nYou can use the `date` command to get the formatted time using a simple description of your desired start.\nFor example, if you want your release to start at 10:00 AM on Monday:\n\n```shell\nRELEASE_START_TIME=\"$(date '+%Y-%m-%dT%H:%M:%S%:z' -d 'Monday 10am')\"\n```\n\nNow we can create the repo using that time:\n\n```shell\ncargo make -e \"RELEASE_START_TIME=${RELEASE_START_TIME}\" repo\n```\n\n### Roles and keys\n\n#### Background on roles and keys\n\nTUF repos use [signed metadata](https://theupdateframework.io/metadata/) to ensure the repo content is secure and consistent.\nBottlerocket images contain a signed root role that verifies the data in the update repo they talk to.\n\nIf you run the `cargo make repo` command above without any configuration, it will generate a root role file and a signing key for you.\n\nThe generated role and key are functional, but a bit basic.\nThere's only a single key, and a \"signing threshold\" of 1, meaning only 1 key needs to sign replacement keys.\nFor production use, you should consider having multiple root keys with a higher signing threshold.\nThe benefit is that if someone compromises a single root key, TUF libraries won't trust any new keys they try to issue.\n\nIt's also a good idea to keep your key somewhere safer than your local disk.\nThis helps guard against loss of the key, which would leave you unable to update your repo.\nWe currently support storing keys in local files, in [AWS SSM Parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html), and in [AWS KMS](https://aws.amazon.com/kms/).\nSSM supports encrypted \"SecureString\" parameters for cases like this, and you can upload an existing private key into a parameter.\nKMS is even stronger in that private keys can never be uploaded or read - they're held in secure hardware.\n\nAnother improvement is to separate your root key from your \"publication\" key, where the publication key controls the snapshot, targets, and timestamp roles.\nThose three roles are updated a lot more frequently.\nThe benefit is that even if the publication key is compromised, you still control the root key, and can replace the publication key.\n\nTo use a separate publication key, you can generate two keys using [tuftool](https://github.com/awslabs/tough/tree/develop/tuftool).\nAssuming you have a root.json from `tuftool root init`, you can create keys like this:\n\n```shell\ntuftool root gen-rsa-key /path/to/root.json /path/to/my-new-root-key.pem --role root\ntuftool root gen-rsa-key /path/to/root.json /path/to/my-new-publication-key.pem --role snapshot --role targets --role timestamp\n```\n\nIf you're using keys in SSM or KMS, then you can add them to your root role with a similar command.\nFor example, with a KMS key, instead of `gen-rsa-key` you'd run `add-key` like this:\n\n```shell\ntuftool root add-key /path/to/root.json aws-kms:///abc-def-123 --role root\ntuftool root add-key /path/to/root.json aws-kms:///456-cba-fed --role snapshot --role targets --role timestamp\n```\n\n#### Role and key configuration\n\nYou can specify your own root role and your own key in `Infra.toml`.\nRoot roles and keys are associated with a specific named repo.\nThe publishing system assumes a repo named \"default\", so it's easiest to get started by using that name.\n(You can also pass `-e PUBLISH_REPO=myrepo` to `cargo make` commands to use a different name.)\n\nHere's an example repo configuration in `Infra.toml`:\n\n```toml\n[repo.default]\nroot_role_url = \"https://example.com/root.json\"\nroot_role_sha512 = \"0123456789abcdef\"\nsigning_keys = { file = { path = \"/home/user/key.pem\" } }\n```\n\nIf you have your own root role, you specify it by URL; this can be a `file://` URL for a local file.\nYou also specify the SHA512 checksum, to confirm that the file is the one you expect, in case we're downloading it from a remote URL.\nThere's nothing secret in a root role file, so if you have a way of storing it remotely, a URL can be more convenient.\n\nThe `signing_keys` portion above references a local file path.\nIf you want to use an SSM or KMS key, you'd write it like this, instead:\n\n```toml\nsigning_keys = { kms = { key_id = \"abc-def-123\" } }\n```\n\n...or...\n\n```toml\nsigning_keys = { ssm = { parameter = \"/my/parameter\" } }\n```\n\n### Repo location\n\n#### Uploading your repo\n\nYour repo needs to be accessible to your hosts by URL.\nOne good place to store repos is S3; this is how Bottlerocket's official repos are stored.\n(If you want, you can put a CloudFront distribution on top of this to make it accessible even more quickly around the world.)\nYou can also store your repo behind any HTTP server; the key part is that the repo is accessible from your host.\nThis could mean it's publicly accessible, or only accessible inside a VPC, or something similar.\n\nLet's assume you're using an S3 bucket.\nYou just need to sync the built repo, like this.\n(If you're using a repo other than `default`, make sure you change the repo name.)\n\n```shell\naws s3 sync build/repos/default/latest/ s3://my-bucket/\n```\n\nThis syncs the metadata and targets directories of the repo into the root of your bucket.\nYou can also sync to a subdirectory of your bucket if desired, for example if you use the bucket for other purposes.\nJust make sure you include that subdirectory in the URL in the next step.\n\n> Note: for production repos, it's safer to sync the targets directory before the metadata directory so that clients aren't pointed to targets they can't download yet.\n\n#### Configuring your repo location\n\nAfter your repo is uploaded, you can add the location into the repo configuration in your `Infra.toml`.\nThis will allow you to use `cargo make repo` to update your existing repo in the future, rather than creating a new one from scratch every time.\nThis is important so that your hosts can see all available updates in the repo, not just the latest one.\n\nInside the repo section of your `Infra.toml` (for example, underneath `[repo.default]`) you'd add something like this:\n\n```toml\nmetadata_base_url = \"https://example.com/\"\ntargets_url = \"https://example.com/targets/\"\n```\n\n(You can use a `file://` URL if you want to update a repo based on one you keep locally.)\n\nThe variant and architecture are automatically added onto the metadata URL, matching the format of the directories inside `build/repos/default/latest`.\n(The targets directories is shared for all variants and architectures, since target files are prefixed with a checksum.)\n\n### Using your repo from a Bottlerocket host\n\nBy default, Bottlerocket hosts talk to the project's official repos.\nThere are two ways to point your hosts at your own repo - at build time or at run time.\n\nIf you're maintaining your own fork of Bottlerocket, you'd probably want to change the settings at build time, so you don't have to change settings for every host you launch.\nIf you're just running a few hosts, or don't want to maintain a fork, then it's easier to change settings at run time.\n\nTo change your repo URLs at build time, you would change the `settings.updates.targets-base-url` and `metadata.settings.updates.metadata-base-url.template` settings.\n\nThe default settings are defined in TOML files.\nFirst, open the directory for your variant under [sources/models/src/](sources/models/src/).\nThen, open the `defaults.d` directory.\nHere, you can have any number of TOML files, or symlinks to shared TOML files, that define your default settings.\nLater files override earlier ones.\nFor an example, take a look at the [aws-ecs-2 defaults](sources/models/src/aws-ecs-2/defaults.d/).\n\nThese default settings will be applied to your hosts at startup, meaning any host you run would already know to look at your repo.\n(You'll probably want to commit your changes into your fork of the repo; we're working on ways of making it easier to maintain your own model and settings without a fork.)\n\nThe easiest way to change your repo URLs at run time is to include the settings changes in user data.\nThis method is covered [in README](README.md#using-user-data).\nFor example, if you built the `aws-k8s-1.32` variant for `x86_64` and uploaded to the public S3 bucket `my-bucket`, your URLs could look like:\n\n```toml\n[settings.updates]\ntargets-base-url = \"https://my-bucket.s3-us-west-2.amazonaws.com/targets/\"\nmetadata-base-url = \"https://my-bucket.s3-us-west-2.amazonaws.com/aws-k8s-1.32/x86_64/\"\n```\n\n### Waves\n\nWhen you release a new version, you may want to make your update available to a small number of hosts in the beginning, then gradually expand.\nThis can help mitigate the risk of the change and give you more time to detect issues before they're widespread.\n\nThe Bottlerocket update system uses the concept of 'waves' of updates.\nFor example, you can say that you want:\n* one hour before updates start, so you can prepare\n* 1% of hosts to get the update within 4 hours\n* 5% of hosts to get the update within 1 day\n* 15% of hosts to get the update within 2 days\n* 40% of hosts to get the update within 4 days\n* 60% of hosts to get the update within 5 days\n* 90% of hosts to get the update within 6 days\n* 100% of hosts to get the update after 6 days\n\nThis provides a gradual ramp-up so you can watch the status of your deployment more easily.\nAnd, in fact, this is the default wave policy!\n\nThe policy above is defined in [default-waves](sources/updater/waves/default-waves.toml).\nThere's also an [accelerated schedule](sources/updater/waves/accelerated-waves.toml) for more urgent deployments, and an [\"oh no\" schedule](sources/updater/waves/ohno.toml) for emergencies.\n\nIf you want to use a different policy, pass `-e PUBLISH_WAVE_POLICY_PATH=sources/updater/waves/chosen-policy.toml` when building your repo.\nFor example, to use the accelerated schedule:\n\n```shell\ncargo make -e PUBLISH_WAVE_POLICY_PATH=sources/updater/waves/accelerated-waves.toml repo\n```\n\nTo learn more about waves, check out the [README](sources/updater/waves).\n\n### Expiration policy\n\nEach piece of signed metadata in a TUF repo expires after a specific length of time, meaning that repos need to re-signed regularly.\nThis lets users know that the repo has been verified recently by the owner.\n\nThe [default policy](tools/pubsys/policies/repo-expiration/2w-2w-1w.toml) sets the timestamp expiration relatively short, [as recommended by TUF](https://theupdateframework.io/metadata/#timestamp-metadata-timestampjson), with the snapshot and targets expirations a bit longer.\nIf you want to use different expiration policy, you can copy and modify the existing policy, then point to your file like this:\n\n```shell\ncargo make -e PUBLISH_EXPIRATION_POLICY_PATH=/my/policy/path repo\n```\n\n**Note:** remember to update your repo before the expiration date.\nIf you forget, your hosts won't be able to talk to the repo until you update it.\n(Don't worry, they're not lost forever.)\n\nCurrently, to refresh an existing repo, you would use the [tuftool update](https://github.com/awslabs/tough/tree/develop/tuftool) command without specifying any new targets.\nWe're working on ways to make this easier, and integrated into the `cargo make` system.\n"
  },
  {
    "path": "QUICKSTART-ECS.md",
    "content": "# Using a Bottlerocket AMI with Amazon ECS\n\n[Amazon Elastic Container Service (Amazon ECS)](https://ecs.aws) is a highly scalable, fast container management service that makes it easy to run, stop, and manage containers on a cluster.\nYour containers are defined in a task definition which you use to run individual tasks or as a service.\n\nThis quickstart will walk through setting up an Amazon ECS cluster with Bottlerocket container instances (using the EC2 launch type).\nCheck out the [Amazon ECS developer guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html) for an overview of ECS.\n\n## Prerequisites\n\nBefore you begin, be sure that you've completed the steps in\n[Setting up with Amazon ECS](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/get-set-up-for-amazon-ecs.html)\nand that your AWS user has either the [`AdministratorAccess`](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AdministratorAccess) policy\nor the permissions specified in the [Amazon ECS First Run Wizard Permissions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/security_iam_id-based-policy-examples.html#first-run-permissions) IAM policy example.\n\nYou'll also need [aws-cli](https://aws.amazon.com/cli/) set up to interact with AWS.\n\n\n## Create a cluster\n\nAn Amazon ECS cluster is a logical grouping of tasks, services, and container instances.\nFor more information about clusters, see\n[Amazon ECS clusters](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html).\n\nYou can create a cluster with the AWS CLI as follows:\n\n```shell\naws ecs --region us-west-2 create-cluster --cluster-name bottlerocket\n```\n\n> Note: The command above and subsequent examples include the AWS region, so change it from `us-west-2` if you operate in another region.\n\n## Finding an AMI\n\nThe official AMI IDs are stored in [public SSM parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters.html).\nThe parameter names look like this: `/aws/service/bottlerocket/aws-ecs-2/x86_64/latest/image_id`\n\nJust change the variant (`aws-ecs-2`) and architecture (`x86_64`) to the ones you want to use.\nSupported variants and architectures are described in the [README](README.md#variants).\nFor the purposes of SSM parameters, the valid architecture names are `x86_64` and `arm64` (also known as `aarch64`).\nAlso, if you know a specific Bottlerocket version you'd like to use, for example `1.0.6`, you can replace `latest` with that version.\n\nBottlerocket ECS variants with NVIDIA support append `-nvidia` to the variant name.\nFor instance, the NVIDIA variant corresponding to `aws-ecs-2` is `aws-ecs-2-nvidia`.\n\nOnce you have the parameter name you want to use, the easiest way to use it is to pass it directly to EC2.\nJust prefix the parameter name with `resolve:ssm:` and EC2 will fetch the current value for you.\n(You can also use this method for CloudFormation and other services that launch EC2 instances for you.)\n\nFor example, to use the parameter above, you would pass this as the AMI ID in your launch request: `resolve:ssm:/aws/service/bottlerocket/aws-ecs-2/x86_64/latest/image_id`\n\n#### Manually querying SSM\n\nIf you prefer to fetch the AMI ID yourself, you can use [aws-cli](https://aws.amazon.com/cli/) on the command line.\nTo fetch the example parameter above, for the us-west-2 region, you could run this:\n\n```shell\naws ssm get-parameter --region us-west-2 --name \"/aws/service/bottlerocket/aws-ecs-2/x86_64/latest/image_id\" --query Parameter.Value --output text\n```\n\nIf you have `jq` installed and would like a bit more information, try this:\n\n```shell\naws ssm get-parameters --region us-west-2 \\\n   --names \"/aws/service/bottlerocket/aws-ecs-2/x86_64/latest/image_id\" \\\n           \"/aws/service/bottlerocket/aws-ecs-2/x86_64/latest/image_version\" \\\n   --output json | jq -r '.Parameters | .[] | \"\\(.Name): \\(.Value) (updated \\(.LastModifiedDate | gmtime | strftime(\"%c\")) UTC)\"'\n```\n\n## Launching your first instance\n\nIn order to launch a Bottlerocket instance into your ECS cluster, you'll first need some information about the resources in your AWS account.\n\n### Subnet info\n\nYou should either have a default virtual private cloud (VPC) or have already\n[created a VPC](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/get-set-up-for-amazon-ecs.html#create-a-vpc)\nin your account.\n\nTo find your default VPC, run this command.\n(If you use an AWS region other than \"us-west-2\", make sure to change that.)\n\n```shell\naws ec2 describe-vpcs \\\n   --region us-west-2 \\\n   --filters=Name=isDefault,Values=true \\\n   | jq --raw-output '.Vpcs[].VpcId'\n```\n\nIf you want to use a different VPC you created, run this to get the ID for your VPC.\nMake sure to change VPC_NAME to the name of the VPC you created.\n(If you use an EC2 region other than \"us-west-2\", make sure to change that too.)\n\n```shell\naws ec2 describe-vpcs \\\n   --region us-west-2 \\\n   --filters=Name=tag:Name,Values=VPC_NAME \\\n   | jq --raw-output '.Vpcs[].VpcId'\n```\n\nNext, run this to get information about the subnets in your VPC.\nIt will give you a list of the subnets and tell you whether each is public or private.\nMake sure to change VPC_ID to the value you received from the previous command.\n(If you use an EC2 region other than \"us-west-2\", make sure to change that too.)\n\n```shell\naws ec2 describe-subnets \\\n   --region us-west-2 \\\n   --filter=Name=vpc-id,Values=VPC_ID \\\n   | jq '.Subnets[] | {id: .SubnetId, public: .MapPublicIpOnLaunch, az: .AvailabilityZone}'\n```\n\nYou'll want to pick one and save it for the launch command later.\n\nYou can choose whether you want public or private.\n* Choose private for production deployments to get maximum isolation of instances.\n* Choose public to more easily debug your instance.\n  These subnets have an Internet Gateway, so if you add a public IP address to your instance, you can talk to it.\n  (You can manually add an Internet Gateway to a private subnet later, so this is a reversible decision.)\n\nNote that if you choose to use the public subnet, you'll need your instance to have a publicly accessible IP address.\nThat either means adding `--associate-public-ip-address` to the launch command below, or attaching an Elastic IP address after launch.\nThere will be a reminder about this when we talk about the launch command.\n\nFinally, note that if you want to launch in a specific availability zone, make sure you pick a subnet that matches; the AZ is listed right below the public/private status.\n\n### IAM role\n\nThe instance we launch needs to be associated with an IAM role that allows for communication with ECS.\n\nECS provides a\n[managed policy](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_managed_policies.html#AmazonEC2ContainerServiceforEC2Role)\nwith all of the appropriate permissions.\nIf you've used ECS before, you may already have an appropriate role in your account called `ecsInstanceRole`.\nIf you do not, you can\n[follow the instructions in the ECS Developer Guide to create a role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html).\n\nNote down the instance role name in your account for the instructions below.\n\n#### Enabling SSM\n\nIf you add SSM permissions, you can use Bottlerocket's default SSM agent to get a shell session on the instance.\n\nTo attach the role policy for SSM permissions, run the following (replacing INSTANCE_ROLE_NAME with the name of your instance role):\n\n```shell\naws iam attach-role-policy \\\n   --role-name INSTANCE_ROLE_NAME \\\n   --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\n```\n\nNext, to retrieve the instance profile name used to launch instances, run this:\n\n```shell\naws iam list-instance-profiles-for-role --role-name INSTANCE_ROLE_NAME --query \"InstanceProfiles[*].InstanceProfileName\" --output text\n```\n\nNote this down as the INSTANCE_PROFILE_NAME for the final launch command.\n\n### Connecting to your cluster\n\nFor the instance to be able to communicate with ECS, we need to make sure to configure the instance with the name of the cluster.\n\nCreate a file called `user-data.toml` with the following contents, where CLUSTER_NAME is the name of the cluster you created above (for example, \"bottlerocket\").\n\n```toml\n[settings.ecs]\ncluster = \"CLUSTER_NAME\"\n```\n\nIf you want to customize the behavior of your instance further, you can find the full set of supported settings [here](README.md#settings).\n\n### Launch!\n\nNow we can launch a Bottlerocket instance in our cluster!\n\nThere are a few values to make sure you change in this command:\n* YOUR_KEY_NAME: your SSH key pair name, as registered with EC2\n* SUBNET_ID: the subnet you selected earlier\n  * If you chose a public subnet, either add `--associate-public-ip-address` to the command, or attach an Elastic IP afterward.\n* BOTTLEROCKET_AMI_ID: the Amazon-provided AMI ID you found above, or the ID of an AMI you registered\n* user-data.toml: the path to the user data file you created earlier\n* INSTANCE_PROFILE_NAME: the IAM instance profile you created, e.g. `ecsInstanceRole`\n\n```shell\naws ec2 run-instances --key-name YOUR_KEY_NAME \\\n   --subnet-id SUBNET_ID \\\n   --image-id BOTTLEROCKET_AMI_ID \\\n   --instance-type c7.large \\\n   --region us-west-2 \\\n   --tag-specifications 'ResourceType=instance,Tags=[{Key=bottlerocket,Value=quickstart}]' \\\n   --user-data file://user-data.toml \\\n   --iam-instance-profile Name=INSTANCE_PROFILE_NAME\n```\n\nAnd remember, if you used a public subnet, add `--associate-public-ip-address` or attach an Elastic IP after launch.\n\nOnce it launches, you should be able to run tasks on your Bottlerocket instance using the ECS API and console.\n\n\n### aws-ecs-*-nvidia variants\n\nThe `aws-ecs-*-nvidia` variants include the required packages and configurations to leverage NVIDIA GPUs.\nThey come with the [NVIDIA Tesla driver](https://docs.nvidia.com/datacenter/tesla/drivers/index.html) along with the libraries required by the [NVIDIA container runtime](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit).\nIn hosts with multiple GPUs (ex. EC2 `g4dn` instances) you can assign one or multiple GPUs per container by specifying the resource requirements in your container definitions as described in the [official ECS documentation](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-gpu.html):\n\n```json\n{\n  \"containerDefinitions\": [\n     {\n        \"resourceRequirements\" : [\n            {\n               \"type\" : \"GPU\",\n               \"value\" : \"2\"\n            }\n        ]\n     }\n  ]\n}\n```\n\n### Neuron Support\n\nBottlerocket `v1.30.0+` supports Neuron Instance Types such as: `inf1`, `inf2`, `trn1`, and `trn2`. You can assign one or multiple Neuron devices per container by specifying the `linuxParameter` in the task definitions as described in the [official ECS documentation](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-inference.html):\n\n```json\n{\n  \"containerDefinitions\": [\n      {\n         \"linuxParameters\": \n            {\n                     \"devices\": [\n                        {\n                              \"containerPath\": \"/dev/neuron0\",\n                              \"hostPath\": \"/dev/neuron0\",\n                              \"permissions\": [\n                                 \"read\",\n                                 \"write\"\n                              ]\n                        }\n                     ],\n                     \"capabilities\": {\n                        \"add\": [\n                           \"IPC_LOCK\"\n                              \n                        ]\n                     }\n            },\n      }\n   ]\n}\n```\n"
  },
  {
    "path": "QUICKSTART-EKS.md",
    "content": "# Using a Bottlerocket AMI with Amazon EKS\n\nThe first release of Bottlerocket focuses on Kubernetes, in particular serving as the host OS for Kubernetes pods.\n\nOne easy way to get started is to use Amazon EKS, a service that manages a Kubernetes control plane for you.\nThis document will focus on EKS to make it easy to follow a single path.\nThere's nothing that limits Bottlerocket to EKS or AWS, though.\n\nMost of this is one-time setup, and yes, we plan to automate more of it!\nOnce you have a cluster, you can skip to the last step, [Launch!](#launch)\n\n## Dependencies\n\nEKS has a command-line tool called `eksctl` that makes cluster setup easy.\nVersions of eksctl starting with 0.15.0-rc.2 support Bottlerocket natively.\nWe recommend that you download the [latest version of eksctl](https://github.com/weaveworks/eksctl/releases) to get this support.\n\nYou'll also need to [install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) to augment `eksctl` during setup, and to run pods afterward.\n\nFinally, you'll need [aws-cli](https://aws.amazon.com/cli/) set up to interact with AWS.\n(You'll need a [recent v1 release](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html#install-tool-bundled) with EKS support.)\n\n## Automated setup\n\nIf you have a recent `eksctl`, as mentioned above, most of Bottlerocket setup for EKS is automated.\n\n### Cluster setup\n\n#### Cluster setup configuration file\n\neksctl can use a configuration file to simplify setup.\nWe have sample configuration files in the repo:\n* [`sample-eksctl.yaml`](sample-eksctl.yaml) - recommended for most setups.\n* [`sample-eksctl-ssh.yaml`](sample-eksctl-ssh.yaml) - for test clusters where you know you'll want SSH access.  Make sure to change the `publicKeyName` setting to the name of the SSH key pair you have registered with EC2.\n\nPick the file most appropriate for you and make a copy, for example `my-eksctl.yaml`.\nIn this file you can change your desired numbered of nodes and even set Bottlerocket settings in advance if you like.  The 'settings' section under 'bottlerocket' can include any [Bottlerocket settings](https://github.com/bottlerocket-os/bottlerocket#description-of-settings).\n\nNote that the configuration file includes the AWS region, so change it from `us-west-2` if you operate in another region.\n\nTo learn more about eksctl configuration files, you can look at the [full schema](https://eksctl.io/usage/schema/) or [official examples](https://github.com/weaveworks/eksctl/tree/master/examples).\n\n#### Cluster creation\n\nYou can set up a new cluster like this, pointing to the file you created in the last step:\n\n```shell\neksctl create cluster --config-file ./my-eksctl.yaml\n```\n\nThis will take a few minutes to create the EKS cluster and spin up your Bottlerocket worker nodes.\n\n#### Optional cluster configuration\n\n##### CSI plugin\n\nIf you want to create a [persistent volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) on a Bottlerocket host, you will need to use the [EBS CSI Plugin](https://github.com/kubernetes-sigs/aws-ebs-csi-driver).\nThis is because the default EBS driver relies on file system tools that are not included with Bottlerocket.\nA walk-through of creating a storage class using the driver is available [here](https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html).\n\n##### conntrack configuration\n\nBy default `kube-proxy` will set the `nf_conntrack_max` kernel parameter to a default value that may differ from what Bottlerocket originally sets at boot.\nIf you prefer to keep Bottlerocket's [default setting](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/packages/release/release-sysctl.conf), edit the kube-proxy-config ConfigMap with:\n\n```shell\nkubectl edit -n kube-system cm/kube-proxy-config\n```\n\nChange the `maxPerCore` and `min` fields for `conntrack` like so (a setting of 0 implies no change):\n\n```yaml\nconntrack:\n  maxPerCore: 0\n  min: 0\n  tcpCloseWaitTimeout: 1h0m0s\n  tcpEstablishedTimeout: 24h0m0s\n```\n\n### Done!\n\nBottlerocket instances are launched in an autoscaling group, up to the number specified in your eksctl configuration file.\n(You can change this number after creation by [configuring the ASG](https://console.aws.amazon.com/ec2/autoscaling/home#AutoScalingGroups:view=details), the same way you might change other ASGs.)\n\nThe Bottlerocket instances will automatically register into the EKS cluster created by eksctl.\nYou can now use normal Kubernetes tools like `kubectl` to manage your cluster and the Bottlerocket nodes.\n\nFor example, to run a simple busybox pod:\n`kubectl run -i -t busybox --image=busybox --restart=Never`\n\n## Manual setup\n\nIf you'd like even more control over your setup, something that eksctl can't (yet) provide, or you just want to see what's involved, you can follow these steps.\n\n### Finding an AMI\n\nThe official AMI IDs are stored in [public SSM parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters.html).\nThe parameter names look like this: `/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id`\n\nJust change the variant (`aws-k8s-1.32`) and architecture (`x86_64`) to the ones you want to use.\nSupported variants and architectures are described in the [README](README.md#variants).\nFor the purposes of SSM parameters, the valid architecture names are `x86_64` and `arm64` (also known as `aarch64`).\nAlso, if you know a specific Bottlerocket version you'd like to use, for example `1.11.0`, you can replace `latest` with that version.\n\nAll Bottlerocket EKS variants `v1.30.0+` support Neuron instance types. So, for instance, the variant for Kubernetes version 1.28 with Neuron support is `aws-k8s-1.28`.\n\nBottlerocket EKS variants with NVIDIA support append `-nvidia` to the variant name.\nFor instance, the variant for Kubernetes version 1.28 with NVIDIA support is `aws-k8s-1.28-nvidia`.\n\nOnce you have the parameter name you want to use, the easiest way to use it is to pass it directly to EC2.\n(You can also use this method for CloudFormation and other services that launch EC2 instances for you.)\nJust prefix the parameter name with `resolve:ssm:` and EC2 will fetch the current value for you.\n\nFor example, to use the parameter above, you would pass this as the AMI ID in your launch request: `resolve:ssm:/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id`\n\n#### Manually querying SSM\n\nIf you prefer to fetch the AMI ID yourself, you can use [aws-cli](https://aws.amazon.com/cli/) on the command line.\nTo fetch the example parameter above, for the us-west-2 region, you could run this:\n\n```shell\naws ssm get-parameter --region us-west-2 --name \"/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id\" --query Parameter.Value --output text\n```\n\nIf you have `jq` installed and would like a bit more information, try this:\n\n```shell\naws ssm get-parameters --region us-west-2 \\\n   --names \"/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id\" \\\n           \"/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_version\" \\\n   --output json | jq -r '.Parameters | .[] | \"\\(.Name): \\(.Value) (updated \\(.LastModifiedDate | gmtime | strftime(\"%c\")) UTC)\"'\n```\n\n### Cluster setup\n\n*Note:* most commands will have a region argument; make sure to change it if you don't want to set up in us-west-2.\nAlso be aware that when operating in GovCloud the IAM ARNs will need to be updated to the following: `arn:aws-us-gov`.\nFor example, `arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy` must be updated to\n`arn:aws-us-gov:iam::aws:policy/AmazonEKSWorkerNodePolicy`.\n\nYou can set up a new cluster like this:\n\n```shell\neksctl create cluster --region us-west-2 --name bottlerocket\n```\n\nThis will automatically add a \"context\" so `kubectl` knows how to interact with your cluster, and it'll set that context as your default.\nYou can see your contexts (clusters) using `kubectl config get-contexts` and change your current one with `kubectl config use-context 'NEW-CONTEXT-HERE'`.\n\n### Cluster info\n\nThis section helps you determine some of the cluster information needed later by the instance launch command.\n\n#### Kubernetes cluster info\n\nBottlerocket uses a TOML-formatted configuration file as user data.\nThis can include the configuration of the Kubernetes cluster we just created.\n\nRun this to generate the configuration file with the relevant cluster config, including the API endpoint and base64-encoded certificate authority.\n\n```shell\neksctl get cluster --region us-west-2 --name bottlerocket -o json \\\n   | jq --raw-output '.[] | \"[settings.kubernetes]\\napi-server = \\\"\" + .Endpoint + \"\\\"\\ncluster-certificate =\\\"\" + .CertificateAuthority.Data + \"\\\"\\ncluster-name = \\\"bottlerocket\\\"\"' > user-data.toml\n```\n\nThis will save the TOML-formatted configuration data into a file named `user-data.toml`.\nThis will be used at the end, in the instance launch command.\n\n#### Subnet info\n\nNext, run this to get information about the subnets that eksctl created.\nIt will give you a list of the subnets and tell you whether each is public or private.\n(If you use an EC2 region other than \"us-west-2\", make sure to change that.)\n\n```shell\naws ec2 describe-subnets \\\n   --subnet-ids $(eksctl get cluster --region us-west-2 --name bottlerocket -o json | jq --raw-output '.[].ResourcesVpcConfig.SubnetIds[]') \\\n   --region us-west-2 \\\n   --query \"Subnets[].[SubnetId, Tags[?Key=='aws:cloudformation:logical-id'].Value]\" \\\n   | xargs -L2\n```\n\nYou'll want to pick one and save it for the launch command later.\n\nYou can choose whether you want public or private.\n* Choose private for production deployments to get maximum isolation of worker nodes.\n* Choose public to more easily debug your instance.  These subnets have an Internet Gateway, so if you add a public IP address to your instance, you can talk to it.  (You can manually add an Internet Gateway to a private subnet later, so this is a reversible decision.)\n\nNote that if you choose to use the public subnet, you'll need your instance to have a publicly accessible IP address.\nThat either means adding `--associate-public-ip-address` to the launch command below, or attaching an Elastic IP address after launch.\nThere will be a reminder about this when we talk about the launch command.\n\nFinally, note that if you want to launch in a specific availability zone, make sure you pick a subnet that matches; the AZ is listed right next to the public/private status.\n\n### IAM role\n\nThe instance we launch needs to be associated with an IAM role that allows for communication with EKS and ECR.\n\n`eksctl` by default already creates such a role (and an instance profile that allows use of the role) as part of the cluster nodegroup.\n\nThe ARN of the IAM role can be retrieved with:\n\n```shell\neksctl get iamidentitymapping --region us-west-2 --cluster bottlerocket\n```\n\nThe output should look like this:\n\n```\nARN                                                               USERNAME                                GROUPS\narn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/INSTANCE_ROLE_NAME          system:node:{{EC2PrivateDNSName}}       system:bootstrappers,system:nodes\n```\n\nNote down the INSTANCE_ROLE_NAME for the instructions below.\n\n##### Enabling SSM\n\nIf you add SSM permissions, you can use Bottlerocket's default SSM agent to get a shell session on the instance.\n\nTo attach the role policy for SSM permissions, run the following:\n\n```shell\naws iam attach-role-policy \\\n   --role-name INSTANCE_ROLE_NAME \\\n   --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\n```\n\nIf you receive the following error, you need to truncate INSTANCE_ROLE_NAME to 64 characters.\n(We are working on improving this.)\n\n```\n1 validation error detected: Value 'INSTANCE_ROLE_NAME' at 'role Name' failed to satisfy constraint:\nMember must have length less than or equal to 64\n```\n\nNext, to retrieve the instance profile name used to launch instances, run this:\n\n```shell\naws iam list-instance-profiles-for-role --role-name INSTANCE_ROLE_NAME --query \"InstanceProfiles[*].InstanceProfileName\" --output text\n```\n\nThere should only be one that looks like:\n\n```\neksctl-bottlerocket-nodegroup-ng-IDENTIFIER-NodeInstanceProfile-IDENTIFIER\n```\n\nNote this down as the `INSTANCE_PROFILE_NAME` for the final launch command.\n\n### kube-proxy settings\n\nBy default `kube-proxy` will set the `nf_conntrack_max` kernel parameter to a default value that may differ from what Bottlerocket originally sets at boot.\nIf you prefer to keep Bottlerocket's [default setting](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/packages/release/release-sysctl.conf), edit the kube-proxy configuration details with:\n\n```shell\nkubectl edit -n kube-system daemonset kube-proxy\n```\n\nAdd `--conntrack-max-per-core` and `--conntrack-min` to the kube-proxy arguments like so (a setting of 0 implies no change):\n\n```yaml\n      containers:\n      - command:\n        - kube-proxy\n        - --v=2\n        - --config=/var/lib/kube-proxy-config/config\n        - --conntrack-max-per-core=0\n        - --conntrack-min=0\n\n```\n\n### Final launch details\n\nFor the instance to be able to communicate with the EKS cluster control plane and other worker nodes, we need to make sure the instance is launched with the right security groups.\n\nRun the following command:\n\n```shell\naws ec2 describe-security-groups --region us-west-2 \\\n  --filters 'Name=tag:Name,Values=*bottlerocket*' \\\n  --query \"SecurityGroups[*].{Name:GroupName,ID:GroupId}\"\n```\n\nThis will output several security group names and IDs.\nYou want to save the IDs for the `...ClusterSharedNodeSecurityGroup...` and `...nodegroup...` entries.\n\nExample:\n\n```json\n[\n    {\n        \"Name\": \"eksctl-bottlerocket-cluster-ClusterSharedNodeSecurityGroup-IDENTIFIER\",\n        \"ID\": \"SECURITY_GROUP_ID_1\"\n    },\n    {\n        \"Name\": \"eksctl-bottlerocket-cluster-ControlPlaneSecurityGroup-IDENTIFIER\",\n        \"ID\": *ignore*\n    },\n    {\n        \"Name\": \"eksctl-bottlerocket-nodegroup-ng-IDENTIFIER-SG-IDENTIFIER\",\n        \"ID\": \"SECURITY_GROUP_ID_2\"\n    }\n]\n```\n\nIf you chose a public subnet, and you plan to SSH to the instance (using the admin container), you'll also need to allow SSH traffic to your security group.\nYou can do that with a command like this - just make sure to insert a security group from the last command, and your source network CIDR.\n\n```shell\naws ec2 authorize-security-group-ingress --region us-west-2 \\\n   --group-id SECURITY_GROUP_ID_1 --cidr YOUR_NETWORK_CIDR \\\n   --protocol tcp --port 22\n```\n\nIf you chose a private subnet and you want to SSH in, you can do so from another instance in the same subnet and security group.\n\n### Launch!\n\nNow we can launch a Bottlerocket instance in our cluster!\n\nThere are a few values to make sure you change in this command:\n* YOUR_KEY_NAME: your SSH key pair name, as registered with EC2\n* SUBNET_ID: the subnet you selected earlier\n  * If you chose a public subnet, either add `--associate-public-ip-address` to the command, or attach an Elastic IP afterward.\n* SECURITY_GROUP_ID_1, SECURITY_GROUP_ID_2: the two security groups you found earlier\n* BOTTLEROCKET_AMI_ID: the ID of the AMI you registered, or an Amazon-provided AMI ID\n* user-data.toml: the path to the user data file you created earlier\n* INSTANCE_PROFILE_NAME: the instance profile created by `eksctl` for the cluster nodegroups.\n\n```shell\naws ec2 run-instances --key-name YOUR_KEY_NAME \\\n   --subnet-id SUBNET_ID \\\n   --security-group-ids SECURITY_GROUP_ID_1 SECURITY_GROUP_ID_2 \\\n   --image-id BOTTLEROCKET_AMI_ID \\\n   --instance-type c7.large \\\n   --region us-west-2 \\\n   --tag-specifications 'ResourceType=instance,Tags=[{Key=kubernetes.io/cluster/bottlerocket,Value=owned}]' \\\n   --user-data file://user-data.toml \\\n   --iam-instance-profile Name=INSTANCE_PROFILE_NAME\n```\n\nAnd remember, if you used a public subnet, add `--associate-public-ip-address` or attach an Elastic IP after launch.\n\nOnce it launches, you should be able to run pods on your Bottlerocket instance using normal Kubernetes workflows.\n\nFor example, to run busybox:\n`kubectl run -i -t busybox --image=busybox --restart=Never`\n\n### aws-k8s-*-nvidia variants\n\nThe `aws-k8s-*-nvidia` variants include the required packages and configurations to leverage NVIDIA GPUs.\nThey come with the [NVIDIA Tesla driver](https://docs.nvidia.com/datacenter/tesla/drivers/index.html) along with the libraries required by the [NVIDIA container runtime](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit).\nThey also include the [NVIDIA k8s device plugin](https://github.com/NVIDIA/k8s-device-plugin).\nIf you already have a daemonset for the device plugin in your cluster, you may need to use taints and tolerations to keep it from running on Bottlerocket nodes.\n\nAdditional NVIDIA tools such as [DCGM exporter](https://github.com/NVIDIA/dcgm-exporter) and [GPU Feature Discovery](https://github.com/NVIDIA/gpu-feature-discovery) will work as expected.\nYou can install them in your cluster by following the `helm install` instructions provided for each project.\n\nThe [GPU Operator](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/getting-started.html#install-nvidia-gpu-operator) can also be used to install these tools.\nHowever, it is cumbersome to select the right subset of features to avoid conflicts with the software included in the variant.\nTherefore we recommend installing the tools individually if they are required.\n\nIn hosts with multiple GPUs (ex. EC2 `g4dn` instances) you can assign a GPU per container by specifying the resource in the containers' spec as described in the [official kubernetes documentation](https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/):\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: test\nspec:\n  restartPolicy: OnFailure\n  containers:\n    - name: test\n      image: amazonlinux:2\n      resources:\n        limits:\n          nvidia.com/gpu: 1 # requesting 1 GPU\n```\n\n### Neuron Support\nBottlerocket `v1.30.0+` supports Neuron Instance Types such as: `inf1`, `inf2`, `trn1`, and `trn2`. To enable Neuron workloads, you will need the following user-data configurations:\n\n```toml\n[settings]\n[settings.kubernetes]\ndevice-ownership-from-security-context = true\n```\nThis setting allows the container to take ownership of the mounted Neuron device based on the `runAsUser` and `runAsGroup` values provided in the spec.\nFor more details on this, see the [Kubernetes documentation](https://kubernetes.io/blog/2021/11/09/non-root-containers-and-devices/):\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: test\nspec:\n  hostNetwork: true\n  securityContext:\n    runAsUser: 1001\n    runAsGroup: 2001\n    fsGroup: 3001\n  restartPolicy: OnFailure\n  containers:\n  - name: test\n    image: amazonlinux:2023\n    resources:\n      limits:\n        aws.amazon.com/neuron: \"1\"\n```\n\nAlong with the `device-ownership-from-secuirity-context` setting, you will need to deploy the [neuron-device-plugin](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/containers/kubernetes-getting-started.html#neuron-device-plugin), and optionally, the [neuron-scheduler](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/containers/kubernetes-getting-started.html#neuron-scheduler-extension).\n"
  },
  {
    "path": "QUICKSTART-LOCAL.md",
    "content": "# Testing Bottlerocket in a local virtual machine\n\nThis quickstart will walk through launching a Bottlerocket VM guest on a local machine using QEMU and KVM.\nThe VM will not join an ECS or Kubernetes cluster.\nThis way of running Bottlerocket is therefore best used for testing purposes when developing Bottlerocket components that do not need to integrate with any orchestrators or to just get a feel for what a Bottlerocket node looks from the inside.\n\n\n## Prerequisites\n\nWe assume you are following along on a machine running Fedora.\nIf you are using a cloud VM, ensure you can use hardware-assisted virtualization.\nFor example, on Amazon EC2 this requires the use of a .metal instance type.\n\nYou need a clone of the main Bottlerocket repository and a build of the metal-dev variant.\nPlease refer to [`BUILDING.md`](https://github.com/bottlerocket-os/bottlerocket/blob/develop/BUILDING.md) for instructions on how to build a Bottlerocket image and ensure you pass `-e BUILDSYS_VARIANT=metal-dev` to `cargo make`.\n\nThe use of QEMU requires extra packages which you may install using this dnf invocation:\n\n```shell\nsudo dnf install qemu\n```\n\nIf you'd (optionally) like to make use of the control container, you'll need an AWS account and AWS CLI.\n\n\n## Configuring Bottlerocket\n\nBottlerocket is configured [via an API](https://github.com/bottlerocket-os/bottlerocket/#using-the-api-client) or, if running in a cloud VM, [via user data](https://github.com/bottlerocket-os/bottlerocket/#using-user-data) upon boot.\nFor running a local VM, neither mechanism can be used to apply configuration on first boot: Bottlerocket is not yet running, making its API server unavailable, and the goal to have Bottlerocket running locally precludes use of the user data mechanism.\nAs an alternative, the `start-local-vm` wrapper script included in the `tools` directory of the main repository allows to inject configuration into well-known locations of the built image for Bottlerocket to find on boot.\n\n\n### Set up networking\n\nThe `start-local-vm` wrapper configures QEMU to provide one virtual network interface to the VM.\nTo enable this interface, create a file named `net.toml` containing the following TOML snippet:\n\n```toml\nversion = 1\n\n[enp0s16]\ndhcp4 = true\n```\n\nThis will prompt [netdog](https://github.com/bottlerocket-os/bottlerocket/blob/develop/sources/netdog/README.md) to set up `enp0s16` as the primary network interface with IPv4 networking configured via DHCP.\nNo dedicated DHCP server needs to be running on the host as QEMU will act as one on the virtual network interface.\nNote that for virtual machines launched with `start-local-vm`, the primary network interface will always be named `enp0s16`.\nThe name will differ when running on bare metal or in a cloud environment.\n\n\n### Accessing your Bottlerocket guest via host containers\n\nWhen running a Bottlerocket development variant such as metal-dev locally, you can directly interact with the system via the serial console that `start-local-vm` connects you to.\nFor remote access to your running Bottlerocket VMs, you will need to provide additional configuration to enable host containers.\nThe Bottlerocket metal images don't include any host containers enabled by default.\nBut don't worry!\nYou can use our [admin](https://github.com/bottlerocket-os/bottlerocket-admin-container) and/or [control](https://github.com/bottlerocket-os/bottlerocket-control-container) containers, they just need to be configured first.\nInformation about the roles these host containers play can be found [here](https://github.com/bottlerocket-os/bottlerocket/#exploration).\n\n\n#### Admin container\n\nIf you would like to use the admin container, you will need to create some base64 encoded user data which will be passed to the container at runtime.\nFull details are covered in the [admin container documentation](https://github.com/bottlerocket-os/bottlerocket-admin-container#authenticating-with-the-admin-container).\nIf we assume you have a public key at `${HOME}/.ssh/id_rsa.pub`, the below will add the correct user data to your `user-data.toml`.\n\n```shell\nPUBKEY_FILE=\"${HOME}/.ssh/id_rsa.pub\"\nPUBKEY=$(< \"${PUBKEY_FILE}\")\nADMIN_USER_DATA=\"$(echo '{\"ssh\": {\"authorized-keys\": [\"'\"${PUBKEY}\"'\"]}}' | base64 -w 0)\"\n\ncat <<EOF >>user-data.toml\n[settings.host-containers.admin]\nenabled = true\nsuperpowered = true\nuser-data = \"${ADMIN_USER_DATA}\"\nsource = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.1\"\nEOF\n```\n\n\n#### Control container\n\nEnabling the control container is very similar to the admin container; you will create some base64 encoded user data that will be passed to the container at runtime.\nThis user data includes an activation ID and code retrieved from AWS SSM.\nFull details can be found in the [control container documentation](https://github.com/bottlerocket-os/bottlerocket-control-container#connecting-to-aws-systems-manager-ssm).\n\nYou'll first need an AWS account, and AWS CLI installed.\nThen you'll create a service role in that account to [grant AWS STS trust to the AWS Systems Manager service](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-service-role.html).\n\n```shell\ncat <<EOF > ssmservice-trust.json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": {\n        \"Effect\": \"Allow\",\n        \"Principal\": {\n            \"Service\": \"ssm.amazonaws.com\"\n        },\n        \"Action\": \"sts:AssumeRole\"\n    }\n}\nEOF\n\n# Create the role using the above policy\naws iam create-role \\\n    --role-name SSMServiceRole \\\n    --assume-role-policy-document file://ssmservice-trust.json\n\n# Attach the policy enabling the role to create session tokens\naws iam attach-role-policy \\\n    --role-name SSMServiceRole \\\n    --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\n```\n\nOnce the above is created, we can use the role to create an activation code and ID.\n\n```shell\nexport SSM_ACTIVATION=\"$(aws ssm create-activation \\\n  --iam-role SSMServiceRole \\\n  --registration-limit 100 \\\n  --region us-west-2 \\\n  --output json)\"\n```\n\nUsing the above activation data we can create our user data to pass to the control container:\n\n```shell\nSSM_ACTIVATION_ID=\"$(jq -r '.ActivationId' <<< ${SSM_ACTIVATION})\"\nSSM_ACTIVATION_CODE=\"$(jq -r '.ActivationCode' <<< ${SSM_ACTIVATION})\"\nCONTROL_USER_DATA=\"$(echo '{\"ssm\": {\"activation-id\": \"'${SSM_ACTIVATION_ID}'\", \"activation-code\": \"'${SSM_ACTIVATION_CODE}'\", \"region\": \"us-west-2\"}}' | base64 -w0)\"\n\ncat <<EOF >>user-data.toml\n[settings.host-containers.control]\nenabled = true\nuser-data = \"${CONTROL_USER_DATA}\"\nsource = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.1\"\nEOF\n```\n\n\n## Launch!\n\nWe have now prepared all configuration we might need.\nAssuming you are in the root of the main Bottlerocket repository, you can run\n\n```shell\n./tools/start-local-vm --variant metal-dev --arch $(uname -m) --inject-file net.toml --inject-file user-data.toml\n```\n\nto start a local VM with the Bottlerocket image you built earlier.\n\nThe `--inject-file` options add the listed files to the private partition of the image, where Bottlerocket's various services will find them on boot.\nThe final configuration files ending up in the image need to be named like in the examples above.\nIf you named yours differently, you can ensure they have the right name in the image by using a colon as the separator of local file name and file name in the image, e.g. `--inject-file admin-container-only.toml:user-data.toml`.\nIf you did not enable any host containers and thus have no `user-data.toml` you need to leave this option off.\n\nOnce the VM launches, boot output will be visible in the terminal.\nThe `start-local-vm` script connects you to the serial console of the VM, which can also be used to interact with the system if you are running a development variant such as metal-dev.\nWhen prompted to login, any username will do.\n\nThe virtual serial console will capture most keyboard input, such as Ctrl-C.\nIf you want to terminate the VM, you can either instruct it to `systemctl poweroff` from within or exit QEMU via the Ctrl-A X shortcut.\n\nBy default, the `start-local-vm` wrapper will forward the host's TCP port 2222 to the VM's port 22.\nIf you enabled the admin host container, the SSH server running in it will therefore be available by connecting to localhost's port 2222:\n\n```shell\nssh -p 2222 ec2-user@localhost\n```\n"
  },
  {
    "path": "QUICKSTART-VMWARE.md",
    "content": "# Using Bottlerocket as a Kubernetes worker node with VMware\n\nThis quickstart will walk through joining a Bottlerocket VM guest to an existing Kubernetes cluster running in VMware.\n\n## Prerequisites\n\nYou must be able to access vSphere, via webUI or some type of client.\nWe will use the CLI tool [`govc`](https://github.com/vmware/govmomi/tree/master/govc) to communicate with vSphere in this guide.\n`govc` can use [environment variables or take arguments](https://github.com/vmware/govmomi/tree/master/govc#usage) to specify needed parameters.\nFor the purposes of this guide we will assume that the following environment variables are set to the proper values in your environment:\n\n```\nGOVC_URL\nGOVC_USERNAME\nGOVC_PASSWORD\nGOVC DATACENTER\nGOVC_DATASTORE\nGOVC_NETWORK\nGOVC_RESOURCE_POOL\nGOVC_FOLDER\n```\n\nThis guide assumes you already have a functioning Kubernetes cluster running in VMware.\nYou'll need to have [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl) and [`kubeadm`](https://kubernetes.io/docs/tasks/tools/#kubeadm) installed, as well as a `kubeconfig` for your cluster.\nThese tools allow us to access information about your cluster to facilitate the joining of Bottlerocket nodes.\n\nYou'll need to install [`tuftool`](https://github.com/awslabs/tough/blob/develop/tuftool/README.md) to assist you with fetching the signed Bottlerocket OVA from the Bottlerocket TUF repository.\n\n`jq` should also be installed.\n\nIf you'd (optionally) like to make use of the control container, you'll need an AWS account and AWS CLI.\n\n## Fetch the OVA\n\nThe Bottlerocket OVA is signed and uploaded alongside the rest of the Bottlerocket release artifacts.\n\nYou first need the Bottlerocket root role, which is used by `tuftool` to verify the OVA.\nThe following will download and verify the root role itself:\n\n```shell\ncurl -O \"https://cache.bottlerocket.aws/root.json\"\nsha512sum -c <<<\"4fcb272345fd6adb94d4c04834400548178fecb57407ca79bc2c3d20e0428fc9ed3a82cea268d7f9c667b5803524a4f465acd701a86953d5d732bf6ecb064888  root.json\"\n```\n\nNext, set your desired version and variant, and download the OVA:\n\n```shell\nVERSION=\"v1.31.0\"\nVARIANT=\"vmware-k8s-1.32\"\nOVA=\"bottlerocket-${VARIANT}-x86_64-${VERSION}.ova\"\nOUTDIR=\"${VARIANT}-${VERSION}\"\n\ntuftool download \"${OUTDIR}\" --target-name \"${OVA}\" \\\n   --root ./root.json \\\n   --metadata-url \"https://updates.bottlerocket.aws/2020-07-07/${VARIANT}/x86_64/\" \\\n   --targets-url \"https://updates.bottlerocket.aws/targets/\"\n```\n\n## Upload the OVA\n\nOnce you have downloaded the OVA, you can upload it to vSphere.\n\nThe first command generates a spec file (`bottlerocket_spec.json` in this case) using the OVA and gives you few options for your deployment.\n\n```shell\ngovc import.spec \"${OUTDIR}/${OVA}\" > bottlerocket_spec.json\n```\n\nThe spec will look similar to this:\n\n```json\n{\n  \"DiskProvisioning\": \"flat\",\n  \"IPAllocationPolicy\": \"dhcpPolicy\",\n  \"IPProtocol\": \"IPv4\",\n  \"NetworkMapping\": [\n    {\n      \"Name\": \"VM Network\",\n      \"Network\": \"\"\n    }\n  ],\n  \"MarkAsTemplate\": false,\n  \"PowerOn\": false,\n  \"InjectOvfEnv\": false,\n  \"WaitForIP\": false,\n  \"Name\": null\n}\n```\n\nWe will use `$GOVC_NETWORK` to populate the value for `Network` in the file and use it to upload the OVA!\n\n```shell\nVM_NAME=\"bottlerocket-quickstart-${VERSION}\"\n\njq --arg network \"${GOVC_NETWORK}\" \\\n  '.NetworkMapping[].Network = $network' \\\n  bottlerocket_spec.json > bottlerocket_spec_edit.json\n\ngovc import.ova -options=bottlerocket_spec_edit.json -name=\"${VM_NAME}\" \"${OUTDIR}/${OVA}\"\n```\n\nSince we intend to run multiple identical VMs, let's mark the OVA you just uploaded as a template.\nYou can think of a template as a \"golden\" image, allowing you to create many VMs without affecting the \"golden\" image.\n\n```shell\ngovc vm.markastemplate \"${VM_NAME}\"\n```\n\nLet's create 3 Bottlerocket VMs using the template.\nThe following will clone from the template, but leave the VMs turned off since we still need to set user data.\n\n```shell\nfor node in 1 2 3; do\n  govc vm.clone -vm \"${VM_NAME}\" -on=false \"${VM_NAME}-${node}\"\ndone\n```\n\n## Gathering cluster info\n\nThis section will help you gather cluster information needed to configure Bottlerocket via user data.\nThe below commands assume a single cluster.\n\n#### API Server\nThis is the address (including port) of the control plane.\n\n```shell\nexport API_SERVER=\"$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')\"\n```\n\n#### Cluster DNS IP\nThis is the IP address of the DNS pod/service.\n\n```shell\nexport CLUSTER_DNS_IP=\"$(kubectl -n kube-system get svc -l k8s-app=kube-dns -o=jsonpath='{.items[0].spec.clusterIP}')\"\n```\n\n#### Bootstrap token\nNodes require a token to establish trust between the node and the control plane.\nTokens must be [used within 24 hours](https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-token/), but once the node has booted and registered with the cluster, it isn't used again.\n\n```shell\nexport BOOTSTRAP_TOKEN=\"$(kubeadm token create)\"\n```\n\n#### Cluster Certificate\nThis is the base64 encoded cluster certificate authority.\n\n```shell\nexport CLUSTER_CERTIFICATE=\"$(kubectl config view --raw -o=jsonpath='{.clusters[0].cluster.certificate-authority-data}')\"\n```\n\n## Configuring Bottlerocket\n\nIn order to join Bottlerocket to your cluster, it must be configured via user data.\nThere are multiple methods of passing user data to Bottlerocket in VMware; we will demonstrate all of them.\n\nCreate a file called `user-data.toml` and populate it with the values you just retrieved.\n\n```shell\ncat <<EOF > user-data.toml\n[settings.kubernetes]\napi-server = \"${API_SERVER}\"\ncluster-dns-ip = \"${CLUSTER_DNS_IP}\"\nbootstrap-token = \"${BOOTSTRAP_TOKEN}\"\ncluster-certificate = \"${CLUSTER_CERTIFICATE}\"\nEOF\n```\n\n### Accessing your Bottlerocket guest via host containers\nFor remote access to your running Bottlerocket VMs, you will need to add additional user data to enable host containers.\nThe Bottlerocket VMware images don't include any host containers enabled by default.\nBut don't worry!\nYou can use our [admin](https://github.com/bottlerocket-os/bottlerocket-admin-container) and/or [control](https://github.com/bottlerocket-os/bottlerocket-control-container) containers, they just need to be configured first.\n\n#### Admin container\nIf you would like to use the admin container, you will need to create some base64 encoded user data which will be passed to the container at runtime.\nFull details are covered in the [admin container documentation](https://github.com/bottlerocket-os/bottlerocket-admin-container#authenticating-with-the-admin-container).\nIf we assume you have a public key at `${HOME}/.ssh/id_rsa.pub`, the below will add the correct user data to your `user-data.toml`.\n\n```shell\nPUBKEY=\"${HOME}/.ssh/id_rsa.pub\"\nADMIN_USER_DATA=\"$(echo '{\"ssh\":{\"authorized-keys\":[\"'\"$(cat ${PUBKEY})\"'\"]}}' | base64 -w 0)\"\n\ncat <<EOF >>user-data.toml\n[settings.host-containers.admin]\nenabled = true\nuser-data = \"${ADMIN_USER_DATA}\"\nEOF\n```\n\n#### Control container\nEnabling the control container is very similar to the admin container; you will create some base64 encoded user data that will be passed to the container at runtime.\nThis user data includes an activation ID and code retrieved from AWS SSM.\nFull details can be found in the [control container documentation](https://github.com/bottlerocket-os/bottlerocket-control-container#connecting-to-aws-systems-manager-ssm).\n\nYou'll first need an AWS account, and AWS CLI installed.\nThen you'll create a service role in that account to [grant AWS STS trust to the AWS Systems Manager service](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-service-role.html).\n\n```shell\ncat <<EOF > ssmservice-trust.json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": {\n        \"Effect\": \"Allow\",\n        \"Principal\": {\n            \"Service\": \"ssm.amazonaws.com\"\n        },\n        \"Action\": \"sts:AssumeRole\"\n    }\n}\nEOF\n\n# Create the role using the above policy\naws iam create-role \\\n    --role-name SSMServiceRole \\\n    --assume-role-policy-document file://ssmservice-trust.json\n\n# Attach the policy enabling the role to create session tokens\naws iam attach-role-policy \\\n    --role-name SSMServiceRole \\\n    --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\n```\n\nOnce the above is created, we can use the role to create an activation code and ID.\n\n```shell\nexport SSM_ACTIVATION=\"$(aws ssm create-activation \\\n  --iam-role SSMServiceRole \\\n  --registration-limit 100 \\\n  --region us-west-2 \\\n  --output json)\"\n```\n\nUsing the above activation data we can create our user data to pass to the control container:\n\n```shell\nSSM_ACTIVATION_ID=\"$(jq -r '.ActivationId' <<< ${SSM_ACTIVATION})\"\nSSM_ACTIVATION_CODE=\"$(jq -r '.ActivationCode' <<< ${SSM_ACTIVATION})\"\nCONTROL_USER_DATA=\"$(echo '{\"ssm\":{\"activation-id\":\"'${SSM_ACTIVATION_ID}'\",\"activation-code\":\"'${SSM_ACTIVATION_CODE}'\",\"region\":\"us-west-2\"}}' | base64 -w0)\"\n\ncat <<EOF >>user-data.toml\n[settings.host-containers.control]\nenabled = true\nuser-data = \"${CONTROL_USER_DATA}\"\nEOF\n```\n\n### Setting user data via \"guestinfo\" interface\n**Note: You must set these values before you start the VM for the first time!**\n\nVMware allows you to set some extended attributes of your VM, which your VM can then access via a \"guestinfo\" interface.\nThese extended attributes are `guestinfo.userdata` and `guestinfo.userdata.encoding`.\n\n`guestinfo.userdata` may be passed as base64, gzipped base64, or (least desirable) raw TOML.\nValid values for `guestinfo.userdata.encoding` are: `base64`, `b64`, `gzip+base64`, and `gz+b64`.\n\nGiven the above file `user-data.toml`, base64 encode and set user data for your VM:\n```shell\nexport BR_USERDATA=$(base64 -w0 user-data.toml)\n\nfor node in 1 2 3; do\n  govc vm.change -vm \"${VM_NAME}-${node}\" \\\n    -e guestinfo.userdata=\"${BR_USERDATA}\" \\\n    -e guestinfo.userdata.encoding=\"base64\"\ndone\n```\n\nYou can check that your user data was set; using node \"1\" as an example below:\n```shell\ngovc vm.info -e -r -t \"${VM_NAME}-1\"\n```\n\n## Launch!\nOnce you've created your user data and given your VM a way to access it via guestinfo, you can launch all 3 Bottlerocket VMs in your cluster!\n```shell\nfor node in 1 2 3; do\n  govc vm.power -on \"${VM_NAME}-${node}\"\ndone\n```\n\nOnce it launches, you should be able to use your Bottlerocket instance using normal Kubernetes workflows.\nAll boot output should be visible in the vSphere console if you need to troubleshoot.\n"
  },
  {
    "path": "README.md",
    "content": "# Bottlerocket OS\n\nWelcome to Bottlerocket!\n\nBottlerocket is a free and open-source Linux-based operating system meant for hosting containers.\n\nTo learn more about Bottlerocket, visit the [official Bottlerocket website and documentation](https://bottlerocket.dev/).\nOtherwise, if you’re ready to jump right in, read one of our setup guides for running Bottlerocket in [Amazon EKS](QUICKSTART-EKS.md), [Amazon ECS](QUICKSTART-ECS.md), or [VMware](QUICKSTART-VMWARE.md).\nIf you're interested in running Bottlerocket on bare metal servers, please refer to the [provisioning guide](PROVISIONING-METAL.md) to get started.\n\nBottlerocket focuses on security and maintainability, providing a reliable, consistent, and safe platform for container-based workloads.\nThis is a reflection of what we've learned building operating systems and services at Amazon.\nYou can read more about what drives us in [our charter](CHARTER.md).\n\nThe base operating system has just what you need to run containers reliably, and is built with standard open-source components.\nBottlerocket-specific additions focus on reliable updates and on the API.\nInstead of making configuration changes manually, you can change settings with an API call, and these changes are automatically migrated through updates.\n\nSome notable features include:\n\n* [API access](#api) for configuring your system, with secure out-of-band [access methods](#exploration) when you need them.\n* [Updates](#updates) based on partition flips, for fast and reliable system updates.\n* [Modeled configuration](#settings) that's automatically migrated through updates.\n* [Security](#security) as a top priority.\n\n## Participate in the Community\n\nThere are many ways to take part in the Bottlerocket community:\n\n- [Join us on Meetup](https://www.meetup.com/bottlerocket-community/) to hear about the latest Bottlerocket (virtual/in-person) events and community meetings.\n  Community meetings are typically every other week.\n\n  Details can be found under the [Events section on Meetup](https://www.meetup.com/bottlerocket-community/events/), and you will receive email notifications if you become a member of the Meetup group. (It's free to join!)\n\n- [Start or join a discussion](https://github.com/bottlerocket-os/bottlerocket/discussions) if you have questions about Bottlerocket.\n- If you're interested in contributing, thank you!\n  Please see our [contributor's guide](CONTRIBUTING.md).\n\n## Contact us\n\nIf you find a security issue, please [contact our security team](https://github.com/bottlerocket-os/bottlerocket/security/policy) rather than opening an issue.\n\nWe use GitHub issues to track other bug reports and feature requests.\nYou can look at [existing issues](https://github.com/bottlerocket-os/bottlerocket/issues) to see whether your concern is already known.\n\nIf not, you can select from a few templates and get some guidance on the type of information that would be most helpful.\n[Contact us with a new issue here.](https://github.com/bottlerocket-os/bottlerocket/issues/new/choose)\n\nWe don't have other communication channels set up quite yet, but don't worry about making an issue or a discussion thread!\nYou can let us know about things that seem difficult, or even ways you might like to help.\n\n## Variants\n\nTo start, we're focusing on the use of Bottlerocket as a host OS in AWS EKS Kubernetes clusters and Amazon ECS clusters.\nWe’re excited to get early feedback and to continue working on more use cases!\n\nBottlerocket is architected such that different cloud environments and container orchestrators can be supported in the future.\nA build of Bottlerocket that supports different features or integration characteristics is known as a 'variant'.\nThe artifacts of a build will include the architecture and variant name.\nFor example, an `x86_64` build of the `aws-k8s-1.32` variant will produce an image named `bottlerocket-aws-k8s-1.32-x86_64-<version>-<commit>.img`.\n\nThe following variants support EKS, as described above:\n\n* `aws-k8s-1.29`\n* `aws-k8s-1.30`\n* `aws-k8s-1.31`\n* `aws-k8s-1.32`\n* `aws-k8s-1.33`\n* `aws-k8s-1.34`\n* `aws-k8s-1.35`\n* `aws-k8s-1.29-nvidia`\n* `aws-k8s-1.30-nvidia`\n* `aws-k8s-1.31-nvidia`\n* `aws-k8s-1.32-nvidia`\n* `aws-k8s-1.33-nvidia`\n* `aws-k8s-1.34-nvidia`\n* `aws-k8s-1.35-nvidia`\n\nThe following variants support ECS:\n\n* `aws-ecs-2`\n* `aws-ecs-2-nvidia`\n* `aws-ecs-3`\n* `aws-ecs-3-fips`\n* `aws-ecs-3-nvidia`\n\nWe also have variants that are designed to be Kubernetes worker nodes in VMware:\n\n* `vmware-k8s-1.29`\n* `vmware-k8s-1.30`\n* `vmware-k8s-1.31`\n* `vmware-k8s-1.32`\n* `vmware-k8s-1.33`\n* `vmware-k8s-1.34`\n* `vmware-k8s-1.35`\n\nThe following variants are no longer supported:\n\n* All Kubernetes variants using Kubernetes 1.28 and earlier\n* VMware variants using Kubernetes 1.28 and earlier\n* Bare metal variants for Kubernetes\n* ECS-1 variants\n\nWe recommend users replace nodes running these variants with the [latest variant compatible with their cluster](variants/).\n\n## Architectures\n\nOur supported architectures include `x86_64` and `aarch64` (written as `arm64` in some contexts).\n\n## Setup\n\n:walking: :running:\n\nBottlerocket is best used with a container orchestrator.\nTo get started with Kubernetes in Amazon EKS, please see [QUICKSTART-EKS](QUICKSTART-EKS.md).\nTo get started with Kubernetes in VMware, please see [QUICKSTART-VMWARE](QUICKSTART-VMWARE.md).\nTo get started with Amazon ECS, please see [QUICKSTART-ECS](QUICKSTART-ECS.md).\nThese guides describe:\n\n* how to set up a cluster with the orchestrator, so your Bottlerocket instance can run containers\n* how to launch a Bottlerocket instance in EC2 or VMware\n\nTo see how to provision Bottlerocket on bare metal, see [PROVISIONING-METAL](PROVISIONING-METAL.md).\n\nTo build your own Bottlerocket images, please see [BUILDING](BUILDING.md).\nIt describes:\n\n* how to build an image\n* how to register an EC2 AMI from an image\n\nTo publish your built Bottlerocket images, please see [PUBLISHING](PUBLISHING.md).\nIt describes:\n\n* how to make TUF repos including your image\n* how to copy your AMI across regions\n* how to mark your AMIs public or grant access to specific accounts\n* how to make your AMIs discoverable using [SSM parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html)\n\n## Exploration\n\nTo improve security, there's no SSH server in a Bottlerocket image, and not even a shell.\n\nDon't panic!\n\nThere are a couple out-of-band access methods you can use to explore Bottlerocket like you would a typical Linux system.\nEither option will give you a shell within Bottlerocket.\nFrom there, you can [change settings](#settings), manually [update Bottlerocket](#updates), debug problems, and generally explore.\n\n**Note:** These methods require that your instance has permission to access the ECR repository where these containers live; the appropriate policy to add to your instance's IAM role is `AmazonEC2ContainerRegistryReadOnly`.\n\n### Control container\n\nBottlerocket has a [\"control\" container](https://github.com/bottlerocket-os/bottlerocket-control-container), enabled by default, that runs outside of the orchestrator in a separate instance of containerd.\nThis container runs the [AWS SSM agent](https://github.com/aws/amazon-ssm-agent) that lets you run commands, or start shell sessions, on Bottlerocket instances in EC2.\n(You can easily replace this control container with your own just by changing the URI; see [Settings](#settings).)\n\nIn AWS, you need to give your instance the SSM role for this to work; see the [setup guide](QUICKSTART-EKS.md#enabling-ssm).\nOutside of AWS, you can use [AWS Systems Manager for hybrid environments](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-managedinstances.html).\nThere's more detail about hybrid environments in the [control container documentation](https://github.com/bottlerocket-os/bottlerocket-control-container/#connecting-to-aws-systems-manager-ssm).\n\nOnce the instance is started, you can start a session:\n\n* Go to AWS SSM's [Session Manager](https://console.aws.amazon.com/systems-manager/session-manager/sessions)\n* Select \"Start session\" and choose your Bottlerocket instance\n* Select \"Start session\" again to get a shell\n\nIf you prefer a command-line tool, you can start a session with a recent [AWS CLI](https://aws.amazon.com/cli/) and the [session-manager-plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html).\nThen you'd be able to start a session using only your instance ID, like this:\n\n```shell\naws ssm start-session --target INSTANCE_ID --region REGION_CODE\n```\n\nWith the [default control container](https://github.com/bottlerocket-os/bottlerocket-control-container), you can make [API calls](#api) to configure and manage your Bottlerocket host.\nTo do even more, read the next section about the [admin container](#admin-container).\nYou can access the admin container from the control container like this:\n\n```shell\nenter-admin-container\n```\n\n### Admin container\n\nBottlerocket has an [administrative container](https://github.com/bottlerocket-os/bottlerocket-admin-container), disabled by default, that runs outside of the orchestrator in a separate instance of containerd.\nThis container has an SSH server that lets you log in as `ec2-user` using your EC2-registered SSH key.\nOutside of AWS, you can [pass in your own SSH keys](https://github.com/bottlerocket-os/bottlerocket-admin-container#authenticating-with-the-admin-container).\n(You can easily replace this admin container with your own just by changing the URI; see [Settings](#settings).\n\nTo enable the container, you can change the setting in user data when starting Bottlerocket, for example EC2 instance user data:\n\n```toml\n[settings.host-containers.admin]\nenabled = true\n```\n\nIf Bottlerocket is already running, you can enable the admin container from the default [control container](#control-container) like this:\n\n```shell\nenable-admin-container\n```\n\nOr you can start an interactive session immediately like this:\n\n```shell\nenter-admin-container\n```\n\nIf you're using a custom control container, or want to make the API calls directly, you can enable the admin container like this instead:\n\n```shell\napiclient set host-containers.admin.enabled=true\n```\n\nOnce you've enabled the admin container, you can either access it through SSH or execute commands from the control container like this:\n\n```shell\napiclient exec admin bash\n```\n\nOnce you're in the admin container, you can run `sheltie` to get a full root shell in the Bottlerocket host.\nBe careful; while you can inspect and change even more as root, Bottlerocket's filesystem and dm-verity setup will prevent most changes from persisting over a restart - see [Security](#security).\n\n## Updates\n\nRather than a package manager that updates individual pieces of software, Bottlerocket downloads a full filesystem image and reboots into it.\nIt can automatically roll back if boot failures occur, and workload failures can trigger manual rollbacks.\n\nThe update process uses images secured by [TUF](https://theupdateframework.github.io/).\nFor more details, see the [update system documentation](sources/updater/).\n\n### Update methods\n\nThere are several ways of updating your Bottlerocket hosts.\nWe provide tools for automatically updating hosts, as well as an API for direct control of updates.\n\n#### Automated updates\n\nFor EKS variants of Bottlerocket, we recommend using the [Bottlerocket update operator](https://github.com/bottlerocket-os/bottlerocket-update-operator) for automated updates.\n\nFor the ECS variant of Bottlerocket, we recommend using the [Bottlerocket ECS updater](https://github.com/bottlerocket-os/bottlerocket-ecs-updater/) for automated updates.\n\n#### Update API\n\nThe [Bottlerocket API](#api) includes methods for checking and starting system updates.\nYou can read more about the update APIs in our [update system documentation](sources/updater/README.md#update-api).\n\napiclient knows how to handle those update APIs for you, and you can run it from the [control](#control-container) or [admin](#admin-container) containers.\n\nTo see what updates are available:\n\n```shell\napiclient update check\n```\n\nIf an update is available, it will show up in the `chosen_update` field.\nThe `available_updates` field will show the full list of available versions, including older versions, because Bottlerocket supports safely rolling back.\n\nTo apply the latest update:\n\n```shell\napiclient update apply\n```\n\nThe next time you reboot, you'll start up in the new version, and system configuration will be automatically [migrated](sources/api/migration/).\nTo reboot right away:\n\n```shell\napiclient reboot\n```\n\nIf you're confident about updating, the `apiclient update apply` command has `--check` and `--reboot` flags to combine the above actions, so you can accomplish all of the above steps like this:\n\n```shell\napiclient update apply --check --reboot\n```\n\nSee the [apiclient documentation](sources/api/apiclient/) for more details.\n\n### Update rollback\n\nThe system will automatically roll back if it's unable to boot.\nIf the update is not functional for a given container workload, you can do a manual rollback:\n\n```shell\nsignpost rollback-to-inactive\nreboot\n```\n\nThis doesn't require any external communication, so it's quicker than `apiclient`, and it's made to be as reliable as possible.\n\n## Settings\n\nHere we'll describe the settings you can configure on your Bottlerocket instance, and how to do it.\n\n(API endpoints are defined in our [OpenAPI spec](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/api/openapi.yaml) if you want more detail.)\n\n### Interacting with settings\n\n#### Using the API client\n\nYou can see the current settings with an API request:\n\n```shell\napiclient get settings\n```\n\nThis will return all of the current settings in JSON format.\nFor example, here's an abbreviated response:\n\n```json\n{\"motd\": \"...\", {\"kubernetes\": {}}}\n```\n\nYou can change settings like this:\n\n```shell\napiclient set motd=\"hi there\" kubernetes.node-labels.environment=test\n```\n\nYou can also use a JSON input mode to help change many related settings at once, and a \"raw\" mode if you want more control over how the settings are committed and applied to the system.\nSee the [apiclient README](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/api/apiclient/) for details.\n\n#### Using user data\n\nIf you know what settings you want to change when you start your Bottlerocket instance, you can send them in the user data.\n\nIn user data, we structure the settings in TOML form to make things a bit simpler.\nHere's the user data to change the message of the day setting, as we did in the last section:\n\n```toml\n[settings]\nmotd = \"my own value!\"\n```\n\nIf your user data is over the size limit of the platform (e.g. 16KiB for EC2) you can compress the contents with gzip.\n(With [aws-cli](https://aws.amazon.com/cli/), you can use `--user-data fileb:///path/to/gz-file` to pass binary data.)\n\n### Description of settings\n\nHere we'll describe each setting you can change.\n\n**Note:** You can see the default values (for any settings that are not generated at runtime) by looking in the `defaults.d` directory for a variant, for example [aws-ecs-2](sources/models/src/aws-ecs-2/defaults.d/).\n\nWhen you're sending settings to the API, or receiving settings from the API, they're in a structured JSON format.\nThis allows modification of any number of keys at once.\nIt also lets us ensure that they fit the definition of the Bottlerocket data model - requests with invalid settings won't even parse correctly, helping ensure safety.\n\nHere, however, we'll use the shortcut \"dotted key\" syntax for referring to keys.\nThis is used in some API endpoints with less-structured requests or responses.\nIt's also more compact for our needs here.\n\nIn this format, \"settings.kubernetes.cluster-name\" refers to the same key as in the JSON `{\"settings\": {\"kubernetes\": {\"cluster-name\": \"value\"}}}`.\n\n**NOTE:** [bottlerocket.dev](https://bottlerocket.dev/en/os/latest/#/api/settings/) now contains a complete, versioned setting reference.\nThis documents retains the headings below for existing link and bookmark compatability.\nPlease update your bookmarks and check out [bottlerocket.dev](https://bottlerocket.dev/) for future updates to the setting reference.\n\n#### Top-level settings\n\nSee the [`settings.motd` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/motd/).\n\n#### Kubernetes settings\n\nSee the [`settings.kubernetes.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/kubernetes/).\n\n#### Amazon ECS settings\n\nSee the [`settings.ecs.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/ecs/).\n\n#### CloudFormation signal helper settings\n\nSee the [`settings.cloudformation.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/cloudformation/).\n\n#### Auto Scaling group settings\n\nSee the [`settings.autoscaling.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/autoscaling/).\n\n#### OCI Hooks settings\n\nSee the [`settings.oci-hooks.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/oci-hooks/).\n\n#### OCI Defaults settings\n\nSee the [`settings.oci-defaults.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/oci-defaults/).\n\n##### OCI Defaults: Capabilities\n\nSee the [\"Capabilities Settings\" section in the `settings.oci-defaults.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/oci-defaults/).\n\n##### OCI Defaults: Resource Limits\n\nSee the [\"Resource Limits Settings\" section in the `settings.oci-defaults.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/oci-defaults/).\n\n#### Container image registry settings\n\nSee the [`settings.container-registry.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/container-registry/).\n\n#### Container runtime settings\n\nSee the [`settings.container-runtime.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/container-runtime/).\n\n#### Updates settings\n\nSee the [`settings.updates.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/updates/).\n\n#### Network settings\n\nSee the [`settings.network.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/network/).\n\n##### Proxy settings\n\nSee the [\"Proxy Settings\" section in the `settings.networks.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/network/).\n\n#### Metrics settings\n\nSee the [`settings.metrics.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/metrics/).\n\n#### Time settings\n\nSee the [`settings.ntp.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/ntp/).\n\n#### Kernel settings\n\nSee the [`settings.kernel.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/kernel/).\n\n#### Boot-related settings\n\nSee the [`settings.boot.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/boot/).\n\n#### Custom CA certificates settings\n\nSee the [`settings.pki.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/pki/).\n\n#### Host containers settings\n\nSee the [`settings.host-containers.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/host-containers/).\n\n##### Custom host containers\n\nSee the [Host Containers documentation](https://bottlerocket.dev/en/os/latest/#/concepts/host-containers/).\n\n#### Bootstrap commands settings\n\nSee the [`settings.bootstrap-commands.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/bootstrap-commands/) as well as the [Bootstrap Commands documentation](https://bottlerocket.dev/en/os/latest/#/concepts/bootstrap-commands/)\n\n#### Bootstrap containers settings\n\nSee the [`settings.bootstrap-containers.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/bootstrap-containers/) as well as the [Bootstrap Containers documentation](https://bottlerocket.dev/en/os/latest/#/concepts/bootstrap-containers/)\n\n##### Mount propagations in bootstrap and superpowered containers\n\nBoth bootstrap and superpowered host containers are configured with the `/.bottlerocket/rootfs/mnt` bind mount that points to `/mnt` in the host, which itself is a bind mount of `/local/mnt`.\nThis bind mount is set up with shared propagations, so any new mount point created underneath `/.bottlerocket/rootfs/mnt` in any bootstrap or superpowered host container will propagate across mount namespaces.\nYou can use this feature to configure ephemeral disks attached to your hosts that you may want to use on your workloads.\n\n#### Platform-specific settings\n\nPlatform-specific settings are automatically set at boot time by [early-boot-config](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/early-boot-config/early-boot-config) based on metadata available on the running platform.\nThey can be overridden for testing purposes in [the same way as other settings](#interacting-with-settings).\n\n##### AWS-specific settings\n\nSee the [`settings.aws.*` reference](https://bottlerocket.dev/en/os/latest/#/api/settings/aws/).\n\n### Logs\n\nYou can use `logdog` through the [admin container](#admin-container) to obtain an archive of log files from your Bottlerocket host.\n\nFor a list of what is collected, see the logdog [command list](https://github.com/bottlerocket-os/bottlerocket-core-kit/blob/develop/sources/logdog/src/log_request.rs).\n\n#### Generating logs\n\nSSH to the Bottlerocket host or `apiclient exec admin bash` to access the admin container, then run:\n\n```shell\nsudo sheltie\nlogdog\n```\n\nThis will write an archive of the logs to `/var/log/support/bottlerocket-logs.tar.gz`.\nThis archive is accessible from host containers at `/.bottlerocket/support`.\n\n#### Fetching logs\n\nThere are multiple methods to retrieve the generated log archive.\n\n- **Via SSH if already enabled**\n\n    Once you have exited from the Bottlerocket host, run a command like:\n\n    ```shell\n    ssh -i YOUR_KEY_FILE \\\n    ec2-user@YOUR_HOST \\\n    \"cat /.bottlerocket/support/bottlerocket-logs.tar.gz\" > bottlerocket-logs.tar.gz\n    ```\n\n- **With `kubectl get` if running Kubernetes**\n\n    ```shell\n    kubectl get --raw \\\n    \"/api/v1/nodes/NODE_NAME/proxy/logs/support/bottlerocket-logs.tar.gz\" > bottlerocket-logs.tar.gz\n    ```\n\n- **Using [SSH over SSM](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html) if your instance isn't accessible through SSH or Kubernetes**\n\n### Kdump Support\n\nBottlerocket provides support to collect kernel crash dumps whenever the system kernel panics.\nOnce this happens, both the dmesg log and vmcore dump are stored at `/var/log/kdump`, and the system reboots.\n\nThere are a few important caveats about the provided kdump support:\n\n* Currently, only vmware variants have kdump support enabled\n* The system kernel will reserve 256MB for the crash kernel, only when the host has at least 2GB of memory; the reserved space won't be available for processes running in the host\n* The crash kernel will only be loaded when the `crashkernel` parameter is present in the kernel's cmdline and if there is memory reserved for it\n\n### NVIDIA GPUs Support\n\nBottlerocket's `nvidia` variants include the required packages and configurations to leverage NVIDIA GPUs.\nCurrently, the following NVIDIA driver versions are supported in Bottlerocket:\n\n* 470.X\n* 515.X\n\nThe official AMIs for these variants can be used with EC2 GPU-equipped instance types such as: `p2`, `p3`, `p4`, `g3`, `g4dn`, `g5` and `g5g`.\nNote that older instance types, such as `p2`, are not supported by NVIDIA driver `515.X` and above.\nYou need to make sure you select the appropriate AMI depending on the instance type you are planning to use.\nPlease see [QUICKSTART-EKS](QUICKSTART-EKS.md#aws-k8s--nvidia-variants) for further details about Kubernetes variants, and [QUICKSTART-ECS](QUICKSTART-ECS.md#aws-ecs--nvidia-variants) for ECS variants.\n\n### Neuron Accelerated Instance Support\n\nBottlerocket variants, from `v1.30.0+`, include the required packages and configurations to leverage [AWS Neuron Accelerated Instances](https://aws.amazon.com/ai/machine-learning/neuron/).\n\nThe AMIs can be used with EC2 Neuron-equipped instance types such as: `inf1`, `inf2`, `trn1`, and `trn2`.\n\nPlease see [QUICKSTART-EKS](QUICKSTART-EKS.md#Neuron-Support) for further details about Kubernetes variants, and [QUICKSTART-ECS](QUICKSTART-ECS.md#Neuron-Support) for ECS variants.\n\n## Details\n\n### Security\n\n:shield: :crab:\n\nTo learn more about security features in Bottlerocket, please see [SECURITY FEATURES](SECURITY_FEATURES.md).\nIt describes how we use features like [dm-verity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) and [SELinux](https://selinuxproject.org/) to protect the system from security threats.\n\nTo learn more about security recommendations for Bottlerocket, please see [SECURITY GUIDANCE](SECURITY_GUIDANCE.md).\nIt documents additional steps you can take to secure the OS, and includes resources such as a [Pod Security Policy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) for your reference.\n\nIn addition, almost all first-party components are written in [Rust](https://www.rust-lang.org/).\nRust eliminates some classes of memory safety issues, and encourages design patterns that help security.\n\n### Packaging\n\nBottlerocket is built from source using a container toolchain.\nWe use RPM package definitions to build and install individual packages into an image.\nRPM itself is not in the image - it's just a common and convenient package definition format.\n\nWe currently package the following major third-party components:\n\n* Linux kernel ([background](https://en.wikipedia.org/wiki/Linux), [5.10 packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/kernel-5.10/), [5.15 packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/kernel-5.15/))\n* glibc ([background](https://www.gnu.org/software/libc/), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/glibc/))\n* Buildroot as build toolchain ([background](https://buildroot.org/), via the [SDK](https://github.com/bottlerocket-os/bottlerocket-sdk))\n* GRUB, with patches for partition flip updates ([background](https://www.gnu.org/software/grub/), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/grub/))\n* systemd as init ([background](https://en.wikipedia.org/wiki/Systemd), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/systemd/))\n* wicked for networking ([background](https://github.com/openSUSE/wicked), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/wicked/))\n* containerd ([background](https://containerd.io/), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/containerd/))\n* Kubernetes ([background](https://kubernetes.io/), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/kubernetes-1.30/))\n* aws-iam-authenticator ([background](https://github.com/kubernetes-sigs/aws-iam-authenticator), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/aws-iam-authenticator/))\n* Amazon ECS agent ([background](https://github.com/aws/amazon-ecs-agent), [packaging](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/ecs-agent/))\n\nFor further documentation or to see the rest of the packages, see the [packaging directory](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages/).\n\n### Updates\n\nThe Bottlerocket image has two identical sets of partitions, A and B.\nWhen updating Bottlerocket, the partition table is updated to point from set A to set B, or vice versa.\n\nWe also track successful boots, and if there are failures it will automatically revert back to the prior working partition set.\n\nThe update process uses images secured by [TUF](https://theupdateframework.github.io/).\nFor more details, see the [update system documentation](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/updater).\n\n### API\n\nThere are two main ways you'd interact with a production Bottlerocket instance.\n(There are a couple more [exploration](#exploration) methods above for test instances.)\n\nThe first method is through a container orchestrator, for when you want to run or manage containers.\nThis uses the standard channel for your orchestrator, for example a tool like `kubectl` for Kubernetes.\n\nThe second method is through the Bottlerocket API, for example when you want to configure the system.\n\nThere's an HTTP API server that listens on a local Unix-domain socket.\nRemote access to the API requires an authenticated transport such as SSM's RunCommand or Session Manager, as described above.\nFor more details, see the [apiserver documentation](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/api/apiserver/).\n\nThe [apiclient](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/api/apiclient/) can be used to make requests.\nThey're just HTTP requests, but the API client simplifies making requests with the Unix-domain socket.\n\nTo make configuration easier, we have [early-boot-config](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/early-boot-config/early-boot-config), which can send an API request for you based on instance user data.\nIf you start a virtual machine, like an EC2 instance, it will read TOML-formatted Bottlerocket configuration from user data and send it to the API server.\nThis way, you can configure your Bottlerocket instance without having to make API calls after launch.\n\nSee [Settings](#settings) above for examples and to understand what you can configure.\n\nYou can also access host containers through the API using [apiclient exec](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/api/apiclient#exec-mode).\n\nThe server and client are the user-facing components of the API system, but there are a number of other components that work together to make sure your settings are applied, and that they survive upgrades of Bottlerocket.\n\nFor more details, see the [API system documentation](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/sources/api).\n\n### Default Volumes\n\nBottlerocket operates with two default storage volumes.\n\n* The root device, holds the active and passive [partition sets](#updates-1).\n  It also contains the bootloader, the dm-verity hash tree for verifying the [immutable root filesystem](SECURITY_FEATURES.md#immutable-rootfs-backed-by-dm-verity), and the data store for the Bottlerocket API.\n* The data device is used as persistent storage for container images, container orchestration, [host-containers](#Custom-host-containers), and [bootstrap containers](#Bootstrap-containers-settings).\n  The operating system does not typically make changes to this volume during regular updates, though changes to upstream software such as containerd or kubelet could result in changes to their stored data.\n  This device (mounted to `/local` on the host) can be used for application storage for orchestrated workloads; however, we recommend using an additional volume if possible for such cases.\n  See [this section of the Security Guidance documentation](./SECURITY_GUIDANCE.md#limit-access-to-system-mounts) for more information.\n\nOn boot Bottlerocket will increase the data partition size to use all of the data device.\nIf you increase the size of the device, you can reboot Bottlerocket to extend the data partition.\nIf you need to extend the data partition without rebooting, have a look at this [discussion](https://github.com/bottlerocket-os/bottlerocket/discussions/2011).\n"
  },
  {
    "path": "ROADMAP.md",
    "content": "# Roadmap\n\nThe Bottlerocket roadmap is public and hosted as a GitHub Project at the following URL:\n\nhttps://github.com/orgs/bottlerocket-os/projects/18\n\nGitHub Projects allows for multiple views that represent different ways of looking at the same data.\nIn the case of Bottlerocket, there are four views (represented as tabs):\n\n* [All Items](https://github.com/orgs/bottlerocket-os/projects/18/views/1): a list of all the issues being actively worked on.\n* [Upcoming Releases](https://github.com/orgs/bottlerocket-os/projects/18/views/2): the issues sorted into columns that represent an upcoming release.\n* [Feature Highlights](https://github.com/orgs/bottlerocket-os/projects/18/views/4): selected issues sorted into columns that represent particular features.\n* [Themes](https://github.com/orgs/bottlerocket-os/projects/18/views/5): selected issues sorted into columns as they align to overarching thematic changes.\n\n## What does the roadmap represent?\n\nThe roadmap is best understood as a point-in-time snapshot of what is being worked on and the intentions for upcoming releases.\nEach item on the roadmap links back to a GitHub issue; issues represent a problem (i.e. a bug) or a change from the current functional state (i.e. an enhancement).\n\nBoth bug and enhancements can take a non-linear path to resolution.\nThe work to resolve these can take more or less effort than anticipated as paths are explored and complexity is thoughtfully considered.\nReleases in Bottlerocket follow a loose release train model with each being spaced out about six weeks apart.\nSo, roadmap items are continuously reconsidered and roadmap adjustments may be required.\n\n## How do I follow a specific change to the roadmap?\n\nFor individual items, the best way to find out more information is to subscribe to notifications on GitHub for the specific issues linked in the roadmap.\nThis will give you insight into both the development and any large changes to how the issue gets packaged into a release.\nAdditionally, you can ask questions, provide feedback, and, hopefully, contribute.\n\n## Can I see a log of all the changes to the roadmap?\n\nThis was supported in [GitHub Projects classic](https://docs.github.com/en/issues/organizing-your-work-with-project-boards/tracking-work-with-project-boards/tracking-progress-on-your-project-board) however, Bottlerocket uses the newer version of this GitHub feature which lacks this particular log-like view.\nIn the future, it would be great to see this feature return to GitHub Projects or similar functionality through the  [Bottlerocket website](https://github.com/bottlerocket-os/project-website) initiative.\n"
  },
  {
    "path": "Release.toml",
    "content": "version = \"1.57.0\"\n\n[migrations]\n\"(0.3.1, 0.3.2)\" = [\"migrate_v0.3.2_admin-container-v0-5-0.lz4\"]\n\"(0.3.2, 0.3.3)\" = []\n\"(0.3.3, 0.3.4)\" = []\n\"(0.3.4, 0.4.0)\" = []\n\"(0.4.0, 0.4.1)\" = [\"migrate_v0.4.1_add-version-lock-ignore-waves.lz4\", \"migrate_v0.4.1_pivot-repo-2020-07-07.lz4\"]\n\"(0.4.1, 0.5.0)\" = [\"migrate_v0.5.0_add-cluster-domain.lz4\", \"migrate_v0.5.0_admin-container-v0-5-2.lz4\", \"migrate_v0.5.0_control-container-v0-4-1.lz4\"]\n\"(0.5.0, 1.0.0)\" = [\"migrate_v1.0.0_ecr-helper-admin.lz4\", \"migrate_v1.0.0_ecr-helper-control.lz4\"]\n\"(1.0.0, 1.0.1)\" = []\n\"(1.0.1, 1.0.2)\" = [\"migrate_v1.0.2_add-enable-spot-instance-draining.lz4\"]\n\"(1.0.2, 1.0.3)\" = [\"migrate_v1.0.3_add-sysctl.lz4\"]\n\"(1.0.3, 1.0.4)\" = []\n\"(1.0.4, 1.0.5)\" = [\n    \"migrate_v1.0.5_add-lockdown.lz4\",\n    \"migrate_v1.0.5_sysctl-subcommand.lz4\",\n    \"migrate_v1.0.5_add-user-data.lz4\",\n    \"migrate_v1.0.5_add-network-settings.lz4\",\n    \"migrate_v1.0.5_add-proxy-restart.lz4\",\n    \"migrate_v1.0.5_add-proxy-services.lz4\",\n]\n\"(1.0.5, 1.0.6)\" = [\n    \"migrate_v1.0.6_metricdog-init.lz4\",\n    \"migrate_v1.0.6_add-static-pods.lz4\",\n    \"migrate_v1.0.6_kubelet-standalone-tls-settings.lz4\",\n    \"migrate_v1.0.6_kubelet-standalone-tls-services.lz4\",\n    \"migrate_v1.0.6_control-container-v0-4-2.lz4\",\n    \"migrate_v1.0.6_add-shibaken.lz4\",\n    \"migrate_v1.0.6_admin-container-v0-6-0.lz4\",\n]\n\"(1.0.6, 1.0.7)\" = []\n\"(1.0.7, 1.0.8)\" = [\n    \"migrate_v1.0.8_kubelet-eviction-hard.lz4\",\n    \"migrate_v1.0.8_kubelet-unsafe-sysctl-kube-reserved.lz4\",\n    \"migrate_v1.0.8_proxy-affect-host-containers.lz4\",\n    \"migrate_v1.0.8_control-container-v0-5-0.lz4\",\n    \"migrate_v1.0.8_admin-container-v0-7-0.lz4\",\n    \"migrate_v1.0.8_add-bootstrap-containers.lz4\"\n]\n\"(1.0.8, 1.1.0)\" = [\n    \"migrate_v1.1.0_kubelet-server-tls-bootstrap.lz4\",\n    \"migrate_v1.1.0_kubelet-cloud-provider.lz4\",\n    \"migrate_v1.1.0_kubelet-registry-qps-registry-burst.lz4\",\n    \"migrate_v1.1.0_shared-containerd-configs.lz4\",\n    \"migrate_v1.1.0_kubelet-event-qps-event-burst.lz4\",\n    \"migrate_v1.1.0_schnauzer-paws.lz4\",\n    \"migrate_v1.1.0_kubelet-kube-api-qps-kube-api-burst.lz4\",\n]\n\"(1.1.0, 1.1.1)\" = []\n\"(1.1.1, 1.1.2)\" = [\n    \"migrate_v1.1.2_kubelet-container-log.lz4\",\n    \"migrate_v1.1.2_kubelet-system-reserved.lz4\",\n    \"migrate_v1.1.2_admin-container-v0-7-1.lz4\",\n    \"migrate_v1.1.2_control-container-v0-5-1.lz4\",\n]\n\"(1.1.2, 1.1.3)\" = [\n    \"migrate_v1.1.3_kubelet-cpu-manager-state.lz4\",\n    \"migrate_v1.1.3_kubelet-cpu-manager.lz4\",\n]\n\"(1.1.3, 1.1.4)\" = []\n\"(1.1.4, 1.2.0)\" = [\n    \"migrate_v1.2.0_hostname-setting.lz4\",\n    \"migrate_v1.2.0_hostname-setting-metadata.lz4\",\n    \"migrate_v1.2.0_add-custom-certificates.lz4\",\n    \"migrate_v1.2.0_kubelet-topology-manager.lz4\",\n    \"migrate_v1.2.0_container-registry-mirrors.lz4\",\n    \"migrate_v1.2.0_container-registry-config-restarts.lz4\",\n    \"migrate_v1.2.0_admin-container-v0-7-2.lz4\",\n]\n\"(1.2.0, 1.2.1)\" = []\n\"(1.2.1, 1.3.0)\" = [\n    \"migrate_v1.3.0_etc-hosts-service.lz4\",\n    \"migrate_v1.3.0_hostname-affects-etc-hosts.lz4\",\n    \"migrate_v1.3.0_control-container-v0-5-2.lz4\",\n]\n\"(1.3.0, 1.4.0)\" = [\n    \"migrate_v1.4.0_registry-mirror-representation.lz4\",\n]\n\"(1.4.0, 1.4.1)\" = []\n\"(1.4.1, 1.4.2)\" = [\n    \"migrate_v1.4.2_admin-container-v0-7-3.lz4\",\n    \"migrate_v1.4.2_control-container-v0-5-3.lz4\",\n]\n\"(1.4.2, 1.5.0)\" = [\n    \"migrate_v1.5.0_oci-hooks-setting.lz4\",\n    \"migrate_v1.5.0_oci-hooks-setting-metadata.lz4\",\n]\n\"(1.5.0, 1.5.1)\" = [\n    \"migrate_v1.5.1_control-container-v0-5-4.lz4\",\n]\n\"(1.5.1, 1.5.2)\" = []\n\"(1.5.2, 1.5.3)\" = [\n    \"migrate_v1.5.3_vmware-host-containers.lz4\",\n]\n\"(1.5.3, 1.6.0)\" = [\n    \"migrate_v1.6.0_node-taints-representation.lz4\",\n    \"migrate_v1.6.0_aws-admin-container-v0-7-4.lz4\",\n    \"migrate_v1.6.0_aws-control-container-v0-5-5.lz4\",\n    \"migrate_v1.6.0_public-admin-container-v0-7-4.lz4\",\n    \"migrate_v1.6.0_public-control-container-v0-5-5.lz4\",\n]\n\"(1.6.0, 1.6.1)\" = []\n\"(1.6.1, 1.6.2)\" = [\n    \"migrate_v1.6.2_add-cfsignal.lz4\",\n    \"migrate_v1.6.2_container-registry-credentials.lz4\",\n    \"migrate_v1.6.2_container-registry-credentials-metadata.lz4\",\n]\n\"(1.6.2, 1.7.0)\" = [\n    \"migrate_v1.7.0_aws-admin-container-v0-8-0.lz4\",\n    \"migrate_v1.7.0_aws-control-container-v0-6-0.lz4\",\n    \"migrate_v1.7.0_public-admin-container-v0-8-0.lz4\",\n    \"migrate_v1.7.0_public-control-container-v0-6-0.lz4\",\n]\n\"(1.7.0, 1.7.1)\" = []\n\"(1.7.1, 1.7.2)\" = []\n\"(1.7.2, 1.8.0)\" = [\n    \"migrate_v1.8.0_boot-setting.lz4\",\n    \"migrate_v1.8.0_boot-setting-metadata.lz4\",\n    \"migrate_v1.8.0_kubelet-pod-pids-limit.lz4\",\n    \"migrate_v1.8.0_add-pull-behavior.lz4\",\n    \"migrate_v1.8.0_add-autoscaling.lz4\",\n    \"migrate_v1.8.0_etc-hosts.lz4\",\n    \"migrate_v1.8.0_etc-hosts-metadata.lz4\",\n    \"migrate_v1.8.0_cluster-dns-ip-list.lz4\",\n    \"migrate_v1.8.0_pki-affected-services.lz4\",\n    \"migrate_v1.8.0_kubelet-provider-id.lz4\",\n    \"migrate_v1.8.0_aws-admin-container-v0-9-0.lz4\",\n    \"migrate_v1.8.0_aws-control-container-v0-6-1.lz4\",\n    \"migrate_v1.8.0_public-admin-container-v0-9-0.lz4\",\n    \"migrate_v1.8.0_public-control-container-v0-6-1.lz4\",\n]\n\"(1.8.0, 1.9.0)\" = [\n    \"migrate_v1.9.0_ntp-affected-services.lz4\",\n    \"migrate_v1.9.0_shibaken-admin-userdata-semantics.lz4\",\n    \"migrate_v1.9.0_shibaken-send-metrics.lz4\",\n    \"migrate_v1.9.0_image-gc-thresholds.lz4\",\n    \"migrate_v1.9.0_kernel-modules-setting.lz4\",\n    \"migrate_v1.9.0_kernel-modules-setting-metadata.lz4\",\n    \"migrate_v1.9.0_kubelet-no-daemon-reload.lz4\",\n    \"migrate_v1.9.0_updates-targets-base-url.lz4\",\n]\n\"(1.9.0, 1.9.1)\" = []\n\"(1.9.1, 1.9.2)\" = []\n\"(1.9.2, 1.10.0)\" = [\n    \"migrate_v1.10.0_dns-settings.lz4\",\n    \"migrate_v1.10.0_dns-settings-metadata.lz4\",\n    \"migrate_v1.10.0_reboot-to-reconcile-setting.lz4\",\n    \"migrate_v1.10.0_kubelet-log-level.lz4\",\n    \"migrate_v1.10.0_aws-admin-container-v0-9-2.lz4\",\n    \"migrate_v1.10.0_public-admin-container-v0-9-2.lz4\",\n    \"migrate_v1.10.0_aws-control-container-v0-6-3.lz4\",\n    \"migrate_v1.10.0_public-control-container-v0-6-3.lz4\"\n]\n\"(1.10.0, 1.10.1)\" = [\n    \"migrate_v1.10.1_container-runtime.lz4\",\n    \"migrate_v1.10.1_container-runtime-metadata.lz4\"\n]\n\"(1.10.1, 1.11.0)\" = [\n    \"migrate_v1.11.0_aws-config-settings.lz4\",\n    \"migrate_v1.11.0_aws-creds.lz4\",\n    \"migrate_v1.11.0_aws-creds-metadata.lz4\",\n    \"migrate_v1.11.0_credential-providers.lz4\",\n    \"migrate_v1.11.0_kubelet-tls-config.lz4\",\n    \"migrate_v1.11.0_kubelet-tls-files.lz4\",\n    \"migrate_v1.11.0_kubelet-new-config-files.lz4\",\n    \"migrate_v1.11.0_ecs-additional-configurations.lz4\",\n    \"migrate_v1.11.0_aws-admin-container-v0-9-3.lz4\",\n    \"migrate_v1.11.0_public-admin-container-v0-9-3.lz4\",\n    \"migrate_v1.11.0_aws-control-container-v0-6-4.lz4\",\n    \"migrate_v1.11.0_public-control-container-v0-6-4.lz4\",\n]\n\"(1.11.0, 1.11.1)\" = []\n\"(1.11.1, 1.12.0)\" = [\n    \"migrate_v1.12.0_k8s-private-pki-path.lz4\",\n    \"migrate_v1.12.0_add-k8s-autoscaling-warm-pool-setting.lz4\",\n    \"migrate_v1.12.0_add-k8s-autoscaling-warm-pool-setting-metadata.lz4\",\n    \"migrate_v1.12.0_oci-defaults-setting.lz4\",\n    \"migrate_v1.12.0_oci-defaults-setting-metadata.lz4\",\n    \"migrate_v1.12.0_aws-admin-container-v0-9-4.lz4\",\n    \"migrate_v1.12.0_public-admin-container-v0-9-4.lz4\",\n    \"migrate_v1.12.0_aws-control-container-v0-7-0.lz4\",\n    \"migrate_v1.12.0_public-control-container-v0-7-0.lz4\",\n]\n\"(1.12.0, 1.13.0)\" = [\n    \"migrate_v1.13.0_k8s-registry.lz4\",\n    \"migrate_v1.13.0_aws-admin-container-v0-10-0.lz4\",\n    \"migrate_v1.13.0_public-admin-container-v0-10-0.lz4\",\n    \"migrate_v1.13.0_aws-control-container-v0-7-1.lz4\",\n    \"migrate_v1.13.0_public-control-container-v0-7-1.lz4\",\n]\n\"(1.13.0, 1.13.1)\" = [\n    \"migrate_v1.13.1_aws-profile-cred-provider.lz4\",\n]\n\"(1.13.1, 1.13.2)\" = []\n\"(1.13.2, 1.13.3)\" = [\n    \"migrate_v1.13.3_aws-k8s-provider-id-gen.lz4\",\n]\n\"(1.13.3, 1.13.4)\" = [\n    \"migrate_v1.13.4_add-hostname-override.lz4\",\n    \"migrate_v1.13.4_add-hostname-override-metadata.lz4\",\n]\n\"(1.13.4, 1.13.5)\" = []\n\"(1.13.5, 1.14.0)\" = [\n    \"migrate_v1.14.0_kubernetes-gc-percent-type-change.lz4\",\n    \"migrate_v1.14.0_kubelet-config-settings.lz4\",\n    \"migrate_v1.14.0_kubelet-prefix-config-settings.lz4\",\n    \"migrate_v1.14.0_k8s-services-mode.lz4\",\n    \"migrate_v1.14.0_aws-admin-container-v0-10-1.lz4\",\n    \"migrate_v1.14.0_public-admin-container-v0-10-1.lz4\",\n    \"migrate_v1.14.0_aws-control-container-v0-7-2.lz4\",\n    \"migrate_v1.14.0_public-control-container-v0-7-2.lz4\",\n]\n\"(1.14.0, 1.14.1)\" = []\n\"(1.14.1, 1.14.2)\" = [\n    \"migrate_v1.14.2_ecs-images-cleanup.lz4\",\n]\n\"(1.14.2, 1.14.3)\" = [\n    \"migrate_v1.14.3_aws-admin-container-v0-10-2.lz4\",\n    \"migrate_v1.14.3_public-admin-container-v0-10-2.lz4\",\n    \"migrate_v1.14.3_aws-control-container-v0-7-3.lz4\",\n    \"migrate_v1.14.3_public-control-container-v0-7-3.lz4\",\n]\n\"(1.14.3, 1.15.0)\" = [\n    \"migrate_v1.15.0_oci-defaults-resource-setting.lz4\",\n    \"migrate_v1.15.0_oci-defaults-max-open-files.lz4\",\n    \"migrate_v1.15.0_seccomp-default-setting.lz4\",\n    \"migrate_v1.15.0_oci-defaults-docker-setting.lz4\",\n    \"migrate_v1.15.0_oci-defaults-docker-setting-metadata.lz4\",\n    \"migrate_v1.15.0_aws-admin-container-v0-11-0.lz4\",\n    \"migrate_v1.15.0_public-admin-container-v0-11-0.lz4\",\n    \"migrate_v1.15.0_aws-control-container-v0-7-4.lz4\",\n    \"migrate_v1.15.0_public-control-container-v0-7-4.lz4\",\n    \"migrate_v1.15.0_log4j-hotpatch-enabled-metadata.lz4\",\n    \"migrate_v1.15.0_deprecate-log4j-hotpatch-enabled.lz4\",\n]\n\"(1.15.0, 1.15.1)\" = []\n\"(1.15.1, 1.16.0)\" = [\n    \"migrate_v1.16.0_kernel-modules-autoload-configs.lz4\",\n    \"migrate_v1.16.0_kernel-modules-autoload-files.lz4\",\n    \"migrate_v1.16.0_kernel-modules-autoload-restart.lz4\",\n    \"migrate_v1.16.0_kernel-modules-autoload-settings.lz4\",\n    \"migrate_v1.16.0_aws-admin-container-v0-11-1.lz4\",\n    \"migrate_v1.16.0_public-admin-container-v0-11-1.lz4\",\n    \"migrate_v1.16.0_aws-control-container-v0-7-5.lz4\",\n    \"migrate_v1.16.0_public-control-container-v0-7-5.lz4\",\n    \"migrate_v1.16.0_schnauzer-v2-generators.lz4\",\n]\n\"(1.16.0, 1.16.1)\" = [\n    \"migrate_v1.16.1_updog-network-affected.lz4\",\n]\n\"(1.16.1, 1.17.0)\" = [\n    \"migrate_v1.17.0_aws-admin-container-v0-11-2.lz4\",\n    \"migrate_v1.17.0_public-admin-container-v0-11-2.lz4\",\n    \"migrate_v1.17.0_aws-control-container-v0-7-6.lz4\",\n    \"migrate_v1.17.0_public-control-container-v0-7-6.lz4\",\n]\n\"(1.17.0, 1.18.0)\" = [\n    \"migrate_v1.18.0_aws-admin-container-v0-11-3.lz4\",\n    \"migrate_v1.18.0_public-admin-container-v0-11-3.lz4\",\n    \"migrate_v1.18.0_aws-control-container-v0-7-7.lz4\",\n    \"migrate_v1.18.0_public-control-container-v0-7-7.lz4\",\n]\n\"(1.18.0, 1.19.0)\" = [\n    \"migrate_v1.19.0_add-additional-ecs-settings.lz4\",\n]\n\"(1.19.0, 1.19.1)\" = [\n    \"migrate_v1.19.1_aws-admin-container-v0-11-4.lz4\",\n    \"migrate_v1.19.1_public-admin-container-v0-11-4.lz4\",\n    \"migrate_v1.19.1_aws-control-container-v0-7-8.lz4\",\n    \"migrate_v1.19.1_public-control-container-v0-7-8.lz4\",\n]\n\"(1.19.1, 1.19.2)\" = [\n    \"migrate_v1.19.2_certdog-config-file-v0-1-0.lz4\",\n    \"migrate_v1.19.2_certdog-service-cfg-v0-1-0.lz4\",\n    \"migrate_v1.19.2_add-ecs-enable-container-metadata.lz4\",\n]\n\"(1.19.2, 1.19.3)\" = [\n    \"migrate_v1.19.3_aws-admin-container-v0-11-6.lz4\",\n    \"migrate_v1.19.3_public-admin-container-v0-11-6.lz4\",\n    \"migrate_v1.19.3_aws-control-container-v0-7-10.lz4\",\n    \"migrate_v1.19.3_public-control-container-v0-7-10.lz4\",\n]\n\"(1.19.3, 1.19.4)\" = []\n\"(1.19.4, 1.19.5)\" = [\n    \"migrate_v1.19.5_aws-admin-container-v0-11-7.lz4\",\n    \"migrate_v1.19.5_public-admin-container-v0-11-7.lz4\",\n    \"migrate_v1.19.5_aws-control-container-v0-7-11.lz4\",\n    \"migrate_v1.19.5_public-control-container-v0-7-11.lz4\",\n]\n\"(1.19.5, 1.20.0)\" = [\n    \"migrate_v1.20.0_prairiedog-config-file-v0-1-0.lz4\",\n    \"migrate_v1.20.0_prairiedog-services-cfg-v0-1-0.lz4\",\n    \"migrate_v1.20.0_thar-be-updates-config-file-v0-1-0.lz4\",\n    \"migrate_v1.20.0_thar-be-updates-affected-services-v0-1-0.lz4\",\n    \"migrate_v1.20.0_host-containers-config-file-v0-1-0.lz4\",\n    \"migrate_v1.20.0_host-containers-config-list-v0-1-0.lz4\",\n    \"migrate_v1.20.0_corndog-config-file-v0-1-0.lz4\",\n    \"migrate_v1.20.0_corndog-services-cfg-v0-1-0.lz4\",\n    \"migrate_v1.20.0_bootstrap-containers-config-file-v0-1-0.lz4\",\n    \"migrate_v1.20.0_bootstrap-containers-services-cfg-v0-1-0.lz4\",\n    \"migrate_v1.20.0_remove-ecs-settings-applier.lz4\",\n    \"migrate_v1.20.0_update-ecs-config-path.lz4\",\n    \"migrate_v1.20.0_update-ecs-config-template-path.lz4\",\n    \"migrate_v1.20.0_add-ntp-default-options-v0-1-0.lz4\",\n    \"migrate_v1.20.0_static-pods-add-prefix-v0-1-0.lz4\",\n    \"migrate_v1.20.0_static-pods-services-cfg-v0-1-0.lz4\",\n    \"migrate_v1.20.0_container-runtime-nvidia.lz4\",\n    \"migrate_v1.20.0_container-runtime-metadata-nvidia.lz4\",\n    \"migrate_v1.20.0_aws-admin-container-v0-11-8.lz4\",\n    \"migrate_v1.20.0_public-admin-container-v0-11-8.lz4\",\n    \"migrate_v1.20.0_aws-control-container-v0-7-12.lz4\",\n    \"migrate_v1.20.0_public-control-container-v0-7-12.lz4\",\n]\n\"(1.20.0, 1.20.1)\" = []\n\"(1.20.1, 1.20.2)\" = []\n\"(1.20.2, 1.20.3)\" = []\n\"(1.20.3, 1.20.4)\" = []\n\"(1.20.4, 1.20.5)\" = [\n    \"migrate_v1.20.5_aws-admin-container-v0-11-9.lz4\",\n    \"migrate_v1.20.5_public-admin-container-v0-11-9.lz4\",\n    \"migrate_v1.20.5_aws-control-container-v0-7-13.lz4\",\n    \"migrate_v1.20.5_public-control-container-v0-7-13.lz4\",\n]\n\"(1.20.5, 1.21.0)\" = [\n    \"migrate_v1.21.0_pluto-remove-generators-v0-1-0.lz4\",\n    \"migrate_v1.21.0_pod-infra-container-image-remove-settings-generator.lz4\",\n    \"migrate_v1.21.0_pod-infra-container-image-affected-services.lz4\",\n    \"migrate_v1.21.0_pod-infra-container-image-services.lz4\",\n    \"migrate_v1.21.0_k8s-reserved-cpus-v0-1-0.lz4\",\n    \"migrate_v1.21.0_add-hostname-override-source.lz4\",\n]\n\"(1.21.0, 1.21.1)\" = [\n    \"migrate_v1.21.1_aws-admin-container-v0-11-10.lz4\",\n    \"migrate_v1.21.1_public-admin-container-v0-11-10.lz4\",\n    \"migrate_v1.21.1_aws-control-container-v0-7-14.lz4\",\n    \"migrate_v1.21.1_public-control-container-v0-7-14.lz4\",\n]\n\"(1.21.1, 1.22.0)\" = [\n    \"migrate_v1.22.0_aws-admin-container-v0-11-11.lz4\",\n    \"migrate_v1.22.0_public-admin-container-v0-11-11.lz4\",\n    \"migrate_v1.22.0_aws-control-container-v0-7-15.lz4\",\n    \"migrate_v1.22.0_public-control-container-v0-7-15.lz4\",\n    \"migrate_v1.22.0_bootstrap-commands-settings.lz4\",\n    \"migrate_v1.22.0_bootstrap-commands-metadata.lz4\",\n]\n\"(1.22.0, 1.23.0)\" = [\n    \"migrate_v1.23.0_kubelet-device-plugins-metadata.lz4\",\n    \"migrate_v1.23.0_kubelet-device-plugins-settings.lz4\",\n    \"migrate_v1.23.0_nvidia-container-runtime-metadata.lz4\",\n    \"migrate_v1.23.0_nvidia-container-runtime-settings.lz4\",\n]\n\"(1.23.0, 1.24.0)\" = []\n\"(1.24.0, 1.24.1)\" = [\n    \"migrate_v1.24.1_aws-admin-container-v0-11-12.lz4\",\n    \"migrate_v1.24.1_public-admin-container-v0-11-12.lz4\",\n    \"migrate_v1.24.1_aws-control-container-v0-7-16.lz4\",\n    \"migrate_v1.24.1_public-control-container-v0-7-16.lz4\",\n]\n\"(1.24.1, 1.25.0)\" = [\n    \"migrate_v1.25.0_kubernetes-service-config.lz4\",\n    \"migrate_v1.25.0_kubelet-device-plugins-time-slicing-settings.lz4\",\n    \"migrate_v1.25.0_aws-admin-container-v0-11-13.lz4\",\n    \"migrate_v1.25.0_public-admin-container-v0-11-13.lz4\",\n    \"migrate_v1.25.0_aws-control-container-v0-7-17.lz4\",\n    \"migrate_v1.25.0_public-control-container-v0-7-17.lz4\",\n]\n\"(1.25.0, 1.26.0)\" = []\n\"(1.26.0, 1.26.1)\" = []\n\"(1.26.1, 1.26.2)\" = []\n\"(1.26.2, 1.27.0)\" = [\n    \"migrate_v1.27.0_aws-config.lz4\",\n]\n\"(1.27.0, 1.27.1)\" = []\n\"(1.27.1, 1.28.0)\" = [\n    \"migrate_v1.28.0_kernel-sysctl-hugepages.lz4\",\n    \"migrate_v1.28.0_aws-admin-container-v0-11-14.lz4\",\n    \"migrate_v1.28.0_public-admin-container-v0-11-14.lz4\",\n    \"migrate_v1.28.0_aws-control-container-v0-7-18.lz4\",\n    \"migrate_v1.28.0_public-control-container-v0-7-18.lz4\",\n]\n\"(1.28.0, 1.29.0)\" = []\n\"(1.29.0, 1.30.0)\" = [\n    \"migrate_v1.30.0_kubernetes-device-ownership-metadata.lz4\",\n    \"migrate_v1.30.0_kubernetes-device-ownership-settings.lz4\",\n    \"migrate_v1.30.0_aws-admin-container-v0-11-15.lz4\",\n    \"migrate_v1.30.0_public-admin-container-v0-11-15.lz4\",\n    \"migrate_v1.30.0_aws-control-container-v0-7-19.lz4\",\n    \"migrate_v1.30.0_public-control-container-v0-7-19.lz4\",\n]\n\"(1.30.0, 1.31.0)\" = [\n    \"migrate_v1.31.0_aws-admin-container-v0-11-16.lz4\",\n    \"migrate_v1.31.0_public-admin-container-v0-11-16.lz4\",\n    \"migrate_v1.31.0_aws-control-container-v0-7-20.lz4\",\n    \"migrate_v1.31.0_public-control-container-v0-7-20.lz4\",\n]\n\"(1.31.0, 1.32.0)\" = []\n\"(1.32.0, 1.33.0)\" = [\n    \"migrate_v1.33.0_public-control-container-v0-7-19-update.lz4\",\n    \"migrate_v1.33.0_public-control-container-v0-7-20-update.lz4\",\n    \"migrate_v1.33.0_aws-remove-schnauzer-admin.lz4\",\n    \"migrate_v1.33.0_aws-remove-schnauzer-control.lz4\",\n    \"migrate_v1.33.0_public-remove-source-admin.lz4\",\n    \"migrate_v1.33.0_public-remove-source-control.lz4\",\n    \"migrate_v1.33.0_remove-metadata-and-weak-settings-migration.lz4\",\n]\n\"(1.33.0, 1.34.0)\" = [\n    \"migrate_v1.34.0_kubelet-device-plugins-mig-settings.lz4\",\n]\n\"(1.34.0, 1.35.0)\" = []\n\"(1.35.0, 1.36.0)\" = [\n    \"migrate_v1.36.0_kubernetes-ecr-credential-providers-expansion.lz4\",\n]\n\"(1.36.0, 1.37.0)\" = [\n    \"migrate_v1.37.0_delete-configs-and-services-on-downgrade.lz4\",\n]\n\"(1.37.0, 1.38.0)\" = []\n\"(1.38.0, 1.39.0)\" = [\n    \"migrate_v1.39.0_kubelet-setting-container-log-single-process-oom-kill.lz4\"\n]\n\"(1.39.0, 1.39.1)\" = []\n\"(1.39.1, 1.40.0)\" = [\n    \"migrate_v1.40.0_kubelet-device-plugins-cdi-settings.lz4\"\n]\n\"(1.40.0, 1.41.0)\" = [\n    \"migrate_v1.41.0_kubernetes-ecr-credential-providers-correction.lz4\",\n]\n\"(1.41.0, 1.42.0)\" = [\n    \"migrate_v1.42.0_kubernetes-memory-swap-behavior-setting.lz4\",\n]\n\"(1.42.0, 1.43.0)\" = []\n\"(1.43.0, 1.44.0)\" = [\n    \"migrate_v1.44.0_container-runtime-plugins-settings.lz4\",\n    \"migrate_v1.44.0_container-runtime-snapshotter-setting.lz4\",\n]\n\"(1.44.0, 1.45.0)\" = []\n\"(1.45.0, 1.46.0)\" = [\n    \"migrate_v1.46.0_kubernetes-static-pods-enabled-setting.lz4\",\n]\n\"(1.46.0, 1.47.0)\" = [\n    \"migrate_v1.47.0_container-runtime-concurrent-download-chunk-size.lz4\",\n    \"migrate_v1.47.0_host-bootstrap-containers-command-setting.lz4\"\n]\n\"(1.47.0, 1.48.0)\" = []\n\"(1.48.0, 1.49.0)\" = []\n\"(1.49.0, 1.50.0)\" = [\n    \"migrate_v1.50.0_kubernetes-reserved-pid-settings.lz4\",\n]\n\"(1.50.0, 1.51.0)\" = [\n    \"migrate_v1.51.0_kubernetes-ecr-credential-provider-patterns.lz4\",\n    \"migrate_v1.51.0_kubernetes-additional-settings.lz4\",\n    \"migrate_v1.51.0_kubernetes-beta-cpu-manager-policy-options.lz4\",\n]\n\"(1.51.0, 1.52.0)\" = []\n\"(1.52.0, 1.53.0)\" = []\n\"(1.53.0, 1.54.0)\" = [\n    \"migrate_v1.54.0_kubelet-device-plugins-mps-settings.lz4\",\n    \"migrate_v1.54.0_kubelet-device-plugins-mps-prefix-settings.lz4\"\n]\n\"(1.54.0, 1.55.0)\" = []\n\"(1.55.0, 1.56.0)\" = [\n    \"migrate_v1.56.0_image-verifier-plugins-extensible.lz4\"\n]\n\"(1.56.0, 1.57.0)\" = []\n"
  },
  {
    "path": "SECURITY.md",
    "content": "## Reporting a Vulnerability\n\nIf you discover a potential security issue in this project, we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com.\nPlease do **not** create a public GitHub issue.\n"
  },
  {
    "path": "SECURITY_FEATURES.md",
    "content": "# Security Features\n\n## Goals\n\nBottlerocket has the following high-level security goals.\nThey are listed in priority order.\n\n1. Harden the OS against persistent threats.\n2. Mitigate the impact of vulnerabilities in the OS.\n3. Protect containers from other containers.\n\nWe will add and enhance security features over time based on these goals.\n\n## Overview\n\n| Feature                                                                           | Version  |\n| :-------------------------------------------------------------------------------- | :------: |\n| [Automated security updates](#automated-security-updates)                         |  0.3.0   |\n| [Immutable rootfs backed by dm-verity](#immutable-rootfs-backed-by-dm-verity)     |  0.3.0   |\n| [Stateless tmpfs for /etc](#stateless-tmpfs-for-etc)                              |  0.3.0   |\n| [No shell or interpreters installed](#no-shell-or-interpreters-installed)         |  0.3.0   |\n| [Executables built with hardening flags](#executables-built-with-hardening-flags) |  0.3.0   |\n| [SELinux enabled in enforcing mode](#selinux-enabled-in-enforcing-mode)           |  0.3.0   |\n| [Kernel lockdown in integrity mode](#kernel-lockdown-in-integrity-mode)           |  1.1.0   |\n| [Secure Boot enabled](#secure-boot-enabled)                                       |  1.15.0  |\n\nThe version listed indicates the first release of Bottlerocket that included the feature.\nFeatures may evolve or improve over time.\n\n## Details\n\n### Automated security updates\n\nBottlerocket is designed for reliable security updates that can be applied through automation.\n\nThis is achieved through the following mechanisms:\n* Two partition sets and an active/passive flip to swap OS images\n* Declarative API with modeled settings for runtime configuration\n* Variants to silo backwards-incompatible or breaking changes\n\nUsing partition sets and modeled settings removes the dependency on correct local state for reliable updates.\nThere is no package manager database or shared filesystem tree that can become corrupted and make the process non-deterministic.\n\n#### Update Policy\n\nOur philosophy for variants is that the right time for an unexpected major version update to the kernel or orchestrator agent is \"never\".\nNew variants can introduce newer LTS kernels or GPU drivers.\nOn release, variants peg to a kernel and GPU driver version and relevant security patches are applied.\nHowever, in a situation where security patches are no longer available for the kernel or GPU driver, an existing variant may adopt a new version to address security vulnerabilities.\n\n##### Kubernetes variants\n\nBottlerocket provides updates for each Kubernetes variant for approximately 14 months after the first release of each variant.\nFor `aws-k8s-*` variants, Bottlerocket follows the [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html) support policy, including extended support beyond the typical 12 months support period.\n\nWe provide [a Kubernetes operator](https://github.com/bottlerocket-os/bottlerocket-update-operator) for automated updates to Bottlerocket.\nWe recommend deploying it on your Kubernetes clusters.\n\n##### ECS variant\n\nBottlerocket provides updates for each ECS variant for at least one year after the first release of each variant.\nBecause the ECS agent is backwards compatible, there is no need to create new variants on a regular cadence.\nECS variants will be added as necessary to introduce newer LTS kernels or potentially breaking changes.\n\nWe provide [an updater](https://github.com/bottlerocket-os/bottlerocket-ecs-updater) for automated updates to Bottlerocket.\nWe recommend deploying it on your ECS clusters.\n\n### Immutable rootfs backed by dm-verity\n\nBottlerocket uses [dm-verity](https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html) for its root filesystem image.\nThis provides transparent integrity checking of the underlying block device using a cryptographic digest.\n\nThe root filesystem is marked as read-only and cannot be directly modified by userspace processes.\nThis protects against some container escape vulnerabilities such as [CVE-2019-5736](https://www.openwall.com/lists/oss-security/2019/02/11/2).\n\nThe kernel is configured to restart if corruption is detected.\nThat allows the system to fail closed if the underlying block device is unexpectedly modified and the node is in an unknown state.\nThe uncontrolled reboot will disrupt running containers, which can trigger alarms and prompt administrators to investigate.\n\nAlthough this provides a powerful layer of protection, it is incomplete unless [Secure Boot is enabled](#secure-boot-enabled).\nOtherwise, an attacker with full access to the block device could alter both the verity metadata and the contents of the root filesystem.\n\n### Stateless tmpfs for /etc\n\nBottlerocket uses [tmpfs](https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt), a memory-backed filesystem, for `/etc`.\n\nDirect modification of system configuration files such as `/etc/resolv.conf` or `/etc/containerd/config.toml` is not supported.\nThis makes OS updates more reliable, as it is not necessary to account for local edits that might have changed the behavior of system services.\nIt also makes it harder for an attacker to modify these files in a way that persists across a reboot.\n\nThere are two supported ways to configure the OS in the presence of these restrictions.\n\nThe first is through the API.\nSettings are persisted across reboot and migrated through OS upgrades.\nThey are used to render system configuration files from templates on every boot.\n\nThe second is by using containers.\nSpecifications such as [CNI](https://github.com/containernetworking/cni) and [CSI](https://github.com/container-storage-interface/spec) provide ways to configure networking and storage devices.\nContainers written to these specifications can be deployed to nodes using orchestrator-specific mechanisms like [DaemonSets](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/).\n\nAll variants will include a secondary filesystem for local storage.\nIt will be mounted at `/local` with bind mounts for `/var` and `/opt`.\nModifications to this area will survive an OS update or a reboot.\n\n### No shell or interpreters installed\n\nBottlerocket does not have a shell installed in non-developer builds.\nInterpreted languages such as Python are not installed or even available as packages.\n\nShells and interpreters enable administrators to write code that combines other programs on the system in new ways.\nHowever, these properties can also be exploited by an attacker to pivot from a vulnerability that grants local code execution.\n\nThe lack of a shell also serves as a forcing function to ensure that new code for the OS is written in a preferred language such as Rust or Go.\nThese languages offer built-in protection against memory safety issues such as buffer overflows.\n\n### Executables built with hardening flags\n\nThe GCC cross-compilers in the [Bottlerocket SDK](https://github.com/bottlerocket-os/bottlerocket-sdk) are built with these options:\n* `--enable-default-pie` for `-fPIE` and `-pie` by default\n* `--enable-default-ssp` for `-fstack-protector-strong` by default\n\nPosition-independent executables (PIE) have their address space randomized on every execution.\nThis makes addresses harder to predict for an attacker that attempts to exploit a memory corruption vulnerability.\n\nThe stack protector feature enables stack canaries to detect stack overflow and abort the program if it occurs.\nThe \"strong\" version enables it for additional functions.\n\nAll C and C++ programs are compiled with the following options:\n* `-Wall` to warn about questionable constructs\n* `-Werror=format-security` to warn about unsafe uses of format functions\n* `-Wp,-D_FORTIFY_SOURCE=2` for runtime error checks in libc\n* `-Wp,-D_GLIBCXX_ASSERTIONS` for runtime error checks in libstdc++\n* `-fstack-clash-protection` for stack overflow detection\n\nAlthough C and C++ lack the memory safety of Go and Rust, these options add a layer of defense during build and execution.\n\nAll binaries are linked with the following options:\n* `-Wl,-z,relro` to mark segments read-only after relocation\n* `-Wl,-z,now` to resolve all symbols at load time\n\nTogether these enable [full RELRO support](https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro) which makes [ROP](https://en.wikipedia.org/wiki/Return-oriented_programming) attacks more difficult to execute.\n\n**Note:** Certain variants, such as the ones for NVIDIA, include precompiled binaries that may not have been built with these hardening flags.\n\n### SELinux enabled in enforcing mode\n\nBottlerocket enables SELinux by default, sets it to enforcing mode, and loads the policy during boot.\nThere is no way to disable it.\n\nSELinux is a Linux Security Module (LSM) that provides a mechanism for mandatory access control (MAC).\nProcesses that run as root with full capabilities are still subject to the mandatory policy restrictions.\n\nThe policy in Bottlerocket has the following objectives:\n1) Prevent most components from directly modifying the API settings.\n2) Block most components from modifying the container archives saved on disk.\n3) Stop containers from directly modifying the layers for other running containers.\n\nThe policy is currently aimed at hardening the OS against persistent threats.\nFuture enhancements to the policy will focus on mitigating the impact of OS vulnerabilities, and protecting containers from other containers.\n\n### Kernel lockdown in integrity mode\n\nBottlerocket enables Lockdown in \"integrity\" mode by default on most variants.\n\nLockdown is a Linux Security Module (LSM) that blocks certain actions which could compromise the Linux kernel.\nAs with SELinux, even processes that run as root with full capabilities are subject to these restrictions.\n\nCertain variants such as `*-nvidia` need to load unsigned kernel modules at runtime.\nThis is prohibited by the \"integrity\" mode, but required for the hardware to work as expected.\nOn these variants, Lockdown is set to \"none\" instead.\n\n### Secure Boot enabled\n\nBottlerocket enables Secure Boot for all new variants on platforms that support UEFI boot.\n\nThe goal is to prevent unsigned, untrusted code from running at any point until containers are started.\nThis is achieved by establishing the following chain of trust:\n1) The trusted platform firmware verifies that shim is signed correctly, then loads it.\n2) shim verifies that grub is signed correctly, then loads it.\n3) grub verifies that its grub.cfg is signed correctly, then loads it.\n4) grub verifies that the Linux kernel is signed correctly, then loads it.\n5) The Linux kernel verifies that the [immutable root filesystem](#immutable-rootfs-backed-by-dm-verity) has not been altered.\n\nSecure Boot only applies to platforms using UEFI firmware, and it is only enforced when the feature is enabled in the firmware.\nTherefore, systems using the legacy BIOS boot mode cannot benefit from Secure Boot.\nThis includes Xen-based EC2 instance types, and bare metal machines configured to emulate the legacy BIOS boot mode.\n"
  },
  {
    "path": "SECURITY_GUIDANCE.md",
    "content": "# Security Guidance\n\n## Overview\n\nBottlerocket adheres to the [Shared Responsibility Model](https://aws.amazon.com/compliance/shared-responsibility-model/) which defines security and compliance as a shared responsibility between the OS vendor and the customer.\n\nWe provide these recommendations, along with [details](#details) and [examples](#examples), to help you create a configuration that meets your security and compliance requirements.\n\n| Recommendation                                                                                                                        | Priority  |\n| :--------------------------------------------------------------------------------------------------                                   | :-------- |\n| [Enable automatic updates](#enable-automatic-updates)                                                                                 | Critical  |\n| [Avoid containers with elevated privileges](#avoid-containers-with-elevated-privileges)                                               | Critical  |\n| [Restrict access to the host API socket](#restrict-access-to-the-host-api-socket)                                                     | Critical  |\n| [Restrict access to the container runtime socket](#restrict-access-to-the-container-runtime-socket)                                   | Critical  |\n| [Design for host replacement](#design-for-host-replacement)                                                                           | Important |\n| [Enable kernel lockdown](#enable-kernel-lockdown)                                                                                     | Important |\n| [Limit use of host containers](#limit-use-of-host-containers)                                                                         | Important |\n| [Limit use of privileged SELinux labels](#limit-use-of-privileged-selinux-labels)                                                     | Important |\n| [Limit access to system mounts](#limit-access-to-system-mounts)                                                                       | Important |\n| [Limit access to host namespaces](#limit-access-to-host-namespaces)                                                                   | Important |\n| [Limit access to block devices](#limit-access-to-block-devices)                                                                       | Important |\n| [Enforce requested NVIDIA GPU limits for unprivileged containers](#enforce-requested-nvidia-gpu-limits-for-unprivileged-containers)   | Important |\n| [Limit use of NVIDIA GPU Time-Slicing](#limit-use-of-nvidia-gpu-time-slicing)                                                         | Important |\n| [Do not run containers as UID 0](#do-not-run-containers-as-uid-0)                                                                     | Moderate  |\n\n## Details\n\n### Enable automatic updates\n\nBottlerocket includes many [security features](SECURITY_FEATURES.md) to mitigate software vulnerabilities.\nThese countermeasures serve to reduce the reliability of exploits and to raise their cost.\nHowever, it is always better to patch vulnerabilities than to rely on mitigations alone.\n\nFor our Kubernetes variants, we provide [a Kubernetes operator](https://github.com/bottlerocket-os/bottlerocket-update-operator) for automated updates to Bottlerocket.\nWe recommend deploying it on your Kubernetes clusters.\n\nFor our ECS variant, we provide [an updater](https://github.com/bottlerocket-os/bottlerocket-ecs-updater) for automated updates to Bottlerocket.\nWe recommend deploying it on your ECS clusters.\n\n### Avoid containers with elevated privileges\n\nContainers can be made more secure by limiting the capabilities they have, by filtering syscalls they can make, and by changing the SELinux labels they use.\n\nCapabilities are a way to split up the traditional powers of the `root` user so that a subset of the permissions can be granted instead.\nFor example, `CAP_NET_BIND_SERVICE` can be granted to allow binding to a low-numbered port.\nBottlerocket uses `runc` to execute containers with [a subset of Linux capabilities](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md#security).\n\nSyscalls are a way for userspace programs to request services from the kernel.\nSeccomp filters can be used to allow access to a subset of syscalls.\nBottlerocket uses `containerd` as the container runtime which provides [a default seccomp profile](https://github.com/containerd/containerd/blob/master/contrib/seccomp/seccomp_default.go).\n\nSELinux labels are part of mandatory access controls, which impose constraints after discretionary access controls are checked.\nBottlerocket runs unprivileged containers with the restrictive `container_t` label.\n\nOrchestrators provide ways to disable these protections:\n* Docker can run containers with the `--privileged` flag\n* Kubernetes can run pods with `privileged: true` in the pod definition\n* Amazon ECS can run tasks with `\"privileged\": true` in the task definition\n\nBy default, Kubernetes also runs pods with no seccomp filter applied.\nPods can specify a seccomp profile, or you can apply a default profile using a [Pod Security Policy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/).\n\nWe recommend that you avoid containers with elevated privileges.\nThe default set of capabilities, the default seccomp filter, and the default SELinux labels should be used where possible.\n\n### Restrict access to the host API socket\n\nThe Bottlerocket API server listens for requests on a Unix domain socket.\nThe canonical location of this socket is `/run/api.sock`.\nIt is owned by UID 0 (`root`) and GID 274 (`api`).\nIt is labeled `api_socket_t`, so only processes with privileged SELinux labels can use it.\n\nWrite access to this socket will grant full control over system configuration.\nThis includes the ability to define an arbitrary source for a host container, and to run that container with \"superpowers\" that bypass other restrictions.\nThese \"superpowers\" are described [below](#limit-use-of-host-containers).\nFor Kubernetes variants, it also includes the ability to define and run static pods.\nThese are managed directly by `kubelet` and are not subject to admission controllers that enforce security policies for the cluster.\n\nWe recommend blocking access to the API socket from containers managed by the orchestrator.\nThe \"control\" host container can be used to modify settings when needed.\n\n### Restrict access to the container runtime socket\n\nDifferent [variants](variants/) of Bottlerocket may have different container runtimes installed.\nEach container runtime will have its own API and will listen for requests on a Unix domain socket.\nThe socket will usually be owned by UID 0 (`root`) and GID 0 (`root`).\n\nSome potential locations of container runtime sockets are:\n* `/run/docker.sock`\n* `/run/dockershim.sock`\n* `/run/containerd/containerd.sock`\n* `/run/host-containerd/host-containerd.sock`\n\nWrite access to any of these sockets will grant full control over container execution.\nThis includes the ability to run containers with elevated privileges and with access to all filesystem locations.\n\nOne common use case for mounting the container runtime socket is to perform container image builds.\nInstead of mounting the socket, you can use an image build tool that does not require additional privileges.\n\nWe recommend blocking access to the container runtime socket from containers managed by the orchestrator.\n\n### Design for host replacement\n\nOne of the main security objectives of Bottlerocket is to harden the OS against persistent threats.\nThis is closely related to the support for automated, in-place updates.\nApplying updates to the same host makes sense if you are confident that the underlying software can still be trusted.\n\nHowever, containers share the same kernel with the host.\nThe exposed kernel interface can be minimized through techniques such as seccomp filters, but it cannot be eliminated.\nIf the kernel is ever compromised through a local exploit, then other defenses may break down.\n\nWe recommend designing for periodic host replacement even with automated updates enabled.\n\n### Enable kernel lockdown\n\nThe security mechanisms in Bottlerocket ultimately depend on the kernel for enforcement.\nThis includes access controls such as capabilities and SELinux, and integrity checks such as dm-verity.\nModifications to the running kernel could bypass or subvert these mechanisms.\n\nBottlerocket enables the Lockdown security module and offers settings to choose from one of three modes.\n\nThe first mode, \"none\", effectively disables the protection.\n\nThe second mode, \"integrity\", blocks most ways to overwrite the kernel's memory and modify its code.\nEnabling this mode will prevent unsigned kernel modules from being loaded.\n\nThe third mode, \"confidentiality\", stops most ways of reading the kernel's memory from userspace.\nThe goal is to protect secrets that may be stored in the kernel, such as keys used to detect modification while the system is offline.\nBottlerocket does not make use of the secrets that this mode is meant to protect.\nEnabling this mode will break BPF, perf, and any other tools that rely on reading kernel memory.\n\nWe recommend enabling kernel lockdown in \"integrity\" mode.\n\n### Limit use of host containers\n\nBottlerocket offers host containers to provide out-of-band access to the underlying host OS.\n\nHost containers can be configured with an optional `superpowered` flag.\nThis causes the container to run with extra privileges, an unrestricted SELinux label, and additional mounts.\nThe current implementation can be found in [host-ctr](sources/host-ctr/cmd/host-ctr/main.go).\n\nTwo host containers are defined in the default configuration.\nThe [\"control\" host container](README.md#control-container) is enabled by default unless otherwise specified.\nIt provides remote connectivity through the AWS SSM [Session Manager](https://console.aws.amazon.com/systems-manager/session-manager/sessions).\nThe [\"admin\" host container](README.md#admin-container) is disabled by default unless otherwise specified.\nIt can be enabled through the \"control\" host container, through instance user data, or by accessing the host API socket.\n\nWe recommend leaving the \"admin\" host container disabled until it is necessary to use it.\nThe \"control\" host container can also be disabled if you are confident you will not need it.\n**This could leave you with no way to access the API and change settings on an existing node!**\n\nIf you define your own host container, avoid using `superpowered = true` unless your use case requires an extremely high level of privilege, such as loading an out-of-tree kernel module.\n\n### Limit use of privileged SELinux labels\n\nBottlerocket enables SELinux in enforcing mode by default.\nSELinux works by associating labels with subjects (processes) and objects (such as files).\n\nLabels are \"sticky\" by default: processes will receive the label of their parent process, and files will receive the label of the directory where they are created.\nA process can change its own label or the label of a child process under certain circumstances.\nThese changes are called \"transitions\".\nThe SELinux policy for Bottlerocket defines special transition rules for container runtimes.\n\nA container runtime can transition a child processes to any of these labels:\n* `container_t` (the default for ordinary containers)\n* `control_t` (the default for privileged containers)\n* `super_t` (opt-in for \"superpowered\" containers)\n\nThe `control_t` and `super_t` labels allow writes to the API socket.\nThe `super_t` label allows modifications to any file or directory on the host OS.\n\nSome orchestrators allow SELinux labels to be defined in the container specification, including Kubernetes and Amazon ECS.\nIf `control_t` or `super_t` is specified in this way, it will override the default transition rules and the container will run with additional privileges.\n\nWe recommend limiting access to any SELinux label other than `container_t`.\n\n### Limit access to system mounts\n\nBottlerocket provides a read-only root filesystem, ephemeral mounts for system directories such as `/etc` and `/run`, and persistent storage under `/local`.\n\nThe `/etc` directory contains system configuration files generated by the API.\nThese are regenerated when a setting changes, but otherwise not monitored.\nIf the contents of this directory are mounted into a privileged container, they can be modified in unexpected ways.\nThis is not supported and may interfere with the reliability of automated updates.\n\nThe `/run` directory contains ephemeral files such as Unix domain sockets used by the API server and the container runtime.\nIf the contents of this directory are mounted into a privileged container, they can be used to bypass security protections.\n\nThe `/local` directory is where persistent storage is mounted, with `/var` and `/opt` as subdirectories.\nThis is where cached container images, unpacked container layers, and files for host containers are stored.\nIf this directory or its subdirectories are mounted into a privileged container, the integrity of the system can be compromised.\n\nWe recommend limiting access to all system mounts.\n\n### Limit access to host namespaces\n\nNamespaces are one of the key building blocks for Linux containers.\n\nNetwork namespaces provide isolation for network resources such as IP addresses, ports, and routing tables.\nContainers that share the host network namespace can connect to services listening on the host loopback addresses `127.0.0.1` and `::1`.\nThese services are not otherwise reachable from the network.\n\nSharing the network namespace also enables access to abstract sockets.\nContainers that share the host network namespace can send messages to processes on the host which expose APIs over abstract sockets.\nThis can bypass intended restrictions for API access.\n\nPID namespaces provide isolation for the process ID number space.\nContainers that share the host PID namespace can interact with processes running on the host.\nThis includes the ability to send signals to those processes, which may interfere with system functionality.\n\nSharing the host PID namespace also enables access to the host filesystem through `/proc/<pid>/root` links for host processes.\nThis can bypass intended restrictions for system mounts.\n\nWe recommend limiting access to all host namespaces.\n\n### Limit access to block devices\n\nDirect access to block devices can be used to bypass abstractions such as filesystems and caches.\nThis is useful for databases and storage applications that want full control over the data layout on disk.\n\nThe order in which the kernel enumerates block devices is inconsistent and subject to change.\nTo avoid referring to the wrong device, Linux distributions use links under `/dev/disk` to map predictable identifiers to specific devices.\nBottlerocket relies on partition type GUIDs and partition names to discover its devices.\n\nOrchestrators offer ways to associate block devices with containers.\nFor example, Kubernetes allows pods to claim a \"block mode\" volume and mount the device to a desired path.\nContainers with direct access to a block device can alter the partition table or modify the filesystem metadata.\nIf the same partition type or partition name is used for another device, the `/dev/disk` link may point to the wrong device.\nThis could compromise the integrity of the host.\n\nWe recommend limiting access to block devices.\n\n### Enforce requested NVIDIA GPU limits for unprivileged containers\n\nWhen launching a container that has requested NVIDIA GPUs, the host software responsible for adding the devices to the container - the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html) - will use one of these sources to determine which devices should be added:\n\n* The `NVIDIA_VISIBLE_DEVICES` environment variable\n* Mounts configured by the [NVIDIA Kubernetes Device Plugin](https://github.com/NVIDIA/k8s-device-plugin)\n\nIf `NVIDIA_VISIBLE_DEVICES=\"all\"` is set in a container’s environment, it can gain access to all NVIDIA GPUs on the system regardless of the NVIDIA GPU limits requested through Kubernetes directives.\nBecause most popular container base images are configured this way, respecting this value by default would grant unprivileged containers access to all NVIDIA GPUs, ignoring the requested limits.\n\nTo prevent this, Bottlerocket configures the host software so that `NVIDIA_VISIBLE_DEVICES=\"all\"` is only respected for privileged containers.\n\nIf you need to grant unprivileged containers access to all NVIDIA GPUs using this environment variable - bypassing any requested GPU limits - you can apply these settings:\n\n\n```toml\n[settings.kubelet-device-plugins.nvidia]\n# Configures NVIDIA_VISIBLE_DEVICES with the list of devices\ndevice-list-strategy = \"envvar\"\n\n[settings.nvidia-container-runtime]\n# Allows reading the devices from NVIDIA_VISIBLE_DEVICES\nvisible-devices-as-volume-mounts = false\n\n# Allows granting access to all unprivileged\n# containers with NVIDIA_VISIBLE_DEVICES=all\nvisible-devices-envvar-when-unprivileged = true\n```\n\nWe recommend leaving these settings at the default values, which will enforce the requested NVIDIA GPU limits for unprivileged containers.\n\n### Limit use of NVIDIA GPU Time-Slicing\nBottlerocket supports NVIDIA GPU time-slicing, enabling system administrators to allocate a set of replicas for a GPU, which can be assigned to individual pods for running various workloads.\n\nInternally, GPU time-slicing is used to multiplex workloads from multiple replicas of the same underlying GPU, providing each process with an equal share of time across all pods. However, while time-slicing allows sharing of GPUs among multiple workloads, it does not provide memory or fault isolation between replicas.\n\nWithout memory isolation, all workloads share the same memory space, which can lead to contention, and possible interference between processes. This can affect the predictability and performance of each workload, as one process may consume more resources than anticipated, leaving less available for others. Moreover, without fault isolation, if one process fails, it has the potential to affect all other processes running on the GPU. These impacts can happen to processes running in different containers with different privilege levels.\n\nWe recommend keeping the NVIDIA GPU time-slicing feature in a disabled state and only enabling it when necessary.\n\n### Do not run containers as UID 0\n\nBottlerocket does not currently support user namespaces.\nThis means that UID 0 (`root`) inside the container is the same as UID 0 on the host.\n\nA process in a container that runs as UID 0 will have nearly unlimited access to the host if all of these are true:\n* it uses a privileged SELinux label\n* it has access to system mounts\n* it shares the host namespaces\n* it has elevated privileges, with all capabilities and no seccomp filter\n\nThis is essentially the configuration that is used for a host container with \"superpowers\", where `superpowered = true` is set.\n\nWe recommend that you do not run containers as UID 0.\n\n## Examples\n\n### Amazon EC2\n\nThese settings can passed as [user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) on EC2 instance launch.\nThey apply to any Bottlerocket variant.\n\n```toml\n# Enable kernel lockdown in \"integrity\" mode.\n# This prevents modifications to the running kernel, even by privileged users.\n[settings.kernel]\nlockdown = \"integrity\"\n\n# The admin host container provides SSH access and runs with \"superpowers\".\n# It is disabled by default, but can be disabled explicitly.\n[settings.host-containers.admin]\nenabled = false\n\n# The control host container provides out-of-band access via SSM.\n# It is enabled by default, and can be disabled if you do not expect to use SSM.\n# This could leave you with no way to access the API and change settings on an existing node!\n[settings.host-containers.control]\nenabled = false\n```\n\n### Amazon ECS\n\nThese settings can passed as [user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html) on EC2 instance launch.\nThey are specific to the `aws-ecs-2` variant.\n\n```toml\n# By default, this variant does not allow launching privileged containers.\n# The feature can also be disabled explicitly.\n[settings.ecs]\nallow-privileged-containers = false\n```\n\n### Kubernetes\n\nThe following [Pod Security Policy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) is based on our recommendations.\nIt can be used as a starting point for your own policy.\n\n```yaml\n---\napiVersion: policy/v1beta1\nkind: PodSecurityPolicy\nmetadata:\n  name: restricted-psp\n\n  # Ensure that the default seccomp filter is used.\n  annotations:\n    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'runtime/default'\n    seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'\n\nspec:\n  # Do not allow containers to run as privileged.\n  privileged: false\n\n  # Do not allow containers to gain new privileges.\n  allowPrivilegeEscalation: false\n\n  # Remove all capabilities from the default set.\n  requiredDropCapabilities:\n    - ALL\n\n  # Run all containers with the less privileged container_t label.\n  seLinux:\n    rule: 'MustRunAs'\n    seLinuxOptions:\n      user: system_u\n      role: system_r\n      type: container_t\n      level: s0\n\n  # Do not allow containers to run as any system user.\n  runAsUser:\n    rule: 'MustRunAs'\n    ranges:\n      - min: 1000\n        max: 65535\n\n  # Do not allow containers to run as any system group.\n  runAsGroup:\n    rule: 'MustRunAs'\n    ranges:\n      - min: 1000\n        max: 65535\n\n  # Do not allow containers to add other system groups.\n  supplementalGroups:\n    rule: 'MustRunAs'\n    ranges:\n      - min: 1000\n        max: 65535\n\n  # Do not allow containers to use other system groups for volumes.\n  fsGroup:\n    rule: 'MustRunAs'\n    ranges:\n      - min: 1000\n        max: 65535\n\n  # Do not allow containers to share host namespaces.\n  hostNetwork: false\n  hostIPC: false\n  hostPID: false\n\n  # Do not allow containers to use or write to host paths.\n  allowedHostPaths:\n    - pathPrefix: \"/tmp\"\n      readOnly: true\n\n  # Allow minimal set of core volume types.\n  volumes:\n    - 'configMap'\n    - 'emptyDir'\n    - 'projected'\n    - 'secret'\n    - 'downwardAPI'\n    - 'persistentVolumeClaim'\n```\n"
  },
  {
    "path": "SUPPORTED-HARDWARE.md",
    "content": "# Supported hardware for Bottlerocket on bare metal\n\nThe Bottlerocket bare metal variant is intended to run Bottlerocket on targets outside of AWS or vmware clusters.\nThe vast diversity of available hardware poses a challenge.\nThe need to be compatible with as much hardware as possible out-of-the-box conflicts with Bottlerocket's core principles of keeping it small and simple.\nTo strike the right balance, the initial offering focuses on compatibility with common x86_64 server hardware.\nThe Bottlerocket kernel for metal is configured to include drivers for a wider spread of 10G+ Ethernet NICs in their base configuration (no model-specific FPGA offloading support and similar) as well as common RAID controllers.\n\nBeyond that, the number of drivers included in the Bottlerocket kernels has been reduced substantially comparing to common general purpose Linux distributions.\nThe aim is to keep Bottlerocket images as lean as possible, while trying to maintain a good out-of-the-box coverage.\n\nIt is possible that Bottlerocket is missing drivers for your specific hardware.\nPlease [submit an issue](https://github.com/bottlerocket-os/bottlerocket/issues/new?assignees=&labels=&template=metal_driver.md) to open a discussion on inclusion of additional drivers.\n\n## Limitations of hardware support to be added\n\nAdding drivers that are part of the upstream Linux source tree is an easy fix for certain target platforms.\nHowever, there are limitations of what to add to the Bottlerocket metal variant in order to accommodate Bottlerocket's core principles of keeping it small and simple.\nIf you want to create a custom variant that for example contains specific drivers, the current work towards out-of-tree builds will help you achieve that.\nWork for that is currently underway and can be tracked in [issue #2669](https://github.com/bottlerocket-os/bottlerocket/issues/2669).\nUntil out-of-tree builds land the following limitations apply to the available Bottlerocket variants:\n\n* There is no plan to add out-of-tree drivers to Bottlerocket images.\n* There is no plan to add additional CPU architectures.\n* There is no plan to add drivers for embedded devices in the core images.\n\nIf you have questions about these limitations or want to debate them, feel free to open an issue or start a discussion.\n\n## Testing\n\nThe AWS Bottlerocket team does basic functional testing on a limited set of server configurations they have available (See [Hardware configurations confirmed to work](#hardware-configurations-confirmed-to-work)).\n\"Functional testing\" means that machines are provisioned and base functionality of storage and network hardware is proven by a properly functioning distribution.\n\nWith the vast diversity of hardware available community involvement in confirming hardware configurations work is key.\nWe are interested to learn about your success stories running Bottlerocket on other hardware platforms.\nFeel free to report a working configuration below by opening a PR with the information.\n\n### Hardware configurations confirmed to work\n\nBottlerocket is tested on and known to work with the hardware below.\n\n| Server model | CPU | BIOS/UEFI | Network Card | Disk | RAID/Storage controller | Entity confirming |\n| --- | --- | --- | --- | --- | --- | --- |\n| Supermicro SYS-E200-8D | Intel Xeon D-1528 | BIOS & UEFI | Intel i350 1G & 10G | SATA SSD, NVME | N/A | AWS Bottlerocket team |\n| Dell R240 | Intel Xeon E2236 | BIOS & UEFI | Broadcom BCM5720 1G | SATA SSD (RAID0) | PERC H730P | AWS Bottlerocket team |\n| Dell R620 | Intel Xeon E5-2660 | BIOS | Intel i350 1G | SATA HDD | PERC H710P | AWS Bottlerocket team |\n| HP DL20 | Intel Xeon E2234 | BIOS | HPE 361i 1G | SATA SSD | HPE Smart Array S100i | AWS Bottlerocket team |\n\n"
  },
  {
    "path": "TESTING.md",
    "content": "# Testing Bottlerocket\n\n🚧 👷\n\nThis section is under active development.\nWe are working on tooling for running Bottlerocket integration tests.\nWhile the work is underway, there will be frequent changes to this document.\n\n## Unit Tests\n\nIt is easy to execute unit tests, you can run them from the root of the repo with `cargo make unit-tests`.\nNote that some code in Bottlerocket is conditionally compiled based on variant thus some tests won't be executed.\nUnless you intend to test the default variant, it is best to pass the relevant variant and architecture like this:\n\n```shell\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-ecs-2\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  unit-tests\n```\n\n## Integration Tests\n\nUnit tests will only get us so far.\nUltimately we want to know if Bottlerocket runs correctly as a complete system.\nWe have created a [command line utility] and [testing system] to help us test Bottlerocket holistically.\n\n[command line utility]: ./tools/testsys\n[testing system]: https://github.com/bottlerocket-os/bottlerocket-test-system\n\nThe test system coordinates:\n- the creation of a cluster (or re-use of an existing cluster),\n- creation of Bottlerocket instances,\n- running tests that target the created cluster and instances,\n- terminating the Bottlerocket instances,\n- terminating the Kubernetes cluster (if desired)\n\nTestsys uses a Kubernetes operator to test bottlerocket.\nThe operator runs in a cluster that is separate from the one where you are testing Bottlerocket nodes.\nWe call this control cluster the *testsys cluster*.\nWhen you launch a Bottlerocket integration test, pods run in the testsys cluster to perform the steps described above.\n\n## Setup\n\n### EKS\n\nIt is possible to run your testsys cluster anywhere so long as it has the necessary authorization and networking.\nWe have plans to make this easy to do in EKS by providing the instructions and role permissions you need.\nHowever, some work is still needed on the roles, so check back for those instructions in the future!\n\n### Using a Temporary Kind Cluster\n\nFor developer workflows, the quickest way to run a testsys cluster is using [kind].\n\n[kind]: https://kind.sigs.k8s.io/\n\n**Important:** only use `kind` for temporary testsys clusters that you will be using yourself.\nDo not use `kind` for long-lived clusters or clusters that you will share with other users.\n\nHere are the steps to set up a testsys cluster using `kind`.\n\nCreate a kind cluster (any name will suffice):\n\n```shell\nkind create cluster --name testsys\n```\n\nIf you want to store the kubeconfig file, set the `KUBECONFIG` variable to some path (there should be no pre-existing file there).\nIt doesn't really matter where this is, since this is a throwaway cluster and then write the\nkubeconfig to that path.\nThe environment variable `TESTSYS_KUBECONFIG` is used by all testsys\nrelated cargo make tasks.\n\n```shell\nexport TESTSYS_KUBECONFIG=\"${HOME}/testsys-kubeconfig.yaml\"\nkind get kubeconfig --name testsys > $TESTSYS_KUBECONFIG\n```\n\nInstall the testsys cluster components:\n\n```shell\ncargo make setup-test\n```\n\nTestsys containers will need AWS credentials.\n\n**Reminder**: this is for your developer workflow only, do not share this cluster with other users.\n\n```shell\ncargo make testsys add secret map  \\\n --name \"creds\" \\\n \"access-key-id=$(aws configure get aws_access_key_id)\" \\\n \"secret-access-key=$(aws configure get aws_secret_access_key)\"\n```\n\nIf you have a named profile you can use the following.\n```shell\nPROFILE=<Your desired profile name>\ncargo make testsys add secret map  \\\n --name \"creds\" \\\n \"access-key-id=$(aws configure get aws_access_key_id --profile ${PROFILE})\" \\\n \"secret-access-key=$(aws configure get aws_secret_access_key --profile ${PROFILE})\"\n```\n\nIf you added a secret, you then need to pass the secret's name to testsys\nthrough an environment variable:\n```shell\nexport TESTSYS_AWS_SECRET_NAME=\"awsCredentials=<Name of your secret>\"\n```\n\n### Conveniences\n\nAll testsys commands can be run using cargo make to eliminate the chance of 2 different versions of\ntestsys being used.\nTestsys requires the controller and the agent images to be of the same testsys version.\n\n```shell\ncargo make testsys <arguments>\n```\n\nThe Bottlerocket components are found in the `testsys` Kubernetes namespace.\n\n## Run\n\nNow that you have the testsys cluster set up, it's time to run a Bottlerocket integration test!\n\n### Configuration\n\nThere are many arguments that can be configured via environment variables with `cargo make`; however, it is possible to create a configuration file instead.\nCheck out the [example config file](tools/testsys/Test.toml.example) for a sample `Test.toml` file.\n\nFor example, the instance type can be specified based on variant requirements:\n\n```toml\n[aws-k8s]\n# Set the default instance type for all `aws-k8s` variants\ninstance-type = \"m5.xlarge\"\n\n[aws-k8s-nvidia]\n# Override the instance type for `nvidia` `aws-k8s` variants\ninstance-type = \"g5g.2xlarge\"\n```\n\nSince `aws-k8s-nvidia` is a `<FAMILY>-<FLAVOR>` level configuration it will take precedence over `aws-k8s` which is `<FAMILY>` level configuration.\n\nTables can also be created for custom testing configurations. For a custom test type called `foo`, the config above can be updated: \n\n```toml\n[aws-k8s]\n# Set the default instance type for all `aws-k8s` variants\ninstance-type = \"m5.xlarge\"\n\n[aws-k8s.configuration.foo]\n# Set the default instance type for all `aws-k8s` variants when `TESTSYS_TEST=foo` is set\ninstance-type = \"m5.8xlarge\"\n\n[aws-k8s-nvidia]\n# Override the instance type for `nvidia` `aws-k8s` variants\ninstance-type = \"g5g.2xlarge\"\n\n[aws-k8s-nvidia.configuration.foo]\n# Override the instance type for `nvidia` `aws-k8s` variants when `TESTSYS_TEST=foo` is set\ninstance-type = \"g5g.8xlarge\"\n```\n\n### Variants\n\nDifferent Bottlerocket variants require different implementations in the test system.\nFor example, to ensure that Kubernetes variants are working correctly, we use [Sonobuoy] to run through the K8s E2E conformance test suite.\nFor ECS, we run a [task] on Bottlerocket to make sure Bottlerocket is working.\nWe use EC2 and EKS for `aws-k8s` variants and vSphere for `vmware-k8s` variants, and so on.\n\n[Sonobuoy]: https://sonobuoy.io/\n[task]: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/welcome-features.html\n\nWe have attempted use sensible defaults for these behaviors when calling the `cargo make test` command.\n\n### aws-k8s\n\nYou need to [build](BUILDING.md) Bottlerocket and create an AMI before you can run a test.\nChange the commands below to the desired `aws-k8s` variant and AWS region:\n\n**Caution**: An EKS cluster will be created for you.\nBecause these take a long time to create, the default testsys behavior is to leave this in place so you can re-use it.\nYou will need to delete the EKS cluster manually when you are done using it.\n(EC2 instances are terminated automatically, but it's worth double-checking to make sure they were terminated.)\n\n```shell\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-k8s-1.32\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  build\n\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-k8s-1.32\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  -e PUBLISH_REGIONS=\"us-west-2\" \\\n  ami\n\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-k8s-1.32\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  test\n```\n\n```shell\ncargo make watch-test\n```\n\n**Note**: You can provision nodes with karpenter by specifying `resource-agent-type = \"karpenter\"` in `Test.toml`.\nTo follow the generic mapping, use the following configuration:\n\n```toml\n[aws-k8s.configuration.karpenter]\ntest-type = \"quick\"\nresource-agent-type = \"karpenter\"\nblock-device-mapping = [\n    {name = \"/dev/xvda\", volumeType = \"gp3\", volumeSize = 4, deleteOnTermination = true},\n    {name = \"/dev/xvdb\", volumeType = \"gp3\", volumeSize = 20, deleteOnTermination = true},\n]\n```\n\nThis configuration creates a new test type for all `aws-k8s` variants called `karpenter` (the string following `.configuration` in the table heading).\n\n\nBefore launching nodes with karpenter you will need to add the karpenter role to your cluster's `aws-auth` config map.\n\n```bash\n# Change to your clusters name\nCLUSTER_NAME=my-cluster\nACCOUNT_ID=your-account-id\nREGION=us-west-2\neksctl create iamidentity mapping \\\n  -r ${REGION} \\\n  --cluster ${CLUSTER_NAME} \\\n  --arn arn:aws:iam::${ACCOUNT_ID}:role/KarpenterInstanceNodeRole \\\n  --username system:node:{{EC2PrivateDNSName}} \\\n  --group system:bootstrappers \\\n  --group system:nodes\n```\n\nYou can run the test by calling,\n\n```bash\ncargo make -e TESTSYS_TEST=karpenter test\n```\n\n### aws-ecs\n\nYou need to [build](BUILDING.md) Bottlerocket and create an AMI before you can run a test.\nThe default instance type to be used is `m5.large` for `x86_64` and `m6g.large` for `aarch64`, but can be controlled by setting the environment variable `TESTSYS_INSTANCE_TYPE`.\nThis is useful while testing NVIDIA variants, since they require instance types with support for NVIDIA GPUs.\nChange the commands below to the desired `aws-ecs` variant and AWS region:\n\n```shell\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-ecs-2\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  build\n\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-ecs-2\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  -e PUBLISH_REGIONS=\"us-west-2\" \\\n  ami\n\ncargo make \\\n  -e BUILDSYS_VARIANT=\"aws-ecs-2\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  test\n```\n\n```shell\ncargo make watch-test\n```\n\n**Note:** For more information on publishing AMIs see [publishing](PUBLISHING.md).\n\n### vmware-k8s\n\nFirst, an initial management cluster needs to be created using [`EKS Anywhere`](https://anywhere.eks.amazonaws.com/docs/getting-started/production-environment/vsphere-getstarted/#create-an-initial-cluster).\nYou can then set `TESTSYS_MGMT_CLUSTER_KUBECONFIG` to the path to the management clusters kubeconfig.\nYou need to [build](BUILDING.md) Bottlerocket and a publicly accessible [TUF repository](https://github.com/bottlerocket-os/bottlerocket/blob/develop/PUBLISHING.md#repo-location) to test VMware variants.\nEither `Infra.toml` or your environment need to be configured.\nIf using environment variables make sure to set the following environment variables:\n- GOVC_URL\n- GOVC_USERNAME\n- GOVC_PASSWORD\n- GOVC_DATACENTER\n- GOVC_DATASTORE\n- GOVC_NETWORK\n- GOVC_RESOURCE_POOL\n- GOVC_FOLDER\n\nTestsys will use the data center specified in `Test.toml` first.\nIf no data center is specified in `Test.toml`, testsys will use the first data center listed in `Infra.toml`\nVMware testing also requires a `control-plane-endpoint` to be set in `Test.toml` for vSphere K8s cluster creation.\nChange the commands below to the desired `vmware-k8s` variant:\n\nFirst, build the VMware variant you want to test.\n\n```shell\ncargo make \\\n  -e BUILDSYS_VARIANT=\"vmware-k8s-1.31\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  build\n```\n\nBuild the TUF repo containing the OVA templates.\n\n```shell\ncargo make \\\n  -e BUILDSYS_VARIANT=\"vmware-k8s-1.31\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  repo\n```\n\nSync TUF repos containing the VMware variant's metadata and targets.\nMake sure the TUF repos are accessible via unauthenticated HTTP or HTTPS and match the URLs in `Infra.toml`.\n\nNow, you can run the test.\n\n```shell\ncargo make \\\n  -e BUILDSYS_VARIANT=\"vmware-k8s-1.31\" \\\n  -e BUILDSYS_ARCH=\"x86_64\" \\\n  test \\\n  --mgmt-cluster-kubeconfig ${TESTSYS_MGMT_CLUSTER_KUBECONFIG}\n```\n\nYou can monitor the tests with:\n\n```shell\ncargo make watch-test\n```\n\n## Migration Testing\n\nMigration testing is used to ensure Bottlerocket can update from one version to a new version and back.\nThis involves launching Bottlerocket instances, upgrading them, and downgrading them.\n\nMigration testing launches instances of a starting Bottlerocket version, or a provided initial AMI and migrates instances to the target version.\nIn order to accomplish this a few artifacts need to be created:\n* A publicly accessible TUF repository\n* A previous release of Bottlerocket signed with available keys\n* The AMI ID for the previous release\n* Image artifacts and local TUF repos of said artifacts for current changes\n\n### The setup\n\n#### Prepare `Infra.toml`\n\nWe need the URL of an accessible TUF repo so the Bottlerocket instances know where to retrieve the update metadata and targets.\nFollow our [publishing guide](PUBLISHING.md#repo-location) to set up TUF repos.\n`Infra.toml` is used by testsys to determine TUF repo locations, so `metadata_base_url` and `targets_base_url` need to be set based on the repo that was just created.\nThe examples below also assume that the default repo is being used in `Infra.toml`, but any repo can be used by setting the `PUBLISH_REPO` environment variable.\n\n#### Starting Bottlerocket images\n\nIn this example we will use `v1.9.0` as our starting Bottlerocket version, but any tag from Bottlerocket will work.\nThe following bash script will checkout the proper branch from git and create the build images and TUF repos for testing.\n\n```shell\ngit checkout \"v1.9.0\"\ncargo make\ncargo make ami\ncargo make repo\n```\n\nRemember to sync your TUF repos with the new metadata and targets.\n\n#### Target Bottlerocket images\n\nNow, it's time to create the Bottlerocket artifacts that need to be upgraded to.\n\nSwitch to the working git branch that should be built from.\n\n```shell\nWORKING_BRANCH=\"develop\"\ngit checkout \"${WORKING_BRANCH}\"\n```\n\nNext, build Bottlerocket images and repos and sync TUF repos.\nThe architecture and variant can be configured with `BUILDSYS_ARCH` and `BUILDSYS_VARIANT`.\n\n```shell\ncargo make\ncargo make ami\ncargo make repo\n```\n\nNow, sync your TUF repos with the new metadata and targets.\n\nThis completes the setup and it is time to test migrations!\n\n### Testing Migrations\n\nThe previous steps set up the artifacts necessary to perform migration testing using `testsys`.\nEnsure all environment variables are still set and set them if they aren't.\n\nTo run the migration test set `TESTSYS_TEST=migration` in the `cargo make test` call.\nThis will automatically determine the AMI that should be used by finding the latest released version of bottlerocket and checking the user's AMIs to find the correct starting AMI ID.\nRemember to set the environment variables for the architecture and variant.\n\n```shell\ncargo make -e TESTSYS_TEST=migration test\n```\n\nTo see the state of the tests as they run use `cargo make watch-test`.\n\n### Testing Workloads\n\nWorkload tests are tests designed to run as an orchestrated container.\nA workload test is defined in `Test.toml` with a map named `workloads`.\n\n```toml\n[aws-nvidia]\nworkloads = { <WORKLOAD-NAME> = \"<WORKLOAD-IMAGE-URI>\" }\n```\n\nTo run the workload test set `TESTSYS_TEST=workload` in the `cargo make test` call.\n\n```shell\ncargo make -e TESTSYS_TEST=workload test\n```\n\nTo see the state of the tests as they run use `cargo make watch-test`.\n\nFor more information can be found in the [TestSys workload documentation](https://github.com/bottlerocket-os/bottlerocket-test-system/tree/develop/bottlerocket/tests/workload).\n\n### Custom Test Types\n\nCustom tests can be run with TestSys by calling `cargo make -e TESTSYS_TEST=<CUSTOM-TEST-NAME> test -f <PATH-TO-TEMPLATED-YAML>`.\n\nFirst, a test agent needs to be constructed.\nThe `test-agent-cli` provides an interface for creating bash based testing agents.\nCheckout the [runbook](https://github.com/bottlerocket-os/bottlerocket-test-system/blob/develop/agent/test-agent-cli/design/RUNBOOK.md) for instructions on creating an agent.\n\nOnce an agent has been created, the yaml template can be created.\nValues from `Test.toml` can be inserted into a yaml manifest so that a single manifest can be used for all variants in a family.\n\n```yaml\napiVersion: {{api-version}}\nkind: Test\nmetadata:\n  # The name of the crd created is dependent on the arch and variant for \n  # the test being run.\n  name: {{kube-arch}}-{{kube-variant}}-custom\n  namespace: {{namespace}}\nspec:\n  retries: 5\n  agent:\n    name: custom-test-agent\n    image: example-test-agent-cli:latest\n    keepRunning: false\n    configuration:\n      clusterName: {{cluster-name}}\n      instanceType: {{instance-type}}\n  resources: []\n  dependsOn: []\n  # The secrets will automatically be populated from the config file, \n  # no template is needed.\n  secrets: {}\n```\n\nAfter the agent has been build and the yaml file is created, the test can be run using `cargo make -e TESTSYS_TEST=<CUSTOM-TEST-NAME> test -f <PATH-TO-YAML-FILE>` \n"
  },
  {
    "path": "TRADEMARKS.md",
    "content": "# TRADEMARK POLICY\n\nUpdated April 13, 2023\n\nThis Policy provides guidelines for use of the \"Bottlerocket\" name and logos (the \"Bottlerocket Trademarks\") to identify the Bottlerocket software.\nAmazon.com, Inc. or its affiliates (\"Amazon\") strives to be a steward of the Bottlerocket brand for the entire Bottlerocket Community and is the owner of the Bottlerocket Trademarks.\nAs such, the law obligates us to police and protect the trademarks.\nTherefore, we require use of the Bottlerocket Trademarks to be in accordance with this Policy.\nIndeed, Amazon’s own use is designed to be consistent with this Policy.\n\nOur goal is to ensure, on behalf of the Bottlerocket Community, that the Bottlerocket Trademark remain reliable indicators of quality and security while also permitting community members, software distributors and others to discuss Bottlerocket and to accurately describe their products’ affiliation with Bottlerocket or the Bottlerocket Community, as well as exercise their rights given Bottlerocket’s open source nature.\nNote that this Policy only applies to use of the Bottlerocket Trademarks.\n\n## Overall Guidelines\n\nYou may use the Bottlerocket Trademarks to refer to the Bottlerocket software provided that your use is in compliance with this Policy.\nAny other use of the Bottlerocket Trademarks requires prior written permission.\nOverall, your use of the Bottlerocket Trademarks must not be confusing, misleading, false, or damaging to the Bottlerocket software, the Bottlerocket Community or to the Bottlerocket Trademarks themselves.\n\nPeople should always know who they are dealing with, and where the software they are downloading and using came from.\nYou may not use the Bottlerocket Trademarks in any manner that implies approval or endorsement by, or association with, the Bottlerocket project or the Bottlerocket Community.\nWhen using the Bottlerocket Trademarks, your branding should be distinguishable from Bottlerocket trade dress.\n\nYou may not use the Bottlerocket Trademarks in a manner that may diminish or otherwise damage the goodwill in the Bottlerocket Trademarks.\nThe \"Bottlerocket\" word mark should be used in its exact form, and not abbreviated or combined with any other word or words (e.g., \"Bottlerocket\" software rather than \"BTLRKT\" or \"Bottlerocket-ified\").\nSimilarly, the Bottlerocket logos should not be modified or integrated with your logos or other designs.\nYou may create a lockup with your logo and a Bottlerocket logo side by side so long as your logo is not confusingly similar to the Bottlerocket logo and appears first and so long as your use complies with this policy.\n\nYour use of the Bottlerocket Trademarks does not transfer rights in the trademarks or goodwill to you.\n\n## Uses that do not require permission\n\nProvided your use complies with this Policy, you may use the Bottlerocket logos to link to the Bottlerocket website, to indicate that your software or service uses the Bottlerocket software, in architecture diagrams to show how your software or service integrates with Bottlerocket, and in presentations, social media posts (but not as your account image or avatar), whitepapers, blog posts, and similar content as a reference to the Bottlerocket project itself.\nIt should be clear what role the Bottlerocket project or software plays in the context of your software or services.\nThe Bottlerocket logos should not be more prominent than your own branding.\n\nUse the official versions of the Bottlerocket logos available for download [here](https://avatars.githubusercontent.com/u/61023959?s=200&v=4).\nYou may transform the file format itself for ease of use and modify the colors.\n\n![Original Bottlerocket Logo](https://avatars.githubusercontent.com/u/61023959?s=200&v=4)\n\nProvided your use complies with this Policy, you may use the \"Bottlerocket\" word mark to accurately reference the Bottlerocket software, including on your website, in presentations and publications, at events, in advertising and marketing material, etc., for commercial and noncommercial purposes.\nYou may use the \"Bottlerocket\" word mark and any logos we placed on the software in connection with a redistribution of an official distribution of the Bottlerocket software that has not been modified or changed in any way.\n\nThose taking full advantage of the open source nature of the Bottlerocket code may make modifications in accordance with the applicable open source license of Bottlerocket.\nYou may use the \"Bottlerocket\" word mark to refer to your modified version of Bottlerocket provided (a) you include an additional identifier indicating you as the source of the modified version (e.g., \"Foocorp’s Bottlerocket Derivative\"), (b) you clearly identify your modifications and indicate you are the source of the modifications, (c) your use does not suggest any affiliation between Bottlerocket or the Bottlerocket Community and you or your modified version of Bottlerocket, and (d) your use of the \"Bottlerocket\" word mark should not be more prominent than your additional identifier.\n\nThose taking advantage of the open source nature of the Bottlerocket code may also offer services for, or software that works with, Bottlerocket or modified versions of Bottlerocket, such as cloud management services.\nUsers should not be confused as to the source of your software or services. With that in mind, you may use the \"Bottlerocket\" word mark to refer to services for, or software that works with, Bottlerocket or modified versions of Bottlerocket provided (a) you include an additional identifier indicating you as the source of the software or services (e.g., \"Foocorp’s Bottlerocket Tool\" or \"Foocorp Bottlerocket Service\"), (b) if your services or software works with a modified version of Bottlerocket, you clearly identify the modifications and indicate the source of the modifications, (c) your use does not suggest any affiliation between Bottlerocket or the Bottlerocket Community and you or your work, and (d) your use of the \"Bottlerocket\" mark should not be more prominent than your additional identifier.\n\nYou may also use the \"Bottlerocket\" word mark to make accurate statements about compatibility and interoperability using relational phrases such as \"works with,\" \"runs on,\" \"compatible with,\" and the like (e.g., \"Foocorp Software powered by Bottlerocket\" or \"Foocorp Software for Bottlerocket\" or \"Foocorp Software with Bottlerocket compatibility\").\n\n## Uses that require permission\n\nThe following uses of the Bottlerocket Trademarks require our prior written approval:\n\n* Use of the Bottlerocket logos in any way other than as expressly authorized by this Policy;\n* Use as part of a domain name, except that you may use the Bottlerocket Trademarks in a subdomain name provided your use otherwise complies with this Policy (e.g., Bottlerocket.foocorp.com);\n* Use with non-software goods or services (e.g., physical products like devices or services that do not directly use the Bottlerocket software), except that you may use the Bottlerocket Trademarks with a limited number of swag or promotional items not for sale such as t-shirts, lanyards, stickers, mugs, or pens; and\n* Use that does not comply with the terms of this Policy.\n\nYou may not use the Bottlerocket Trademarks in connection with use or distribution of the Bottlerocket software, except as permitted by this Policy.\n\n## Questions\n\nIf you are unsure whether your use of the Bottlerocket Trademarks is permitted under this Policy, feel free to contact us and ask.\nIf you have questions about these guidelines or use of any other Amazon trademark, please contact trademarks@amazon.com for assistance, or write to us at:\n\n```text\nAmazon.com, Inc.\nAttention: Trademarks\nPO Box 81226\nSeattle, WA 98108-1226\n```\n\nThis Policy is based in part on the [open source trademark policy defined by the Mozilla organization](https://www.mozilla.org/en-US/foundation/trademarks/policy/), therefore, the text of this Policy (and not the Bottlerocket Trademarks themselves) is licensed under the Creative Commons \"Attribution-ShareAlike 2.0\" license.\n\n## FAQ\n\n**1. Can I create and redistribute my own builds of Bottlerocket?**\n\nIf you build Bottlerocket from unmodified source and redistribute the results, you may use \"Bottlerocket\" only if it is clear in both the name of your distribution and the content associated with it that your distribution is your build of Bottlerocket and not the official build, and you must identify the commit from which it is built, including the commit date.\n\n**2. What OS changes do I need to make to a modified version of Bottlerocket to comply with this Policy?**\n\nYou must modify the os-release file to either use Bottlerocket according to this Policy or to remove the Bottlerocket Trademarks. This can be done by modifying both `packages/release/release.spec` and `tools/rpm2img`. Names of the system root (e.g. `/x86_64-bottlerocket-linux-gnu/sys-root`), partition labels, directory paths, and service file descriptions do not need to be changed to comply with this Policy.\n\n**3. What can I do if I see abuse of the Bottlerocket Trademarks?**\n\nIf you are aware of confusing or misleading use or other misuse of the Bottlerocket Trademarks, you may contact us as described above at trademarks@amazon.com so we can investigate further.\n\n**4. This Policy requires modifications and their source to be identified for modified versions of Bottlerocket, where should I put this information?**\n\nYou may put this information in any location that is commonly used to convey differences from an upstream open source project, such as a NOTICE text or end-user documentation.\n"
  },
  {
    "path": "Twoliter.toml",
    "content": "schema-version = 2\nrelease-version = \"1.57.0\"\nproject-vendor = \"Bottlerocket\"\n\n[vendor.bottlerocket]\nregistry = \"public.ecr.aws/bottlerocket\"\n\n[sdk]\nname = \"bottlerocket-sdk\"\nversion = \"0.72.0\"\nvendor = \"bottlerocket\"\n\n[[kit]]\nname = \"bottlerocket-kernel-kit\"\nversion = \"5.2.0\"\nvendor = \"bottlerocket\"\n\n[[kit]]\nname = \"bottlerocket-core-kit\"\nversion = \"13.3.0\"\nvendor = \"bottlerocket\"\n"
  },
  {
    "path": "packages/.gitignore",
    "content": "*.patch.bz2\n*.src.rpm\n*.zip\n"
  },
  {
    "path": "packages/build.rs",
    "content": "use std::process::{exit, Command};\n\nfn main() -> Result<(), std::io::Error> {\n    let ret = Command::new(\"buildsys\").arg(\"build-package\").status()?;\n    if !ret.success() {\n        exit(1);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "packages/packages.rs",
    "content": "/*!\n\nThis is an intentionally empty file that all of the package `Cargo.toml` files can point to as their\n`lib.rs`. The build system uses `build.rs` to invoke `buildsys` but Cargo needs something to compile\nso we give it an empty `lib.rs` file.\n\n!*/\n"
  },
  {
    "path": "packages/settings-defaults/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[lib]\npath = \"../packages.rs\"\n\n[package.metadata.build-package]\nsource-groups = [\n    \"settings-defaults\"\n]\n\n# RPM BuildRequires\n[build-dependencies]\n\n# RPM Requires\n[dependencies]\n"
  },
  {
    "path": "packages/settings-defaults/settings-defaults.spec",
    "content": "%global _cross_first_party 1\n%undefine _debugsource_packages\n\n%global cargo_clean %{__cargo_cross_env} %{__cargo} clean\n\n%global _cross_defaultsdir %{_cross_datadir}/storewolf\n\nName: %{_cross_os}settings-defaults\nVersion: 0.0\nRelease: 1%{?dist}\nSummary: Settings defaults\nLicense: Apache-2.0 OR MIT\nURL: https://github.com/bottlerocket-os/bottlerocket\nBuildRequires: %{_cross_os}glibc-devel\nRequires: %{_cross_os}settings-defaults(any)\n\n%description\n%{summary}.\n\n%package aws-dev\nSummary: Settings defaults for the aws-dev variant\nRequires: %{_cross_os}variant(aws-dev)\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-dev)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-dev\n%{summary}.\n\n%package aws-ecs-2\nSummary: Settings defaults for the aws-ecs-2 FIPS and non-FIPS variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-ecs-2) or\n           %{_cross_os}variant(aws-ecs-2-fips)\n          %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-ecs-2)\nProvides: %{_cross_os}settings-defaults(aws-ecs-2-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-ecs-2\n%{summary}.\n\n%package aws-ecs-2-nvidia\nSummary: Settings defaults for the aws-ecs-2-nvidia variant\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-ecs-2-nvidia) or\n           %{_cross_os}variant(aws-ecs-2-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-ecs-2-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-ecs-2-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-ecs-2-nvidia\n%{summary}.\n\n%package aws-ecs-3\nSummary: Settings defaults for the aws-ecs-3 FIPS and non-FIPS variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-ecs-3) or\n           %{_cross_os}variant(aws-ecs-3-fips)\n          %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-ecs-3)\nProvides: %{_cross_os}settings-defaults(aws-ecs-3-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-ecs-3\n%{summary}.\n\n%package aws-ecs-3-nvidia\nSummary: Settings defaults for the aws-ecs-3-nvidia variant\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-ecs-3-nvidia) or\n           %{_cross_os}variant(aws-ecs-3-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-ecs-3-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-ecs-3-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-ecs-3-nvidia\n%{summary}.\n\n%package aws-k8s-1.31\nSummary: Settings defaults for the aws-k8s 1.29 through 1.31 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.29)      or\n           %{_cross_os}variant(aws-k8s-1.29-fips) or\n           %{_cross_os}variant(aws-k8s-1.30)      or\n           %{_cross_os}variant(aws-k8s-1.30-fips) or\n           %{_cross_os}variant(aws-k8s-1.31)      or\n           %{_cross_os}variant(aws-k8s-1.31-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.29)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.29-fips)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.30)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.30-fips)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.31)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.31-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.31\n%{summary}.\n\n%package aws-k8s-1.31-nvidia\nSummary: Settings defaults for the aws-k8s 1.29 through 1.31 nvidia variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.29-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.29-nvidia-fips) or\n           %{_cross_os}variant(aws-k8s-1.30-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.30-nvidia-fips) or\n           %{_cross_os}variant(aws-k8s-1.31-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.31-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.29-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.29-nvidia-fips)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.30-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.30-nvidia-fips)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.31-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.31-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.31-nvidia\n%{summary}.\n\n%package aws-k8s-1.32\nSummary: Settings defaults for the aws-k8s 1.32 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.32)      or\n           %{_cross_os}variant(aws-k8s-1.32-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.32)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.32-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.32\n%{summary}.\n\n%package aws-k8s-1.32-nvidia\nSummary: Settings defaults for the aws-k8s 1.32 nvidia variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.32-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.32-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.32-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.32-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.32-nvidia\n%{summary}.\n\n%package aws-k8s-1.33\nSummary: Settings defaults for the aws-k8s 1.33 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.33)      or\n           %{_cross_os}variant(aws-k8s-1.33-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.33)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.33-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.33\n%{summary}.\n\n%package aws-k8s-1.33-nvidia\nSummary: Settings defaults for the aws-k8s 1.33 nvidia variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.33-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.33-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.33-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.33-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.33-nvidia\n%{summary}.\n\n%package aws-k8s-1.34\nSummary: Settings defaults for the aws-k8s 1.34 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.34)      or\n           %{_cross_os}variant(aws-k8s-1.34-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.34)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.34-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.34\n%{summary}.\n\n%package aws-k8s-1.34-nvidia\nSummary: Settings defaults for the aws-k8s 1.34 nvidia variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.34-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.34-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.34-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.34-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.34-nvidia\n%{summary}.\n\n%package aws-k8s-1.35\nSummary: Settings defaults for the aws-k8s 1.35 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.35)      or\n           %{_cross_os}variant(aws-k8s-1.35-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.35)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.35-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.35\n%{summary}.\n\n%package aws-k8s-1.35-nvidia\nSummary: Settings defaults for the aws-k8s 1.35 nvidia variants\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-k8s-1.35-nvidia)      or\n           %{_cross_os}variant(aws-k8s-1.35-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.35-nvidia)\nProvides: %{_cross_os}settings-defaults(aws-k8s-1.35-nvidia-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description aws-k8s-1.35-nvidia\n%{summary}.\n\n%package metal-dev\nSummary: Settings defaults for the metal-dev variant\nRequires: %{_cross_os}variant(metal-dev)\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(metal-dev)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description metal-dev\n%{summary}.\n\n%package vmware-dev\nSummary: Settings defaults for the vmware-dev variant\nRequires: %{_cross_os}variant(vmware-dev)\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(vmware-dev)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description vmware-dev\n%{summary}.\n\n%package vmware-k8s-1.32\nSummary: Settings defaults for the vmware-k8s 1.29 through 1.32 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(vmware-k8s-1.29)      or\n           %{_cross_os}variant(vmware-k8s-1.29-fips) or\n           %{_cross_os}variant(vmware-k8s-1.30)      or\n           %{_cross_os}variant(vmware-k8s-1.30-fips) or\n           %{_cross_os}variant(vmware-k8s-1.31)      or\n           %{_cross_os}variant(vmware-k8s-1.31-fips) or\n           %{_cross_os}variant(vmware-k8s-1.32)      or\n           %{_cross_os}variant(vmware-k8s-1.32-fips)\n          %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.29)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.29-fips)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.30)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.30-fips)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.31)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.31-fips)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.32)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.32-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description vmware-k8s-1.32\n%{summary}.\n\n%package vmware-k8s-1.33\nSummary: Settings defaults for the vmware-k8s 1.33 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(vmware-k8s-1.33)      or\n           %{_cross_os}variant(vmware-k8s-1.33-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.33)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.33-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description vmware-k8s-1.33\n%{summary}.\n\n%package vmware-k8s-1.35\nSummary: Settings defaults for the vmware-k8s 1.35 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(vmware-k8s-1.35)      or\n           %{_cross_os}variant(vmware-k8s-1.35-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.35)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.35-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description vmware-k8s-1.35\n%{summary}.\n\n%package vmware-k8s-1.34\nSummary: Settings defaults for the vmware-k8s 1.34 variants\nRequires: (%{shrink:\n           %{_cross_os}variant(vmware-k8s-1.34)      or\n           %{_cross_os}variant(vmware-k8s-1.34-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-defaults(any)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.34)\nProvides: %{_cross_os}settings-defaults(vmware-k8s-1.34-fips)\nConflicts: %{_cross_os}settings-defaults(any)\n\n%description vmware-k8s-1.34\n%{summary}.\n\n%prep\n%setup -T -c\n%cargo_prep\n\n%build\ndeclare -a projects\nfor defaults in \\\n  aws-dev \\\n  aws-ecs-2 \\\n  aws-ecs-2-nvidia \\\n  aws-ecs-3 \\\n  aws-ecs-3-nvidia \\\n  aws-k8s-1.31 \\\n  aws-k8s-1.31-nvidia \\\n  aws-k8s-1.32 \\\n  aws-k8s-1.32-nvidia \\\n  aws-k8s-1.33 \\\n  aws-k8s-1.33-nvidia \\\n  aws-k8s-1.34 \\\n  aws-k8s-1.34-nvidia \\\n  aws-k8s-1.35 \\\n  aws-k8s-1.35-nvidia \\\n  metal-dev \\\n  vmware-dev \\\n  vmware-k8s-1.32 \\\n  vmware-k8s-1.33 \\\n  vmware-k8s-1.34 \\\n  vmware-k8s-1.35 \\\n  ;\ndo\n  projects+=( \"-p\" \"settings-defaults-$(echo \"${defaults}\" | sed -e 's,\\.,_,g')\" )\ndone\n\n# Output is written to an unpredictable directory name, so clean it up first to\n# avoid reusing any cached artifacts.\n%cargo_clean --manifest-path %{_builddir}/sources/Cargo.toml \\\n  \"${projects[@]}\" \\\n  %{nil}\n\n%cargo_build --manifest-path %{_builddir}/sources/Cargo.toml \\\n  \"${projects[@]}\" \\\n  %{nil}\n\n%install\ninstall -d %{buildroot}%{_cross_defaultsdir}\ninstall -d %{buildroot}%{_cross_tmpfilesdir}\n\nfor defaults in \\\n  aws-dev \\\n  aws-ecs-2 \\\n  aws-ecs-2-nvidia \\\n  aws-ecs-3 \\\n  aws-ecs-3-nvidia \\\n  aws-k8s-1.31 \\\n  aws-k8s-1.31-nvidia \\\n  aws-k8s-1.32 \\\n  aws-k8s-1.32-nvidia \\\n  aws-k8s-1.33 \\\n  aws-k8s-1.33-nvidia \\\n  aws-k8s-1.34 \\\n  aws-k8s-1.34-nvidia \\\n  aws-k8s-1.35 \\\n  aws-k8s-1.35-nvidia \\\n  metal-dev \\\n  vmware-dev \\\n  vmware-k8s-1.32 \\\n  vmware-k8s-1.33 \\\n  vmware-k8s-1.34 \\\n  vmware-k8s-1.35 \\\n  ;\ndo\n  crate=\"$(echo \"${defaults}\" | sed -e 's,\\.,_,g')\"\n  for f in $(find \"${HOME}/.cache\" -name \"settings-defaults-${crate}.toml\") ; do\n    install -p -m 0644 \"${f}\" \"%{buildroot}%{_cross_defaultsdir}/${defaults}.toml\"\n  done\n  echo \\\n    \"L+ /etc/storewolf/defaults.toml - - - - %{_cross_defaultsdir}/${defaults}.toml\" > \\\n    \"%{buildroot}%{_cross_tmpfilesdir}/storewolf-defaults-${defaults}.conf\"\ndone\n\n%files\n%dir %{_cross_defaultsdir}\n\n%files aws-dev\n%{_cross_defaultsdir}/aws-dev.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-dev.conf\n\n%files aws-ecs-2\n%{_cross_defaultsdir}/aws-ecs-2.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-ecs-2.conf\n\n%files aws-ecs-2-nvidia\n%{_cross_defaultsdir}/aws-ecs-2-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-ecs-2-nvidia.conf\n\n%files aws-ecs-3\n%{_cross_defaultsdir}/aws-ecs-3.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-ecs-3.conf\n\n%files aws-ecs-3-nvidia\n%{_cross_defaultsdir}/aws-ecs-3-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-ecs-3-nvidia.conf\n\n%files aws-k8s-1.31\n%{_cross_defaultsdir}/aws-k8s-1.31.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.31.conf\n\n%files aws-k8s-1.31-nvidia\n%{_cross_defaultsdir}/aws-k8s-1.31-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.31-nvidia.conf\n\n%files aws-k8s-1.32\n%{_cross_defaultsdir}/aws-k8s-1.32.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.32.conf\n\n%files aws-k8s-1.32-nvidia\n%{_cross_defaultsdir}/aws-k8s-1.32-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.32-nvidia.conf\n\n%files aws-k8s-1.33\n%{_cross_defaultsdir}/aws-k8s-1.33.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.33.conf\n\n%files aws-k8s-1.33-nvidia\n%{_cross_defaultsdir}/aws-k8s-1.33-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.33-nvidia.conf\n\n%files aws-k8s-1.34\n%{_cross_defaultsdir}/aws-k8s-1.34.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.34.conf\n\n%files aws-k8s-1.34-nvidia\n%{_cross_defaultsdir}/aws-k8s-1.34-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.34-nvidia.conf\n\n%files aws-k8s-1.35\n%{_cross_defaultsdir}/aws-k8s-1.35.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.35.conf\n\n%files aws-k8s-1.35-nvidia\n%{_cross_defaultsdir}/aws-k8s-1.35-nvidia.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.35-nvidia.conf\n\n%files metal-dev\n%{_cross_defaultsdir}/metal-dev.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-metal-dev.conf\n\n%files vmware-dev\n%{_cross_defaultsdir}/vmware-dev.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-vmware-dev.conf\n\n%files vmware-k8s-1.32\n%{_cross_defaultsdir}/vmware-k8s-1.32.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-vmware-k8s-1.32.conf\n\n%files vmware-k8s-1.33\n%{_cross_defaultsdir}/vmware-k8s-1.33.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-vmware-k8s-1.33.conf\n\n%files vmware-k8s-1.34\n%{_cross_defaultsdir}/vmware-k8s-1.34.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-vmware-k8s-1.34.conf\n\n%files vmware-k8s-1.35\n%{_cross_defaultsdir}/vmware-k8s-1.35.toml\n%{_cross_tmpfilesdir}/storewolf-defaults-vmware-k8s-1.35.conf\n"
  },
  {
    "path": "packages/settings-migrations/Cargo.toml",
    "content": "[package]\nname = \"settings-migrations\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[lib]\npath = \"../packages.rs\"\n\n[package.metadata.build-package]\nsource-groups = [\n    \"settings-migrations\"\n]\n\n# RPM BuildRequires\n[build-dependencies]\n\n# RPM Requires\n[dependencies]\n"
  },
  {
    "path": "packages/settings-migrations/settings-migrations.spec",
    "content": "%global _cross_first_party 1\n%undefine _debugsource_packages\n\nName: %{_cross_os}migrations\nVersion: 0.0\nRelease: 1%{?dist}\nSummary: Settings migrations\nLicense: Apache-2.0 OR MIT\nURL: https://github.com/bottlerocket-os/bottlerocket\n\n# Ideally this would be the package name, but for now the build system expects to find a package\n# named \"bottlerocket-migrations\".\nProvides: %{_cross_os}settings-migrations\n\n%description\n%{summary}.\n\n%prep\n%setup -T -c\n%cargo_prep\n\n%build\n# First we find the migrations in the source tree.  We assume the directory name is the same as\n# the crate name.\nmigrations=()\nfor migration in $(find %{_builddir}/sources/settings-migrations/v[0-9]* -mindepth 1 -maxdepth 1 -type d); do\n    migrations+=(\"-p $(basename ${migration})\")\ndone\n\n# We need to build migrations statically, because they need to run after a system update where\n# available libraries can change.\n%cargo_build_static --manifest-path %{_builddir}/sources/Cargo.toml ${migrations[*]}\n\n%install\ninstall -d %{buildroot}%{_cross_datadir}/migrations\nfor version_path in %{_builddir}/sources/settings-migrations/v[0-9]*; do\n  [ -e \"${version_path}\" ] || continue\n  for migration_path in \"${version_path}\"/*; do\n    [ -e \"${migration_path}\" ] || continue\n\n    version=\"${version_path##*/}\"\n    crate_name=\"${migration_path##*/}\"\n    migration_binary_name=\"migrate_${version}_${crate_name#migrate-}\"\n    built_path=\"%{__cargo_outdir_static}/${crate_name}\"\n    target_path=\"%{buildroot}%{_cross_datadir}/migrations/${migration_binary_name}\"\n\n    install -m 0555 \"${built_path}\" \"${target_path}\"\n  done\ndone\n\n%files\n%dir %{_cross_datadir}/migrations\n%{_cross_datadir}/migrations\n"
  },
  {
    "path": "packages/settings-plugins/Cargo.toml",
    "content": "[package]\nname = \"settings-plugins\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[lib]\npath = \"../packages.rs\"\n\n[package.metadata.build-package]\nsource-groups = [\n    \"settings-plugins\"\n]\n\n# RPM BuildRequires\n[build-dependencies]\n\n# RPM Requires\n[dependencies]\n"
  },
  {
    "path": "packages/settings-plugins/settings-plugins.spec",
    "content": "%global _cross_first_party 1\n%undefine _debugsource_packages\n\n# Do not prefer shared linking, since the libstd we use at build time\n# may not match the one installed on the final image.\n%global __global_rustflags_shared %__global_rustflags -C link-arg=-Wl,-soname=libsettings.so\n\n%global _cross_pluginsdir %{_cross_libdir}/settings-plugins\n\nName: %{_cross_os}settings-plugins\nVersion: 0.0\nRelease: 1%{?dist}\nSummary: Settings plugins\nLicense: Apache-2.0 OR MIT\nURL: https://github.com/bottlerocket-os/bottlerocket\nBuildRequires: %{_cross_os}glibc-devel\nRequires: %{_cross_os}glibc\nRequires: %{_cross_os}settings-plugin(any)\n\n%description\n%{summary}.\n\n%package aws-dev\nSummary: Settings plugin for the aws-dev variant\nRequires: %{_cross_os}variant(aws-dev)\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(aws-dev)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description aws-dev\n%{summary}.\n\n%package aws-ecs-2\nSummary: Settings plugin for the aws-ecs-2 variant\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-ecs-2) or\n           %{_cross_os}variant(aws-ecs-2-fips) or\n           %{_cross_os}variant(aws-ecs-2-nvidia) or\n           %{_cross_os}variant(aws-ecs-2-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(aws-ecs-2)\nProvides: %{_cross_os}settings-plugin(aws-ecs-2-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-ecs-2-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-ecs-2-fips)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description aws-ecs-2\n%{summary}.\n\n%package aws-ecs-3\nSummary: Settings plugin for the aws-ecs-3 variant\nRequires: (%{shrink:\n           %{_cross_os}variant(aws-ecs-3) or\n           %{_cross_os}variant(aws-ecs-3-fips) or\n           %{_cross_os}variant(aws-ecs-3-nvidia) or\n           %{_cross_os}variant(aws-ecs-3-nvidia-fips)\n           %{nil}})\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(aws-ecs-3)\nProvides: %{_cross_os}settings-plugin(aws-ecs-3-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-ecs-3-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-ecs-3-fips)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description aws-ecs-3\n%{summary}.\n\n%package aws-k8s\nSummary: Settings plugin for the aws-k8s variants\nRequires: %{_cross_os}variant-family(aws-k8s)\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.29)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.29-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.30)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.30-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.31)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.31-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.32)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.32-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.33)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.33-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.34)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.34-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.35)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.35-fips)\nConflicts: %{_cross_os}settings-plugin(any)\nConflicts: %{_cross_os}variant-flavor(nvidia)\n\n\n%description aws-k8s\n%{summary}.\n\n%package aws-k8s-nvidia\nSummary: Settings plugin for the aws-k8s-nvidia variants\nRequires: (%{_cross_os}variant-family(aws-k8s) and %{_cross_os}variant-flavor(nvidia))\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.29-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.29-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.30-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.30-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.31-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.31-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.32-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.32-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.33-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.33-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.34-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.34-nvidia-fips)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.35-nvidia)\nProvides: %{_cross_os}settings-plugin(aws-k8s-1.35-nvidia-fips)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description aws-k8s-nvidia\n%{summary}.\n\n%package metal-dev\nSummary: Settings plugin for the metal-dev variant\nRequires: %{_cross_os}variant(metal-dev)\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(metal-dev)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description metal-dev\n%{summary}.\n\n%package vmware-dev\nSummary: Settings plugin for the vmware-dev variant\nRequires: %{_cross_os}variant(vmware-dev)\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(vmware-dev)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description vmware-dev\n%{summary}.\n\n%package vmware-k8s\nSummary: Settings plugin for the vmware-k8s variants\nRequires: %{_cross_os}variant-family(vmware-k8s)\nProvides: %{_cross_os}settings-plugin(any)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.29)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.29-fips)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.30)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.30-fips)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.31)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.31-fips)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.32)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.32-fips)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.33)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.33-fips)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.34)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.34-fips)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.35)\nProvides: %{_cross_os}settings-plugin(vmware-k8s-1.35-fips)\nConflicts: %{_cross_os}settings-plugin(any)\n\n%description vmware-k8s\n%{summary}.\n\n%prep\n%setup -T -c\n%cargo_prep\n\n%build\n%cargo_build --manifest-path %{_builddir}/sources/Cargo.toml \\\n  -p settings-plugin-aws-dev \\\n  -p settings-plugin-aws-ecs-2 \\\n  -p settings-plugin-aws-ecs-3 \\\n  -p settings-plugin-aws-k8s \\\n  -p settings-plugin-aws-k8s-nvidia \\\n  -p settings-plugin-metal-dev \\\n  -p settings-plugin-vmware-dev \\\n  -p settings-plugin-vmware-k8s \\\n  %{nil}\n\n%install\ninstall -d %{buildroot}%{_cross_pluginsdir}\ninstall -d %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d\ninstall -d %{buildroot}%{_cross_tmpfilesdir}\n\nfor plugin in \\\n  aws-dev \\\n  aws-ecs-2 \\\n  aws-ecs-3 \\\n  aws-k8s-nvidia \\\n  aws-k8s \\\n  metal-dev \\\n  vmware-dev \\\n  vmware-k8s \\\n  ;\ndo\n  install -d \"%{buildroot}%{_cross_pluginsdir}/${plugin}\"\n  plugin_so=\"libsettings_$(echo \"${plugin}\" | sed -e 's,-,_,g' -e 's,\\.,_,g').so\"\n  install -p -m 0755 \\\n    \"${HOME}/.cache/%{__cargo_target}/release/${plugin_so}\" \\\n    \"%{buildroot}%{_cross_pluginsdir}/${plugin}/libsettings.so\"\n  echo \\\n    \"%{_cross_pluginsdir}/${plugin}\" > \\\n    \"%{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/${plugin}.conf\"\n  echo \\\n    \"C /etc/ld.so.conf.d/${plugin}.conf\" > \\\n    \"%{buildroot}%{_cross_tmpfilesdir}/settings-plugin-${plugin}.conf\"\ndone\n\n%files\n%dir %{_cross_pluginsdir}\n\n%files aws-dev\n%{_cross_pluginsdir}/aws-dev/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/aws-dev.conf\n%{_cross_tmpfilesdir}/settings-plugin-aws-dev.conf\n\n%files aws-ecs-2\n%{_cross_pluginsdir}/aws-ecs-2/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/aws-ecs-2.conf\n%{_cross_tmpfilesdir}/settings-plugin-aws-ecs-2.conf\n\n%files aws-ecs-3\n%{_cross_pluginsdir}/aws-ecs-3/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/aws-ecs-3.conf\n%{_cross_tmpfilesdir}/settings-plugin-aws-ecs-3.conf\n\n%files aws-k8s\n%{_cross_pluginsdir}/aws-k8s/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/aws-k8s.conf\n%{_cross_tmpfilesdir}/settings-plugin-aws-k8s.conf\n\n%files aws-k8s-nvidia\n%{_cross_pluginsdir}/aws-k8s-nvidia/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/aws-k8s-nvidia.conf\n%{_cross_tmpfilesdir}/settings-plugin-aws-k8s-nvidia.conf\n\n%files metal-dev\n%{_cross_pluginsdir}/metal-dev/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/metal-dev.conf\n%{_cross_tmpfilesdir}/settings-plugin-metal-dev.conf\n\n%files vmware-dev\n%{_cross_pluginsdir}/vmware-dev/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/vmware-dev.conf\n%{_cross_tmpfilesdir}/settings-plugin-vmware-dev.conf\n\n%files vmware-k8s\n%{_cross_pluginsdir}/vmware-k8s/libsettings.so\n%{_cross_factorydir}%{_cross_sysconfdir}/ld.so.conf.d/vmware-k8s.conf\n%{_cross_tmpfilesdir}/settings-plugin-vmware-k8s.conf\n"
  },
  {
    "path": "sample-eksctl-ssh.yaml",
    "content": "---\napiVersion: eksctl.io/v1alpha5\nkind: ClusterConfig\n\nmetadata:\n  name: bottlerocket\n  region: us-west-2\n  version: '1.24'\n\nnodeGroups:\n  - name: ng-bottlerocket\n    instanceType: m5.large\n    desiredCapacity: 4\n    amiFamily: Bottlerocket\n    disableIMDSv1: true\n    iam:\n       attachPolicyARNs:\n          - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy\n          - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy\n          - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly\n          - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\n    ssh:\n        allow: true\n        publicKeyName: YOUR_EC2_KEYPAIR_NAME\n    bottlerocket:\n      settings:\n        motd: \"Hello from eksctl!\"\n"
  },
  {
    "path": "sample-eksctl.yaml",
    "content": "---\napiVersion: eksctl.io/v1alpha5\nkind: ClusterConfig\n\nmetadata:\n  name: bottlerocket\n  region: us-west-2\n  version: '1.24'\n\nnodeGroups:\n  - name: ng-bottlerocket\n    instanceType: m5.large\n    desiredCapacity: 4\n    amiFamily: Bottlerocket\n    disableIMDSv1: true\n    iam:\n       attachPolicyARNs:\n          - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy\n          - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy\n          - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly\n          - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\n    bottlerocket:\n      settings:\n        motd: \"Hello from eksctl!\"\n"
  },
  {
    "path": "sources/Cargo.toml",
    "content": "[workspace]\nresolver = \"1\"\nmembers = [\n    \"api/datastore\",\n    \"api/migration/migration-helpers\",\n\n    \"bottlerocket-release\",\n    \"constants\",\n\n    \"generate-readme\",\n\n    \"models\",\n\n    \"retry-read\",\n\n    \"settings-defaults/aws-dev\",\n    \"settings-defaults/aws-ecs-2\",\n    \"settings-defaults/aws-ecs-2-nvidia\",\n    \"settings-defaults/aws-ecs-3\",\n    \"settings-defaults/aws-ecs-3-nvidia\",\n    \"settings-defaults/aws-k8s-1.31\",\n    \"settings-defaults/aws-k8s-1.31-nvidia\",\n    \"settings-defaults/aws-k8s-1.32\",\n    \"settings-defaults/aws-k8s-1.32-nvidia\",\n    \"settings-defaults/aws-k8s-1.33\",\n    \"settings-defaults/aws-k8s-1.33-nvidia\",\n    \"settings-defaults/aws-k8s-1.34\",\n    \"settings-defaults/aws-k8s-1.34-nvidia\",\n    \"settings-defaults/aws-k8s-1.35\",\n    \"settings-defaults/aws-k8s-1.35-nvidia\",\n    \"settings-defaults/metal-dev\",\n    \"settings-defaults/metal-k8s-1.30\",\n    \"settings-defaults/vmware-dev\",\n    \"settings-defaults/vmware-k8s-1.32\",\n    \"settings-defaults/vmware-k8s-1.33\",\n    \"settings-defaults/vmware-k8s-1.34\",\n    \"settings-defaults/vmware-k8s-1.35\",\n\n    # (all previous migrations archived; add new ones after this line)\n    \"settings-migrations/v1.34.0/kubelet-device-plugins-mig-settings\",\n    \"settings-migrations/v1.36.0/kubernetes-ecr-credential-providers-expansion\",\n    \"settings-migrations/v1.37.0/delete-configs-and-services-on-downgrade\",\n    \"settings-migrations/v1.39.0/kubelet-setting-container-log-single-process-oom-kill\",\n    \"settings-migrations/v1.40.0/kubelet-device-plugins-cdi-settings\",\n    \"settings-migrations/v1.41.0/kubernetes-ecr-credential-providers-correction\",\n    \"settings-migrations/v1.42.0/kubernetes-memory-swap-behavior-setting\",\n    \"settings-migrations/v1.44.0/container-runtime-plugins-settings\",\n    \"settings-migrations/v1.44.0/container-runtime-snapshotter-setting\",\n    \"settings-migrations/v1.46.0/kubernetes-static-pods-enabled-setting\",\n    \"settings-migrations/v1.47.0/container-runtime-concurrent-download-chunk-size\",\n    \"settings-migrations/v1.47.0/host-bootstrap-containers-command-setting\",\n    \"settings-migrations/v1.50.0/kubernetes-reserved-pid-settings\",\n    \"settings-migrations/v1.51.0/kubernetes-ecr-credential-provider-patterns\",\n    \"settings-migrations/v1.51.0/kubernetes-additional-settings\",\n    \"settings-migrations/v1.51.0/kubernetes-beta-cpu-manager-policy-options\",\n    \"settings-migrations/v1.54.0/kubelet-device-plugins-mps-settings\",\n    \"settings-migrations/v1.54.0/kubelet-device-plugins-mps-prefix-settings\",\n    \"settings-migrations/v1.56.0/image-verifier-plugins-extensible\",\n\n    \"settings-plugins/aws-dev\",\n    \"settings-plugins/aws-ecs-2\",\n    \"settings-plugins/aws-ecs-3\",\n    \"settings-plugins/aws-k8s\",\n    \"settings-plugins/aws-k8s-nvidia\",\n    \"settings-plugins/metal-dev\",\n    \"settings-plugins/metal-k8s\",\n    \"settings-plugins/vmware-dev\",\n    \"settings-plugins/vmware-k8s\",\n\n    \"constants\",\n]\n\n[workspace.dependencies]\nbottlerocket-release = { version = \"0.1\", path = \"bottlerocket-release\" }\nconstants = { version = \"0.1\", path = \"constants\" }\ndatastore = { version = \"0.1\", path = \"api/datastore\" }\ngenerate-readme = { version = \"0.1\", path = \"generate-readme\" }\nmigration-helpers = { version = \"0.1.0\", path = \"api/migration/migration-helpers\" }\nmodels = { version = \"0.1\", path = \"models\" }\nretry-read = { version = \"0.1\", path = \"retry-read\" }\n\nabi_stable = \"0.11.3\"\nargh = \"0.1\"\nasync-trait = \"0.1\"\naws-lc-rs = \"1\"\nbase64 = \"0.21\"\ncached = \"0.49\"\ncargo-readme = \"3\"\ndns-lookup = \"2\"\nenvy = \"0.4\"\nfutures = { version = \"0.3\", default-features = false }\nfutures-channel = { version = \"0.3\", default-features = false }\nhandlebars = \"4\"\nhttp = \"0.2\"\nhttparse = \"1\"\nhyper = { version = \"0.14\", default-features = false }\nhyper-unix-connector = \"0.2\"\nlazy_static = \"1\"\nlibc = \"0.2\"\nlog = \"0.4\"\nmaplit = \"1.0\"\nnix = \"0.26\"\nnum_cpus = \"1\"\npercent-encoding = \"2\"\npest = \"2.5\"\npest_derive = \"2.5\"\nrand = \"0.8\"\nregex = \"1\"\nreqwest = { version = \"0.12\", default-features = false }\nrustls = \"0.23\"\nsemver = \"1\"\nserde = \"1\"\nserde_json = \"1\"\nserde_plain = \"1\"\nshlex = \"1\"\nsignal-hook = \"0.3\"\nsimplelog = \"0.12\"\nsnafu = \"0.8\"\ntokio = { version = \"~1.43\", default-features = false }\ntokio-tungstenite = { version = \"0.20\", default-features = false }\ntoml = \"0.8\"\nunindent = \"0.1\"\nurl = \"2\"\nwalkdir = \"2\"\n\n[workspace.dependencies.bottlerocket-defaults-helper]\ngit = \"https://github.com/bottlerocket-os/bottlerocket-settings-sdk\"\ntag = \"bottlerocket-settings-models-v0.21.0\"\nversion = \"0.1.1\"\n\n[workspace.dependencies.bottlerocket-modeled-types]\ngit = \"https://github.com/bottlerocket-os/bottlerocket-settings-sdk\"\ntag = \"bottlerocket-settings-models-v0.21.0\"\nversion = \"0.14.0\"\n\n[workspace.dependencies.bottlerocket-settings-models]\ngit = \"https://github.com/bottlerocket-os/bottlerocket-settings-sdk\"\ntag = \"bottlerocket-settings-models-v0.21.0\"\nversion = \"0.21.0\"\n\n[workspace.dependencies.bottlerocket-settings-plugin]\ngit = \"https://github.com/bottlerocket-os/bottlerocket-settings-sdk\"\ntag = \"bottlerocket-settings-models-v0.21.0\"\nversion = \"0.1.0\"\n\n[workspace.dependencies.settings-extension-oci-defaults]\ngit = \"https://github.com/bottlerocket-os/bottlerocket-settings-sdk\"\ntag = \"bottlerocket-settings-models-v0.21.0\"\nversion = \"0.1.0\"\n\n[profile.release]\ndebug = true\n"
  },
  {
    "path": "sources/README.md",
    "content": "## Sources\n\nThe `sources/` directory contains most of Bottlerocket's first-party code.\nEach subdirectory contains related code that's built together in one package in the `../packages/` directory.\n\nEach subdirectory has its own README - please read further inside.\n"
  },
  {
    "path": "sources/api/.gitignore",
    "content": "/target\n"
  },
  {
    "path": "sources/api/datastore/.gitignore",
    "content": "/target\n**/*.rs.bk\n"
  },
  {
    "path": "sources/api/datastore/Cargo.toml",
    "content": "[package]\nname = \"datastore\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nbuild = \"build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nlog.workspace = true\npercent-encoding.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nserde_json.workspace = true\nsnafu.workspace = true\nwalkdir.workspace = true\nserde_plain.workspace = true\n\n[build-dependencies]\ngenerate-readme.workspace = true\n\n[dev-dependencies]\nmaplit.workspace = true\ntoml.workspace = true\n"
  },
  {
    "path": "sources/api/datastore/README.md",
    "content": "# datastore\n\nCurrent version: 0.1.0\n\n## Background\n\nA 'data store' in Bottlerocket is responsible for storing key/value pairs and metadata about those pairs, with the ability to commit changes in transactions.\n\nFor more detail about their usage, see [apiserver](../apiserver).\n\n## Library\n\nThis library provides a trait defining the exact requirements, along with basic implementations for filesystem and memory data stores.\n\nThere's also a common error type and some methods that implementations of DataStore should generally share, like scalar serialization.\n\nWe represent scalars -- the actual values stored under a datastore key -- using JSON, just to have a convenient human-readable form.\n(TOML doesn't allow raw scalars.  The JSON spec doesn't seem to either, but this works, and the format is so simple for scalars that it could be easily swapped out if needed.)\n\n## Serialization and deserialization\n\nThe `serialization` module provides code to serialize Rust types into a mapping of datastore-acceptable keys (a.b.c) and values.\n\nThe `deserialization` module provides code to deserialize datastore-acceptable keys (a.b.c) and values into Rust types.\n\n## Current limitations\n\n* The user (e.g. apiserver) needs to handle locking.\n* There's no support for rolling back transactions.\n* The `serialization` module can't handle complex types under lists; it assumes lists can be serialized as scalars.\n\n## Colophon\n\nThis text was generated using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/api/datastore/README.tpl",
    "content": "# {{crate}}\n\nCurrent version: {{version}}\n\n{{readme}}\n\n## Colophon\n\nThis text was generated using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/api/datastore/build.rs",
    "content": "fn main() {\n    generate_readme::from_lib().unwrap();\n}\n"
  },
  {
    "path": "sources/api/datastore/src/constraints_check.rs",
    "content": "//! The outcome of the constraint check determines whether the transaction can proceed to commit.\n//! A ‘rejected’ result means that one or more constraints have not been satisfied,\n//! preventing the transaction from being committed. On the other hand, an ‘approved’\n//! result confirms that all constraints are satisfied and provides the required\n//! settings and metadata for the commit.\n//! Constraint checks can alter the write.\n\nuse std::collections::HashMap;\n\nuse crate::{error, Key};\n\ntype RejectReason = String;\n\n/// Represents a successful write operation after constraints have been approved.\n/// Contains the following fields:\n/// - `settings`: A collection of key-value pairs representing the settings to be committed.\n/// - `metadata`: A collection of metadata entries.\n#[derive(PartialEq)]\npub struct ApprovedWrite {\n    pub settings: HashMap<Key, String>,\n    pub metadata: Vec<(Key, Key, String)>,\n}\n\n/// Represents the result of a constraint check.\n/// The result can either reject the operation or approve it with the required data.\n#[derive(PartialEq)]\npub enum ConstraintCheckResult {\n    Reject(RejectReason),\n    Approve(ApprovedWrite),\n}\n\nimpl TryFrom<ConstraintCheckResult> for ApprovedWrite {\n    type Error = error::Error;\n\n    fn try_from(constraint_check_result: ConstraintCheckResult) -> Result<Self, Self::Error> {\n        match constraint_check_result {\n            ConstraintCheckResult::Reject(err) => error::ConstraintCheckRejectSnafu { err }.fail(),\n            ConstraintCheckResult::Approve(approved_write) => Ok(approved_write),\n        }\n    }\n}\n\nimpl From<Option<ApprovedWrite>> for ConstraintCheckResult {\n    fn from(approved_write: Option<ApprovedWrite>) -> Self {\n        match approved_write {\n            None => ConstraintCheckResult::Reject(\n                \"The write for the given transaction is rejected\".to_string(),\n            ),\n            Some(approved_write) => ConstraintCheckResult::Approve(approved_write),\n        }\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/deserialization/error.rs",
    "content": "use serde::de;\nuse snafu::{IntoError, NoneError as NoSource, Snafu};\n\nuse crate::{Error as DataStoreError, ScalarError};\n\n/// Potential errors from deserialization.\n#[derive(Debug, Snafu)]\n#[snafu(visibility(pub))]\npub enum Error {\n    // This error variant is required to implement ser::Error for serde.\n    #[snafu(display(\"Error during deserialization: {}\", msg))]\n    Message { msg: String },\n\n    #[snafu(display(\"Error deserializing scalar value: {}\", source))]\n    DeserializeScalar { source: ScalarError },\n\n    #[snafu(display(\n        \"Data store deserializer must be used on a struct, or you must give a prefix\"\n    ))]\n    BadRoot {},\n\n    #[snafu(display(\n        \"Removal of prefix '{}' from key '{}' failed: {}\",\n        prefix,\n        name,\n        source\n    ))]\n    StripPrefix {\n        prefix: String,\n        name: String,\n        #[snafu(source(from(DataStoreError, Box::new)))]\n        source: Box<DataStoreError>,\n    },\n\n    #[snafu(display(\"Prefix '{}' is not a valid key: {}\", prefix, source))]\n    InvalidPrefix {\n        prefix: String,\n        #[snafu(source(from(DataStoreError, Box::new)))]\n        source: Box<DataStoreError>,\n    },\n}\n\npub type Result<T> = std::result::Result<T, Error>;\n\nimpl de::Error for Error {\n    fn custom<T: std::fmt::Display>(msg: T) -> Self {\n        MessageSnafu {\n            msg: msg.to_string(),\n        }\n        .into_error(NoSource)\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/deserialization/mod.rs",
    "content": "//! The deserialization module implements generic deserialization techniques that are particularly\n//! useful for populating Rust structures from the datastore.\n\nmod error;\nmod pairs;\n\npub use error::{Error, Result};\npub use pairs::{from_map, from_map_with_prefix};\n"
  },
  {
    "path": "sources/api/datastore/src/deserialization/pairs.rs",
    "content": "//! The goal of this module is to be able to turn a mapping of dotted keys -> values into a\n//! populated structure.  The keys are of the form \"a.b.c\" and match up to nested structures\n//! A { B { C } }.\n//!\n//! For example, with these structures:\n//!    struct A {\n//!        b: B,\n//!    }\n//!\n//!    struct B {\n//!        c: u64,\n//!        d: u64,\n//!    }\n//!\n//! An input map of {\"a.b.c\": 42, \"a.b.d\": 43} would return a populated structure:\n//!    A {\n//!      B {\n//!        c: 42,\n//!        d: 43,\n//!      }\n//!    }\n//!\n//! Note: serde deserialization is harder to understand than serialization, so this implementation\n//! was kept as simple as possible rather than taking advantage of all of the structure that serde\n//! provides.  forward_to_deserialize_any lets us omit most type-specific functions so we can\n//! handle all scalars the same and all compound structures the same; see ValueDeserializer.\n//!\n//! The primary work is done by serde's MapDeserializer; it abstracts away the need to build the\n//! visitor that serde expects.  It gives us the name of a field in a structure, and we have to\n//! provide the value.  We use it recursively, and at each recursion, append a dot and the name of\n//! the field to our \"path\" string.  In the example above, when we're looking at field \"c\", path\n//! would be \"a.b\", so we know we should look for \"a.b.c\" in our input mapping.\n\nuse log::{error, trace};\nuse serde::de::{value::MapDeserializer, IntoDeserializer, Visitor};\nuse serde::{forward_to_deserialize_any, Deserialize};\nuse snafu::ResultExt;\nuse std::borrow::Borrow;\nuse std::collections::{HashMap, HashSet, VecDeque};\nuse std::hash::Hash;\n\nuse super::{error, Error, Result};\nuse crate::{deserializer_for_scalar, Key, KeyType, ScalarDeserializer};\n\n/// This is the primary interface to deserialization.  We turn the input map into the requested\n/// output type, assuming all non-Option fields are provided, etc.\n///\n/// This only allows for deserialization into structs; to deserialize into maps, see\n/// from_map_with_prefix.\n///\n/// The BuildHasher bound on the input HashMap lets you use a HashMap with any hashing\n/// implementation.  This is just an implementation detail and not something you have to specify\n/// about your input HashMap - any HashMap using string-like key/value types is fine.\npub fn from_map<'de, K, S, T, BH>(map: &'de HashMap<K, S, BH>) -> Result<T>\nwhere\n    K: Borrow<Key> + Eq + Hash,\n    S: AsRef<str>,\n    T: Deserialize<'de>,\n    BH: std::hash::BuildHasher,\n{\n    let de = CompoundDeserializer::new(map, map.keys().map(|s| s.borrow().clone()).collect(), None);\n    trace!(\"Deserializing keys: {:?}\", de.keys);\n    T::deserialize(de)\n}\n\n/// This is an alternate interface to deserialization that allows deserializing into maps.\n///\n/// To use this, you need to provide a string prefix, which represents the prefix of the map keys\n/// that needs to be stripped away in order to match the map's expected fields.\n///\n/// For example, if you have `type Services = HashMap<String, Service>` and you have map keys like\n/// \"services.x.y.z\", then you need to strip away the \"services\" component that represents the\n/// map's \"name\", otherwise we'd think you have a \"services\" key in the map itself.  (The dot is\n/// removed automatically, you don't need to specify it.)\n///\n/// This isn't necessary for structs because serde knows the struct's name, so we\n/// can strip it automatically.\npub fn from_map_with_prefix<'de, K, S, T, BH>(\n    prefix: Option<String>,\n    map: &'de HashMap<K, S, BH>,\n) -> Result<T>\nwhere\n    K: Borrow<Key> + Eq + Hash,\n    S: AsRef<str>,\n    T: Deserialize<'de>,\n    BH: std::hash::BuildHasher,\n{\n    let key_prefix = match prefix {\n        None => None,\n        Some(ref p) => {\n            Some(Key::new(KeyType::Data, p).context(error::InvalidPrefixSnafu { prefix: p })?)\n        }\n    };\n    let de = CompoundDeserializer::new(\n        map,\n        map.keys().map(|s| s.borrow().clone()).collect(),\n        key_prefix,\n    );\n    trace!(\n        \"Deserializing keys with prefix {:?}: {:?}\",\n        de.path,\n        de.keys\n    );\n    T::deserialize(de)\n}\n\n/// ValueDeserializer is what interfaces with serde's MapDeserializer, which expects to receive a\n/// key name and a deserializer for it on each iteration, i.e. for each field.  Based on whether\n/// the key name has a dot, we know if we need to recurse again or just deserialize a final value,\n/// which we represent as the two arms of the enum.\nenum ValueDeserializer<'de, K, S, BH> {\n    Scalar(ScalarDeserializer<'de>),\n    Compound(CompoundDeserializer<'de, K, S, BH>),\n}\n\nimpl<'de, K, S, BH> serde::de::Deserializer<'de> for ValueDeserializer<'de, K, S, BH>\nwhere\n    K: Borrow<Key> + Eq + Hash,\n    S: AsRef<str>,\n    BH: std::hash::BuildHasher,\n{\n    type Error = Error;\n\n    /// Here we either pass off a scalar value to actually turn into a Rust data type, or\n    /// recursively call our CompoundDeserializer to handle nested structure.\n    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>\n    where\n        V: Visitor<'de>,\n    {\n        match self {\n            ValueDeserializer::Scalar(mut scalar_deserializer) => {\n                trace!(\"Handing off to scalar deserializer for deserialize_any\");\n                scalar_deserializer\n                    .deserialize_any(visitor)\n                    .context(error::DeserializeScalarSnafu)\n            }\n            ValueDeserializer::Compound(compound_deserializer) => {\n                compound_deserializer.deserialize_map(visitor)\n            }\n        }\n    }\n\n    /// Here we deserialize values into Some(value) for any Option fields to represent that\n    /// yes, we do indeed have the data.\n    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>\n    where\n        V: Visitor<'de>,\n    {\n        match self {\n            ValueDeserializer::Scalar(mut scalar_deserializer) => {\n                trace!(\"Handing off to scalar deserializer for deserialize_option\");\n                scalar_deserializer\n                    .deserialize_option(visitor)\n                    .context(error::DeserializeScalarSnafu)\n            }\n            ValueDeserializer::Compound(compound_deserializer) => {\n                compound_deserializer.deserialize_option(visitor)\n            }\n        }\n    }\n\n    forward_to_deserialize_any! {\n        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string\n        bytes byte_buf unit unit_struct newtype_struct seq tuple\n        tuple_struct map struct enum identifier ignored_any\n    }\n}\n\nimpl<'de, K, S, BH> IntoDeserializer<'de, Error> for ValueDeserializer<'de, K, S, BH>\nwhere\n    K: Borrow<Key> + Eq + Hash,\n    S: AsRef<str>,\n    BH: std::hash::BuildHasher,\n{\n    type Deserializer = Self;\n\n    fn into_deserializer(self) -> Self::Deserializer {\n        self\n    }\n}\n\n/// CompoundDeserializer is our main structure that drives serde's MapDeserializer and stores the\n/// state we need to understand the recursive structure of the output.\nstruct CompoundDeserializer<'de, K, S, BH> {\n    /// A reference to the input data we're deserializing.\n    map: &'de HashMap<K, S, BH>,\n    /// The keys that we need to consider in this iteration.  Starts out the same as the keys\n    /// of the input map, but on recursive calls it's only the keys that are relevant to the\n    /// sub-struct we're handling, with the duplicated prefix (the 'path') removed.\n    keys: HashSet<Key>,\n    /// The path tells us where we are in our recursive structures.\n    path: Option<Key>,\n}\n\nimpl<'de, K, S, BH> CompoundDeserializer<'de, K, S, BH>\nwhere\n    BH: std::hash::BuildHasher,\n{\n    fn new(\n        map: &'de HashMap<K, S, BH>,\n        keys: HashSet<Key>,\n        path: Option<Key>,\n    ) -> CompoundDeserializer<'de, K, S, BH> {\n        CompoundDeserializer { map, keys, path }\n    }\n}\n\nfn bad_root<T>() -> Result<T> {\n    error::BadRootSnafu.fail()\n}\n\nimpl<'de, K, S, BH> serde::de::Deserializer<'de> for CompoundDeserializer<'de, K, S, BH>\nwhere\n    K: Borrow<Key> + Eq + Hash,\n    S: AsRef<str>,\n    BH: std::hash::BuildHasher,\n{\n    type Error = Error;\n\n    fn deserialize_struct<V>(\n        mut self,\n        name: &'static str,\n        _fields: &'static [&'static str],\n        visitor: V,\n    ) -> Result<V::Value>\n    where\n        V: Visitor<'de>,\n    {\n        // On the first interaction for a struct, we won't have a prefix yet, unless the user called\n        // from_map_with_prefix and specified it.  We can make the prefix from the struct name.\n        // (Recursive calls will have a path but no name, because we always treat nested structures\n        // as maps, because we don't need any nested struct names and it lets us use the nice\n        // MapDeserializer.)\n        if !name.is_empty() {\n            trace!(\"Path before name check: {:?}\", self.path);\n            if self.path.is_none() {\n                self.path = Some(\n                    // to_lowercase handles the discrepancy between key naming and struct naming;\n                    // this initial 'path' creation is the only place we take the struct name from\n                    // serde, per above comment.\n                    Key::from_segments(KeyType::Data, &[name.to_lowercase()])\n                        .context(error::InvalidPrefixSnafu { prefix: name })?,\n                );\n            }\n            trace!(\"Path after name check: {:?}\", self.path);\n        }\n\n        if let Some(ref path) = self.path {\n            // Remove the known path from the beginning of the keys. serde doesn't care about the\n            // name of the top-level struct, just the fields inside, so we have to remove it before\n            // handing it to the MapDeserializer.  (Our real customer is the one specifying the\n            // dotted keys, and we always use the struct name there for clarity.)\n            trace!(\"Keys before path strip: {:?}\", self.keys);\n            let mut new_keys = HashSet::new();\n            for key in self.keys {\n                new_keys.insert(key.strip_prefix_segments(path.segments()).context(\n                    error::StripPrefixSnafu {\n                        prefix: path.name(),\n                        name: key.name(),\n                    },\n                )?);\n            }\n            self.keys = new_keys;\n            trace!(\"Keys after path strip: {:?}\", self.keys);\n        }\n\n        // We have to track which structs we've already handled and skip over them.  This is\n        // because we could get keys like \"a.b.c\" and \"a.b.d\", so we'll see that \"a\" prefix\n        // twice at the top level, but by the time we see the second one we've already recursed\n        // and handled all of \"a\" from the first one.\n        let mut structs_done = HashSet::new();\n\n        // As mentioned above, MapDeserializer does a lot of nice work for us.  We just need to\n        // give it an iterator that yields (key, deserializer) pairs.  The nested deserializers\n        // have the appropriate 'path' and a subset of 'keys' so they can do their job.\n        visitor.visit_map(MapDeserializer::new(self.keys.iter().filter_map(|key| {\n            let mut segments: VecDeque<_> = key.segments().clone().into();\n            // Inside this filter_map closure, we can't return early from the outer function, so we\n            // log an error and skip the key.  Errors in this path are generally logic errors\n            // rather than user errors, so this isn't so bad.\n            let struct_name = match segments.pop_front() {\n                Some(s) => s,\n                None => {\n                    error!(\"Logic error - Key segments.pop_front failed, empty Key?\");\n                    return None;\n                }\n            };\n            trace!(\"Visiting key '{}', struct name '{}'\", key, &struct_name);\n\n            // At the top level (None path) we start with struct_name as Key, otherwise append\n            // struct_name.\n            trace!(\"Old path: {:?}\", &self.path);\n            let path = match self.path {\n                None => match Key::from_segments(KeyType::Data, &[&struct_name]) {\n                    Ok(key) => key,\n                    Err(e) => {\n                        error!(\n                            \"Tried to construct invalid key from struct name '{}', skipping: {}\",\n                            &struct_name, e\n                        );\n                        return None;\n                    }\n                },\n                Some(ref old_path) => match old_path.append_segments(&[&struct_name]) {\n                    Ok(key) => key,\n                    Err(e) => {\n                        error!(\n                            \"Appending '{}' to existing key '{}' resulted in invalid key, skipping: {}\",\n                            old_path, &struct_name, e\n                        );\n                        return None;\n                    }\n                }\n            };\n            trace!(\"New path: {}\", &path);\n\n            if !segments.is_empty() {\n                if structs_done.contains(&struct_name) {\n                    // We've handled this structure with a recursive call, so we're done.\n                    trace!(\"Already handled struct '{}', skipping\", &struct_name);\n                    None\n                } else {\n                    // Otherwise, mark it, and recurse.\n                    structs_done.insert(struct_name.clone());\n\n                    // Subset the keys so the recursive call knows what it needs to handle -\n                    // only things starting with the new path.\n                    let keys = self\n                        .keys\n                        .iter()\n                        .filter(|new_key| new_key.starts_with_segments(&[&struct_name]))\n                        // Remove the prefix - should always work, but log and skip the key otherwise\n                        .filter_map(|new_key| new_key\n                                    .strip_prefix(&struct_name)\n                                    .map_err(|e| error!(\"Key starting with segment '{}' couldn't remove it as prefix: {}\", &struct_name, e)).ok())\n                        .collect();\n\n                    // And here's what MapDeserializer expects, the key and deserializer for it\n                    trace!(\n                        \"Recursing for struct '{}' with keys: {:?}\",\n                        &struct_name,\n                        keys\n                    );\n                    Some((\n                        struct_name,\n                        ValueDeserializer::Compound(CompoundDeserializer::new(\n                            self.map,\n                            keys,\n                            Some(path),\n                        )),\n                    ))\n                }\n            } else {\n                // No dot, so we have a scalar; hand the data to a scalar deserializer.\n                trace!(\n                    \"Key '{struct_name}' is scalar, getting '{path}' from input to deserialize\"\n                );\n                let val = self.map.get(&path)?;\n                Some((\n                    struct_name,\n                    ValueDeserializer::Scalar(deserializer_for_scalar(val.as_ref())),\n                ))\n            }\n        })))\n    }\n\n    /// We use deserialize_map for all maps, including top-level maps, but to allow top-level maps\n    /// we require that the user specified a prefix for us using from_map_with_prefix.\n    ///\n    /// We also use it for structs below the top level, because you don't need a name once you're\n    /// recursing - you'd always be pointed to by a struct field or map key whose name we use.\n    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>\n    where\n        V: Visitor<'de>,\n    {\n        match self.path {\n            Some(_) => self.deserialize_struct(\"\", &[], visitor),\n            None => bad_root(),\n        }\n    }\n\n    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>\n    where\n        V: Visitor<'de>,\n    {\n        visitor.visit_some(self)\n    }\n\n    /// Scalar types, and compound types we can't use at the root, are forwarded here to be\n    /// rejected.  (Compound types need to have a name to serve at the root level.)\n    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>\n    where\n        V: Visitor<'de>,\n    {\n        if self.path.is_none() {\n            return self.deserialize_struct(\"settings\", &[], visitor);\n        }\n\n        bad_root()\n    }\n\n    // This gives us the rest of the implementations needed to compile, and forwards them to the\n    // function above that will reject them.\n    forward_to_deserialize_any! {\n        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string\n        bytes byte_buf unit unit_struct newtype_struct seq tuple\n        tuple_struct enum identifier ignored_any\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::{from_map, from_map_with_prefix};\n    use crate::{deserialization::Error, Key, KeyType};\n\n    use maplit::hashmap;\n    use serde::Deserialize;\n    use std::collections::HashMap;\n\n    // Helper macro for making a data Key for testing whose name we know is valid.\n    macro_rules! key {\n        ($name:expr) => {\n            Key::new(KeyType::Data, $name).unwrap()\n        };\n    }\n\n    #[derive(Debug, Deserialize, PartialEq)]\n    struct A {\n        id: Option<u64>,\n        name: String,\n        list: Vec<u8>,\n        nested: B,\n        map: HashMap<String, String>,\n    }\n\n    #[derive(Debug, Deserialize, PartialEq)]\n    struct B {\n        a: String,\n        b: bool,\n        c: Option<i64>,\n        d: Option<C>,\n    }\n\n    #[derive(Debug, Deserialize, PartialEq)]\n    struct C {\n        boolean: bool,\n    }\n\n    #[test]\n    fn basic_struct_works() {\n        let c: C = from_map(&hashmap! {\n            key!(\"c.boolean\") => \"true\".to_string(),\n        })\n        .unwrap();\n        assert_eq!(c, C { boolean: true });\n    }\n\n    #[test]\n    fn deep_struct_works() {\n        let a: A = from_map(&hashmap! {\n            key!(\"a.id\") => \"1\".to_string(),\n            key!(\"a.name\") => \"\\\"it's my name\\\"\".to_string(),\n            key!(\"a.list\") => \"[1,2, 3, 4]\".to_string(),\n            key!(\"a.map.a\") => \"\\\"answer is always map\\\"\".to_string(),\n            key!(\"a.nested.a\") => \"\\\"quite nested\\\"\".to_string(),\n            key!(\"a.nested.b\") => \"false\".to_string(),\n            key!(\"a.nested.c\") => \"null\".to_string(),\n            key!(\"a.nested.d.boolean\") => \"true\".to_string(),\n        })\n        .unwrap();\n        assert_eq!(\n            a,\n            A {\n                id: Some(1),\n                name: \"it's my name\".to_string(),\n                list: vec![1, 2, 3, 4],\n                map: hashmap! {\n                    \"a\".to_string() => \"answer is always map\".to_string(),\n                },\n                nested: B {\n                    a: \"quite nested\".to_string(),\n                    b: false,\n                    c: None,\n                    d: Some(C { boolean: true })\n                }\n            }\n        );\n    }\n\n    #[test]\n    fn map_doesnt_work_at_root() {\n        let a: Result<HashMap<String, String>, Error> = from_map(&hashmap! {\n            key!(\"a\") => \"\\\"it's a\\\"\".to_string(),\n            key!(\"b\") => \"\\\"it's b\\\"\".to_string(),\n        });\n        a.unwrap_err();\n    }\n\n    #[test]\n    fn map_works_at_root_with_prefix() {\n        let map = &hashmap! {\n            key!(\"x.boolean\") => \"true\".to_string()\n        };\n        let x: HashMap<String, bool> = from_map_with_prefix(Some(\"x\".to_string()), map).unwrap();\n        assert_eq!(\n            x,\n            hashmap! {\n                \"boolean\".to_string() => true,\n            }\n        );\n    }\n\n    #[derive(Debug, Deserialize, PartialEq)]\n    struct Bad {\n        id: u64,\n    }\n\n    #[test]\n    fn disallowed_data_type() {\n        let bad: Result<Bad, Error> = from_map(&hashmap! {\n            key!(\"id\") => \"42\".to_string(),\n        });\n        bad.unwrap_err();\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/error.rs",
    "content": "use snafu::Snafu;\nuse std::io;\nuse std::path::PathBuf;\n\nuse super::{serialization, ScalarError};\n\n/// Possible errors from datastore operations.\n#[derive(Debug, Snafu)]\n#[snafu(visibility(pub))]\npub enum Error {\n    #[snafu(display(\"Error serializing {}: {} \", given, source))]\n    Serialization {\n        given: String,\n        source: serialization::Error,\n    },\n\n    #[snafu(display(\"Error serializing scalar {}: {} \", given, source))]\n    SerializeScalar { given: String, source: ScalarError },\n\n    #[snafu(display(\"Key would traverse outside data store: {}\", name))]\n    PathTraversal { name: String },\n\n    #[snafu(display(\"Reading key '{}' failed: {}\", key, source))]\n    KeyRead { key: String, source: io::Error },\n\n    #[snafu(display(\"Removing key at '{}' failed: {}\", path.display(), source))]\n    DeleteKey { path: PathBuf, source: io::Error },\n\n    #[snafu(display(\"IO error on '{}': {}\", path.display(), source))]\n    Io { path: PathBuf, source: io::Error },\n\n    #[snafu(display(\"Can't handle non-Unicode file for {}: {}\", context, file))]\n    NonUnicodeFile { file: String, context: String },\n\n    #[snafu(display(\"Data store logic error: {}\", msg))]\n    Internal { msg: String },\n\n    #[snafu(display(\"Data store integrity violation at {}: {}\", path.display(), msg))]\n    Corruption { msg: String, path: PathBuf },\n\n    #[snafu(display(\"Error building data store path: {}\", source))]\n    Path { source: std::path::StripPrefixError },\n\n    #[snafu(display(\"Error listing datastore keys: {}\", source))]\n    ListKeys { source: walkdir::Error },\n\n    #[snafu(display(\"Listed key '{}' not found on disk\", key))]\n    ListedKeyNotPresent { key: String },\n\n    #[snafu(display(\n        \"Listed metadata '{}' for key '{}' not found on disk\",\n        meta_key,\n        data_key\n    ))]\n    ListedMetaNotPresent { meta_key: String, data_key: String },\n\n    #[snafu(display(\"Key name '{}' has invalid format: {}\", name, msg))]\n    InvalidKey { name: String, msg: String },\n\n    #[snafu(display(\"Key name beyond maximum length {}: {}\", name, max))]\n    KeyTooLong { name: String, max: usize },\n\n    #[snafu(display(\"Unable to serialize data: {}\", source))]\n    Serialize { source: serde_json::Error },\n\n    #[snafu(display(\"Unable to run the check constraint function: {}\", source))]\n    CheckConstraintExecution {\n        source: Box<dyn std::error::Error + Send + Sync>,\n    },\n\n    #[snafu(display(\n        \"Check constraint function rejected the transaction. Aborting commit : {}\",\n        err\n    ))]\n    ConstraintCheckReject { err: String },\n}\n\npub type Result<T, E = Error> = std::result::Result<T, E>;\n"
  },
  {
    "path": "sources/api/datastore/src/filesystem.rs",
    "content": "//! This implementation of the DataStore trait relies on the filesystem for data and metadata\n//! storage.\n//!\n//! Data is kept in files with paths resembling the keys, e.g. a/b/c for a.b.c, and metadata is\n//! kept in a suffixed file next to the data, e.g. a/b/c.meta for metadata \"meta\" about a.b.c\n\nuse log::{debug, error, trace};\nuse percent_encoding::{percent_decode_str, utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};\nuse snafu::{ensure, OptionExt, ResultExt};\nuse std::collections::{HashMap, HashSet};\nuse std::fs;\nuse std::io;\nuse std::path::{self, Path, PathBuf};\nuse walkdir::{DirEntry, WalkDir};\n\nuse crate::constraints_check::{ApprovedWrite, ConstraintCheckResult};\n\nuse super::key::{Key, KeyType};\nuse super::{error, Committed, DataStore, Result};\n\nconst METADATA_KEY_PREFIX: &str = \".\";\n\n// This describes the set of characters we encode when making the filesystem path for a given key.\n// Any non-ASCII characters, plus these ones, will be encoded.\n// We start off very strict (anything not alphanumeric) and remove characters we'll allow.\n// To make inspecting the filesystem easier, we allow any filesystem-safe characters that are\n// allowed in a Key.\nconst ENCODE_CHARACTERS: &AsciiSet = &NON_ALPHANUMERIC.remove(b'_').remove(b'-');\n\n#[derive(Debug)]\npub struct FilesystemDataStore {\n    live_path: PathBuf,\n    pending_base_path: PathBuf,\n}\n\nimpl FilesystemDataStore {\n    pub fn new<P: AsRef<Path>>(base_path: P) -> FilesystemDataStore {\n        FilesystemDataStore {\n            live_path: base_path.as_ref().join(\"live\"),\n            pending_base_path: base_path.as_ref().join(\"pending\"),\n        }\n    }\n\n    /// Returns the appropriate filesystem path for pending or live data.\n    fn base_path(&self, committed: &Committed) -> PathBuf {\n        match committed {\n            Committed::Pending { tx } => {\n                let encoded = encode_path_component(tx);\n                self.pending_base_path.join(encoded)\n            }\n            Committed::Live => self.live_path.clone(),\n        }\n    }\n\n    /// Returns the appropriate path on the filesystem for the given data key.\n    fn data_path(&self, key: &Key, committed: &Committed) -> Result<PathBuf> {\n        let base_path = self.base_path(committed);\n\n        // Encode key segments so they're filesystem-safe\n        let encoded: Vec<_> = key.segments().iter().map(encode_path_component).collect();\n        // Join segments with filesystem separator to get path underneath data store\n        let path_suffix = encoded.join(path::MAIN_SEPARATOR_STR);\n\n        // Make path from base + prefix\n        // FIXME: canonicalize requires that the full path exists.  We know our Key is checked\n        // for acceptable characters, so join should be safe enough, but come back to this.\n        // let path = fs::canonicalize(self.base_path.join(path_suffix))?;\n        let path = base_path.join(path_suffix);\n\n        // Confirm no path traversal outside of base\n        ensure!(\n            path != *base_path && path.starts_with(base_path),\n            error::PathTraversalSnafu { name: key.name() }\n        );\n\n        Ok(path)\n    }\n\n    /// Returns the appropriate path on the filesystem for the given metadata key.\n    fn metadata_path(\n        &self,\n        metadata_key: &Key,\n        data_key: &Key,\n        committed: &Committed,\n    ) -> Result<PathBuf> {\n        let path = self.data_path(data_key, committed)?;\n\n        // We want to add to the existing file name, not create new path components (directories),\n        // so we use a string type rather than a path type.\n        let mut path_str = path.into_os_string();\n\n        // Key names have quotes as necessary to identify segments with special characters, so\n        // we don't think \"a.b\" is actually two segments, for example.\n        // Metadata keys only have a single segment, and we encode that as a single path\n        // component, so we don't need the quotes in the filename.\n        let raw_key_name = metadata_key\n            .segments()\n            .first()\n            .context(error::InternalSnafu {\n                msg: \"metadata key with no segments\",\n            })?;\n\n        let encoded_meta = encode_path_component(raw_key_name);\n        path_str.push(METADATA_KEY_PREFIX);\n        path_str.push(encoded_meta);\n\n        Ok(path_str.into())\n    }\n\n    /// Deletes the given path from the filesystem.  Also removes the parent directory if empty\n    /// (repeatedly, up to the base path), so as to have consistent artifacts on the filesystem\n    /// after adding and removing keys.\n    ///\n    /// If the path doesn't exist, we still return Ok for idempotency, but if it exists and we\n    /// fail to remove it, we return Err.\n    ///\n    /// If we fail to remove an empty directory, we log an error, but still return Ok.  (The\n    /// error for trying to remove an empty directory is not specific, and we don't want to rely\n    /// on platform-specific error codes or the error description.  We could check the directory\n    /// contents ourself, but it would be more complex and subject to timing issues.)\n    fn delete_key_path<P>(&mut self, path: P, committed: &Committed) -> Result<()>\n    where\n        P: AsRef<Path>,\n    {\n        let path = path.as_ref();\n\n        // Remove the file.  If it doesn't exist, we're still OK.\n        match fs::remove_file(path) {\n            Ok(()) => {}\n            Err(e) => {\n                if e.kind() != io::ErrorKind::NotFound {\n                    return Err(e).context(error::DeleteKeySnafu { path });\n                }\n            }\n        }\n\n        // Remove the directory if it's empty, i.e. if the setting we removed was the last setting\n        // in that prefix.  Continue up the tree until the base, in case it was the only thing in\n        // that subtree.\n        let base = self.base_path(committed);\n        if let Some(parent) = path.parent() {\n            // Note: ancestors() includes 'parent' itself\n            for parent in parent.ancestors() {\n                // Stop at the base directory; we don't expect anything here or above to be empty,\n                // but stop as a safeguard.\n                if parent == base {\n                    break;\n                }\n                if let Err(e) = fs::remove_dir(parent) {\n                    // If the directory doesn't exist, continue up the tree.  Modulo timing issues,\n                    // this means the key didn't exist either, which means a previous attempt to remove\n                    // the directory failed or we got an unset request for a bogus key.  Either way, we\n                    // can clean up and make things consistent.\n                    if e.kind() == io::ErrorKind::NotFound {\n                        continue;\n\n                    // \"Directory not empty\" doesn't have its own ErrorKind, so we have to check a\n                    // platform-specific error number or the error description, neither of which is\n                    // ideal.  Still, we can at least log an error in the case we know.  Don't\n                    // fail, though, because we've still accomplished our main purpose.\n                    } else if e.raw_os_error() != Some(39) {\n                        error!(\n                            \"Failed to delete directory '{}' we believe is empty: {}\",\n                            parent.display(),\n                            e\n                        );\n                    }\n                    // We won't be able to delete parent directories if this one still exists.\n                    break;\n                }\n            }\n        }\n        Ok(())\n    }\n}\n\n// Filesystem helpers\n\n/// Encodes a string so that it's safe to use as a filesystem path component.\nfn encode_path_component<S: AsRef<str>>(segment: S) -> String {\n    let encoded = utf8_percent_encode(segment.as_ref(), ENCODE_CHARACTERS);\n    encoded.to_string()\n}\n\n/// Decodes a path component, removing the encoding that's applied to make it filesystem-safe.\nfn decode_path_component<S, P>(segment: S, path: P) -> Result<String>\nwhere\n    S: AsRef<str>,\n    P: AsRef<Path>,\n{\n    let segment = segment.as_ref();\n\n    percent_decode_str(segment)\n        .decode_utf8()\n        // Get back a plain String.\n        .map(|cow| cow.into_owned())\n        // decode_utf8 will only fail if someone messed with the filesystem contents directly\n        // and created a filename that contains percent-encoded bytes that are invalid UTF-8.\n        .ok()\n        .context(error::CorruptionSnafu {\n            path: path.as_ref(),\n            msg: format!(\"invalid UTF-8 in encoded segment '{segment}'\"),\n        })\n}\n\n/// Helper for reading a key from the filesystem.  Returns Ok(None) if the file doesn't exist\n/// rather than erroring.\nfn read_file_for_key(key: &Key, path: &Path) -> Result<Option<String>> {\n    match fs::read_to_string(path) {\n        Ok(s) => Ok(Some(s)),\n        Err(e) => {\n            if e.kind() == io::ErrorKind::NotFound {\n                return Ok(None);\n            }\n\n            Err(e).context(error::KeyReadSnafu { key: key.name() })\n        }\n    }\n}\n\n/// Helper for writing a file that makes the directory tree beforehand, so we can handle\n/// arbitrarily dotted keys without needing to create fixed structure first.\nfn write_file_mkdir<S: AsRef<str>>(path: PathBuf, data: S) -> Result<()> {\n    // create key prefix directory if necessary\n    let dirname = path.parent().with_context(|| error::InternalSnafu {\n        msg: format!(\n            \"Given path to write without proper prefix: {}\",\n            path.display()\n        ),\n    })?;\n    fs::create_dir_all(dirname).context(error::IoSnafu { path: dirname })?;\n\n    fs::write(&path, data.as_ref().as_bytes()).context(error::IoSnafu { path: &path })\n}\n\n/// KeyPath represents the filesystem path to a data or metadata key, relative to the base path of\n/// the live or pending data store.  For example, the data key \"settings.a.b\" would be\n/// \"settings/a/b\" and the metadata key \"meta1\" for \"settings.a.b\" would be \"settings/a/b.meta1\".\n///\n/// It allows access to the data_key and (if it's a metadata key) the metadata_key based on the\n/// path.\n///\n/// This structure can be useful when it doesn't matter where the key is physically stored, but\n/// you still need to deal with the interaction between key name and filename, e.g. when\n/// abstracting over data and metadata keys during a search.\n// Note: this may be useful in other parts of the FilesystemDataStore code too.  It may also be\n// useful enough to use its ideas to extend the Key type directly, instead.\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\nstruct KeyPath {\n    data_key: Key,\n    metadata_key: Option<Key>,\n}\n\nimpl KeyPath {\n    /// Given a DirEntry, gives you a KeyPath if it's a valid path to a key.  Specifically, we return\n    /// Ok(Some(Key)) if it seems like a datastore key.  Returns Ok(None) if it doesn't seem like a\n    /// datastore key, e.g. a directory, or if it's a file otherwise invalid as a key.  Returns Err if\n    /// we weren't able to check.\n    fn from_entry<P: AsRef<Path>>(\n        entry: &DirEntry,\n        strip_path_prefix: P,\n    ) -> Result<Option<KeyPath>> {\n        if !entry.file_type().is_file() {\n            trace!(\"Skipping non-file entry: {}\", entry.path().display());\n            return Ok(None);\n        }\n\n        let key_path_raw = entry\n            .path()\n            .strip_prefix(strip_path_prefix)\n            .context(error::PathSnafu)?;\n        // If from_path doesn't think this is an OK key, we'll return Ok(None), otherwise the KeyPath\n        Ok(Self::from_path(key_path_raw).ok())\n    }\n\n    fn from_path(path: &Path) -> Result<KeyPath> {\n        let path_str = path.to_str().context(error::CorruptionSnafu {\n            msg: \"Non-UTF8 path\",\n            path,\n        })?;\n\n        // Split the data and metadata parts.\n        // Any dots in key names are encoded.\n        let mut keys = path_str.splitn(2, '.');\n        let data_key_raw = keys.next().context(error::InternalSnafu {\n            msg: \"KeyPath given empty path\",\n        })?;\n        // Turn the data path into a dotted key\n        let data_segments = data_key_raw\n            .split(path::MAIN_SEPARATOR)\n            .map(|s| decode_path_component(s, path))\n            .collect::<Result<Vec<_>>>()?;\n        let data_key = Key::from_segments(KeyType::Data, &data_segments)?;\n\n        // If we have a metadata portion, make that a Key too\n        let metadata_key = match keys.next() {\n            Some(meta_key_str) => Some(Key::new(KeyType::Meta, meta_key_str)?),\n            None => None,\n        };\n\n        Ok(KeyPath {\n            data_key,\n            metadata_key,\n        })\n    }\n\n    fn key_type(&self) -> KeyType {\n        match self.metadata_key {\n            Some(_) => KeyType::Meta,\n            None => KeyType::Data,\n        }\n    }\n}\n\n/// Helper to walk through the filesystem to find populated keys of the given type, starting with\n/// the given prefix.  Each item in the returned set is a KeyPath representing a data or metadata\n/// key.\n// Note: if we needed to list all possible keys, a walk would only work if we had empty files to\n// represent unset values, which could be ugly.\n// Another option would be to use a procedural macro to step through a structure to list possible\n// keys; this would be similar to serde, but would need to step through Option fields.\nfn find_populated_key_paths<S: AsRef<str>>(\n    datastore: &FilesystemDataStore,\n    key_type: KeyType,\n    prefix: S,\n    committed: &Committed,\n) -> Result<HashSet<KeyPath>> {\n    // Find the base path for our search, and confirm it exists.\n    let base = datastore.base_path(committed);\n    if !base.exists() {\n        match committed {\n            // No live keys; something must be wrong because we create a default datastore.\n            Committed::Live => {\n                return error::CorruptionSnafu {\n                    msg: \"Live datastore missing\",\n                    path: base,\n                }\n                .fail()\n            }\n            // No pending keys, OK, return empty set.\n            Committed::Pending { .. } => {\n                trace!(\n                    \"Returning empty list because pending path doesn't exist: {}\",\n                    base.display()\n                );\n                return Ok(HashSet::new());\n            }\n        }\n    }\n\n    // Walk through the filesystem.\n    let walker = WalkDir::new(&base)\n        .follow_links(false) // shouldn't be links...\n        .same_file_system(true); // shouldn't be filesystems to cross...\n\n    let mut key_paths = HashSet::new();\n    trace!(\n        \"Starting walk of filesystem to list {:?} key paths under {}\",\n        key_type,\n        base.display()\n    );\n\n    // For anything we find, confirm it matches the user's filters, and add it to results.\n    for entry in walker {\n        let entry = entry.context(error::ListKeysSnafu)?;\n        if let Some(kp) = KeyPath::from_entry(&entry, &base)? {\n            if !kp.data_key.name().starts_with(prefix.as_ref()) {\n                trace!(\n                    \"Discarded {:?} key whose data_key '{}' doesn't start with prefix '{}'\",\n                    kp.key_type(),\n                    kp.data_key,\n                    prefix.as_ref()\n                );\n                continue;\n            } else if kp.key_type() != key_type {\n                continue;\n            }\n\n            trace!(\"Found {:?} key at {}\", key_type, entry.path().display());\n            key_paths.insert(kp);\n        }\n    }\n\n    Ok(key_paths)\n}\n\n// TODO: maybe add/strip single newline at end, so file is easier to read\nimpl DataStore for FilesystemDataStore {\n    fn key_populated(&self, key: &Key, committed: &Committed) -> Result<bool> {\n        let path = self.data_path(key, committed)?;\n\n        Ok(path.exists())\n    }\n\n    /// Returns the set of all data keys that are currently populated in the datastore, that\n    /// start with the given prefix.\n    fn list_populated_keys<S: AsRef<str>>(\n        &self,\n        prefix: S,\n        committed: &Committed,\n    ) -> Result<HashSet<Key>> {\n        let key_paths = find_populated_key_paths(self, KeyType::Data, prefix, committed)?;\n        let keys = key_paths.into_iter().map(|kp| kp.data_key).collect();\n        Ok(keys)\n    }\n\n    /// Finds all metadata keys that are currently populated in the datastore whose data keys\n    /// start with the given prefix.  If you specify metadata_key_name, only metadata keys with\n    /// that name will be returned.\n    ///\n    /// Returns a mapping of the data keys to the set of populated metadata keys for each.\n    ///\n    /// Note: The data keys do not need to be populated themselves; sometimes metadata is used\n    /// to help generate the data, for example.  (Committed status is then irrelevant, too.)\n    fn list_populated_metadata<S1, S2>(\n        &self,\n        prefix: S1,\n        committed: &Committed,\n        metadata_key_name: &Option<S2>,\n    ) -> Result<HashMap<Key, HashSet<Key>>>\n    where\n        S1: AsRef<str>,\n        S2: AsRef<str>,\n    {\n        // Find metadata key paths on disk\n        let key_paths = find_populated_key_paths(self, KeyType::Meta, prefix, committed)?;\n\n        // For each file on disk, check the user's conditions, and add it to our output\n        let mut result = HashMap::new();\n        for key_path in key_paths {\n            let data_key = key_path.data_key;\n            let meta_key = key_path.metadata_key.context(error::InternalSnafu {\n                msg: format!(\"Found meta key path with no dot: {data_key}\"),\n            })?;\n\n            // If the user requested specific metadata, move to the next key unless it matches.\n            if let Some(name) = metadata_key_name {\n                if name.as_ref() != meta_key.name() {\n                    continue;\n                }\n            }\n\n            // Insert into output if we met the requested conditions; don't add an entry for\n            // the data key unless we did find some metadata.\n            let data_entry = result.entry(data_key).or_insert_with(HashSet::new);\n            data_entry.insert(meta_key);\n        }\n        Ok(result)\n    }\n\n    fn get_key(&self, key: &Key, committed: &Committed) -> Result<Option<String>> {\n        let path = self.data_path(key, committed)?;\n        read_file_for_key(key, &path)\n    }\n\n    fn set_key<S: AsRef<str>>(&mut self, key: &Key, value: S, committed: &Committed) -> Result<()> {\n        let path = self.data_path(key, committed)?;\n        write_file_mkdir(path, value)\n    }\n\n    fn unset_key(&mut self, key: &Key, committed: &Committed) -> Result<()> {\n        let path = self.data_path(key, committed)?;\n        self.delete_key_path(path, committed)\n    }\n\n    fn get_metadata_raw(\n        &self,\n        metadata_key: &Key,\n        data_key: &Key,\n        committed: &Committed,\n    ) -> Result<Option<String>> {\n        let path = self.metadata_path(metadata_key, data_key, committed)?;\n        read_file_for_key(metadata_key, &path)\n    }\n\n    fn set_metadata<S: AsRef<str>>(\n        &mut self,\n        metadata_key: &Key,\n        data_key: &Key,\n        value: S,\n        committed: &Committed,\n    ) -> Result<()> {\n        let path = self.metadata_path(metadata_key, data_key, committed)?;\n        write_file_mkdir(path, value)\n    }\n\n    fn unset_metadata(&mut self, metadata_key: &Key, data_key: &Key) -> Result<()> {\n        let path = self.metadata_path(metadata_key, data_key, &Committed::Live)?;\n        self.delete_key_path(path, &Committed::Live)\n    }\n\n    /// We commit by copying pending keys to live, then removing pending.  Something smarter (lock,\n    /// atomic flip, etc.) will be required to make the server concurrent.\n    fn commit_transaction<S, C>(\n        &mut self,\n        transaction: S,\n        constraint_check: &C,\n    ) -> Result<HashSet<Key>>\n    where\n        S: Into<String> + AsRef<str>,\n        C: Fn(\n            &mut Self,\n            &Committed,\n        ) -> std::result::Result<\n            ConstraintCheckResult,\n            Box<dyn std::error::Error + Send + Sync + 'static>,\n        >,\n    {\n        let mut pending_keys: HashSet<Key> = Default::default();\n\n        let transactions = self.list_transactions()?;\n        if !transactions.contains(transaction.as_ref()) {\n            return Ok(pending_keys);\n        }\n\n        let pending = Committed::Pending {\n            tx: transaction.into(),\n        };\n\n        let constraints_check_result =\n            constraint_check(self, &pending).context(error::CheckConstraintExecutionSnafu)?;\n\n        let approved_write = ApprovedWrite::try_from(constraints_check_result)?;\n\n        trace!(\n            \"commit_transaction: transaction_metadata: {:?}\",\n            approved_write.metadata\n        );\n\n        // write the metadata.\n        for (metadata_key, data_key, value) in approved_write.metadata {\n            self.set_metadata(&metadata_key, &data_key, value, &Committed::Live)?;\n        }\n\n        let pending_data = approved_write.settings;\n\n        if !pending_data.is_empty() {\n            // Save Keys for return value\n            pending_keys = pending_data.keys().cloned().collect();\n\n            // Apply changes to live\n            debug!(\"Writing pending keys to live\");\n            self.set_keys(&pending_data, &Committed::Live)?;\n        }\n\n        // Remove pending\n        debug!(\"Removing old pending keys\");\n        let path = self.base_path(&pending);\n        fs::remove_dir_all(&path).context(error::IoSnafu { path })?;\n\n        Ok(pending_keys)\n    }\n\n    fn delete_transaction<S>(&mut self, transaction: S) -> Result<HashSet<Key>>\n    where\n        S: Into<String> + AsRef<str>,\n    {\n        let pending = Committed::Pending {\n            tx: transaction.into(),\n        };\n        // Get changed keys so we can return the list\n        let pending_data = self.get_prefix(\"settings.\", &pending)?;\n\n        // Pull out just the keys so we can log them and return them\n        let pending_keys = pending_data.into_keys().collect();\n        debug!(\"Found pending keys: {:?}\", &pending_keys);\n\n        // Delete pending from the filesystem, same as a commit\n        let path = self.base_path(&pending);\n        debug!(\"Removing transaction directory {}\", path.display());\n        if let Err(e) = fs::remove_dir_all(&path) {\n            // If path doesn't exist, it's fine, we'll just return an empty list.\n            if e.kind() != io::ErrorKind::NotFound {\n                return Err(e).context(error::IoSnafu { path });\n            }\n        }\n\n        Ok(pending_keys)\n    }\n\n    /// We store transactions as subdirectories of the pending data store, so to list them we list\n    /// the names of the subdirectories.\n    fn list_transactions(&self) -> Result<HashSet<String>> {\n        // Any directory under pending should be a transaction name.\n        let walker = WalkDir::new(&self.pending_base_path)\n            .min_depth(1)\n            .max_depth(1);\n\n        let mut transactions = HashSet::new();\n        trace!(\n            \"Starting walk of filesystem to list transactions under {}\",\n            self.pending_base_path.display(),\n        );\n\n        for entry in walker {\n            let entry = match entry {\n                Ok(entry) => entry,\n                Err(e) => {\n                    if let Some(io_error) = e.io_error() {\n                        // If there's no pending directory, that's OK, just return empty set.\n                        if io_error.kind() == io::ErrorKind::NotFound {\n                            break;\n                        }\n                    }\n                    return Err(e).context(error::ListKeysSnafu);\n                }\n            };\n\n            if entry.file_type().is_dir() {\n                // The directory name should be valid UTF-8, encoded by encode_path_component,\n                // or the data store has been corrupted.\n                let file_name = entry.file_name().to_str().context(error::CorruptionSnafu {\n                    msg: \"Non-UTF8 path\",\n                    path: entry.path(),\n                })?;\n                let transaction = decode_path_component(file_name, entry.path())?;\n                transactions.insert(transaction);\n            }\n        }\n\n        Ok(transactions)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn data_path() {\n        let f = FilesystemDataStore::new(\"/base\");\n        let key = Key::new(KeyType::Data, \"a.b.c\").unwrap();\n\n        let tx = \"test transaction\";\n        let pending = f\n            .data_path(&key, &Committed::Pending { tx: tx.into() })\n            .unwrap();\n        assert_eq!(\n            pending.into_os_string(),\n            \"/base/pending/test%20transaction/a/b/c\"\n        );\n\n        let live = f.data_path(&key, &Committed::Live).unwrap();\n        assert_eq!(live.into_os_string(), \"/base/live/a/b/c\");\n    }\n\n    #[test]\n    fn metadata_path() {\n        let f = FilesystemDataStore::new(\"/base\");\n        let data_key = Key::new(KeyType::Data, \"a.b.c\").unwrap();\n        let md_key = Key::new(KeyType::Meta, \"my-metadata\").unwrap();\n\n        let tx = \"test transaction\";\n        let pending = f\n            .metadata_path(&md_key, &data_key, &Committed::Pending { tx: tx.into() })\n            .unwrap();\n        assert_eq!(\n            pending.into_os_string(),\n            \"/base/pending/test%20transaction/a/b/c.my-metadata\"\n        );\n\n        let live = f\n            .metadata_path(&md_key, &data_key, &Committed::Live)\n            .unwrap();\n        assert_eq!(live.into_os_string(), \"/base/live/a/b/c.my-metadata\");\n    }\n\n    #[test]\n    fn encode_path_component_works() {\n        assert_eq!(encode_path_component(\"a-b_42\"), \"a-b_42\");\n        assert_eq!(encode_path_component(\"a.b\"), \"a%2Eb\");\n        assert_eq!(encode_path_component(\"a/b\"), \"a%2Fb\");\n        assert_eq!(encode_path_component(\"a b%c<d>e\"), \"a%20b%25c%3Cd%3Ee\");\n    }\n\n    #[test]\n    fn decode_path_component_works() {\n        assert_eq!(decode_path_component(\"a-b_42\", \"\").unwrap(), \"a-b_42\");\n        assert_eq!(decode_path_component(\"a%2Eb\", \"\").unwrap(), \"a.b\");\n        assert_eq!(decode_path_component(\"a%2Fb\", \"\").unwrap(), \"a/b\");\n        assert_eq!(\n            decode_path_component(\"a%20b%25c%3Cd%3Ee\", \"\").unwrap(),\n            \"a b%c<d>e\"\n        );\n\n        // Invalid UTF-8\n        decode_path_component(\"%C3%28\", \"\").unwrap_err();\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/key.rs",
    "content": "// Note: this only allows reading and writing UTF-8 keys and values; is that OK?\n\nuse log::trace;\nuse serde::{Serialize, Serializer};\nuse snafu::ensure;\nuse std::fmt;\nuse std::hash::{Hash, Hasher};\n\nuse super::{error, Result};\n\npub const KEY_SEPARATOR: char = '.';\n// String refs are more convenient for some Rust functions\npub const KEY_SEPARATOR_STR: &str = \".\";\n\n/// Maximum key name length matches the maximum filename length of 255; if we need to have longer\n/// keys (up to 4096) we could make prefixes not count against this limit.\nconst MAX_KEY_NAME_LENGTH: usize = 255;\n\n/// KeyType represents whether we want to check a Key as a data key or metadata key.\n#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]\npub enum KeyType {\n    Data,\n    Meta,\n}\n\n/// A Key is a pointer into the datastore with a convenient name.  Their names are simply dotted\n/// strings (\"a.b.c\") with the dots implying hierarchy, so \"a.b.c\" and \"a.b.d\" are probably\n/// related.\n///\n/// Keys that need to include dots in the name can quote that segment of the name, for example the\n/// key a.\"b.c\".d has three segments: \"a\", \"b.c\", and \"d\".\n#[derive(Clone, Debug)]\npub struct Key {\n    name: String,\n    segments: Vec<String>,\n}\n\nimpl Key {\n    /// Returns a list of the segments that make up the key name.\n    ///\n    /// Examples:\n    /// * a.b.c -> [\"a\", \"b\", \"c\"]\n    /// * \"a.b\".c -> [\"a.b\", \"c\"]\n    pub fn segments(&self) -> &Vec<String> {\n        &self.segments\n    }\n\n    /// Returns the name of the key.\n    ///\n    /// If you created the Key using with_segments(), the segments are quoted as necessary to\n    /// handle special characters.  Examples:\n    /// * created with segments [\"a\", \"b\", \"c\"] -> a.b.c\n    /// * created with segments [\"a.b\", \"c\"] -> \"a.b\".c\n    pub fn name(&self) -> &String {\n        &self.name\n    }\n\n    /// Creates a Key of the given type from the given name.\n    ///\n    /// If there are special characters in the name, like \".\" which is used as a separator,\n    /// then you should quote that segment, for example: a.\"b.c\".d to represent three segments\n    /// \"a\", \"b.c\", and \"d\".  If possible, you should use `Key::from_segments` instead, to more\n    /// accurately represent the individual segments.\n    pub fn new<S: AsRef<str>>(key_type: KeyType, name: S) -> Result<Self> {\n        let segments = Self::parse_name_segments(&name)?;\n\n        Self::check_key(key_type, &name, &segments)?;\n\n        Ok(Self {\n            name: name.as_ref().to_string(),\n            segments,\n        })\n    }\n\n    /// Creates a Key of the given type from the given name segments.\n    ///\n    /// For example, passing &[\"a\", \"b.c\", \"c\"] will create a key named: a.\"b.c\".c\n    pub fn from_segments<S>(key_type: KeyType, segments: &[S]) -> Result<Self>\n    where\n        S: AsRef<str>,\n    {\n        let name = Self::encode_name_segments(segments)?;\n\n        Self::check_key(key_type, &name, segments)?;\n\n        Ok(Self {\n            name,\n            segments: segments.iter().map(|s| s.as_ref().into()).collect(),\n        })\n    }\n\n    /// Removes the given prefix from the key name, returning a new Key.\n    ///\n    /// This is intended to remove key name segments from the beginning of the name, therefore\n    /// this only makes sense for Data keys, not Meta keys.  A Data key will be returned.\n    ///\n    /// You should not include an ending separator (dot), it will be removed for you.\n    ///\n    /// If the key name does not begin with the given prefix, the returned key will be\n    /// identical.\n    ///\n    /// Fails if the new key would be invalid, e.g. if the prefix is the entire key.\n    pub(super) fn strip_prefix<S>(&self, prefix: S) -> Result<Self>\n    where\n        S: AsRef<str>,\n    {\n        let prefix = prefix.as_ref();\n        ensure!(\n            prefix != self.name,\n            error::InvalidKeySnafu {\n                name: \"\",\n                msg: format!(\"strip_prefix of '{prefix}' matches key\")\n            }\n        );\n\n        let strip = prefix.to_string() + \".\";\n\n        // Check starts_with so we don't replace in the middle of the string...\n        let name = if self.name.starts_with(&strip) {\n            self.name.replacen(&strip, \"\", 1)\n        } else {\n            self.name.clone()\n        };\n\n        Self::new(KeyType::Data, name)\n    }\n\n    /// Removes the given key segments from the beginning of the key, returning a new Key.\n    ///\n    /// This only makes sense for Data keys because Meta keys only have one segment.  A Data key\n    /// will be returned.\n    ///\n    /// If the key does not begin with all of the given segments, no segments will be removed,\n    /// so the returned key will be identical.\n    ///\n    /// Fails if the new key would be invalid, e.g. if the given segments are the entire key.\n    pub(super) fn strip_prefix_segments<S>(&self, prefix: &[S]) -> Result<Self>\n    where\n        S: AsRef<str>,\n    {\n        // We walk through the given prefix segments, looking for anything that doesn't match\n        // our segments, at which point we know we're going to return an unchanged key.\n        for (i, theirs) in prefix.iter().enumerate() {\n            match self.segments().get(i) {\n                // If we run out of our segments, the prefix is longer than the existing key,\n                // and therefore can't match; we return an unchanged key.\n                None => return Ok(self.clone()),\n                Some(ours) => {\n                    // Difference found; return an unchanged key.\n                    if ours != theirs.as_ref() {\n                        return Ok(self.clone());\n                    }\n                }\n            }\n        }\n\n        // No differences were found, so we remove the given segments.\n        Self::from_segments(KeyType::Data, &self.segments[prefix.len()..])\n    }\n\n    /// Adds the given segments to the key name, returning a new Key.\n    ///\n    /// The given segments should not be quoted even if they contain the separator character;\n    /// using a segment list allows us to be precise about the distinction between segments.\n    ///\n    /// Fails if the new key would be invalid, e.g. the suffix contains invalid characters.\n    pub(super) fn append_segments<S>(&self, segments: &[S]) -> Result<Self>\n    where\n        S: AsRef<str>,\n    {\n        let our_segments = self.segments().iter().map(|s| s.as_ref());\n        let their_segments = segments.iter().map(|s| s.as_ref());\n\n        let new_segments: Vec<_> = our_segments.chain(their_segments).collect();\n        Self::from_segments(KeyType::Data, &new_segments)\n    }\n\n    /// Adds the given key's name to this key name and returns a new Key.\n    ///\n    /// This is done precisely using each key's segments, so handling of separators and quoting\n    /// is automatic.\n    ///\n    /// Fails if the new key would be invalid, e.g. too long.\n    pub(super) fn append_key(&self, key: &Key) -> Result<Self> {\n        let our_segments = self.segments().iter();\n        let their_segments = key.segments().iter();\n\n        let new_segments: Vec<_> = our_segments.chain(their_segments).collect();\n        Self::from_segments(KeyType::Data, &new_segments)\n    }\n\n    /// Additional safety checks for parsed or generated keys.\n    fn check_key<S1, S2>(key_type: KeyType, name: S1, segments: &[S2]) -> Result<()>\n    where\n        S1: AsRef<str>,\n        S2: AsRef<str>,\n    {\n        let name = name.as_ref();\n\n        ensure!(\n            name.len() <= MAX_KEY_NAME_LENGTH,\n            error::KeyTooLongSnafu {\n                name,\n                max: MAX_KEY_NAME_LENGTH,\n            }\n        );\n\n        match key_type {\n            KeyType::Data => {\n                ensure!(\n                    !segments.is_empty(),\n                    error::InvalidKeySnafu {\n                        name,\n                        msg: \"data keys must have at least one segment\",\n                    }\n                );\n            }\n            KeyType::Meta => {\n                ensure!(\n                    segments.len() == 1,\n                    error::InvalidKeySnafu {\n                        name,\n                        msg: \"meta keys may only have one segment\",\n                    }\n                );\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Determines whether a character is acceptable within a segment of a key name.  This is\n    /// separate from quoting; if a character isn't valid, it isn't valid quoted, either.\n    fn valid_character(c: char) -> bool {\n        matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '/')\n    }\n\n    /// Given a key name, returns a list of its name segments, separated by KEY_SEPARATOR.\n    /// Respects quoting of segments so they can contain dots.\n    ///\n    /// Examples:\n    /// * a.b.c -> [\"a\", \"b\", \"c\"]\n    /// * \"a.b\".c -> [\"a.b\", \"c\"]\n    fn parse_name_segments<S: AsRef<str>>(name: S) -> Result<Vec<String>> {\n        let name = name.as_ref();\n\n        ensure!(\n            !name.is_empty(),\n            error::InvalidKeySnafu {\n                name,\n                msg: \"cannot be empty\",\n            }\n        );\n\n        // The full list of name segments we're going to return.\n        let mut segments = Vec::new();\n        // The current name segment we're checking.\n        let mut segment = String::new();\n        // Track whether we're inside a quoted section of the key name\n        let mut in_quotes = false;\n\n        // Walk through each character, looking for quotes or separators to update state\n        for c in name.chars() {\n            if c == '\"' {\n                // Quotes don't go into the name segments, so we just flip the flag.\n                in_quotes = !in_quotes;\n            } else if c == KEY_SEPARATOR {\n                if in_quotes {\n                    // If we see a separator inside quotes, it's just like any other character.\n                    segment.push(c);\n                } else {\n                    // If we see a separator outside quotes, it should be ending a segment.\n                    // Segments can't be empty.\n                    ensure!(\n                        !segment.is_empty(),\n                        error::InvalidKeySnafu {\n                            name,\n                            msg: \"empty key segment\",\n                        }\n                    );\n                    // Save the segment we just saw and start a new one.\n                    segments.push(segment);\n                    segment = String::new();\n                }\n            } else {\n                // Not a special character; make sure it's a valid part of a name segment.\n                if Self::valid_character(c) {\n                    segment.push(c);\n                } else {\n                    return error::InvalidKeySnafu {\n                        name,\n                        msg: format!(\"invalid character in key: '{c}'\"),\n                    }\n                    .fail();\n                }\n            }\n        }\n\n        ensure!(\n            !in_quotes,\n            error::InvalidKeySnafu {\n                name,\n                msg: \"unbalanced quotes\",\n            }\n        );\n        ensure!(\n            !segment.is_empty(),\n            error::InvalidKeySnafu {\n                name,\n                msg: \"ends with separator\",\n            }\n        );\n\n        // Push final segment (keys don't end with a dot, which is when we normally push)\n        segments.push(segment);\n\n        trace!(\"Parsed key name '{name}' to segments {segments:?}\");\n        Ok(segments)\n    }\n\n    /// Given a list of key name segments, encodes them into a name string.  Any segments with\n    /// special characters (like the separator) are quoted.\n    fn encode_name_segments<S: AsRef<str>>(segments: &[S]) -> Result<String> {\n        let segments: Vec<_> = segments.iter().map(|s| s.as_ref()).collect();\n        let mut outputs = Vec::new();\n\n        // Check whether we need quoting for each segment.\n        for segment in segments.iter() {\n            for chr in segment.chars() {\n                ensure!(\n                    chr == KEY_SEPARATOR || Self::valid_character(chr),\n                    error::InvalidKeySnafu {\n                        // Give an understandable key name in the error, even if it's invalid\n                        name: segments.join(\".\"),\n                        msg: format!(\"Segment '{segment}' contains invalid character '{chr}'\"),\n                    }\n                );\n            }\n\n            if segment.chars().any(|c| c == KEY_SEPARATOR) {\n                // Includes separator; quote the segment.\n                outputs.push(format!(\"\\\"{segment}\\\"\"));\n            } else {\n                // No special characters, no escaping needed.\n                outputs.push(segment.to_string());\n            }\n        }\n\n        // Join the (possibly quoted) segments with our separator.\n        let name = outputs.join(KEY_SEPARATOR_STR);\n        trace!(\"Encoded key '{name}' from segments {segments:?}\");\n        Ok(name)\n    }\n\n    pub fn starts_with_segments<S>(&self, segments: &[S]) -> bool\n    where\n        S: AsRef<str>,\n    {\n        if self.segments.len() < segments.len() {\n            return false;\n        }\n\n        let ours = self.segments()[0..segments.len()].iter();\n        let theirs = segments.iter().map(|s| s.as_ref());\n\n        ours.zip(theirs).all(|(a, b)| a == b)\n    }\n}\n\nimpl fmt::Display for Key {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.name)\n    }\n}\n\n// We can't implement Deserialize for Key because Key doesn't store its key type, but we can\n// serialize it to its name.\nimpl Serialize for Key {\n    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(&self.name)\n    }\n}\n\n// The segments are our source of truth.\nimpl PartialEq for Key {\n    fn eq(&self, other: &Key) -> bool {\n        self.segments == other.segments\n    }\n}\nimpl Eq for Key {}\nimpl Hash for Key {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.segments.hash(state);\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::{Key, KeyType, MAX_KEY_NAME_LENGTH};\n\n    // Helper macro for testing conditions that apply to both data and metadata keys\n    macro_rules! data_and_meta {\n        ($fn:expr) => {\n            $fn(KeyType::Data);\n            $fn(KeyType::Meta);\n        };\n    }\n\n    #[test]\n    fn short_key_ok() {\n        data_and_meta!(|t| assert!(Key::new(t, \"a\").is_ok()));\n    }\n\n    #[test]\n    fn dotted_data_key_ok() {\n        assert!(Key::new(KeyType::Data, \"a.b.c.d.e.f.g\").is_ok());\n    }\n\n    #[test]\n    fn dotted_metadata_key_fails() {\n        assert!(Key::new(KeyType::Meta, \"a.b.c.d.e.f.g\").is_err());\n    }\n\n    #[test]\n    fn quoted_data_key_ok() {\n        let name = \"a.\\\"b.c\\\".d\";\n        let key = Key::new(KeyType::Data, name).unwrap();\n        assert_eq!(key.name(), name);\n        assert_eq!(key.segments(), &[\"a\", \"b.c\", \"d\"]);\n    }\n\n    #[test]\n    fn quoted_metadata_key_ok() {\n        // Metadata keys can only have one segment, but it can be quoted\n        let name = \"\\\"b.c\\\"\";\n        let key = Key::new(KeyType::Data, name).unwrap();\n        assert_eq!(key.name(), name);\n        assert_eq!(key.segments(), &[\"b.c\"]);\n    }\n\n    #[test]\n    fn from_segments() {\n        let name = \"a.\\\"b.c\\\".d\";\n        let segments = &[\"a\", \"b.c\", \"d\"];\n        let key = Key::from_segments(KeyType::Data, segments).unwrap();\n        assert_eq!(key.name(), name);\n        assert_eq!(key.segments(), segments);\n    }\n\n    #[test]\n    fn key_with_special_chars_ok() {\n        data_and_meta!(|t| assert!(Key::new(t, \"a-b_c\").is_ok()));\n    }\n\n    #[test]\n    fn long_key_ok() {\n        data_and_meta!(|t| assert!(Key::new(t, \"a\".repeat(MAX_KEY_NAME_LENGTH)).is_ok()));\n    }\n\n    #[test]\n    fn key_too_long() {\n        data_and_meta!(|t| assert!(Key::new(t, \"a\".repeat(MAX_KEY_NAME_LENGTH + 1)).is_err()));\n    }\n\n    #[test]\n    fn key_bad_chars() {\n        data_and_meta!(|t| assert!(Key::new(t, \"!\").is_err()));\n        data_and_meta!(|t| assert!(Key::new(t, \"$\").is_err()));\n        data_and_meta!(|t| assert!(Key::new(t, \"&\").is_err()));\n        data_and_meta!(|t| assert!(Key::new(t, \";\").is_err()));\n        data_and_meta!(|t| assert!(Key::new(t, \"|\").is_err()));\n        data_and_meta!(|t| assert!(Key::new(t, r\"\\\").is_err()));\n    }\n\n    #[test]\n    fn key_bad_format() {\n        data_and_meta!(|t| assert!(Key::new(t, \"a.\").is_err()));\n    }\n\n    #[test]\n    fn strip_prefix_ok() {\n        // Remove plain prefix\n        let key = Key::new(KeyType::Data, \"a.b.c.d\").unwrap();\n        let prefix = \"a.b\";\n        assert_eq!(key.strip_prefix(prefix).unwrap().name(), \"c.d\");\n\n        // Don't remove non-matching prefix; no change\n        let key = Key::new(KeyType::Data, \"a.b.c.d\").unwrap();\n        let prefix = \"x.y\";\n        assert_eq!(key.strip_prefix(prefix).unwrap().name(), \"a.b.c.d\");\n\n        // Don't remove prefix that doesn't match whole quoted segment\n        let key = Key::new(KeyType::Data, \"a.\\\"b.c\\\".d\").unwrap();\n        let prefix = \"a.b\";\n        assert_eq!(key.strip_prefix(prefix).unwrap().name(), \"a.\\\"b.c\\\".d\");\n\n        // Do remove prefix that does match whole quoted segment\n        let key = Key::new(KeyType::Data, \"a.\\\"b.c\\\".d\").unwrap();\n        let prefix = \"a.\\\"b.c\\\"\";\n        assert_eq!(key.strip_prefix(prefix).unwrap().name(), \"d\");\n    }\n\n    #[test]\n    fn strip_prefix_err() {\n        let key = Key::new(KeyType::Data, \"a.b.c.d\").unwrap();\n        let prefix = \"a.b.c.d\";\n        key.strip_prefix(prefix).unwrap_err();\n    }\n\n    #[test]\n    fn strip_prefix_segments_ok() {\n        // Remove plain prefix\n        let key = Key::new(KeyType::Data, \"a.b.c.d\").unwrap();\n        let prefix = &[\"a\", \"b\"];\n        assert_eq!(key.strip_prefix_segments(prefix).unwrap().name(), \"c.d\");\n\n        // Don't remove non-matching prefix; no change\n        let key = Key::new(KeyType::Data, \"a.b.c.d\").unwrap();\n        let prefix = &[\"x\", \"y\"];\n        assert_eq!(key.strip_prefix_segments(prefix).unwrap().name(), \"a.b.c.d\");\n\n        // Don't remove prefix that doesn't match whole quoted segment\n        let key = Key::new(KeyType::Data, \"a.\\\"b.c\\\".d\").unwrap();\n        let prefix = &[\"a\", \"b\"];\n        assert_eq!(\n            key.strip_prefix_segments(prefix).unwrap().name(),\n            \"a.\\\"b.c\\\".d\"\n        );\n\n        // Do remove prefix that does match whole quoted segment\n        let key = Key::new(KeyType::Data, \"a.\\\"b.c\\\".d\").unwrap();\n        let prefix = &[\"a\", \"b.c\"];\n        assert_eq!(key.strip_prefix_segments(prefix).unwrap().name(), \"d\");\n    }\n\n    #[test]\n    fn strip_prefix_segments_err() {\n        let key = Key::new(KeyType::Data, \"a.b.c.d\").unwrap();\n        let prefix = &[\"a\", \"b\", \"c\", \"d\"];\n        key.strip_prefix_segments(prefix).unwrap_err();\n    }\n\n    #[test]\n    fn append_segments_ok() {\n        let key = Key::new(KeyType::Data, \"a.b\").unwrap();\n        let new = key.append_segments(&[\"x\"]).unwrap();\n        assert_eq!(new.name(), \"a.b.x\");\n\n        let new = key.append_segments(&[\"x.y\"]).unwrap();\n        assert_eq!(new.name(), \"a.b.\\\"x.y\\\"\");\n\n        let new = key.append_segments(&[\"x\", \"y\"]).unwrap();\n        assert_eq!(new.name(), \"a.b.x.y\");\n    }\n\n    #[test]\n    fn append_segments_err() {\n        let key = Key::new(KeyType::Data, \"a.b\").unwrap();\n        key.append_segments(&[\"@\"]).unwrap_err();\n    }\n\n    #[test]\n    fn append_key_ok() {\n        let key = Key::new(KeyType::Data, \"a.b\").unwrap();\n        let key2 = Key::new(KeyType::Data, \"c.d\").unwrap();\n        let new = key.append_key(&key2).unwrap();\n        assert_eq!(new.name(), \"a.b.c.d\");\n\n        let key2 = Key::new(KeyType::Data, \"\\\"c.d\\\"\").unwrap();\n        let new = key.append_key(&key2).unwrap();\n        assert_eq!(new.name(), \"a.b.\\\"c.d\\\"\");\n    }\n\n    #[test]\n    fn append_key_err() {\n        let long_key = Key::new(KeyType::Data, \"a\".repeat(MAX_KEY_NAME_LENGTH)).unwrap();\n        let key2 = Key::new(KeyType::Data, \"b\").unwrap();\n        long_key.append_key(&key2).unwrap_err();\n    }\n\n    #[test]\n    fn starts_with_segments() {\n        let key = Key::new(KeyType::Data, \"a.b\").unwrap();\n        assert!(key.starts_with_segments(&[\"a\"]));\n        assert!(!key.starts_with_segments(&[\"\\\"a.b\\\"\"]));\n        assert!(!key.starts_with_segments(&[\"a.\"]));\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/lib.rs",
    "content": "/*!\n# Background\n\nA 'data store' in Bottlerocket is responsible for storing key/value pairs and metadata about those pairs, with the ability to commit changes in transactions.\n\nFor more detail about their usage, see [apiserver](../apiserver).\n\n# Library\n\nThis library provides a trait defining the exact requirements, along with basic implementations for filesystem and memory data stores.\n\nThere's also a common error type and some methods that implementations of DataStore should generally share, like scalar serialization.\n\nWe represent scalars -- the actual values stored under a datastore key -- using JSON, just to have a convenient human-readable form.\n(TOML doesn't allow raw scalars.  The JSON spec doesn't seem to either, but this works, and the format is so simple for scalars that it could be easily swapped out if needed.)\n\n# Serialization and deserialization\n\nThe `serialization` module provides code to serialize Rust types into a mapping of datastore-acceptable keys (a.b.c) and values.\n\nThe `deserialization` module provides code to deserialize datastore-acceptable keys (a.b.c) and values into Rust types.\n\n# Current limitations\n\n* The user (e.g. apiserver) needs to handle locking.\n* There's no support for rolling back transactions.\n* The `serialization` module can't handle complex types under lists; it assumes lists can be serialized as scalars.\n*/\n\npub mod constraints_check;\npub mod deserialization;\npub mod error;\npub mod filesystem;\npub mod key;\npub mod memory;\npub mod serialization;\n\nuse constraints_check::ConstraintCheckResult;\npub use error::{Error, Result};\npub use filesystem::FilesystemDataStore;\npub use key::{Key, KeyType, KEY_SEPARATOR, KEY_SEPARATOR_STR};\n\nuse log::{info, trace};\nuse serde::{Deserialize, Serialize};\nuse snafu::OptionExt;\nuse std::collections::{HashMap, HashSet};\n\n/// Committed represents whether we want to look at pending (uncommitted) or live (committed) data\n/// in the datastore.\n#[derive(Debug, Clone, PartialEq)]\npub enum Committed {\n    Live,\n    Pending {\n        // If the change is pending, we need to know the transaction name.\n        tx: String,\n    },\n}\n\npub trait DataStore {\n    /// Returns whether a key is present (has a value) in the datastore.\n    fn key_populated(&self, key: &Key, committed: &Committed) -> Result<bool>;\n    /// Returns a list of the populated data keys in the datastore whose names start with the given\n    /// prefix.\n    fn list_populated_keys<S: AsRef<str>>(\n        &self,\n        prefix: S,\n        committed: &Committed,\n    ) -> Result<HashSet<Key>>;\n    /// Finds all metadata keys that are currently populated in the datastore whose data keys\n    /// start with the given prefix.  If you specify metadata_key_name, only metadata keys with\n    /// that name will be returned.\n    ///\n    /// Returns a mapping of the data keys to the set of populated metadata keys for each.\n    fn list_populated_metadata<S1, S2>(\n        &self,\n        prefix: S1,\n        committed: &Committed,\n        metadata_key_name: &Option<S2>,\n    ) -> Result<HashMap<Key, HashSet<Key>>>\n    where\n        S1: AsRef<str>,\n        S2: AsRef<str>;\n\n    /// Retrieve the value for a single data key from the datastore.\n    fn get_key(&self, key: &Key, committed: &Committed) -> Result<Option<String>>;\n    /// Set the value of a single data key in the datastore.\n    fn set_key<S: AsRef<str>>(&mut self, key: &Key, value: S, committed: &Committed) -> Result<()>;\n    /// Removes the given data key from the datastore.  If we succeeded, we return Ok(()); if\n    /// the key didn't exist, we also return Ok(()); we return Err only if we failed to check\n    /// or remove the key.\n    fn unset_key(&mut self, key: &Key, committed: &Committed) -> Result<()>;\n\n    /// Retrieve the value for a single metadata key from the datastore.  Values will inherit from\n    /// earlier in the tree, if more specific values are not found later.\n    fn get_metadata(\n        &self,\n        metadata_key: &Key,\n        data_key: &Key,\n        committed: &Committed,\n    ) -> Result<Option<String>> {\n        let mut result = Ok(None);\n        let mut current_path = Vec::new();\n\n        // Walk through segments of the data key in order, returning the last metadata we find\n        for component in data_key.segments() {\n            current_path.push(component);\n\n            let data_key = Key::from_segments(KeyType::Data, &current_path).unwrap_or_else(|_| {\n                unreachable!(\"Prefix of Key failed to make Key: {:?}\", current_path)\n            });\n\n            if let Some(md) = self.get_metadata_raw(metadata_key, &data_key, committed)? {\n                result = Ok(Some(md));\n            }\n        }\n        result\n    }\n\n    /// Retrieve the value for a single metadata key from the datastore, without taking into\n    /// account inheritance of metadata from earlier in the tree.\n    fn get_metadata_raw(\n        &self,\n        metadata_key: &Key,\n        data_key: &Key,\n        committed: &Committed,\n    ) -> Result<Option<String>>;\n    /// Set the value of a single metadata key in the datastore.\n    fn set_metadata<S: AsRef<str>>(\n        &mut self,\n        metadata_key: &Key,\n        data_key: &Key,\n        value: S,\n        committed: &Committed,\n    ) -> Result<()>;\n    /// Removes the given metadata key from the given data key in the datastore.  If we\n    /// succeeded, we return Ok(()); if the data or metadata key didn't exist, we also return\n    /// Ok(()); we return Err only if we failed to check or remove the key.\n    fn unset_metadata(&mut self, metadata_key: &Key, data_key: &Key) -> Result<()>;\n\n    /// Applies pending changes from the given transaction to the live datastore.  Returns the\n    /// list of changed keys.\n    fn commit_transaction<S, C>(\n        &mut self,\n        transaction: S,\n        constraint_check: &C,\n    ) -> Result<HashSet<Key>>\n    where\n        S: Into<String> + AsRef<str>,\n        C: Fn(\n            &mut Self,\n            &Committed,\n        ) -> std::result::Result<\n            ConstraintCheckResult,\n            Box<dyn std::error::Error + Send + Sync + 'static>,\n        >;\n\n    /// Remove the given pending transaction from the datastore.  Returns the list of removed\n    /// keys.  If the transaction doesn't exist, will return Ok with an empty list.\n    fn delete_transaction<S>(&mut self, transaction: S) -> Result<HashSet<Key>>\n    where\n        S: Into<String> + AsRef<str>;\n\n    /// Returns a list of the names of any pending transactions in the data store.\n    fn list_transactions(&self) -> Result<HashSet<String>>;\n\n    /// Set multiple data keys at once in the data store.\n    ///\n    /// Implementers can replace the default implementation if there's a faster way than setting\n    /// each key individually.\n    fn set_keys<S>(&mut self, pairs: &HashMap<Key, S>, committed: &Committed) -> Result<()>\n    where\n        S: AsRef<str>,\n    {\n        for (key, value) in pairs {\n            match committed {\n                Committed::Live => {\n                    info!(\"Committed data key {}\", key.name());\n                }\n                state => {\n                    trace!(\"Data key {} state changed to {:?}\", key.name(), state);\n                }\n            };\n            self.set_key(key, value, committed)?;\n        }\n        Ok(())\n    }\n    /// Removes multiple data keys at once in the data store.\n    ///\n    /// Implementers can replace the default implementation if there's a faster way than\n    /// unsetting each key individually.\n    fn unset_keys(&mut self, keys: &HashSet<Key>, committed: &Committed) -> Result<()> {\n        for key in keys {\n            trace!(\"Unsetting data key {}\", key.name());\n            self.unset_key(key, committed)?;\n        }\n        Ok(())\n    }\n\n    /// Retrieves all keys starting with the given prefix, returning them in a Key -> value map.\n    ///\n    /// Can be followed up by a deserialize::from_map call to build a structure.\n    fn get_prefix<S: AsRef<str>>(\n        &self,\n        find_prefix: S,\n        committed: &Committed,\n    ) -> Result<HashMap<Key, String>> {\n        let keys = self.list_populated_keys(&find_prefix, committed)?;\n        trace!(\"Found populated keys: {keys:?}\");\n        if keys.is_empty() {\n            return Ok(HashMap::new());\n        }\n\n        let mut result = HashMap::new();\n        for key in keys {\n            // Already confirmed key via listing keys, so an error is more serious.\n            trace!(\"Pulling value from datastore for key: {key}\");\n            let value = self\n                .get_key(&key, committed)?\n                .context(error::ListedKeyNotPresentSnafu { key: key.name() })?;\n\n            result.insert(key, value);\n        }\n        Ok(result)\n    }\n\n    /// Retrieves all metadata for data keys starting with the given prefix.  If you specify\n    /// metadata_key_name, only metadata keys with that name will be returned.  Returns a\n    /// mapping of each data key to its metadata, where metadata is a mapping of metadata Key to\n    /// string value.\n    fn get_metadata_prefix<S1, S2>(\n        &self,\n        find_prefix: S1,\n        committed: &Committed,\n        metadata_key_name: &Option<S2>,\n    ) -> Result<HashMap<Key, HashMap<Key, String>>>\n    where\n        S1: AsRef<str>,\n        S2: AsRef<str>,\n    {\n        let meta_map = self.list_populated_metadata(&find_prefix, committed, metadata_key_name)?;\n        trace!(\"Found populated metadata: {meta_map:?}\");\n        if meta_map.is_empty() {\n            return Ok(HashMap::new());\n        }\n\n        let mut result = HashMap::new();\n        for (data_key, meta_keys) in meta_map {\n            for meta_key in meta_keys {\n                // If the user requested specific metadata, move to the next key unless it\n                // matches.\n                if let Some(name) = metadata_key_name {\n                    if name.as_ref() != meta_key.name() {\n                        continue;\n                    }\n                }\n\n                // Already confirmed key via listing keys, so an error is more serious.\n                trace!(\n                    \"Pulling metadata '{}' from datastore for key: {}\",\n                    meta_key,\n                    &data_key\n                );\n                let value = self\n                    .get_metadata(&meta_key, &data_key, committed)?\n                    .context(error::ListedMetaNotPresentSnafu {\n                        meta_key: meta_key.name(),\n                        data_key: data_key.name(),\n                    })?;\n\n                // Insert a top-level map entry for the data key if we've found metadata.\n                let data_entry = result.entry(data_key.clone()).or_insert_with(HashMap::new);\n\n                data_entry.insert(meta_key, value);\n            }\n        }\n        Ok(result)\n    }\n}\n\n/////\n\n// This section ties together serialization and deserialization of scalar values, so it's in the\n// parent module of serialization and deserialization.\n\n/// Concrete error type for scalar ser/de.\npub type ScalarError = serde_json::Error;\n\n/// Serialize a given scalar value to the module-standard serialization format.\npub fn serialize_scalar<S, E>(scalar: &S) -> std::result::Result<String, E>\nwhere\n    S: Serialize,\n    E: From<ScalarError>,\n{\n    serde_json::to_string(scalar).map_err(Into::into)\n}\n\n/// Deserialize a given scalar value from the module-standard serialization format.\npub fn deserialize_scalar<'de, D, E>(scalar: &'de str) -> std::result::Result<D, E>\nwhere\n    D: Deserialize<'de>,\n    E: From<ScalarError>,\n{\n    serde_json::from_str(scalar).map_err(Into::into)\n}\n\n/// Serde Deserializer type matching the deserialize_scalar implementation.\ntype ScalarDeserializer<'de> = serde_json::Deserializer<serde_json::de::StrRead<'de>>;\n\n/// Constructor for ScalarDeserializer.\nfn deserializer_for_scalar(scalar: &str) -> ScalarDeserializer<'_> {\n    serde_json::Deserializer::from_str(scalar)\n}\n\n/// Serde generic \"Value\" type representing a tree of deserialized values.  Should be able to hold\n/// anything returned by the deserialization bits above.\npub type Value = serde_json::Value;\n\n#[cfg(test)]\nmod test {\n    use super::memory::MemoryDataStore;\n    use super::{Committed, DataStore, Key, KeyType};\n    use maplit::{hashmap, hashset};\n\n    #[test]\n    fn set_unset_keys() {\n        let mut m = MemoryDataStore::new();\n\n        let k1 = Key::new(KeyType::Data, \"memtest1\").unwrap();\n        let k2 = Key::new(KeyType::Data, \"memtest2\").unwrap();\n        let k3 = Key::new(KeyType::Data, \"memtest3\").unwrap();\n        let v1 = \"memvalue1\".to_string();\n        let v2 = \"memvalue2\".to_string();\n        let v3 = \"memvalue3\".to_string();\n        let data = hashmap!(\n            k1.clone() => &v1,\n            k2.clone() => &v2,\n            k3.clone() => &v3,\n        );\n\n        let tx = \"test transaction\";\n        let pending = Committed::Pending { tx: tx.into() };\n        m.set_keys(&data, &pending).unwrap();\n\n        assert_eq!(m.get_key(&k1, &pending).unwrap(), Some(v1));\n        assert_eq!(m.get_key(&k2, &pending).unwrap(), Some(v2));\n        assert_eq!(m.get_key(&k3, &pending).unwrap(), Some(v3.clone()));\n\n        let unset = hashset!(k1.clone(), k2.clone());\n        m.unset_keys(&unset, &pending).unwrap();\n\n        assert_eq!(m.get_key(&k1, &pending).unwrap(), None);\n        assert_eq!(m.get_key(&k2, &pending).unwrap(), None);\n        assert_eq!(m.get_key(&k3, &pending).unwrap(), Some(v3));\n    }\n\n    #[test]\n    fn get_metadata_inheritance() {\n        let mut m = MemoryDataStore::new();\n\n        let meta = Key::new(KeyType::Meta, \"mymeta\").unwrap();\n        let parent = Key::new(KeyType::Data, \"a\").unwrap();\n        let grandchild = Key::new(KeyType::Data, \"a.b.c\").unwrap();\n\n        // Set metadata on parent\n        m.set_metadata(&meta, &parent, \"value\", &Committed::Live)\n            .unwrap();\n        // Metadata shows up on grandchild...\n        assert_eq!(\n            m.get_metadata(&meta, &grandchild, &Committed::Live)\n                .unwrap(),\n            Some(\"value\".to_string())\n        );\n        // ...but only through inheritance, not directly.\n        assert_eq!(\n            m.get_metadata_raw(&meta, &grandchild, &Committed::Live)\n                .unwrap(),\n            None\n        );\n    }\n\n    #[test]\n    fn get_prefix() {\n        let mut m = MemoryDataStore::new();\n        let data = hashmap!(\n            Key::new(KeyType::Data, \"x.1\").unwrap() => \"x1\".to_string(),\n            Key::new(KeyType::Data, \"x.2\").unwrap() => \"x2\".to_string(),\n            Key::new(KeyType::Data, \"y.3\").unwrap() => \"y3\".to_string(),\n        );\n        let tx = \"test transaction\";\n        let pending = Committed::Pending { tx: tx.into() };\n        m.set_keys(&data, &pending).unwrap();\n\n        assert_eq!(\n            m.get_prefix(\"x.\", &pending).unwrap(),\n            hashmap!(Key::new(KeyType::Data, \"x.1\").unwrap() => \"x1\".to_string(),\n                     Key::new(KeyType::Data, \"x.2\").unwrap() => \"x2\".to_string())\n        );\n    }\n\n    #[test]\n    fn get_metadata_prefix() {\n        let mut m = MemoryDataStore::new();\n\n        // Build some data keys to which we can attach metadata; they don't actually have to be\n        // set in the data store.\n        let k1 = Key::new(KeyType::Data, \"x.1\").unwrap();\n        let k2 = Key::new(KeyType::Data, \"x.2\").unwrap();\n        let k3 = Key::new(KeyType::Data, \"y.3\").unwrap();\n\n        // Set some metadata to check\n        let mk1 = Key::new(KeyType::Meta, \"metatest1\").unwrap();\n        let mk2 = Key::new(KeyType::Meta, \"metatest2\").unwrap();\n        let mk3 = Key::new(KeyType::Meta, \"metatest3\").unwrap();\n        m.set_metadata(&mk1, &k1, \"41\", &Committed::Live).unwrap();\n        m.set_metadata(&mk2, &k2, \"42\", &Committed::Live).unwrap();\n        m.set_metadata(&mk3, &k3, \"43\", &Committed::Live).unwrap();\n\n        // Check all metadata\n        assert_eq!(\n            m.get_metadata_prefix(\"x.\", &Committed::Live, &None as &Option<&str>)\n                .unwrap(),\n            hashmap!(k1 => hashmap!(mk1 => \"41\".to_string()),\n                     k2.clone() => hashmap!(mk2.clone() => \"42\".to_string()))\n        );\n\n        // Check metadata matching a given name\n        assert_eq!(\n            m.get_metadata_prefix(\"x.\", &Committed::Live, &Some(\"metatest2\"))\n                .unwrap(),\n            hashmap!(k2 => hashmap!(mk2 => \"42\".to_string()))\n        );\n    }\n\n    #[test]\n    fn get_metadata_prefix_from_pending() {\n        let mut m = MemoryDataStore::new();\n\n        // Build some data keys to which we can attach metadata; they don't actually have to be\n        // set in the data store.\n        let k1 = Key::new(KeyType::Data, \"x.1\").unwrap();\n        let k2 = Key::new(KeyType::Data, \"x.2\").unwrap();\n        let k3 = Key::new(KeyType::Data, \"y.3\").unwrap();\n\n        // Set some metadata to check\n        let mk1 = Key::new(KeyType::Meta, \"metatest1\").unwrap();\n        let mk2 = Key::new(KeyType::Meta, \"metatest2\").unwrap();\n        let mk3 = Key::new(KeyType::Meta, \"metatest3\").unwrap();\n        m.set_metadata(\n            &mk1,\n            &k1,\n            \"41\",\n            &Committed::Pending {\n                tx: \"test\".to_owned(),\n            },\n        )\n        .unwrap();\n        m.set_metadata(\n            &mk2,\n            &k2,\n            \"42\",\n            &Committed::Pending {\n                tx: \"test\".to_owned(),\n            },\n        )\n        .unwrap();\n        m.set_metadata(\n            &mk3,\n            &k3,\n            \"43\",\n            &Committed::Pending {\n                tx: \"test\".to_owned(),\n            },\n        )\n        .unwrap();\n\n        // Check all metadata\n        assert_eq!(\n            m.get_metadata_prefix(\n                \"x.\",\n                &Committed::Pending {\n                    tx: \"test\".to_owned()\n                },\n                &None as &Option<&str>\n            )\n            .unwrap(),\n            hashmap!(k1 => hashmap!(mk1 => \"41\".to_string()),\n                     k2.clone() => hashmap!(mk2.clone() => \"42\".to_string()))\n        );\n\n        // Check metadata matching a given name\n        assert_eq!(\n            m.get_metadata_prefix(\n                \"x.\",\n                &Committed::Pending {\n                    tx: \"test\".to_owned()\n                },\n                &Some(\"metatest2\")\n            )\n            .unwrap(),\n            hashmap!(k2 => hashmap!(mk2 => \"42\".to_string()))\n        );\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/memory.rs",
    "content": "//! In-memory datastore for use in testing other modules.\n//!\n//! Mimics some of the decisions made for FilesystemDataStore, e.g. metadata being committed\n//! immediately.\n\nuse std::collections::{HashMap, HashSet};\n\nuse crate::constraints_check::{ApprovedWrite, ConstraintCheckResult};\n\nuse super::{Committed, DataStore, Key, Result};\n\n#[derive(Debug, Default)]\npub struct MemoryDataStore {\n    // Transaction name -> (key -> data)\n    pending: HashMap<String, HashMap<Key, String>>,\n    // Committed (live) data.\n    live: HashMap<Key, String>,\n    // Map of data keys to their metadata, which in turn is a mapping of metadata keys to\n    // arbitrary (string/serialized) values.\n    metadata: HashMap<Key, HashMap<Key, String>>,\n    // Map of data keys to their metadata, which in turn is a mapping of metadata keys to\n    // arbitrary (string/serialized) values in pending transaction\n    pending_metadata: HashMap<Key, HashMap<Key, String>>,\n}\n\nimpl MemoryDataStore {\n    pub fn new() -> Self {\n        Default::default()\n    }\n\n    fn dataset(&self, committed: &Committed) -> Option<&HashMap<Key, String>> {\n        match committed {\n            Committed::Live => Some(&self.live),\n            Committed::Pending { tx } => self.pending.get(tx),\n        }\n    }\n\n    fn dataset_mut(&mut self, committed: &Committed) -> &mut HashMap<Key, String> {\n        match committed {\n            Committed::Live => &mut self.live,\n            Committed::Pending { tx } => self.pending.entry(tx.clone()).or_default(),\n        }\n    }\n}\n\nimpl DataStore for MemoryDataStore {\n    fn list_populated_keys<S: AsRef<str>>(\n        &self,\n        prefix: S,\n        committed: &Committed,\n    ) -> Result<HashSet<Key>> {\n        let empty = HashMap::new();\n        let dataset = self.dataset(committed).unwrap_or(&empty);\n        Ok(dataset\n            .keys()\n            // Make sure the data keys start with the given prefix.\n            .filter(|k| k.name().starts_with(prefix.as_ref()))\n            .cloned()\n            .collect())\n    }\n\n    fn list_populated_metadata<S1, S2>(\n        &self,\n        prefix: S1,\n        committed: &Committed,\n        metadata_key_name: &Option<S2>,\n    ) -> Result<HashMap<Key, HashSet<Key>>>\n    where\n        S1: AsRef<str>,\n        S2: AsRef<str>,\n    {\n        let metadata_to_use = match committed {\n            Committed::Live => &self.metadata,\n            Committed::Pending { .. } => &self.pending_metadata,\n        };\n\n        let mut result = HashMap::new();\n\n        for (data_key, meta_map) in metadata_to_use.iter() {\n            // Confirm data key matches requested prefix.\n            if !data_key.name().starts_with(prefix.as_ref()) {\n                continue;\n            }\n\n            let mut meta_for_data = HashSet::new();\n            for meta_key in meta_map.keys() {\n                // Confirm metadata key matches requested name, if any.\n                if let Some(name) = metadata_key_name {\n                    if name.as_ref() != meta_key.name() {\n                        continue;\n                    }\n                }\n                meta_for_data.insert(meta_key.clone());\n            }\n            // Only add an entry for the data key if we found metadata.\n            if !meta_for_data.is_empty() {\n                result.insert(data_key.clone(), meta_for_data);\n            }\n        }\n\n        Ok(result)\n    }\n\n    fn get_key(&self, key: &Key, committed: &Committed) -> Result<Option<String>> {\n        let empty = HashMap::new();\n        let dataset = self.dataset(committed).unwrap_or(&empty);\n        Ok(dataset.get(key).cloned())\n    }\n\n    fn set_key<S: AsRef<str>>(&mut self, key: &Key, value: S, committed: &Committed) -> Result<()> {\n        self.dataset_mut(committed)\n            .insert(key.clone(), value.as_ref().to_owned());\n        Ok(())\n    }\n\n    fn unset_key(&mut self, key: &Key, committed: &Committed) -> Result<()> {\n        self.dataset_mut(committed).remove(key);\n        Ok(())\n    }\n\n    fn key_populated(&self, key: &Key, committed: &Committed) -> Result<bool> {\n        let empty = HashMap::new();\n        let dataset = self.dataset(committed).unwrap_or(&empty);\n        Ok(dataset.contains_key(key))\n    }\n\n    fn get_metadata_raw(\n        &self,\n        metadata_key: &Key,\n        data_key: &Key,\n        committed: &Committed,\n    ) -> Result<Option<String>> {\n        let metadata_to_use = match committed {\n            Committed::Live => &self.metadata,\n            Committed::Pending { .. } => &self.pending_metadata,\n        };\n\n        let metadata_for_data = metadata_to_use.get(data_key);\n\n        // If we have a metadata entry for this data key, then we can try fetching the requested\n        // metadata key, otherwise we'll return early with Ok(None).\n        let result = metadata_for_data.and_then(|m| m.get(metadata_key));\n        Ok(result.cloned())\n    }\n\n    fn set_metadata<S: AsRef<str>>(\n        &mut self,\n        metadata_key: &Key,\n        data_key: &Key,\n        value: S,\n        committed: &Committed,\n    ) -> Result<()> {\n        match committed {\n            Committed::Live => set_metadata_raw(&mut self.metadata, metadata_key, data_key, value),\n            Committed::Pending { .. } => {\n                set_metadata_raw(&mut self.pending_metadata, metadata_key, data_key, value)\n            }\n        }\n    }\n\n    fn unset_metadata(&mut self, metadata_key: &Key, data_key: &Key) -> Result<()> {\n        // If we have any metadata for this data key, remove the given metadata key.\n        if let Some(metadata_for_data) = self.metadata.get_mut(data_key) {\n            metadata_for_data.remove(metadata_key);\n        }\n        Ok(())\n    }\n\n    fn commit_transaction<S, C>(\n        &mut self,\n        transaction: S,\n        constraint_check: &C,\n    ) -> Result<HashSet<Key>>\n    where\n        S: Into<String> + AsRef<str>,\n        C: Fn(\n            &mut Self,\n            &Committed,\n        ) -> std::result::Result<\n            ConstraintCheckResult,\n            Box<dyn std::error::Error + Send + Sync + 'static>,\n        >,\n    {\n        let tx = transaction.as_ref();\n        let pending = Committed::Pending { tx: tx.into() };\n\n        let constraint_check_result =\n            constraint_check(self, &pending).unwrap_or(ConstraintCheckResult::Reject(\n                \"Check constraint function rejected the transaction. Aborting commit\".to_string(),\n            ));\n        let approved_write = ApprovedWrite::try_from(constraint_check_result)?;\n\n        let mut pending_keys: HashSet<Key> = Default::default();\n        // Remove anything pending for this transaction\n\n        if !approved_write.settings.is_empty() {\n            // Save Keys for return value\n            pending_keys = approved_write.settings.keys().cloned().collect();\n\n            // Apply pending changes to live\n            self.set_keys(&approved_write.settings, &Committed::Live)?;\n        }\n\n        self.pending.remove(tx);\n\n        // Return keys that were committed\n        Ok(pending_keys)\n    }\n\n    fn delete_transaction<S>(&mut self, transaction: S) -> Result<HashSet<Key>>\n    where\n        S: Into<String> + AsRef<str>,\n    {\n        // Remove anything pending for this transaction\n        if let Some(pending) = self.pending.remove(transaction.as_ref()) {\n            // Return the old pending keys\n            Ok(pending.keys().cloned().collect())\n        } else {\n            Ok(HashSet::new())\n        }\n    }\n\n    fn list_transactions(&self) -> Result<HashSet<String>> {\n        Ok(self.pending.keys().cloned().collect())\n    }\n}\n\nfn set_metadata_raw<S: AsRef<str>>(\n    metadata_to_use: &mut HashMap<Key, HashMap<Key, String>>,\n    metadata_key: &Key,\n    data_key: &Key,\n    value: S,\n) -> Result<()> {\n    // If we don't already have a metadata entry for this data key, insert one.\n    let metadata_for_data = metadata_to_use\n        // Clone data key because we want the HashMap key type to be Key, not &Key, and we\n        // can't pass ownership because we only have a reference from our parameters.\n        .entry(data_key.clone())\n        .or_default();\n\n    metadata_for_data.insert(metadata_key.clone(), value.as_ref().to_owned());\n    Ok(())\n}\n\n#[cfg(test)]\nmod test {\n    use std::collections::HashMap;\n\n    use super::super::{Committed, DataStore, Key, KeyType};\n    use super::MemoryDataStore;\n    use crate::constraints_check::{ApprovedWrite, ConstraintCheckResult};\n    use crate::{deserialize_scalar, serialize_scalar, ScalarError};\n    use maplit::hashset;\n\n    fn constraint_check(\n        datastore: &mut MemoryDataStore,\n        committed: &Committed,\n    ) -> super::Result<ConstraintCheckResult, Box<dyn std::error::Error + Send + Sync + 'static>>\n    {\n        let mut transaction_metadata = datastore\n            .get_metadata_prefix(\"settings.\", committed, &None as &Option<&str>)\n            .unwrap();\n\n        let settings_to_commit: HashMap<Key, String> = match committed {\n            Committed::Pending { tx: transaction } => datastore\n                .pending\n                .get(transaction)\n                .unwrap_or(&HashMap::new())\n                .clone(),\n            Committed::Live => HashMap::new(),\n        };\n\n        let mut metadata_to_commit: Vec<(Key, Key, String)> = Vec::new();\n\n        for (key, value) in transaction_metadata.iter_mut() {\n            for (metadata_key, metadata_value) in value {\n                if metadata_key.name() != \"strength\" {\n                    continue;\n                }\n\n                // strength in pending transaction\n                let pending_strength: String =\n                    deserialize_scalar::<_, ScalarError>(&metadata_value.clone()).unwrap();\n                let met_value = serialize_scalar::<_, ScalarError>(&pending_strength).unwrap();\n                metadata_to_commit.push((metadata_key.clone(), key.clone(), met_value));\n            }\n        }\n        let approved_write = ApprovedWrite {\n            settings: settings_to_commit,\n            metadata: metadata_to_commit,\n        };\n\n        Ok(ConstraintCheckResult::from(Some(approved_write)))\n    }\n\n    #[test]\n    fn get_set_unset() {\n        let mut m = MemoryDataStore::new();\n        let k = Key::new(KeyType::Data, \"memtest\").unwrap();\n        let v = \"memvalue\";\n        m.set_key(&k, v, &Committed::Live).unwrap();\n        assert_eq!(\n            m.get_key(&k, &Committed::Live).unwrap(),\n            Some(v.to_string())\n        );\n\n        let mdkey = Key::new(KeyType::Meta, \"testmd\").unwrap();\n        let md = \"mdval\";\n        m.set_metadata(&mdkey, &k, md, &Committed::Live).unwrap();\n        assert_eq!(\n            m.get_metadata_raw(&mdkey, &k, &Committed::Live).unwrap(),\n            Some(md.to_string())\n        );\n\n        m.set_metadata(\n            &mdkey,\n            &k,\n            md,\n            &Committed::Pending {\n                tx: \"test\".to_owned(),\n            },\n        )\n        .unwrap();\n        assert_eq!(\n            m.get_metadata_raw(\n                &mdkey,\n                &k,\n                &Committed::Pending {\n                    tx: \"test\".to_owned()\n                }\n            )\n            .unwrap(),\n            Some(md.to_string())\n        );\n\n        m.unset_metadata(&mdkey, &k).unwrap();\n        assert_eq!(\n            m.get_metadata_raw(&mdkey, &k, &Committed::Live).unwrap(),\n            None\n        );\n\n        m.unset_key(&k, &Committed::Live).unwrap();\n        assert_eq!(m.get_key(&k, &Committed::Live).unwrap(), None);\n    }\n\n    #[test]\n    fn populated() {\n        let mut m = MemoryDataStore::new();\n        let k1 = Key::new(KeyType::Data, \"memtest1\").unwrap();\n        let k2 = Key::new(KeyType::Data, \"memtest2\").unwrap();\n        let v = \"memvalue\";\n        m.set_key(&k1, v, &Committed::Live).unwrap();\n        m.set_key(&k2, v, &Committed::Live).unwrap();\n\n        assert!(m.key_populated(&k1, &Committed::Live).unwrap());\n        assert!(m.key_populated(&k2, &Committed::Live).unwrap());\n        assert_eq!(\n            m.list_populated_keys(\"\", &Committed::Live).unwrap(),\n            hashset!(k1, k2),\n        );\n\n        let bad_key = Key::new(KeyType::Data, \"memtest3\").unwrap();\n        assert!(!m.key_populated(&bad_key, &Committed::Live).unwrap());\n    }\n\n    #[test]\n    fn commit() {\n        let mut m = MemoryDataStore::new();\n        let k = Key::new(KeyType::Data, \"settings.a.b.c\").unwrap();\n        let v = \"memvalue\";\n        let tx = \"test transaction\";\n        let pending = Committed::Pending { tx: tx.into() };\n        m.set_key(&k, v, &pending).unwrap();\n\n        assert!(m.key_populated(&k, &pending).unwrap());\n        assert!(!m.key_populated(&k, &Committed::Live).unwrap());\n        m.commit_transaction(tx, &constraint_check).unwrap();\n        assert!(!m.key_populated(&k, &pending).unwrap());\n        assert!(m.key_populated(&k, &Committed::Live).unwrap());\n    }\n\n    #[test]\n    fn delete_transaction() {\n        let mut m = MemoryDataStore::new();\n        let k = Key::new(KeyType::Data, \"settings.a.b.c\").unwrap();\n        let v = \"memvalue\";\n        let tx = \"test transaction\";\n        let pending = Committed::Pending { tx: tx.into() };\n        m.set_key(&k, v, &pending).unwrap();\n\n        // Set something in a different transaction to ensure it doesn't get deleted\n        let k2 = Key::new(KeyType::Data, \"settings.x.y.z\").unwrap();\n        let v2 = \"memvalue 2\";\n        let tx2 = \"test transaction 2\";\n        let pending2 = Committed::Pending { tx: tx2.into() };\n        m.set_key(&k2, v2, &pending2).unwrap();\n\n        assert!(m.key_populated(&k, &pending).unwrap());\n        assert!(!m.key_populated(&k, &Committed::Live).unwrap());\n        m.delete_transaction(tx).unwrap();\n        assert!(!m.key_populated(&k, &pending).unwrap());\n        assert!(!m.key_populated(&k, &Committed::Live).unwrap());\n\n        // Assure other transactions were not deleted\n        assert!(m.key_populated(&k2, &pending2).unwrap());\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/serialization/error.rs",
    "content": "use serde::ser;\nuse snafu::{IntoError, NoneError as NoSource, Snafu};\n\nuse crate::ScalarError;\n\n/// Potential errors from serialization.\n#[derive(Debug, Snafu)]\n#[snafu(visibility(pub))]\npub enum Error {\n    // This error variant is required to implement ser::Error for serde.\n    #[snafu(display(\"Error during serialization: {}\", msg))]\n    Message { msg: String },\n\n    #[snafu(display(\"Serializer logic error: {}\", msg))]\n    Internal { msg: String },\n\n    #[snafu(display(\"Error creating valid datastore key: {}\", msg))]\n    InvalidKey {\n        // \"msg\" instead of just key name because we want to include the data store error\n        // message, but can't have it as a \"source\" because that'd be circular\n        msg: String,\n    },\n\n    #[snafu(display(\"Tried to output concrete value without prefix; value: {}\", value))]\n    MissingPrefix { value: String },\n\n    #[snafu(display(\"Error serializing {}: {} \", given, source))]\n    Serialization { given: String, source: ScalarError },\n\n    #[snafu(display(\"Error deserializing {}: {} \", given, source))]\n    Deserialization { given: String, source: ScalarError },\n\n    #[snafu(display(\"'{}' not allowed by Serializer\", typename))]\n    InvalidType { typename: String },\n\n    #[snafu(display(\"'{}' not allowed as map key\", typename))]\n    BadMapKey { typename: String },\n}\n\npub type Result<T> = std::result::Result<T, Error>;\n\nimpl ser::Error for Error {\n    fn custom<T: std::fmt::Display>(msg: T) -> Self {\n        MessageSnafu {\n            msg: msg.to_string(),\n        }\n        .into_error(NoSource)\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/serialization/mod.rs",
    "content": "//! The serialization module implements generic serialization techniques that are particularly\n//! useful for turning Rust structures into simpler types that are easy to write to a datastore.\n\nmod error;\nmod pairs;\n\npub use error::{Error, Result};\npub use pairs::{to_pairs, to_pairs_with_prefix};\n\nuse log::{debug, trace};\nuse serde::{ser, Serialize};\nuse snafu::{IntoError, NoneError as NoSource};\n\nuse crate::{Key, KeyType};\n\n// Below are serializers not specific to the pairs module that could be used for other serializers.\n// For example, a 'keys' serializer that just returns a set of keys, without associated data.\n\n/// We use this in serialize_key to ensure map keys are only strings, for easy interoperability\n/// with TOML/JSON.\n///\n/// We also ensure map keys are valid datastore keys.\nstruct MapKeySerializer {}\n\nimpl MapKeySerializer {\n    fn new() -> Self {\n        Self {}\n    }\n}\n\n/// Most types are invalid map keys (only strings are OK) so we need to return an error in most\n/// cases.  This simplifies the creation of that error, with a customizable message for the type.\nfn bad_key<T>(typename: &str) -> Result<T> {\n    error::BadMapKeySnafu { typename }.fail()\n}\n\nimpl ser::Serializer for &MapKeySerializer {\n    type Ok = String;\n    type Error = Error;\n\n    type SerializeSeq = ser::Impossible<String, Error>;\n    type SerializeTuple = ser::Impossible<String, Error>;\n    type SerializeTupleStruct = ser::Impossible<String, Error>;\n    type SerializeTupleVariant = ser::Impossible<String, Error>;\n    type SerializeMap = ser::Impossible<String, Error>;\n    type SerializeStruct = ser::Impossible<String, Error>;\n    type SerializeStructVariant = ser::Impossible<String, Error>;\n\n    // Allow serialization of strings for map keys, but nothing else.\n\n    fn serialize_str(self, value: &str) -> Result<String> {\n        // Make sure string is valid as a key.\n        let key = Key::from_segments(KeyType::Data, &[value]).map_err(|e| {\n            debug!(\"MapKeySerializer got invalid key name: {value}\");\n            error::InvalidKeySnafu {\n                msg: format!(\"{e}\"),\n            }\n            .into_error(NoSource)\n        })?;\n        trace!(\"MapKeySerializer got OK key: {key}\");\n        Ok(key.to_string())\n    }\n\n    fn serialize_bool(self, _value: bool) -> Result<String> {\n        bad_key(\"bool\")\n    }\n\n    fn serialize_i8(self, _value: i8) -> Result<String> {\n        bad_key(\"i8\")\n    }\n\n    fn serialize_i16(self, _value: i16) -> Result<String> {\n        bad_key(\"i16\")\n    }\n\n    fn serialize_i32(self, _value: i32) -> Result<String> {\n        bad_key(\"i32\")\n    }\n\n    fn serialize_i64(self, _value: i64) -> Result<String> {\n        bad_key(\"i64\")\n    }\n\n    fn serialize_u8(self, _value: u8) -> Result<String> {\n        bad_key(\"u8\")\n    }\n\n    fn serialize_u16(self, _value: u16) -> Result<String> {\n        bad_key(\"u16\")\n    }\n\n    fn serialize_u32(self, _value: u32) -> Result<String> {\n        bad_key(\"u32\")\n    }\n\n    fn serialize_u64(self, _value: u64) -> Result<String> {\n        bad_key(\"u64\")\n    }\n\n    fn serialize_f32(self, _value: f32) -> Result<String> {\n        bad_key(\"f32\")\n    }\n\n    fn serialize_f64(self, _value: f64) -> Result<String> {\n        bad_key(\"f64\")\n    }\n\n    fn serialize_char(self, _value: char) -> Result<String> {\n        bad_key(\"char\")\n    }\n\n    fn serialize_bytes(self, _value: &[u8]) -> Result<String> {\n        bad_key(\"bytes\")\n    }\n\n    fn serialize_unit(self) -> Result<String> {\n        bad_key(\"unit\")\n    }\n\n    fn serialize_unit_struct(self, _name: &'static str) -> Result<String> {\n        bad_key(\"unit_struct\")\n    }\n\n    /// A simple enum can be used as if it were a string, so we allow these to serve as map keys.\n    fn serialize_unit_variant(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        variant: &'static str,\n    ) -> Result<String> {\n        self.serialize_str(variant)\n    }\n\n    fn serialize_newtype_struct<T>(self, _name: &'static str, _value: &T) -> Result<String>\n    where\n        T: ?Sized + Serialize,\n    {\n        bad_key(\"newtype_struct\")\n    }\n\n    fn serialize_newtype_variant<T>(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        _variant: &'static str,\n        _value: &T,\n    ) -> Result<String>\n    where\n        T: ?Sized + Serialize,\n    {\n        bad_key(\"newtype_variant\")\n    }\n\n    fn serialize_none(self) -> Result<String> {\n        bad_key(\"none\")\n    }\n\n    fn serialize_some<T>(self, _value: &T) -> Result<String>\n    where\n        T: ?Sized + Serialize,\n    {\n        bad_key(\"some\")\n    }\n\n    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {\n        bad_key(\"seq\")\n    }\n\n    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {\n        bad_key(\"tuple\")\n    }\n\n    fn serialize_tuple_struct(\n        self,\n        _name: &'static str,\n        _len: usize,\n    ) -> Result<Self::SerializeTupleStruct> {\n        bad_key(\"tuple struct\")\n    }\n\n    fn serialize_tuple_variant(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        _variant: &'static str,\n        _len: usize,\n    ) -> Result<Self::SerializeTupleVariant> {\n        bad_key(\"tuple variant\")\n    }\n\n    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {\n        bad_key(\"map\")\n    }\n\n    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {\n        bad_key(\"struct\")\n    }\n\n    fn serialize_struct_variant(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        _variant: &'static str,\n        _len: usize,\n    ) -> Result<Self::SerializeStructVariant> {\n        bad_key(\"struct variant\")\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::MapKeySerializer;\n    use serde::Serialize;\n\n    // This enum is fine because its variants are \"simple\", thus it can be represented as a simple\n    // string and can be used as a map key.\n    #[derive(Debug, Serialize)]\n    enum TestEnum {\n        Value,\n    }\n\n    // This enum cannot be used as a map key because it has a variant that can't be serialized as a\n    // simple string.\n    #[derive(Debug, Serialize)]\n    enum BadEnum {\n        Value(i32),\n    }\n\n    #[test]\n    fn ok_key() {\n        let serializer = MapKeySerializer::new();\n        let m = \"A\".to_string();\n        let res = m.serialize(&serializer).unwrap();\n        assert_eq!(res, \"A\");\n    }\n\n    #[test]\n    fn ok_enum_key() {\n        let serializer = MapKeySerializer::new();\n        let m = TestEnum::Value;\n        let res = m.serialize(&serializer).unwrap();\n        assert_eq!(res, \"Value\");\n    }\n\n    #[test]\n    fn bad_keys() {\n        let serializer = MapKeySerializer::new();\n        42u8.serialize(&serializer).unwrap_err();\n        42i32.serialize(&serializer).unwrap_err();\n        true.serialize(&serializer).unwrap_err();\n        'q'.serialize(&serializer).unwrap_err();\n        ().serialize(&serializer).unwrap_err();\n        [1u8].serialize(&serializer).unwrap_err();\n        (None as Option<u8>).serialize(&serializer).unwrap_err();\n        Some(42).serialize(&serializer).unwrap_err();\n        BadEnum::Value(1).serialize(&serializer).unwrap_err();\n    }\n}\n"
  },
  {
    "path": "sources/api/datastore/src/serialization/pairs.rs",
    "content": "//! The goal of this module is to be able to turn serializable structures, primarily the API model,\n//! into a form that can be easily written to our data store, key by key, since we will often\n//! receive arbitrary subsets of the valid keys.  We use serde to help walk through the structure,\n//! and use the Serializer's associated types to keep track of where we are in the tree of nested\n//! structures.\n\n//! The serialization pattern below could be used for other structures as well, but we're starting\n//! out by orienting it toward the API model.  As such, data types are oriented around TOML/JSON\n//! types, to be sure we support the various forms of input/output we care about.\n\nuse log::trace;\nuse serde::{ser, Serialize};\nuse snafu::{IntoError, NoneError as NoSource, OptionExt, ResultExt};\nuse std::collections::HashMap;\n\nuse super::{error, Error, MapKeySerializer, Result};\nuse crate::{serialize_scalar, Key, KeyType, ScalarError};\n\n/// This is the primary interface to our serialization.  We turn anything implementing Serialize\n/// into pairs of datastore keys and serialized values.  For example, a nested struct like this:\n///    Settings -> DockerSettings -> bridge_ip = u64\n/// would turn into a key of \"settings.docker-settings.bridge-ip\" and a serialized String\n/// representing the u64 data.\npub fn to_pairs<T: Serialize>(value: &T) -> Result<HashMap<Key, String>> {\n    let mut output = HashMap::new();\n    let serializer = Serializer::new(&mut output, None);\n    value.serialize(serializer)?;\n    Ok(output)\n}\n\n/// Like to_pairs, but lets you add an arbitrary prefix to the resulting keys.  A separator will\n/// automatically be added after the prefix.\npub fn to_pairs_with_prefix<S, T>(prefix: S, value: &T) -> Result<HashMap<Key, String>>\nwhere\n    S: AsRef<str>,\n    T: Serialize,\n{\n    let prefix = prefix.as_ref();\n    let prefix_key = Key::new(KeyType::Data, prefix).map_err(|e| {\n        error::InvalidKeySnafu {\n            msg: format!(\"Prefix '{prefix}' not valid as Key: {e}\"),\n        }\n        .into_error(NoSource)\n    })?;\n\n    let mut output = HashMap::new();\n    let serializer = Serializer::new(&mut output, Some(prefix_key));\n    value.serialize(serializer)?;\n    Ok(output)\n}\n\n/////\n\n/// Serializer does most of the work by recursively serializing compound structures, and trivially\n/// serializing scalars.\n///\n/// Caveat: for a list/tuple, the elements inside only have indexes, which doesn't work well with\n/// the data store.  Lists are common enough that we need some answer, so we say that lists can\n/// only contain scalars, not further compound objects.  That way we can serialize the list\n/// directly (see FlatSerializer) rather than as a compound.\n///\n/// (We could handle lists as proper compound structures by improving the data store such that it\n/// can store unnamed sub-components, perhaps by using a visible index (\"a.b.c[0]\", \"a.b.c[1]\").\n/// It's more common to use a HashMap in the model, and then to use named keys instead of indexes,\n/// which works fine.)\nstruct Serializer<'a> {\n    output: &'a mut HashMap<Key, String>,\n    prefix: Option<Key>,\n    // This is temporary storage for serializing maps, because serde gives us keys and values\n    // separately.  See the SerializeMap implementation below.\n    key: Option<Key>,\n}\n\nimpl<'a> Serializer<'a> {\n    fn new(output: &'a mut HashMap<Key, String>, prefix: Option<Key>) -> Self {\n        Self {\n            output,\n            prefix,\n            key: None,\n        }\n    }\n}\n\n/// This helps us handle the cases where we have to have an existing prefix in order to output a\n/// value.  It creates an explanatory error if the given prefix is None.\nfn expect_prefix(maybe_prefix: Option<Key>, value: &str) -> Result<Key> {\n    maybe_prefix.context(error::MissingPrefixSnafu { value })\n}\n\n/// Serializes a concrete value and saves it to the output, assuming we have a prefix.\nmacro_rules! concrete_output {\n    ($self:expr, $value:expr) => {\n        trace!(\"Serializing scalar at prefix {:?}\", $self.prefix);\n        let value = serialize_scalar::<_, ScalarError>(&$value).with_context(|_| {\n            error::SerializationSnafu {\n                given: format!(\"concrete value '{}'\", $value),\n            }\n        })?;\n        let prefix = expect_prefix($self.prefix, &value)?;\n        $self.output.insert(prefix, value);\n        return Ok(());\n    };\n}\n\n/// Several types are invalid for our serialization so we commonly need to return an error.  This\n/// simplifies the creation of that error, with a customizable message for the type.\nfn bad_type<T>(typename: &str) -> Result<T> {\n    error::InvalidTypeSnafu { typename }.fail()\n}\n\nimpl<'a> ser::Serializer for Serializer<'a> {\n    type Ok = ();\n    type Error = Error;\n\n    // See the docs on Serializer for reasoning about this.\n    type SerializeSeq = FlatSerializer<'a>;\n    type SerializeTuple = ser::Impossible<(), Error>;\n    type SerializeTupleStruct = ser::Impossible<(), Error>;\n    type SerializeTupleVariant = ser::Impossible<(), Error>;\n    type SerializeStructVariant = ser::Impossible<(), Error>;\n    type SerializeMap = Self;\n    type SerializeStruct = Self;\n\n    // Simple concrete types.\n    fn serialize_bool(self, v: bool) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_i8(self, v: i8) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_i16(self, v: i16) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_i32(self, v: i32) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_i64(self, v: i64) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_u8(self, v: u8) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_u16(self, v: u16) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_u32(self, v: u32) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_u64(self, v: u64) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_f32(self, v: f32) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_f64(self, v: f64) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    fn serialize_str(self, v: &str) -> Result<()> {\n        concrete_output!(self, v);\n    }\n\n    // Don't serialize None at all; it should mean the key wasn't given.\n    fn serialize_none(self) -> Result<()> {\n        Ok(())\n    }\n\n    // Serialize the Some(x) as x.  Our basic structure is that all settings are optional, so\n    // the API is ergonomic to call with a subset of keys, and so Some just means they wanted this\n    // key set.\n    fn serialize_some<T>(self, value: &T) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        value.serialize(self)\n    }\n\n    // Compound types\n    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {\n        Ok(FlatSerializer::new(\n            self.output,\n            expect_prefix(self.prefix, \"seq\")?,\n        ))\n    }\n\n    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {\n        Ok(Serializer::new(self.output, self.prefix))\n    }\n\n    fn serialize_struct(self, name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {\n        trace!(\"Serializing struct '{}' at prefix {:?}\", name, self.prefix);\n        // If we already have a prefix, use it - could be because we're in a nested struct, or the\n        // user gave a prefix.  Otherwise, use the given name - this is a top-level struct.\n        let prefix = match self.prefix {\n            p @ Some(_) => p,\n            None => {\n                trace!(\"Had no prefix, starting with struct name: {name}\");\n                let key = Key::from_segments(KeyType::Data, &[&name]).map_err(|e| {\n                    error::InvalidKeySnafu {\n                        msg: format!(\"struct '{name}' not valid as Key: {e}\"),\n                    }\n                    .into_error(NoSource)\n                })?;\n                Some(key)\n            }\n        };\n        Ok(Serializer::new(self.output, prefix))\n    }\n\n    // Types we can't (or don't want to) represent.\n    // No char type, and using String would lose the distinction you were trying to make by\n    // using a char.\n    fn serialize_char(self, _v: char) -> Result<()> {\n        bad_type(\"char\")\n    }\n\n    // No binary type; could use base64 or similar if we implement our own deserialization\n    // that understands it.\n    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {\n        bad_type(\"bytes\")\n    }\n\n    // We just don't expect to need these, and we doesn't have a great way to represent them.\n    fn serialize_unit(self) -> Result<()> {\n        bad_type(\"unit\")\n    }\n\n    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {\n        bad_type(\"unit struct\")\n    }\n\n    // When we use \"simple\" enums (those that only have \"unit\" variants), we represent them as\n    // strings in the data model. As far as the API is concerned, these are string values, but in\n    // the model we constrain them using an enum.\n    fn serialize_unit_variant(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        variant: &'static str,\n    ) -> Result<()> {\n        self.serialize_str(variant)\n    }\n\n    fn serialize_newtype_struct<T>(self, _name: &'static str, _value: &T) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        bad_type(\"newtype struct\")\n    }\n    fn serialize_newtype_variant<T>(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        _variant: &'static str,\n        _value: &T,\n    ) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        bad_type(\"newtype variant\")\n    }\n\n    // We don't expect to need tuples, and we don't have a great way to represent them,\n    // distinct from lists.\n    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {\n        bad_type(\"tuple\")\n    }\n\n    fn serialize_tuple_struct(\n        self,\n        _name: &'static str,\n        _len: usize,\n    ) -> Result<Self::SerializeTupleStruct> {\n        bad_type(\"tuple struct\")\n    }\n\n    fn serialize_tuple_variant(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        _variant: &'static str,\n        _len: usize,\n    ) -> Result<Self::SerializeTupleVariant> {\n        bad_type(\"tuple variant\")\n    }\n\n    fn serialize_struct_variant(\n        self,\n        _name: &'static str,\n        _variant_index: u32,\n        _variant: &'static str,\n        _len: usize,\n    ) -> Result<Self::SerializeStructVariant> {\n        bad_type(\"struct variant\")\n    }\n}\n\n/// Helper that combines the existing prefix, if any, with a separator and the new key.\nfn key_append_or_create(old_prefix: &Option<Key>, key: &Key) -> Result<Key> {\n    if let Some(old_prefix) = old_prefix {\n        old_prefix.append_key(key).map_err(|e| {\n            error::InvalidKeySnafu {\n                msg: format!(\"appending '{key}' to '{old_prefix}' is invalid as Key: {e}\"),\n            }\n            .into_error(NoSource)\n        })\n    } else {\n        Ok(key.clone())\n    }\n}\n\n/// Serialize map structures, recursively handling any inner compound structures by using the key\n/// name as the new prefix.\n///\n/// Two important notes here.\n///\n/// First, we can only allow map keys to be strings, for easy interoperability with TOML/JSON.\n/// We delegate to the MapKeySerializer to handle that.\n///\n/// Second, serde is limited in the sense that it requires you to serialize keys and values\n/// separately, whereas we'd prefer a single pass because we only need to store the output.  To\n/// work around this, we use the Option 'key' in the struct to store the last-serialized key,\n/// knowing that serde will serialize keys and values in that order.\nimpl ser::SerializeMap for Serializer<'_> {\n    type Ok = ();\n    type Error = Error;\n\n    fn serialize_key<T>(&mut self, key: &T) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        trace!(\"Serializing map key at prefix {:?}\", self.prefix);\n        // We're given a serializable thing; need to serialize it to get a string we can work with.\n        let key_str = key.serialize(&MapKeySerializer::new())?;\n        // It should be valid as a Key.\n        // Note: we use 'new', not 'from_segments', because we just serialized into a string,\n        // meaning it's in quoted form.\n        let key = Key::new(KeyType::Data, &key_str).map_err(|e| {\n            error::InvalidKeySnafu {\n                msg: format!(\"serialized map key '{}' not valid as Key: {}\", &key_str, e),\n            }\n            .into_error(NoSource)\n        })?;\n        // Store the key to use later in serialize_value.\n        self.key = Some(key_append_or_create(&self.prefix, &key)?);\n        Ok(())\n    }\n\n    fn serialize_value<T>(&mut self, value: &T) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        // Pull out the stored key and serialize whatever's in the value using the key as its name\n        // prefix.\n        match self.key.take() {\n            Some(key) => {\n                trace!(\n                    \"Recursively serializing map value at prefix {:?}\",\n                    self.prefix\n                );\n                value.serialize(Serializer::new(self.output, Some(key)))\n            }\n            None => error::InternalSnafu {\n                msg: \"Attempted to serialize value without key\",\n            }\n            .fail(),\n        }\n    }\n\n    // No need to \"end\" the structure, we're not serializing to a single text format.\n    fn end(self) -> Result<()> {\n        Ok(())\n    }\n}\n\n/// Serialize structs, recursively handling any inner compound structures by using the key name as\n/// the new prefix.  (No need to use the struct's name; we're not at the root level, so it was\n/// already pointed to by some name.)\nimpl ser::SerializeStruct for Serializer<'_> {\n    type Ok = ();\n    type Error = Error;\n\n    fn serialize_field<T>(&mut self, key_str: &'static str, value: &T) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        let key = Key::from_segments(KeyType::Data, &[&key_str]).map_err(|e| {\n            error::InvalidKeySnafu {\n                msg: format!(\"struct field '{key_str}' not valid as Key: {e}\"),\n            }\n            .into_error(NoSource)\n        })?;\n\n        let new_root = key_append_or_create(&self.prefix, &key)?;\n        trace!(\n            \"Recursively serializing struct with new root '{}' from prefix '{:?}' and key '{}'\",\n            new_root,\n            self.prefix,\n            &key\n        );\n        value.serialize(Serializer::new(self.output, Some(new_root)))\n    }\n\n    fn end(self) -> Result<()> {\n        Ok(())\n    }\n}\n\n/////\n\n/// This serializes compound structures into a flat blob, for cases where recursively serializing\n/// compound structures doesn't make sense.  See Serializer for detail on why it uses this.\n///\n/// Warning; this requires hacks.  serde gives you three callbacks during serialization - starting\n/// the structure, for each element, and ending the structure.  There's no option to handle an\n/// entire structure at once, which is exactly what we'd want.  We can't clone the elements, since\n/// we only have a Serialize bound, and I couldn't figure out how to store the references, so we do\n/// the unthinkable - serialize each element to a String, store those in a list during the\n/// serialization steps, and then at the end, deserialize the strings back into a list of the\n/// original type, and serialize the entire list.  Sorry.\nstruct FlatSerializer<'a> {\n    output: &'a mut HashMap<Key, String>,\n    prefix: Key,\n    list: Vec<String>,\n}\n\nimpl<'a> FlatSerializer<'a> {\n    fn new(output: &'a mut HashMap<Key, String>, prefix: Key) -> Self {\n        FlatSerializer {\n            output,\n            prefix,\n            list: Vec::new(),\n        }\n    }\n}\n\nimpl ser::SerializeSeq for FlatSerializer<'_> {\n    type Ok = ();\n    type Error = Error;\n\n    fn serialize_element<T>(&mut self, value: &T) -> Result<()>\n    where\n        T: ?Sized + Serialize,\n    {\n        trace!(\"Serializing element of list\");\n        self.list.push(\n            serde_json::to_string(value).context(error::SerializationSnafu {\n                given: \"list element\",\n            })?,\n        );\n        Ok(())\n    }\n\n    fn end(self) -> Result<()> {\n        let mut originals: Vec<serde_json::Value> = Vec::new();\n        trace!(\"Deserializing elements of list\");\n        for original in self.list {\n            originals.push(original.parse().context(error::DeserializationSnafu {\n                given: \"list element\",\n            })?);\n        }\n\n        trace!(\"Serializing list\");\n        self.output.insert(\n            self.prefix,\n            serde_json::to_string(&originals)\n                .context(error::SerializationSnafu { given: \"list\" })?,\n        );\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::{to_pairs, to_pairs_with_prefix};\n    use crate::{Key, KeyType};\n    use maplit::hashmap;\n    use serde::Serialize;\n\n    // Helper macro for making a data Key for testing whose name we know is valid.\n    macro_rules! key {\n        ($name:expr) => {\n            Key::new(KeyType::Data, $name).unwrap()\n        };\n    }\n\n    #[derive(PartialEq, Serialize)]\n    struct A {\n        id: u8,\n        b: Option<B>,\n    }\n\n    #[derive(PartialEq, Serialize)]\n    struct B {\n        list: Vec<u8>,\n        boolean: bool,\n    }\n\n    #[test]\n    fn basic_struct_keys() {\n        let b = B {\n            list: vec![3, 4, 5],\n            boolean: true,\n        };\n        let keys = to_pairs(&b).unwrap();\n        assert_eq!(\n            keys,\n            hashmap!(\n                key!(\"B.list\") => \"[3,4,5]\".to_string(),\n                key!(\"B.boolean\") => \"true\".to_string(),\n            )\n        );\n    }\n\n    #[test]\n    fn empty_value() {\n        let val: toml::Value = toml::from_str(\"\").unwrap();\n        let keys = to_pairs(&val).unwrap();\n        assert_eq!(keys, hashmap!())\n    }\n\n    #[test]\n    fn nested_struct_keys() {\n        let b = B {\n            list: vec![5, 6, 7],\n            boolean: true,\n        };\n        let a = A { id: 42, b: Some(b) };\n        let keys = to_pairs(&a).unwrap();\n        assert_eq!(\n            keys,\n            hashmap!(\n                key!(\"A.b.list\") => \"[5,6,7]\".to_string(),\n                key!(\"A.b.boolean\") => \"true\".to_string(),\n                key!(\"A.id\") => \"42\".to_string(),\n            )\n        );\n    }\n\n    #[test]\n    fn map() {\n        let m = hashmap!(\n            key!(\"A\") => hashmap!(\n                key!(\"id\") => 42,\n                key!(\"ie\") => 43,\n            ),\n        );\n        let keys = to_pairs_with_prefix(\"map\", &m).unwrap();\n        assert_eq!(\n            keys,\n            hashmap!(\n                key!(\"map.A.id\") => \"42\".to_string(),\n                key!(\"map.A.ie\") => \"43\".to_string(),\n            )\n        );\n    }\n\n    #[test]\n    fn map_no_root() {\n        let m = hashmap!(\n            key!(\"A\") => hashmap!(\n                key!(\"id\") => 42,\n                key!(\"ie\") => 43,\n            ),\n        );\n        let keys = to_pairs(&m).unwrap();\n        assert_eq!(\n            keys,\n            hashmap!(\n                key!(\"A.id\") => \"42\".to_string(),\n                key!(\"A.ie\") => \"43\".to_string(),\n            )\n        );\n    }\n\n    #[test]\n    fn concrete_fails() {\n        let i = 42;\n        to_pairs(&i).unwrap_err();\n    }\n\n    #[test]\n    fn string_values() {\n        let m = hashmap!(\n            key!(\"A\") => hashmap!(\n                key!(\"id\") => \"apples\",\n                key!(\"ie\") => \"oranges\",\n            ),\n        );\n        let keys = to_pairs(&m).unwrap();\n        assert_eq!(\n            keys,\n            hashmap!(\n                key!(\"A.id\") => \"\\\"apples\\\"\".to_string(),\n                key!(\"A.ie\") => \"\\\"oranges\\\"\".to_string(),\n            )\n        );\n    }\n\n    #[derive(Serialize)]\n    #[serde(rename_all = \"kebab-case\")]\n    enum TestEnum {\n        Alpha,\n        Beta,\n    }\n\n    #[test]\n    fn enum_values() {\n        let m = hashmap!(\n            key!(\"A\") => hashmap!(\n                key!(\"id\") => TestEnum::Alpha,\n                key!(\"ie\") => TestEnum::Beta,\n            ),\n        );\n        let keys = to_pairs(&m).unwrap();\n        assert_eq!(\n            keys,\n            hashmap!(\n                key!(\"A.id\") => \"\\\"alpha\\\"\".to_string(),\n                key!(\"A.ie\") => \"\\\"beta\\\"\".to_string(),\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "sources/api/migration/migration-helpers/Cargo.toml",
    "content": "[package]\nname = \"migration-helpers\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nbottlerocket-release.workspace = true\ndatastore.workspace = true\nhandlebars.workspace = true\nmodels.workspace = true\nregex.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nshlex.workspace = true\nsnafu.workspace = true\ntokio = { workspace = true, features = [\"rt-multi-thread\"] }\n\n[dev-dependencies]\nmaplit.workspace = true\n"
  },
  {
    "path": "sources/api/migration/migration-helpers/src/args.rs",
    "content": "//! Helpers for parsing arguments common to migrations.\n\nuse std::env;\nuse std::process;\n\nuse crate::{MigrationType, Result};\n\n/// Stores user-supplied arguments.\npub struct Args {\n    pub source_datastore: String,\n    pub target_datastore: String,\n    pub migration_type: MigrationType,\n}\n\n/// Informs the user about proper usage of the program and exits.\nfn usage() -> ! {\n    let program_name = env::args().next().unwrap_or_else(|| \"program\".to_string());\n    eprintln!(\n        r\"Usage: {program_name}\n            --source-datastore PATH\n            --target-datastore PATH\n            ( --forward | --backward )\"\n    );\n    process::exit(2);\n}\n\n/// Prints a more specific message before exiting through usage().\nfn usage_msg<S: AsRef<str>>(msg: S) -> ! {\n    eprintln!(\"{}\\n\", msg.as_ref());\n    usage();\n}\n\n/// Parses user arguments into an Args structure.\npub(crate) fn parse_args(args: env::Args) -> Result<Args> {\n    let mut migration_type = None;\n    let mut source_datastore = None;\n    let mut target_datastore = None;\n\n    let mut iter = args.skip(1);\n    while let Some(arg) = iter.next() {\n        match arg.as_ref() {\n            \"--source-datastore\" => {\n                source_datastore =\n                    Some(iter.next().unwrap_or_else(|| {\n                        usage_msg(\"Did not give argument to --source-datastore\")\n                    }))\n            }\n\n            \"--target-datastore\" => {\n                target_datastore =\n                    Some(iter.next().unwrap_or_else(|| {\n                        usage_msg(\"Did not give argument to --target-datastore\")\n                    }))\n            }\n\n            \"--forward\" => migration_type = Some(MigrationType::Forward),\n            \"--backward\" => migration_type = Some(MigrationType::Backward),\n\n            _ => usage(),\n        }\n    }\n\n    // In no other case should they be the same; we use it for compatibility checks.\n    if source_datastore == target_datastore {\n        usage_msg(\"--source-datastore and --target-datastore cannot be the same\");\n    }\n\n    Ok(Args {\n        source_datastore: source_datastore.unwrap_or_else(|| usage()),\n        target_datastore: target_datastore.unwrap_or_else(|| usage()),\n        migration_type: migration_type.unwrap_or_else(|| usage()),\n    })\n}\n"
  },
  {
    "path": "sources/api/migration/migration-helpers/src/common_migrations.rs",
    "content": "use crate::{error, Migration, MigrationData, Result};\nuse regex::Regex;\nuse snafu::{OptionExt, ResultExt};\n\n/// We use this migration when we add settings and want to make sure they're removed before we go\n/// back to old versions that don't understand them.\npub struct AddSettingsMigration<'a>(pub &'a [&'static str]);\n\nimpl Migration for AddSettingsMigration<'_> {\n    /// New versions must either have a default for the settings or generate them; we don't need to\n    /// do anything.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\n            \"AddSettingsMigration({:?}) has no work to do on upgrade.\",\n            self.0\n        );\n        Ok(input)\n    }\n\n    /// Older versions don't know about the settings; we remove them so that old versions don't see\n    /// them and fail deserialization.  (The settings must be defaulted or generated in new versions,\n    /// and safe to remove.)\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for setting in self.0 {\n            if let Some(data) = input.data.remove(*setting) {\n                println!(\"Removed {setting}, which was set to '{data}'\");\n            } else {\n                println!(\"Found no {setting} to remove\");\n            }\n        }\n        Ok(input)\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// We use this migration when we add a cluster of settings under known prefixes and want to make\n/// sure they're removed before we go back to old versions that don't understand them.  Normally\n/// you'd use AddSettingsMigration since you know the key names, but this is useful for\n/// user-defined keys, for example in a map like settings.kernel.sysctl or\n/// settings.host-containers.\npub struct AddPrefixesMigration(pub Vec<&'static str>);\n\nimpl Migration for AddPrefixesMigration {\n    /// New versions must either have a default for the settings or generate them; we don't need to\n    /// do anything.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\n            \"AddPrefixesMigration({:?}) has no work to do on upgrade.\",\n            self.0\n        );\n        Ok(input)\n    }\n\n    /// Older versions don't know about the settings; we remove them so that old versions don't see\n    /// them and fail deserialization.  (The settings must be defaulted or generated in new versions,\n    /// and safe to remove.)\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let settings = input\n            .data\n            .keys()\n            .filter(|k| self.0.iter().any(|prefix| k.starts_with(prefix)))\n            .cloned()\n            .collect::<Vec<_>>();\n        for setting in settings {\n            if let Some(data) = input.data.remove(&setting) {\n                println!(\"Removed {setting}, which was set to '{data}'\");\n            }\n        }\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test_add_prefixes_migration {\n    use super::AddPrefixesMigration;\n    use crate::{Migration, MigrationData};\n    use maplit::hashmap;\n    use std::collections::HashMap;\n\n    #[test]\n    fn single() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.me.a\".into() => 0.into(),\n                \"remove.me.b\".into() => 0.into(),\n                \"keep.this.c\".into() => 0.into(),\n                \"remove.me.d.e\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        // Run backward, e.g. downgrade, to test that the right keys are removed\n        let result = AddPrefixesMigration(vec![\"remove.me\"])\n            .backward(data)\n            .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.me.a\".into() => 0.into(),\n                \"keep.this.c\".into() => 0.into(),\n            }\n        );\n    }\n\n    #[test]\n    fn multiple() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.me.a\".into() => 0.into(),\n                \"remove.me.b\".into() => 0.into(),\n                \"keep.this.c\".into() => 0.into(),\n                \"remove.this.d.e\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        // Run backward, e.g. downgrade, to test that the right keys are removed\n        let result = AddPrefixesMigration(vec![\"remove.me\", \"remove.this\"])\n            .backward(data)\n            .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.me.a\".into() => 0.into(),\n                \"keep.this.c\".into() => 0.into(),\n            }\n        );\n    }\n\n    #[test]\n    fn no_match() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.me.a\".into() => 0.into(),\n                \"remove.me.b\".into() => 0.into(),\n                \"keep.this.c\".into() => 0.into(),\n                \"remove.this.d.e\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        // Run backward, e.g. downgrade, to test that the right keys are removed\n        let result = AddPrefixesMigration(vec![\"not.found\", \"nor.this\"])\n            .backward(data)\n            .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.me.a\".into() => 0.into(),\n                \"remove.me.b\".into() => 0.into(),\n                \"keep.this.c\".into() => 0.into(),\n                \"remove.this.d.e\".into() => 0.into(),\n            }\n        );\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\npub struct PrefixSuffix {\n    pub prefix: &'static str,\n    pub suffix: &'static str,\n}\npub struct AddPrefixSuffixMigration(pub Vec<PrefixSuffix>);\n\nimpl Migration for AddPrefixSuffixMigration {\n    /// New versions must either have a default for the settings or generate them; we don't need to\n    /// do anything.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\n            \"AddPrefixSuffixMigration({:?}) has no work to do on upgrade.\",\n            self.0\n                .iter()\n                .map(|ps| format!(\"{}*{}\", ps.prefix, ps.suffix))\n                .collect::<Vec<_>>()\n        );\n        Ok(input)\n    }\n\n    /// Older versions don't know about the settings; we remove them so that old versions don't see\n    /// them and fail deserialization.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let mut compiled_patterns = Vec::new();\n        for pattern in &self.0 {\n            let regex_pattern = format!(\n                r\"^{}\\.(.+)\\.{}$\",\n                regex::escape(pattern.prefix),\n                regex::escape(pattern.suffix)\n            );\n            let regex =\n                Regex::new(&regex_pattern).context(error::InvalidPrefixSuffixPatternSnafu {\n                    prefix: pattern.prefix,\n                    suffix: pattern.suffix,\n                })?;\n            compiled_patterns.push(regex);\n        }\n\n        let settings = input\n            .data\n            .keys()\n            .filter(|k| compiled_patterns.iter().any(|regex| regex.is_match(k)))\n            .cloned()\n            .collect::<Vec<_>>();\n        for setting in settings {\n            if let Some(data) = input.data.remove(&setting) {\n                println!(\"Removed {setting}, which was set to '{data}'\");\n            }\n        }\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test_add_prefix_suffix_migration {\n    use super::{AddPrefixSuffixMigration, PrefixSuffix};\n    use crate::{Migration, MigrationData};\n    use maplit::hashmap;\n    use std::collections::HashMap;\n\n    #[test]\n    fn single_entry() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"remove.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n                \"remove.also.like.this\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = AddPrefixSuffixMigration(vec![PrefixSuffix {\n            prefix: \"remove\",\n            suffix: \"this\",\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n            }\n        );\n    }\n\n    #[test]\n    fn compound_suffix() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"remove.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n                \"remove.not.this\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = AddPrefixSuffixMigration(vec![PrefixSuffix {\n            prefix: \"remove\",\n            suffix: \"like.this\",\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n                \"remove.not.this\".into() => 0.into(),\n            }\n        );\n    }\n\n    #[test]\n    fn multiple_entries() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"remove.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n                \"remove.also.this\".into() => 0.into(),\n                \"delete.something.here\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = AddPrefixSuffixMigration(vec![\n            PrefixSuffix {\n                prefix: \"remove\",\n                suffix: \"this\",\n            },\n            PrefixSuffix {\n                prefix: \"delete\",\n                suffix: \"here\",\n            },\n        ])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n            }\n        );\n    }\n\n    #[test]\n    fn no_match() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n                \"other.setting.here\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = AddPrefixSuffixMigration(vec![PrefixSuffix {\n            prefix: \"remove.\",\n            suffix: \".this\",\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"keep.stuff.like.this\".into() => 0.into(),\n                \"keep.this.too\".into() => 0.into(),\n                \"other.setting.here\".into() => 0.into(),\n            }\n        );\n    }\n\n    #[test]\n    fn tight_matching() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"settings.host-containers.admin.command\".into() => 0.into(),\n                \"settings.host-containers.command\".into() => 0.into(), // No middle segment\n                \"settings.host-containersadmincommand\".into() => 0.into(), // No dots\n                \"keep.this\".into() => 0.into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = AddPrefixSuffixMigration(vec![PrefixSuffix {\n            prefix: \"settings.host-containers\",\n            suffix: \"command\",\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"settings.host-containers.command\".into() => 0.into(),\n                \"settings.host-containersadmincommand\".into() => 0.into(),\n                \"keep.this\".into() => 0.into(),\n            }\n        );\n    }\n}\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// We use this migration when we remove settings from the model, so the new version doesn't see\n/// them and error.\npub struct RemoveSettingsMigration<'a>(pub &'a [&'static str]);\n\nimpl Migration for RemoveSettingsMigration<'_> {\n    /// Newer versions don't know about the settings; we remove them so that new versions don't see\n    /// them and fail deserialization.  (The settings must be defaulted or generated in old versions,\n    /// and safe to remove.)\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for setting in self.0 {\n            if let Some(data) = input.data.remove(*setting) {\n                println!(\"Removed {setting}, which was set to '{data}'\");\n            } else {\n                println!(\"Found no {setting} to remove\");\n            }\n        }\n        Ok(input)\n    }\n\n    /// Old versions must either have a default for the settings or generate it; we don't need to\n    /// do anything.\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\n            \"RemoveSettingsMigration({:?}) has no work to do on downgrade.\",\n            self.0\n        );\n        Ok(input)\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// We use this migration when we replace a setting's old string value with a new string value.\npub struct ReplaceStringMigration {\n    pub setting: &'static str,\n    pub old_val: &'static str,\n    pub new_val: &'static str,\n}\n\nimpl Migration for ReplaceStringMigration {\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(data) = input.data.get_mut(self.setting) {\n            match data {\n                serde_json::Value::String(data) => {\n                    if data == self.old_val {\n                        self.new_val.clone_into(data);\n                        println!(\n                            \"Changed value of '{}' from '{}' to '{}' on upgrade\",\n                            self.setting, self.old_val, self.new_val\n                        );\n                    } else {\n                        println!(\n                            \"'{}' is not set to '{}', leaving alone\",\n                            self.setting, self.old_val\n                        );\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'; ReplaceStringMigration only handles strings\",\n                        self.setting, data\n                    );\n                }\n            }\n        } else {\n            println!(\"Found no '{}' to change on upgrade\", self.setting);\n        }\n        Ok(input)\n    }\n\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(data) = input.data.get_mut(self.setting) {\n            match data {\n                serde_json::Value::String(data) => {\n                    if data == self.new_val {\n                        self.old_val.clone_into(data);\n                        println!(\n                            \"Changed value of '{}' from '{}' to '{}' on downgrade\",\n                            self.setting, self.new_val, self.old_val\n                        );\n                    } else {\n                        println!(\n                            \"'{}' is not set to '{}', leaving alone\",\n                            self.setting, self.new_val\n                        );\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'; ReplaceStringMigration only handles strings\",\n                        self.setting, data\n                    );\n                }\n            }\n        } else {\n            println!(\"Found no '{}' to change on downgrade\", self.setting);\n        }\n        Ok(input)\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// We use this migration when we need to replace settings that contain lists of string values;\n/// for example, when a release changes the list of configuration-files associated with a service.\n// String is the only type we use today, and handling multiple value types is more complicated than\n// we need at the moment.  Allowing &[serde_json::Value] seems nice, but it would allow arbitrary\n// data transformations that the API model would then fail to load.\npub struct ListReplacement {\n    pub setting: &'static str,\n    pub old_vals: &'static [&'static str],\n    pub new_vals: &'static [&'static str],\n}\n\npub struct ReplaceListsMigration(pub Vec<ListReplacement>);\n\nimpl Migration for ReplaceListsMigration {\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for replacement in &self.0 {\n            if let Some(data) = input.data.get_mut(replacement.setting) {\n                match data {\n                    serde_json::Value::Array(data) => {\n                        // We only handle string lists; convert each value to a str we can compare.\n                        let list: Vec<&str> = data\n                            .iter()\n                            .map(|v| v.as_str())\n                            .collect::<Option<Vec<&str>>>()\n                            .with_context(|| error::ReplaceListContentsSnafu {\n                                setting: replacement.setting,\n                                data: data.clone(),\n                            })?;\n\n                        if list == replacement.old_vals {\n                            // Convert back to the original type so we can store it.\n                            *data = replacement.new_vals.iter().map(|s| (*s).into()).collect();\n                            println!(\n                                \"Changed value of '{}' from {:?} to {:?} on upgrade\",\n                                replacement.setting, replacement.old_vals, replacement.new_vals\n                            );\n                        } else {\n                            println!(\n                                \"'{}' is not set to {:?}, leaving alone\",\n                                replacement.setting, list\n                            );\n                        }\n                    }\n                    _ => {\n                        println!(\n                            \"'{}' is set to non-list value '{}'; ReplaceListsMigration only handles lists\",\n                            replacement.setting, data\n                        );\n                    }\n                }\n            } else {\n                println!(\"Found no '{}' to change on upgrade\", replacement.setting);\n            }\n        }\n        Ok(input)\n    }\n\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for replacement in &self.0 {\n            if let Some(data) = input.data.get_mut(replacement.setting) {\n                match data {\n                    serde_json::Value::Array(data) => {\n                        // We only handle string lists; convert each value to a str we can compare.\n                        let list: Vec<&str> = data\n                            .iter()\n                            .map(|v| v.as_str())\n                            .collect::<Option<Vec<&str>>>()\n                            .with_context(|| error::ReplaceListContentsSnafu {\n                                setting: replacement.setting,\n                                data: data.clone(),\n                            })?;\n\n                        if list == replacement.new_vals {\n                            // Convert back to the original type so we can store it.\n                            *data = replacement.old_vals.iter().map(|s| (*s).into()).collect();\n                            println!(\n                                \"Changed value of '{}' from {:?} to {:?} on downgrade\",\n                                replacement.setting, replacement.new_vals, replacement.old_vals\n                            );\n                        } else {\n                            println!(\n                                \"'{}' is not set to {:?}, leaving alone\",\n                                replacement.setting, list\n                            );\n                        }\n                    }\n                    _ => {\n                        println!(\n                        \"'{}' is set to non-list value '{}'; ReplaceListsMigration only handles lists\",\n                        replacement.setting, data\n                    );\n                    }\n                }\n            } else {\n                println!(\"Found no '{}' to change on downgrade\", replacement.setting);\n            }\n        }\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test_replace_list {\n    use super::{ListReplacement, ReplaceListsMigration};\n    use crate::{Migration, MigrationData};\n    use maplit::hashmap;\n    use std::collections::HashMap;\n\n    #[test]\n    fn single() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"hi\".into() => vec![\"there\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = ReplaceListsMigration(vec![ListReplacement {\n            setting: \"hi\",\n            old_vals: &[\"there\"],\n            new_vals: &[\"sup\"],\n        }])\n        .forward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"hi\".into() => vec![\"sup\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn backward() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"hi\".into() => vec![\"there\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = ReplaceListsMigration(vec![ListReplacement {\n            setting: \"hi\",\n            old_vals: &[\"sup\"],\n            new_vals: &[\"there\"],\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"hi\".into() => vec![\"sup\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn multiple() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"hi\".into() => vec![\"there\", \"you\"].into(),\n                \"hi2\".into() => vec![\"hey\", \"listen\"].into(),\n                \"ignored\".into() => vec![\"no\", \"change\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = ReplaceListsMigration(vec![\n            ListReplacement {\n                setting: \"hi\",\n                old_vals: &[\"there\", \"you\"],\n                new_vals: &[\"sup\", \"hey\"],\n            },\n            ListReplacement {\n                setting: \"hi2\",\n                old_vals: &[\"hey\", \"listen\"],\n                new_vals: &[\"look\", \"watch out\"],\n            },\n        ])\n        .forward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"hi\".into() => vec![\"sup\", \"hey\"].into(),\n                \"hi2\".into() => vec![\"look\", \"watch out\"].into(),\n                \"ignored\".into() => vec![\"no\", \"change\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn no_match() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"hi\".into() => vec![\"no\", \"change\"].into(),\n                \"hi2\".into() => vec![\"no\", \"change\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = ReplaceListsMigration(vec![ListReplacement {\n            setting: \"hi\",\n            old_vals: &[\"there\"],\n            new_vals: &[\"sup\", \"hey\"],\n        }])\n        .forward(data)\n        .unwrap();\n        // No change\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"hi\".into() => vec![\"no\", \"change\"].into(),\n                \"hi2\".into() => vec![\"no\", \"change\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn not_list() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"hi\".into() => \"just a string, not a list\".into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = ReplaceListsMigration(vec![ListReplacement {\n            setting: \"hi\",\n            old_vals: &[\"there\"],\n            new_vals: &[\"sup\", \"hey\"],\n        }])\n        .forward(data)\n        .unwrap();\n        // No change\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"hi\".into() => \"just a string, not a list\".into(),\n            }\n        );\n    }\n\n    #[test]\n    fn not_string() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"hi\".into() => vec![0].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        ReplaceListsMigration(vec![ListReplacement {\n            setting: \"hi\",\n            old_vals: &[\"there\"],\n            new_vals: &[\"sup\", \"hey\"],\n        }])\n        .forward(data)\n        .unwrap_err();\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// When we add conditional migrations that can only run for specific variants, we need to run this\n/// migration helper for cases where the migration does NOT apply so migrator will still create a valid\n/// intermediary datastore that the host can transition to.\n#[derive(Debug)]\npub struct NoOpMigration;\n\nimpl Migration for NoOpMigration {\n    /// No work to do on forward migrations, copy the same datastore\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"NoOpMigration has no work to do on upgrade.\",);\n        Ok(input)\n    }\n\n    /// No work to do on backward migrations, copy the same datastore\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"NoOpMigration has no work to do on downgrade.\",);\n        Ok(input)\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// We use this migration when we add new values to a list setting that older versions don't\n/// understand. On downgrade, we filter the list to only include values the old version accepts.\npub struct ListRestriction {\n    pub setting: &'static str,\n    pub allowed_vals: &'static [&'static str],\n}\n\npub struct RestrictListsMigration(pub Vec<ListRestriction>);\n\nimpl Migration for RestrictListsMigration {\n    /// New versions can handle all values; no work needed on upgrade.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\n            \"RestrictListsMigration({:?}) has no work to do on upgrade.\",\n            self.0.iter().map(|r| r.setting).collect::<Vec<_>>()\n        );\n        Ok(input)\n    }\n\n    /// Older versions only understand certain values; remove any values not in the allowed list.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for restriction in &self.0 {\n            if let Some(data) = input.data.get_mut(restriction.setting) {\n                match data {\n                    serde_json::Value::Array(data) => {\n                        let list: Vec<&str> = data\n                            .iter()\n                            .map(|v| v.as_str())\n                            .collect::<Option<Vec<&str>>>()\n                            .with_context(|| error::ReplaceListContentsSnafu {\n                                setting: restriction.setting,\n                                data: data.clone(),\n                            })?;\n\n                        let filtered: Vec<&str> = list\n                            .into_iter()\n                            .filter(|val| restriction.allowed_vals.contains(val))\n                            .collect();\n\n                        if filtered.len() != data.len() {\n                            let new_data: Vec<serde_json::Value> =\n                                filtered.iter().map(|s| (*s).into()).collect();\n                            println!(\n                                \"Filtered '{}' to allowed values {:?} on downgrade\",\n                                restriction.setting, filtered\n                            );\n                            *data = new_data;\n                        } else {\n                            println!(\n                                \"'{}' already contains only allowed values, leaving alone\",\n                                restriction.setting\n                            );\n                        }\n                    }\n                    _ => {\n                        println!(\n                            \"'{}' is set to non-list value '{}'; RestrictListsMigration only handles lists\",\n                            restriction.setting, data\n                        );\n                    }\n                }\n            } else {\n                println!(\"Found no '{}' to filter on downgrade\", restriction.setting);\n            }\n        }\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test_restrict_lists {\n    use super::{ListRestriction, RestrictListsMigration};\n    use crate::{Migration, MigrationData};\n    use maplit::hashmap;\n    use std::collections::HashMap;\n\n    #[test]\n    fn filter_values() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"setting\".into() => vec![\"old1\", \"old2\", \"new1\", \"new2\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = RestrictListsMigration(vec![ListRestriction {\n            setting: \"setting\",\n            allowed_vals: &[\"old1\", \"old2\"],\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"setting\".into() => vec![\"old1\", \"old2\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn no_filtering_needed() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"setting\".into() => vec![\"old1\", \"old2\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = RestrictListsMigration(vec![ListRestriction {\n            setting: \"setting\",\n            allowed_vals: &[\"old1\", \"old2\", \"new1\"],\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"setting\".into() => vec![\"old1\", \"old2\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn forward_no_change() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"setting\".into() => vec![\"old1\", \"new1\", \"new2\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = RestrictListsMigration(vec![ListRestriction {\n            setting: \"setting\",\n            allowed_vals: &[\"old1\"],\n        }])\n        .forward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"setting\".into() => vec![\"old1\", \"new1\", \"new2\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn multiple_restrictions() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"setting1\".into() => vec![\"a\", \"b\", \"c\"].into(),\n                \"setting2\".into() => vec![\"x\", \"y\", \"z\"].into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = RestrictListsMigration(vec![\n            ListRestriction {\n                setting: \"setting1\",\n                allowed_vals: &[\"a\", \"b\"],\n            },\n            ListRestriction {\n                setting: \"setting2\",\n                allowed_vals: &[\"x\"],\n            },\n        ])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"setting1\".into() => vec![\"a\", \"b\"].into(),\n                \"setting2\".into() => vec![\"x\"].into(),\n            }\n        );\n    }\n\n    #[test]\n    fn not_list() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"setting\".into() => \"not a list\".into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = RestrictListsMigration(vec![ListRestriction {\n            setting: \"setting\",\n            allowed_vals: &[\"old1\"],\n        }])\n        .backward(data)\n        .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"setting\".into() => \"not a list\".into(),\n            }\n        );\n    }\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// We use this migration to remove a setting string if it matches the old value.\n/// We will need this migration once to adapt the concept of Strength on settings.\npub struct RemoveMatchingString {\n    pub setting: &'static str,\n    pub old_val: &'static str,\n}\n\nimpl Migration for RemoveMatchingString {\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(data) = input.data.get_mut(self.setting) {\n            match data {\n                serde_json::Value::String(data) => {\n                    if data == self.old_val {\n                        input.data.remove(self.setting);\n                    } else {\n                        println!(\n                            \"'{}' is not set to '{}', leaving alone\",\n                            self.setting, self.old_val\n                        );\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'; RemoveOldData expects a string setting value\",\n                        self.setting, data\n                    );\n                }\n            }\n        } else {\n            println!(\"Found no '{}' to change on upgrade\", self.setting);\n        }\n        Ok(input)\n    }\n\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"RemoveOldData has no work to do on downgrade.\",);\n        Ok(input)\n    }\n}\n"
  },
  {
    "path": "sources/api/migration/migration-helpers/src/datastore_helper.rs",
    "content": "//! This module contains the functions that interact with the data store, retrieving data to\n//! migrate and writing back migrated data.\n\nuse bottlerocket_release::BottlerocketRelease;\nuse snafu::ResultExt;\nuse std::collections::HashMap;\n\nuse crate::{error, MigrationData, Result};\nuse datastore::{\n    deserialize_scalar, serialization::to_pairs_with_prefix, serialize_scalar, Committed,\n    DataStore, Key, KeyType,\n};\n\n// To get input data from the existing data store, we use datastore methods, because we assume\n// breaking changes in the basic data store API would be a major-version migration of the data\n// store, and that would be handled separately.  This method is private to the crate, so we can\n// reconsider as needed.\n/// Retrieves data from the specified data store in a consistent format for easy modification.\npub(crate) fn get_input_data<D: DataStore>(\n    datastore: &D,\n    committed: &Committed,\n) -> Result<MigrationData> {\n    let raw_data = datastore\n        .get_prefix(\"\", committed)\n        .with_context(|_| error::GetDataSnafu {\n            committed: committed.clone(),\n        })?;\n\n    let mut data = HashMap::new();\n    for (data_key, value_str) in raw_data.into_iter() {\n        // Store keys with just their name, rather than the full Key, so that migrations are easier\n        // to write, and we don't tie migrations to any specific data store version.  Migrations\n        // shouldn't need to link against data store code.\n        let key_name = data_key.name();\n        // Deserialize values to Value so there's a consistent input type.  (We can't specify item\n        // types because we'd have to know the model structure.)\n        let value =\n            deserialize_scalar(&value_str).context(error::DeserializeSnafu { input: value_str })?;\n        data.insert(key_name.clone(), value);\n    }\n\n    // We also want to make \"os.*\" values, like variant and arch, available to migrations.\n    let release = BottlerocketRelease::new().context(error::BottlerocketReleaseSnafu)?;\n    let os_pairs = to_pairs_with_prefix(\"os\", &release).context(error::SerializeReleaseSnafu)?;\n    for (data_key, value_str) in os_pairs.into_iter() {\n        let value =\n            deserialize_scalar(&value_str).context(error::DeserializeSnafu { input: value_str })?;\n        data.insert(data_key.name().clone(), value);\n    }\n\n    // Metadata isn't committed, it goes live immediately, so we only populate the metadata\n    // output for Committed::Live.\n    let mut metadata = HashMap::new();\n    if let Committed::Live = committed {\n        let raw_metadata = datastore\n            .get_metadata_prefix(\"\", committed, &None as &Option<&str>)\n            .context(error::GetMetadataSnafu)?;\n        for (data_key, meta_map) in raw_metadata.into_iter() {\n            // See notes above about storing key Strings and Values.\n            let data_key_name = data_key.name();\n            let data_entry = metadata\n                .entry(data_key_name.clone())\n                .or_insert_with(HashMap::new);\n            for (metadata_key, value_str) in meta_map.into_iter() {\n                let metadata_key_name = metadata_key.name();\n                let value = deserialize_scalar(&value_str)\n                    .context(error::DeserializeSnafu { input: value_str })?;\n                data_entry.insert(metadata_key_name.clone(), value);\n            }\n        }\n    }\n\n    Ok(MigrationData { data, metadata })\n}\n\n// Similar to get_input_data, we use datastore methods here; please read the comment on\n// get_input_data.  This method is also private to the crate, so we can reconsider as needed.\n/// Updates the given data store with the given (migrated) data.\npub(crate) fn set_output_data<D: DataStore>(\n    datastore: &mut D,\n    input: &MigrationData,\n    committed: &Committed,\n) -> Result<()> {\n    // Prepare serialized data\n    let mut data = HashMap::new();\n    for (data_key_name, raw_value) in &input.data {\n        // See notes above about storing key Strings and Values.\n        let data_key = Key::new(KeyType::Data, data_key_name).context(error::InvalidKeySnafu {\n            key_type: KeyType::Data,\n            key: data_key_name,\n        })?;\n        let value = serialize_scalar(raw_value).context(error::SerializeSnafu)?;\n        data.insert(data_key, value);\n    }\n\n    // This is one of the rare cases where we want to set keys directly in the datastore:\n    // * We're operating on a temporary copy of the datastore, so no concurrency issues\n    // * We're either about to reboot or just have, and the settings applier will run afterward\n    datastore\n        .set_keys(&data, committed)\n        .context(error::DataStoreWriteSnafu)?;\n\n    // Set metadata in a loop (currently no batch API)\n    for (data_key_name, meta_map) in &input.metadata {\n        let data_key = Key::new(KeyType::Data, data_key_name).context(error::InvalidKeySnafu {\n            key_type: KeyType::Data,\n            key: data_key_name,\n        })?;\n        for (metadata_key_name, raw_value) in meta_map.iter() {\n            let metadata_key =\n                Key::new(KeyType::Meta, metadata_key_name).context(error::InvalidKeySnafu {\n                    key_type: KeyType::Meta,\n                    key: metadata_key_name,\n                })?;\n            let value = serialize_scalar(&raw_value).context(error::SerializeSnafu)?;\n            datastore\n                .set_metadata(&metadata_key, &data_key, value, committed)\n                .context(error::DataStoreWriteSnafu)?;\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "sources/api/migration/migration-helpers/src/error.rs",
    "content": "//! Contains the Error and Result types used by the migration helper functions and migrations.\n\nuse snafu::Snafu;\nuse std::path::PathBuf;\n\n/// Error contains the errors that can happen in the migration helper functions and in migrations.\n#[derive(Debug, Snafu)]\n#[snafu(visibility(pub))]\npub enum Error {\n    #[snafu(display(\"Unable to get system release data: {}\", source))]\n    BottlerocketRelease { source: bottlerocket_release::Error },\n\n    #[snafu(display(\"Unable to get {:?} data for migration: {}\", committed, source))]\n    GetData {\n        committed: datastore::Committed,\n        #[snafu(source(from(datastore::Error, Box::new)))]\n        source: Box<datastore::Error>,\n    },\n\n    #[snafu(display(\"Unable to get metadata for migration: {}\", source))]\n    GetMetadata {\n        #[snafu(source(from(datastore::Error, Box::new)))]\n        source: Box<datastore::Error>,\n    },\n\n    #[snafu(display(\"Unable to deserialize to Value from '{}': {}\", input, source))]\n    Deserialize {\n        input: String,\n        source: datastore::ScalarError,\n    },\n\n    #[snafu(display(\"Unable to serialize Value: {}\", source))]\n    Serialize { source: datastore::ScalarError },\n\n    #[snafu(display(\"Unable to serialize datastore for rendering templates: {}\", source))]\n    SerializeTemplateData { source: serde_json::Error },\n\n    #[snafu(display(\"Unable to serialize release data: {}\", source))]\n    SerializeRelease {\n        source: datastore::serialization::Error,\n    },\n\n    #[snafu(display(\"Unable to write to data store: {}\", source))]\n    DataStoreWrite {\n        #[snafu(source(from(datastore::Error, Box::new)))]\n        source: Box<datastore::Error>,\n    },\n\n    #[snafu(display(\"Unable to remove key '{}' from data store: {}\", key, source))]\n    DataStoreRemove {\n        key: String,\n        #[snafu(source(from(datastore::Error, Box::new)))]\n        source: Box<datastore::Error>,\n    },\n\n    #[snafu(display(\"Migrated data failed validation: {}\", msg))]\n    Validation { msg: String },\n\n    // Generic error variant for migration authors\n    #[snafu(display(\"Migration returned error: {}\", msg))]\n    Migration { msg: String },\n\n    // More specific error variants for migration authors to handle common cases\n    #[snafu(display(\"Migration requires missing key: {}\", key))]\n    MissingData { key: String },\n\n    #[snafu(display(\"Migration used invalid {:?} key '{}': {}\", key_type, key, source))]\n    InvalidKey {\n        key_type: datastore::KeyType,\n        key: String,\n        #[snafu(source(from(datastore::Error, Box::new)))]\n        source: Box<datastore::Error>,\n    },\n\n    #[snafu(display(\n        \"Invalid regex pattern for prefix '{}' and suffix '{}': {}\",\n        prefix,\n        suffix,\n        source\n    ))]\n    InvalidPrefixSuffixPattern {\n        prefix: String,\n        suffix: String,\n        source: regex::Error,\n    },\n\n    #[snafu(display(\"Unable to list transactions in data store: {}\", source))]\n    ListTransactions {\n        #[snafu(source(from(datastore::Error, Box::new)))]\n        source: Box<datastore::Error>,\n    },\n\n    #[snafu(display(\"'{}' is set to non-string value\", setting))]\n    NonStringSettingDataType { setting: String },\n\n    #[snafu(display(\"Unable to deserialize datastore data: {}\", source))]\n    DeserializeDatastore {\n        source: datastore::deserialization::Error,\n    },\n\n    #[snafu(display(\"Unable to create new key: {}\", source))]\n    NewKey { source: datastore::error::Error },\n\n    #[snafu(display(\"Setting '{}' contains non-string item: {:?}\", setting, data))]\n    ReplaceListContents {\n        setting: String,\n        data: Vec<serde_json::Value>,\n    },\n\n    #[snafu(display(\n        \"Metadata '{}' for setting '{}' contains non-string item: {:?}\",\n        metadata,\n        setting,\n        data\n    ))]\n    ReplaceMetadataListContents {\n        setting: String,\n        metadata: String,\n        data: Vec<serde_json::Value>,\n    },\n\n    #[snafu(display(\"Failed to delete file '{}': '{}'\", path.display(), source))]\n    RemoveFile {\n        path: PathBuf,\n        source: std::io::Error,\n    },\n\n    #[snafu(display(\"Failed to create async runtime: {}\", source))]\n    CreateTokioRuntime { source: std::io::Error },\n\n    #[snafu(display(\n        \"Error in deserializing response value to SettingsGenerator: {}\",\n        source\n    ))]\n    DeserializeSettingsGenerator { source: serde_json::Error },\n\n    #[snafu(display(\"Setting data '{}' must be either a string or a list\", data))]\n    InvalidSettingType { data: String },\n}\n\n/// Result alias containing our Error type.\npub type Result<T> = std::result::Result<T, Error>;\n"
  },
  {
    "path": "sources/api/migration/migration-helpers/src/lib.rs",
    "content": "//! This module aims to make it as easy as possible to migrate a data store between minor\n//! versions.  Migration authors just implement one trait, and can then use helper methods to take\n//! care of everything else in their main function.\n//!\n//! Note that you must still name your migration binary according to spec for it to be handled\n//! properly by the migration runner.\n\n// Note that migrations must be run serially; technically, this is because the data store isn't\n// locked, and also because migration authors are given an interface for ordering via migration\n// name, and running in parallel would violate that.\n\nmod args;\npub mod common_migrations;\nmod datastore_helper;\npub mod error;\n\nuse snafu::ResultExt;\nuse std::collections::HashMap;\nuse std::env;\nuse std::fmt;\n\nuse datastore::{Committed, Value};\npub use datastore::{DataStore, FilesystemDataStore};\n\nuse args::{parse_args, Args};\nuse datastore_helper::{get_input_data, set_output_data};\npub use error::Result;\n\n/// The data store implementation currently in use.  Used by the simpler `migrate` interface; can\n/// be overridden by using the `run_migration` interface.\ntype DataStoreImplementation = FilesystemDataStore;\n\n/// Migrations must implement this trait, and can then use the migrate method to let this module\n/// do the rest of the work.\n///\n/// Migrations must implement forward and backward methods so changes can be rolled back as\n/// necessary.\n///\n/// Migrations must not assume any key will exist because they're run on pending data as well as\n/// live, and pending transactions usually do not impact all keys.  For the same reason, migrations\n/// must not add a key in all cases if it's missing, because you could be adding the key to an\n/// unrelated pending transaction.  Instead, make sure you're adding a key to an existing\n/// structure.\npub trait Migration {\n    /// Migrates data forward from the prior version to the version specified in the migration\n    /// name.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData>;\n\n    /// Migrates data backward from the version specified in the migration name to the prior\n    /// version.\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData>;\n}\n\n/// Mapping of metadata key name to arbitrary value.  Each data key can have a Metadata describing\n/// its metadata keys.\npub type Metadata = HashMap<String, Value>;\n\n/// MigrationData holds all data that can be migrated in a migration, and serves as the input and\n/// output format of migrations.  A serde Value type is used to hold the arbitrary data of each\n/// key because we can't represent types when they could change in the migration.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct MigrationData {\n    /// Mapping of data key names to their arbitrary values.\n    pub data: HashMap<String, Value>,\n    /// Mapping of data key names to their metadata.\n    pub metadata: HashMap<String, Metadata>,\n}\n\n/// Returns the default settings for a given path so you can easily replace a given section of the\n/// datastore with new defaults.  For example, you could request \"settings\" to get all new default\n/// settings, or \"settings.serviceX.subsection\" to scope it down.\npub fn defaults_for<S: AsRef<str>>(_path: S) -> Result<Value> {\n    unimplemented!()\n}\n\n/// Ensures we can use the migrated data in the new data store.  Can use this result to stop the\n/// migration process before saving any data.\nfn validate_migrated_data(_migrated: &MigrationData) -> Result<()> {\n    // No validations yet.\n    // You can check the migrated data and throw error::Validation if anything seems wrong.\n    Ok(())\n}\n\n/// If you need a little more control over a migration than with migrate, or you're using this\n/// module as a library, you can call run_migration directly with the arguments that would\n/// normally be parsed from the migration binary's command line.\npub fn run_migration(mut migration: impl Migration, args: &Args) -> Result<()> {\n    let source = DataStoreImplementation::new(&args.source_datastore);\n    let mut target = DataStoreImplementation::new(&args.target_datastore);\n\n    // Run for live data and for each pending transaction\n    let mut committeds = vec![Committed::Live];\n    let transactions = source\n        .list_transactions()\n        .context(error::ListTransactionsSnafu)?;\n    committeds.extend(transactions.into_iter().map(|tx| Committed::Pending { tx }));\n\n    for committed in committeds {\n        let input = get_input_data(&source, &committed)?;\n\n        let mut migrated = input.clone();\n        migrated = match args.migration_type {\n            MigrationType::Forward => migration.forward(migrated),\n            MigrationType::Backward => migration.backward(migrated),\n        }?;\n\n        validate_migrated_data(&migrated)?;\n\n        set_output_data(&mut target, &migrated, &committed)?;\n    }\n    Ok(())\n}\n\n/// Represents the type of migration, so we know which Migration trait method to call.\n#[derive(Debug, Copy, Clone)]\npub enum MigrationType {\n    Forward,\n    Backward,\n}\n\nimpl fmt::Display for MigrationType {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            MigrationType::Forward => write!(f, \"forward\"),\n            MigrationType::Backward => write!(f, \"backward\"),\n        }\n    }\n}\n\n/// This is the primary entry point for migration authors.  When you've implemented the Migration\n/// trait, you should just be able to pass it to this function from your main function and let it\n/// take care of the rest.  The migration runner will pass in the appropriate datastore paths and\n/// migration type.\npub fn migrate(migration: impl Migration) -> Result<()> {\n    let args = parse_args(env::args())?;\n    run_migration(migration, &args)\n}\n"
  },
  {
    "path": "sources/bottlerocket-release/Cargo.toml",
    "content": "[package]\nname = \"bottlerocket-release\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nenvy.workspace = true\nlog.workspace = true\nsemver = { workspace = true, features = [\"serde\"] }\nserde = { workspace = true, features = [\"derive\"] }\nsnafu.workspace = true\n\n[build-dependencies]\ngenerate-readme.workspace = true\n"
  },
  {
    "path": "sources/bottlerocket-release/README.md",
    "content": "# bottlerocket-release\n\nCurrent version: 0.1.0\n\n## Background\n\nThis library lets you get a BottlerocketRelease struct that represents the data in the standard os-release file, or another file you point to.\nThe VERSION_ID is returned as a semver::Version for convenience.\n\nThe information is pulled at runtime because build_id changes frequently and would cause unnecessary rebuilds.\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/bottlerocket-release/README.tpl",
    "content": "# {{crate}}\n\nCurrent version: {{version}}\n\n{{readme}}\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/bottlerocket-release/build.rs",
    "content": "use std::path::Path;\nuse std::{env, fs};\n\nfn generate_readme() {\n    generate_readme::from_lib().unwrap();\n}\n\nfn generate_constants() {\n    let out_dir = env::var(\"OUT_DIR\").unwrap();\n    let arch = env::var(\"CARGO_CFG_TARGET_ARCH\").unwrap();\n    let contents = format!(\"const ARCH: &str = \\\"{arch}\\\";\");\n    let path = Path::new(&out_dir).join(\"constants.rs\");\n    fs::write(path, contents).unwrap();\n}\n\nfn main() {\n    generate_readme();\n    generate_constants();\n}\n"
  },
  {
    "path": "sources/bottlerocket-release/src/lib.rs",
    "content": "/*!\n# Background\n\nThis library lets you get a BottlerocketRelease struct that represents the data in the standard os-release file, or another file you point to.\nThe VERSION_ID is returned as a semver::Version for convenience.\n\nThe information is pulled at runtime because build_id changes frequently and would cause unnecessary rebuilds.\n*/\n\nconst DEFAULT_RELEASE_FILE: &str = \"/usr/lib/os-release\";\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/constants.rs\"));\n\nuse log::debug;\nuse semver::Version;\nuse serde::{Deserialize, Serialize};\nuse snafu::ResultExt;\nuse std::fs;\nuse std::path::Path;\n\n/// BottlerocketRelease represents the data found in the release file.\n#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]\npub struct BottlerocketRelease {\n    // Fields from os-release\n    pub pretty_name: String,\n    pub variant_id: String,\n    pub version_id: Version,\n    pub build_id: String,\n\n    // Other system information\n    pub arch: String,\n}\n\nmod error {\n    use snafu::Snafu;\n    use std::io;\n    use std::path::PathBuf;\n\n    #[derive(Debug, Snafu)]\n    #[snafu(visibility(pub(super)))]\n    pub enum Error {\n        #[snafu(display(\"Unable to read release file '{}': {}\", path.display(), source))]\n        ReadReleaseFile { path: PathBuf, source: io::Error },\n\n        #[snafu(display(\"Unable to load release data from file '{}': {}\", path.display(), source))]\n        LoadReleaseData { path: PathBuf, source: envy::Error },\n    }\n}\npub use error::Error;\ntype Result<T> = std::result::Result<T, error::Error>;\n\nimpl BottlerocketRelease {\n    pub fn new() -> Result<Self> {\n        Self::from_file(DEFAULT_RELEASE_FILE)\n    }\n\n    pub fn from_file<P>(path: P) -> Result<Self>\n    where\n        P: AsRef<Path>,\n    {\n        let path = path.as_ref();\n\n        let release_data =\n            fs::read_to_string(path).context(error::ReadReleaseFileSnafu { path })?;\n\n        // Split and process each line\n        let mut pairs: Vec<(String, String)> = release_data\n            .lines()\n            .filter_map(|line| {\n                // Allow for comments\n                if line.starts_with('#') {\n                    return None;\n                }\n\n                // Split out KEY=VALUE; if there is no \"=\" we skip the line\n                let mut parts = line.splitn(2, '=');\n                let key = parts.next().expect(\"split returned zero parts\");\n                let mut value = match parts.next() {\n                    Some(part) => part,\n                    None => return None,\n                };\n\n                // If the value was quoted (unnecessary in this file) then remove the quotes\n                if value.starts_with('\"') {\n                    value = &value[1..];\n                }\n                if value.ends_with('\"') {\n                    value = &value[..value.len() - 1];\n                }\n\n                debug!(\"Found os-release value {key}={value}\");\n                Some((key.to_owned(), value.to_owned()))\n            })\n            .collect();\n\n        // Add information from other sources\n        pairs.push((\"arch\".to_string(), ARCH.to_string()));\n\n        envy::from_iter(pairs).context(error::LoadReleaseDataSnafu { path })\n    }\n}\n"
  },
  {
    "path": "sources/clarify.toml",
    "content": "[clarify.actix-macros]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x31de3fcd },\n    { path = \"LICENSE-MIT\", hash = 0xfeb1e4a7 },\n]\n\n[clarify.actix-codec]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x31de3fcd },\n    { path = \"LICENSE-MIT\", hash = 0xfeb1e4a7 },\n]\n\n[clarify.actix-http]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x31de3fcd },\n    { path = \"LICENSE-MIT\", hash = 0xfeb1e4a7 },\n]\n\n[clarify.backtrace-sys]\n# backtrace-sys is MIT/Apache-2.0, libbacktrace is BSD-3-Clause\nexpression = \"(MIT OR Apache-2.0) AND BSD-3-Clause\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0x9374b940 },\n    { path = \"src/libbacktrace/LICENSE\", hash = 0x0ce09262 },\n]\n\n[[clarify.bstr]]\nversion = \"^0.2\"\nexpression = \"(MIT OR Apache-2.0) AND Unicode-DFS-2016\"\nlicense-files = [\n    { path = \"COPYING\", hash = 0x28398560 },\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0x462dee44 },\n    { path = \"src/unicode/data/LICENSE-UNICODE\", hash = 0x70f7339 },\n]\n\n[[clarify.bstr]]\nversion = \"=1\"\nexpression = \"(MIT OR Apache-2.0) AND Unicode-DFS-2016\"\nlicense-files = [\n    { path = \"COPYING\", hash = 0x278afbcf },\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0x462dee44 },\n    { path = \"src/unicode/data/LICENSE-UNICODE\", hash = 0x70f7339 },\n]\n\n[clarify.cached]\nexpression = \"MIT\"\nlicense-files = [\n    { path = \"COPYRIGHT\", hash = 0xaf811590 },\n    { path = \"LICENSE\", hash = 0x77e163f0 },\n]\n\n[clarify.crossbeam-queue]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0x386ca1bc },\n    { path = \"LICENSE-THIRD-PARTY\", hash = 0x7e40bc60 },\n]\n\n[clarify.crossbeam-channel]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0xbc436f08 },\n    { path = \"LICENSE-THIRD-PARTY\", hash = 0x847bf39 },\n]\n\n# https://github.com/hsivonen/encoding_rs The non-test code that isn't generated from the WHATWG data in this crate is\n# under Apache-2.0 OR MIT. Test code is under CC0.\n[clarify.encoding_rs]\nexpression = \"(Apache-2.0 OR MIT) AND BSD-3-Clause\"\nlicense-files = [\n    { path = \"COPYRIGHT\", hash = 0x39f8ad31 },\n    { path = \"LICENSE-APACHE\", hash = 0x18785531 },\n    { path = \"LICENSE-MIT\", hash = 0xafaec4cb },\n    { path = \"LICENSE-WHATWG\", hash = 0xbcb87a0c },\n    { path = \"COPYRIGHT\", hash = 0x39f8ad31 },\n]\n\n[clarify.lz4-sys]\n# The lz4-sys crate's license is listed as MIT.\n#\n# lz4-sys compiles four files from liblz4 as a static library:\n# - lib/lz4.c\n# - lib/lz4frame.c\n# - lib/lz4hc.c\n# - lib/xxhash.c\n#\n# liblz4's LICENSE file states:\n# > This repository uses 2 different licenses :\n# > - all files in the `lib` directory use a BSD 2-Clause license\n# > - all other files use a GPLv2 license, unless explicitly stated otherwise\nexpression = \"MIT AND BSD-2-Clause\"\nlicense-files = [\n    { path = \"liblz4/lib/LICENSE\", hash = 0xe411c460 },\n]\nskip-files = [\n    \"liblz4/LICENSE\", # top-level explainer file\n    \"liblz4/contrib/djgpp/LICENSE\",\n    \"liblz4/examples/COPYING\",\n    \"liblz4/programs/COPYING\",\n    \"liblz4/tests/COPYING\",\n]\n\n[clarify.minimal-lexical]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE.md\", hash = 0xfe66d806 },\n    { path = \"LICENSE-APACHE\", hash = 0x4fccb6b7 },\n    { path = \"LICENSE-MIT\", hash = 0x386ca1bc },\n]\n\n[clarify.pulldown-cmark]\nexpression = \"MIT\"\nlicense-files = [\n    { path = \"LICENSE\", hash = 0x4cb272b3 },\n]\nskip-files = [\n    \"third_party/CommonMark/LICENSE\", # only contains the commonmark specification\n]\n\n[clarify.regex]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0xb755395b },\n]\nskip-files = [\n    \"src/testdata/LICENSE\", # we aren't using the test data\n]\n\n[[clarify.regex-automata]]\nversion = \"^0.1\"\nexpression = \"Unlicense OR MIT\"\nlicense-files = [\n    { path = \"COPYING\", hash = 0x969f37d8 },\n    { path = \"LICENSE-MIT\", hash = 0x616d8a83 },\n    { path = \"UNLICENSE\", hash = 0x87b84020 },\n]\nskip-files = [\n    \"data/fowler-tests/LICENSE\", # we aren't using the test data\n    \"data/tests/fowler/LICENSE\",\n]\n\n[[clarify.regex-automata]]\nversion = \"^0.3\"\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE-MIT\", hash = 0xb755395b },\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n]\n\n[clarify.regex-syntax]\nexpression = \"(MIT OR Apache-2.0) AND Unicode-DFS-2016\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0x24b54f4b },\n    { path = \"LICENSE-MIT\", hash = 0xb755395b },\n    { path = \"src/unicode_tables/LICENSE-UNICODE\", hash = 0xa7f28b93 },\n]\n\n[clarify.ring]\nexpression = \"MIT AND ISC AND OpenSSL\"\nlicense-files = [\n    { path = \"LICENSE\", hash = 0xbd0eed23 },\n    { path = \"third_party/fiat/LICENSE\", hash = 0x75829ee2 },\n]\n\n[clarify.tokio-macros]\nexpression = \"MIT\"\nlicense-files = [\n    { path = \"LICENSE\", hash = 0x402b08de },\n]\n\n[clarify.unicode-ident]\nexpression = \"(MIT OR Apache-2.0) AND Unicode-DFS-2016\"\nlicense-files = [\n    { path = \"LICENSE-APACHE\", hash = 0xb5518783 },\n    { path = \"LICENSE-MIT\", hash = 0x386ca1bc },\n    { path = \"LICENSE-UNICODE\", hash = 0x9698cbbe },\n]\n\n[clarify.vmw_backdoor]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"COPYRIGHT\", hash = 0x3fd7d639 },\n    { path = \"LICENSE-APACHE-2.0\", hash = 0x18785531 },\n    { path = \"LICENSE-MIT\", hash = 0x28392cf3 },\n]\n\n[clarify.typenum]\nexpression = \"MIT OR Apache-2.0\"\nlicense-files = [\n    { path = \"LICENSE\", hash = 0xa4618a29 },\n    { path = \"LICENSE-MIT\", hash = 0xb9f15462 },\n    { path = \"LICENSE-APACHE\", hash = 0x91d5a0a7 },\n]\n"
  },
  {
    "path": "sources/constants/Cargo.toml",
    "content": "[package]\nname = \"constants\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\n\n[build-dependencies]\ngenerate-readme.workspace = true\n"
  },
  {
    "path": "sources/constants/README.md",
    "content": "# constants\n\nCurrent version: 0.1.0\n\n  This crate contains constants shared across multiple Bottlerocket crates\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`.\n"
  },
  {
    "path": "sources/constants/README.tpl",
    "content": "# {{crate}}\n\nCurrent version: {{version}}\n\n{{readme}}\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`.\n"
  },
  {
    "path": "sources/constants/build.rs",
    "content": "fn main() {\n    generate_readme::from_lib().unwrap();\n}\n"
  },
  {
    "path": "sources/constants/src/lib.rs",
    "content": "/*!\n  This crate contains constants shared across multiple Bottlerocket crates\n*/\n\n// Shared API settings\npub const API_SOCKET: &str = \"/run/api.sock\";\npub const API_SETTINGS_URI: &str = \"/settings\";\npub const API_SETTINGS_GENERATORS_URI: &str = \"/metadata/setting-generators\";\n\n// Shared transaction used by boot time services\npub const LAUNCH_TRANSACTION: &str = \"bottlerocket-launch\";\n\n// Shared binaries' locations\npub const SYSTEMCTL_BIN: &str = \"/bin/systemctl\";\npub const HOST_CTR_BIN: &str = \"/bin/host-ctr\";\n"
  },
  {
    "path": "sources/deny.toml",
    "content": "[licenses]\nversion = 2\n\n# We want really high confidence when inferring licenses from text\nconfidence-threshold = 0.93\n\n# Commented license types are allowed but not currently used\nallow = [\n    \"Apache-2.0\",\n    # \"BSD-2-Clause\",\n    \"BSD-3-Clause\",\n    # \"BSL-1.0\",\n    # \"CC0-1.0\",\n    \"ISC\",\n    \"MIT\",\n    # \"OpenSSL\",\n    \"Unlicense\",\n    \"Zlib\",\n    \"MPL-2.0\",\n    \"Unicode-3.0\",\n]\n\nexceptions = [\n    { name = \"unicode-ident\", version = \"1.0.4\", allow = [\n        \"MIT\",\n        \"Apache-2.0\",\n        \"Unicode-DFS-2016\",\n    ] },\n]\n\n# https://github.com/hsivonen/encoding_rs The non-test code that isn't generated from the WHATWG data in this crate is\n# under Apache-2.0 OR MIT. Test code is under CC0.\n[[licenses.clarify]]\nname = \"encoding_rs\"\nversion = \"0.8.30\"\nexpression = \"(Apache-2.0 OR MIT) AND BSD-3-Clause\"\nlicense-files = [{ path = \"COPYRIGHT\", hash = 0x39f8ad31 }]\n\n[[licenses.clarify]]\nname = \"ring\"\nexpression = \"MIT AND ISC AND OpenSSL\"\nlicense-files = [{ path = \"LICENSE\", hash = 0xbd0eed23 }]\n\n[[licenses.clarify]]\nname = \"webpki\"\nexpression = \"ISC\"\nlicense-files = [{ path = \"LICENSE\", hash = 0x001c7e6c }]\n\n[bans]\n# Deny multiple versions or wildcard dependencies.\nmultiple-versions = \"deny\"\nwildcards = \"deny\"\n\ndeny = [{ name = \"structopt\" }, { name = \"clap\", wrappers = [\"cargo-readme\"] }]\n\nskip = [\n    # bottlerocket-settings-sdk requires syn 1.x and 2.x for proc-macros\n    # within itself and its dependencies.\n    { name = \"syn\", version = \"=1.0\" },\n]\n\nskip-tree = [\n    # windows-sys is not a direct dependency. mio and schannel\n    # are using different versions of windows-sys. we skip the\n    # dependency tree because windows-sys has many sub-crates\n    # that differ in major version.\n    { name = \"windows-sys\" },\n]\n\n[advisories]\n# generational-arena is currently unmaintained.\nignore = [\"RUSTSEC-2024-0014\"]\n\n[sources]\n# Deny crates from unknown registries or git repositories.\nunknown-registry = \"deny\"\nunknown-git = \"deny\"\n\nallow-git = [\n    # The settings SDK is currently provided as a git dependency,\n    # We will allow it as an exception until the following is resolved:\n    # https://github.com/bottlerocket-os/bottlerocket-settings-sdk/issues/18\n    \"https://github.com/bottlerocket-os/bottlerocket-settings-sdk\",\n]\n"
  },
  {
    "path": "sources/generate-readme/Cargo.toml",
    "content": "[package]\nname = \"generate-readme\"\nversion = \"0.1.0\"\nauthors = [\"Matt Briggs <brigmatt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n\n[dependencies]\ncargo-readme.workspace = true\nsnafu.workspace = true\n"
  },
  {
    "path": "sources/generate-readme/src/lib.rs",
    "content": "/*!\nThis small lib is used to generate README files for the crates in the `sources` workspace. These\nfunctions are called in a crate's build.rs file to generate a README from Rust doc comments.\n!*/\n\nuse snafu::ResultExt;\nuse std::fs::File;\nuse std::io::Write;\nuse std::path::{Path, PathBuf};\n\npub type Result<T> = std::result::Result<T, error::Error>;\n\npub mod error {\n    use snafu::Snafu;\n    use std::path::PathBuf;\n\n    #[derive(Debug, Snafu)]\n    #[snafu(visibility(pub(super)))]\n    pub enum Error {\n        #[snafu(display(\"Unable to create the 'README.md' file: {}\", source))]\n        ReadmeCreate { source: std::io::Error },\n\n        #[snafu(display(\"Unable to generate the 'README.md' file contents: {}\", error))]\n        ReadmeGenerate { error: String },\n\n        #[snafu(display(\"Unable to open '{}': {}\", file.display(), source))]\n        ReadmeSourceOpen {\n            file: PathBuf,\n            source: std::io::Error,\n        },\n\n        #[snafu(display(\"Unable to open 'README.tpl': {}\", source))]\n        ReadmeTemplateOpen { source: std::io::Error },\n\n        #[snafu(display(\"Unable to write to the 'README.md' file: {}\", source))]\n        ReadmeWrite { source: std::io::Error },\n    }\n}\n\n/// When this function is called in a `build.rs` file, it will generate a `README.md` (as a sibling\n/// to `build.rs`). It uses the doc comments found in `src/main.rs` and the `cargo-readme` crate to\n/// do so. The template for `cargo-readme` is expected to be `README.tpl` as a sibling file to\n/// `build.rs`.\npub fn from_main() -> Result<()> {\n    from_file(\"src/main.rs\")\n}\n\n/// When this function is called in a `build.rs` file, it will generate a `README.md` (as a sibling\n/// to `build.rs`). It uses the doc comments found in `src/lib.rs` and the `cargo-readme` crate to\n/// do so. The template for `cargo-readme` is expected to be `README.tpl` as a sibling file to\n/// `build.rs`.\npub fn from_lib() -> Result<()> {\n    from_file(\"src/lib.rs\")\n}\n\n/// When this function is called in a `build.rs` file, it will generate a `README.md` (as a sibling\n/// to `build.rs`). It uses the doc comments found in `rust_file` and the `cargo-readme` crate to do\n/// so. The template for `cargo-readme` is expected to be `README.tpl` as a sibling file to\n/// `build.rs`.\npub fn from_file<P>(rust_file: P) -> Result<()>\nwhere\n    P: AsRef<Path>,\n{\n    // Check for environment variable \"SKIP_README\". If it is set,\n    // skip README generation\n    if std::env::var_os(\"SKIP_README\").is_some() {\n        return Ok(());\n    }\n\n    let mut source = File::open(rust_file.as_ref()).context(error::ReadmeSourceOpenSnafu {\n        file: rust_file.as_ref(),\n    })?;\n    let mut template = File::open(\"README.tpl\").context(error::ReadmeTemplateOpenSnafu)?;\n\n    let mut content = cargo_readme::generate_readme(\n        &PathBuf::from(\".\"), // root\n        &mut source,         // source\n        Some(&mut template), // template\n        // The \"add x\" arguments don't apply when using a template.\n        true,  // add title\n        false, // add badges\n        false, // add license\n        true,  // indent headings\n    )\n    .map_err(|e| error::ReadmeGenerateSnafu { error: e }.build())?;\n\n    // Make sure the end of the file has a newline\n    if content.chars().last().unwrap_or_default() != '\\n' {\n        content += \"\\n\";\n    }\n\n    let mut readme = File::create(\"README.md\").context(error::ReadmeCreateSnafu)?;\n    readme\n        .write_all(content.as_bytes())\n        .context(error::ReadmeWriteSnafu)?;\n    Ok(())\n}\n"
  },
  {
    "path": "sources/models/.gitignore",
    "content": "/src/variant/current\n/src/variant/mod.rs\n"
  },
  {
    "path": "sources/models/Cargo.toml",
    "content": "[package]\nname = \"models\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nbuild = \"build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nbottlerocket-release.workspace = true\nlibc.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nserde_json.workspace = true\nserde_plain.workspace = true\ntoml.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n\n[build-dependencies]\ngenerate-readme.workspace = true\n\n[lib]\n# We're loading the correct *model* at runtime, so users shouldn't think about\n# importing *models* (plural), just the one current model.\nname = \"model\"\npath = \"src/lib.rs\"\n"
  },
  {
    "path": "sources/models/README.md",
    "content": "# models\n\nCurrent version: 0.1.0\n\n## API models\n\nBottlerocket has different variants supporting different features and use cases.\nEach variant has its own set of software, and therefore needs its own configuration.\nWe support having an API model for each variant to support these different configurations.\n\nThe model here defines a top-level `Settings` structure, and delegates the actual implementation to a [\"settings plugin\"](https://github.com/bottlerocket-os/bottlerocket-settings-sdk/tree/develop/bottlerocket-settings-plugin).\nSettings plugin are written in Rust as a \"cdylib\" crate, and loaded at runtime.\n\nEach settings plugin must define its own private `Settings` structure.\nIt can use pre-defined structures inside, or custom ones as needed.\n\n`apiserver::datastore` offers serialization and deserialization modules that make it easy to map between Rust types and the data store, and thus, all inputs and outputs are type-checked.\n\nAt the field level, standard Rust types can be used, or [\"modeled types\"](https://github.com/bottlerocket-os/bottlerocket-settings-sdk/tree/develop/bottlerocket-settings-models/modeled-types) that add input validation.\n\nThe `#[model]` attribute on Settings and its sub-structs reduces duplication and adds some required metadata; see [its docs](model-derive/) for details.\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/models/README.tpl",
    "content": "# {{crate}}\n\nCurrent version: {{version}}\n\n{{readme}}\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/models/build.rs",
    "content": "fn main() {\n    generate_readme::from_lib().unwrap();\n}\n"
  },
  {
    "path": "sources/models/src/exec.rs",
    "content": "//! The 'exec' module holds types used to communicate between client and server for\n//! 'apiclient exec'.\nuse libc::winsize as WinSize;\nuse serde::{Deserialize, Serialize};\nuse std::ffi::OsString;\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// Server messages to client.\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub enum ServerMessage {\n    Capacity(Capacity),\n}\n\n/// A capacity update; this tells the client how many writes the server has completed so the client\n/// can figure out how many more input messages it can read and send.\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct Capacity {\n    /// The maximum number of messages the server is willing to have outstanding before it\n    /// terminates the client.\n    pub max_messages_outstanding: u64,\n    /// The number of input messages the server has successfully written to the child process.\n    pub messages_written: u64,\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n\n/// Client messages to server.\n#[derive(Debug, Clone, Deserialize, Serialize)]\npub enum ClientMessage {\n    // It'd be nice to include initialization parameters in the initial HTTP request body, but not\n    // all WebSocket clients support data there.\n    Initialize(Initialize),\n    ContentComplete,\n    Winch(Size),\n}\n\n/// Tells the server how to initialize the command the user is requesting.\n#[derive(Debug, Clone, Deserialize, Serialize)]\npub struct Initialize {\n    /// What command (and arguments) to run.\n    pub command: Vec<OsString>,\n    /// What container (task) to run the command in.\n    pub target: String,\n    /// Whether the user wants a TTY.\n    pub tty: Option<TtyInit>,\n}\n\n/// If the user wants a TTY, these are the initial parameters the TTY should be set up with.\n#[derive(Debug, Clone, Deserialize, Serialize)]\npub struct TtyInit {\n    /// Initial size of the TTY window.\n    pub size: Option<Size>,\n}\n\n// =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=   =^..^=\n// Helper types\n\n// Note: nix::pty::Winsize == libc::winsize.\n// WinSize doesn't support serde, so we make a slim wrapper.\n/// Size of the terminal window.\n#[derive(Debug, Copy, Clone, Deserialize, Serialize)]\npub struct Size {\n    pub rows: u16,\n    pub cols: u16,\n}\n\nimpl From<Size> for WinSize {\n    fn from(size: Size) -> Self {\n        Self {\n            ws_row: size.rows,\n            ws_col: size.cols,\n            ws_xpixel: 0,\n            ws_ypixel: 0,\n        }\n    }\n}\n\nimpl From<WinSize> for Size {\n    fn from(winsize: WinSize) -> Self {\n        Self {\n            rows: winsize.ws_row,\n            cols: winsize.ws_col,\n        }\n    }\n}\n"
  },
  {
    "path": "sources/models/src/generator.rs",
    "content": "//! The 'generator' module holds types that handles the settings generator metadata\n//! definition (containing command, strength and depth) among various systems\n//! like apiserver, sundog, datastore.\n//!\n//! The command field defines the command that needs to be executed to populate the\n//! setting.\n//! The strength field defines whether a setting needs to be deleted on reboot.\n//! The depth field defines how metadata is inherited across hierarchical levels,\n//! allowing a parent to provide metadata that can be applied at children at a given depth.\n//!\n//! SettingsGenerator type is used to hold generator that is applied strictly\n//! to the given setting and have depth 0.\n//! The RawSettingsGenerator holds the generators that can be dynamically applied\n//! to the successors at the given depth where a depth '0' means the generator\n//! should be applied on the given key.\n//!\n//! We use a custom deserializer because the metadata may not always be\n//! structured as an object; it can also appear as a string. This deserializer\n//! handles both formats, keeping the deserialization logic close to the struct\n//! for maintainability and clarity.\n\nuse serde::{\n    de::{self, MapAccess, Visitor},\n    Deserialize, Deserializer, Serialize,\n};\nuse serde_plain::derive_fromstr_from_deserialize;\nuse std::fmt::{self, Display};\n\n/// Weak settings are ephemeral and deleted on upgrade/downgrade, regardless of whether or not it\n/// is written by a setting generator.\n#[derive(Default, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]\n#[serde(rename_all = \"kebab-case\")]\npub enum Strength {\n    #[default]\n    Strong,\n    Weak,\n}\n\nimpl Display for Strength {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Strength::Strong => write!(f, \"strong\"),\n            Strength::Weak => write!(f, \"weak\"),\n        }\n    }\n}\n\nderive_fromstr_from_deserialize!(Strength);\n\n/// Struct to hold the setting generator definition containing\n/// command, strength, depth\n#[derive(Clone, Default, Serialize, Debug, PartialEq)]\n#[serde(rename_all = \"kebab-case\", deny_unknown_fields)]\npub struct RawSettingsGenerator {\n    pub command: String,\n    pub strength: Strength,\n    pub depth: u32,\n}\n\nimpl RawSettingsGenerator {\n    pub fn is_weak(&self) -> bool {\n        self.strength == Strength::Weak\n    }\n}\n\nimpl<'de> Deserialize<'de> for RawSettingsGenerator {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        struct SettingsGeneratorVisitor;\n        impl<'de> Visitor<'de> for SettingsGeneratorVisitor {\n            type Value = RawSettingsGenerator;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a string or a map\")\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                // If the value is a string, use it as the `command` with defaults for other fields.\n                Ok(RawSettingsGenerator {\n                    command: value.to_string(),\n                    ..RawSettingsGenerator::default()\n                })\n            }\n\n            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>\n            where\n                M: MapAccess<'de>,\n            {\n                // Extract values from the map\n                let mut command = None;\n                let mut strength = None;\n                let mut depth = None;\n                while let Some(key) = map.next_key::<String>()? {\n                    match key.as_str() {\n                        \"command\" => command = Some(map.next_value()?),\n                        \"strength\" => strength = Some(map.next_value()?),\n                        \"depth\" => depth = Some(map.next_value()?),\n                        _ => {\n                            return Err(de::Error::unknown_field(\n                                &key,\n                                &[\"command\", \"strength\", \"depth\"],\n                            ))\n                        }\n                    }\n                }\n                Ok(RawSettingsGenerator {\n                    command: command.ok_or_else(|| de::Error::missing_field(\"command\"))?,\n                    strength: strength.unwrap_or_default(),\n                    depth: depth.unwrap_or_default(),\n                })\n            }\n        }\n        deserializer.deserialize_any(SettingsGeneratorVisitor)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use std::collections::HashMap;\n\n    use super::*;\n\n    #[test]\n    fn test_setting_generator_deserialization() {\n        let api_response = r#\"\n            {\n                \"host-containers.admin.source\": \"generator1\",\n                \"host-containers.control.source\": {\n                    \"command\": \"generator2\",\n                    \"strength\": \"weak\",\n                    \"depth\": 0\n                },\n                \"host-containers.no_depth.source\": {\n                    \"command\": \"generator3\",\n                    \"strength\": \"weak\"\n                },\n                \"host-containers.depth_given.source\": {\n                    \"command\": \"generator4\",\n                    \"strength\": \"weak\",\n                    \"depth\": 1\n                }\n            }\"#;\n\n        let expected_admin = RawSettingsGenerator {\n            command: \"generator1\".to_string(),\n            strength: Strength::Strong,\n            depth: 0,\n        };\n\n        let expected_control = RawSettingsGenerator {\n            command: \"generator2\".to_string(),\n            strength: Strength::Weak,\n            depth: 0,\n        };\n\n        let expected_no_depth = RawSettingsGenerator {\n            command: \"generator3\".to_string(),\n            strength: Strength::Weak,\n            depth: 0,\n        };\n\n        let expected_depth_given = RawSettingsGenerator {\n            command: \"generator4\".to_string(),\n            strength: Strength::Weak,\n            depth: 1,\n        };\n\n        let result: HashMap<String, RawSettingsGenerator> =\n            serde_json::from_str(api_response).unwrap();\n\n        assert_eq!(\n            result.get(\"host-containers.admin.source\").unwrap(),\n            &expected_admin\n        );\n        assert_eq!(\n            result.get(\"host-containers.control.source\").unwrap(),\n            &expected_control\n        );\n        assert_eq!(\n            result.get(\"host-containers.no_depth.source\").unwrap(),\n            &expected_no_depth\n        );\n        assert_eq!(\n            result.get(\"host-containers.depth_given.source\").unwrap(),\n            &expected_depth_given\n        );\n    }\n}\n\n/// Struct to hold the setting generator definition containing\n/// command, strength\n#[derive(Default, Serialize, std::fmt::Debug, PartialEq)]\npub struct SettingsGenerator {\n    pub command: String,\n    pub strength: Strength,\n}\n\nimpl From<RawSettingsGenerator> for SettingsGenerator {\n    fn from(value: RawSettingsGenerator) -> Self {\n        SettingsGenerator {\n            command: value.command,\n            strength: value.strength,\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for SettingsGenerator {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        struct SettingsGeneratorVisitor;\n        impl<'de> Visitor<'de> for SettingsGeneratorVisitor {\n            type Value = SettingsGenerator;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a string or a map\")\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                // If the value is a string, use it as the `command` with defaults for other fields.\n                Ok(SettingsGenerator {\n                    command: value.to_string(),\n                    ..SettingsGenerator::default()\n                })\n            }\n\n            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>\n            where\n                M: MapAccess<'de>,\n            {\n                // Extract values from the map\n                let mut command = None;\n                let mut strength = None;\n                while let Some(key) = map.next_key::<String>()? {\n                    match key.as_str() {\n                        \"command\" => command = Some(map.next_value()?),\n                        \"strength\" => strength = Some(map.next_value()?),\n                        _ => return Err(de::Error::unknown_field(&key, &[\"command\", \"strength\"])),\n                    }\n                }\n                Ok(SettingsGenerator {\n                    command: command.ok_or_else(|| de::Error::missing_field(\"command\"))?,\n                    strength: strength.unwrap_or_default(),\n                })\n            }\n        }\n        deserializer.deserialize_any(SettingsGeneratorVisitor)\n    }\n}\n"
  },
  {
    "path": "sources/models/src/lib.rs",
    "content": "/*!\n# API models\n\nBottlerocket has different variants supporting different features and use cases.\nEach variant has its own set of software, and therefore needs its own configuration.\nWe support having an API model for each variant to support these different configurations.\n\nThe model here defines a top-level `Settings` structure, and delegates the actual implementation to a [\"settings plugin\"](https://github.com/bottlerocket-os/bottlerocket-settings-sdk/tree/develop/bottlerocket-settings-plugin).\nSettings plugin are written in Rust as a \"cdylib\" crate, and loaded at runtime.\n\nEach settings plugin must define its own private `Settings` structure.\nIt can use pre-defined structures inside, or custom ones as needed.\n\n`apiserver::datastore` offers serialization and deserialization modules that make it easy to map between Rust types and the data store, and thus, all inputs and outputs are type-checked.\n\nAt the field level, standard Rust types can be used, or [\"modeled types\"](https://github.com/bottlerocket-os/bottlerocket-settings-sdk/tree/develop/bottlerocket-settings-models/modeled-types) that add input validation.\n\nThe `#[model]` attribute on Settings and its sub-structs reduces duplication and adds some required metadata; see [its docs](model-derive/) for details.\n*/\n\n// Types used to communicate between client and server for 'apiclient exec'.\npub mod exec;\n\n// Types used to handle the settings generator metadata among various systems\npub mod generator;\n\nuse bottlerocket_release::BottlerocketRelease;\nuse bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::BottlerocketSettings;\nuse serde::{Deserialize, Serialize};\nuse std::collections::HashMap;\n\nuse bottlerocket_settings_models::modeled_types::SingleLineString;\n\n#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct Settings {\n    inner: BottlerocketSettings,\n}\n\n// This is the top-level model exposed by the API system. It contains the common sections for all\n// variants.  This allows a single API call to retrieve everything the API system knows, which is\n// useful as a check and also, for example, as a data source for templated configuration files.\n#[model]\npub struct Model {\n    settings: Settings,\n    services: Services,\n    configuration_files: ConfigurationFiles,\n    os: BottlerocketRelease,\n}\n\n///// Internal services\n\n// Note: Top-level objects that get returned from the API should have a \"rename\" attribute\n// matching the struct name, but in kebab-case, e.g. ConfigurationFiles -> \"configuration-files\".\n// This lets it match the datastore name.\n// Objects that live inside those top-level objects, e.g. Service lives in Services, should have\n// rename=\"\" so they don't add an extra prefix to the datastore path that doesn't actually exist.\n// This is important because we have APIs that can return those sub-structures directly.\n\npub type Services = HashMap<String, Service>;\n\n#[model(add_option = false, rename = \"\")]\nstruct Service {\n    configuration_files: Vec<SingleLineString>,\n    restart_commands: Vec<String>,\n}\n\npub type ConfigurationFiles = HashMap<String, ConfigurationFile>;\n\n#[model(add_option = false, rename = \"\")]\nstruct ConfigurationFile {\n    path: SingleLineString,\n    template_path: SingleLineString,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    mode: Option<String>,\n}\n\n///// Metadata\n\n#[model(add_option = false, rename = \"metadata\")]\nstruct Metadata {\n    key: SingleLineString,\n    md: SingleLineString,\n    val: toml::Value,\n}\n\n#[model(add_option = false)]\nstruct Report {\n    name: String,\n    description: String,\n}\n"
  },
  {
    "path": "sources/models/src/variant/.keep",
    "content": "FIXME: this directory is no longer needed for builds, but can't be removed yet\nbecause Twoliter expects it to exist.\n"
  },
  {
    "path": "sources/retry-read/Cargo.toml",
    "content": "[package]\nname = \"retry-read\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[build-dependencies]\ngenerate-readme.workspace = true\n"
  },
  {
    "path": "sources/retry-read/README.md",
    "content": "# retry-read\n\nCurrent version: 0.1.0\n\nThis library provides a `RetryRead` trait with a `retry_read` function that's available for any\n`Read` type.  `retry_read` retries after standard interruptions (unlike `read`) but also\nreturns the number of bytes read (unlike `read_exact`), and without needing to read to the end\nof the input (unlike `read_to_end` and `read_to_string`).\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/retry-read/README.tpl",
    "content": "# {{crate}}\n\nCurrent version: {{version}}\n\n{{readme}}\n\n## Colophon\n\nThis text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.\n"
  },
  {
    "path": "sources/retry-read/build.rs",
    "content": "fn main() {\n    generate_readme::from_lib().unwrap();\n}\n"
  },
  {
    "path": "sources/retry-read/src/lib.rs",
    "content": "//! This library provides a `RetryRead` trait with a `retry_read` function that's available for any\n//! `Read` type.  `retry_read` retries after standard interruptions (unlike `read`) but also\n//! returns the number of bytes read (unlike `read_exact`), and without needing to read to the end\n//! of the input (unlike `read_to_end` and `read_to_string`).\n\nuse std::io::{ErrorKind, Read, Result};\n\n/// Provides a way to retry standard read operations while also returning the number of bytes read.\npub trait RetryRead<R> {\n    fn retry_read(&mut self, buf: &mut [u8]) -> Result<usize>;\n}\n\nimpl<R: Read> RetryRead<R> for R {\n    // This implementation is based on stdlib Read::read_exact, but hitting EOF isn't a failure, we\n    // just want to return the number of bytes we could read.\n    /// Like `Read::read` but retries on ErrorKind::Interrupted, returning the number of bytes read.\n    fn retry_read(&mut self, mut buf: &mut [u8]) -> Result<usize> {\n        let mut count = 0;\n\n        // Read until we have no more space in the output buffer\n        while !buf.is_empty() {\n            match self.read(buf) {\n                // No bytes left, done\n                Ok(0) => break,\n                // Read n bytes, slide ahead n in the output buffer and read more\n                Ok(n) => {\n                    count += n;\n                    let tmp = buf;\n                    buf = &mut tmp[n..];\n                }\n                // Retry on interrupt\n                Err(e) if e.kind() == ErrorKind::Interrupted => {}\n                // Other failures are fatal\n                Err(e) => return Err(e),\n            }\n        }\n\n        Ok(count)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::{ErrorKind, Read, Result, RetryRead};\n    use std::io::{Error, Write};\n\n    // Helper method for simple test cases, confirming we read the full given slice.\n    fn test(data: &[u8]) {\n        let mut output = vec![0; data.len()];\n        let count = (&data[..]).retry_read(&mut output).unwrap();\n        assert_eq!(count, data.len());\n        assert_eq!(data, &output);\n    }\n\n    #[test]\n    fn zero_read() {\n        test(&[]);\n    }\n\n    #[test]\n    fn small_read() {\n        test(&[0, 1, 2, 3, 42]);\n    }\n\n    #[test]\n    fn large_read() {\n        test(&[42; 9999]);\n    }\n\n    // Confirm we retry reads when interrupted.\n    #[test]\n    fn retried_read() {\n        let mut reader = InterruptedReader::new(5);\n        let mut output = vec![0; 5];\n        let count = reader.retry_read(&mut output).unwrap();\n        assert_eq!(count, 5);\n        assert_eq!(output, vec![42, 42, 42, 42, 42]);\n    }\n\n    // Helper that implements Read, eventually returning the requested number of bytes, but returns\n    // ErrorKind::Interrupted every other call.\n    struct InterruptedReader {\n        requested_reads: u64,\n        finished_reads: u64,\n        interrupt: bool,\n    }\n\n    impl InterruptedReader {\n        fn new(requested_reads: u64) -> Self {\n            Self {\n                requested_reads,\n                finished_reads: 0,\n                interrupt: false,\n            }\n        }\n    }\n\n    impl Read for InterruptedReader {\n        fn read(&mut self, mut buf: &mut [u8]) -> Result<usize> {\n            if self.finished_reads > self.requested_reads {\n                return Ok(0);\n            }\n\n            if self.interrupt {\n                self.interrupt = false;\n                Err(Error::new(ErrorKind::Interrupted, \"you asked for it\"))\n            } else {\n                self.interrupt = true;\n                self.finished_reads += 1;\n                buf.write(&[42])\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sources/settings-defaults/aws-dev/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-dev/defaults.d/50-aws-dev.toml",
    "content": "# Metrics\n[settings.metrics]\nsend-metrics = false\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"docker\"]\n\n# Network\n[metadata.settings.network]\naffected-services = [\"containerd\", \"docker\", \"host-containerd\", \"host-containers\", \"updog\"]\n"
  },
  {
    "path": "sources/settings-defaults/aws-ecs-2/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-ecs-2\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-ecs-2-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-ecs-2-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-ecs-3/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-ecs-3\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-ecs-3-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-ecs-3-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.31/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_31\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.31-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_31-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.32/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_32\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.32-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_32-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.33/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_33\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.33-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_33-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.34/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_34\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.34-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_34-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.35/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_35\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/aws-k8s-1.35-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-aws-k8s-1_35-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/build-defaults.rs",
    "content": "fn main() {\n    bottlerocket_defaults_helper::generate_defaults_toml().unwrap();\n}\n"
  },
  {
    "path": "sources/settings-defaults/defaults-toml.rs",
    "content": "// This \"crate\" only generates a defaults.toml as a side effect of the build.\n"
  },
  {
    "path": "sources/settings-defaults/metal-dev/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-metal-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/metal-dev/defaults.d/50-metal-dev.toml",
    "content": "# Metrics\n[settings.metrics]\nsend-metrics = false\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"docker\"]\n\n# Network\n[metadata.settings.network]\naffected-services = [\"containerd\", \"docker\", \"host-containerd\", \"host-containers\", \"updog\"]\n"
  },
  {
    "path": "sources/settings-defaults/metal-k8s-1.30/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-metal-k8s-1_30\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/vmware-dev/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-vmware-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/vmware-dev/defaults.d/50-vmware-dev.toml",
    "content": "# Metrics\n[settings.metrics]\nsend-metrics = false\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"docker\", \"vmtoolsd\"]\n\n# Network\n[metadata.settings.network]\naffected-services = [\"containerd\", \"docker\", \"host-containerd\", \"host-containers\", \"updog\"]\n"
  },
  {
    "path": "sources/settings-defaults/vmware-k8s-1.32/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-vmware-k8s-1_32\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/vmware-k8s-1.33/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-vmware-k8s-1_33\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/vmware-k8s-1.34/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-vmware-k8s-1_34\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-defaults/vmware-k8s-1.35/Cargo.toml",
    "content": "[package]\nname = \"settings-defaults-vmware-k8s-1_35\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nbuild = \"../build-defaults.rs\"\n\n[lib]\npath = \"../defaults-toml.rs\"\n\n[build-dependencies]\nbottlerocket-defaults-helper.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/.keep",
    "content": ""
  },
  {
    "path": "sources/settings-migrations/archived/v0.3.2/migrate-admin-container-v0-5-0/Cargo.toml",
    "content": "[package]\nname = \"migrate-admin-container-v0-5-0\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.3.2/migrate-admin-container-v0-5-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-admin:v0.4.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-admin:v0.5.0\";\n\n/// We bumped the version of the default admin container from v0.4.0 to v0.5.0\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.4.1/add-version-lock-ignore-waves/Cargo.toml",
    "content": "[package]\nname = \"add-version-lock-ignore-waves\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.4.1/add-version-lock-ignore-waves/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings, `updates.version-lock` and `updates.ignore-waves`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.updates.version-lock\",\n        \"settings.updates.ignore-waves\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.4.1/pivot-repo-2020-07-07/Cargo.toml",
    "content": "[package]\nname = \"pivot-repo-2020-07-07\"\nversion = \"0.1.0\"\nauthors = [\"Jamie Anderson <jamieand@amazon.com\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.4.1/pivot-repo-2020-07-07/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst BEFORE_PIVOT_REPO_URL: &str =\n    \"https://updates.bottlerocket.aws/2020-02-02/{{ os.variant_id }}/{{ os.arch }}/\";\nconst AFTER_PIVOT_REPO_URL: &str =\n    \"https://updates.bottlerocket.aws/2020-07-07/{{ os.variant_id }}/{{ os.arch }}/\";\n\n/// Starting with v0.4.1 we use a new set of repos that does not contain\n/// unsigned migrations\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.updates.metadata-base-url\",\n        old_template: BEFORE_PIVOT_REPO_URL,\n        new_template: AFTER_PIVOT_REPO_URL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.5.0/add-cluster-domain/Cargo.toml",
    "content": "[package]\nname = \"add-cluster-domain\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.5.0/add-cluster-domain/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting, `kubernetes.cluster-domain`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.cluster-domain\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.5.0/migrate-admin-container-v0-5-2/Cargo.toml",
    "content": "[package]\nname = \"migrate-admin-container-v0-5-2\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.5.0/migrate-admin-container-v0-5-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-admin:v0.5.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-admin:v0.5.2\";\n\n/// We bumped the version of the default admin container from v0.5.0 to v0.5.2\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.5.0/migrate-control-container-v0-4-1/Cargo.toml",
    "content": "[package]\nname = \"migrate-control-container-v0-4-1\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v0.5.0/migrate-control-container-v0-4-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-control:v0.4.0\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-control:v0.4.1\";\n\n/// We bumped the version of the default control container from v0.4.0 to v0.4.1\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.0/ecr-helper-admin/Cargo.toml",
    "content": "[package]\nname = \"ecr-helper-admin\"\nversion = \"0.1.0\"\nauthors = [\"Matt Briggs <brigmatt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.0/ecr-helper-admin/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-admin:v0.5.2\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.5.2\";\n\n/// We added a helper to lookup an ECR registry number by region.\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.0/ecr-helper-control/Cargo.toml",
    "content": "[package]\nname = \"ecr-helper-control\"\nversion = \"0.1.0\"\nauthors = [\"Matt Briggs <brigmatt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.0/ecr-helper-control/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"328549459982.dkr.ecr.{{ settings.aws.region }}.amazonaws.com/bottlerocket-control:v0.4.1\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.4.1\";\n\n/// We added a helper to lookup an ECR registry number by region.\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"metadata.settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.2/add-enable-spot-instance-draining/Cargo.toml",
    "content": "[package]\nname = \"add-enable-spot-instance-draining\"\nversion = \"0.1.0\"\nauthors = [\"Magnus Kulke <mkulke@gmail.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.2/add-enable-spot-instance-draining/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting, `ecs.enable-spot-instance-draining`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.ecs.enable-spot-instance-draining\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.3/add-sysctl/Cargo.toml",
    "content": "[package]\nname = \"add-sysctl\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.3/add-sysctl/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added the ability to set sysctl keys via API settings.  We don't want to track all possible\n/// Linux sysctl keys, so we remove the whole prefix if we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kernel.sysctl\",\n        \"services.sysctl\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-lockdown/Cargo.toml",
    "content": "[package]\nname = \"add-lockdown\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-lockdown/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added the ability to set kernel lockdown mode through a setting, so on downgrade we need to\n/// remove the setting and the associated settings for the service that writes out changes.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kernel.lockdown\",\n        \"services.lockdown\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-network-settings/Cargo.toml",
    "content": "[package]\nname = \"add-network-settings\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-network-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a set of settings for configuring service network behavior and their associated\n/// configuration file. Remove the whole `settings.network`, `configuration-files.proxy-env` prefix\n/// if we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.network\",\n        \"configuration-files.proxy-env\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-proxy-restart/Cargo.toml",
    "content": "[package]\nname = \"add-proxy-restart\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-proxy-restart/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the restart-commands and configuration-files settings for several existing services.\n/// We need to replace them upon downgrades and upgrades\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![\n        ListReplacement {\n            setting: \"services.containerd.configuration-files\",\n            old_vals: &[\"containerd-config-toml\"],\n            new_vals: &[\"containerd-config-toml\", \"proxy-env\"],\n        },\n        ListReplacement {\n            setting: \"services.containerd.restart-commands\",\n            old_vals: &[],\n            new_vals: &[\"/bin/systemctl try-restart containerd.service\"],\n        },\n        ListReplacement {\n            setting: \"services.kubernetes.configuration-files\",\n            old_vals: &[\n                \"kubelet-env\",\n                \"kubelet-config\",\n                \"kubelet-kubeconfig\",\n                \"kubernetes-ca-crt\",\n            ],\n            new_vals: &[\n                \"kubelet-env\",\n                \"kubelet-config\",\n                \"kubelet-kubeconfig\",\n                \"kubernetes-ca-crt\",\n                \"proxy-env\",\n            ],\n        },\n        ListReplacement {\n            setting: \"services.kubernetes.restart-commands\",\n            old_vals: &[],\n            new_vals: &[\"/bin/systemctl try-restart kubelet.service\"],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-proxy-services/Cargo.toml",
    "content": "[package]\nname = \"add-proxy-services\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-proxy-services/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new configuration files and restart commands for docker and host-containerd.\n/// On downgrade we need to remove all settings under these services\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"services.docker\",\n        \"services.host-containerd\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-user-data/Cargo.toml",
    "content": "[package]\nname = \"add-user-data\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/add-user-data/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\n/// This migration removes host-container user data settings when downgrading to versions that\n/// don't understand them.\npub struct AddUserDataMigration;\n\nimpl Migration for AddUserDataMigration {\n    /// There's no user data by default, it's just left empty on upgrade.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"AddUserDataMigration has no work to do on upgrade.\");\n        Ok(input)\n    }\n\n    /// Older versions don't know about the user-data settings; we remove them so that old versions\n    /// don't see them and fail deserialization.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for setting in input.data.clone().keys() {\n            // We don't currently have structured data available to migrations, and we don't want\n            // to re-parse keys.  We know no other keys could match these basic patterns.\n            if setting.starts_with(\"settings.host-containers.\") && setting.ends_with(\".user-data\") {\n                if let Some(data) = input.data.remove(setting) {\n                    println!(\"Removed {}, which was set to '{}'\", setting, data);\n                }\n            }\n        }\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    migrate(AddUserDataMigration)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/sysctl-subcommand/Cargo.toml",
    "content": "[package]\nname = \"sysctl-subcommand\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.5/sysctl-subcommand/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We changed corndog to use subcommands so it can handle different kernel settings without having\n/// to apply them all every time.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.sysctl.restart-commands\",\n        old_vals: &[\"/usr/bin/corndog\"],\n        new_vals: &[\"/usr/bin/corndog sysctl\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/add-shibaken/Cargo.toml",
    "content": "[package]\nname = \"add-shibaken\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/add-shibaken/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting metadata, `host-containers.admin.user-data.setting-generator`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"setting-generator\"],\n        setting: \"settings.host-containers.admin.user-data\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/add-static-pods/Cargo.toml",
    "content": "[package]\nname = \"add-static-pods\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/add-static-pods/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for defining k8s static pods.\n/// Remove `settings.kubernetes.static-pods`, `services.static-pods` prefixes when we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.static-pods\",\n        \"services.static-pods\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/admin-container-v0-6-0/Cargo.toml",
    "content": "[package]\nname = \"admin-container-v0-6-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/admin-container-v0-6-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.5.2\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.6.0\";\n\n/// We bumped the version of the default admin container from v0.5.2 to v0.6.0\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/control-container-v0-4-2/Cargo.toml",
    "content": "[package]\nname = \"control-container-v0-4-2\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/control-container-v0-4-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.4.1\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.4.2\";\n\n\n/// We bumped the version of the default control container from v0.4.1 to v0.4.2\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/kubelet-standalone-tls-services/Cargo.toml",
    "content": "[package]\nname = \"kubelet-standalone-tls-services\"\nversion = \"0.1.0\"\nauthors = [\"Ben Cressey <bcressey@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/kubelet-standalone-tls-services/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the configuration files and restart commands to support running kubelet in\n/// standalone mode, and for configuring it to use TLS auth. They need to be restored to\n/// the prior values on downgrade.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![\n        ListReplacement {\n            setting: \"services.kubernetes.configuration-files\",\n            old_vals: &[\n                \"kubelet-env\",\n                \"kubelet-config\",\n                \"kubelet-kubeconfig\",\n                \"kubernetes-ca-crt\",\n                \"proxy-env\",\n            ],\n            new_vals: &[\n                \"kubelet-env\",\n                \"kubelet-config\",\n                \"kubelet-kubeconfig\",\n                \"kubelet-bootstrap-kubeconfig\",\n                \"kubelet-exec-start-conf\",\n                \"kubernetes-ca-crt\",\n                \"proxy-env\",\n            ],\n        },\n        ListReplacement {\n            setting: \"services.kubernetes.restart-commands\",\n            old_vals: &[\"/bin/systemctl try-restart kubelet.service\"],\n            new_vals: &[\n                \"/usr/bin/systemctl daemon-reload\",\n                \"/bin/systemctl try-restart kubelet.service\",\n            ],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/kubelet-standalone-tls-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-standalone-tls-settings\"\nversion = \"0.1.0\"\nauthors = [\"Ben Cressey <bcressey@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/kubelet-standalone-tls-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for running kubelet in standalone mode, and for using TLS auth.\n/// We also added new configuration files to apply these settings. They need to be removed\n/// when we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.bootstrap-token\",\n        \"settings.kubernetes.authentication-mode\",\n        \"settings.kubernetes.standalone-mode\",\n        \"configuration-files.kubelet-bootstrap-kubeconfig\",\n        \"configuration-files.kubelet-exec-start-conf\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/metricdog-init/Cargo.toml",
    "content": "[package]\nname = \"metricdog-init\"\nversion = \"0.1.0\"\nauthors = [\"Matt Briggs <brigmatt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.6/metricdog-init/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// Add settings for the new `metricdog` program.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.metrics\",\n        \"services.metricdog\",\n        \"configuration-files.metricdog\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/add-bootstrap-containers/Cargo.toml",
    "content": "[package]\nname = \"add-bootstrap-containers\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/add-bootstrap-containers/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added the setting `bootstrap-containers`\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.bootstrap-containers\",\n        \"services.bootstrap-containers\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/admin-container-v0-7-0/Cargo.toml",
    "content": "[package]\nname = \"admin-container-v0-7-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/admin-container-v0-7-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.6.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.0\";\n\n/// We bumped the version of the default admin container from v0.6.0 to v0.7.0\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/control-container-v0-5-0/Cargo.toml",
    "content": "[package]\nname = \"control-container-v0-5-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/control-container-v0-5-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.4.2\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.0\";\n\n/// We bumped the version of the default control container from v0.4.2 to v0.5.0\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/kubelet-eviction-hard/Cargo.toml",
    "content": "[package]\nname = \"kubelet-eviction-hard\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/kubelet-eviction-hard/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new settings for configuring kubelet,`settings.kubernetes.eviction-hard`.\n/// We don't want to track all possible keys for these settings,\n/// so we remove the whole prefix when we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.eviction-hard\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/kubelet-unsafe-sysctl-kube-reserved/Cargo.toml",
    "content": "[package]\nname = \"kubelet-unsafe-sysctl-kube-reserved\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/kubelet-unsafe-sysctl-kube-reserved/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings for configuring kubelet, `kubernetes.allowed-unsafe-sysctls`\n/// `kubernetes.kube-reserved`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.allowed-unsafe-sysctls\",\n        \"settings.kubernetes.kube-reserved\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/proxy-affect-host-containers/Cargo.toml",
    "content": "[package]\nname = \"proxy-affect-host-containers\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.0.8/proxy-affect-host-containers/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.network' to include\n/// host-containers. The metadata list need to be restored to the prior value on downgrade and\n/// updated to include host-containers on upgrades.\n/// We're trying to match old values for different variants.\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\"containerd\", \"host-containerd\"],\n            new_vals: &[\"containerd\", \"host-containerd\", \"host-containers\"],\n        },\n        // For K8S variants\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\"containerd\", \"kubernetes\", \"host-containerd\"],\n            new_vals: &[\n                \"containerd\",\n                \"kubernetes\",\n                \"host-containerd\",\n                \"host-containers\",\n            ],\n        },\n        // For the aws-ecs-1 variant\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\"containerd\", \"docker\", \"ecs\", \"host-containerd\"],\n            new_vals: &[\n                \"containerd\",\n                \"docker\",\n                \"ecs\",\n                \"host-containerd\",\n                \"host-containers\",\n            ],\n        },\n        // For aws-dev and vmware-dev variants\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\"containerd\", \"docker\", \"host-containerd\"],\n            new_vals: &[\"containerd\", \"docker\", \"host-containerd\", \"host-containers\"],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-cloud-provider/Cargo.toml",
    "content": "[package]\nname = \"kubelet-cloud-provider\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-cloud-provider/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new settings for configuring kubelet, `settings.kubernetes.cloud-provider`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.cloud-provider\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-event-qps-event-burst/Cargo.toml",
    "content": "[package]\nname = \"kubelet-event-qps-event-burst\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-event-qps-event-burst/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings for configuring kubelet, `settings.kubernetes.event-qps`\n/// and `settings.kubernetes.event-burst`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.event-qps\",\n        \"settings.kubernetes.event-burst\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-kube-api-qps-kube-api-burst/Cargo.toml",
    "content": "[package]\nname = \"kubelet-kube-api-qps-kube-api-burst\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-kube-api-qps-kube-api-burst/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings for configuring kubelet, `settings.kubernetes.kube-api-qps`\n/// and `settings.kubernetes.kube-api-burst`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.kube-api-qps\",\n        \"settings.kubernetes.kube-api-burst\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-registry-qps-registry-burst/Cargo.toml",
    "content": "[package]\nname = \"kubelet-registry-qps-registry-burst\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-registry-qps-registry-burst/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings for configuring kubelet, `settings.kubernetes.registry-qps`\n/// and `settings.kubernetes.registry-burst`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.registry-qps\",\n        \"settings.kubernetes.registry-burst\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-server-tls-bootstrap/Cargo.toml",
    "content": "[package]\nname = \"kubelet-server-tls-bootstrap\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/kubelet-server-tls-bootstrap/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring kubelet, `kubernetes.server-tls-bootstrap`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.server-tls-bootstrap\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/schnauzer-paws/Cargo.toml",
    "content": "[package]\nname = \"schnauzer-paws\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\nserde_json = \"1.0\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/schnauzer-paws/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst SETTING: &str = \"settings.kubernetes.pod-infra-container-image\";\nconst OLD_SETTING_GENERATOR: &str = \"pluto pod-infra-container-image\";\nconst NEW_SETTING_GENERATOR: &str = \"schnauzer settings.kubernetes.pod-infra-container-image\";\nconst NEW_TEMPLATE: &str =\n    \"{{ pause-prefix settings.aws.region }}/eks/pause-{{ goarch os.arch }}:3.1\";\n\n/// We moved from using pluto to schnauzer for generating the pause container image URL, since it\n/// lets us reuse the existing region and arch settings, improving reliability and allowing for\n/// testing new regions through settings overrides.\npub struct SchnauzerPaws;\n\nimpl Migration for SchnauzerPaws {\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        // Check if we have this setting at all.\n        if let Some(metadata) = input.metadata.get_mut(SETTING) {\n            if let Some(metadata_value) = metadata.get_mut(\"setting-generator\") {\n                // Make sure the value is what we expect.\n                match metadata_value {\n                    serde_json::Value::String(string) => {\n                        if string == OLD_SETTING_GENERATOR {\n                            // Happy path.  Update the generator.\n                            *metadata_value = NEW_SETTING_GENERATOR.into();\n                            println!(\n                                \"Changed setting-generator for '{}' from {:?} to {:?} on upgrade\",\n                                SETTING, OLD_SETTING_GENERATOR, NEW_SETTING_GENERATOR\n                            );\n\n                            // Set the associated template.  We didn't have a template for this\n                            // setting before, and metadata can't be changed by the user, so we can\n                            // just set it.\n                            metadata.insert(\"template\".to_string(), NEW_TEMPLATE.into());\n                            println!(\n                                \"Set 'template' metadata on '{}' to '{}'\",\n                                SETTING, NEW_TEMPLATE\n                            );\n                        } else {\n                            println!(\n                                \"setting-generator for '{}' is not set to {:?}, leaving alone\",\n                                SETTING, OLD_SETTING_GENERATOR\n                            );\n                        }\n                    }\n                    _ => {\n                        println!(\n                            \"setting-generator for '{}' is set to non-string value '{}'; SchnauzerPaws only handles strings\",\n                            SETTING, metadata_value\n                        );\n                    }\n                }\n            } else {\n                println!(\"Found no setting-generator for '{}'\", SETTING);\n            }\n        } else {\n            println!(\"Found no metadata for '{}'\", SETTING);\n        }\n\n        Ok(input)\n    }\n\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        // Check if we have this setting at all.\n        if let Some(metadata) = input.metadata.get_mut(SETTING) {\n            if let Some(metadata_value) = metadata.get_mut(\"setting-generator\") {\n                // Make sure the value is what we expect.\n                match metadata_value {\n                    serde_json::Value::String(string) => {\n                        if string == NEW_SETTING_GENERATOR {\n                            // Happy path.  Update the generator.\n                            *metadata_value = OLD_SETTING_GENERATOR.into();\n                            println!(\n                                \"Changed setting-generator for '{}' from {:?} to {:?} on downgrade\",\n                                SETTING, NEW_SETTING_GENERATOR, OLD_SETTING_GENERATOR\n                            );\n\n                            // Remove the associated template.  We didn't have a template for this\n                            // setting before, and metadata can't be changed by the user, so we can\n                            // just remove it.\n                            if let Some(metadata_value) = metadata.remove(\"template\") {\n                                println!(\n                                    \"Removed 'template' metadata on '{}', which was set to '{}'\",\n                                    SETTING, metadata_value\n                                );\n                            } else {\n                                println!(\n                                    \"Found no 'template' metadata to remove on setting '{}'\",\n                                    SETTING\n                                );\n                            }\n                        } else {\n                            println!(\n                                \"setting-generator for '{}' is not set to {:?}, leaving alone\",\n                                SETTING, NEW_SETTING_GENERATOR\n                            );\n                        }\n                    }\n                    _ => {\n                        println!(\n                            \"setting-generator for '{}' is set to non-string value '{}'; SchnauzerPaws only handles strings\",\n                            SETTING, metadata_value\n                        );\n                    }\n                }\n            } else {\n                println!(\"Found no setting-generator for '{}'\", SETTING);\n            }\n        } else {\n            println!(\"Found no metadata for '{}'\", SETTING);\n        }\n\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    migrate(SchnauzerPaws)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/shared-containerd-configs/Cargo.toml",
    "content": "[package]\nname = \"shared-containerd-configs\"\nversion = \"0.1.0\"\nauthors = [\"Tom Kirchner <tjk@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nlazy_static = \"1.4\"\nmigration-helpers = { path = \"../../../migration-helpers\" }\nserde_json = \"1.0\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.0/shared-containerd-configs/src/main.rs",
    "content": "use lazy_static::lazy_static;\nuse migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst SETTING: &'static str = \"configuration-files.containerd-config-toml.template-path\";\n\nlazy_static! {\n    static ref TEMPLATE_CHANGES: &'static [(&'static str, &'static str)] = &[\n        (\n            \"/usr/share/templates/containerd-config-toml_aws-dev\",\n            \"/usr/share/templates/containerd-config-toml_basic\"\n        ),\n        (\n            \"/usr/share/templates/containerd-config-toml_aws-ecs-1\",\n            \"/usr/share/templates/containerd-config-toml_basic\"\n        ),\n        (\n            \"/usr/share/templates/containerd-config-toml_aws-k8s\",\n            \"/usr/share/templates/containerd-config-toml_k8s\"\n        ),\n        (\n            \"/usr/share/templates/containerd-config-toml_vmware-dev\",\n            \"/usr/share/templates/containerd-config-toml_basic\"\n        ),\n    ];\n}\n\n/// We refactored containerd config file templates to share data where possible, instead of\n/// duplicating them for variants with identical configs.  thar-be-settings runs at startup and\n/// regenerates all files based on templates, so if we change the source during migration (early in\n/// boot) it'll automatically be written out based on the new template.\nfn run() -> Result<()> {\n    migrate(SharedContainerdConfigs {})\n}\n\npub struct SharedContainerdConfigs {}\n\nimpl SharedContainerdConfigs {\n    fn migrate(\n        &mut self,\n        mut input: MigrationData,\n        transforms: &[(&str, &str)],\n        action: &'static str,\n    ) -> Result<MigrationData> {\n        if let Some(data) = input.data.get_mut(SETTING) {\n            match data {\n                serde_json::Value::String(string) => {\n                    for (outgoing, incoming) in transforms {\n                        if string == outgoing {\n                            *data = (*incoming).into();\n                            println!(\n                                \"Changed '{}' from {:?} to {:?} on {}\",\n                                SETTING, outgoing, incoming, action\n                            );\n                            // We've done what we came to do - the transformations don't\n                            // overlap, so we do one at most.  (Without this, Rust knows that\n                            // we still have a reference to 'data' for another iteration, and\n                            // it won't let us change it.  So smart.)\n                            break;\n                        } else {\n                            println!(\"'{}' is not set to {:?}, leaving alone\", SETTING, outgoing);\n                        }\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'; SharedContainerdConfigs only handles strings\",\n                        SETTING, data\n                    );\n                }\n            }\n        } else {\n            println!(\"Found no setting '{}'\", SETTING);\n        }\n\n        Ok(input)\n    }\n}\n\nimpl Migration for SharedContainerdConfigs {\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        self.migrate(input, *TEMPLATE_CHANGES, \"upgrade\")\n    }\n\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        let transforms: Vec<(&str, &str)> =\n            TEMPLATE_CHANGES.iter().map(|(a, b)| (*b, *a)).collect();\n        self.migrate(input, &transforms, \"downgrade\")\n    }\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/admin-container-v0-7-1/Cargo.toml",
    "content": "[package]\nname = \"admin-container-v0-7-1\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/admin-container-v0-7-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.1\";\n\n/// We bumped the version of the default admin container from v0.7.0 to v0.7.1\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/control-container-v0-5-1/Cargo.toml",
    "content": "[package]\nname = \"control-container-v0-5-1\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/control-container-v0-5-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.0\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.1\";\n\n/// We bumped the version of the default control container from v0.5.0 to v0.5.1\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/kubelet-container-log/Cargo.toml",
    "content": "[package]\nname = \"kubelet-container-log\"\nversion = \"0.1.0\"\nauthors = [\"Sungwon Cho <samjo.nyang@gmail.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/kubelet-container-log/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new settings for configuring kubelet, `settings.kubernetes.container-log-max-size`\n/// and `settings.kubernetes.container-log-max-files`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.container-log-max-size\",\n        \"settings.kubernetes.container-log-max-files\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/kubelet-system-reserved/Cargo.toml",
    "content": "[package]\nname = \"kubelet-system-reserved\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.2/kubelet-system-reserved/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new settings for configuring kubelet, `settings.kubernetes.system-reserved`\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.system-reserved\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.3/kubelet-cpu-manager/Cargo.toml",
    "content": "[package]\nname = \"kubelet-cpu-manager\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.3/kubelet-cpu-manager/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings for configuring kubelet, `settings.kubernetes.cpu-manager-reconcile-period`\n/// and `settings.kubernetes.cpu-manager-policy`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.cpu-manager-policy\",\n        \"settings.kubernetes.cpu-manager-reconcile-period\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.3/kubelet-cpu-manager-state/Cargo.toml",
    "content": "[package]\nname = \"kubelet-cpu-manager-state\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\nsnafu = \"0.8\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.1.3/kubelet-cpu-manager-state/src/main.rs",
    "content": "use migration_helpers::{error, migrate, Migration, MigrationData, Result};\nuse snafu::ResultExt;\nuse std::fs;\nuse std::io;\nuse std::process;\n\nconst CPU_MANAGER_POLICY_CHECKPOINT: &str = \"/var/lib/kubelet/cpu_manager_state\";\n\n/// forward - We always remove the state file on boot, therefore we don't need to explicitly\n/// remove the file during forward migration.\n/// backward - We remove cpu manager policy checkpoint value on downgrade, since older versions did not\n/// clean up this state file on boot.\npub struct CpuManagerPolicyCleaner;\n\nimpl Migration for CpuManagerPolicyCleaner {\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"CpuManagerPolicyCleaner has no work to do on upgrade.\");\n        Ok(input)\n    }\n\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        // removing existing cpu_manager_policy_state file\n        println!(\n            \"Deleting existing cpu manager policy checkpoint: '{}'\",\n            CPU_MANAGER_POLICY_CHECKPOINT\n        );\n        if let Err(e) = fs::remove_file(CPU_MANAGER_POLICY_CHECKPOINT) {\n            if e.kind() != io::ErrorKind::NotFound {\n                return Err(e).context(error::RemoveFile {\n                    path: CPU_MANAGER_POLICY_CHECKPOINT,\n                });\n            } else {\n                println!(\"NotFound: '{}'\", CPU_MANAGER_POLICY_CHECKPOINT)\n            }\n        }\n        Ok(input)\n    }\n}\n/// We changed the default for CPU manager policy and need to handle kubelet's state file.\nfn run() -> Result<()> {\n    migrate(CpuManagerPolicyCleaner)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/aws-admin-container-v0-9-2/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-9-2\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/aws-admin-container-v0-9-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.2\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/aws-control-container-v0-6-3/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-6-3\"\nversion = \"0.1.0\"\nauthors = [\"Ethan Pullen <pullenep@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/aws-control-container-v0-6-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.1\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.3\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/dns-settings/Cargo.toml",
    "content": "[package]\nname = \"dns-settings\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/dns-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings under `settings.dns` for configuring /etc/resolv.conf\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.dns\",\n        \"services.dns\",\n        \"configuration-files.netdog-toml\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/dns-settings-metadata/Cargo.toml",
    "content": "[package]\nname = \"dns-settings-metadata\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/dns-settings-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and `affected-services` metadata for `settings.dns`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.dns\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/kubelet-log-level/Cargo.toml",
    "content": "[package]\nname = \"kubelet-log-level\"\nversion = \"0.1.0\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/kubelet-log-level/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new settings for configuring kubelet logging verbosity:\n/// `settings.kubernetes.log-level`.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\"settings.kubernetes.log-level\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/public-admin-container-v0-9-2/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-9-2\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/public-admin-container-v0-9-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.0\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.2\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/public-control-container-v0-6-3/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-6-3\"\nversion = \"0.1.0\"\nauthors = [\"Ethan Pullen <pullenep@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/public-control-container-v0-6-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.1\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.3\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/reboot-to-reconcile-setting/Cargo.toml",
    "content": "[package]\nname = \"reboot-to-reconcile-setting\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.0/reboot-to-reconcile-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for letting the host reboot if boot settings changed,\n/// `settings.boot.reboot-to-reconcile`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\"settings.boot.reboot-to-reconcile\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.1/container-runtime/Cargo.toml",
    "content": "[package]\nname = \"container-runtime\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.1/container-runtime/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\"settings.container-runtime\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.1/container-runtime-metadata/Cargo.toml",
    "content": "[package]\nname = \"container-runtime-metadata\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}"
  },
  {
    "path": "sources/settings-migrations/archived/v1.10.1/container-runtime-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.container-runtime\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-admin-container-v0-9-3/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-9-3\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-admin-container-v0-9-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.2\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.3\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-config-settings/Cargo.toml",
    "content": "[package]\nname = \"aws-config-settings\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-config-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring the AWS client configuration. This\n/// can be used by any client expecting to find settings in the default\n/// `~/.aws/*` location.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"services.aws\",\n        \"configuration-files.aws-config\",\n        \"configuration-files.aws-credentials\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-control-container-v0-6-4/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-6-4\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-control-container-v0-6-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.3\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.4\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-creds/Cargo.toml",
    "content": "[package]\nname = \"aws-creds\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-creds/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-creds/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixesMigration, AddSettingsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for AWS credential configuration.\nfn run() -> Result<()> {\n    if cfg!(variant_platform = \"aws\") {\n        migrate(AddSettingsMigration(&[\n            \"settings.aws.config\",\n            \"settings.aws.credentials\",\n            \"settings.aws.profile\",\n        ]))\n    } else {\n        // Non-AWS variants did not have any AWS setting until this point,\n        // so need to completely clean up on downgrade.\n        migrate(AddPrefixesMigration(vec![\"settings.aws\"]))\n    }\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-creds-metadata/Cargo.toml",
    "content": "[package]\nname = \"aws-creds-metadata\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/aws-creds-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for AWS credential configuration.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.aws\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/credential-providers/Cargo.toml",
    "content": "[package]\nname = \"credential-providers\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/credential-providers/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring kubelet's image credential\n/// provider plugins. Initially this is only to support ecr-credential-provider,\n/// but others may be added as needed.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.credential-providers\",\n        \"configuration-files.credential-provider-config-yaml\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/ecs-additional-configurations/Cargo.toml",
    "content": "[package]\nname = \"ecs-additional-configurations\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/ecs-additional-configurations/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added additional configurations for the ECS agent\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.ecs.container-stop-timeout\",\n        \"settings.ecs.task-cleanup-wait\",\n        \"settings.ecs.metadata-service-rps\",\n        \"settings.ecs.metadata-service-burst\",\n        \"settings.ecs.reserved-memory\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/kubelet-new-config-files/Cargo.toml",
    "content": "[package]\nname = \"kubelet-new-config-files\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/kubelet-new-config-files/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// Handle new configuration files for kubelet configuration.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.kubernetes.configuration-files\",\n        old_vals: &[\n            \"kubelet-env\",\n            \"kubelet-config\",\n            \"kubelet-kubeconfig\",\n            \"kubelet-bootstrap-kubeconfig\",\n            \"kubelet-exec-start-conf\",\n            \"kubernetes-ca-crt\",\n            \"proxy-env\",\n        ],\n        new_vals: &[\n            \"kubelet-env\",\n            \"kubelet-config\",\n            \"kubelet-kubeconfig\",\n            \"kubelet-bootstrap-kubeconfig\",\n            \"kubelet-exec-start-conf\",\n            \"kubernetes-ca-crt\",\n            \"proxy-env\",\n            \"kubelet-server-crt\",\n            \"kubelet-server-key\",\n            \"credential-provider-config-yaml\",\n        ],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/kubelet-tls-config/Cargo.toml",
    "content": "[package]\nname = \"kubelet-tls-config\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/kubelet-tls-config/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added a new setting for providing TLS certs.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.server-certificate\",\n        \"settings.kubernetes.server-key\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/kubelet-tls-files/Cargo.toml",
    "content": "[package]\nname = \"kubelet-tls-files\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/kubelet-tls-files/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added support for adding new kubelet TLS certs/keys for communicating with the Kubernetes API server.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.kubelet-server-crt\",\n        \"configuration-files.kubelet-server-key\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/public-admin-container-v0-9-3/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-9-3\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/public-admin-container-v0-9-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.2\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.3\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/public-control-container-v0-6-4/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-6-4\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.11.0/public-control-container-v0-6-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.3\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.4\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/add-k8s-autoscaling-warm-pool-setting/Cargo.toml",
    "content": "[package]\nname = \"add-k8s-autoscaling-warm-pool-setting\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/add-k8s-autoscaling-warm-pool-setting/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/add-k8s-autoscaling-warm-pool-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixesMigration, NoOpMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting prefix for configuring autoscaling in k8s variants.\n/// Remove the whole `settings.autoscaling` prefix if we downgrade.\nfn run() -> Result<()> {\n    if cfg!(variant_family = \"aws-k8s\") {\n        migrate(AddPrefixesMigration(vec![\n            \"settings.autoscaling\",\n            \"services.autoscaling-warm-pool\",\n            \"configuration-files.warm-pool-wait-toml\",\n        ]))?;\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/add-k8s-autoscaling-warm-pool-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"add-k8s-autoscaling-warm-pool-setting-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/add-k8s-autoscaling-warm-pool-setting-metadata/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/add-k8s-autoscaling-warm-pool-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, NoOpMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and `affected-services` metadata for `settings.autoscaling`\nfn run() -> Result<()> {\n    if cfg!(variant_family = \"aws-k8s\") {\n        migrate(AddMetadataMigration(&[SettingMetadata {\n            metadata: &[\"affected-services\"],\n            setting: \"settings.autoscaling\",\n        }]))?;\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/aws-admin-container-v0-9-4/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-9-4\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/aws-admin-container-v0-9-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.3\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.4\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/aws-control-container-v0-7-0/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/aws-control-container-v0-7-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.4\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.0\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/k8s-private-pki-path/Cargo.toml",
    "content": "[package]\nname = \"k8s-private-pki-path\"\nversion = \"0.1.0\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\nserde_json = \"1.0\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/k8s-private-pki-path/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst SETTING: &str = \"configuration-files.kubelet-server-key.path\";\nconst OLD_VALUE: &str = \"/etc/kubernetes/pki/kubelet-server.key\";\nconst NEW_VALUE: &str = \"/etc/kubernetes/pki/private/kubelet-server.key\";\n\n/// We moved the render output location for the kubelet PKI private key to be in a restricted\n/// subdirectory. We need to update this output path in the stored configuration so updated nodes\n/// pick up the change.\nfn run() -> Result<()> {\n    migrate(KubeletServerKey {})\n}\n\npub struct KubeletServerKey {}\n\nimpl KubeletServerKey {\n    fn migrate(&mut self, mut input: MigrationData, action: &'static str) -> Result<MigrationData> {\n        let old_value;\n        let new_value;\n        if action == \"upgrade\" {\n            old_value = OLD_VALUE;\n            new_value = NEW_VALUE;\n        } else {\n            // Downgrade: everything old is new again\n            old_value = NEW_VALUE;\n            new_value = OLD_VALUE;\n        }\n\n        if let Some(data) = input.data.get_mut(SETTING) {\n            match data {\n                serde_json::Value::String(current_value) => {\n                    if current_value == old_value {\n                        *data = new_value.into();\n                        println!(\n                            \"Changed '{}' from {:?} to {:?} on {}\",\n                            SETTING, old_value, new_value, action\n                        );\n                    } else {\n                        println!(\n                            \"'{}' is already set to {:?}, leaving alone\",\n                            SETTING, new_value\n                        );\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'; KubeletServerKey only handles strings\",\n                        SETTING, data\n                    );\n                }\n            }\n        } else {\n            println!(\"Found no setting '{}'\", SETTING);\n        }\n\n        Ok(input)\n    }\n}\n\nimpl Migration for KubeletServerKey {\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        self.migrate(input, \"upgrade\")\n    }\n\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        self.migrate(input, \"downgrade\")\n    }\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/oci-defaults-setting/Cargo.toml",
    "content": "[package]\nname = \"oci-defaults-setting\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Mahdi Chaker <mmchaker@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/oci-defaults-setting/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/oci-defaults-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixesMigration, NoOpMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for configuring the default OCI runtime spec,\n/// `settings.oci-defaults`, which will initially contain\n/// `settings.oci-defaults.capabilities` and\n/// `settings.oci-defaults.resource-limits`\nfn run() -> Result<()> {\n    if cfg!(variant_runtime = \"k8s\") {\n        migrate(AddPrefixesMigration(vec![\n            \"settings.oci-defaults\",\n            \"services.oci-defaults\",\n            \"configuration-files.oci-defaults\",\n        ]))?\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/oci-defaults-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"oci-defaults-setting-metadata\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Mahdi Chaker <mmchaker@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/oci-defaults-setting-metadata/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/oci-defaults-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, NoOpMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.oci-defaults'\n/// to include itself and containerd on upgrade, and to remove those values on\n/// downgrade, depending on the running variant.\nfn run() -> Result<()> {\n    if cfg!(variant_runtime = \"k8s\") {\n        migrate(AddMetadataMigration(&[SettingMetadata {\n            metadata: &[\"affected-services\"],\n            setting: \"settings.oci-defaults\",\n        }]))?\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/public-admin-container-v0-9-4/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-9-4\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/public-admin-container-v0-9-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.3\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.4\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/public-control-container-v0-7-0/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.12.0/public-control-container-v0-7-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.4\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.0\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/aws-admin-container-v0-10-0/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-10-0\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/aws-admin-container-v0-10-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.4\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.10.0\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/aws-control-container-v0-7-1/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-1\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/aws-control-container-v0-7-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.0\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.1\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/k8s-registry/Cargo.toml",
    "content": "[package]\nname = \"k8s-registry\"\nversion = \"0.1.0\"\nauthors = [\"John McBride <jpmmcb@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/k8s-registry/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_K8S_PAUSE_IMAGE: &str = \"k8s.gcr.io/pause:3.2\";\nconst NEW_K8S_PAUSE_IMAGE: &str = \"public.ecr.aws/eks-distro/kubernetes/pause:3.3\";\n\n// The `k8s.gcr.io` registry, as of April 2023 will be frozen and\n// images will no longer be pushed to that registry.\n// For further details: https://kubernetes.io/blog/2023/02/06/k8s-gcr-io-freeze-announcement/\n//\n// In this migration, we move pause container image references from `k8s.gcr.io` to `public.ecr.aws/eks-distro/kubernetes/`\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.kubernetes.pod-infra-container-image\",\n        old_val: OLD_K8S_PAUSE_IMAGE,\n        new_val: NEW_K8S_PAUSE_IMAGE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/public-admin-container-v0-10-0/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-10-0\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/public-admin-container-v0-10-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.4\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.10.0\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/public-control-container-v0-7-1/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-1\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.0/public-control-container-v0-7-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.0\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.1\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.1/aws-profile-cred-provider/Cargo.toml",
    "content": "[package]\nname = \"aws-profile-cred-provider\"\nversion = \"0.1.0\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.1/aws-profile-cred-provider/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added `affected-services` metadata for `aws.profile`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.aws.profile\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.3/aws-k8s-provider-id-gen/Cargo.toml",
    "content": "[package]\nname = \"aws-k8s-provider-id-gen\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.3/aws-k8s-provider-id-gen/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new `setting-generator` metadata for `kubernetes.provider-id`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"setting-generator\"],\n        setting: \"settings.kubernetes.provider-id\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.4/add-hostname-override/Cargo.toml",
    "content": "[package]\nname = \"add-hostname-override\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.4/add-hostname-override/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for specifying the '--hostname-override' kubelet option for kubernetes variants\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.hostname-override\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.4/add-hostname-override-metadata/Cargo.toml",
    "content": "[package]\nname = \"add-hostname-override-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.13.4/add-hostname-override-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added the `setting-generator` metadata for `kubernetes.hostname-override`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"setting-generator\"],\n        setting: \"settings.kubernetes.hostname-override\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/aws-admin-container-v0-10-1/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-10-1\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/aws-admin-container-v0-10-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.10.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.10.1\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/aws-control-container-v0-7-2/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-2\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/aws-control-container-v0-7-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.1\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.2\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/k8s-services-mode/Cargo.toml",
    "content": "[package]\nname = \"k8s-services-mode\"\nversion = \"0.1.0\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\nserde_json = \"1.0\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/k8s-services-mode/src/main.rs",
    "content": "use migration_helpers::{common_migrations::AddSettingsMigration, migrate, Result};\nuse std::process;\n\n/// Mode settings were added for a handful of the templated kubelet configuration files.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"configuration-files.kubelet-config.mode\",\n        \"configuration-files.kubelet-kubeconfig.mode\",\n        \"configuration-files.kubelet-bootstrap-kubeconfig.mode\",\n        \"configuration-files.kubelet-exec-start-conf.mode\",\n        \"configuration-files.credential-provider-config-yaml.mode\",\n        \"configuration-files.kubernetes-ca-crt.mode\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/kubelet-config-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-config-settings\"\nversion = \"0.1.0\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/kubelet-config-settings/src/main.rs",
    "content": "use migration_helpers::{common_migrations::AddSettingsMigration, migrate, Result};\nuse std::process;\n\n/// Additional `settings.kubernetes` options for this release.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.cpu-manager-policy-options\",\n        \"settings.kubernetes.cpu-cfs-quota-enforced\",\n        \"settings.kubernetes.shutdown-grace-period\",\n        \"settings.kubernetes.shutdown-grace-period-for-critical-pods\",\n        \"settings.kubernetes.eviction-soft\",\n        \"settings.kubernetes.eviction-soft-grace-period\",\n        \"settings.kubernetes.eviction-max-pod-grace-period\",\n        \"settings.kubernetes.memory-manager-policy\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/kubelet-prefix-config-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-prefix-config-settings\"\nversion = \"0.1.0\"\nauthors = [\"Sean McGinnis <stmcg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/kubelet-prefix-config-settings/src/main.rs",
    "content": "use migration_helpers::{common_migrations::AddPrefixesMigration, migrate, Result};\nuse std::process;\n\n/// Additional `settings.kubernetes` options for this release.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.memory-manager-reserved-memory\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/kubernetes-gc-percent-type-change/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-gc-percent-type-change\"\nversion = \"0.1.0\"\nauthors = [\"Matt Briggs <brigmatt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\nserde_json = \"1\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/kubernetes-gc-percent-type-change/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse serde_json::Value;\nuse std::process;\n\nconst GC_HIGH_SETTING: &str = \"settings.kubernetes.image-gc-high-threshold-percent\";\nconst GC_LOW_SETTING: &str = \"settings.kubernetes.image-gc-low-threshold-percent\";\n\n/// We changed these settings so that they can be specified as numbers. Previously they could only\n/// be specified as strings, which was confusing since they are numeric. On upgrade we don't need\n/// to do anything because a valid string representation will still be accepted. On downgrade, we\n/// need to check if the values are represented as numbers, and if so, convert them to strings.\npub struct ChangeK8sGcPercentType;\n\nfn convert_to_string(value: &mut Value) {\n    let s = if let Value::Number(n) = value {\n        n.to_string()\n    } else {\n        return;\n    };\n    *value = Value::String(s);\n}\n\nimpl Migration for ChangeK8sGcPercentType {\n    /// On upgrade there is nothing to do (see above).\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        Ok(input)\n    }\n\n    /// On downgrade, if the value is a number, we need to convert it to a string (see above).\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(v) = input.data.get_mut(GC_HIGH_SETTING) {\n            convert_to_string(v);\n        }\n        if let Some(v) = input.data.get_mut(GC_LOW_SETTING) {\n            convert_to_string(v);\n        }\n        Ok(input)\n    }\n}\n\n/// We made changes to `image-gc-low-threshold-percent` and `image-gc-high-threshold-percent`.\nfn run() -> Result<()> {\n    migrate(ChangeK8sGcPercentType)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/public-admin-container-v0-10-1/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-10-1\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/public-admin-container-v0-10-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.10.0\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.10.1\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/public-control-container-v0-7-2/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-2\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.0/public-control-container-v0-7-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.1\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.2\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.2/ecs-images-cleanup/Cargo.toml",
    "content": "[package]\nname = \"ecs-images-cleanup\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.2/ecs-images-cleanup/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added additional configurations for the ECS agent\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.ecs.image-cleanup-wait\",\n        \"settings.ecs.image-cleanup-delete-per-cycle\",\n        \"settings.ecs.image-cleanup-enabled\",\n        \"settings.ecs.image-cleanup-age\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/aws-admin-container-v0-10-2/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-10-2\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/aws-admin-container-v0-10-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.10.1\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.10.2\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/aws-control-container-v0-7-3/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-3\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/aws-control-container-v0-7-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.2\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.3\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/public-admin-container-v0-10-2/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-10-2\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/public-admin-container-v0-10-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.10.1\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.10.2\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/public-control-container-v0-7-3/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-3\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.14.3/public-control-container-v0-7-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.2\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.3\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/aws-admin-container-v0-11-0/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-0\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/aws-admin-container-v0-11-0/src/main.rs",
    "content": "#![allow(deprecated)]\nuse migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.10.2\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.0\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/aws-control-container-v0-7-4/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-4\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/aws-control-container-v0-7-4/src/main.rs",
    "content": "#![allow(deprecated)]\nuse migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.3\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.4\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/deprecate-log4j-hotpatch-enabled/Cargo.toml",
    "content": "[package]\nname = \"deprecate-log4j-hotpatch-enabled\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/deprecate-log4j-hotpatch-enabled/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new service to log a warning to the journal when log4j-hotpatch-enabled\n/// is true\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"services.log4j-hotpatch-enabled\",\n        \"configuration-files.log4j-hotpatch-enabled-log-message\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/log4j-hotpatch-enabled-metadata/Cargo.toml",
    "content": "[package]\nname = \"log4j-hotpatch-enabled-metadata\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/log4j-hotpatch-enabled-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new service to print a warning when log4j-hotpatch-enabled is true.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.oci-hooks.log4j-hotpatch-enabled\",\n    }]))?;\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-docker-setting/Cargo.toml",
    "content": "[package]\nname = \"oci-defaults-docker-setting\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-docker-setting/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-docker-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixesMigration, NoOpMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for configuring the default OCI runtime spec for ECS,\n/// `settings.oci-defaults`, which will initially contain\n/// `settings.oci-defaults.capabilities` and\n/// `settings.oci-defaults.resource-limits`\nfn run() -> Result<()> {\n    if cfg!(variant_runtime = \"ecs\") {\n        migrate(AddPrefixesMigration(vec![\n            \"settings.oci-defaults\",\n            \"services.oci-defaults\",\n            \"configuration-files.oci-defaults\",\n        ]))?\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-docker-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"oci-defaults-docker-setting-metadata\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-docker-setting-metadata/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-docker-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, NoOpMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.oci-defaults'\n/// to include itself and containerd on upgrade, and to remove those values on\n/// downgrade, depending on the running variant.\nfn run() -> Result<()> {\n    if cfg!(variant_runtime = \"ecs\") {\n        migrate(AddMetadataMigration(&[SettingMetadata {\n            metadata: &[\"affected-services\"],\n            setting: \"settings.oci-defaults\",\n        }]))?\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-max-open-files/Cargo.toml",
    "content": "[package]\nname = \"oci-defaults-max-open-files\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\nserde_json = \"1\"\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-max-open-files/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-max-open-files/src/main.rs",
    "content": "use migration_helpers::common_migrations::NoOpMigration;\nuse migration_helpers::{migrate, Migration, MigrationData, Result};\nuse serde_json::Value;\nuse std::process;\n\nconst HARD_RESOURCE_LIMIT_SETTING_NAME: &str =\n    \"settings.oci-defaults.resource-limits.max-open-files.hard-limit\";\nconst SOFT_RESOURCE_LIMIT_SETTING_NAME: &str =\n    \"settings.oci-defaults.resource-limits.max-open-files.soft-limit\";\n\n/// This migration changes the hard and soft limit for rlimit_nofile to u32 from i64 on downgrade.\n/// There is no need of migration on upgrade as u32 will automatically change to i64\npub struct ChangeMaxOpenFileResourceLimitType;\n\nfn convert_to_u32(value: &mut Value) {\n    if !value.is_i64() {\n        return;\n    }\n    let v: i64 = serde_json::from_value(value.clone()).unwrap();\n    let s = match v {\n        -1 => u32::MAX,\n        v if v > u32::MAX as i64 => u32::MAX,\n        _ => v as u32,\n    };\n\n    *value = Value::Number(s.into());\n}\n\nimpl Migration for ChangeMaxOpenFileResourceLimitType {\n    /// On upgrade there is nothing to do (see above).\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        Ok(input)\n    }\n\n    /// On downgrade, if the value is an i64 integer, we need to convert it to a u32.\n    ///\n    /// Note that this potentially causes data loss, if current value of the setting\n    /// is -1 or higher than u_32::MAX we will set it to max possible value i.e. u32::MAX.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(v) = input.data.get_mut(HARD_RESOURCE_LIMIT_SETTING_NAME) {\n            convert_to_u32(v);\n        }\n        if let Some(v) = input.data.get_mut(SOFT_RESOURCE_LIMIT_SETTING_NAME) {\n            convert_to_u32(v);\n        }\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    if cfg!(variant_runtime = \"k8s\") {\n        migrate(ChangeMaxOpenFileResourceLimitType)?\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-resource-setting/Cargo.toml",
    "content": "[package]\nname = \"oci-defaults-resource-setting\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-resource-setting/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/oci-defaults-resource-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixesMigration, NoOpMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new resource limit settings for configuring the default OCI runtime spec.\nfn run() -> Result<()> {\n    if cfg!(variant_runtime = \"k8s\") {\n        migrate(AddPrefixesMigration(vec![\n            \"settings.oci-defaults.resource-limits.max-address-space\",\n            \"settings.oci-defaults.resource-limits.max-core-file-size\",\n            \"settings.oci-defaults.resource-limits.max-cpu-time\",\n            \"settings.oci-defaults.resource-limits.max-data-size\",\n            \"settings.oci-defaults.resource-limits.max-file-locks\",\n            \"settings.oci-defaults.resource-limits.max-file-size\",\n            \"settings.oci-defaults.resource-limits.max-locked-memory\",\n            \"settings.oci-defaults.resource-limits.max-msgqueue-size\",\n            \"settings.oci-defaults.resource-limits.max-nice-priority\",\n            \"settings.oci-defaults.resource-limits.max-pending-signals\",\n            \"settings.oci-defaults.resource-limits.max-processes\",\n            \"settings.oci-defaults.resource-limits.max-realtime-priority\",\n            \"settings.oci-defaults.resource-limits.max-realtime-timeout\",\n            \"settings.oci-defaults.resource-limits.max-resident-set\",\n            \"settings.oci-defaults.resource-limits.max-stack-size\",\n        ]))?\n    } else {\n        migrate(NoOpMigration)?;\n    }\n\n    Ok(())\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/public-admin-container-v0-11-0/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-0\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/public-admin-container-v0-11-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.10.2\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.0\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/public-control-container-v0-7-4/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-4\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/public-control-container-v0-7-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.3\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.4\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/seccomp-default-setting/Cargo.toml",
    "content": "[package]\nname = \"seccomp-default-setting\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Cartrius Phipps <cartrius@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.15.0/seccomp-default-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting to expose the ability to toggle the SeccompDefault setting.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.seccomp-default\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/aws-admin-container-v0-11-1/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-1\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/aws-admin-container-v0-11-1/src/main.rs",
    "content": "#![allow(deprecated)]\nuse migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.1\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/aws-control-container-v0-7-5/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-5\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/aws-control-container-v0-7-5/src/main.rs",
    "content": "#![allow(deprecated)]\nuse migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.4\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.5\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-configs/Cargo.toml",
    "content": "[package]\nname = \"kernel-modules-autoload-configs\"\nversion = \"0.1.0\"\nauthors = [\"Leonard Foerster <foersleo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers/\", version = \"0.1.0\" }\nserde_json = \"1\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-configs/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings under `settings.kernel.modules` for configuring\n/// /etc/modules-load.d/modules-load.conf. The actual autoload settings are\n/// migrated separately in kernel-modules-autoload-settings migration as they\n/// require a custom migration implementation.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.modules-load\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-files/Cargo.toml",
    "content": "[package]\nname = \"kernel-modules-autoload-files\"\nversion = \"0.1.0\"\nauthors = [\"Leonard Foerster <foersleo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers/\", version = \"0.1.0\" }\nserde_json = \"1\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-files/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a config file to the configuration-files list for services.kernel-modules\n/// to facilitate module autoload. This needs to be restored to prior values on downgrade.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.kernel-modules.configuration-files\",\n        old_vals: &[\"modprobe-conf\"],\n        new_vals: &[\"modprobe-conf\", \"modules-load\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-restart/Cargo.toml",
    "content": "[package]\nname = \"kernel-modules-autoload-restart\"\nversion = \"0.1.0\"\nauthors = [\"Leonard Foerster <foersleo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers/\", version = \"0.1.0\" }\nserde_json = \"1\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-restart/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new `autoload` setting to `settings.kernel.modules`, which needs\n/// re restart of `systemd-modules-load.services`.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.kernel-modules.restart-commands\",\n        old_vals: &[],\n        new_vals: &[\"/usr/bin/systemctl try-restart systemd-modules-load\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-settings/Cargo.toml",
    "content": "[package]\nname = \"kernel-modules-autoload-settings\"\nversion = \"0.1.0\"\nauthors = [\"Leonard Foerster <foersleo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers/\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/kernel-modules-autoload-settings/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst KMOD_AUTOLOAD_PREFIX: &str = \"settings.kernel.modules\";\nconst KMOD_AUTOLOAD_SETTING: &str = \"autoload\";\n\n/// We added a new autoload setting to the kernel.mudules set of tables. These tables\n/// come with a variable name containing the module name. We can hence not just use\n/// an `AddSettingsMigration` as these require the full name. We rather need a hybrid\n/// of `AddSettingsMigration` and `AddPrefixesMigration` in order to select the correct\n/// parts of these variably named tables to remove on downgrade. Similar to the common\n/// forms of `Add*Migrations` we do not need to do anything on upgrade.\npub struct AddKmodAutoload;\n\nimpl Migration for AddKmodAutoload {\n    /// On upgrade there is nothing to do (see above).\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        Ok(input)\n    }\n\n    /// On downgrade, we need to find the `autoload` setting in all tables with\n    /// prefix `settings.kernel.modules` and remove them.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let settings = input\n            .data\n            .keys()\n            .filter(|k| k.starts_with(KMOD_AUTOLOAD_PREFIX))\n            .filter(|k| k.ends_with(KMOD_AUTOLOAD_SETTING))\n            .cloned()\n            .collect::<Vec<_>>();\n        for setting in settings {\n            if let Some(data) = input.data.remove(&setting) {\n                println!(\"Removed {}, which was set to '{}'\", setting, data);\n            }\n        }\n        Ok(input)\n    }\n}\n\n/// We added `settigns.kernel.modules.<name>.auotload`.\nfn run() -> Result<()> {\n    migrate(AddKmodAutoload)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/public-admin-container-v0-11-1/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-1\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/public-admin-container-v0-11-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.0\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.1\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/public-control-container-v0-7-5/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-5\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/public-control-container-v0-7-5/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.4\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.5\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/schnauzer-v2-generators/Cargo.toml",
    "content": "[package]\nname = \"schnauzer-v2-generators\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/schnauzer-v2-generators/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.0/schnauzer-v2-generators/src/main.rs",
    "content": "use migration_helpers::common_migrations::{MetadataReplacement, ReplaceMetadataMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn build_metadata_migrations() -> Vec<MetadataReplacement> {\n    let mut migrations = vec![];\n\n    // On AWS platforms, we use regional ECR repositories.\n    // Elsewhere, we use ecr-public, which is global.\n    #[cfg(variant_platform = \"aws\")]\n    {\n        migrations.append(&mut vec![\n            MetadataReplacement {\n                setting: \"settings.host-containers.admin.source\",\n                metadata: \"setting-generator\",\n                old_val: \"schnauzer settings.host-containers.admin.source\",\n                new_val: \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.1'\",\n            },\n            MetadataReplacement {\n                setting: \"settings.host-containers.control.source\",\n                metadata: \"setting-generator\",\n                old_val: \"schnauzer settings.host-containers.control.source\",\n                new_val: \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.5'\",\n            },\n            MetadataReplacement {\n                setting: \"settings.updates.metadata-base-url\",\n                metadata: \"setting-generator\",\n                old_val: \"schnauzer settings.updates.metadata-base-url\",\n                new_val: \"schnauzer-v2 render --requires 'aws@v1' --requires 'updates@v1(helpers=[metadata-prefix, tuf-prefix])' --template '{{ tuf-prefix settings.aws.region }}{{ metadata-prefix settings.aws.region }}/2020-07-07/{{ os.variant_id }}/{{ os.arch }}/'\",\n            },\n            MetadataReplacement {\n                setting: \"settings.updates.targets-base-url\",\n                metadata: \"setting-generator\",\n                old_val: \"schnauzer settings.updates.targets-base-url\",\n                new_val: \"schnauzer-v2 render --requires 'aws@v1' --requires 'updates@v1(helpers=[tuf-prefix])' --template '{{ tuf-prefix settings.aws.region }}/targets/'\",\n            },\n        ]);\n    }\n    #[cfg(not(variant_platform = \"aws\"))]\n    {\n        migrations.append(&mut vec![\n            MetadataReplacement {\n                setting: \"settings.updates.metadata-base-url\",\n                metadata: \"setting-generator\",\n                old_val: \"schnauzer settings.updates.metadata-base-url\",\n                new_val: \"schnauzer-v2 render --template 'https://updates.bottlerocket.aws/2020-07-07/{{ os.variant_id }}/{{ os.arch }}/'\",\n            },\n        ]);\n    }\n\n    #[cfg(variant_family = \"aws-k8s\")]\n    {\n        migrations.append(&mut vec![\n            MetadataReplacement {\n                setting: \"settings.kubernetes.pod-infra-container-image\",\n                metadata: \"setting-generator\",\n                old_val: \"schnauzer settings.kubernetes.pod-infra-container-image\",\n                new_val: \"schnauzer-v2 render --requires 'aws@v1' --requires 'kubernetes@v1(helpers=[pause-prefix])' --template '{{ pause-prefix settings.aws.region }}/eks/pause:3.1-eksbuild.1'\",\n            },\n        ]);\n    }\n\n    migrations\n}\n\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataMigration(build_metadata_migrations()))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.1/updog-network-affected/Cargo.toml",
    "content": "[package]\nname = \"updog-network-affected\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.16.1/updog-network-affected/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.network' to include\n/// updog. The metadata list need to be restored to the prior value on downgrade and\n/// updated to include updog on upgrades.\n/// We're trying to match old values for different variants.\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\"containerd\", \"host-containerd\", \"host-containers\"],\n            new_vals: &[\"containerd\", \"host-containerd\", \"host-containers\", \"updog\"],\n        },\n        // For K8S variants\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\n                \"containerd\",\n                \"kubernetes\",\n                \"host-containerd\",\n                \"host-containers\",\n            ],\n            new_vals: &[\n                \"containerd\",\n                \"kubernetes\",\n                \"host-containerd\",\n                \"host-containers\",\n                \"updog\",\n            ],\n        },\n        // For the ECS variants\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\n                \"containerd\",\n                \"docker\",\n                \"ecs\",\n                \"host-containerd\",\n                \"host-containers\",\n            ],\n            new_vals: &[\n                \"containerd\",\n                \"docker\",\n                \"ecs\",\n                \"host-containerd\",\n                \"host-containers\",\n                \"updog\",\n            ],\n        },\n        // For *-dev variants\n        MetadataListReplacement {\n            setting: \"settings.network\",\n            metadata: \"affected-services\",\n            old_vals: &[\"containerd\", \"docker\", \"host-containerd\", \"host-containers\"],\n            new_vals: &[\n                \"containerd\",\n                \"docker\",\n                \"host-containerd\",\n                \"host-containers\",\n                \"updog\",\n            ],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/aws-admin-container-v0-11-2/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-2\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/aws-admin-container-v0-11-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.1'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.2'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/aws-control-container-v0-7-6/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-6\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/aws-control-container-v0-7-6/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.5'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.6'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/public-admin-container-v0-11-2/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-2\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/public-admin-container-v0-11-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.1\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.2\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/public-control-container-v0-7-6/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-6\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.17.0/public-control-container-v0-7-6/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.5\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.6\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/aws-admin-container-v0-11-3/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-3\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/aws-admin-container-v0-11-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.2'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.3'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/aws-control-container-v0-7-7/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-7\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/aws-control-container-v0-7-7/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.6'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.7'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/public-admin-container-v0-11-3/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-3\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/public-admin-container-v0-11-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.2\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.3\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/public-control-container-v0-7-7/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-7\"\nversion = \"0.1.0\"\nauthors = [\"Markus Boehme <markubo@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.18.0/public-control-container-v0-7-7/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.6\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.7\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.0/add-additional-ecs-settings/Cargo.toml",
    "content": "[package]\nname = \"add-additional-ecs-settings\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.0/add-additional-ecs-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added additional configurations for the ECS agent\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.ecs.backend-host\",\n        \"settings.ecs.awsvpc-block-imds\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/aws-admin-container-v0-11-4/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-4\"\nversion = \"0.1.0\"\nauthors = [\"Matthew Yeazel <yeazelm@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/aws-admin-container-v0-11-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.3'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.4'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/aws-control-container-v0-7-8/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-8\"\nversion = \"0.1.0\"\nauthors = [\"Matthew Yeazel <yeazelm@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/aws-control-container-v0-7-8/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.7'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.8'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/public-admin-container-v0-11-4/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-4\"\nversion = \"0.1.0\"\nauthors = [\"Matthew Yeazel <yeazelm@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/public-admin-container-v0-11-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.3\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.4\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/public-control-container-v0-7-8/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-8\"\nversion = \"0.1.0\"\nauthors = [\"Matthew Yeazel <yeazelm@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.1/public-control-container-v0-7-8/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.7\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.8\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.2/add-ecs-enable-container-metadata/Cargo.toml",
    "content": "[package]\nname = \"add-ecs-enable-container-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.2/add-ecs-enable-container-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added additional configurations for the ECS agent\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.ecs.enable-container-metadata\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.2/certdog-config-file-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"certdog-config-file-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.2/certdog-config-file-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// Add settings for the new certdog-toml config file\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.certdog-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.2/certdog-service-cfg-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"certdog-service-cfg-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.2/certdog-service-cfg-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// Add settings for the new certdog-toml config file\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.pki.configuration-files\",\n        old_vals: &[],\n        new_vals: &[\"certdog-toml\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/aws-admin-container-v0-11-6/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-6\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/aws-admin-container-v0-11-6/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.4'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.6'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/aws-control-container-v0-7-10/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-10\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/aws-control-container-v0-7-10/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.8'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.10'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/public-admin-container-v0-11-6/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-6\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/public-admin-container-v0-11-6/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.4\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.6\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/public-control-container-v0-7-10/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-10\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.3/public-control-container-v0-7-10/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.8\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.10\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/aws-admin-container-v0-11-7/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-7\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/aws-admin-container-v0-11-7/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.6'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.7'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/aws-control-container-v0-7-11/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-11\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/aws-control-container-v0-7-11/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.10'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.11'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/public-admin-container-v0-11-7/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-7\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/public-admin-container-v0-11-7/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.6\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.7\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/public-control-container-v0-7-11/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-11\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.19.5/public-control-container-v0-7-11/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.10\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.11\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/add-custom-certificates/Cargo.toml",
    "content": "[package]\nname = \"add-custom-certificates\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/add-custom-certificates/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added the settings and services for `pki`\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\"settings.pki\", \"services.pki\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/admin-container-v0-7-2/Cargo.toml",
    "content": "[package]\nname = \"admin-container-v0-7-2\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/admin-container-v0-7-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.1\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.2\";\n\n/// We bumped the version of the default admin container from v0.7.1 to v0.7.2\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/container-registry-config-restarts/Cargo.toml",
    "content": "[package]\nname = \"container-registry-config-restarts\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/container-registry-config-restarts/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We templatized the configuration file for the Docker daemon.\n/// We also added a new configuration file for host-containers and bootstrap-containers\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![\n        ListReplacement {\n            setting: \"services.docker.configuration-files\",\n            old_vals: &[\"proxy-env\"],\n            new_vals: &[\"docker-daemon-config\", \"proxy-env\"],\n        },\n        ListReplacement {\n            setting: \"services.bootstrap-containers.configuration-files\",\n            old_vals: &[],\n            new_vals: &[\"host-ctr-toml\"],\n        },\n        ListReplacement {\n            setting: \"services.host-containers.configuration-files\",\n            old_vals: &[],\n            new_vals: &[\"host-ctr-toml\"],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/container-registry-mirrors/Cargo.toml",
    "content": "[package]\nname = \"container-registry-mirrors\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/container-registry-mirrors/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring image registries, `settings.container-registry`\n/// We also added a new configuration template file for the Docker daemon\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.container-registry\",\n        \"configuration-files.docker-daemon-config\",\n        \"configuration-files.host-ctr-toml\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/hostname-setting/Cargo.toml",
    "content": "[package]\nname = \"hostname-setting\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/hostname-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for configuring hostname\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.network.hostname\",\n        \"services.hostname\",\n        \"configuration-files.hostname\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/hostname-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"hostname-setting-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/hostname-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for configuring hostname\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"setting-generator\", \"affected-services\"],\n        setting: \"settings.network.hostname\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/kubelet-topology-manager/Cargo.toml",
    "content": "[package]\nname = \"kubelet-topology-manager\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.2.0/kubelet-topology-manager/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added two new settings for configuring kubelet, `settings.kubernetes.topology-manager-policy`\n/// and `settings.kubernetes.topology-manager-scope`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.topology-manager-scope\",\n        \"settings.kubernetes.topology-manager-policy\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/add-ntp-default-options-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"add-ntp-default-options-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Dom Goodwin <domgoodwin@monzo.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/add-ntp-default-options-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added the ability to set additional options for NTP\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\"settings.ntp.options\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/aws-admin-container-v0-11-8/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-8\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/aws-admin-container-v0-11-8/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.7'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.8'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/aws-control-container-v0-7-12/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-12\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/aws-control-container-v0-7-12/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.11'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.12'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/bootstrap-containers-config-file-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"bootstrap-containers-config-file-v0-1-0\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/bootstrap-containers-config-file-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.bootstrap-containers-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/bootstrap-containers-services-cfg-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"bootstrap-containers-services-cfg-v0-1-0\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/bootstrap-containers-services-cfg-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.bootstrap-containers.configuration-files\",\n        old_vals: &[\"host-ctr-toml\"],\n        new_vals: &[\"host-ctr-toml\", \"bootstrap-containers-toml\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/container-runtime-metadata-nvidia/Cargo.toml",
    "content": "[package]\nname = \"container-runtime-metadata-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Matthew Yeazel <yeazelm@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/container-runtime-metadata-nvidia/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/container-runtime-metadata-nvidia/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, NoOpMigration, SettingMetadata};\nuse migration_helpers::migrate;\nuse migration_helpers::Result;\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings only for NVIDIA k8s variants.\nfn run() -> Result<()> {\n    if cfg!(variant_family = \"aws-k8s\") && cfg!(variant_flavor = \"nvidia\") {\n        migrate(AddMetadataMigration(&[SettingMetadata {\n            metadata: &[\"affected-services\"],\n            setting: \"settings.container-runtime\",\n        }]))\n    } else {\n        migrate(NoOpMigration)\n    }\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/container-runtime-nvidia/Cargo.toml",
    "content": "[package]\nname = \"container-runtime-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Matthew Yeazel <yeazelm@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/container-runtime-nvidia/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/container-runtime-nvidia/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixesMigration, NoOpMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings only for NVIDIA k8s variants.\nfn run() -> Result<()> {\n    if cfg!(variant_family = \"aws-k8s\") && cfg!(variant_flavor = \"nvidia\") {\n        migrate(AddPrefixesMigration(vec![\"settings.container-runtime\"]))\n    } else {\n        migrate(NoOpMigration)\n    }\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/corndog-config-file-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"corndog-config-file-v0-1-0\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/corndog-config-file-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.corndog-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/corndog-services-cfg-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"corndog-services-cfg-v0-1-0\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/corndog-services-cfg-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![\n        ListReplacement {\n            setting: \"services.sysctl.configuration-files\",\n            old_vals: &[],\n            new_vals: &[\"corndog-toml\"],\n        },\n        ListReplacement {\n            setting: \"services.lockdown.configuration-files\",\n            old_vals: &[],\n            new_vals: &[\"corndog-toml\"],\n        },\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/host-containers-config-file-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"host-containers-config-file-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Sam Berning <bernings@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/host-containers-config-file-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// Create the new config file\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.host-containers-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/host-containers-config-list-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"host-containers-config-list-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Sam Berning <bernings@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/host-containers-config-list-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// Add new config file to host-containers\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.host-containers.configuration-files\",\n        old_vals: &[\"host-ctr-toml\"],\n        new_vals: &[\"host-ctr-toml\", \"host-containers-toml\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/prairiedog-config-file-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"prairiedog-config-file-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/prairiedog-config-file-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.prairiedog-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/prairiedog-services-cfg-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"prairiedog-services-cfg-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/prairiedog-services-cfg-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.bootconfig.configuration-files\",\n        old_vals: &[],\n        new_vals: &[\"prairiedog-toml\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/public-admin-container-v0-11-8/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-8\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/public-admin-container-v0-11-8/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.7\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.8\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/public-control-container-v0-7-12/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-12\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/public-control-container-v0-7-12/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.11\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.12\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/remove-ecs-settings-applier/Cargo.toml",
    "content": "[package]\nname = \"remove-ecs-settings-applier\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Arnaldo Garcia <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/remove-ecs-settings-applier/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.ecs' to remove\n/// ecs-settings-applier on upgrade, and to add it on downgrade.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.ecs.restart-commands\",\n        old_vals: &[\n            \"/usr/bin/ecs-settings-applier\",\n            \"/bin/systemctl try-reload-or-restart ecs.service\",\n        ],\n        new_vals: &[\"/bin/systemctl try-reload-or-restart ecs.service\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/static-pods-add-prefix-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"static-pods-add-prefix-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/static-pods-add-prefix-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.static-pods-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/static-pods-services-cfg-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"static-pods-services-cfg-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/static-pods-services-cfg-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.static-pods.configuration-files\",\n        old_vals: &[],\n        new_vals: &[\"static-pods-toml\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/thar-be-updates-affected-services-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"thar-be-updates-affected-services-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/thar-be-updates-affected-services-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.updates\",\n            metadata: \"affected-services\",\n            old_vals: &[\"updog\"],\n            new_vals: &[\"updog\", \"thar-be-updates\"],\n        },\n    ]))\n}\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/thar-be-updates-config-file-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"thar-be-updates-config-file-v0-1-0\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/thar-be-updates-config-file-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"configuration-files.thar-be-updates-toml\",\n        \"services.thar-be-updates\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/update-ecs-config-path/Cargo.toml",
    "content": "[package]\nname = \"update-ecs-config-path\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Arnaldo Garcia <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/update-ecs-config-path/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'path' string for 'ecs-config'\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"configuration-files.ecs-config.path\",\n        old_val: \"/etc/ecs/ecs.config\",\n        new_val: \"/etc/systemd/system/ecs.service.d/10-base.conf\",\n    })\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/update-ecs-config-template-path/Cargo.toml",
    "content": "[package]\nname = \"update-ecs-config-template-path\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Arnaldo Garcia <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.0/update-ecs-config-template-path/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'template-path' for 'ecs-config'\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"configuration-files.ecs-config.template-path\",\n        old_val: \"/usr/share/templates/ecs.config\",\n        new_val: \"/usr/share/templates/ecs-base-conf\",\n    })\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/aws-admin-container-v0-11-9/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-9\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/aws-admin-container-v0-11-9/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.8'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.9'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/aws-control-container-v0-7-13/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-13\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/aws-control-container-v0-7-13/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.12'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.13'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/public-admin-container-v0-11-9/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-9\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/public-admin-container-v0-11-9/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.8\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.9\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/public-control-container-v0-7-13/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-13\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.20.5/public-control-container-v0-7-13/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.12\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.13\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/add-hostname-override-source/Cargo.toml",
    "content": "[package]\nname = \"add-hostname-override-source\"\nversion = \"0.1.0\"\nauthors = [\"Todd Neal <tnealt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/add-hostname-override-source/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added one new settings for configuring the override method for the method used to determine\n/// the node\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.hostname-override-source\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/k8s-reserved-cpus-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"k8s-reserved-cpus-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"James Masson <james.masson@weareadaptive.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/k8s-reserved-cpus-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// Add the option to set Kubernetes reserved-cpus\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\"settings.kubernetes.reserved-cpus\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pluto-remove-generators-v0-1-0/Cargo.toml",
    "content": "[package]\nname = \"pluto-remove-generators-v0-1-0\"\nversion = \"0.1.0\"\nauthors = [\"Jarrett Tierney <jmt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pluto-remove-generators-v0-1-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::{RemoveMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\nfn run() -> Result<()> {\n    migrate(RemoveMetadataMigration(&[\n        SettingMetadata {\n            setting: \"settings.kubernetes.max-pods\",\n            metadata: &[\"setting-generator\"],\n        },\n        SettingMetadata {\n            setting: \"settings.kubernetes.cluster-dns-ip\",\n            metadata: &[\"setting-generator\"],\n        },\n        SettingMetadata {\n            setting: \"settings.kubernetes.node-ip\",\n            metadata: &[\"setting-generator\"],\n        },\n        SettingMetadata {\n            setting: \"settings.kubernetes.provider-id\",\n            metadata: &[\"setting-generator\"],\n        },\n        SettingMetadata {\n            setting: \"settings.kubernetes.hostname-override\",\n            metadata: &[\"setting-generator\"],\n        },\n    ]))\n}\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pod-infra-container-image-affected-services/Cargo.toml",
    "content": "[package]\nname = \"pod-infra-container-image-affected-services\"\nversion = \"0.1.0\"\nauthors = [\"Todd Neal <tnealt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pod-infra-container-image-affected-services/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.kubernetes.pod-infra-container-image\",\n            metadata: \"affected-services\",\n            old_vals: &[\"kubernetes\", \"containerd\"],\n            new_vals: &[\"pod-infra-container-image\"],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pod-infra-container-image-remove-settings-generator/Cargo.toml",
    "content": "[package]\nname = \"pod-infra-container-image-remove-settings-generator\"\nversion = \"0.1.0\"\nauthors = [\"Todd Neal <tnealt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pod-infra-container-image-remove-settings-generator/src/main.rs",
    "content": "use migration_helpers::common_migrations::{RemoveMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(RemoveMetadataMigration(&[SettingMetadata {\n        setting: \"settings.kubernetes.pod-infra-container-image\",\n        metadata: &[\"setting-generator\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pod-infra-container-image-services/Cargo.toml",
    "content": "[package]\nname = \"pod-infra-container-image-services\"\nversion = \"0.1.0\"\nauthors = [\"Todd Neal <tnealt@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.0/pod-infra-container-image-services/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"services.pod-infra-container-image\",\n        \"configuration-files.pod-infra-container-image-log-message\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/aws-admin-container-v0-11-10/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-10\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/aws-admin-container-v0-11-10/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.9'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.10'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/aws-control-container-v0-7-14/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-14\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/aws-control-container-v0-7-14/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.13'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.14'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/public-admin-container-v0-11-10/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-10\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/public-admin-container-v0-11-10/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.9\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.10\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/public-control-container-v0-7-14/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-14\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.21.1/public-control-container-v0-7-14/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.13\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.14\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/aws-admin-container-v0-11-11/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-11\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/aws-admin-container-v0-11-11/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.10'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.11'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/aws-control-container-v0-7-15/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-15\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/aws-control-container-v0-7-15/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.14'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.15'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/bootstrap-commands-metadata/Cargo.toml",
    "content": "[package]\nname = \"bootstrap-commands-metadata\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Piyush Jena <jepiyush@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/bootstrap-commands-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::migrate;\nuse migration_helpers::Result;\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings only for NVIDIA k8s variants.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.bootstrap-commands\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/bootstrap-commands-settings/Cargo.toml",
    "content": "[package]\nname = \"bootstrap-commands-settings\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Piyush Jena <jepiyush@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\nexclude = [\"README.md\"]\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/bootstrap-commands-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.bootstrap-commands\",\n        \"services.bootstrap-commands\",\n        \"configuration-files.bootstrap-commands-toml\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/public-admin-container-v0-11-11/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-11\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/public-admin-container-v0-11-11/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.10\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.11\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/public-control-container-v0-7-15/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-15\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.22.0/public-control-container-v0-7-15/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.14\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.15\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/kubelet-device-plugins-metadata/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Monirul Islam <monirulu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/kubelet-device-plugins-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring the NVIDIA k8s device plugin.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.kubelet-device-plugins\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/kubelet-device-plugins-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-settings\"\nversion = \"0.1.0\"\nauthors = [\"Monirul Islam <monirulu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/kubelet-device-plugins-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring the NVIDIA k8s device plugin.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubelet-device-plugins\",\n        \"services.nvidia-k8s-device-plugin\",\n        \"configuration-files.nvidia-k8s-device-plugin-conf\",\n        \"configuration-files.nvidia-k8s-device-plugin-exec-start-conf\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/nvidia-container-runtime-metadata/Cargo.toml",
    "content": "[package]\nname = \"nvidia-container-runtime-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Monirul Islam <monirulu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/nvidia-container-runtime-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings only for NVIDIA k8s variants.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.nvidia-container-runtime\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/nvidia-container-runtime-settings/Cargo.toml",
    "content": "[package]\nname = \"nvidia-container-runtime-settings\"\nversion = \"0.1.0\"\nauthors = [\"Monirul Islam <monirulu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.23.0/nvidia-container-runtime-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring container runtime (containerd) settings only for NVIDIA k8s variants.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.nvidia-container-runtime\",\n        \"services.nvidia-container-toolkit\",\n        \"configuration-files.nvidia-container-toolkit\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/aws-admin-container-v0-11-12/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-12\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/aws-admin-container-v0-11-12/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.11'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.12'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/aws-control-container-v0-7-16/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-16\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/aws-control-container-v0-7-16/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.15'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.16'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/public-admin-container-v0-11-12/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-12\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/public-admin-container-v0-11-12/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.11\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.12\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/public-control-container-v0-7-16/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-16\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.24.1/public-control-container-v0-7-16/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.15\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.16\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/aws-admin-container-v0-11-13/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-13\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/aws-admin-container-v0-11-13/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.12'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.13'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/aws-control-container-v0-7-17/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-17\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/aws-control-container-v0-7-17/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.16'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.17'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/kubelet-device-plugins-time-slicing-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-time-slicing-settings\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/kubelet-device-plugins-time-slicing-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for configuring the NVIDIA k8s device plugin.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubelet-device-plugins.nvidia.device-sharing-strategy\",\n        \"settings.kubelet-device-plugins.nvidia.time-slicing.replicas\",\n        \"settings.kubelet-device-plugins.nvidia.time-slicing.rename-by-default\",\n        \"settings.kubelet-device-plugins.nvidia.time-slicing.fail-requests-greater-than-one\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/kubernetes-service-config/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-service-config\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/kubernetes-service-config/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_MODE: &str = \"0600\";\nconst NEW_MODE: &str = \"0644\";\n\n/// We changed the version of configuration mode\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"configuration-files.kubelet-exec-start-conf.mode\",\n        old_val: OLD_MODE,\n        new_val: NEW_MODE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/public-admin-container-v0-11-13/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-13\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/public-admin-container-v0-11-13/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.12\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.13\";\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/public-control-container-v0-7-17/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-17\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.25.0/public-control-container-v0-7-17/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.16\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.17\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.27.0/aws-config/Cargo.toml",
    "content": "[package]\nname = \"aws-config\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.27.0/aws-config/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n///  We added new settings metadata, `aws.config.setting-generator`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"setting-generator\"],\n        setting: \"settings.aws.config\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/aws-admin-container-v0-11-14/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-14\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/aws-admin-container-v0-11-14/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.13'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.14'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/aws-control-container-v0-7-18/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-18\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/aws-control-container-v0-7-18/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.17'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.18'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/kernel-sysctl-hugepages/Cargo.toml",
    "content": "[package]\nname = \"kernel-sysctl-hugepages\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/kernel-sysctl-hugepages/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n///  We added new settings metadata, `metadata.settings.kernel.sysctl.vm/nr_hugepages.setting-generator`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"setting-generator\"],\n        setting: \"settings.kernel.sysctl.vm/nr_hugepages\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/public-admin-container-v0-11-14/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-14\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/public-admin-container-v0-11-14/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.13\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.14\";\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/public-control-container-v0-7-18/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-18\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.28.0/public-control-container-v0-7-18/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.17\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.18\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.3.0/control-container-v0-5-2/Cargo.toml",
    "content": "[package]\nname = \"control-container-v0-5-2\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.3.0/control-container-v0-5-2/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.1\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.2\";\n\n/// We bumped the version of the default control container from v0.5.1 to v0.5.2\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.3.0/etc-hosts-service/Cargo.toml",
    "content": "[package]\nname = \"etc-hosts-service\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.3.0/etc-hosts-service/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for configuring hostname\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"services.hosts\",\n        \"configuration-files.hosts\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.3.0/hostname-affects-etc-hosts/Cargo.toml",
    "content": "[package]\nname = \"hostname-affects-etc-hosts\"\nversion = \"0.1.0\"\nauthors = [\"Zac Mrowicki <mrowicki@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.3.0/hostname-affects-etc-hosts/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.network.hostname' to include the\n/// hosts \"service\" on upgrade, and to remove it on downgrade.\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.network.hostname\",\n            metadata: \"affected-services\",\n            old_vals: &[\"hostname\"],\n            new_vals: &[\"hostname\", \"hosts\"],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/aws-admin-container-v0-11-15/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-15\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/aws-admin-container-v0-11-15/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.14'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.15'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/aws-control-container-v0-7-19/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-19\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/aws-control-container-v0-7-19/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.18'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.19'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/kubernetes-device-ownership-metadata/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-device-ownership-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Vighnesh Maheshwari <vighmah@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/kubernetes-device-ownership-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n///  We added a new setting, `settings.kubernetes.device-ownership-from-security-context` to allow containers to gain\n/// ownership of the requested device\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.device-ownership-from-security-context\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/kubernetes-device-ownership-settings/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-device-ownership-settings\"\nversion = \"0.1.0\"\nauthors = [\"Vighnesh Maheshwari <vighmah@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/kubernetes-device-ownership-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n///  We added a new setting, `settings.kubernetes.device-ownership-from-security-context` to allow containers to gain\n/// ownership of the requested device\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.kubernetes.device-ownership-from-security-context\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/public-admin-container-v0-11-15/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-15\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/public-admin-container-v0-11-15/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.14\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.15\";\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/public-control-container-v0-7-19/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-19\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.30.0/public-control-container-v0-7-19/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.18\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.19\";\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/aws-admin-container-v0-11-16/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-11-16\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/aws-admin-container-v0-11-16/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.15'\";\nconst NEW_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.16'\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_schnauzer_cmdline: OLD_ADMIN_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/aws-control-container-v0-7-20/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-7-20\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/aws-control-container-v0-7-20/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.19'\";\nconst NEW_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.20'\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_schnauzer_cmdline: OLD_CONTROL_CTR_CMDLINE,\n        new_schnauzer_cmdline: NEW_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/public-admin-container-v0-11-16/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-11-16\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/public-admin-container-v0-11-16/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.15\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.16\";\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/public-control-container-v0-7-20/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-20\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.31.0/public-control-container-v0-7-20/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.19\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.20\";\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/aws-remove-schnauzer-admin/Cargo.toml",
    "content": "[package]\nname = \"aws-remove-schnauzer-admin\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/aws-remove-schnauzer-admin/src/main.rs",
    "content": "use migration_helpers::common_migrations::RemoveSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.11.16'\";\n\n/// We are removing settings.host-containers.admin.source setting\n/// to populate it from defaults.\nfn run() -> Result<()> {\n    migrate(RemoveSchnauzerMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_cmdline: OLD_ADMIN_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/aws-remove-schnauzer-control/Cargo.toml",
    "content": "[package]\nname = \"aws-remove-schnauzer-control\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/aws-remove-schnauzer-control/src/main.rs",
    "content": "use migration_helpers::common_migrations::RemoveSchnauzerMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_CMDLINE: &str =\n    \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.7.20'\";\n\n/// We are removing settings.host-containers.control.source setting\n/// to populate it from defaults.\nfn run() -> Result<()> {\n    migrate(RemoveSchnauzerMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_cmdline: OLD_CONTROL_CTR_CMDLINE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-control-container-v0-7-19-update/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-19-update\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-control-container-v0-7-19-update/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.18\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.19\";\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-control-container-v0-7-20-update/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-7-20-update\"\nversion = \"0.1.0\"\nauthors = [\"Sparks Song <shijiao@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-control-container-v0-7-20-update/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.19\";\nconst NEW_CONTROL_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.20\";\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR_SOURCE_VAL,\n        new_val: NEW_CONTROL_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-remove-source-admin/Cargo.toml",
    "content": "[package]\nname = \"public-remove-source-admin\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-remove-source-admin/src/main.rs",
    "content": "use migration_helpers::common_migrations::RemoveMatchingString;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.11.16\";\n\n/// We are removing settings.host-containers.admin.source setting\n/// to populate it from defaults.\nfn run() -> Result<()> {\n    migrate(RemoveMatchingString {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-remove-source-control/Cargo.toml",
    "content": "[package]\nname = \"public-remove-source-control\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/public-remove-source-control/src/main.rs",
    "content": "use migration_helpers::common_migrations::RemoveMatchingString;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.7.20\";\n\n/// We are removing settings.host-containers.admin.source setting\n/// to populate it from defaults.\nfn run() -> Result<()> {\n    migrate(RemoveMatchingString {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_CTR,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/remove-metadata-and-weak-settings-migration/Cargo.toml",
    "content": "[package]\nname = \"remove-metadata-and-weak-settings-migration\"\nversion = \"0.1.0\"\nauthors = [\"Shikha Vyaghra <vyaghras@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.33.0/remove-metadata-and-weak-settings-migration/src/main.rs",
    "content": "use migration_helpers::common_migrations::RemoveMetadataAndWeakSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// Remove the weak settings and metadata on downgrade\nfn run() -> Result<()> {\n    migrate(RemoveMetadataAndWeakSettingsMigration)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.4.0/registry-mirror-representation/Cargo.toml",
    "content": "[package]\nname = \"registry-mirror-representation\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\nserde_json = \"1.0\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.4.0/registry-mirror-representation/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse serde_json::{Map, Value};\nuse std::collections::HashMap;\nuse std::process;\n\nconst MIRRORS_SETTING_NAME: &'static str = \"settings.container-registry.mirrors\";\nconst DATASTORE_KEY_SEPARATOR: char = '.';\n\n/// This migration changes the model type of `settings.container-registry.mirrors` from `HashMap<SingleLineString, Vec<Url>>`\n/// to `Vec<RegistryMirrors>` on upgrade and vice-versa on downgrades.\npub struct ChangeRegistryMirrorsType;\n\n// Snapshot of the `datastore::Key::valid_character` method in Bottlerocket version 1.3.0\n//\n// Determines whether a character is acceptable within a segment of a key name.  This is\n// separate from quoting; if a character isn't valid, it isn't valid quoted, either.\nfn valid_character(c: char) -> bool {\n    match c {\n        'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '/' => true,\n        _ => false,\n    }\n}\n\nimpl Migration for ChangeRegistryMirrorsType {\n    /// Newer versions store `settings.container-registry.mirrors` as `Vec<RegistryMirrors>`.\n    /// Need to convert from `HashMap<SingleLineString, Vec<Url>>`.\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let mirrors: HashMap<_, _> = input\n            .data\n            .iter()\n            .filter(|&(k, _)| k.starts_with(format!(\"{}.\", MIRRORS_SETTING_NAME).as_str()))\n            .map(|(k, v)| (k.to_owned(), v.to_owned()))\n            .collect();\n        let mut new_mirrors = Vec::new();\n        for (setting, endpoint) in mirrors {\n            // Get the registry name from the settings name. Trim any quotes the settings name might have.\n            let registry = setting\n                .strip_prefix(&format!(\"{}.\", MIRRORS_SETTING_NAME))\n                .unwrap_or_default()\n                .trim_matches('\"');\n            let mut registry_mirrors = Map::new();\n            registry_mirrors.insert(\"registry\".to_string(), Value::String(registry.to_string()));\n            registry_mirrors.insert(\"endpoint\".to_string(), endpoint.to_owned());\n            new_mirrors.push(Value::Object(registry_mirrors));\n            if let Some(data) = input.data.remove(&setting) {\n                println!(\"Removed setting '{}', which was set to '{}'\", setting, data);\n            }\n        }\n        let data = Value::Array(new_mirrors);\n        println!(\n            \"Creating new setting '{}', which is set to '{}'\",\n            MIRRORS_SETTING_NAME, &data\n        );\n        input.data.insert(MIRRORS_SETTING_NAME.to_string(), data);\n        Ok(input)\n    }\n\n    /// Older versions store `settings.container-registry.mirrors` as `HashMap<SingleLineString, Vec<Url>>`.\n    /// Need to convert from `Vec<RegistryMirrors>`.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(data) = input.data.get_mut(MIRRORS_SETTING_NAME).cloned() {\n            match data {\n                Value::Array(arr) => {\n                    if let Some(data) = input.data.remove(MIRRORS_SETTING_NAME) {\n                        println!(\n                            \"Removed setting '{}', which was set to '{}'\",\n                            MIRRORS_SETTING_NAME, data\n                        );\n                    }\n                    for obj in arr {\n                        if let Some(obj) = obj.as_object() {\n                            if let (Some(registry), Some(endpoint)) = (\n                                obj.get(\"registry\").and_then(|s| s.as_str()),\n                                obj.get(\"endpoint\"),\n                            ) {\n                                // Ensure the registry contains valid datastore key characters.\n                                // If we encounter any invalid key characters, we skip writing out\n                                // the setting key to prevent breakage of the datastore.\n                                if registry\n                                    .chars()\n                                    .all(|c| valid_character(c) || c == DATASTORE_KEY_SEPARATOR)\n                                {\n                                    let setting_name =\n                                        format!(r#\"{}.\"{}\"\"#, MIRRORS_SETTING_NAME, registry);\n                                    println!(\n                                        \"Creating new setting '{}', which is set to '{}'\",\n                                        setting_name, &endpoint\n                                    );\n                                    input.data.insert(setting_name, endpoint.to_owned());\n                                } else {\n                                    eprintln!(\n                                        \"Container registry '{}' contains invalid datastore key character(s). Skipping to prevent datastore breakage...\",\n                                        registry\n                                    );\n                                }\n                            }\n                        } else {\n                            println!(\n                                \"'{}' contains non-JSON Object value: '{}'.\",\n                                MIRRORS_SETTING_NAME, obj\n                            );\n                        }\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is not a JSON Array value: '{}'.\",\n                        MIRRORS_SETTING_NAME, data\n                    );\n                }\n            }\n        } else {\n            println!(\"Didn't find setting '{}'\", MIRRORS_SETTING_NAME);\n        }\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    migrate(ChangeRegistryMirrorsType)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.4.2/admin-container-v0-7-3/Cargo.toml",
    "content": "[package]\nname = \"admin-container-v0-7-3\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.4.2/admin-container-v0-7-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.2\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.3\";\n\n/// We bumped the version of the default admin container from v0.7.2 to v0.7.3\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.4.2/control-container-v0-5-3/Cargo.toml",
    "content": "[package]\nname = \"control-container-v0-5-3\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.4.2/control-container-v0-5-3/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.2\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.3\";\n\n/// We bumped the version of the default control container from v0.5.2 to v0.5.3\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.0/oci-hooks-setting/Cargo.toml",
    "content": "[package]\nname = \"oci-hooks-setting\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.0/oci-hooks-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for configuring oci hooks\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.oci-hooks\",\n        \"services.oci-hooks\",\n        \"configuration-files.oci-hooks\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.0/oci-hooks-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"oci-hooks-setting-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.0/oci-hooks-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for configuring oci hooks\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.oci-hooks\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.1/control-container-v0-5-4/Cargo.toml",
    "content": "[package]\nname = \"control-container-v0-5-4\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.1/control-container-v0-5-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.3\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.4\";\n\n/// We bumped the version of the default control container from v0.5.3 to v0.5.4\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.3/vmware-host-containers/Cargo.toml",
    "content": "[package]\nname = \"vmware-host-containers\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nserde_json = \"1\"\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.5.3/vmware-host-containers/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst ADMIN_CONTAINER_SOURCE_SETTING_NAME: &str = \"settings.host-containers.admin.source\";\nconst ADMIN_CONTAINER_IMAGE_REPOSITORY: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin\";\nconst PREVIOUS_ADMIN_CONTAINER_VERSIONS: &[&str] = &[\"v0.7.0\", \"v0.7.1\", \"v0.7.2\"];\nconst TARGET_ADMIN_CONTAINER_VERSION: &str = \"v0.7.3\";\n\nconst CONTROL_CONTAINER_SOURCE_SETTING_NAME: &str = \"settings.host-containers.control.source\";\nconst CONTROL_CONTAINER_IMAGE_REPOSITORY: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control\";\nconst PREVIOUS_CONTROL_CONTAINER_VERSIONS: &[&str] = &[\"v0.5.0\", \"v0.5.1\", \"v0.5.2\", \"v0.5.3\"];\nconst TARGET_CONTROL_CONTAINER_VERSION: &str = \"v0.5.4\";\n\npub struct VmwareHostContainerVersions;\n\nimpl Migration for VmwareHostContainerVersions {\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        // For admin container\n        if let Some(data) = input.data.get_mut(ADMIN_CONTAINER_SOURCE_SETTING_NAME) {\n            match data {\n                serde_json::Value::String(source) => {\n                    for ver in PREVIOUS_ADMIN_CONTAINER_VERSIONS {\n                        let prev_source = format!(\"{}:{}\", ADMIN_CONTAINER_IMAGE_REPOSITORY, ver);\n                        if *source == prev_source {\n                            *source = format!(\n                                \"{}:{}\",\n                                ADMIN_CONTAINER_IMAGE_REPOSITORY, TARGET_ADMIN_CONTAINER_VERSION\n                            );\n                            println!(\n                                \"Changed value of '{}' from '{}' to '{}' on upgrade\",\n                                ADMIN_CONTAINER_SOURCE_SETTING_NAME, prev_source, source\n                            );\n                            break;\n                        }\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'\",\n                        ADMIN_CONTAINER_SOURCE_SETTING_NAME, data\n                    );\n                }\n            }\n        } else {\n            println!(\n                \"Found no '{}' to change on upgrade\",\n                ADMIN_CONTAINER_SOURCE_SETTING_NAME\n            );\n        }\n\n        // For control container\n        if let Some(data) = input.data.get_mut(CONTROL_CONTAINER_SOURCE_SETTING_NAME) {\n            match data {\n                serde_json::Value::String(source) => {\n                    for ver in PREVIOUS_CONTROL_CONTAINER_VERSIONS {\n                        let prev_source = format!(\"{}:{}\", CONTROL_CONTAINER_IMAGE_REPOSITORY, ver);\n                        if *source == prev_source {\n                            *source = format!(\n                                \"{}:{}\",\n                                CONTROL_CONTAINER_IMAGE_REPOSITORY,\n                                TARGET_CONTROL_CONTAINER_VERSION\n                            );\n                            println!(\n                                \"Changed value of '{}' from '{}' to '{}' on upgrade\",\n                                CONTROL_CONTAINER_SOURCE_SETTING_NAME, prev_source, source\n                            );\n                            break;\n                        }\n                    }\n                }\n                _ => {\n                    println!(\n                        \"'{}' is set to non-string value '{}'\",\n                        CONTROL_CONTAINER_SOURCE_SETTING_NAME, data\n                    );\n                }\n            }\n        } else {\n            println!(\n                \"Found no '{}' to change on upgrade\",\n                CONTROL_CONTAINER_SOURCE_SETTING_NAME\n            );\n        }\n\n        Ok(input)\n    }\n\n    fn backward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        // It's unclear what version of the host-containers we should downgrade to since it could\n        // be any of the older host-container versions.\n        // We can just stay on the latest host-container version since there are no breaking changes.\n        println!(\"Vmware host-container versions migration has no work to do on downgrade\");\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    migrate(VmwareHostContainerVersions)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/aws-admin-container-v0-7-4/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-7-4\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/aws-admin-container-v0-7-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.3\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.4\";\n\n/// We bumped the version of the default admin container from v0.7.3 to v0.7.4\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/aws-control-container-v0-5-5/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-5-5\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/aws-control-container-v0-5-5/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.4\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.5\";\n\n/// We bumped the version of the default control container from v0.5.4 to v0.5.5\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/node-taints-representation/Cargo.toml",
    "content": "[package]\nname = \"node-taints-representation\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\nserde_json = \"1\"\nsnafu = \"0.8\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/node-taints-representation/src/main.rs",
    "content": "use migration_helpers::{error, migrate, Migration, MigrationData, Result};\nuse serde_json::Value;\nuse snafu::OptionExt;\nuse std::process;\n\nconst NODE_TAINTS_SETTING_NAME: &str = \"settings.kubernetes.node-taints\";\n\n/// This migration changes the model type of `settings.kubernetes.node-taints` from `HashMap<KubernetesLabelKey, KubernetesTaintValue>`\n/// to `HashMap<KubernetesLabelKey, Vec<KubernetesTaintValue>>` on upgrade and vice-versa on downgrades.\npub struct ChangeNodeTaintsType;\n\nimpl Migration for ChangeNodeTaintsType {\n    /// Newer versions store `settings.kubernetes.node-taints` as `HashMap<KubernetesLabelKey, Vec<KubernetesTaintValue>>`.\n    /// Need to convert from `HashMap<KubernetesLabelKey, KubernetesTaintValue>`.\n    fn forward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for (taint_key, taint_val) in input\n            .data\n            .iter_mut()\n            .filter(|&(k, _)| k.starts_with(format!(\"{}.\", NODE_TAINTS_SETTING_NAME).as_str()))\n        {\n            match taint_val {\n                Value::String(taint_val_string) => {\n                    let taint_val_array =\n                        Value::Array(vec![Value::String(taint_val_string.to_owned())]);\n                    println!(\n                        \"Changing '{}', from '{}' to '{}' on upgrade\",\n                        taint_key, &taint_val, taint_val_array\n                    );\n                    *taint_val = taint_val_array;\n                }\n                _ => {\n                    println!(\n                        \"'{}' is not a JSON string value: '{}'\",\n                        taint_key, taint_val\n                    );\n                }\n            }\n        }\n        Ok(input)\n    }\n\n    /// Older versions store `settings.kubernetes.node-taints` as `HashMap<KubernetesLabelKey, KubernetesTaintValue>`.\n    /// Need to convert from `HashMap<KubernetesLabelKey, Vec<KubernetesTaintValue>>`.\n    ///\n    /// Note that this potentially causes data loss if there are more than one taint value/effect assigned to a taint key.\n    /// Older versions can only map one taint value/effect to a taint key, so we default to choosing the first in the list if there are multiple.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        for (taint_key, taint_val) in input\n            .data\n            .iter_mut()\n            .filter(|&(k, _)| k.starts_with(format!(\"{}.\", NODE_TAINTS_SETTING_NAME).as_str()))\n        {\n            match taint_val {\n                Value::Array(taint_val_array) => {\n                    // There should always at least be one value in the sequence\n                    let first_taint_val = Value::String(\n                        taint_val_array\n                            .first()\n                            .cloned()\n                            .unwrap_or_default()\n                            .as_str()\n                            .context(error::NonStringSettingDataTypeSnafu {\n                                setting: taint_key.to_string(),\n                            })?\n                            .to_string(),\n                    );\n                    println!(\n                        \"Changing '{}', from '{}' to '{}' on downgrade\",\n                        taint_key, &taint_val, first_taint_val\n                    );\n                    *taint_val = first_taint_val;\n                }\n                _ => {\n                    println!(\"'{}' is not a JSON Array value: '{}'\", taint_key, taint_val);\n                }\n            }\n        }\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    migrate(ChangeNodeTaintsType)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/public-admin-container-v0-7-4/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-7-4\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/public-admin-container-v0-7-4/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.7.3\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.7.4\";\n\n/// We bumped the version of the default admin container from v0.7.3 to v0.7.4\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/public-control-container-v0-5-5/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-5-5\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.0/public-control-container-v0-5-5/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.5.4\";\nconst NEW_CONTROL_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.5.5\";\n\n/// We bumped the version of the default control container from v0.5.4 to v0.5.5\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_SOURCE_VAL,\n        new_val: NEW_CONTROL_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.2/add-cfsignal/Cargo.toml",
    "content": "[package]\nname = \"add-cfsignal\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.2/add-cfsignal/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a set of settings for configuring service cfsignal.\n/// Remove the whole `settings.cloudformation` prefix if we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.cloudformation\",\n        \"services.cfsignal\",\n        \"configuration-files.cfsignal-toml\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.2/container-registry-credentials/Cargo.toml",
    "content": "[package]\nname = \"container-registry-credentials\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.2/container-registry-credentials/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring image credentials, `settings.container-registry.credentials`\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.container-registry.credentials\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.2/container-registry-credentials-metadata/Cargo.toml",
    "content": "[package]\nname = \"container-registry-credentials-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.6.2/container-registry-credentials-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and `affected-services` metadata for `container-registry.credentials`\n/// We subdivided metadata for `container-registry` into `container-registry.mirrors` and `container-registry.credentials`\n/// This is for the docker variants where don't want to restart the docker daemon when credentials settings change.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[\n        SettingMetadata {\n            metadata: &[\"affected-services\"],\n            setting: \"settings.container-registry.credentials\",\n        },\n        SettingMetadata {\n            metadata: &[\"affected-services\"],\n            setting: \"settings.container-registry.mirrors\",\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/aws-admin-container-v0-8-0/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-8-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/aws-admin-container-v0-8-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.7.4\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.8.0\";\n\n/// We bumped the version of the default admin container from v0.7.4 to v0.8.0\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/aws-control-container-v0-6-0/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-6-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/aws-control-container-v0-6-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.5.5\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.0\";\n\n/// We bumped the version of the default control container from v0.5.5 to v0.6.0\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/public-admin-container-v0-8-0/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-8-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/public-admin-container-v0-8-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.7.4\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.8.0\";\n\n/// We bumped the version of the default admin container from v0.7.4 to v0.8.0\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/public-control-container-v0-6-0/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-6-0\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.7.0/public-control-container-v0-6-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.5.5\";\nconst NEW_CONTROL_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.0\";\n\n/// We bumped the version of the default control container from v0.5.5 to v0.6.0\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_SOURCE_VAL,\n        new_val: NEW_CONTROL_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/add-autoscaling/Cargo.toml",
    "content": "[package]\nname = \"add-autoscaling\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/add-autoscaling/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a setting prefix for configuring autoscaling.\n/// Remove the whole `settings.autoscaling` prefix if we downgrade.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\"settings.autoscaling\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/add-pull-behavior/Cargo.toml",
    "content": "[package]\nname = \"add-pull-behavior\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/add-pull-behavior/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added one new settings for configuring ecs-agent, `settings.ecs.image-pull-behavior`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\"settings.ecs.image-pull-behavior\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/aws-admin-container-v0-9-0/Cargo.toml",
    "content": "[package]\nname = \"aws-admin-container-v0-9-0\"\nversion = \"0.1.0\"\nauthors = [\"Richard Kelly <rpkelly@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/aws-admin-container-v0-9-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.8.0\";\nconst NEW_ADMIN_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.9.0\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_template: OLD_ADMIN_CTR_TEMPLATE,\n        new_template: NEW_ADMIN_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/aws-control-container-v0-6-1/Cargo.toml",
    "content": "[package]\nname = \"aws-control-container-v0-6-1\"\nversion = \"0.1.0\"\nauthors = [\"Richard Kelly <rpkelly@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/aws-control-container-v0-6-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceTemplateMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.0\";\nconst NEW_CONTROL_CTR_TEMPLATE: &str =\n    \"{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.6.1\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceTemplateMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_template: OLD_CONTROL_CTR_TEMPLATE,\n        new_template: NEW_CONTROL_CTR_TEMPLATE,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/boot-setting/Cargo.toml",
    "content": "[package]\nname = \"boot-setting\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/boot-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for kernel boot configuration\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.boot\",\n        \"services.bootconfig\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/boot-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"boot-setting-metadata\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/boot-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and generator for kernel boot configuration\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.boot\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/cluster-dns-ip-list/Cargo.toml",
    "content": "[package]\nname = \"cluster-dns-ip-list\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n\n[dev-dependencies]\nserde_json = \"1\"\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/cluster-dns-ip-list/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst CLUSTER_DNS_IP_KEY: &str = \"settings.kubernetes.cluster-dns-ip\";\n\n/// We changed `settings.kubernetes.cluster-dns-ip` to support being either a string or a list of strings.\nfn run() -> Result<()> {\n    migrate(ClusterDNSIPListMigration)\n}\n\nstruct ClusterDNSIPListMigration;\n\nimpl Migration for ClusterDNSIPListMigration {\n    /// New versions allow the older string values to be present, so we don't need to do anything.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"ClusterDNSIPListMigration has no work to do on upgrade.\");\n        Ok(input)\n    }\n\n    /// Older versions don't know about list-style settings, so we need to create a scalar setting using the first value.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let maybe_prior_value = input.data.get(CLUSTER_DNS_IP_KEY);\n\n        // If the current value is a string, don't touch it.\n        if let Some(prior_value) = maybe_prior_value {\n            if prior_value.is_string() {\n                println!(\n                    \"{} is already a string value ('{}'), and does not require migration.\",\n                    CLUSTER_DNS_IP_KEY, prior_value\n                );\n                return Ok(input);\n            }\n        }\n\n        // If the current value is an array and the first element is a string, that element becomes the new value.\n        // Any other cases result in clearing the value.\n        let new_value = maybe_prior_value\n            .and_then(|dns_ip_value| {\n                println!(\n                    \"Found existing value for '{}': '{}'\",\n                    CLUSTER_DNS_IP_KEY, dns_ip_value\n                );\n                dns_ip_value.as_array()\n            })\n            .and_then(|ip_array| ip_array.iter().next())\n            .map(|ip_value| ip_value.clone());\n\n        match new_value {\n            Some(ip_value) if ip_value.is_string() => {\n                input\n                    .data\n                    .insert(CLUSTER_DNS_IP_KEY.to_string(), ip_value.clone());\n                println!(\n                    \"Replaced prior value for '{}' with '{}'\",\n                    CLUSTER_DNS_IP_KEY, ip_value\n                );\n            }\n            _ => {\n                println!(\n                    \"Prior value for '{}' was not recognized. Removing it.\",\n                    CLUSTER_DNS_IP_KEY\n                );\n                input.data.remove(CLUSTER_DNS_IP_KEY);\n            }\n        };\n\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use std::collections::HashMap;\n\n    #[test]\n    fn test_downgrade_string() {\n        let input = MigrationData {\n            data: serde_json::from_str(r#\"{\"settings.kubernetes.cluster-dns-ip\": \"10.0.0.1\"}\"#)\n                .unwrap(),\n            metadata: HashMap::new(),\n        };\n        let expected = MigrationData {\n            data: serde_json::from_str(r#\"{\"settings.kubernetes.cluster-dns-ip\": \"10.0.0.1\"}\"#)\n                .unwrap(),\n            metadata: HashMap::new(),\n        };\n        assert_eq!(ClusterDNSIPListMigration.backward(input).unwrap(), expected);\n    }\n\n    #[test]\n    fn test_downgrade_list() {\n        let test_cases = [\n            (\n                MigrationData {\n                    data: serde_json::from_str(\n                        r#\"{\"settings.kubernetes.cluster-dns-ip\": [\"10.0.0.1\"]}\"#,\n                    )\n                    .unwrap(),\n                    metadata: HashMap::new(),\n                },\n                MigrationData {\n                    data: serde_json::from_str(\n                        r#\"{\"settings.kubernetes.cluster-dns-ip\": \"10.0.0.1\"}\"#,\n                    )\n                    .unwrap(),\n                    metadata: HashMap::new(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: serde_json::from_str(r#\"{\"settings.kubernetes.cluster-dns-ip\": []}\"#)\n                        .unwrap(),\n                    metadata: HashMap::new(),\n                },\n                MigrationData {\n                    data: HashMap::new(),\n                    metadata: HashMap::new(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: serde_json::from_str(\n                        r#\"{\"settings.kubernetes.cluster-dns-ip\": [\"10.0.0.2\", \"10.0.0.1\"]}\"#,\n                    )\n                    .unwrap(),\n                    metadata: HashMap::new(),\n                },\n                MigrationData {\n                    data: serde_json::from_str(\n                        r#\"{\"settings.kubernetes.cluster-dns-ip\": \"10.0.0.2\"}\"#,\n                    )\n                    .unwrap(),\n                    metadata: HashMap::new(),\n                },\n            ),\n        ];\n        for (input, expected) in test_cases.iter() {\n            assert_eq!(\n                ClusterDNSIPListMigration.backward(input.clone()).unwrap(),\n                *expected\n            );\n        }\n    }\n\n    #[test]\n    fn test_downgrade_other() {\n        let test_cases = [\n            (\n                MigrationData {\n                    data: serde_json::from_str(\n                        r#\"{\"settings.kubernetes.cluster-dns-ip\": {\"1\": 2}}\"#,\n                    )\n                    .unwrap(),\n                    metadata: HashMap::new(),\n                },\n                MigrationData {\n                    data: HashMap::new(),\n                    metadata: HashMap::new(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: serde_json::from_str(r#\"{\"settings.kubernetes.cluster-dns-ip\": 56}\"#)\n                        .unwrap(),\n                    metadata: HashMap::new(),\n                },\n                MigrationData {\n                    data: HashMap::new(),\n                    metadata: HashMap::new(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: serde_json::from_str(r#\"{\"settings.kubernetes.cluster-dns-ip\": false}\"#)\n                        .unwrap(),\n                    metadata: HashMap::new(),\n                },\n                MigrationData {\n                    data: HashMap::new(),\n                    metadata: HashMap::new(),\n                },\n            ),\n        ];\n        for (input, expected) in test_cases.iter() {\n            assert_eq!(\n                ClusterDNSIPListMigration.backward(input.clone()).unwrap(),\n                *expected\n            );\n        }\n    }\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/etc-hosts/Cargo.toml",
    "content": "[package]\nname = \"etc-hosts\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/etc-hosts/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting under `settings.network` for configuring /etc/hosts: `settings.network.hosts`\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\"settings.network.hosts\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/etc-hosts-metadata/Cargo.toml",
    "content": "[package]\nname = \"etc-hosts-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/etc-hosts-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and `affected-services` metadata for `network.hosts`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.network.hosts\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/kubelet-pod-pids-limit/Cargo.toml",
    "content": "[package]\nname = \"kubelet-pod-pids-limit\"\nversion = \"0.1.0\"\nauthors = [\"Tianhao Geng <tianhg@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/kubelet-pod-pids-limit/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring pod-pids-limit, `settings.kubernetes.pod-pids-limit`\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubernetes.pod-pids-limit\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/kubelet-provider-id/Cargo.toml",
    "content": "[package]\nname = \"kubelet-provider-id\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Erikson Tung <etung@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/kubelet-provider-id/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring kubelet's provider-id option, `settings.kubernetes.provider-id`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\"settings.kubernetes.provider-id\"]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/pki-affected-services/Cargo.toml",
    "content": "[package]\nname = \"pki-affected-services\"\nversion = \"0.1.0\"\nauthors = [\"Arnaldo Garcia Rincon <agarrcia@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\nbuild = \"build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n\n[build-dependencies]\nbottlerocket-variant = { version = \"0.1\", path = \"../../../../../bottlerocket-variant\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/pki-affected-services/build.rs",
    "content": "use bottlerocket_variant::Variant;\n\nfn main() {\n    let variant = Variant::from_env().unwrap();\n    variant.emit_cfgs();\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/pki-affected-services/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.pki' to include\n/// containerd or docker on upgrade, and to remove them on downgrade depending on the\n/// running variant.\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.pki\",\n            metadata: \"affected-services\",\n            old_vals: &[\"pki\"],\n            new_vals: if cfg!(variant_runtime = \"k8s\") {\n                &[\"pki\", \"containerd\"]\n            } else {\n                &[\"pki\", \"docker\"]\n            },\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/public-admin-container-v0-9-0/Cargo.toml",
    "content": "[package]\nname = \"public-admin-container-v0-9-0\"\nversion = \"0.1.0\"\nauthors = [\"Richard Kelly <rpkelly@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/public-admin-container-v0-9-0/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.8.0\";\nconst NEW_ADMIN_CTR_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-admin:v0.9.0\";\n\n/// We bumped the version of the default admin container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.admin.source\",\n        old_val: OLD_ADMIN_CTR_SOURCE_VAL,\n        new_val: NEW_ADMIN_CTR_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/public-control-container-v0-6-1/Cargo.toml",
    "content": "[package]\nname = \"public-control-container-v0-6-1\"\nversion = \"0.1.0\"\nauthors = [\"Richard Kelly <rpkelly@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.8.0/public-control-container-v0-6-1/src/main.rs",
    "content": "use migration_helpers::common_migrations::ReplaceStringMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\nconst OLD_CONTROL_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.0\";\nconst NEW_CONTROL_SOURCE_VAL: &str = \"public.ecr.aws/bottlerocket/bottlerocket-control:v0.6.1\";\n\n/// We bumped the version of the default control container\nfn run() -> Result<()> {\n    migrate(ReplaceStringMigration {\n        setting: \"settings.host-containers.control.source\",\n        old_val: OLD_CONTROL_SOURCE_VAL,\n        new_val: NEW_CONTROL_SOURCE_VAL,\n    })\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/image-gc-thresholds/Cargo.toml",
    "content": "[package]\nname = \"image-gc-thresholds\"\nversion = \"0.1.0\"\nedition = \"2018\"\nauthors = [\"Mahdi Chaker <mmchaker@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/image-gc-thresholds/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting for configuring kubelet's image-gc-high-threshold-percent\n/// and image-gc-low-threshold-percent options,\n/// `settings.kubernetes.image-gc-high-threshold-percent` and\n/// `settings.kubernetes.image-gc-low-threshold-percent`\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.image-gc-high-threshold-percent\",\n        \"settings.kubernetes.image-gc-low-threshold-percent\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/kernel-modules-setting/Cargo.toml",
    "content": "[package]\nname = \"kernel-modules-setting\"\nversion = \"0.1.0\"\nauthors = [\"Ben Cressey <bcressey@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/kernel-modules-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings under `settings.kernel.modules` for configuring\n/// /etc/modprobe.d/modprobe.conf.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kernel.modules\",\n        \"services.kernel-modules\",\n        \"configuration-files.modprobe-conf\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/kernel-modules-setting-metadata/Cargo.toml",
    "content": "[package]\nname = \"kernel-modules-setting-metadata\"\nversion = \"0.1.0\"\nauthors = [\"Ben Cressey <bcressey@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/kernel-modules-setting-metadata/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a new setting and `affected-services` metadata for `settings.kernel.modules`\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        metadata: &[\"affected-services\"],\n        setting: \"settings.kernel.modules\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/kubelet-no-daemon-reload/Cargo.toml",
    "content": "[package]\nname = \"kubelet-no-daemon-reload\"\nversion = \"0.1.0\"\nauthors = [\"Ben Cressey <bcressey@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/kubelet-no-daemon-reload/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the restart commands for kubelet to avoid an unnecessary reload\n/// of systemd. They need to be restored to the prior values on downgrade.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"services.kubernetes.restart-commands\",\n        old_vals: &[\n            \"/usr/bin/systemctl daemon-reload\",\n            \"/usr/bin/systemctl try-restart kubelet.service\",\n        ],\n        new_vals: &[\"/usr/bin/systemctl try-restart kubelet.service\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/ntp-affected-services/Cargo.toml",
    "content": "[package]\nname = \"ntp-affected-services\"\nversion = \"0.1.0\"\nauthors = [\"Ben Cressey <bcressey@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\" }\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/ntp-affected-services/src/main.rs",
    "content": "use migration_helpers::common_migrations::{\n    MetadataListReplacement, ReplaceMetadataListsMigration,\n};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We updated the 'affected-services' list metadata for 'settings.ntp' to refer\n/// to the correct service name (\"ntp\") instead of the incorrect one (\"chronyd\").\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataListsMigration(vec![\n        MetadataListReplacement {\n            setting: \"settings.ntp\",\n            metadata: \"affected-services\",\n            old_vals: &[\"chronyd\"],\n            new_vals: &[\"ntp\"],\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/shibaken-admin-userdata-semantics/Cargo.toml",
    "content": "[package]\nname = \"shibaken-admin-userdata-semantics\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/shibaken-admin-userdata-semantics/src/main.rs",
    "content": "use migration_helpers::common_migrations::{MetadataReplacement, ReplaceMetadataMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We modified the setting generator for `settings.host-containers.admin.user-data` to use the\n/// new interface to shibaken.\nfn run() -> Result<()> {\n    migrate(ReplaceMetadataMigration(vec![MetadataReplacement {\n        setting: \"settings.host-containers.admin.user-data\",\n        metadata: \"setting-generator\",\n        old_val: \"shibaken\",\n        new_val: \"shibaken generate-admin-userdata\",\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/shibaken-send-metrics/Cargo.toml",
    "content": "[package]\nname = \"shibaken-send-metrics\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/shibaken-send-metrics/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a `setting-generator` for `settings.metrics.send-metrics` on AWS variants.\n/// This migration will do nothing on upgrade, but will remove the metadata if present on downgrade.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        setting: \"settings.metrics.send-metrics\",\n        metadata: &[\"setting-generator\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/updates-targets-base-url/Cargo.toml",
    "content": "[package]\nname = \"updates-targets-base-url\"\nversion = \"0.1.0\"\nauthors = [\"Patrick J.P. Culp <jpculp@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2018\"\npublish = false\n\n[dependencies]\nmigration-helpers = { path = \"../../../migration-helpers\", version = \"0.1.0\"}\n"
  },
  {
    "path": "sources/settings-migrations/archived/v1.9.0/updates-targets-base-url/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddMetadataMigration, SettingMetadata};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added a `setting-generator` for `settings.updates.targets-base-url` on AWS variants.\n/// This migration will do nothing on upgrade, but will remove the metadata if present on downgrade.\nfn run() -> Result<()> {\n    migrate(AddMetadataMigration(&[SettingMetadata {\n        setting: \"settings.updates.targets-base-url\",\n        metadata: &[\"setting-generator\"],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{}\", e);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.34.0/kubelet-device-plugins-mig-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-mig-settings\"\nversion = \"0.1.0\"\nauthors = [\"Piyush Jena <jepiyush@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.34.0/kubelet-device-plugins-mig-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for configuring the NVIDIA k8s device plugin.\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubelet-device-plugins.nvidia.device-partitioning-strategy\",\n        \"settings.kubelet-device-plugins.nvidia.mig\",\n        \"configuration-files.nvidia-k8s-device-plugin-mig-conf\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.36.0/kubernetes-ecr-credential-providers-expansion/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-ecr-credential-providers-expansion\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.36.0/kubernetes-ecr-credential-providers-expansion/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new hostname patterns to be matched by the ECR credential provider.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"settings.kubernetes.credential-providers.ecr-credential-provider.image-patterns\",\n        old_vals: &[\n            \"*.dkr.ecr.*.amazonaws.com\",\n            \"*.dkr.ecr.*.amazonaws.com.cn\",\n            \"*.dkr.ecr-fips.*.amazonaws.com\",\n            \"*.dkr.ecr.eu-isoe-west-1.cloud.adc-e.uk\",\n            \"*.dkr.ecr-fips.eu-isoe-west-1.cloud.adc-e.uk\",\n            \"*.dkr.ecr.us-iso-east-1.c2s.ic.gov\",\n            \"*.dkr.ecr.us-isob-east-1.sc2s.sgov.gov\",\n        ],\n        new_vals: &[\n            \"*.dkr.ecr.*.amazonaws.com\",\n            \"*.dkr.ecr.*.amazonaws.com.cn\",\n            \"*.dkr.ecr.*.on.aws\",\n            \"*.dkr.ecr.*.on.amazonwebservices.com.cn\",\n            \"*.dkr.ecr-fips.*.amazonaws.com\",\n            \"*.dkr.ecr.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr-fips.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr.*.c2s.ic.gov\",\n            \"*.dkr.ecr-fips.*.c2s.ic.gov\",\n            \"*.dkr.ecr.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr-fips.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr.*.csp.hci.ic.gov\",\n            \"*.dkr.ecr-fips.*.csp.hci.ic.gov\",\n            \"public.ecr.aws\",\n        ],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.37.0/delete-configs-and-services-on-downgrade/Cargo.toml",
    "content": "[package]\nname = \"delete-configs-and-services-on-downgrade\"\nversion = \"0.1.0\"\nauthors = [\"Sean P. Kelly <seankell@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\nsnafu.workspace = true\n\n[dev-dependencies]\nmaplit.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.37.0/delete-configs-and-services-on-downgrade/src/main.rs",
    "content": "//! In core-kit 6.4.0, we introduced a change to delete all configuration-files and services on\n//! whenever the migrator runs (https://github.com/bottlerocket-os/bottlerocket-core-kit/pull/456).\n//!\n//! This migrations ensures that nodes downgrading to versions prior to core-kit 6.4.0 will delete\n//! and re-populate these keys.\nuse migration_helpers::{migrate, Migration, MigrationData, Result};\n\nconst PREFIXES_TO_DELETE: &[&str] = &[\"configuration-files.\", \"services.\"];\n\n#[snafu::report]\nfn main() -> Result<()> {\n    migrate(DeleteConfigsAndServicesOnDowngradeMigration)\n}\n\npub struct DeleteConfigsAndServicesOnDowngradeMigration;\n\nimpl Migration for DeleteConfigsAndServicesOnDowngradeMigration {\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"DeleteConfigsAndServicesOnDowngradeMigration has no work to do on upgrade.\",);\n        Ok(input)\n    }\n\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        input.data.retain(|key, _| {\n            let to_keep = !(PREFIXES_TO_DELETE\n                .iter()\n                .any(|prefix| key.starts_with(prefix)));\n            if !to_keep {\n                println!(\"Removed '{key}'\");\n            }\n            to_keep\n        });\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use maplit::hashmap;\n    use std::collections::HashMap;\n\n    #[test]\n    fn nothing_to_clear() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"settings.hello\".into() => \"there\".into(),\n                \"settings.something.configuration-files\".into() => \"retain this!\".into(),\n                \"settings.something.services\".into() => \"and this!\".into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = DeleteConfigsAndServicesOnDowngradeMigration\n            .backward(data)\n            .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"settings.hello\".into() => \"there\".into(),\n                \"settings.something.configuration-files\".into() => \"retain this!\".into(),\n                \"settings.something.services\".into() => \"and this!\".into(),\n            }\n        );\n    }\n\n    #[test]\n    fn all_clear() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"services.delete-this\".into() => \"yep\".into(),\n                \"configuration-files.delete-this\".into() => \"this too\".into(),\n                \"configuration-files.another-one\".into() => \"bye\".into(),\n                \"services.and-this\".into() => \"au revoir\".into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = DeleteConfigsAndServicesOnDowngradeMigration\n            .backward(data)\n            .unwrap();\n        assert_eq!(result.data, HashMap::new());\n    }\n\n    #[test]\n    fn delete_some() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"services.delete-this\".into() => \"deleted\".into(),\n                \"configuration-files.and-this\".into() => \"deleted\".into(),\n                \"settings.but-not-this\".into() => \"stays\".into(),\n                \"or-this-either.configuration-files\".into() => \"also-stays\".into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = DeleteConfigsAndServicesOnDowngradeMigration\n            .backward(data)\n            .unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                \"settings.but-not-this\".into() => \"stays\".into(),\n                \"or-this-either.configuration-files\".into() => \"also-stays\".into(),\n            }\n        );\n    }\n\n    #[test]\n    fn dont_touch_the_metadata() {\n        let data = MigrationData {\n            data: hashmap! {\n                \"configuration-files.delete\".into() => \"delete\".into(),\n                \"services.delete\".into() => \"delete\".into(),\n                \"settings.keep\".into() => \"keep\".into(),\n            },\n            metadata: hashmap! {\n                \"configuration-files.delete\".into() => hashmap! {\n                    \"keep\".into() => \"yep!\".into(),\n                },\n                \"services.delete\".into() => hashmap! {\n                    \"keep\".into() => \"yep!\".into(),\n                },\n                \"settings.keep\".into() => hashmap! {\n                    \"keep\".into() => \"yep!\".into(),\n                },\n            },\n        };\n        let result = DeleteConfigsAndServicesOnDowngradeMigration\n            .backward(data)\n            .unwrap();\n        assert_eq!(\n            result,\n            MigrationData {\n                data: hashmap! {\n                    \"settings.keep\".into() => \"keep\".into(),\n                },\n                metadata: hashmap! {\n                    \"configuration-files.delete\".into() => hashmap! {\n                        \"keep\".into() => \"yep!\".into(),\n                    },\n                    \"services.delete\".into() => hashmap! {\n                        \"keep\".into() => \"yep!\".into(),\n                    },\n                    \"settings.keep\".into() => hashmap! {\n                        \"keep\".into() => \"yep!\".into(),\n                    },\n                },\n            },\n        );\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.39.0/kubelet-setting-container-log-single-process-oom-kill/Cargo.toml",
    "content": "[package]\nname = \"kubelet-setting-container-log-single-process-oom-kill\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\nsnafu.workspace = true\n\n[dev-dependencies]\nmaplit.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.39.0/kubelet-setting-container-log-single-process-oom-kill/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new k8s settings for:\n/// - singleProcessOOMKill\n/// - containerLogMaxWorkers\n/// - containerLogMonitorInterval\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.container-log-max-workers\",\n        \"settings.kubernetes.container-log-monitor-interval\",\n        \"settings.kubernetes.single-process-oom-kill\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.40.0/kubelet-device-plugins-cdi-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-cdi-settings\"\nversion = \"0.1.0\"\nauthors = [\"Jingwei Wang <jweiw@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\nserde_json.workspace = true\nsnafu.workspace = true\n\n[dev-dependencies]\nmaplit.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.40.0/kubelet-device-plugins-cdi-settings/src/main.rs",
    "content": "use migration_helpers::{error, migrate, Migration, MigrationData, Result};\nuse snafu::OptionExt;\n\nconst DEVICE_LIST_STRATEGY_SETTING: &str =\n    \"settings.kubelet-device-plugins.nvidia.device-list-strategy\";\n\n#[snafu::report]\nfn main() -> Result<()> {\n    migrate(ReplaceDeviceListStrategy)\n}\n\n/// We changed the type of the device-list-strategy in the NVIDIA Kubernetes Device\n/// plugin API from a string to a list, and accept \"cdi-cri\" as a valid value\npub struct ReplaceDeviceListStrategy;\n\nimpl Migration for ReplaceDeviceListStrategy {\n    /// New versions must either have a default for the settings or generate them; we don't need to\n    /// do anything.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"ReplaceDeviceListStrategy has no work to do on upgrade.\");\n        Ok(input)\n    }\n\n    /// Older versions don't know about the setting now accepting both a string, a list and a new accepted value \"cdi-cri\";\n    /// we remove the list option and the \"cdi-cri\" value so that old versions don't see them and fail deserialization.\n    /// (The settings must be defaulted or generated in new versions, and safe to remove.)\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let setting = DEVICE_LIST_STRATEGY_SETTING;\n        if let Some(data) = input.data.get_mut(setting) {\n            match data {\n                serde_json::Value::Array(arr) => {\n                    let list: Vec<&str> = arr\n                        .iter()\n                        .map(|v| v.as_str())\n                        .collect::<Option<Vec<&str>>>()\n                        .context(error::ReplaceListContentsSnafu {\n                            setting,\n                            data: arr.clone(),\n                        })?;\n\n                    let new_value = match list.first() {\n                        None | Some(&\"cdi-cri\") => \"volume-mounts\".to_string(),\n                        Some(value) => value.to_string(),\n                    };\n\n                    *data = serde_json::Value::String(new_value.to_string());\n                }\n\n                serde_json::Value::String(setting_str) => {\n                    if setting_str == \"cdi-cri\" {\n                        *data = serde_json::Value::String(\"volume-mounts\".to_string());\n                    } else {\n                        *data = serde_json::Value::String(setting_str.to_string());\n                    }\n                }\n\n                _ => error::InvalidSettingTypeSnafu {\n                    data: setting.to_string(),\n                }\n                .fail()?,\n            }\n        } else {\n            println!(\"Found no '{setting}' to change on downgrade\");\n        }\n\n        Ok(input)\n    }\n}\n\n#[cfg(test)]\nmod test_replace_list {\n    use super::*;\n    use crate::{Migration, MigrationData};\n    use maplit::hashmap;\n    use serde_json::Value;\n    use std::collections::HashMap;\n\n    #[test]\n    fn forward_test() {\n        let data = MigrationData {\n            data: hashmap! {\n                DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n            },\n            metadata: HashMap::new(),\n        };\n        let result = ReplaceDeviceListStrategy.forward(data).unwrap();\n        assert_eq!(\n            result.data,\n            hashmap! {\n                DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n            }\n        );\n    }\n\n    #[test]\n    fn backward_test() {\n        let test_cases: Vec<(MigrationData, HashMap<String, Value>)> = vec![\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"cdi-cri\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => Vec::<String>::new().into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"volume-mounts\", \"envvar\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"envvar\", \"volume-mounts\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"envvar\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"cdi-cri\", \"envvar\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"cdi-cri\", \"envvar\", \"volume-mounts\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"envvar\", \"volume-mounts\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"envvar\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => vec![\"volume-mounts\", \"envvar\"].into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => \"cdi-cri\".into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"volume-mounts\".into(),\n                },\n            ),\n            (\n                MigrationData {\n                    data: hashmap! {\n                        DEVICE_LIST_STRATEGY_SETTING.into() => \"envvar\".into(),\n                    },\n                    metadata: HashMap::new(),\n                },\n                hashmap! {\n                    DEVICE_LIST_STRATEGY_SETTING.into() => \"envvar\".into(),\n                },\n            ),\n        ];\n\n        for (input, expected) in test_cases {\n            let result = ReplaceDeviceListStrategy.backward(input).unwrap();\n            assert_eq!(result.data, expected);\n        }\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.41.0/kubernetes-ecr-credential-providers-correction/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-ecr-credential-providers-correction\"\nversion = \"0.1.0\"\nauthors = [\"Carter McKinnon <mckdev@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.41.0/kubernetes-ecr-credential-providers-correction/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added incorrect hostname patterns to be matched by the ECR credential provider.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"settings.kubernetes.credential-providers.ecr-credential-provider.image-patterns\",\n        old_vals: &[\n            \"*.dkr.ecr.*.amazonaws.com\",\n            \"*.dkr.ecr.*.amazonaws.com.cn\",\n            \"*.dkr.ecr.*.on.aws\",\n            \"*.dkr.ecr.*.on.amazonwebservices.com.cn\",\n            \"*.dkr.ecr-fips.*.amazonaws.com\",\n            \"*.dkr.ecr.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr-fips.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr.*.c2s.ic.gov\",\n            \"*.dkr.ecr-fips.*.c2s.ic.gov\",\n            \"*.dkr.ecr.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr-fips.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr.*.csp.hci.ic.gov\",\n            \"*.dkr.ecr-fips.*.csp.hci.ic.gov\",\n            \"public.ecr.aws\",\n        ],\n        new_vals: &[\n            \"*.dkr.ecr.*.amazonaws.com\",\n            \"*.dkr.ecr.*.amazonaws.com.cn\",\n            \"*.dkr-ecr.*.on.aws\",\n            \"*.dkr-ecr.*.on.amazonwebservices.com.cn\",\n            \"*.dkr.ecr-fips.*.amazonaws.com\",\n            \"*.dkr.ecr.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr-fips.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr.*.c2s.ic.gov\",\n            \"*.dkr.ecr-fips.*.c2s.ic.gov\",\n            \"*.dkr.ecr.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr-fips.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr.*.csp.hci.ic.gov\",\n            \"*.dkr.ecr-fips.*.csp.hci.ic.gov\",\n            \"public.ecr.aws\",\n        ],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.42.0/kubernetes-memory-swap-behavior-setting/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-memory-swap-behavior-setting\"\nversion = \"0.1.0\"\nauthors = [\"Jan Teske <jteske@posteo.net>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.42.0/kubernetes-memory-swap-behavior-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added a new kubernetes setting controlling the memory swap behavior.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.memory-swap-behavior\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.44.0/container-runtime-plugins-settings/Cargo.toml",
    "content": "[package]\nname = \"container-runtime-plugins-settings\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.44.0/container-runtime-plugins-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added new settings container-runtime-plugins\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.container-runtime-plugins\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.44.0/container-runtime-snapshotter-setting/Cargo.toml",
    "content": "[package]\nname = \"container-runtime-snapshotter-setting\"\nversion = \"0.1.0\"\nauthors = [\"Gavin Inglis <giinglis@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.44.0/container-runtime-snapshotter-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added a new container-runtime setting for selecting snapshotter.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.container-runtime.snapshotter\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.46.0/kubernetes-static-pods-enabled-setting/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-static-pods-enabled-setting\"\nversion = \"0.1.0\"\nauthors = [\"Vighnesh Maheshwari <vighmah@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\nsnafu.workspace = true\n\n[dev-dependencies]\nmaplit.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.46.0/kubernetes-static-pods-enabled-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new k8s settings for:\n/// - static_pods_enabled\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.static-pods-enabled\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.47.0/container-runtime-concurrent-download-chunk-size/Cargo.toml",
    "content": "[package]\nname = \"container-runtime-concurrent-download-chunk-size\"\nversion = \"0.1.0\"\nauthors = [\"Kyle Sessions <kssessio@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.47.0/container-runtime-concurrent-download-chunk-size/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new container-runtime setting for:\n/// - concurrent_download_chunk_size\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.container-runtime.concurrent-download-chunk-size\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.47.0/host-bootstrap-containers-command-setting/Cargo.toml",
    "content": "[package]\nname = \"host-bootstrap-containers-command-setting\"\nversion = \"0.1.0\"\nauthors = [\"Yutong Sun <yutongsu@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\nsnafu.workspace = true\n\n[dev-dependencies]\nmaplit.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.47.0/host-bootstrap-containers-command-setting/src/main.rs",
    "content": "use migration_helpers::common_migrations::{AddPrefixSuffixMigration, PrefixSuffix};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added new settings container-runtime-plugins\nfn run() -> Result<()> {\n    migrate(AddPrefixSuffixMigration(vec![\n        PrefixSuffix {\n            prefix: \"settings.host-containers\",\n            suffix: \"command\",\n        },\n        PrefixSuffix {\n            prefix: \"settings.bootstrap-containers\",\n            suffix: \"command\",\n        },\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.50.0/kubernetes-reserved-pid-settings/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-reserved-pid-settings\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.50.0/kubernetes-reserved-pid-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added new kubernetes settings to reserve pids for kubernetes and system components.\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.kube-reserved.pid\",\n        \"settings.kubernetes.system-reserved.pid\",\n    ]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.51.0/kubernetes-additional-settings/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-additional-settings\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.51.0/kubernetes-additional-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddSettingsMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// We added new kubernetes settings to configure:\n// - min/max duration before an unused image is garbage-collected\n// - max number of image pulls in parallel\n// - mapping length of UIDs and GIDs\nfn run() -> Result<()> {\n    migrate(AddSettingsMigration(&[\n        \"settings.kubernetes.image-minimum-gc-age\",\n        \"settings.kubernetes.image-maximum-gc-age\",\n        \"settings.kubernetes.max-parallel-image-pulls\",\n        \"settings.kubernetes.ids-per-pod\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.51.0/kubernetes-beta-cpu-manager-policy-options/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-beta-cpu-manager-policy-options\"\nversion = \"0.1.0\"\nauthors = [\"Kush Upadhyay <kushupad@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.51.0/kubernetes-beta-cpu-manager-policy-options/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListRestriction, RestrictListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n// Beta options for cpu-manager-policy-options became available without feature gates:\n// - strict-cpu-reservation: 1.32 or higher\n// - distribute-cpus-across-numa: 1.33 or higher\n// - prefer-align-cpus-by-uncorecache: 1.34 or higher\n//\n// On downgrade, we remove these newer options to prevent kubelet from receiving\n// incompatible configuration values. We keep full-pcpus-only as it's stable.\nfn run() -> Result<()> {\n    migrate(RestrictListsMigration(vec![ListRestriction {\n        setting: \"settings.kubernetes.cpu-manager-policy-options\",\n        allowed_vals: &[\"full-pcpus-only\"],\n    }]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.51.0/kubernetes-ecr-credential-provider-patterns/Cargo.toml",
    "content": "[package]\nname = \"kubernetes-ecr-credential-provider-patterns\"\nversion = \"0.1.0\"\nauthors = [\"Sam Berning <bernings@amazon.com>\"]\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.51.0/kubernetes-ecr-credential-provider-patterns/src/main.rs",
    "content": "use migration_helpers::common_migrations::{ListReplacement, ReplaceListsMigration};\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new hostname patterns to be matched by the ECR credential provider.\nfn run() -> Result<()> {\n    migrate(ReplaceListsMigration(vec![ListReplacement {\n        setting: \"settings.kubernetes.credential-providers.ecr-credential-provider.image-patterns\",\n        old_vals: &[\n            \"*.dkr.ecr.*.amazonaws.com\",\n            \"*.dkr.ecr.*.amazonaws.com.cn\",\n            \"*.dkr.ecr.*.on.aws\",\n            \"*.dkr.ecr.*.on.amazonwebservices.com.cn\",\n            \"*.dkr.ecr-fips.*.amazonaws.com\",\n            \"*.dkr.ecr.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr-fips.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr.*.c2s.ic.gov\",\n            \"*.dkr.ecr-fips.*.c2s.ic.gov\",\n            \"*.dkr.ecr.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr-fips.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr.*.csp.hci.ic.gov\",\n            \"*.dkr.ecr-fips.*.csp.hci.ic.gov\",\n            \"public.ecr.aws\",\n        ],\n        new_vals: &[\n            \"*.dkr.ecr.*.amazonaws.com\",\n            \"*.dkr.ecr.*.amazonaws.com.cn\",\n            \"*.dkr.ecr.*.amazonaws.eu\",\n            \"*.dkr.ecr.*.on.aws\",\n            \"*.dkr.ecr.*.on.amazonwebservices.com.cn\",\n            \"*.dkr.ecr-fips.*.amazonaws.com\",\n            \"*.dkr.ecr-fips.*.amazonaws.eu\",\n            \"*.dkr.ecr.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr-fips.*.cloud.adc-e.uk\",\n            \"*.dkr.ecr.*.c2s.ic.gov\",\n            \"*.dkr.ecr-fips.*.c2s.ic.gov\",\n            \"*.dkr.ecr.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr-fips.*.sc2s.sgov.gov\",\n            \"*.dkr.ecr.*.csp.hci.ic.gov\",\n            \"*.dkr.ecr-fips.*.csp.hci.ic.gov\",\n            \"public.ecr.aws\",\n        ],\n    }]))\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.54.0/kubelet-device-plugins-mps-prefix-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-mps-prefix-settings\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.54.0/kubelet-device-plugins-mps-prefix-settings/src/main.rs",
    "content": "use migration_helpers::common_migrations::AddPrefixesMigration;\nuse migration_helpers::{migrate, Result};\nuse std::process;\n\n/// We added new settings for configuring NVIDIA MPS (Multi-Process Service)\n/// GPU sharing in the device plugin, remove the prefix for these settings\nfn run() -> Result<()> {\n    migrate(AddPrefixesMigration(vec![\n        \"settings.kubelet-device-plugins.nvidia.mps\",\n    ]))\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.54.0/kubelet-device-plugins-mps-settings/Cargo.toml",
    "content": "[package]\nname = \"kubelet-device-plugins-mps-settings\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\nserde_json.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.54.0/kubelet-device-plugins-mps-settings/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst DEVICE_SHARING_STRATEGY_SETTING: &str =\n    \"settings.kubelet-device-plugins.nvidia.device-sharing-strategy\";\n\npub struct ReplaceDeviceSharingStrategy;\n\nimpl Migration for ReplaceDeviceSharingStrategy {\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"ReplaceDeviceSharingStrategy has no work to do on upgrade.\");\n        Ok(input)\n    }\n\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        if let Some(data) = input.data.get_mut(DEVICE_SHARING_STRATEGY_SETTING) {\n            if let serde_json::Value::String(s) = data {\n                if s == \"mps\" {\n                    *data = serde_json::Value::String(\"none\".to_string());\n                    println!(\"Changed device-sharing-strategy from 'mps' to 'none' on downgrade.\");\n                }\n            }\n        }\n        Ok(input)\n    }\n}\n\n/// We added new enum variant for configuring NVIDIA MPS (Multi-Process Service)\n/// GPU sharing in the device plugin.\nfn run() -> Result<()> {\n    migrate(ReplaceDeviceSharingStrategy)\n}\n\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-migrations/v1.56.0/image-verifier-plugins-extensible/Cargo.toml",
    "content": "[package]\nname = \"image-verifier-plugins-extensible\"\nversion = \"0.1.0\"\nlicense = \"Apache-2.0 OR MIT\"\nedition = \"2021\"\npublish = false\nexclude = [\"README.md\"]\n\n[dependencies]\nmigration-helpers.workspace = true\n"
  },
  {
    "path": "sources/settings-migrations/v1.56.0/image-verifier-plugins-extensible/src/main.rs",
    "content": "use migration_helpers::{migrate, Migration, MigrationData, Result};\nuse std::process;\n\nconst PREFIX: &str = \"settings.image-verifier-plugins.\";\n/// Keys known to the old model that should be preserved on downgrade.\nconst KNOWN_KEYS: &[&str] = &[\"enabled\", \"notation\"];\n\n/// Image verifier plugins changed from a fixed `notation` field to an extensible plugin map.\n/// On downgrade, remove any plugin keys that the old model doesn't recognize.\npub struct ImageVerifierPluginsExtensible;\n\nimpl Migration for ImageVerifierPluginsExtensible {\n    /// New model is a superset of the old; existing data is compatible.\n    fn forward(&mut self, input: MigrationData) -> Result<MigrationData> {\n        println!(\"ImageVerifierPluginsExtensible has no work to do on upgrade.\");\n        Ok(input)\n    }\n\n    /// Remove plugin keys that older versions don't understand.\n    fn backward(&mut self, mut input: MigrationData) -> Result<MigrationData> {\n        let keys: Vec<String> = input\n            .data\n            .keys()\n            .filter(|k| {\n                k.starts_with(PREFIX)\n                    && !KNOWN_KEYS.iter().any(|known| {\n                        let rest = &k[PREFIX.len()..];\n                        rest == *known || rest.starts_with(&format!(\"{known}.\"))\n                    })\n            })\n            .cloned()\n            .collect();\n\n        for key in keys {\n            if let Some(data) = input.data.remove(&key) {\n                println!(\"Removed {key}, which was set to '{data}'\");\n            }\n        }\n\n        Ok(input)\n    }\n}\n\nfn run() -> Result<()> {\n    migrate(ImageVerifierPluginsExtensible)\n}\n\n// Returning a Result from main makes it print a Debug representation of the error, but with Snafu\n// we have nice Display representations of the error, so we wrap \"main\" (run) and print any error.\n// https://github.com/shepmaster/snafu/issues/110\nfn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sources/settings-plugins/aws-dev/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-aws-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_aws_dev\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/aws-dev/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct AwsDevSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/aws-ecs-2/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-aws-ecs-2\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_aws_ecs_2\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/aws-ecs-2/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct AwsEcs2Settings {\n    motd: bottlerocket_settings_models::MotdV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    ecs: bottlerocket_settings_models::ECSSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_defaults: bottlerocket_settings_models::OciDefaultsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1,\n    autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/aws-ecs-3/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-aws-ecs-3\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_aws_ecs_3\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/aws-ecs-3/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct AwsEcs3Settings {\n    motd: bottlerocket_settings_models::MotdV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    ecs: bottlerocket_settings_models::ECSSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_defaults: bottlerocket_settings_models::OciDefaultsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1,\n    autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n    image_verifier_plugins: bottlerocket_settings_models::ImageVerifierPluginsSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/aws-k8s/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-aws-k8s\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_aws_k8s\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/aws-k8s/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct AwsK8sSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    kubernetes: bottlerocket_settings_models::KubernetesSettingsV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_defaults: bottlerocket_settings_models::OciDefaultsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n    container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1,\n    container_runtime_plugins: bottlerocket_settings_models::ContainerRuntimePluginsSettingsV1,\n    autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/aws-k8s-nvidia/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-aws-k8s-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_aws_k8s_nvidia\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-plugin = { workspace = true }\nbottlerocket-settings-models = { workspace = true }\n"
  },
  {
    "path": "sources/settings-plugins/aws-k8s-nvidia/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct AwsK8sSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    kubernetes: bottlerocket_settings_models::KubernetesSettingsV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_defaults: bottlerocket_settings_models::OciDefaultsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    cloudformation: bottlerocket_settings_models::CloudFormationSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n    container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1,\n    container_runtime_plugins: bottlerocket_settings_models::ContainerRuntimePluginsSettingsV1,\n    autoscaling: bottlerocket_settings_models::AutoScalingSettingsV1,\n    nvidia_container_runtime: bottlerocket_settings_models::NvidiaContainerRuntimeSettingsV1,\n    kubelet_device_plugins: bottlerocket_settings_models::KubeletDevicePluginsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/metal-dev/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-metal-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_metal_dev\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/metal-dev/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct MetalDevSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/metal-k8s/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-metal-k8s\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_metal_k8s\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/metal-k8s/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct MetalK8sSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    kubernetes: bottlerocket_settings_models::KubernetesSettingsV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_defaults: bottlerocket_settings_models::OciDefaultsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n    container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/vmware-dev/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-vmware-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_vmware_dev\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/vmware-dev/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct VmwareDevSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n}\n"
  },
  {
    "path": "sources/settings-plugins/vmware-k8s/Cargo.toml",
    "content": "[package]\nname = \"settings-plugin-vmware-k8s\"\nversion = \"0.1.0\"\nedition = \"2021\"\nlicense = \"Apache-2.0 OR MIT\"\npublish = false\n\n[lib]\ncrate-type = [\"cdylib\"]\nname = \"settings_vmware_k8s\"\n\n[dependencies]\nabi_stable.workspace = true\nserde.workspace = true\nserde_json.workspace = true\n\n# settings plugins\nbottlerocket-settings-models.workspace = true\nbottlerocket-settings-plugin.workspace = true\n"
  },
  {
    "path": "sources/settings-plugins/vmware-k8s/src/lib.rs",
    "content": "use bottlerocket_settings_models::model_derive::model;\nuse bottlerocket_settings_plugin::SettingsPlugin;\n\n#[derive(SettingsPlugin)]\n#[model(rename = \"settings\", impl_default = true)]\nstruct VmwareK8sSettings {\n    motd: bottlerocket_settings_models::MotdV1,\n    kubernetes: bottlerocket_settings_models::KubernetesSettingsV1,\n    updates: bottlerocket_settings_models::UpdatesSettingsV1,\n    host_containers: bottlerocket_settings_models::HostContainersSettingsV1,\n    bootstrap_commands: bottlerocket_settings_models::BootstrapCommandsSettingsV1,\n    bootstrap_containers: bottlerocket_settings_models::BootstrapContainersSettingsV1,\n    ntp: bottlerocket_settings_models::NtpSettingsV1,\n    network: bottlerocket_settings_models::NetworkSettingsV1,\n    kernel: bottlerocket_settings_models::KernelSettingsV1,\n    aws: bottlerocket_settings_models::AwsSettingsV1,\n    boot: bottlerocket_settings_models::BootSettingsV1,\n    metrics: bottlerocket_settings_models::MetricsSettingsV1,\n    pki: bottlerocket_settings_models::PkiSettingsV1,\n    container_registry: bottlerocket_settings_models::RegistrySettingsV1,\n    oci_defaults: bottlerocket_settings_models::OciDefaultsV1,\n    oci_hooks: bottlerocket_settings_models::OciHooksSettingsV1,\n    dns: bottlerocket_settings_models::DnsSettingsV1,\n    container_runtime: bottlerocket_settings_models::ContainerRuntimeSettingsV1,\n    container_runtime_plugins: bottlerocket_settings_models::ContainerRuntimePluginsSettingsV1,\n}\n"
  },
  {
    "path": "sources/shared-defaults/aws-autoscaling.toml",
    "content": "# Autoscaling warm pool support\n[settings.autoscaling]\nshould-wait = false\n"
  },
  {
    "path": "sources/shared-defaults/aws-bootstrap-container.toml",
    "content": "[metadata.settings.bootstrap-containers.source.setting-generator]\ncommand = \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-bootstrap:v0.2.14'\"\nstrength = \"weak\"\ndepth = 1\n"
  },
  {
    "path": "sources/shared-defaults/aws-creds.toml",
    "content": "[settings.aws]\nprofile = \"default\"\n\n[metadata.settings.aws.config]\nsetting-generator = \"schnauzer-v2 render --requires 'aws@v1(helpers=[aws-config])' --template '{{ aws-config settings.aws.config settings.aws.profile }}'\"\n\n[services.aws]\nconfiguration-files = [\n  \"aws-config\",\n  \"aws-credentials\",\n]\nrestart-commands = []\n\n[metadata.settings.aws]\naffected-services = [\"aws\"]\n\n[configuration-files.aws-config]\npath = \"/root/.aws/config\"\ntemplate-path = \"/usr/share/templates/aws-config\"\n\n[configuration-files.aws-credentials]\npath = \"/root/.aws/credentials\"\ntemplate-path = \"/usr/share/templates/aws-credentials\"\n"
  },
  {
    "path": "sources/shared-defaults/aws-host-containers.toml",
    "content": "[settings.host-containers.admin]\nenabled = false\nsuperpowered = true\n\n[metadata.settings.host-containers.admin.source.setting-generator]\ncommand = \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-admin:v0.20.4'\"\nstrength = \"weak\"\n\n[metadata.settings.host-containers.admin.user-data]\nsetting-generator = \"shibaken generate-admin-userdata\"\n\n[settings.host-containers.control]\nenabled = true\nsuperpowered = false\n\n[metadata.settings.host-containers.control.source.setting-generator]\ncommand = \"schnauzer-v2 render --requires 'aws@v1(helpers=[ecr-prefix])' --template '{{ ecr-prefix settings.aws.region }}/bottlerocket-control:v0.20.4'\"\nstrength = \"weak\"\n"
  },
  {
    "path": "sources/shared-defaults/aws-tuf.toml",
    "content": "[metadata.settings.updates.targets-base-url]\nsetting-generator = \"schnauzer-v2 render --requires 'aws@v1' --requires 'updates@v1(helpers=[tuf-prefix])' --template '{{ tuf-prefix settings.aws.region }}/targets/'\"\n\n[metadata.settings.updates.metadata-base-url]\nsetting-generator = \"schnauzer-v2 render --requires 'aws@v1' --requires 'updates@v1(helpers=[metadata-prefix, tuf-prefix])' --template '{{ tuf-prefix settings.aws.region }}{{ metadata-prefix settings.aws.region }}/2020-07-07/{{ os.variant_id }}/{{ os.arch }}/'\"\n"
  },
  {
    "path": "sources/shared-defaults/boot.toml",
    "content": "# Boot related settings\n\n[metadata.settings.boot]\naffected-services = [\"bootconfig\"]\nsetting-generator = \"/usr/bin/prairiedog generate-boot-settings\"\n\n[services.bootconfig]\nconfiguration-files = [\"prairiedog-toml\"]\nrestart-commands = [\"/usr/bin/prairiedog generate-boot-config\"]\n\n[configuration-files.prairiedog-toml]\npath = \"/etc/prairiedog.toml\"\ntemplate-path = \"/usr/share/templates/prairiedog-toml\"\n"
  },
  {
    "path": "sources/shared-defaults/cf-signal.toml",
    "content": "[settings.cloudformation]\nshould-signal = false\nstack-name = \"\"\nlogical-resource-id = \"\"\n\n[services.cfsignal]\nconfiguration-files = [\"cfsignal-toml\"]\nrestart-commands = [\"/bin/systemctl try-restart cfsignal.service\"]\n\n[configuration-files.cfsignal-toml]\npath = \"/etc/cfsignal.toml\"\ntemplate-path = \"/usr/share/templates/cfsignal-toml\"\n\n[metadata.settings.cloudformation]\naffected-services = [\"cfsignal\"]\n"
  },
  {
    "path": "sources/shared-defaults/containerd-cri-pki.toml",
    "content": "[metadata.settings.pki]\naffected-services = [\"pki\", \"containerd\"]\n"
  },
  {
    "path": "sources/shared-defaults/defaults.toml",
    "content": "# Here we define a common set of default settings for most variants.\n# A variant includes these by symlinking this file into its `defaults.d` directory.\n# It can override these settings in any file listed after that in the directory.\n\n# The structures, fields, and types here need to match those of the API model,\n# as defined in src/VARIANT/mod.rs.\n\n[settings]\nmotd = \"Welcome to Bottlerocket!\"\n\n[metadata.settings.motd]\naffected-services = [\"motd\"]\n\n[services.motd]\nconfiguration-files = [\"motd\"]\nrestart-commands = []\n\n[configuration-files.motd]\npath = \"/etc/motd\"\ntemplate-path = \"/usr/share/templates/motd\"\n\n# Container runtime.\n\n[services.containerd]\nconfiguration-files = [\"containerd-config-toml\", \"proxy-env\"]\nrestart-commands = [\"/bin/systemctl try-restart containerd.service\"]\n\n[configuration-files.containerd-config-toml]\npath = \"/etc/containerd/config.toml\"\ntemplate-path = \"/usr/share/templates/containerd-config-toml_basic\"\n\n# Container runtime settings.\n\n[metadata.settings.container-runtime]\naffected-services = [\"containerd\"]\n\n# Host-container runtime\n\n[services.host-containerd]\nconfiguration-files = [\"proxy-env\"]\nrestart-commands = [\"/bin/systemctl try-restart host-containerd.service\"]\n\n# Updates.\n\n[settings.updates]\nversion-lock = \"latest\"\nignore-waves = false\n\n[services.thar-be-updates]\nconfiguration-files = [\"thar-be-updates-toml\"]\nrestart-commands = []\n\n[services.updog]\nconfiguration-files = [\"updog-toml\"]\nrestart-commands = []\n\n[configuration-files.thar-be-updates-toml]\npath = \"/etc/thar-be-updates.toml\"\ntemplate-path = \"/usr/share/templates/thar-be-updates-toml\"\n\n[configuration-files.updog-toml]\npath = \"/etc/updog.toml\"\ntemplate-path = \"/usr/share/templates/updog-toml\"\n\n[metadata.settings.updates]\naffected-services = [\"updog\", \"thar-be-updates\"]\nseed.setting-generator = \"bork seed\"\n\n# HostContainers\n\n[services.host-containers]\nconfiguration-files = [\"host-ctr-toml\", \"host-containers-toml\"]\nrestart-commands = [\"/usr/bin/host-containers\"]\n\n[configuration-files.host-ctr-toml]\npath = \"/etc/host-containers/host-ctr.toml\"\ntemplate-path = \"/usr/share/templates/host-ctr-toml\"\n\n[configuration-files.host-containers-toml]\npath = \"/etc/host-containers/host-containers.toml\"\ntemplate-path = \"/usr/share/templates/host-containers-toml\"\n\n[metadata.settings.host-containers]\naffected-services = [\"host-containers\"]\n\n# Network\n\n[configuration-files.proxy-env]\npath = \"/etc/network/proxy.env\"\ntemplate-path = \"/usr/share/templates/proxy-env\"\n\n[metadata.settings.network]\naffected-services = [\"containerd\", \"host-containerd\", \"host-containers\", \"updog\"]\n\n[metadata.settings.network.hostname]\naffected-services = [\"hostname\", \"hosts\"]\nsetting-generator = \"netdog generate-hostname\"\n\n[services.hostname]\nconfiguration-files = [\"hostname\"]\nrestart-commands = [\"/bin/systemctl try-restart set-hostname.service\"]\n\n[configuration-files.hostname]\npath = \"/etc/network/hostname.env\"\ntemplate-path = \"/usr/share/templates/hostname-env\"\n\n[metadata.settings.network.hosts]\naffected-services = [\"hosts\"]\n\n[services.hosts]\nconfiguration-files = [\"hosts\"]\nrestart-commands = []\n\n[configuration-files.hosts]\npath = \"/etc/hosts\"\ntemplate-path = \"/usr/share/templates/hosts\"\n\n# NTP\n\n[settings.ntp]\ntime-servers = [\"169.254.169.123\", \"2.amazon.pool.ntp.org\"]\noptions = [\"iburst\"]\n\n[services.ntp]\nconfiguration-files = [\"chrony-conf\"]\nrestart-commands = [\"/bin/systemctl try-reload-or-restart chronyd.service\"]\n\n[configuration-files.chrony-conf]\npath = \"/etc/chrony.conf\"\ntemplate-path = \"/usr/share/templates/chrony-conf\"\n\n[metadata.settings.ntp]\naffected-services = [\"ntp\"]\n\n# Kernel\n\n[services.sysctl]\nconfiguration-files = [\"corndog-toml\"]\nrestart-commands = [\"/usr/bin/corndog sysctl\"]\n\n[metadata.settings.kernel.sysctl]\naffected-services = [\"sysctl\"]\n\n[services.kernel-modules]\nconfiguration-files = [\"modprobe-conf\", \"modules-load\"]\nrestart-commands = [\"/usr/bin/systemctl try-restart systemd-modules-load\"]\n\n[configuration-files.modprobe-conf]\npath = \"/etc/modprobe.d/modprobe.conf\"\ntemplate-path = \"/usr/share/templates/modprobe-conf\"\n\n[configuration-files.modules-load]\npath = \"/etc/modules-load.d/modules-load.conf\"\ntemplate-path = \"/usr/share/templates/modules-load\"\n\n[metadata.settings.kernel.modules]\naffected-services = [\"kernel-modules\"]\n\n[services.lockdown]\nconfiguration-files = [\"corndog-toml\"]\nrestart-commands = [\"/usr/bin/corndog lockdown\"]\n\n[metadata.settings.kernel.lockdown]\naffected-services = [\"lockdown\"]\n\n[configuration-files.corndog-toml]\npath = \"/etc/corndog.toml\"\ntemplate-path = \"/usr/share/templates/corndog-toml\"\n\n# Bootstrap Commands\n[services.bootstrap-commands]\nconfiguration-files = [\"bootstrap-commands-toml\"]\nrestart-commands = []\n\n[metadata.settings.bootstrap-commands]\naffected-services = [\"bootstrap-commands\"]\n\n[configuration-files.bootstrap-commands-toml]\npath = \"/etc/bootstrap-commands/bootstrap-commands.toml\"\ntemplate-path = \"/usr/share/templates/bootstrap-commands-toml\"\n\n# Bootstrap Containers\n\n[services.bootstrap-containers]\nconfiguration-files = [\"host-ctr-toml\", \"bootstrap-containers-toml\"]\nrestart-commands = [\"/usr/bin/bootstrap-containers create-containers\"]\n\n[metadata.settings.bootstrap-containers]\naffected-services = [\"bootstrap-containers\"]\n\n[configuration-files.bootstrap-containers-toml]\npath = \"/etc/bootstrap-containers/bootstrap-containers.toml\"\ntemplate-path = \"/usr/share/templates/bootstrap-containers-toml\"\n\n# Certdog\n\n[services.pki]\nconfiguration-files = [\"certdog-toml\"]\nrestart-commands = [\"/usr/bin/certdog\"]\n\n# DNS\n[metadata.settings.dns]\naffected-services = [\"dns\"]\n\n[services.dns]\nconfiguration-files = [\"netdog-toml\"]\nrestart-commands = [\"netdog write-resolv-conf\"]\n\n[configuration-files.netdog-toml]\npath = \"/etc/netdog.toml\"\ntemplate-path = \"/usr/share/templates/netdog-toml\"\n\n[configuration-files.certdog-toml]\npath = \"/etc/certdog.toml\"\ntemplate-path = \"/usr/share/templates/certdog-toml\"\n\n# thar-be-registries - renders hosts.toml files for containerd registry config\n[services.thar-be-registries]\nconfiguration-files = [\"thar-be-registries-toml\"]\nrestart-commands = [\"/usr/bin/thar-be-registries\"]\n\n[configuration-files.thar-be-registries-toml]\npath = \"/etc/containerd/thar-be-registries.toml\"\ntemplate-path = \"/usr/share/templates/thar-be-registries-toml\"\n"
  },
  {
    "path": "sources/shared-defaults/docker-daemon-nvidia.toml",
    "content": "[configuration-files.docker-daemon-config]\npath = \"/etc/docker/daemon.json\"\ntemplate-path = \"/usr/share/templates/docker-daemon-nvidia-json\"\n"
  },
  {
    "path": "sources/shared-defaults/docker-pki.toml",
    "content": "[metadata.settings.pki]\naffected-services = [\"pki\", \"docker\"]\n"
  },
  {
    "path": "sources/shared-defaults/docker-services.toml",
    "content": "[services.docker]\nrestart-commands = [\"/bin/systemctl try-restart docker.service\"]\nconfiguration-files = [\"docker-daemon-config\", \"proxy-env\"]\n\n[configuration-files.docker-daemon-config]\npath = \"/etc/docker/daemon.json\"\ntemplate-path = \"/usr/share/templates/docker-daemon-json\"\n\n# Image registries. Retained for backwards compatibility, but superseded by the\n# more specific metadata for mirrors and credentials.\n[metadata.settings.container-registry]\naffected-services = [\"docker\", \"host-containers\", \"bootstrap-containers\", \"thar-be-registries\"]\n\n# Image registry mirrors\n[metadata.settings.container-registry.mirrors]\naffected-services = [\"docker\", \"host-containers\", \"bootstrap-containers\", \"thar-be-registries\"]\n\n# Image registry credentials\n[metadata.settings.container-registry.credentials]\naffected-services = [\"host-containers\", \"bootstrap-containers\", \"thar-be-registries\"]\n"
  },
  {
    "path": "sources/shared-defaults/ecs.toml",
    "content": "# ECS\n[services.ecs]\nrestart-commands = [\"/bin/systemctl try-reload-or-restart ecs.service\"]\nconfiguration-files = [\"ecs-config\"]\n\n[configuration-files.ecs-config]\npath = \"/etc/systemd/system/ecs.service.d/10-base.conf\"\ntemplate-path = \"/usr/share/templates/ecs-base-conf\"\n\n[metadata.settings.ecs]\naffected-services = [\"ecs\"]\n\n[settings.ecs]\nallow-privileged-containers = false\nimage-pull-behavior = \"default\"\nlogging-drivers = [\"json-file\", \"awslogs\", \"none\"]\nloglevel = \"info\"\n\n# Metrics\n[settings.metrics]\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"docker\", \"ecs\"]\n\n# Network\n[metadata.settings.network]\naffected-services = [\"containerd\", \"docker\", \"ecs\", \"host-containerd\", \"host-containers\", \"updog\"]\n\n# Image registry credentials\n[metadata.settings.container-registry.credentials]\naffected-services = [\"ecs\", \"host-containers\", \"bootstrap-containers\", \"thar-be-registries\"]\n"
  },
  {
    "path": "sources/shared-defaults/image-verification.toml",
    "content": "# Container runtime - image verification\n[services.image-verification]\nconfiguration-files = [\n  \"containerd-image-verifiers-toml\",\n  \"thar-be-image-verifiers-toml\",\n]\nrestart-commands = [\"/usr/bin/thar-be-image-verifiers\"]\n\n[metadata.settings.image-verifier-plugins]\naffected-services = [\"image-verification\"]\n\n# Reload the containerd configuration drop-in\n[metadata.settings.image-verifier-plugins.enabled]\naffected-services = [\"containerd\", \"image-verification\"]\n\n[configuration-files.containerd-image-verifiers-toml]\npath = \"/etc/containerd/config.d/002-image-verification-plugins.toml\"\ntemplate-path = \"/usr/share/templates/containerd-image-verifiers-toml\"\n\n[configuration-files.thar-be-image-verifiers-toml]\npath = \"/etc/thar-be-image-verifiers.toml\"\ntemplate-path = \"/usr/share/templates/thar-be-image-verifiers-toml\"\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-aws-credential-provider.toml",
    "content": "[settings.kubernetes.credential-providers.ecr-credential-provider]\nenabled = true\ncache-duration = \"12h\"\nimage-patterns = [\n    \"*.dkr.ecr.*.amazonaws.com\",\n    \"*.dkr.ecr.*.amazonaws.com.cn\",\n    \"*.dkr.ecr.*.amazonaws.eu\",\n    \"*.dkr-ecr.*.on.aws\",\n    \"*.dkr-ecr.*.on.amazonwebservices.com.cn\",\n    \"*.dkr.ecr-fips.*.amazonaws.com\",\n    \"*.dkr.ecr-fips.*.amazonaws.eu\",\n    \"*.dkr.ecr.*.cloud.adc-e.uk\",\n    \"*.dkr.ecr-fips.*.cloud.adc-e.uk\",\n    \"*.dkr.ecr.*.c2s.ic.gov\",\n    \"*.dkr.ecr-fips.*.c2s.ic.gov\",\n    \"*.dkr.ecr.*.sc2s.sgov.gov\",\n    \"*.dkr.ecr-fips.*.sc2s.sgov.gov\",\n    \"*.dkr.ecr.*.csp.hci.ic.gov\",\n    \"*.dkr.ecr-fips.*.csp.hci.ic.gov\",\n    \"public.ecr.aws\",\n]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-aws-external-cloud-provider.toml",
    "content": "[settings.kubernetes]\ncloud-provider = \"external\"\nhostname-override-source = \"private-dns-name\"\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-aws-graceful-shutdown.toml",
    "content": "[settings.kubernetes]\nshutdown-grace-period = \"150s\"\nshutdown-grace-period-for-critical-pods = \"30s\"\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-aws.toml",
    "content": "[settings.kubernetes]\ncluster-domain = \"cluster.local\"\nstandalone-mode = false\nauthentication-mode = \"aws\"\nserver-tls-bootstrap = true\ncloud-provider = \"aws\"\n\n[metadata.settings.kubernetes]\naffected-services = [\"kubernetes\"]\n\n[metadata.settings.kubernetes.pod-infra-container-image]\naffected-services = [\"pod-infra-container-image\"]\n\n[services.pod-infra-container-image]\nconfiguration-files = [\"pod-infra-container-image-log-message\"]\nrestart-commands = [\"systemctl restart deprecation-warning@pod-infra-container-image.timer\"]\n\n[configuration-files.pod-infra-container-image-log-message]\npath = \"/etc/deprecated-settings/pod-infra-container-image\"\ntemplate-path = \"/usr/share/templates/pod-infra-container-image\"\n\n[settings.metrics]\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"kubelet\"]\n\n[metadata.settings.network]\naffected-services = [\"containerd\", \"kubernetes\", \"host-containerd\", \"host-containers\", \"updog\"]\n\n[services.autoscaling-warm-pool]\nconfiguration-files = [\"warm-pool-wait-toml\"]\nrestart-commands = []\n\n[configuration-files.warm-pool-wait-toml]\npath = \"/etc/warm-pool-wait.toml\"\ntemplate-path = \"/usr/share/templates/warm-pool-wait-toml\"\n\n[metadata.settings.autoscaling]\naffected-services = [\"autoscaling-warm-pool\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-containerd-nvidia.toml",
    "content": "[configuration-files.containerd-config-toml]\n# No override to path\ntemplate-path = \"/usr/share/templates/containerd-config-toml_k8s_nvidia_containerd_sock\"\n\n# Image registries\n[metadata.settings.container-registry]\naffected-services = [\"containerd\", \"host-containers\", \"bootstrap-containers\", \"soci-snapshotter\", \"thar-be-registries\"]\n\n[configuration-files.snapshotter-toml]\npath = \"/etc/containerd/config.d/001-snapshotter.toml\"\ntemplate-path = \"/usr/share/templates/snapshotter-toml\"\noverwrite-path-if-present = false\n\n# Container runtime - soci.\n[services.soci-snapshotter]\nconfiguration-files = [\"soci-config-toml\"]\nrestart-commands = [\"/bin/systemctl try-restart soci-snapshotter.service\"]\n\n[configuration-files.soci-config-toml]\npath = \"/etc/soci-snapshotter/config.toml\"\ntemplate-path = \"/usr/share/templates/soci-config-toml\"\n\n[configuration-files.selected-snapshotter]\npath = \"/etc/containerd/selected-snapshotter\"\ntemplate-path = \"/usr/share/templates/selected-snapshotter\"\n\n# Container runtime plugins settings.\n\n[metadata.settings.container-runtime-plugins.soci-snapshotter]\naffected-services = [\"soci-snapshotter\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-containerd.toml",
    "content": "[configuration-files.containerd-config-toml]\n# No override to path\ntemplate-path = \"/usr/share/templates/containerd-config-toml_k8s_containerd_sock\"\n\n# Image registries\n[metadata.settings.container-registry]\naffected-services = [\"containerd\", \"host-containers\", \"bootstrap-containers\", \"soci-snapshotter\", \"thar-be-registries\"]\n\n[configuration-files.snapshotter-toml]\npath = \"/etc/containerd/config.d/001-snapshotter.toml\"\ntemplate-path = \"/usr/share/templates/snapshotter-toml\"\noverwrite-path-if-present = false\n\n# Container runtime - soci.\n[services.soci-snapshotter]\nconfiguration-files = [\"soci-config-toml\"]\nrestart-commands = [\"/bin/systemctl try-restart soci-snapshotter.service\"]\n\n[configuration-files.soci-config-toml]\npath = \"/etc/soci-snapshotter/config.toml\"\ntemplate-path = \"/usr/share/templates/soci-config-toml\"\n\n[configuration-files.selected-snapshotter]\npath = \"/etc/containerd/selected-snapshotter\"\ntemplate-path = \"/usr/share/templates/selected-snapshotter\"\n\n# Container runtime plugins settings.\n\n[metadata.settings.container-runtime-plugins.soci-snapshotter]\naffected-services = [\"soci-snapshotter\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-device-ownership-default-false.toml",
    "content": "[settings.kubernetes]\ndevice-ownership-from-security-context = false\n\n[metadata.settings.kubernetes.device-ownership-from-security-context]\naffected-services = [\"containerd\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-device-ownership-default-true.toml",
    "content": "[settings.kubernetes]\ndevice-ownership-from-security-context = true\n\n[metadata.settings.kubernetes.device-ownership-from-security-context]\naffected-services = [\"containerd\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-kubelet-env-nvidia.toml",
    "content": "[configuration-files.kubelet-env]\ntemplate-path = \"/usr/share/templates/kubelet-env-nvidia\"\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-metal.toml",
    "content": "[settings.kubernetes]\ncluster-domain = \"cluster.local\"\nstandalone-mode = false\nauthentication-mode = \"tls\"\npod-infra-container-image = \"public.ecr.aws/eks-distro/kubernetes/pause:3.5\"\nserver-tls-bootstrap = false\ncloud-provider = \"\"\n\n[metadata.settings.kubernetes]\nnode-ip.setting-generator = \"netdog node-ip\"\naffected-services = [\"kubernetes\"]\n\n# Metrics\n[settings.metrics]\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"kubelet\"]\n\n# Network\n[metadata.settings.network]\naffected-services = [\"containerd\", \"kubernetes\", \"host-containerd\", \"host-containers\", \"updog\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-seccomp-default-false.toml",
    "content": "[settings.kubernetes]\nseccomp-default = false\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-seccomp-default-true.toml",
    "content": "[settings.kubernetes]\nseccomp-default = true\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-services.toml",
    "content": "[services.kubernetes]\nconfiguration-files = [\n  \"kubelet-env\",\n  \"kubelet-config\",\n  \"kubelet-kubeconfig\",\n  \"kubelet-bootstrap-kubeconfig\",\n  \"kubelet-exec-start-conf\",\n  \"kubernetes-ca-crt\",\n  \"proxy-env\",\n  \"kubelet-server-crt\",\n  \"kubelet-server-key\",\n  \"credential-provider-config-yaml\",\n  \"k8s-snapshotter-conf\",\n]\nrestart-commands = [\n  \"/usr/bin/systemctl try-restart kubelet.service\"\n]\n\n[configuration-files.kubelet-env]\npath = \"/etc/kubernetes/kubelet/env\"\ntemplate-path = \"/usr/share/templates/kubelet-env\"\n\n[configuration-files.kubelet-config]\npath = \"/etc/kubernetes/kubelet/config\"\ntemplate-path = \"/usr/share/templates/kubelet-config\"\nmode = \"0600\"\n\n[configuration-files.k8s-snapshotter-conf]\npath = \"/etc/kubernetes/kubelet/config.d/001-snapshotter.conf\"\ntemplate-path = \"/usr/share/templates/k8s-snapshotter-conf\"\nmode = \"0600\"\noverwrite-path-if-present = false\n\n[configuration-files.kubelet-kubeconfig]\npath = \"/etc/kubernetes/kubelet/kubeconfig\"\ntemplate-path = \"/usr/share/templates/kubelet-kubeconfig\"\nmode = \"0600\"\n\n[configuration-files.kubelet-bootstrap-kubeconfig]\npath = \"/etc/kubernetes/kubelet/bootstrap-kubeconfig\"\ntemplate-path = \"/usr/share/templates/kubelet-bootstrap-kubeconfig\"\nmode = \"0600\"\n\n[configuration-files.kubernetes-ca-crt]\npath = \"/etc/kubernetes/pki/ca.crt\"\ntemplate-path = \"/usr/share/templates/kubernetes-ca-crt\"\nmode = \"0600\"\n\n[configuration-files.kubelet-server-crt]\npath = \"/etc/kubernetes/pki/kubelet-server.crt\"\ntemplate-path = \"/usr/share/templates/kubelet-server-crt\"\n\n[configuration-files.kubelet-server-key]\npath = \"/etc/kubernetes/pki/private/kubelet-server.key\"\ntemplate-path = \"/usr/share/templates/kubelet-server-key\"\nmode = \"0600\"\n\n[configuration-files.kubelet-exec-start-conf]\npath = \"/etc/systemd/system/kubelet.service.d/exec-start.conf\"\ntemplate-path = \"/usr/share/templates/kubelet-exec-start-conf\"\nmode = \"0600\"\n\n[configuration-files.credential-provider-config-yaml]\npath = \"/etc/kubernetes/kubelet/credential-provider-config.yaml\"\ntemplate-path = \"/usr/share/templates/credential-provider-config-yaml\"\nmode = \"0600\"\n\n[configuration-files.static-pods-toml]\npath = \"/etc/kubernetes/static-pods-manifest.toml\"\ntemplate-path = \"/usr/share/templates/static-pods-toml\"\n\n[services.static-pods]\nconfiguration-files = [\"static-pods-toml\"]\nrestart-commands = [\"/usr/bin/static-pods\"]\n\n[metadata.settings.kubernetes.static-pods]\naffected-services = [\"static-pods\"]\n\n[metadata.settings.aws.profile]\naffected-services = [\"kubernetes\"]\n"
  },
  {
    "path": "sources/shared-defaults/kubernetes-vmware.toml",
    "content": "[settings.kubernetes]\ncluster-domain = \"cluster.local\"\nstandalone-mode = false\nauthentication-mode = \"tls\"\npod-infra-container-image = \"public.ecr.aws/eks-distro/kubernetes/pause:3.3\"\nserver-tls-bootstrap = false\ncloud-provider = \"external\"\n\n[metadata.settings.kubernetes]\nnode-ip.setting-generator = \"netdog node-ip\"\naffected-services = [\"kubernetes\"]\n\n# Metrics\n[settings.metrics]\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\", \"kubelet\", \"vmtoolsd\"]\n\n# Network\n[metadata.settings.network]\naffected-services = [\"containerd\", \"kubernetes\", \"host-containerd\", \"host-containers\", \"updog\"]\n"
  },
  {
    "path": "sources/shared-defaults/lockdown-integrity.toml",
    "content": "# Kernel\n[settings.kernel]\nlockdown = \"integrity\"\n"
  },
  {
    "path": "sources/shared-defaults/lockdown-none.toml",
    "content": "# Kernel\n[settings.kernel]\nlockdown = \"none\"\n"
  },
  {
    "path": "sources/shared-defaults/metrics.toml",
    "content": "[settings.metrics]\n# the URL to which anonymous health metrics will be sent\nmetrics-url = \"https://metrics.bottlerocket.aws/v1/metrics\"\n# the list of services that are checked to determine if a host is healthy,\n# overridden in each variant to list services critical to that variant\nservice-checks = [\"apiserver\", \"chronyd\", \"containerd\", \"host-containerd\"]\n\n[services.metricdog]\nconfiguration-files = [\"metricdog-toml\", \"proxy-env\"]\nrestart-commands = [\"/bin/systemctl try-restart metricdog.service\"]\n\n[configuration-files.metricdog-toml]\npath = \"/etc/metricdog.toml\"\ntemplate-path = \"/usr/share/templates/metricdog-toml\"\n"
  },
  {
    "path": "sources/shared-defaults/nvidia-k8s-container-toolkit.toml",
    "content": "[settings.nvidia-container-runtime]\nvisible-devices-as-volume-mounts = true\nvisible-devices-envvar-when-unprivileged = false\n\n[metadata.settings.nvidia-container-runtime]\naffected-services = [\"nvidia-container-toolkit\"]\n\n[services.nvidia-container-toolkit]\nconfiguration-files = [\"nvidia-container-toolkit\"]\nrestart-commands = []\n\n[configuration-files.nvidia-container-toolkit]\npath = \"/etc/nvidia-container-runtime/config.toml\"\ntemplate-path = \"/usr/share/templates/nvidia-container-runtime/nvidia-container-toolkit-config-k8s\"\n"
  },
  {
    "path": "sources/shared-defaults/nvidia-k8s-device-plugin-cdi.toml",
    "content": "[settings.kubelet-device-plugins.nvidia]\ndevice-list-strategy=\"cdi-cri\"\n"
  },
  {
    "path": "sources/shared-defaults/nvidia-k8s-device-plugin-legacy.toml",
    "content": "[settings.kubelet-device-plugins.nvidia]\ndevice-list-strategy=\"volume-mounts\"\n"
  },
  {
    "path": "sources/shared-defaults/nvidia-k8s-device-plugin.toml",
    "content": "# nvidia device plugin service\n[services.nvidia-k8s-device-plugin]\nrestart-commands = [\n    \"/bin/systemctl try-reload-or-restart nvidia-k8s-device-plugin.service\",\n]\nconfiguration-files = [\n    \"nvidia-k8s-device-plugin-conf\",\n    \"nvidia-k8s-device-plugin-exec-start-conf\",\n    \"nvidia-k8s-device-plugin-mig-conf\",\n]\n\n[services.nvidia-mps-control-daemon]\nrestart-commands = [\n    \"/bin/systemctl try-reload-or-restart nvidia-mps-control-daemon.service\",\n]\nconfiguration-files = [\n    \"nvidia-k8s-device-plugin-conf\",\n    \"nvidia-mps-control-daemon-exec-start-conf\",\n    \"nvidia-k8s-device-plugin-mig-conf\",\n]\n\n[configuration-files.nvidia-k8s-device-plugin-conf]\npath = \"/etc/nvidia-k8s-device-plugin/settings.yaml\"\ntemplate-path = \"/usr/share/templates/nvidia-k8s-device-plugin-conf\"\n\n[configuration-files.nvidia-k8s-device-plugin-exec-start-conf]\npath = \"/etc/systemd/system/nvidia-k8s-device-plugin.service.d/exec-start.conf\"\ntemplate-path = \"/usr/share/templates/nvidia-k8s-device-plugin-exec-start-conf\"\n\n[configuration-files.nvidia-k8s-device-plugin-mig-conf]\npath = \"/etc/nvidia-migmanager/nvidia-migmanager.toml\"\ntemplate-path = \"/usr/share/templates/nvidia-k8s-device-plugin-mig-conf\"\n\n[configuration-files.nvidia-mps-control-daemon-exec-start-conf]\npath = \"/etc/systemd/system/nvidia-mps-control-daemon.service.d/exec-start.conf\"\ntemplate-path = \"/usr/share/templates/nvidia-mps-control-daemon-exec-start-conf\"\n\n[metadata.settings.kubelet-device-plugins.nvidia]\naffected-services = [\n    \"nvidia-k8s-device-plugin\",\n    \"nvidia-container-toolkit\",\n    \"nvidia-mps-control-daemon\",\n]\n\n[settings.kubelet-device-plugins.nvidia]\npass-device-specs = true\ndevice-id-strategy = \"index\"\ndevice-sharing-strategy = \"none\"\ndevice-partitioning-strategy = \"none\"\n"
  },
  {
    "path": "sources/shared-defaults/oci-defaults-capabilities.toml",
    "content": "[settings.oci-defaults.capabilities]\n# These values represent the default capabilities for Docker and Containerd.\naudit-write = true\nchown = true\ndac-override = true\nfowner = true\nfsetid = true\nkill = true\nmknod = true\nnet-bind-service = true\nnet-raw = true\nsetgid = true\nsetfcap = true\nsetpcap = true\nsetuid = true\nsys-chroot = true\n"
  },
  {
    "path": "sources/shared-defaults/oci-defaults-containerd-cri-resource-limits.toml",
    "content": "[settings.oci-defaults.resource-limits.max-open-files]\nhard-limit = 1048576\nsoft-limit = 65536\n"
  },
  {
    "path": "sources/shared-defaults/oci-defaults-containerd-cri.toml",
    "content": "[metadata.settings.oci-defaults]\naffected-services = [\"oci-defaults\", \"containerd\"]\n\n[services.oci-defaults]\nconfiguration-files = [\"oci-defaults\"]\nrestart-commands = []\n\n[configuration-files.oci-defaults]\npath = \"/etc/containerd/cri-base.json\"\ntemplate-path = \"/usr/share/templates/containerd-cri-base-json\"\n"
  },
  {
    "path": "sources/shared-defaults/oci-defaults-docker-resource-limits.toml",
    "content": "[settings.oci-defaults.resource-limits.max-open-files]\nhard-limit = 4096\nsoft-limit = 1024\n"
  },
  {
    "path": "sources/shared-defaults/oci-defaults-docker.toml",
    "content": "[metadata.settings.oci-defaults]\naffected-services = [\"docker\"]\n"
  },
  {
    "path": "sources/shared-defaults/oci-hooks.toml",
    "content": "[settings.oci-hooks]\nlog4j-hotpatch-enabled = false\n\n[metadata.settings.oci-hooks.log4j-hotpatch-enabled]\naffected-services = [\"log4j-hotpatch-enabled\"]\n\n[services.log4j-hotpatch-enabled]\nconfiguration-files = [\"log4j-hotpatch-enabled-log-message\"]\nrestart-commands = [\"systemctl restart deprecation-warning@log4j-hotpatch-enabled.timer\"]\n\n[configuration-files.log4j-hotpatch-enabled-log-message]\npath = \"/etc/deprecated-settings/log4j-hotpatch-enabled\"\ntemplate-path = \"/usr/share/templates/log4j-hotpatch-enabled\"\n"
  },
  {
    "path": "sources/shared-defaults/public-bootstrap-containers.toml",
    "content": "[metadata.settings.bootstrap-containers.source.setting-generator]\ncommand = \"schnauzer-v2 render --template 'public.ecr.aws/bottlerocket/bottlerocket-bootstrap:v0.2.14'\"\nstrength = \"weak\"\ndepth = 1\n"
  },
  {
    "path": "sources/shared-defaults/public-host-containers.toml",
    "content": "# Both containers are disabled by default in off-AWS variants because the user\n# must supply user data in order to use the containers.  The admin container\n# isn't useful without SSH keys/CA certs, and the control container can only be\n# used with hybrid SSM off of AWS.  Users of off-AWS variants might not want to\n# use either of those options.\n[settings.host-containers.admin]\nenabled = false\nsuperpowered = true\n\n[metadata.settings.host-containers.admin.source.setting-generator]\ncommand = \"schnauzer-v2 render --template 'public.ecr.aws/bottlerocket/bottlerocket-admin:v0.20.4'\"\nstrength = \"weak\"\n\n[settings.host-containers.control]\nenabled = false\nsuperpowered = false\n\n[metadata.settings.host-containers.control.source.setting-generator]\ncommand = \"schnauzer-v2 render --template 'public.ecr.aws/bottlerocket/bottlerocket-control:v0.20.4'\"\nstrength = \"weak\"\n"
  },
  {
    "path": "sources/shared-defaults/public-ntp.toml",
    "content": "# Use a public endpoint, don't assume any local ones.\n[settings.ntp]\ntime-servers = [\"2.amazon.pool.ntp.org\"]\n"
  },
  {
    "path": "sources/shared-defaults/public-tuf.toml",
    "content": "[settings.updates]\ntargets-base-url = \"https://updates.bottlerocket.aws/targets/\"\n\n[metadata.settings.updates.metadata-base-url]\nsetting-generator = \"schnauzer-v2 render --template 'https://updates.bottlerocket.aws/2020-07-07/{{ os.variant_id }}/{{ os.arch }}/'\"\n"
  },
  {
    "path": "sources/shared-defaults/send-metrics-aws.toml",
    "content": "[metadata.settings.metrics.send-metrics]\n# only enable metrics in partitions with unhindered access to the metrics endpoint\nsetting-generator = \"shibaken is-partition --partition aws --partition aws-us-gov\"\n"
  },
  {
    "path": "sources/shared-defaults/send-metrics-global.toml",
    "content": "[settings.metrics]\n# whether or not health metrics will be sent. set to false to opt-out\nsend-metrics = true\n"
  },
  {
    "path": "tools/.gitignore",
    "content": "/bin\n/twoliter\n/.crates.toml\n/.crates2.json\n"
  },
  {
    "path": "tools/diff-kernel-config",
    "content": "#!/usr/bin/env bash\n\n#\n# Common error handling\n#\n\nexit_trap_cmds=()\n\non_exit() {\n    exit_trap_cmds+=( \"$1\" )\n}\n\nrun_exit_trap_cmds() {\n    for cmd in \"${exit_trap_cmds[@]}\"; do\n        eval \"${cmd}\"\n    done\n}\n\ntrap run_exit_trap_cmds EXIT\n\nwarn() {\n    >&2 echo \"Warning: $*\"\n}\n\nbail() {\n    if [[ $# -gt 0 ]]; then\n        >&2 echo \"Error: $*\"\n    fi\n    exit 1\n}\n\nusage() {\n    cat <<EOF\nUsage: $0 -b GITREV_BEFORE -a GITREV_AFTER -o OUTPUT_DIR [-v VARIANT] [-r] [-h]\nCompare kernel configurations before and after a series of commits.\n\n    -a, --after         new Git revision to compare from\n    -b, --before        baseline Git revision to compare against\n    -v, --variant       variant to pick kernel from to compare configs for, may\n                        be given multiple times (optional, defaults to this list:\n                        'aws-k8s-1.23', 'metal-k8s-1.23', 'aws-dev', 'metal-dev')\n    -o, --output-dir    path to the output directory; must not exist yet\n    -r, --resume        resume work on a previous invocation; check which parts\n                        already exist in OUTPUT_DIR and skip builds accordingly\n    -h, --help          show this help text\n\nExample invocation:\n\n    This compares the config changes for kernels 5.10 (through metal-k8s-1.23)\n    and 5.15 (through metal-k8s-1.26) before and after the most recent commit\n    has been applied:\n\n        $0 -b HEAD^ -a HEAD -v metal-k8s-1.23 -v metal-k8s-1.26 -o configs\n\nNotes:\n\n    This compares the config changes for all combinations of aarch64/x86_64,\n    cloud/metal, and kernel versions. Combinations without a corresponding\n    Bottlerocket variant are skipped. Since this involves numerous full kernel\n    builds the comparison will take some time. Consider the working tree this\n    is invoked on busy while the script is running.\n\nEOF\n}\n\nusage_error() {\n    >&2 usage\n    bail \"$1\"\n}\n\n\n#\n# Parse arguments\n#\n\nkernel_versions=()\nvariants=()\n\nwhile [[ $# -gt 0 ]]; do\n    case $1 in\n        -a|--after)\n            shift; gitrev_after_arg=$1 ;;\n        -b|--before)\n            shift; gitrev_before_arg=$1 ;;\n        -v|--variant)\n            shift; variants+=( \"$1\" ) ;;\n        -o|--output-dir)\n            shift; output_dir=$1 ;;\n        -r|--resume)\n            shift; resume=1 ;;\n        -h|--help)\n            usage; exit 0 ;;\n        *)\n            usage_error \"Invalid option '$1'\" ;;\n    esac\n    shift\ndone\n\nif [[ ${#variants[@]} -eq 0 ]]; then\n    variants=( aws-k8s-1.23 metal-k8s-1.23 aws-dev metal-dev )\nfi\n\nfor var in \"${variants[@]}\"; do\n    [[ -d variants/${var} ]] || bail \"Unknown variant '${var}'\"\ndone\nreadonly variants\n\n[[ -n ${output_dir} ]] || usage_error 'require -o|--output-dir'\n[[ -e ${output_dir} && ! -v resume ]] && bail \"Output directory '${output_dir}' exists already, not touching it\"\nreadonly output_dir\n\n# Validate and resolve the given before and after Git revisions. Resolving\n# them now prevents relative references from moving around after the first\n# checkout.\n[[ -n ${gitrev_before_arg} ]] || usage_error 'require -b|--before'\n[[ -n ${gitrev_after_arg} ]] || usage_error 'require -a|--after'\ngitrev_before=$(git rev-parse --verify --end-of-options \"${gitrev_before_arg}^{commit}\")\ngitrev_after=$(git rev-parse --verify --end-of-options \"${gitrev_after_arg}^{commit}\")\n[[ -n ${gitrev_before} ]] || bail \"Invalid Git revision '${gitrev_before_arg}'\"\n[[ -n ${gitrev_after} ]] || bail \"Invalid Git revision '${gitrev_after_arg}'\"\nreadonly gitrev_before\nreadonly gitrev_after\n\n\n#\n# Prepare working tree\n#\n\n# We'll check out the before and after states to compare. For that the working\n# tree and the index need to be clean.\nif [[ -n $(git status --porcelain --untracked-files=no) ]]; then\n    bail 'The working tree or index of the repository are not clean. ' \\\n         'Consider running \"git stash\" to temporarily stow away your changes.'\nfi\n\n# Restore current repository state whenever we exit (either a checked out\n# branch or the current detached head state).\ngitrev_original=$(git rev-parse --abbrev-ref HEAD)\nif [[ -z ${gitrev_original} ]]; then\n    gitrev_original=$(git rev-parse HEAD) || bail 'Cannot determine current repository HEAD.'\nfi\nreadonly gitrev_original\non_exit \"git checkout --quiet '${gitrev_original}'\"\n\n\n#\n# Iterate over all viable build configurations in before and after states\n#\n\nmkdir -p \"${output_dir}\" || bail \"Failed to create output directory '${output_dir}'\"\n\nfor state in after before; do\n\n    gitrev_var=gitrev_${state}\n    git checkout --quiet \"${!gitrev_var}\" || bail \"Cannot check out '${!gitrev_var}'.\"\n\n    for variant in \"${variants[@]}\"; do\n\n        arches=()\n        IFS=\" \" read -r -a arches <<< \"$(grep \"supported-arches\" \"variants/${variant}/Cargo.toml\" | cut -d ' ' -f 3 | tr -d '\"[]')\"\n        if [[ ${#arches[@]} -eq 0 ]]; then\n            arches=( aarch64 x86_64 )\n        fi\n\n        kver=$(grep \"packages/kernel\" \"variants/${variant}/Cargo.toml\" | cut -d ' ' -f 1 | cut -d '-' -f 2 | tr '_' '.')\n\n        kernel_versions+=( \"${kver}\" )\n\n        for arch in \"${arches[@]}\"; do\n            config_path=${output_dir}/config-${arch}-${variant}-${state}\n\n            if [[ -v resume && -e ${config_path} ]]; then\n                echo \"${config_path} already exists, skipping\"\n                continue\n            fi\n\n            debug_id=\"state=${state} arch=${arch} variant=${variant} kernel=${kver}\"\n\n            IFS=- read -ra variant_parts <<<\"${variant}\"\n            variant_platform=\"${variant_parts[0]}\"\n            variant_runtime=\"${variant_parts[1]}\"\n            variant_family=\"${variant_platform}-${variant_runtime}\"\n\n            #\n            # Run build\n            #\n\n            cargo make \\\n                    -e BUILDSYS_ARCH=\"${arch}\" \\\n                    -e BUILDSYS_VARIANT=\"${variant}\" \\\n                    -e BUILDSYS_VARIANT_PLATFORM=\"${variant_platform}\" \\\n                    -e BUILDSYS_VARIANT_RUNTIME=\"${variant_runtime}\" \\\n                    -e BUILDSYS_VARIANT_FAMILY=\"${variant_family}\" \\\n                    -e PACKAGE=\"kernel-${kver/./_}\" \\\n                    build-package \\\n                || bail \"Build failed for ${debug_id}\"\n\n            #\n            # Find kernel RPM\n            #\n\n            shopt -s nullglob\n            kernel_rpms=(\n                ./build/rpms/bottlerocket-*kernel-\"${kver}\"-\"${kver}\".*.\"${arch}\".rpm\n                ./build/rpms/bottlerocket-\"${arch}\"-*kernel-\"${kver}\"-\"${kver}\".*.rpm\n            )\n            shopt -u nullglob\n\n            case ${#kernel_rpms[@]} in\n                0) bail \"No kernel RPM found for ${debug_id}\" ;;\n                1) kernel_rpm=${kernel_rpms[0]} ;;\n                *)\n                    # shellcheck disable=SC2012  # find(1) cannot sort by mtime\n                    kernel_rpm=$(ls -1t \"${kernel_rpms[@]}\" | head -n 1)\n                    warn \"More than one kernel RPM found for ${debug_id}. Choosing '${kernel_rpm}' as the latest build.\"\n                    ;;\n            esac\n\n            kver_full=$(rpm --query --queryformat '%{VERSION}-%{RELEASE}' \"${kernel_rpm}\")\n\n            #\n            # Extract kernel config\n            #\n\n            rpm2cpio \"${kernel_rpm}\" \\\n                | cpio --quiet --extract --to-stdout ./boot/config >\"${config_path}\"\n            [[ -s \"${config_path}\" ]] || bail \"Failed to extract config for ${debug_id}\"\n\n\n            echo \"config-${arch}-${variant}-${state} -> ${kver_full}\" >> \"${output_dir}\"/kver_mapping\n        done  # arch\n\n    done  # variant\n\ndone  # state\n\n\n#\n# Post-process the collected pairs of \"before\" and \"after\" configs (generate diffs, a report, a summary)\n#\n\n# Get the helpful diffconfig script from the kernel source tree. We package it\n# in the kernel-archive RPM from where it can be extracted. Here we extract the\n# latest version of the script, but any kernel version and arch will do.\nlatest_kver=$(printf '%s\\n' \"${kernel_versions[@]}\" | sort -V | tail -n1)\nlatest_archive_rpms=( ./build/rpms/bottlerocket-*kernel-\"${latest_kver}\"-archive-*.rpm )\ndiffconfig=$(mktemp --suffix -bottlerocket-diffconfig)\non_exit \"rm '${diffconfig}'\"\nrpm2cpio \"${latest_archive_rpms[0]}\" \\\n    | cpio --quiet --extract --to-stdout \\\n    | tar --xz --extract --to-stdout kernel-devel/scripts/diffconfig >\"${diffconfig}\"\n[[ -s ${diffconfig} ]] || bail \"Failed to extract diffconfig tool from '${latest_archive_rpms[0]}'.\"\nchmod +x \"${diffconfig}\"\n\n# Diff the before and after states for each collected pair\nfor config_before in \"${output_dir}\"/config-*-before; do\n    config_after=${config_before/before/after}\n    config_diff=${config_before/before/diff}\n    \"${diffconfig}\" \"${config_before}\" \"${config_after}\" >\"${config_diff}\" \\\n        || bail \"Failed to diff '${config_before}' and '${config_after}'\"\ndone\n\n# Generate diff summary\necho\nfor config_diff in \"${output_dir}\"/config-*-diff; do\n    config_base=${config_diff##*/}\n    awk \"\n        /^-/   { removed += 1 }\n        /^+/   { added   += 1 }\n        / -> / { changed += 1 }\n        END    { printf \\\"${config_base}:\\t%3d removed, %3d added, %3d changed\\n\\\", removed, added, changed }\n    \" \"${config_diff}\"\ndone | sort -V | tee \"${output_dir}\"/diff-summary\necho\n\n# Generate combined report of changes\nhead -v -n 999999 \"${output_dir}\"/*-diff >\"${output_dir}\"/diff-report\necho \"A full report has been placed in '${output_dir}/diff-report'\"\n\n# Generate combined report in tabular form (csv)\necho \"config change\" > \"${output_dir}\"/diff-table\ncat \"${output_dir}\"/*-diff | sort | uniq >> \"${output_dir}\"/diff-table\n\nfor config_diff in \"${output_dir}\"/config-*-diff; do\n    variant_name=$(echo \"${config_diff}\" | sed -e \"s%^${output_dir}/config-%%\" -e \"s%-diff$%%\")\n    kver_before=$(grep \"${variant_name}-before\" \"${output_dir}/kver_mapping\" | cut -d ' ' -f 3)\n    kver_after=$(grep \"${variant_name}-after\" \"${output_dir}/kver_mapping\" | cut -d ' ' -f 3)\n    col_name=\"${variant_name} (${kver_before} -> ${kver_after})\"\n\n    sed -i \"s/$/,/\" \"${output_dir}\"/diff-table\n    sed -i \"/^config change/ s/$/${col_name}/\" \"${output_dir}\"/diff-table\n\n    mapfile -t diff_lines < \"${config_diff}\"\n\n    for line in \"${diff_lines[@]}\"; do\n        sed -i \"/^${line}/ s/$/x/\" \"${output_dir}\"/diff-table\n    done\ndone\necho \"A tabular report in csv-format has been placed in '${output_dir}/diff-table'\"\n"
  },
  {
    "path": "tools/install-twoliter.sh",
    "content": "#!/usr/bin/env bash\n\n#\n# Common error handling\n#\n\nexit_trap_cmds=()\n\non_exit() {\n    exit_trap_cmds+=( \"$1\" )\n}\n\nrun_exit_trap_cmds() {\n    for cmd in \"${exit_trap_cmds[@]}\"; do\n        eval \"${cmd}\"\n    done\n}\n\ntrap run_exit_trap_cmds EXIT\n\nwarn() {\n    >&2 echo \"Warning: $*\"\n}\n\nbail() {\n    if [[ $# -gt 0 ]]; then\n        >&2 echo \"Error: $*\"\n    fi\n    exit 1\n}\n\nusage() {\n    cat <<EOF\nUsage: $0 -r GIT_REPO -v TWOLITER_VERSION -d INSTALL_DIR [-e REUSE_EXISTING] [-b BINARY_INSTALL] [ -s SOURCE_INSTALL ] [-h]\n\n    -r, --repo                    the git or GitHub repository from which to install. For source\n                                  install this can be any git repo, including a GitHub. For a binary\n                                  installation, this must be a GitHub repository that has binaries\n                                  attached to releases.\n    -v, --version                 the version (with the v prefix), or the git branch, sha or tag\n    -d, --directory               the directory to install twoliter into\n    -e, --reuse-existing-install  we will skip installation if we find the correct version installed\n    -b, --allow-binary-install    we will try to install a GitHub release-attached binary if the\n                                  host we are on is Linux. Takes an expected sha256 sum for the\n                                  binary as input.\n    -s, --allow-from-source       we will install from source using cargo install pointed to a git\n                                  repo and rev when binary install is either not allowed or not\n                                  possible\n    -k, --skip-version-check      do not check to see if the installed version matches the one that\n                                  is requested by the --version argument. twoliter will not be\n                                  installed when the binary is present, regardless of what version\n                                  it is.\n    -h, --help                    show this help text\n\nExample invocation:\n\n    This installs the twoliter program which is needed to build Bottlerocket\n\n    Example, installing binary and reusing-existing (if it exists):\n\n        $0 \\\\\n            -r https://github.com/bottlerocket-os/twoliter \\\\\n            -v v0.1.0 \\\\\n            -d tools/twoliter \\\\\n            -b \\\\\n            -e\n\n    Example, installing from source whether or not it is already installed:\n\n        $0 \\\\\n            -r https://github.com/myfork/twoliter \\\\\n            -v b0482f1 \\\\\n            -d tools/twoliter \\\\\n            -s\n\nEOF\n}\n\nusage_error() {\n    >&2 usage\n    bail \"$1\"\n}\n\n\n#\n# Parse arguments\n#\n\nwhile [[ $# -gt 0 ]]; do\n    case $1 in\n        -r|--repo)\n            shift; repo=$1 ;;\n        -v|--version)\n            shift; version=$1 ;;\n        -d|--directory)\n            shift; dir=$1 ;;\n        -e|--reuse-existing-install)\n            reuse_existing=\"true\" ;;\n        -b|--allow-binary-install)\n            allow_bin=\"true\"; shift; bin_checksum=$1 ;;\n        -s|--allow-from-source)\n            from_source=\"true\" ;;\n        -k|--skip-version-check)\n            skip_version_check=\"true\" ;;\n        -h|--help)\n            usage; exit 0 ;;\n        *)\n            usage_error \"Invalid option '$1'\" ;;\n    esac\n    shift\ndone\n\nset -e\n\nworkdir=\"$(mktemp -d)\"\non_exit \"rm -rf ${workdir}\"\nmkdir -p \"${dir}\"\n\nif [ \"${reuse_existing}\" = \"true\" ] ; then\n   if [ -x \"${dir}/twoliter\" ] ; then\n      if [ \"${skip_version_check}\" = \"true\" ]; then\n        echo \"Twoliter binary found and --skip-version-check is true. Skipping install.\"\n        exit 0\n      fi\n      version_output=\"$(\"${dir}/twoliter\" --version)\"\n      found_version=v$(echo $version_output | awk '{print $2}')\n      echo \"Found Twoliter ${found_version} installed.\"\n      if [ \"${found_version}\" = \"${version}\" ] ; then\n         echo \"Skipping installation.\"\n         exit 0\n      fi\n   fi\nfi\n\nif [ \"${allow_bin}\" = \"true\" ] ; then\n   host_arch=\"$(uname -m)\"\n   host_arch=\"${host_arch,,}\"\n   host_kernel=\"$(uname -s)\"\n   host_kernel=\"${host_kernel,,}\"\n   case \"${host_kernel}-${host_arch}\" in\n      linux-x86_64 | linux-aarch64)\n      echo \"Installing Twoliter from binary release.\"\n      twoliter_release=\"${repo}/releases/download/${version}\"\n      twoliter_target=\"${host_arch}-unknown-${host_kernel}-musl\"\n      cd \"${workdir}\"\n      curl -sSL \"${twoliter_release}/twoliter-${twoliter_target}.tar.xz\" -o \"twoliter.tar.xz\"\n      echo \"Checking binary checksum...\"\n      sha256sum -c <<< \"${bin_checksum} twoliter.tar.xz\"\n      tar xf twoliter.tar.xz\n      mv \"./twoliter-${twoliter_target}/twoliter\" \"${dir}\"\n      exit 0\n      ;;\n   *)\n      echo \"No pre-built binaries available for twoliter ${version}.\"\n      ;;\n   esac\nelse\n   echo \"Skipping binary installation of twoliter ${version} because --allow-binary-install was not set.\"\nfi\n\nif [ \"${from_source}\" = \"true\" ] ; then\n   echo \"Installing Twoliter version ${version} from source\"\n   cargo +nightly install \\\n     -Z bindeps \\\n     --locked \\\n     --root \"${workdir}\" \\\n     --git \"${repo}\" \\\n     --rev \"${version}\" \\\n     --bin twoliter \\\n     --quiet \\\n     twoliter\n   mv \"${workdir}/bin/twoliter\" \"${dir}/twoliter\"\n   echo \"Installed twoliter ${version} from source.\"\n   exit 0\nelse\n   echo \"Skipped installing twoliter ${version} from source.\"\nfi\n\n\nif [ ! -x \"${dir}/twoliter\" ] ; then\n   echo \"Could not install twoliter ${version}\" >&2\n   exit 1\nfi\n"
  },
  {
    "path": "tools/pubsys/Infra.toml.example",
    "content": "# This is an example infrastructure configuration for pubsys, the tool that\n# creates repos when you call `cargo make repo`.  Save a copy as `Infra.toml`\n# at the root of the repo, then edit the settings below to match your use case.\n\n# You can have any number of repos defined and build a specific one by running like this:\n#     cargo make -e PUBLISH_REPO=myrepo repo\n[repo.default]\n# URL to your root role JSON file; can be a file:// URL for local files.  If\n# you don't specify one here, a file will be generated for you under /roles.\n# For production use, you should store them somewhere safer.\nroot_role_url = \"https://example.com/root.json\"\n# SHA512 checksum of your root role JSON file.\nroot_role_sha512 = \"0123456789abcdef\"\n\n# For reference, this is the Bottlerocket root role:\n#root_role_url = \"https://cache.bottlerocket.aws/root.json\"\n#root_role_sha512 = \"4fcb272345fd6adb94d4c04834400548178fecb57407ca79bc2c3d20e0428fc9ed3a82cea268d7f9c667b5803524a4f465acd701a86953d5d732bf6ecb064888\"\n\n# pubsys assumes a single publication key that signs the snapshot, targets,\n# and timestamp roles.  Here you specify where that key lives so we can sign\n# the created repo.  If you don't specify one here, a key will be generated for\n# you under /keys.  For production use, you should use a key stored in a\n# trusted service like KMS or SSM.\n# (Need inline table syntax until this is fixed: https://github.com/alexcrichton/toml-rs/issues/225)\nsigning_keys = { file = { path = \"/home/user/key.pem\" } }\n#signing_keys = { kms = { key_id = \"abc-def-123\" } }\n#signing_keys = { ssm = { parameter = \"/my/parameter\" } }\n\n# If these URLs are uncommented, the repo will be pulled and used as a starting\n# point, and your images (and related files) will be added as a new update in\n# the created repo.  Otherwise, we build a new repo from scratch.\nmetadata_base_url = \"https://example.com/\"\ntargets_url = \"https://example.com/targets/\"\n\n[aws]\n# The list of regions in which you want to publish AMIs. We register an AMI in\n# the first region and copy it to all other regions.\nregions = [\"us-west-2\", \"us-east-1\", \"us-east-2\"]\n# If specified, we use this named profile from ~/.aws/credentials, rather than\n# the default path of trying credentials from the environment, from a\n# credential process, from the default profile, and then from an IAM instance\n# profile.\nprofile = \"my-profile\"\n# If specified, we assume this role before making any API calls.\nrole = \"arn:aws:iam::012345678901:role/assume-global\"\n# If specified, this string will be prefixed on all parameter names published to SSM.\nssm_prefix = \"/your/prefix/here\"\n\n[aws.region.us-west-2]\n# If specified, we assume this role before making any API calls in this region.\n# (This is assumed after the \"global\" aws.role, if that is also specified.)\nrole = \"arn:aws:iam::012345678901:role/assume-regional\"\n\n[vmware]\n# A list of datacenter names to which you would like to upload an OVA.  These\n# are \"friendly\" names, and do not need to be the actual name of the\n# software-defined datacenter, but can be.  For example, you may have have\n# multiple vSphere instances with datacenters that still carry the default\n# \"SDDC-Datacenter\" name; this field allows you to differentiate them.\ndatacenters = [\"north\", \"south\"]\n\n# ***\n# GOVC_* environment variables set in the current environment override any\n# configuration set in the sections below!\n# ***\n\n# Optional common configuration\n# This configuration allow values to be set in a single place if they are common in\n# multiple datacenters.  They can be overridden in the datacenter's block below.\n[vmware.common]\nnetwork = \"a_network\"\n\n# Datacenter specific configuration\n# This specifies all of the values necessary to communicate with this\n# datacenter via `govc`.  Each value maps directly to the GOVC_* environment\n# variable in the corresponding comment.  If any of these values is missing and\n# isn't in the environment, we will look for them in `vmware.common`.\n[vmware.datacenter.north]\nvsphere_url = \"https://vcenter.1234.vmwarevmc.com\" # GOVC_URL\ndatacenter = \"SDDC-Datacenter\" # GOVC_DATACENTER\ndatastore = \"WorkloadDatastore\" # GOVC_DATASTORE\nnetwork = \"sddc-cgw-network-1\" # GOVC_NETWORK\nfolder = \"my_folder\" # GOVC_FOLDER\nresource_pool = \"/SDDC-Datacenter/host/Cluster/Resources/Compute-ResourcePool\" # GOVC_RESOURCE_POOL\n"
  },
  {
    "path": "tools/pubsys/policies/repo-expiration/2w-2w-1w.toml",
    "content": "snapshot_expiration = '2 weeks'\ntargets_expiration = '2 weeks'\ntimestamp_expiration = '1 week'\n"
  },
  {
    "path": "tools/pubsys/policies/ssm/README.md",
    "content": "# Parameter templates\n\nFiles in this directory contain template strings that are used to generate SSM parameter names and values.\nYou can pass a different directory to `pubsys` to use a different set of parameters.\n\nThe directory is expected to contain a file named `defaults.toml` with a table entry per parameter, like this:\n\n```toml\n[[parameter]]\nname = \"{variant}/{arch}/{image_version}/image_id\"\nvalue = \"{image_id}\"\n```\n\nThe `name` and `value` can contain template variables that will be replaced with information from the current build and from the AMI registered from that build.\n\nThe available variables include:\n* `variant`, for example \"aws-ecs-2\"\n* `arch`, for example \"x86_64\" or \"arm64\".\n  * Note: \"amd64\" and \"aarch64\" are mapped to \"x86_64\" and \"arm64\", respectively, to match the names used by EC2.\n* `image_id`, for example \"ami-0612c21373a768f20\"\n* `image_name`, for example \"bottlerocket-aws-ecs-2-x86_64-v1.42.0-5ed15786\"\n* `image_version`, for example \"1.42.0-5ed15786\"\n* `region`, for example \"us-west-2\"\n\n# Conditional parameters\n\nYou can also list parameters that only apply to specific variants or architectures.\nTo do so, add `variant` or `arch` keys (or both) to your parameter definition.\nThe parameter will only be populated if the current `variant` or `arch` matches one of the values in the list.\n(If both `variant` and `arch` are listed, the build must match an entry from both lists.)\n\nFor example, to add an extra parameter that's only set for \"aarch64\" builds of the \"aws-ecs-2\" variant:\n```toml\n[[parameter]]\narch = [\"aarch64\"]\nvariant = [\"aws-ecs-2\"]\nname = \"/a/special/aarch64/ecs/parameter\"\nvalue = \"{image_name}\"\n```\n"
  },
  {
    "path": "tools/pubsys/policies/ssm/defaults.toml",
    "content": "[[parameter]]\nname = \"{variant}/{arch}/{image_version}/image_id\"\nvalue = \"{image_id}\"\n\n[[parameter]]\nname = \"{variant}/{arch}/{image_version}/image_version\"\nvalue = \"{image_version}\"\n"
  },
  {
    "path": "tools/pubsys/support/vmware/import_spec.template",
    "content": "\\{\n  \"DiskProvisioning\": \"flat\",\n  \"IPAllocationPolicy\": \"dhcpPolicy\",\n  \"IPProtocol\": \"IPv4\",\n  \"NetworkMapping\": [\n    \\{\n      \"Name\": \"VM Network\",\n      \"Network\": \"{ network }\"\n    }\n  ],\n  \"MarkAsTemplate\": { mark_as_template },\n  \"PowerOn\": false,\n  \"InjectOvfEnv\": false,\n  \"WaitForIP\": false,\n  \"Name\": null\n}\n"
  },
  {
    "path": "tools/start-local-vm",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2054  # Arrays are formatted for passing args to other tools\n\n#\n# Common error handling\n#\n\nexit_trap_cmds=()\n\non_exit() {\n    exit_trap_cmds+=( \"$1\" )\n}\n\nrun_exit_trap_cmds() {\n    for cmd in \"${exit_trap_cmds[@]}\"; do\n        eval \"${cmd}\"\n    done\n}\n\ntrap run_exit_trap_cmds exit\n\nbail() {\n    >&2 echo \"$@\"\n    exit 1\n}\n\nshopt -s nullglob\n\narch=${BUILDSYS_ARCH}\nvariant=${BUILDSYS_VARIANT}\nproduct_name=${BUILDSYS_NAME:-bottlerocket}\nhost_port_forwards=tcp::2222-:22\nvm_mem=4G\nvm_cpus=4\nforce_extract=\ndeclare -A extra_files=()\n\nos_image=\ndata_image=\n\n\nif ! git_toplevel=$(git rev-parse --show-toplevel); then\n    bail \"Failed to get the root of the repo.\"\nelse\n    readonly repo_root=\"${git_toplevel}\"\nfi\n\nshow_usage() {\n    echo \"\\\nusage: ${0##*/} [--arch BUILDSYS_ARCH] [--variant BUILDSYS_VARIANT]\n                      [--host-port-forwards HOST_PORT_FWDS]\n                      [--product-name NAME]\n                      [--vm-memory VM_MEMORY] [--vm-cpus VM_CPUS]\n                      [--force-extract]\n                      [--inject-file LOCAL_PATH[:IMAGE_PATH]]...\n                      [--firmware-code PATH] [--firmware-vars PATH]\n                      [--os-image-size SIZE] [--data-image-size SIZE]\n\nLaunch a local virtual machine from a Bottlerocket image.\n\nOptions:\n\n    --arch              architecture of the Bottlerocket image (must match the\n                        host architecture ($(uname -m)); may be omitted if the\n                        BUILDSYS_ARCH environment variable is set)\n    --variant           Bottlerocket variant to run (may be omitted if the\n                        BUILDSYS_VARIANT environment variable is set)\n    --product-name      short product name used as prefix for file and directory\n                        names (defaults to the BUILDSYS_NAME environment variable\n                        or 'bottlerocket' when that is unset)\n    --host-port-forwards\n                        list of host ports to forward to the VM; HOST_PORT_FWDS\n                        must be a valid QEMU port forwarding specifier (default\n                        is ${host_port_forwards})\n    --vm-memory         amount of memory to assign to the VM; VM_MEMORY must be\n                        a valid QEMU memory specifier (default is ${vm_mem})\n    --vm-cpus           number of CPUs to spawn for VM (default is ${vm_cpus})\n    --force-extract     force recreation of the extracted Bottlerocket image,\n                        e.g. to force first boot behavior\n    --inject-file       adds a local file to the private partition of the\n                        Bottlerocket image before launching the virtual machine\n                        (may be given multiple times); existing data on the\n                        private partition will be lost\n    --firmware-code     override the default firmware executable file\n    --firmware-vars     override the initial firmware variable storage file\n    --os-image-size     resize the OS disk image to the given size (e.g. 4096M)\n    --data-image-size   resize the data disk image to the given size (e.g. 20G)\n    --help              shows this usage text\n\nBy default, the virtual machine's port 22 (SSH) will be exposed via the local\nport 2222, i.e. if the Bottlerocket admin container has been enabled via\nuser-data, it can be reached by running\n\n    ssh -p 2222 ec2-user@localhost\n\nfrom the host.\n\nUsage example:\n\n    ${0##*/} --arch $(uname -m) --variant metal-dev --inject-file net.toml\n\"\n}\n\nusage_error() {\n    local error=$1\n\n    {\n        if [[ -n ${error} ]]; then\n            printf \"%s\\n\\n\" \"${error}\"\n        fi\n        show_usage\n    } >&2\n\n    exit 1\n}\n\nparse_args() {\n    while [[ $# -gt 0 ]]; do\n        case $1 in\n            -h|--help)\n                show_usage; exit 0 ;;\n            --arch)\n                shift; arch=$1 ;;\n            --variant)\n                shift; variant=$1 ;;\n            --product-name)\n                shift; product_name=$1 ;;\n            --host-port-forwards)\n                shift; host_port_forwards=$1 ;;\n            --vm-memory)\n                shift; vm_mem=$1 ;;\n            --vm-cpus)\n                shift; vm_cpus=$1 ;;\n            --force-extract)\n                force_extract=yes ;;\n            --inject-file)\n                shift; local file_spec=$1\n                if [[ ${file_spec} = *:* ]]; then\n                    local local_file=${file_spec%%:*}\n                    local image_file=${file_spec#*:}\n                else\n                    local local_file=${file_spec}\n                    local image_file=${file_spec##*/}\n                fi\n                extra_files[${local_file}]=${image_file}\n                ;;\n            --firmware-code)\n                shift; firmware_code=$1\n                ;;\n            --firmware-vars)\n                shift; firmware_vars=$1\n                ;;\n            --os-image-size)\n                shift; os_image_size=$1\n                ;;\n            --data-image-size)\n                shift; data_image_size=$1\n                ;;\n            *)\n                usage_error \"unknown option '$1'\" ;;\n        esac\n        shift\n    done\n\n    [[ -n ${arch} ]] || usage_error 'Architecture needs to be set via either --arch or BUILDSYS_ARCH.'\n    [[ -n ${variant} ]] || usage_error 'Variant needs to be set via either --variant or BUILDSYS_VARIANT.'\n\n    declare -l host_arch\n    host_arch=$(uname -m)\n    [[ ${arch} == \"${host_arch}\" ]] || bail \"Architecture needs to match host architecture (${host_arch}) for hardware virtualization.\"\n\n    for path in \"${!extra_files[@]}\"; do\n        [[ -e ${path} ]] || bail \"Cannot find local file '${path}' to inject.\"\n    done\n}\n\nextract_image() {\n    local -r compressed_image=$1\n    local -r uncompressed_image=$2\n\n    if [[ ${force_extract} = yes ]] || [[ ${compressed_image} -nt ${uncompressed_image} ]]; then\n        lz4 --decompress --force --keep \"${compressed_image}\" \"${uncompressed_image}\" \\\n            || bail \"Failed to extract '${compressed_image}'.\"\n    fi\n}\n\nprepare_raw_images() {\n    local -r image_dir=build/images/${arch}-${variant}/latest\n    local -r compressed_os_image=${image_dir}/${product_name}-${variant}-${arch}.img.lz4\n    local -r compressed_data_image=${image_dir}/${product_name}-${variant}-${arch}-data.img.lz4\n\n    if [[ -e ${compressed_os_image} ]]; then\n        readonly os_image=${compressed_os_image%*.lz4}\n        extract_image \"${compressed_os_image}\" \"${os_image}\"\n    else\n        bail 'Boot image not found. Did the last build fail?'\n    fi\n\n    if [[ -e ${compressed_data_image} ]]; then\n        readonly data_image=${compressed_data_image%*.lz4}\n        extract_image \"${compressed_data_image}\" \"${data_image}\"\n    else\n        # Missing data image is fine. This variant may not be a split build.\n        readonly data_image=\n    fi\n\n    if [[ -n ${os_image_size} ]]; then\n        truncate --no-create --size \"${os_image_size}\" \"${os_image}\" \\\n            || bail \"Failed to resize OS image '${os_image}'.\"\n    fi\n\n    if [[ -n ${data_image_size} ]]; then\n        if [[ -e ${data_image} ]]; then\n            truncate --no-create --size \"${data_image_size}\" \"${data_image}\" \\\n                || bail \"Failed to resize data image '${data_image}'.\"\n        else\n            >&2 echo \"Ignoring option --data-image-size ${data_image_size} since no data image was found.\"\n        fi\n    fi\n}\n\nprepare_firmware() {\n    # Create local copies of the edk2 firmware variable storage, to help with\n    # facilitate Secure Boot testing where custom variables are needed for both\n    # architectures, but can't safely be reused across QEMU invocations. Also\n    # set reasonable defaults for both firmware files, if nothing more specific\n    # was requested.\n    local original_vars\n\n    if [[ ${arch} = x86_64 ]]; then\n        firmware_code=${firmware_code:-/usr/share/edk2/ovmf/OVMF_CODE.fd}\n        original_vars=${firmware_vars:-/usr/share/edk2/ovmf/OVMF_VARS.fd}\n        firmware_vars=\"$(mktemp)\"\n        on_exit \"rm '${firmware_vars}'\"\n        cp \"${original_vars}\" \"${firmware_vars}\"\n    fi\n\n    if [[ ${arch} = aarch64 ]]; then\n        original_code=${firmware_code:-/usr/share/edk2/aarch64/QEMU_EFI.silent.fd}\n        original_vars=${firmware_vars:-/usr/share/edk2/aarch64/QEMU_VARS.fd}\n        firmware_code=\"$(mktemp)\"\n        firmware_vars=\"$(mktemp)\"\n        on_exit \"rm '${firmware_code}' '${firmware_vars}'\"\n        cat \"${original_code}\" /dev/zero \\\n            | head -c 64m > \"${firmware_code}\"\n        cat \"${original_vars}\" /dev/zero \\\n            | head -c 64m > \"${firmware_vars}\"\n    fi\n}\n\ncreate_extra_files() {\n    # Explicitly instruct the kernel to send its output to the serial port on\n    # x86 via a bootconfig initrd. Passing in settings via user-data would be\n    # too late to get console output of the first boot.\n    if [[ ${arch} = x86_64 ]]; then\n        extra_files[\"${repo_root}/tools/bootconfig/qemu-x86-console-bootconfig.data\"]=bootconfig.data\n    fi\n\n    # If the private partition needs to be recreated, ensure that any bootconfig\n    # data file is present, otherwise GRUB will notice the missing file and wait\n    # for a key press.\n    if [[ ${#extra_files[@]} -gt 0 ]]; then\n        local has_bootconfig=no\n        for image_file in \"${extra_files[@]}\"; do\n            if [[ ${image_file} = bootconfig.data ]]; then\n                has_bootconfig=yes\n                break\n            fi\n        done\n        if [[ ${has_bootconfig} = no ]]; then\n            extra_files[\"${repo_root}/tools/bootconfig/empty-bootconfig.data\"]=bootconfig.data\n        fi\n    fi\n}\n\ninject_files() {\n    if [[ ${#extra_files[@]} -eq 0 ]]; then\n        return 0\n    fi\n\n    # We inject files into the boot image by replacing the private partition\n    # entirely. The new partition has to perfectly fit over the original one.\n    # Find the first and last sector, then calculate the partition's size. In\n    # absence of actual hardware, assume a traditional sector size of 512 bytes.\n    local private_first_sector private_last_sector\n    read -r private_first_sector private_last_sector < <(\n        fdisk --list-details \"${os_image}\" \\\n            | awk '/BOTTLEROCKET-PRIVATE/ { print $2, $3 }')\n    if [[ -z ${private_first_sector} ]] || [[ -z ${private_last_sector} ]]; then\n        bail \"Failed to find the private partition in '${os_image}'.\"\n    fi\n    local private_size_mib=$(( (private_last_sector - private_first_sector + 1) * 512 / 1024 / 1024 ))\n\n    local private_mount private_image\n    private_mount=$(mktemp -d)\n    private_image=$(mktemp)\n    on_exit \"rm -rf '${private_mount}' '${private_image}'\"\n\n    for local_file in \"${!extra_files[@]}\"; do\n        local image_file=${extra_files[${local_file}]}\n        cp \"${local_file}\" \"${private_mount}/${image_file}\"\n    done\n\n    if ! mkfs.ext4 -d \"${private_mount}\" \"${private_image}\" \"${private_size_mib}M\" \\\n    || ! dd if=\"${private_image}\" of=\"${os_image}\" conv=notrunc bs=512 seek=\"${private_first_sector}\"\n    then\n        rm -f \"${private_image}\"\n        rm -rf \"${private_mount}\"\n        bail \"Failed to inject files into '${os_image}'.\"\n    fi\n}\n\nlaunch_vm() {\n    local -a qemu_args=(\n        -nographic\n        -enable-kvm\n        -cpu host\n        -smp \"${vm_cpus}\"\n        -m \"${vm_mem}\"\n        -drive if=pflash,format=raw,unit=0,file=\"${firmware_code}\",readonly=on\n        -drive if=pflash,format=raw,unit=1,file=\"${firmware_vars}\"\n        -drive index=0,if=virtio,format=raw,file=\"${os_image}\"\n    )\n\n    # Plug the virtual primary NIC in as BDF 00:10.0 so udev will give it a\n    # consistent name we can know ahead of time--enp0s16 or ens16.\n    qemu_args+=(\n        -netdev user,id=net0,hostfwd=\"${host_port_forwards}\"\n        -device virtio-net-pci,netdev=net0,addr=10.0\n    )\n\n    # Resolve the last bit of uncertainty by disabling ACPI-based PCI hot plug,\n    # causing udev to use the bus location when naming the NIC (enp0s16). Since\n    # QEMU does not support PCI hot plug via ACPI on Arm, turn it off for the\n    # emulated x86_64 chipset only to achieve parity.\n    if [[ ${arch} = x86_64 ]]; then\n        qemu_args+=( -global PIIX4_PM.acpi-root-pci-hotplug=off )\n        qemu_args+=( -machine q35,smm=on )\n    fi\n\n    if [[ ${arch} = aarch64 ]]; then\n        qemu_args+=( -machine virt )\n    fi\n\n    if [[ -n ${data_image} ]]; then\n        qemu_args+=( -drive index=1,if=virtio,format=raw,file=\"${data_image}\" )\n    fi\n\n    qemu-system-\"${arch}\" \"${qemu_args[@]}\"\n}\n\nparse_args \"$@\"\nprepare_raw_images\nprepare_firmware\ncreate_extra_files\ninject_files\nlaunch_vm\n"
  },
  {
    "path": "variants/README.md",
    "content": "# Bottlerocket Variants\n\nThis document describes what Bottlerocket variants are and how they are built.\n\nIn the [Background](#background) section, we discuss the motivation for variants.\n\nIn the [Variants](#variants) section, we list the variants that exist today.\n\nIn the [Development](#development) section, we provide a short guide for adding a new variant.\n\n## Background\n\nBottlerocket is purpose-built for hosting containers.\nIt can run one of several container orchestrator agents.\nIt is also image-based and does not include a package manager for customization at runtime.\n\nConceptually, each image could include all orchestrator agents, but that would conflict with our design goals.\nWe want to keep the footprint of Bottlerocket as small as possible for security and performance reasons.\nInstead, we make different variants available for use, each with its own set of software and API settings.\n\nA variant is essentially a list of packages to install, plus a model that defines the API.\nThe documentation for [packages](https://github.com/bottlerocket-os/bottlerocket-core-kit/tree/develop/packages) covers how to create a package.\nInformation about API settings for variants can be found in the [models](../sources/models/) documentation.\n\n### User data\nBottlerocket variants ingest TOML-formatted [user data](../README.md#using-user-data) from various sources in a predefined order.\nAll variants first attempt to read user data from `/var/lib/bottlerocket/user-data.toml`.\nAWS variants then retrieve user data from IMDS.\nVMware variants will attempt to read user data from a mounted CD-ROM (from a file named \"user-data\" or from an OVF file), and then from VMware's guestinfo interface.\n\nIf a setting is defined in more than one source, the value in later sources will override earlier values.\nFor example, in a VMware variant, settings read from the guestinfo interface will override settings from CD-ROM, and settings from CD-ROM will override settings from the file.\n\n## Variants\n\nSee [_Update Policy_ in the Security Features document](../SECURITY_FEATURES.md#update-policy) for information on when and how Bottlerocket applies security patches to variants.\n\n### aws-k8s-1.29: Kubernetes 1.29 node\n\nThe [aws-k8s-1.29](aws-k8s-1.29/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.29, 1.30, 1.31, and 1.32 clusters.\n\n### aws-k8s-1.29-nvidia: Kubernetes 1.29 NVIDIA node\n\nThe [aws-k8s-1.29-nvidia](aws-k8s-1.29-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.29, 1.30, 1.31 and 1.32 clusters.\n\n### aws-k8s-1.29-nvidia-fips: Kubernetes 1.29 NVIDIA FIPS node\n\nThe [aws-k8s-1.29-nvidia-fips](aws-k8s-1.29-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.29, 1.30, 1.31 and 1.32 clusters.\n\n### aws-k8s-1.30: Kubernetes 1.30 node\n\nThe [aws-k8s-1.30](aws-k8s-1.30/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.30, 1.31, 1.32, and 1.33 clusters.\n\n### aws-k8s-1.30-nvidia: Kubernetes 1.30 NVIDIA node\n\nThe [aws-k8s-1.30-nvidia](aws-k8s-1.30-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.30, 1.31, 1.32, and 1.33 clusters.\n\n### aws-k8s-1.30-nvidia-fips: Kubernetes 1.30 NVIDIA FIPS node\n\nThe [aws-k8s-1.30-nvidia-fips](aws-k8s-1.30-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.30, 1.31, 1.32, and 1.33 clusters.\n\n### aws-k8s-1.31: Kubernetes 1.31 node\n\nThe [aws-k8s-1.31](aws-k8s-1.31/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.31, 1.32, 1.33, and 1.34 clusters.\n\n### aws-k8s-1.31-nvidia: Kubernetes 1.31 NVIDIA node\n\nThe [aws-k8s-1.31-nvidia](aws-k8s-1.31-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.31, 1.32, 1.33, and 1.34 clusters.\n\n### aws-k8s-1.31-nvidia-fips: Kubernetes 1.31 NVIDIA FIPS node\n\nThe [aws-k8s-1.31-nvidia-fips](aws-k8s-1.31-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.31, 1.32, 1.33, and 1.34 clusters.\n\n### aws-k8s-1.32: Kubernetes 1.32 node\n\nThe [aws-k8s-1.32](aws-k8s-1.32/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.32, 1.33, 1.34 and 1.35 clusters.\n\n### aws-k8s-1.32-nvidia: Kubernetes 1.32 NVIDIA node\n\nThe [aws-k8s-1.32-nvidia](aws-k8s-1.32-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.32, 1.33, 1.34 and 1.35 clusters.\n\n### aws-k8s-1.32-nvidia-fips: Kubernetes 1.32 NVIDIA FIPS node\n\nThe [aws-k8s-1.32-nvidia-fips](aws-k8s-1.32-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.32, 1.33, 1.34 and 1.35 clusters.\n\n### aws-k8s-1.33: Kubernetes 1.33 node\n\nThe [aws-k8s-1.33](aws-k8s-1.33/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.33, 1.34, 1.35 and 1.36 clusters.\n\n### aws-k8s-1.33-nvidia: Kubernetes 1.33 NVIDIA node\n\nThe [aws-k8s-1.33-nvidia](aws-k8s-1.33-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.33, 1.34, 1.35 and 1.36 clusters.\n\n### aws-k8s-1.33-nvidia-fips: Kubernetes 1.33 NVIDIA FIPS node\n\nThe [aws-k8s-1.33-nvidia-fips](aws-k8s-1.33-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.33, 1.34, 1.35 and 1.36 clusters.\n\n### aws-k8s-1.34: Kubernetes 1.34 node\n\nThe [aws-k8s-1.34](aws-k8s-1.34/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.34, 1.35, 1.36 and 1.37 clusters.\n\n### aws-k8s-1.34-nvidia: Kubernetes 1.34 NVIDIA node\n\nThe [aws-k8s-1.34-nvidia](aws-k8s-1.34-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.34, 1.35, 1.36 and 1.37 clusters.\n\n### aws-k8s-1.34-nvidia-fips: Kubernetes 1.34 NVIDIA FIPS node\n\nThe [aws-k8s-1.34-nvidia-fips](aws-k8s-1.34-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.34, 1.35, 1.36 and 1.37 clusters.\n\n### aws-k8s-1.35: Kubernetes 1.35 node\n\nThe [aws-k8s-1.35](aws-k8s-1.35/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.35, 1.36, 1.37 and 1.38 clusters.\n\n### aws-k8s-1.35-nvidia: Kubernetes 1.35 NVIDIA node\n\nThe [aws-k8s-1.35-nvidia](aws-k8s-1.35-nvidia/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.35, 1.36, 1.37 and 1.38 clusters.\n\n### aws-k8s-1.35-nvidia-fips: Kubernetes 1.35 NVIDIA FIPS node\n\nThe [aws-k8s-1.35-nvidia-fips](aws-k8s-1.35-nvidia-fips/Cargo.toml) variant includes the packages needed to run a Kubernetes node in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\nIt supports self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant is compatible with Kubernetes 1.35, 1.36, 1.37 and 1.38 clusters.\n\n### aws-ecs-2: Amazon ECS container instance\n\nThe [aws-ecs-2](aws-ecs-2/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\n\n### aws-ecs-2-nvidia: Amazon ECS container instance\n\nThe [aws-ecs-2-nvidia](aws-ecs-2-nvidia/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\n\n### aws-ecs-2-nvidia-fips: Amazon ECS container instance\n\nThe [aws-ecs-2-nvidia-fips](aws-ecs-2-nvidia-fips/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\n\n### aws-ecs-3: Amazon ECS container instance\n\nThe [aws-ecs-3](aws-ecs-3/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\n\n### aws-ecs-3-fips: Amazon ECS container instance with FIPS\n\nThe [aws-ecs-3-fips](aws-ecs-3-fips/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\nIt also is FIPS-enabled.\n\n### aws-ecs-3-nvidia: Amazon ECS container instance with NVIDIA\n\nThe [aws-ecs-3-nvidia](aws-ecs-3-nvidia/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs.\n\n### aws-ecs-3-nvidia-fips: Amazon ECS container instance with NVIDIA and FIPS\n\nThe [aws-ecs-3-nvidia-fips](aws-ecs-3-nvidia-fips/Cargo.toml) variant includes the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\nIt also includes the required packages to configure containers to leverage NVIDIA GPUs and is FIPS-enabled.\n\n### aws-dev: AWS development build\n\nThe [aws-dev](aws-dev/Cargo.toml) variant has useful packages for local development of the OS.\nIt includes tools for troubleshooting as well as Docker for running containers.\nUser data will be read from IMDS.\n\n### vmware-dev: VMware development build\n\nThe [vmware-dev](vmware-dev/Cargo.toml) variant has useful packages for local development of the OS, and is intended to run as a VMware guest.\nIt includes tools for troubleshooting as well as Docker for running containers.\n\n## vmware-k8s-1.29: VMware Kubernetes 1.29 node\n\nThe [vmware-k8s-1.29](vmware-k8s-1.29/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.29, 1.30, 1.31, and 1.32 clusters.\n\n## vmware-k8s-1.30: VMware Kubernetes 1.30 node\n\nThe [vmware-k8s-1.30](vmware-k8s-1.30/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.30, 1.31, 1.32, and 1.33 clusters.\n\n## vmware-k8s-1.31: VMware Kubernetes 1.31 node\n\nThe [vmware-k8s-1.31](vmware-k8s-1.31/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.31, 1.32, 1.33, and 1.34 clusters.\n\n## vmware-k8s-1.32: VMware Kubernetes 1.32 node\n\nThe [vmware-k8s-1.32](vmware-k8s-1.32/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.32, 1.33, 1.34, and 1.35 clusters.\n\n## vmware-k8s-1.33: VMware Kubernetes 1.33 node\n\nThe [vmware-k8s-1.33](vmware-k8s-1.33/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.33, 1.34, 1.35, and 1.36 clusters.\n\n## vmware-k8s-1.34: VMware Kubernetes 1.34 node\n\nThe [vmware-k8s-1.34](vmware-k8s-1.34/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.34, 1.35, 1.36, and 1.37 clusters.\n\n## vmware-k8s-1.35: VMware Kubernetes 1.35 node\n\nThe [vmware-k8s-1.35](vmware-k8s-1.35/Cargo.toml) variant includes the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supports self-hosted clusters.\n\nThis variant is compatible with Kubernetes 1.35, 1.36, 1.37, and 1.38 clusters.\n\n### metal-dev: Metal development build\n\nThe [metal-dev](metal-dev/Cargo.toml) variant has useful packages for local development of the OS and is intended to run bare metal.\nIt includes tools for troubleshooting as well as Docker for running containers.\n\n\n### Deprecated variants\n\n#### aws-k8s-1.15: Kubernetes 1.15 node\n\nThe aws-k8s-1.15 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.15, 1.16, and 1.17 clusters.\nIt reached end-of-life on May 3, 2021.\n\nUpstream support for Kubernetes 1.15 has ended and this variant will no longer be supported in Bottlerocket releases.\n\n### aws-k8s-1.16: Kubernetes 1.16 node\n\nThe aws-k8s-1.16 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.16, 1.17, and 1.18 clusters.\nIt reached end-of-life on July 25, 2021.\n\nUpstream support for Kubernetes 1.16 has ended and this variant will no longer be supported in Bottlerocket releases.\n\n### aws-k8s-1.17: Kubernetes 1.17 node\n\nThe aws-k8s-1.17 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.17, 1.18, and 1.19 clusters.\nIt reached end-of-life on November 2, 2021.\n\nUpstream support for Kubernetes 1.17 has ended and this variant will no longer be supported in Bottlerocket releases.\n\n### aws-k8s-1.18: Kubernetes 1.18 node\n\nThe aws-k8s-1.18 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.18, 1.19, and 1.20 clusters.\nIt reached end-of-life on March 31st, 2022.\n\nUpstream support for Kubernetes 1.18 has ended and this variant will no longer be supported in Bottlerocket releases.\n\n### aws-k8s-1.19: Kubernetes 1.19 node\n\nThe aws-k8s-1.19 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.19, 1.20, and 1.21 clusters.\nIt reached end-of-life on August 1st, 2022.\n\nUpstream support for Kubernetes 1.19 has ended and this variant will no longer be supported in Bottlerocket releases.\n\n### aws-k8s-1.20: Kubernetes 1.20 node\n\nThe aws-k8s-1.20 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.20, 1.21, and 1.22 clusters.\nIt reached end-of-life on November 1st, 2022.\n\nUpstream support for Kubernetes 1.20 has ended and this variant will no longer be supported in Bottlerocket releases.\n\n### vmware-k8s-1.20: VMware Kubernetes 1.20 node\n\nThe vmware-k8s-1.20 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.20, 1.21, and 1.22 clusters.\n\n### aws-k8s-1.21: Kubernetes 1.21 node\n\nThe aws-k8s-1.21 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.21, 1.22, and 1.23 clusters.\n\n### aws-k8s-1.21-nvidia: Kubernetes 1.21 NVIDIA node\n\nThe aws-k8s-1.21-nvidia variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\nThis variant was compatible with Kubernetes 1.21, 1.22, and 1.23 clusters.\n\n### metal-k8s-1.21: Metal Kubernetes 1.21 node\n\nThe metal-k8s-1.21 variant included the packages needed to run a Kubernetes node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.21, 1.22, and 1.23 clusters.\n\n### vmware-k8s-1.21: VMware Kubernetes 1.21 node\n\nThe vmware-k8s-1.21 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.21, 1.22, and 1.23 clusters.\n\n### aws-k8s-1.22: Kubernetes 1.22 node\n\nThe aws-k8s-1.22 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.22, 1.23, and 1.24 clusters.\n\n### aws-k8s-1.22-nvidia: Kubernetes 1.22 NVIDIA node\n\nThe aws-k8s-1.22-nvidia variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.22, 1.23, and 1.24 clusters.\n\n### metal-k8s-1.22: Metal Kubernetes 1.22 node\n\nThe metal-k8s-1.22 variant included the packages needed to run a Kubernetes node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.22, 1.23, and 1.24 clusters.\n\n### vmware-k8s-1.22: VMware Kubernetes 1.22 node\n\nThe vmware-k8s-1.22 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.22, 1.23, and 1.24 clusters.\n\n### aws-k8s-1.23: Kubernetes 1.23 node\n\nThe [aws-k8s-1.23](aws-k8s-1.23/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.23, 1.24, and 1.25 clusters.\n\n### aws-k8s-1.23-nvidia: Kubernetes 1.23 NVIDIA node\n\nThe [aws-k8s-1.23-nvidia](aws-k8s-1.23-nvidia/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.23, 1.24, and 1.25 clusters.\n\n### metal-k8s-1.23: Metal Kubernetes 1.23 node\n\nThe metal-k8s-1.23 variant included the packages needed to run a Kubernetes worker node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.23, 1.24, and 1.25 clusters.\n\n### vmware-k8s-1.23: VMware Kubernetes 1.23 node\n\nThe vmware-k8s-1.23 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.23, 1.24, and 1.25 clusters.\n\n### vmware-k8s-1.24: VMware Kubernetes 1.24 node\n\nThe vmware-k8s-1.24 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.24, 1.25, and 1.26 clusters.\n\n### aws-k8s-1.24: Kubernetes 1.24 node\n\nThe [aws-k8s-1.24](aws-k8s-1.24/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.24, 1.25, and 1.26 clusters.\n\n### aws-k8s-1.24-nvidia: Kubernetes 1.24 NVIDIA node\n\nThe [aws-k8s-1.24-nvidia](aws-k8s-1.24-nvidia/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.24, 1.25, and 1.26 clusters.\n\n### metal-k8s-1.24: Metal Kubernetes 1.24 node\n\nThe metal-k8s-1.24 variant included the packages needed to run a Kubernetes node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.24, 1.25, and 1.26 clusters.\n\n### vmware-k8s-1.25: VMware Kubernetes 1.25 node\n\nThe [vmware-k8s-1.25](vmware-k8s-1.25/Cargo.toml) variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.25, 1.26, 1.27, and 1.28 clusters.\n\n### aws-k8s-1.25: Kubernetes 1.25 node\n\nThe [aws-k8s-1.25](aws-k8s-1.25/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.25, 1.26, 1.27, and 1.28 clusters.\n\n### aws-k8s-1.25-nvidia: Kubernetes 1.25 NVIDIA node\n\nThe [aws-k8s-1.25-nvidia](aws-k8s-1.25-nvidia/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.25, 1.26, 1.27, and 1.28 clusters.\n\n### metal-k8s-1.25: Metal Kubernetes 1.25 node\n\nThe [metal-k8s-1.25](metal-k8s-1.25/Cargo.toml) variant included the packages needed to run a Kubernetes node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.25, 1.26, 1.27, and 1.28 clusters.\n\n### vmware-k8s-1.26: VMware Kubernetes 1.26 node\n\nThe vmware-k8s-1.26 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.26, 1.27, 1.28, and 1.29 clusters.\n\n### aws-k8s-1.26: Kubernetes 1.26 node\n\nThe [aws-k8s-1.26](aws-k8s-1.26/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.26, 1.27, 1.28, and 1.29 clusters.\n\n### aws-k8s-1.26-nvidia: Kubernetes 1.26 NVIDIA node\n\nThe [aws-k8s-1.26-nvidia](aws-k8s-1.26-nvidia/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.26, 1.27, 1.28, and 1.29 clusters.\n\n### metal-k8s-1.26: Metal Kubernetes 1.26 node\n\nThe metal-k8s-1.26 variant included the packages needed to run a Kubernetes node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.26, 1.27, 1.28, and 1.29 clusters.\n\n## vmware-k8s-1.27: VMware Kubernetes 1.27 node\n\nThe [vmware-k8s-1.27](vmware-k8s-1.27/Cargo.toml) variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.27, 1.28, 1.29, and 1.30 clusters.\n\n### aws-k8s-1.27: Kubernetes 1.27 node\n\nThe [aws-k8s-1.27](aws-k8s-1.27/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.27, 1.28, 1.29, and 1.30 clusters.\n\n### aws-k8s-1.27-nvidia: Kubernetes 1.27 NVIDIA node\n\nThe [aws-k8s-1.27-nvidia](aws-k8s-1.27-nvidia/Cargo.toml) variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.27, 1.28, 1.29, and 1.30 clusters.\n\n### metal-k8s-1.27: Metal Kubernetes 1.27 node\n\nThe [metal-k8s-1.27](metal-k8s-1.27/Cargo.toml) variant included the packages needed to run a Kubernetes node on bare metal.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.27, 1.28, 1.29, and 1.30 clusters.\n\n### metal-k8s-1.28: Metal Kubernetes 1.28 node\n\nThe [metal-k8s-1.28](metal-k8s-1.28/Cargo.toml) variant included the packages needed to run a Kubernetes node on bare metal.\nIt supports self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.28, 1.29, 1.30, and 1.31 clusters.\n\n### metal-k8s-1.29: Metal Kubernetes 1.29 node\n\nThe [metal-k8s-1.29](metal-k8s-1.29/Cargo.toml) variant included the packages needed to run a Kubernetes node on bare metal.\nIt supports self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.29, 1.30, 1.31, and 1.32 clusters.\n\n### aws-ecs-1: Amazon ECS container instance\n\nThe [aws-ecs-1](aws-ecs-1/Cargo.toml) variant included the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\n\n### aws-ecs-1-nvidia: Amazon ECS container instance\n\nThe [aws-ecs-1-nvidia](aws-ecs-1-nvidia/Cargo.toml) variant included the packages needed to run an [Amazon ECS](https://ecs.aws)\ncontainer instance in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\n\n### aws-k8s-1.28: Kubernetes 1.28 node\n\nThe aws-k8s-1.28 variant included the packages needed to run a Kubernetes node in AWS.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.28, 1.29, 1.30, and 1.31 clusters.\n\n### aws-k8s-1.28-nvidia: Kubernetes 1.28 NVIDIA node\n\nThe aws-k8s-1.28-nvidia variant included the packages needed to run a Kubernetes node in AWS.\nIt also included the required packages to configure containers to leverage NVIDIA GPUs.\nIt supported self-hosted clusters and clusters managed by [EKS](https://aws.amazon.com/eks/).\n\nThis variant was compatible with Kubernetes 1.28, 1.29, 1.30, and 1.31 clusters.\n\n## vmware-k8s-1.28: VMware Kubernetes 1.28 node\n\nThe vmware-k8s-1.28 variant included the packages needed to run a Kubernetes worker node as a VMware guest.\nIt supported self-hosted clusters.\n\nThis variant was compatible with Kubernetes 1.28, 1.29, 1.30, and 1.31 clusters.\n\n## Development\n\nSay we want to create `my-variant`, a custom build of Bottlerocket that runs `my-agent`.\n\n### Structure\nThis listing shows the directory structure of our sample variant.\n\n```\nvariants/my-variant\n└── Cargo.toml\n```\n\nEach variant has a `Cargo.toml` file that lists the packages to install.\n\nIt also refers to a `build.rs` [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) which tells Cargo to invoke our [buildsys](../tools/buildsys/) tool.\nArtifacts for the variant are built as a side effect of Cargo running the script.\n\nIt points to `/dev/null` for the actual crate, since Cargo expects some Rust code to build, and is happy with an empty file.\n\n### Cargo.toml\n\nOur sample variant has the following manifest.\n\n```toml\n[package]\nname = \"my-variant\"\nversion = \"0.1.0\"\nedition = \"2018\"\npublish = false\nbuild = \"../build.rs\"\n\n[package.metadata.build-variant]\nincluded-packages = [\n    \"release\",\n    \"my-agent\",\n]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 8\ndata-image-size-gib = 20\npartition-plan = \"unified\"\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\n\"my-agent\" = { path = \"../../packages/my-agent\" }\n\"release\" = { path = \"../../packages/release\" }\n```\n\nThe [package.metadata](https://doc.rust-lang.org/cargo/reference/manifest.html#the-metadata-table-optional) table is ignored by Cargo and interpreted by our `buildsys` tool.\n\nIt contains an `included-packages` list which specifies the packages to install when building the image.\nIn the `[build-dependencies]` section, we specify the packages that need to be built, which is sometimes slightly different than `included-packages`.\nThis populates the Cargo build graph with all of the RPM packages that need to be built before the variant can be constructed.\nVariants should almost always include the `release` package.\nThis pulls in the other core packages and includes essential configuration and services.\n\nThis variant includes the (optional) `image-layout` section, which allows the user to customize the layout of the image they are building.\n`os-image-size-gib` is the size of the \"OS\" disk image in GiB.\n`data-image-size-gib` is the size of the \"data\" disk image in GiB.\nThough we've done so here for sake of demonstration, resizing the \"data\" disk image isn't necessary as it expands to fill the disk on boot.\n`partition-plan` is the strategy used for image partitioning, with the options being \"split\" (the default) or \"unified\".\nThe \"split\" partition strategy has separate volumes for \"OS\" and \"data\", while \"unified\" has \"OS\" and \"data\" on a single volume.\nSee [the documentation](../tools/buildsys/src/manifest.rs) for the defaults and additional details.\n\nBe sure to include `publish = false` for all packages, as these are not standard crates and should never appear on [crates.io](https://crates.io/).\n\n### build.rs\n\nWe reuse the same build script for all variants.\n\n```rust\nuse std::process::{exit, Command};\n\nfn main() -> Result<(), std::io::Error> {\n    let ret = Command::new(\"buildsys\").arg(\"build-variant\").status()?;\n    if !ret.success() {\n        exit(1);\n    }\n    Ok(())\n}\n```\n\nIf you need a build script with different behavior, the recommended approach is to modify the `buildsys` tool.\nThe `package.metadata` table can be extended with declarative elements that enable the new feature.\n\n### Next Steps\n\nTo build your variant, run the following command in the top-level Bottlerocket directory.\n```shell\ncargo make -e BUILDSYS_VARIANT=my-variant\n```\n\nThis will build all packages first, not just the ones needed by your variant.\n"
  },
  {
    "path": "variants/aws-dev/Cargo.toml",
    "content": "[package]\nname = \"aws-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nxfs-data-partition = true\nuefi-secure-boot = true\nsystemd-networkd = true\nerofs-root-partition = true\nexternal-kmod-development = false\nencrypted-storage = true\n\n[package.metadata.build-variant]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# docker\n    \"docker-cli-29\",\n    \"docker-engine-29\",\n    \"docker-init\",\n# tools\n    \"login\",\n    \"iputils\",\n    \"strace\",\n    \"chrony-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-2/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-2\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# docker\n    \"docker-cli\",\n    \"docker-engine\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-config\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-2-fips/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-2-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# docker\n    \"docker-cli\",\n    \"docker-engine\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-config\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-2-nvidia/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-2-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# docker\n    \"docker-cli\",\n    \"docker-engine\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-nvidia-config\",\n# NVIDIA support\n    \"ecs-gpu-init\",\n    \"nvidia-container-toolkit-ecs\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\n\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-2-nvidia-fips/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-2-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# docker\n    \"docker-cli\",\n    \"docker-engine\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-nvidia-config\",\n# NVIDIA support\n    \"ecs-gpu-init\",\n    \"nvidia-container-toolkit-ecs\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\n\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-3/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-3\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nsystemd-networkd = true\nerofs-root-partition = true\nexternal-kmod-development = false\nencrypted-storage = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# docker\n    \"docker-cli-29\",\n    \"docker-engine-29\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-config\",\n    \"aws-signer-notation-plugin\",\n    \"notation-image-verifier\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-3/amispec.toml",
    "content": "description = \"This variant is in preview. It contains the newly released Docker v29.0.0 along with features related to image verification and encrypted storage.\"\n\n# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html\nimds-support = \"v2.0\"\n\n# Override the pubsys \"gp2\" default\n[block-device-mappings.\"/dev/xvda\".ebs]\nvolume-type = \"gp3\"\n\n[block-device-mappings.\"/dev/xvdb\".ebs]\nvolume-type = \"gp3\"\n"
  },
  {
    "path": "variants/aws-ecs-3-fips/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-3-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nsystemd-networkd = true\nerofs-root-partition = true\nexternal-kmod-development = false\nencrypted-storage = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# docker\n    \"docker-cli-29\",\n    \"docker-engine-29\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-config\",\n    \"aws-signer-notation-plugin\",\n    \"notation-image-verifier\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-3-fips/amispec.toml",
    "content": "description = \"This variant is in preview. It contains the newly released Docker v29.0.0 along with features related to image verification and encrypted storage.\"\n\n# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html\nimds-support = \"v2.0\"\n\n# Override the pubsys \"gp2\" default\n[block-device-mappings.\"/dev/xvda\".ebs]\nvolume-type = \"gp3\"\n\n[block-device-mappings.\"/dev/xvdb\".ebs]\nvolume-type = \"gp3\"\n"
  },
  {
    "path": "variants/aws-ecs-3-nvidia/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-3-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nsystemd-networkd = true\nerofs-root-partition = true\nexternal-kmod-development = false\nencrypted-storage = true\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# docker\n    \"docker-cli-29\",\n    \"docker-engine-29\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-nvidia-config\",\n    \"aws-signer-notation-plugin\",\n    \"notation-image-verifier\",\n# NVIDIA support\n    \"ecs-gpu-init\",\n    \"nvidia-container-toolkit-ecs\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\n\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-3-nvidia/amispec.toml",
    "content": "description = \"This variant is in preview. It contains the newly released Docker v29.0.0 along with features related to image verification and encrypted storage.\"\n\n# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html\nimds-support = \"v2.0\"\n\n# Override the pubsys \"gp2\" default\n[block-device-mappings.\"/dev/xvda\".ebs]\nvolume-type = \"gp3\"\n\n[block-device-mappings.\"/dev/xvdb\".ebs]\nvolume-type = \"gp3\"\n"
  },
  {
    "path": "variants/aws-ecs-3-nvidia-fips/Cargo.toml",
    "content": "[package]\nname = \"aws-ecs-3-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nsystemd-networkd = true\nerofs-root-partition = true\nexternal-kmod-development = false\nencrypted-storage = true\nfips = true\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# docker\n    \"docker-cli-29\",\n    \"docker-engine-29\",\n    \"docker-init\",\n# ecs\n    \"ecs-agent-nvidia-config\",\n    \"aws-signer-notation-plugin\",\n    \"notation-image-verifier\",\n# NVIDIA support\n    \"ecs-gpu-init\",\n    \"nvidia-container-toolkit-ecs\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\n\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-ecs-3-nvidia-fips/amispec.toml",
    "content": "description = \"This variant is in preview. It contains the newly released Docker v29.0.0 along with features related to image verification and encrypted storage.\"\n\n# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html\nimds-support = \"v2.0\"\n\n# Override the pubsys \"gp2\" default\n[block-device-mappings.\"/dev/xvda\".ebs]\nvolume-type = \"gp3\"\n\n[block-device-mappings.\"/dev/xvdb\".ebs]\nvolume-type = \"gp3\"\n"
  },
  {
    "path": "variants/aws-k8s-1.29/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.29 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_29\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.29\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.29-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.29-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_29-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.29\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.29-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.29-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_29-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.29\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.29-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.29-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_29-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.29\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.30/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.30 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_30\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.30\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.30-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.30-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_30-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.30\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.30-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.30-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_30-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.30\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.30-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.30-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_30-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.30\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.31/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.31 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_31\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.31\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.31-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.31-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_31-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.31\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.31-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.31-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_31-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.31\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.31-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.31-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_31-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.31\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.32/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.32 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_32\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.32\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.32-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.32-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_32-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.32\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.32-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.32-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_32-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.32\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.32-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.32-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_32-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.32\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.1-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.33/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.33 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_33\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.33\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.33-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.33-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_33-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"containerd-2.1\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.33\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.33-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.33-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_33-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.33\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.33-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.33-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_33-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.33\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.34/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.34 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_34\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.34\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.34-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.34-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_34-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.34\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.34-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.34-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_34-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.34\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.34-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.34-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_34-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.34\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.35/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.35 variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_35\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release-swap\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.35\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.35-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.35-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_35-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n# core\n    \"release-swap\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n# k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.35\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.35-nvidia/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.35-nvidia variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_35-nvidia\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release-swap\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.35\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/aws-k8s-1.35-nvidia-fips/Cargo.toml",
    "content": "[package]\n# This is the aws-k8s-1.35-nvidia-fips variant. \".\" is not allowed in crate names, but we\n# don't use this crate name anywhere.\nname = \"aws-k8s-1_35-nvidia-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\nos-image-size-gib = 4\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\nfips = true\n\n[package.metadata.build-variant]\nincluded-packages = [\n    # core\n    \"release-swap\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.35\",\n    \"aws-iam-authenticator\",\n    \"soci-snapshotter\",\n    # nvidia\n    \"nvidia-container-toolkit-k8s\",\n    \"nvidia-k8s-device-plugin\",\n    \"kmod-6.12-nvidia-r580-tesla\",\n]\nkernel-parameters = [\n    \"console=tty0\",\n    \"console=ttyS0,115200n8\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/build.rs",
    "content": "use std::process::{exit, Command};\n\nfn main() -> Result<(), std::io::Error> {\n    let ret = Command::new(\"buildsys\").arg(\"build-variant\").status()?;\n    if !ret.success() {\n        exit(1);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "variants/metal-dev/Cargo.toml",
    "content": "[package]\nname = \"metal-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nxfs-data-partition = true\nerofs-root-partition = true\nuefi-secure-boot = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nimage-format = \"raw\"\nkernel-parameters = [\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\"\n]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.1\",\n    \"linux-firmware\",\n    \"whippet\",\n# docker\n    \"docker-cli\",\n    \"docker-engine\",\n    \"docker-init\",\n# tools\n    \"login\",\n    \"iputils\",\n    \"strace\",\n    \"chrony-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/shared/amispec-split.toml",
    "content": "# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html\nimds-support = \"v2.0\"\n\n# Override the pubsys \"gp2\" default\n[block-device-mappings.\"/dev/xvda\".ebs]\nvolume-type = \"gp3\"\n\n[block-device-mappings.\"/dev/xvdb\".ebs]\nvolume-type = \"gp3\"\n"
  },
  {
    "path": "variants/shared/template-split-secboot.ovf",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<Envelope xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\">\n  <References>\n    <File ovf:id=\"file1\" ovf:href=\"{{OS_DISK}}\"/>\n    <File ovf:id=\"file2\" ovf:href=\"{{DATA_DISK}}\"/>\n  </References>\n  <DiskSection>\n    <Info>List of the virtual disks</Info>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk1\" ovf:capacity=\"{{OS_DISK_BYTES}}\" ovf:fileRef=\"file1\"/>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk2\" ovf:capacity=\"{{DATA_DISK_BYTES}}\" ovf:fileRef=\"file2\"/>\n  </DiskSection>\n  <NetworkSection>\n    <Info>The list of logical networks</Info>\n    <Network ovf:name=\"VM Network\">\n      <Description>The network</Description>\n    </Network>\n  </NetworkSection>\n  <VirtualSystem ovf:id=\"image\">\n    <Info>A Virtual machine</Info>\n    <OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other4xLinux64Guest\">\n      <Info>The operating system installed</Info>\n      <Description>Other 4.x or later Linux (64-bit)</Description>\n    </OperatingSystemSection>\n    <VirtualHardwareSection>\n      <Info>Virtual hardware requirements</Info>\n      <System>\n        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n        <vssd:InstanceID>0</vssd:InstanceID>\n        <vssd:VirtualSystemType>vmx-15</vssd:VirtualSystemType>\n      </System>\n      <Item>\n        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n        <rasd:Description>Number of Virtual CPUs</rasd:Description>\n        <rasd:ElementName>2 virtual CPU(s)</rasd:ElementName>\n        <rasd:InstanceID>1</rasd:InstanceID>\n        <rasd:ResourceType>3</rasd:ResourceType>\n        <rasd:VirtualQuantity>2</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n        <rasd:Description>Memory Size</rasd:Description>\n        <rasd:ElementName>8192MB of memory</rasd:ElementName>\n        <rasd:InstanceID>2</rasd:InstanceID>\n        <rasd:ResourceType>4</rasd:ResourceType>\n        <rasd:VirtualQuantity>8192</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:Address>0</rasd:Address>\n        <rasd:Description>NVMe Controller</rasd:Description>\n        <rasd:ElementName>NVMe Controller 1</rasd:ElementName>\n        <rasd:InstanceID>4</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.nvme.controller</rasd:ResourceSubType>\n        <rasd:ResourceType>20</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 1</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n        <rasd:InstanceID>6</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>1</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 2</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk2</rasd:HostResource>\n        <rasd:InstanceID>7</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:Connection>VM Network</rasd:Connection>\n        <rasd:ElementName>Network adapter 1</rasd:ElementName>\n        <rasd:InstanceID>9</rasd:InstanceID>\n        <rasd:ResourceSubType>VmxNet3</rasd:ResourceSubType>\n        <rasd:ResourceType>10</rasd:ResourceType>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"connectable.allowGuestControl\" vmw:value=\"true\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"wakeOnLanEnabled\" vmw:value=\"false\"/>\n      </Item>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"bootOptions.efiSecureBootEnabled\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"firmware\" vmw:value=\"efi\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"disk.enableUUID\" vmw:value=\"true\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.bootOrder\" vmw:value=\"hdd\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.hddOrder\" vmw:value=\"nvme0:1\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.PKDefault.value0\" vmw:value=\"{{PK_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.PKDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.KEKDefault.value0\" vmw:value=\"{{KEK_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.KEKDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbDefault.value0\" vmw:value=\"{{DB_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbxDefault.value0\" vmw:value=\"{{DBX_EMPTY_HASH_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbxDefault.append\" vmw:value=\"false\"/>\n    </VirtualHardwareSection>\n  </VirtualSystem>\n</Envelope>\n"
  },
  {
    "path": "variants/shared/template-split.ovf",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<Envelope xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\">\n  <References>\n    <File ovf:id=\"file1\" ovf:href=\"{{OS_DISK}}\"/>\n    <File ovf:id=\"file2\" ovf:href=\"{{DATA_DISK}}\"/>\n  </References>\n  <DiskSection>\n    <Info>List of the virtual disks</Info>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk1\" ovf:capacity=\"{{OS_DISK_BYTES}}\" ovf:fileRef=\"file1\"/>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk2\" ovf:capacity=\"{{DATA_DISK_BYTES}}\" ovf:fileRef=\"file2\"/>\n  </DiskSection>\n  <NetworkSection>\n    <Info>The list of logical networks</Info>\n    <Network ovf:name=\"VM Network\">\n      <Description>The network</Description>\n    </Network>\n  </NetworkSection>\n  <VirtualSystem ovf:id=\"image\">\n    <Info>A Virtual machine</Info>\n    <OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other4xLinux64Guest\">\n      <Info>The operating system installed</Info>\n      <Description>Other 4.x or later Linux (64-bit)</Description>\n    </OperatingSystemSection>\n    <VirtualHardwareSection>\n      <Info>Virtual hardware requirements</Info>\n      <System>\n        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n        <vssd:InstanceID>0</vssd:InstanceID>\n        <vssd:VirtualSystemType>vmx-15</vssd:VirtualSystemType>\n      </System>\n      <Item>\n        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n        <rasd:Description>Number of Virtual CPUs</rasd:Description>\n        <rasd:ElementName>2 virtual CPU(s)</rasd:ElementName>\n        <rasd:InstanceID>1</rasd:InstanceID>\n        <rasd:ResourceType>3</rasd:ResourceType>\n        <rasd:VirtualQuantity>2</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n        <rasd:Description>Memory Size</rasd:Description>\n        <rasd:ElementName>8192MB of memory</rasd:ElementName>\n        <rasd:InstanceID>2</rasd:InstanceID>\n        <rasd:ResourceType>4</rasd:ResourceType>\n        <rasd:VirtualQuantity>8192</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:Address>0</rasd:Address>\n        <rasd:Description>NVMe Controller</rasd:Description>\n        <rasd:ElementName>NVMe Controller 1</rasd:ElementName>\n        <rasd:InstanceID>4</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.nvme.controller</rasd:ResourceSubType>\n        <rasd:ResourceType>20</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 1</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n        <rasd:InstanceID>6</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>1</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 2</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk2</rasd:HostResource>\n        <rasd:InstanceID>7</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:Connection>VM Network</rasd:Connection>\n        <rasd:ElementName>Network adapter 1</rasd:ElementName>\n        <rasd:InstanceID>9</rasd:InstanceID>\n        <rasd:ResourceSubType>VmxNet3</rasd:ResourceSubType>\n        <rasd:ResourceType>10</rasd:ResourceType>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"connectable.allowGuestControl\" vmw:value=\"true\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"wakeOnLanEnabled\" vmw:value=\"false\"/>\n      </Item>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"bootOptions.efiSecureBootEnabled\" vmw:value=\"false\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"firmware\" vmw:value=\"bios\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"disk.enableUUID\" vmw:value=\"true\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.bootOrder\" vmw:value=\"hdd\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.hddOrder\" vmw:value=\"nvme0:1\"/>\n    </VirtualHardwareSection>\n  </VirtualSystem>\n</Envelope>\n"
  },
  {
    "path": "variants/shared/template-unified-secboot-tpm.ovf",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<Envelope xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\">\n  <References>\n    <File ovf:id=\"file1\" ovf:href=\"{{OS_DISK}}\"/>\n  </References>\n  <DiskSection>\n    <Info>List of the virtual disks</Info>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk1\" ovf:capacity=\"{{OS_DISK_BYTES}}\" ovf:fileRef=\"file1\"/>\n  </DiskSection>\n  <NetworkSection>\n    <Info>The list of logical networks</Info>\n    <Network ovf:name=\"VM Network\">\n      <Description>The network</Description>\n    </Network>\n  </NetworkSection>\n  <VirtualSystem ovf:id=\"image\">\n    <Info>A Virtual machine</Info>\n    <OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other4xLinux64Guest\">\n      <Info>The operating system installed</Info>\n      <Description>Other 4.x or later Linux (64-bit)</Description>\n    </OperatingSystemSection>\n    <VirtualHardwareSection>\n      <Info>Virtual hardware requirements</Info>\n      <System>\n        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n        <vssd:InstanceID>0</vssd:InstanceID>\n        <vssd:VirtualSystemType>vmx-15</vssd:VirtualSystemType>\n      </System>\n      <Item>\n        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n        <rasd:Description>Number of Virtual CPUs</rasd:Description>\n        <rasd:ElementName>2 virtual CPU(s)</rasd:ElementName>\n        <rasd:InstanceID>1</rasd:InstanceID>\n        <rasd:ResourceType>3</rasd:ResourceType>\n        <rasd:VirtualQuantity>2</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n        <rasd:Description>Memory Size</rasd:Description>\n        <rasd:ElementName>8192MB of memory</rasd:ElementName>\n        <rasd:InstanceID>2</rasd:InstanceID>\n        <rasd:ResourceType>4</rasd:ResourceType>\n        <rasd:VirtualQuantity>8192</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:Address>0</rasd:Address>\n        <rasd:Description>NVMe Controller</rasd:Description>\n        <rasd:ElementName>NVMe Controller 1</rasd:ElementName>\n        <rasd:InstanceID>4</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.nvme.controller</rasd:ResourceSubType>\n        <rasd:ResourceType>20</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 1</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n        <rasd:InstanceID>6</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:Connection>VM Network</rasd:Connection>\n        <rasd:ElementName>Network adapter 1</rasd:ElementName>\n        <rasd:InstanceID>9</rasd:InstanceID>\n        <rasd:ResourceSubType>VmxNet3</rasd:ResourceSubType>\n        <rasd:ResourceType>10</rasd:ResourceType>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"connectable.allowGuestControl\" vmw:value=\"true\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"wakeOnLanEnabled\" vmw:value=\"false\"/>\n      </Item>\n      <Item ovf:required=\"false\">\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:ElementName>Virtual TPM</rasd:ElementName>\n        <rasd:InstanceID>13</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.vtpm</rasd:ResourceSubType>\n        <rasd:ResourceType>1</rasd:ResourceType>\n      </Item>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"bootOptions.efiSecureBootEnabled\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"firmware\" vmw:value=\"efi\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"disk.enableUUID\" vmw:value=\"true\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.bootOrder\" vmw:value=\"hdd\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.hddOrder\" vmw:value=\"nvme0:1\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.PKDefault.value0\" vmw:value=\"{{PK_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.PKDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.KEKDefault.value0\" vmw:value=\"{{KEK_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.KEKDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbDefault.value0\" vmw:value=\"{{DB_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbxDefault.value0\" vmw:value=\"{{DBX_EMPTY_HASH_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbxDefault.append\" vmw:value=\"false\"/>\n    </VirtualHardwareSection>\n  </VirtualSystem>\n</Envelope>\n"
  },
  {
    "path": "variants/shared/template-unified-secboot.ovf",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<Envelope xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\">\n  <References>\n    <File ovf:id=\"file1\" ovf:href=\"{{OS_DISK}}\"/>\n  </References>\n  <DiskSection>\n    <Info>List of the virtual disks</Info>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk1\" ovf:capacity=\"{{OS_DISK_BYTES}}\" ovf:fileRef=\"file1\"/>\n  </DiskSection>\n  <NetworkSection>\n    <Info>The list of logical networks</Info>\n    <Network ovf:name=\"VM Network\">\n      <Description>The network</Description>\n    </Network>\n  </NetworkSection>\n  <VirtualSystem ovf:id=\"image\">\n    <Info>A Virtual machine</Info>\n    <OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other4xLinux64Guest\">\n      <Info>The operating system installed</Info>\n      <Description>Other 4.x or later Linux (64-bit)</Description>\n    </OperatingSystemSection>\n    <VirtualHardwareSection>\n      <Info>Virtual hardware requirements</Info>\n      <System>\n        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n        <vssd:InstanceID>0</vssd:InstanceID>\n        <vssd:VirtualSystemType>vmx-15</vssd:VirtualSystemType>\n      </System>\n      <Item>\n        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n        <rasd:Description>Number of Virtual CPUs</rasd:Description>\n        <rasd:ElementName>2 virtual CPU(s)</rasd:ElementName>\n        <rasd:InstanceID>1</rasd:InstanceID>\n        <rasd:ResourceType>3</rasd:ResourceType>\n        <rasd:VirtualQuantity>2</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n        <rasd:Description>Memory Size</rasd:Description>\n        <rasd:ElementName>8192MB of memory</rasd:ElementName>\n        <rasd:InstanceID>2</rasd:InstanceID>\n        <rasd:ResourceType>4</rasd:ResourceType>\n        <rasd:VirtualQuantity>8192</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:Address>0</rasd:Address>\n        <rasd:Description>NVMe Controller</rasd:Description>\n        <rasd:ElementName>NVMe Controller 1</rasd:ElementName>\n        <rasd:InstanceID>4</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.nvme.controller</rasd:ResourceSubType>\n        <rasd:ResourceType>20</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 1</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n        <rasd:InstanceID>6</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:Connection>VM Network</rasd:Connection>\n        <rasd:ElementName>Network adapter 1</rasd:ElementName>\n        <rasd:InstanceID>9</rasd:InstanceID>\n        <rasd:ResourceSubType>VmxNet3</rasd:ResourceSubType>\n        <rasd:ResourceType>10</rasd:ResourceType>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"connectable.allowGuestControl\" vmw:value=\"true\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"wakeOnLanEnabled\" vmw:value=\"false\"/>\n      </Item>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"bootOptions.efiSecureBootEnabled\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"firmware\" vmw:value=\"efi\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"disk.enableUUID\" vmw:value=\"true\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.bootOrder\" vmw:value=\"hdd\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.hddOrder\" vmw:value=\"nvme0:1\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.PKDefault.value0\" vmw:value=\"{{PK_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.PKDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.KEKDefault.value0\" vmw:value=\"{{KEK_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.KEKDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbDefault.value0\" vmw:value=\"{{DB_CERT_DER_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbDefault.append\" vmw:value=\"false\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbxDefault.value0\" vmw:value=\"{{DBX_EMPTY_HASH_HEX}}\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"uefi.secureBoot.dbxDefault.append\" vmw:value=\"false\"/>\n    </VirtualHardwareSection>\n  </VirtualSystem>\n</Envelope>\n"
  },
  {
    "path": "variants/shared/template-unified.ovf",
    "content": "<?xml version='1.0' encoding='UTF-8'?>\n<Envelope xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\">\n  <References>\n    <File ovf:id=\"file1\" ovf:href=\"{{OS_DISK}}\"/>\n  </References>\n  <DiskSection>\n    <Info>List of the virtual disks</Info>\n    <Disk ovf:capacityAllocationUnits=\"byte\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\" ovf:diskId=\"vmdisk1\" ovf:capacity=\"{{OS_DISK_BYTES}}\" ovf:fileRef=\"file1\"/>\n  </DiskSection>\n  <NetworkSection>\n    <Info>The list of logical networks</Info>\n    <Network ovf:name=\"VM Network\">\n      <Description>The network</Description>\n    </Network>\n  </NetworkSection>\n  <VirtualSystem ovf:id=\"image\">\n    <Info>A Virtual machine</Info>\n    <OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other4xLinux64Guest\">\n      <Info>The operating system installed</Info>\n      <Description>Other 4.x or later Linux (64-bit)</Description>\n    </OperatingSystemSection>\n    <VirtualHardwareSection>\n      <Info>Virtual hardware requirements</Info>\n      <System>\n        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n        <vssd:InstanceID>0</vssd:InstanceID>\n        <vssd:VirtualSystemType>vmx-15</vssd:VirtualSystemType>\n      </System>\n      <Item>\n        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n        <rasd:Description>Number of Virtual CPUs</rasd:Description>\n        <rasd:ElementName>2 virtual CPU(s)</rasd:ElementName>\n        <rasd:InstanceID>1</rasd:InstanceID>\n        <rasd:ResourceType>3</rasd:ResourceType>\n        <rasd:VirtualQuantity>2</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n        <rasd:Description>Memory Size</rasd:Description>\n        <rasd:ElementName>8192MB of memory</rasd:ElementName>\n        <rasd:InstanceID>2</rasd:InstanceID>\n        <rasd:ResourceType>4</rasd:ResourceType>\n        <rasd:VirtualQuantity>8192</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:Address>0</rasd:Address>\n        <rasd:Description>NVMe Controller</rasd:Description>\n        <rasd:ElementName>NVMe Controller 1</rasd:ElementName>\n        <rasd:InstanceID>4</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.nvme.controller</rasd:ResourceSubType>\n        <rasd:ResourceType>20</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:ElementName>Hard Disk 1</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n        <rasd:InstanceID>6</rasd:InstanceID>\n        <rasd:Parent>4</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:Connection>VM Network</rasd:Connection>\n        <rasd:ElementName>Network adapter 1</rasd:ElementName>\n        <rasd:InstanceID>9</rasd:InstanceID>\n        <rasd:ResourceSubType>VmxNet3</rasd:ResourceSubType>\n        <rasd:ResourceType>10</rasd:ResourceType>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"connectable.allowGuestControl\" vmw:value=\"true\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"wakeOnLanEnabled\" vmw:value=\"false\"/>\n      </Item>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"bootOptions.efiSecureBootEnabled\" vmw:value=\"false\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"firmware\" vmw:value=\"bios\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"disk.enableUUID\" vmw:value=\"true\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.bootOrder\" vmw:value=\"hdd\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"bios.hddOrder\" vmw:value=\"nvme0:1\"/>\n    </VirtualHardwareSection>\n  </VirtualSystem>\n</Envelope>\n"
  },
  {
    "path": "variants/variants.rs",
    "content": "/*!\n\nThis is an intentionally empty file that all of the variant `Cargo.toml` files can point to as their\n`lib.rs`. The build system uses `build.rs` to invoke `buildsys` but Cargo needs something to compile\nso we give it an empty `lib.rs` file.\n\n!*/\n"
  },
  {
    "path": "variants/vmware-dev/Cargo.toml",
    "content": "[package]\nname = \"vmware-dev\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nxfs-data-partition = true\nuefi-secure-boot = true\nsystemd-networkd = true\nerofs-root-partition = true\nexternal-kmod-development = false\nencrypted-storage = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n# core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    \"open-vm-tools\",\n# docker\n    \"docker-cli-29\",\n    \"docker-engine-29\",\n    \"docker-init\",\n# tools\n    \"login\",\n    \"iputils\",\n    \"strace\",\n    \"chrony-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.29/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.29 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_29\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.29\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.29-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.29-fips variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_29-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.29\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.30/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.30 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_30\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.30\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.30-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.30-fips variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_30-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.30\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.31/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.31 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_31\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.31\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.31-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.31-fips variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_31-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.31\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.32/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.32 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_32\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.32\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.32-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.32-fips variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_32-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.32\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.33/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.33 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_33\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.33\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.33-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.33-fips variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_33-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.1\",\n    \"containerd-2.1\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.33\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.34/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.34 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_34\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.34\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.34-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.34 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_34-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.34\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.35/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.35 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_35\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release-swap\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.35\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  },
  {
    "path": "variants/vmware-k8s-1.35-fips/Cargo.toml",
    "content": "[package]\n# This is the vmware-k8s-1.35 variant. \".\" is not allowed in crate names, but\n# we don't use this crate name anywhere.\nname = \"vmware-k8s-1_35-fips\"\nversion = \"0.1.0\"\nedition = \"2021\"\npublish = false\nbuild = \"../build.rs\"\n# Don't rebuild crate just because of changes to README.\nexclude = [\"README.md\"]\n\n[package.metadata.build-variant.image-layout]\npartition-plan = \"unified\"\n\n[package.metadata.build-variant.image-features]\ngrub-set-private-var = true\nuefi-secure-boot = true\nxfs-data-partition = true\nerofs-root-partition = true\nsystemd-networkd = true\nfips = true\nexternal-kmod-development = false\n\n[package.metadata.build-variant]\nimage-format = \"vmdk\"\nsupported-arches = [\"x86_64\"]\nkernel-parameters = [\n    \"console=tty1\",\n    # Only reserve if there are at least 2GB\n    \"crashkernel=2G-:256M\",\n    \"net.ifnames=0\",\n    \"netdog.default-interface=eth0:dhcp4,dhcp6?\",\n    \"quiet\",\n]\nincluded-packages = [\n    # core\n    \"release-swap\",\n    \"kernel-6.12\",\n    \"containerd-2.1\",\n    \"systemd-257\",\n    \"nftables\",\n    \"whippet\",\n    # k8s\n    \"cni\",\n    \"cni-plugins\",\n    \"kubelet-1.35\",\n    \"soci-snapshotter\",\n    # vmware\n    \"open-vm-tools\",\n]\n\n[lib]\npath = \"../variants.rs\"\n\n[build-dependencies]\nsettings-defaults = { path = \"../../packages/settings-defaults\" }\nsettings-plugins = { path = \"../../packages/settings-plugins\" }\nsettings-migrations = { path = \"../../packages/settings-migrations\" }\n"
  }
]