8000 feature: "yq" provision mode by norio-nomura · Pull Request #3892 · lima-vm/lima · GitHub
[go: up one dir, main page]

Skip to content

Conversation

norio-nomura
Copy link
Contributor
@norio-nomura norio-nomura commented Aug 22, 2025

8000 based on #3908

# Create or edit a file in the guest filesystem by using `yq`.
# The file specified by `path` will be updated with the specified `expression` using `yq --inplace`.
# If the file does not exist, it will be created using `yq --null-input`.
# `format` is optional and defaults to "auto".
# One of the following is expected to work:
#   "auto", "csv", "ini", "json", "props", "tsv", "toml", "xml", "yaml"
# See https://github.com/mikefarah/yq for more info.
# Any missing directories will be created as needed.
# The file permissions will be set to the specified value.
# The file and directory creation will be performed as the specified owner.
# If the existing file is not writable by the specified owner, the operation will fail.
# `path` and `expression` are required.
# `owner` and `permissions` are optional. Defaults to "root:root" and 644.
- mode: yq
  path: "{{.Home}}/.config/docker/daemon.json"
  expression: ".features.containerd-snapshotter = {{.Param.containerdSnapshotter}}"
  format: auto
  owner: "{{.User}}"
  permissions: 644

updated:

@AkihiroSuda
Copy link
Member

Why not just apt-get yq in a shell script?

@jandubois
Copy link
Member

I think this is too specialized to be built into Lima given that you can already do this with a regular provisioning script:

provision:
- mode: user
  script: |
    if ! command -v yq >/dev/null 2>&1; then
      apt-get update
      apt install -y yq
    fi
    mkdir -p ...
    touch ...
    yq ...

@norio-nomura
Copy link
Contributor Author

Why not just apt-get yq in a shell script?

Because yq installed by apt-get is https://github.com/kislyuk/yq
This PR installs https://github.com/mikefarah/yq

@jandubois
Copy link
Member

Because yq installed by apt-get is https://github.com/kislyuk/yq

Ok, that is unfortunate. I was wondering why it was dragging in Python.

But yq is a standalone binary, so you can also curl/wget it from the GitHub release page.

@jandubois
Copy link
Member

If the guestagent was already using yqlib, then I would be sympathetic to adding a lima-guestagent yq subcommand for convenience, but afaict only limactl uses yqlib.

And we would rather want to bring down the size of the guestagents, so I don't think we should be doing that either.

@AkihiroSuda
Copy link
Member

I was wondering why it was dragging in Python.

Dragging in the Python implementation makes a sense, as it seems more "authentic" version

@jandubois
Copy link
Member

Dragging in the Python implementation makes a sense, as it seems more "authentic" version

Fair enough. Unfortunately on homebrew yq is the standalone Go version, creating a bit of a mess. 😞

Homebrew/homebrew-core#29529

@norio-nomura norio-nomura force-pushed the yq-provision-mode branch 2 times, most recently from cc10a18 to 6cb8a7e Compare August 22, 2025 05:56
@jandubois
Copy link
Member

If we want to support adding large local files to the cidata volume, then I would suggest the way to do this would be to extend the data provisioning mode. I did try this:

base: template://docker
provision:
- mode: data
  path: /usr/local/bin/yq
  file: ~/Downloads/yq_linux_arm
  permissions: 755

It didn't work because of the tilde path (I just created a PR to fix that), but also because template embedding would attempt to include the file as a base64 encoded string, which exceeds the (somewhat arbitrary) max size of 4MB we have for lima.yaml.

I still think that once created a Lima instance should not reference other local files outside the instance directory. We could get rid of the file size limit (not a good idea, imo), or we could have some mechanism that files would be copied into a cache directory inside the instance directory, and the file reference would be rewritten to point to it.

I don't think the use case is particularly strong though when you can also just fetch the file from GitHub in a provisioning script. We do this with all manner of other prerequisites as well. But I can see the utility when you want to bundle something that is not available for download.

@norio-nomura
Copy link
Contributor Author
norio-nomura commented Aug 22, 2025

This PR adds --provision-tool yq=<local path to executable> option to hostagent to install the executable as provision/tool/yq in cidata.

@norio-nomura
Copy link
Contributor Author
provisionTool:
  yq:
  - location: "~/Downloads/yq_linux_amd64"
    arch: "x86_64"
    digest: "sha256:..."

The example above is from .containerd.archives, but it doesn’t support ~ expansion.

@afbjorklund
Copy link
Member

@norio-nomura : I think you should add an issue for what you are trying to accomplish here, before diving straight into the implementation and the PR? My gut feeling is that this will meet the same fate as the "ansible" provisioning.

@jandubois
Copy link
Member

I know this is just an example, but I just realized that you are editing a JSON file, so you can just use jq (which is already installed in Ubuntu).

@jandubois
Copy link
Member

snap.tmpl using built-in jq:

base: template://docker
provision:
- mode: user
  script: |
    set -eux -o pipefail
    DAEMON="{{.Home}}/.config/docker/daemon.json"
    mkdir -p "$(dirname "$DAEMON")"
    [[ ! -e $DAEMON ]] && echo "{}" > "$DAEMON"
    chmod 644 "$DAEMON"
    EXPR='.features["containerd-snapshotter"] = {{.Param.containerdSnapshotter}}'
    jq "$EXPR" "$DAEMON" >"$DAEMON.new"
    mv "$DAEMON.new" "$DAEMON"
param:
  containerdSnapshotter: true

Seems to work fine:

limactl start --yes --name snap ./snap.tmpllimactl shell snap sh -c "cat ~/.config/docker/daemon.json"
{
  "features": {
    "containerd-snapshotter": true
  }
}

@jandubois
Copy link
Member
jandubois commented Aug 22, 2025

Unrelated, but I also think we should just always use the containerdSnapshotter in the docker template. I'm not aware of any reason to use the legacy one.

Even Docker Desktop has been using it by default for over a year now for all new installations. It is not considered experimental anymore.

@norio-nomura
Copy link
Contributor Author

snap.tmpl using built-in jq:

jq is not built-in on Ubuntu-Minimal that I'm using.

Seems to work fine:

Yup, I also have some lima.yaml files that contain similar provision scripts.

I want to make those tasks much simpler like this PR does.

@norio-nomura
Copy link
Contributor Author

@norio-nomura : I think you should add an issue for what you are trying to accomplish here, before diving straight into the implementation and the PR? My gut feeling is that this will meet the same fate as the "ansible" provisioning.

If I make an issue before I write a PR, I expect to receive an answer like #3892 (comment) It came.

Being able to make limactl with this function at my local Mac is more valuable to me than this PR is merged. I just prioritized the time to realize this function rather than the time spent communicating with the issue.

@norio-nomura
Copy link
Contributor Author

Added format field. Now, it can manipulate systemd's unit files like the following:

- mode: yq
  path: /etc/systemd/system/docker.service.d/override.conf
  format: ini
  expression: .Socket.SocketUser="{{.User}}"

@norio-nomura norio-nomura force-pushed the yq-provision-mode branch 4 times, most recently from 9a9c7c4 to 420f6ee Compare August 25, 2025 12:53
@afbjorklund
Copy link
Member

Being able to make limactl with this function at my local Mac is more valuable to me than this PR is merged. I just prioritized the time to realize this function rather than the time spent communicating with the issue.

That is OK, but it also runs into the risk of 1) not realizing there is a simpler way to accomplish the same thing and 2) risking that the PR is never merged - or maybe merged and then deprecated and removed again, like Ansible

@jandubois
Copy link
Member

I like the provision.mode: yq feature, but think the provisionTool design is too specialized, and would have to either piggy-back on the provision.mode: data mechanism or need to be hardcoded into Lima like the nerdctl archives.

I think a better approach would be to bundle yq into our existing binaries. That way we can re-use all the bundled runtime library code (and even yqlib in the case of limactl), and don't have to worry about versions/locations etc.

I've created #3908 to show how simple this is to implement. What do you think about using that approach @norio-nomura?

@norio-nomura
Copy link
Contributor Author

I will separate the provisionTool related code to a separate commit.

@norio-nomura
Copy link
Contributor Author
norio-nomura commented Aug 26, 2025

updated:

@norio-nomura norio-nomura force-pushed the yq-provision-mode branch 7 times, most recently from 8f59a28 to 71563bd Compare August 27, 2025 09:39
@norio-nomura norio-nomura marked this pull request as ready for review August 27, 2025 10:07
@norio-nomura
Copy link
Contributor Author

Pushed a separate commit that applying reviews

A3E2
@AkihiroSuda AkihiroSuda added this to the v2.0.0 milestone Aug 28, 2025
Copy link
Member
@jandubois jandubois left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM

Still have some nit-picks, and I think we are missing the documentation for the order the provisioning types are executed.

@jandubois jandubois dismissed their stale review August 28, 2025 06:22

Requested changes have been made.

@norio-nomura
Copy link
Contributor Author

Pushed a separate commit that applying additional reviews

@norio-nomura
Copy link
Contributor Author

force pushed to fix lint error

@AkihiroSuda
Copy link
Member

Please squash the commits

```yaml
# Create or edit a file in the guest filesystem by using `yq`.
# The file specified by `path` will be updated by `expression`.
# An empty file of the required `format` will be created if it does not yet exist.
# `format` defaults to "auto" and will be detected by file extension of `path`.
# If the extension is not recognized by `yq` then `format` must be set to a
# value from this list:
#   "auto", "csv", "ini", "json", "props", "tsv", "toml", "xml", "yaml"
# See https://github.com/mikefarah/yq for more info.
# Any missing directories will be created as needed.
# The file permissions will be set to the specified value.
# The file and directory creation will be performed as the specified owner.
# If the existing file is not writable by the specified owner, the operation will fail.
# `path` and `expression` are required.
# `owner` and `permissions` are optional. Defaults to "root:root" and 644.
- mode: yq
  path: "{{.Home}}/.config/docker/daemon.json"
  expression: ".features.containerd-snapshotter = {{.Param.containerdSnapshotter}}"
  format: auto
  owner: "{{.User}}"
  permissions: 644

```
Signed-off-by: Norio Nomura <norio.nomura@gmail.com>
Copy link
Member
@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@AkihiroSuda AkihiroSuda merged commit 3db7ced into lima-vm:master Aug 28, 2025
36 checks passed
@norio-nomura
Copy link
Contributor Author

Thanks! 🙏🏻

@norio-nomura norio-nomura deleted the yq-provision-mode branch August 28, 2025 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0