Showing preview only (463K chars total). Download the full file or copy to clipboard to get everything.
Repository: abiosoft/colima
Branch: main
Commit: 8cb5d3528716
Files: 143
Total size: 429.4 KB
Directory structure:
gitextract_xof0cru8/
├── .editorconfig
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yaml
│ │ └── feature_request.yaml
│ ├── dependabot.yaml
│ └── workflows/
│ ├── go.yml
│ ├── golang-ci.yml
│ └── integration.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── app/
│ └── app.go
├── cli/
│ ├── chain.go
│ └── command.go
├── cmd/
│ ├── clone.go
│ ├── colima/
│ │ └── main.go
│ ├── completion.go
│ ├── daemon/
│ │ ├── cmd.go
│ │ ├── daemon.go
│ │ └── daemon_test.go
│ ├── delete.go
│ ├── kubernetes.go
│ ├── list.go
│ ├── model.go
│ ├── nerdctl.go
│ ├── prune.go
│ ├── restart.go
│ ├── root/
│ │ └── root.go
│ ├── ssh-config.go
│ ├── ssh.go
│ ├── start.go
│ ├── start_test.go
│ ├── status.go
│ ├── stop.go
│ ├── template.go
│ ├── update.go
│ ├── util.go
│ └── version.go
├── colima.nix
├── config/
│ ├── config.go
│ ├── configmanager/
│ │ └── configmanager.go
│ ├── files.go
│ └── profile.go
├── core/
│ └── core.go
├── daemon/
│ ├── daemon.go
│ └── process/
│ ├── inotify/
│ │ ├── events.go
│ │ ├── inotify.go
│ │ ├── volumes.go
│ │ ├── volumes_test.go
│ │ └── watch.go
│ ├── process.go
│ └── vmnet/
│ ├── deps.go
│ └── vmnet.go
├── default.nix
├── docs/
│ ├── CONTRIBUTE.md
│ ├── FAQ.md
│ └── INSTALL.md
├── embedded/
│ ├── defaults/
│ │ ├── abort.yaml
│ │ ├── colima.yaml
│ │ └── template.yaml
│ ├── embed.go
│ ├── images/
│ │ ├── images.txt
│ │ └── images_sha.sh
│ ├── k3s/
│ │ └── flannel.json
│ ├── network/
│ │ └── sudo.txt
│ └── sudoers.go
├── environment/
│ ├── container/
│ │ ├── containerd/
│ │ │ ├── buildkitd.toml
│ │ │ ├── config.toml
│ │ │ └── containerd.go
│ │ ├── docker/
│ │ │ ├── config.toml
│ │ │ ├── containerd.go
│ │ │ ├── context.go
│ │ │ ├── daemon.go
│ │ │ ├── docker.go
│ │ │ └── proxy.go
│ │ ├── incus/
│ │ │ ├── config.yaml
│ │ │ ├── incus.go
│ │ │ └── route.go
│ │ └── kubernetes/
│ │ ├── cni.go
│ │ ├── k3s.go
│ │ ├── kubeconfig.go
│ │ └── kubernetes.go
│ ├── container.go
│ ├── environment.go
│ ├── guest/
│ │ └── systemctl/
│ │ ├── systemctl.go
│ │ └── systemctl_test.go
│ ├── host/
│ │ └── host.go
│ ├── host.go
│ ├── vm/
│ │ └── lima/
│ │ ├── certs.go
│ │ ├── config.go
│ │ ├── daemon.go
│ │ ├── disk.go
│ │ ├── disk.sh
│ │ ├── dns.go
│ │ ├── file.go
│ │ ├── lima.go
│ │ ├── limaconfig/
│ │ │ └── config.go
│ │ ├── limautil/
│ │ │ ├── disk.go
│ │ │ ├── files.go
│ │ │ ├── image.go
│ │ │ ├── instance.go
│ │ │ ├── limautil.go
│ │ │ ├── network.go
│ │ │ └── ssh.go
│ │ ├── network.go
│ │ ├── shell.go
│ │ ├── yaml.go
│ │ └── yaml_test.go
│ └── vm.go
├── flake.nix
├── go.mod
├── go.sum
├── integration/
│ └── Dockerfile
├── model/
│ ├── docker.go
│ ├── ramalama.go
│ ├── runner.go
│ └── runner_test.go
├── scripts/
│ ├── build_vmnet.sh
│ └── integration.sh
├── shell.nix
├── store/
│ └── store.go
└── util/
├── debutil/
│ └── debutil.go
├── downloader/
│ ├── curl.go
│ ├── download.go
│ ├── errors.go
│ ├── http.go
│ ├── native.go
│ └── sha.go
├── fsutil/
│ └── fs.go
├── macos.go
├── macos_test.go
├── osutil/
│ └── os.go
├── qemu.go
├── shautil/
│ └── sha.go
├── template.go
├── terminal/
│ ├── output.go
│ └── terminal.go
├── util.go
└── yamlutil/
├── yaml.go
└── yaml_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
[*.go]
indent_style = tab
================================================
FILE: .github/FUNDING.yml
================================================
github: abiosoft
custom:
- "https://buymeacoffee.com/abiosoft"
patreon: colima
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yaml
================================================
name: Bug report
description: Report a bug or issue
body:
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the issue is.
- type: textarea
attributes:
label: Version
description: Please show the output of `colima version && limactl --version && qemu-img --version`.
- type: checkboxes
attributes:
label: Operating System
description: Which Operating System/Architecture does this issue happen on? Check all that apply.
options:
- label: macOS Intel <= 13 (Ventura)
required: false
- label: macOS Intel >= 14 (Sonoma)
required: false
- label: Apple Silicon <= 13 (Ventura)
required: false
- label: Apple Silicon >= 14 (Sonoma)
required: false
- label: Linux
required: false
- type: textarea
attributes:
label: Output of `colima status`
description: The output of `colima status` or `colima status -p <profilename>` tells us what vm-type and mount type, etc.
value:
- type: textarea
attributes:
label: Reproduction Steps
description: Kindly walk us through the steps to reproduce this behaviour.
value: |
1.
2.
3.
- type: textarea
attributes:
label: Expected behaviour
description: A clear and concise description of what you expected to happen.
- type: textarea
attributes:
label: Additional context
description: Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yaml
================================================
name: Feature request
description: Request a missing feature
body:
- type: textarea
attributes:
label: Description
================================================
FILE: .github/dependabot.yaml
================================================
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/go.yml
================================================
name: Go
on:
push:
tags: ["v*"]
paths-ignore:
- "**/*.md"
- "**/*.nix"
- "**/*.lock"
pull_request:
branches: [main]
paths-ignore:
- "**/*.md"
- "**/*.nix"
- "**/*.lock"
permissions: write-all
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
build-macos:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
binaries-linux:
needs: "build-linux"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: install gcc-aarch64-linux-gnu
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: generate binaries
run: |
OS=Linux ARCH=x86_64 make
OS=Linux ARCH=aarch64 make
- name: upload artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: artifacts-linux
path: _output/binaries/
binaries-macos:
needs: "build-macos"
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: generate binaries
run: |
CGO_ENABLED=1 OS=Darwin ARCH=x86_64 make
CGO_ENABLED=1 OS=Darwin ARCH=arm64 make
- name: upload artifacts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: artifacts-macos
path: _output/binaries/
release:
needs: ["binaries-linux", "binaries-macos"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: artifacts-linux
path: _output/binaries/
- uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: artifacts-macos
path: _output/binaries/
- name: create release
if: github.event_name != 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: >
tag="${GITHUB_REF##*/}"
gh release create "${tag}" --draft --title "${tag}"
_output/binaries/colima-Darwin-x86_64
_output/binaries/colima-Darwin-x86_64.sha256sum
_output/binaries/colima-Darwin-arm64
_output/binaries/colima-Darwin-arm64.sha256sum
_output/binaries/colima-Linux-x86_64
_output/binaries/colima-Linux-x86_64.sha256sum
_output/binaries/colima-Linux-aarch64
_output/binaries/colima-Linux-aarch64.sha256sum
================================================
FILE: .github/workflows/golang-ci.yml
================================================
name: golangci-lint
on:
push:
tags: [v*]
branches: [main]
paths-ignore:
- "**/*.md"
- "**/*.nix"
- "**/*.lock"
pull_request:
paths-ignore:
- "**/*.md"
- "**/*.nix"
- "**/*.lock"
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.11.3
args: --timeout 3m0s
================================================
FILE: .github/workflows/integration.yml
================================================
name: Integration
on:
push:
tags: ["v*"]
branches: [main]
paths-ignore:
- "**/*.md"
- "**/*.nix"
- "**/*.lock"
pull_request:
branches: [main]
paths-ignore:
- "**/*.md"
- "**/*.nix"
- "**/*.lock"
workflow_dispatch:
inputs:
debug_enabled:
description: 'Debug with tmate set "debug_enabled"'
required: false
default: "false"
jobs:
kubernetes-docker:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Install CLI deps
run: brew install kubectl docker coreutils lima
- name: Build and Install
run: make && sudo make install
- name: tmate debugging session
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23
with:
limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
- name: Start Colima
run: colima start --runtime docker --kubernetes
- name: Delay
run: sleep 20
- name: Validate Kubernetes
run: kubectl cluster-info && kubectl version && kubectl get nodes -o wide
- name: Teardown
run: colima delete -f
kubernetes-containerd:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Install CLI deps
run: brew install kubectl docker coreutils lima
- name: Build and Install
run: make && sudo make install
- name: tmate debugging session
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23
with:
limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
- name: Start
run: colima start --runtime containerd --kubernetes
- name: Delay
run: sleep 20
- name: Validate Kubernetes
run: kubectl cluster-info && kubectl version && kubectl get nodes -o wide
- name: Teardown
run: colima delete -f
docker:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Install CLI deps
run: brew install kubectl docker coreutils lima
- name: Build and Install
run: make && sudo make install
- name: tmate debugging session
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23
with:
limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
- name: Start Colima
run: colima start --runtime docker
- name: Delay
run: sleep 10
- name: Validate Docker
run: docker ps && docker info
- name: Validate DNS
run: colima ssh -- sh -c "sudo apt-get update -y -qq && sudo apt-get install -qq dnsutils && nslookup host.docker.internal"
- name: Build Image
run: docker build integration
- name: Run Image arm64
run: docker run --rm --platform=linux/arm64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Run Image amd64
run: docker run --rm --platform=linux/amd64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Stop
run: colima stop
- name: Temp Delete
run: colima delete -f
- name: Restart
run: colima start --runtime docker
- name: Assert runtime disk arm64
run: docker run --pull=never --rm --platform=linux/arm64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Assert runtime disk amd64
run: docker run --pull=never --rm --platform=linux/amd64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Teardown
run: colima delete --data -f
containerd:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Install CLI deps
run: brew install kubectl docker coreutils lima
- name: Build and Install
run: make && sudo make install
- name: tmate debugging session
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23
with:
limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
- name: Start Colima
run: colima start --runtime containerd
- name: Delay
run: sleep 10
- name: Validate Containerd
run: colima nerdctl ps && colima nerdctl info
- name: Validate DNS
run: colima ssh -- sh -c "sudo apt-get update -y -qq && sudo apt-get install -qq dnsutils && nslookup host.docker.internal"
- name: Build Image
run: colima nerdctl -- build integration
- name: Run Image arm64
run: colima nerdctl -- run --rm --platform=linux/arm64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Run Image amd64
run: colima nerdctl -- run --rm --platform=linux/amd64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Stop
run: colima stop
- name: Temp Delete
run: colima delete -f
- name: Restart
run: colima start --runtime containerd
- name: Assert runtime disk arm64
run: colima nerdctl -- run --pull=never --rm --platform=linux/arm64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Assert runtime disk amd64
run: colima nerdctl -- run --pull=never --rm --platform=linux/amd64 ghcr.io/linuxcontainers/alpine:latest uname -a
- name: Teardown
run: colima delete --data -f
incus:
runs-on: macos-15-intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "1.26.1"
- name: Install CLI deps
run: brew install kubectl docker coreutils lima incus
- name: Build and Install
run: make && sudo make install
- name: tmate debugging session
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23
with:
limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
- name: Start Colima
run: colima start --runtime incus
- name: Delay
run: sleep 10
- name: Validate Incus
run: incus version && incus list
- name: Launch Instance
run: incus launch images:alpine/edge test-instance
- name: Delay for instance
run: sleep 5
- name: Validate Instance
run: incus exec test-instance -- cat /etc/os-release
- name: Validate DNS
run: colima ssh -- sh -c "sudo apt-get update -y -qq && sudo apt-get install -qq dnsutils && nslookup host.docker.internal"
- name: Stop
run: colima stop
- name: Temp Delete
run: colima delete -f
- name: Restart
run: colima start --runtime incus
- name: Delay for restart
run: sleep 10
- name: Assert instance restored
run: incus exec test-instance -- cat /etc/os-release
- name: Teardown
run: colima delete --data -f
================================================
FILE: .gitignore
================================================
.idea/
.fleet/
.vscode/
_output/
_build/
bin/
result
================================================
FILE: .golangci.yml
================================================
version: "2"
linters:
enable:
- gocritic
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Abiola Ibrahim
Permission 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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE 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.
================================================
FILE: Makefile
================================================
OS ?= $(shell uname)
ARCH ?= $(shell uname -m)
GOOS ?= $(shell echo "$(OS)" | tr '[:upper:]' '[:lower:]')
GOARCH_x86_64 = amd64
GOARCH_aarch64 = arm64
GOARCH_arm64 = arm64
GOARCH ?= $(shell echo "$(GOARCH_$(ARCH))")
VERSION := $(shell git describe --tags --always)
REVISION := $(shell git rev-parse HEAD)
PACKAGE := github.com/abiosoft/colima/config
VERSION_VARIABLES := -X $(PACKAGE).appVersion=$(VERSION) -X $(PACKAGE).revision=$(REVISION)
OUTPUT_DIR := _output/binaries
OUTPUT_BIN := colima-$(OS)-$(ARCH)
INSTALL_DIR := /usr/local/bin
BIN_NAME := colima
LDFLAGS := $(VERSION_VARIABLES)
.PHONY: all
all: build
.PHONY: clean
clean:
rm -rf _output _build
.PHONY: gopath
gopath:
go get -v ./cmd/colima
.PHONY: fmt
fmt:
go fmt ./...
goimports -w .
.PHONY: build
build:
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -ldflags="$(LDFLAGS)" -o $(OUTPUT_DIR)/$(OUTPUT_BIN) ./cmd/colima
ifeq ($(GOOS),darwin)
codesign -s - $(OUTPUT_DIR)/$(OUTPUT_BIN)
endif
cd $(OUTPUT_DIR) && openssl sha256 -r -out $(OUTPUT_BIN).sha256sum $(OUTPUT_BIN)
.PHONY: test
test:
go test -v -ldflags="$(LD_FLAGS)" ./...
.PHONY: vmnet
vmnet:
sh scripts/build_vmnet.sh
.PHONY: install
install:
mkdir -p $(INSTALL_DIR)
rm -f $(INSTALL_DIR)/$(BIN_NAME)
cp $(OUTPUT_DIR)/colima-$(OS)-$(ARCH) $(INSTALL_DIR)/$(BIN_NAME)
chmod +x $(INSTALL_DIR)/$(BIN_NAME)
.PHONY: lint
lint: ## Assumes that golangci-lint is installed and in the path. To install: https://golangci-lint.run/usage/install/
golangci-lint --timeout 3m run
.PHONY: print-binary-name
print-binary-name:
@echo $(OUTPUT_DIR)/$(OUTPUT_BIN)
.PHONY: nix-derivation-shell
nix-derivation-shell:
$(eval DERIVATION=$(shell nix-build))
echo $(DERIVATION) | grep ^/nix
nix-shell -p $(DERIVATION)
.PHONY: integration
integration: build
GOARCH=$(GOARCH) COLIMA_BINARY=$(OUTPUT_DIR)/$(OUTPUT_BIN) scripts/integration.sh
.PHONY: images-sha
images-sha:
bash embedded/images/images_sha.sh
================================================
FILE: README.md
================================================

## Colima - container runtimes on macOS (and Linux) with minimal setup.
[](https://github.com/abiosoft/colima/actions/workflows/go.yml)
[](https://github.com/abiosoft/colima/actions/workflows/integration.yml)
[](https://goreportcard.com/report/github.com/abiosoft/colima)

**Website & Documentation:** [colima.run](https://colima.run) | [colima.run/docs](https://colima.run/docs/)
## Features
Support for Intel and Apple Silicon macOS, and Linux
- Simple CLI interface with sensible defaults
- Automatic Port Forwarding
- Volume mounts
- Multiple instances
- Support for multiple container runtimes
- [Docker](https://docker.com) (with optional Kubernetes)
- [Containerd](https://containerd.io) (with optional Kubernetes)
- [Incus](https://linuxcontainers.org/incus) (containers and virtual machines)
- GPU accelerated containers for AI workloads
## Getting Started
### Installation
Colima is available on Homebrew, MacPorts, Nix and [Mise](http://github.com/jdx/mise). Check [here](docs/INSTALL.md) for other installation options.
```sh
# Homebrew
brew install colima
# MacPorts
sudo port install colima
# Nix
nix-env -iA nixpkgs.colima
# Mise
mise use -g colima@latest
```
Or stay on the bleeding edge (only Homebrew)
```
brew install --HEAD colima
```
## Usage
Start Colima with defaults
```
colima start
```
For more usage options
```
colima --help
colima start --help
```
Or use a config file
```
colima start --edit
```
## Runtimes
On initial startup, Colima initiates with a user specified runtime that defaults to Docker.
### Docker
Docker client is required for Docker runtime. Installable with `brew install docker`.
```
colima start
docker run hello-world
docker ps
```
You can use the `docker` client on macOS after `colima start` with no additional setup.
### Containerd
`colima start --runtime containerd` starts and setup Containerd. You can use `colima nerdctl` to interact with
Containerd using [nerdctl](https://github.com/containerd/nerdctl).
```
colima start --runtime containerd
nerdctl run hello-world
nerdctl ps
```
It is recommended to run `colima nerdctl install` to install `nerdctl` alias script in $PATH.
### Kubernetes
kubectl is required for Kubernetes. Installable with `brew install kubectl`.
To enable Kubernetes, start Colima with `--kubernetes` flag.
```
colima start --kubernetes
kubectl run caddy --image=caddy
kubectl get pods
```
#### Interacting with Image Registry
For Docker runtime, images built or pulled with Docker are accessible to Kubernetes.
For Containerd runtime, images built or pulled in the `k8s.io` namespace are accessible to Kubernetes.
### Incus
<small>**Requires v0.7.0**</small>
Incus client is required for Incus runtime. Installable with brew `brew install incus`.
`colima start --runtime incus` starts and setup Incus.
```
colima start --runtime incus
incus launch images:alpine/edge
incus list
```
You can use the `incus` client on macOS after `colima start` with no additional setup.
**Note:** Running virtual machines on Incus is only supported on m3 or newer Apple Silicon devices.
### AI Models (GPU Accelerated)
<small>**Requires v0.10.0, Apple Silicon and macOS 13+**</small>
Colima supports GPU accelerated containers for AI workloads using the `krunkit` VM type.
**Note:** To use krunkit with colima, ensure it is installed.
```
brew tap slp/krunkit
brew install krunkit
```
Setup and use a model.
```
colima start --runtime docker --vm-type krunkit
colima model run gemma3
```
Colima supports two model runner backends:
- **Docker Model Runner** (default) — supports [Docker AI Registry](https://hub.docker.com/u/ai) and [HuggingFace](https://huggingface.co).
- **Ramalama** — supports [HuggingFace](https://huggingface.co) and [Ollama](https://ollama.com) registries.
The default registry is the Docker AI Registry. Models can be run by name without a prefix:
```sh
colima model run gemma3
colima model run llama3.2
# HuggingFace (Docker Model Runner)
colima model run hf.co/microsoft/Phi-3-mini-4k-instruct-gguf
# Ollama (requires ramalama runner)
colima model run ollama://gemma3 --runner ramalama
```
See the [AI Workloads documentation](https://colima.run/docs/ai/) for more details.
### Customizing the VM
The default VM created by Colima has 2 CPUs, 2GiB memory and 100GiB storage.
The VM can be customized either by passing additional flags to `colima start`.
e.g. `--cpu`, `--memory`, `--disk`, `--runtime`.
Or by editing the config file with `colima start --edit`.
**NOTE**: Disk size can be increased after the VM is created.
#### Customization Examples
- create VM with 1CPU, 2GiB memory and 10GiB storage.
```
colima start --cpu 1 --memory 2 --disk 10
```
- modify an existing VM to 4CPUs and 8GiB memory.
```
colima stop
colima start --cpu 4 --memory 8
```
- create VM with Rosetta 2 emulation. Requires v0.5.3 and macOS >= 13 (Ventura) on Apple Silicon.
```
colima start --vm-type=vz --vz-rosetta
```
## Project Goal
To provide container runtimes on macOS with minimal setup.
## What is with the name?
Colima means Containers on [Lima](https://github.com/lima-vm/lima).
Since Lima is aka Linux Machines. By transitivity, Colima can also mean Containers on Linux Machines.
## And the Logo?
The logo was contributed by [Daniel Hodvogner](https://github.com/dhodvogner). Check [this issue](https://github.com/abiosoft/colima/issues/781) for more.
## Troubleshooting and FAQs
Check [here](docs/FAQ.md) for Frequently Asked Questions, or visit the [online FAQ](https://colima.run/docs/faq/) for a searchable version.
## How to Contribute?
Check [here](docs/CONTRIBUTE.md) for the instructions on contributing to the project.
## Community
- [GitHub Discussions](https://github.com/abiosoft/colima/discussions)
- [GitHub Issues](https://github.com/abiosoft/colima/issues)
- [Announcements](https://colima.run/announcements/)
- `#colima` channel in the CNCF Slack
- New account: <https://slack.cncf.io/>
- Login: <https://cloud-native.slack.com/>
## License
MIT
## Sponsoring the Project
If you (or your company) are benefiting from the project and would like to support the contributors, kindly sponsor.
- [Github Sponsors](https://github.com/sponsors/abiosoft)
- [Buy me a coffee](https://www.buymeacoffee.com/abiosoft)
- [Patreon](https://patreon.com/colima)
---
[<img src="https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png" style="max-height: 150px"/>](https://macstadium.com)
================================================
FILE: SECURITY.md
================================================
Thanks for helping make Colima safe for everyone.
## Security
We take the security of Colima seriously.
We will ensure that your finding gets passed along to the appropriate maintainers for remediation.
## Reporting Security Issues
If you believe you have found a security vulnerability in this repository, please report it to us through coordinated disclosure.
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
Instead, please send an email to git[@]abiosoft.com.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
================================================
FILE: app/app.go
================================================
package app
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/config/configmanager"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/environment/container/containerd"
"github.com/abiosoft/colima/environment/container/docker"
"github.com/abiosoft/colima/environment/container/incus"
"github.com/abiosoft/colima/environment/container/kubernetes"
"github.com/abiosoft/colima/environment/host"
"github.com/abiosoft/colima/environment/vm/lima"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/abiosoft/colima/store"
"github.com/abiosoft/colima/util"
"github.com/docker/go-units"
log "github.com/sirupsen/logrus"
)
type App interface {
Active() bool
Start(config.Config) error
Stop(force bool) error
Delete(data, force bool) error
SSH(args ...string) error
Status(extended bool, json bool) error
Version() error
Runtime() (string, error)
Update() error
Kubernetes() (environment.Container, error)
}
var _ App = (*colimaApp)(nil)
// New creates a new app.
func New() (App, error) {
guest := lima.New(host.New())
if err := host.IsInstalled(guest); err != nil {
return nil, fmt.Errorf("dependency check failed for VM: %w", err)
}
return &colimaApp{
guest: guest,
}, nil
}
type colimaApp struct {
guest environment.VM
}
func (c colimaApp) startWithRuntime(conf config.Config) ([]environment.Container, error) {
kubernetesEnabled := conf.Kubernetes.Enabled
// Kubernetes can only be enabled for docker and containerd
switch conf.Runtime {
case docker.Name, containerd.Name:
default:
kubernetesEnabled = false
}
var containers []environment.Container
{
runtime := conf.Runtime
if kubernetesEnabled {
runtime += "+k3s"
}
log.Println("runtime:", runtime)
}
// runtime
{
env, err := c.containerEnvironment(conf.Runtime)
if err != nil {
return nil, err
}
containers = append(containers, env)
}
// kubernetes should come after required runtime
if kubernetesEnabled {
env, err := c.containerEnvironment(kubernetes.Name)
if err != nil {
return nil, err
}
containers = append(containers, env)
}
return containers, nil
}
func (c colimaApp) Start(conf config.Config) error {
ctx := context.WithValue(context.Background(), config.CtxKey(), conf)
log.Println("starting", config.CurrentProfile().DisplayName)
// print the full path of current profile being used
log.Tracef("starting with config file: %s\n", config.CurrentProfile().File())
var containers []environment.Container
if !environment.IsNoneRuntime(conf.Runtime) {
cs, err := c.startWithRuntime(conf)
if err != nil {
return err
}
containers = cs
}
// the order for start is:
// vm start -> container runtime provision -> container runtime start
// start vm
if err := c.guest.Start(ctx, conf); err != nil {
return fmt.Errorf("error starting vm: %w", err)
}
// run after-boot provision scripts
c.runProvisionScripts(conf, config.ProvisionModeAfterBoot)
// provision and start container runtimes
for _, cont := range containers {
log := log.WithField("context", cont.Name())
log.Println("provisioning ...")
if err := cont.Provision(ctx); err != nil {
return fmt.Errorf("error provisioning %s: %w", cont.Name(), err)
}
log.Println("starting ...")
if err := cont.Start(ctx); err != nil {
return fmt.Errorf("error starting %s: %w", cont.Name(), err)
}
}
// run ready provision scripts
c.runProvisionScripts(conf, config.ProvisionModeReady)
// persist the current runtime
if err := c.setRuntime(conf.Runtime); err != nil {
log.Error(fmt.Errorf("error persisting runtime settings: %w", err))
}
// persist the kubernetes config
if err := c.setKubernetes(conf.Kubernetes); err != nil {
log.Error(fmt.Errorf("error persisting kubernetes settings: %w", err))
}
log.Println("done")
if err := generateSSHConfig(conf.SSHConfig); err != nil {
log.Trace("error generating ssh_config: %w", err)
}
return nil
}
func (c colimaApp) runProvisionScripts(conf config.Config, mode string) {
var failed bool
for _, s := range conf.Provision {
if s.Mode != mode {
continue
}
if err := c.guest.Run("sh", "-c", s.Script); err != nil {
failed = true
}
}
if failed {
log.Warnln(fmt.Errorf("error running %s provision script(s)", mode))
}
}
func (c colimaApp) Stop(force bool) error {
ctx := context.Background()
log.Println("stopping", config.CurrentProfile().DisplayName)
// the order for stop is:
// container stop -> vm stop
// stop container runtimes
if c.guest.Running(ctx) {
containers, err := c.currentContainerEnvironments(ctx)
if err != nil {
log.Warnln(fmt.Errorf("error retrieving runtimes: %w", err))
}
// stop happens in reverse of start
for i := len(containers) - 1; i >= 0; i-- {
cont := containers[i]
log := log.WithField("context", cont.Name())
log.Println("stopping ...")
if err := cont.Stop(ctx, force); err != nil {
// failure to stop a container runtime is not fatal
// it is only meant for graceful shutdown.
// the VM will shut down anyways.
log.Warnln(fmt.Errorf("error stopping %s: %w", cont.Name(), err))
}
}
}
// stop vm
// no need to check running status, it may be in a state that requires stopping.
if err := c.guest.Stop(ctx, force); err != nil {
return fmt.Errorf("error stopping vm: %w", err)
}
log.Println("done")
if err := generateSSHConfig(false); err != nil {
log.Trace("error generating ssh_config: %w", err)
}
return nil
}
func (c colimaApp) Delete(data, force bool) error {
confirmContainerDestruction := func() bool {
return cli.Prompt("\033[31m\033[1mthis will delete ALL container data. Are you sure you want to continue")
}
s, _ := store.Load()
diskInUse := s.DiskFormatted
if !force {
y := cli.Prompt("are you sure you want to delete " + config.CurrentProfile().DisplayName + " and all settings")
if !y {
return nil
}
// runtime disk not in use or data deletion is requested,
// deletion deletes all data, warn accordingly.
if !diskInUse || data {
if y := confirmContainerDestruction(); !y {
return nil
}
}
}
ctx := context.Background()
log.Println("deleting", config.CurrentProfile().DisplayName)
// the order for teardown is:
// container teardown -> vm teardown
// vm teardown would've sufficed but container provision
// may have created configurations on the host.
// it is thereby necessary to teardown containers as well.
// teardown container runtimes
if c.guest.Running(ctx) {
containers, err := c.currentContainerEnvironments(ctx)
if err != nil {
log.Warnln(fmt.Errorf("error retrieving runtimes: %w", err))
}
for _, cont := range containers {
log := log.WithField("context", cont.Name())
log.Println("deleting ...")
if err := cont.Teardown(ctx); err != nil {
// failure here is not fatal
log.Warnln(fmt.Errorf("error during teardown of %s: %w", cont.Name(), err))
}
}
}
// teardown vm
if err := c.guest.Teardown(ctx); err != nil {
return fmt.Errorf("error during teardown of vm: %w", err)
}
// delete configs
if err := configmanager.Teardown(); err != nil {
return fmt.Errorf("error deleting configs: %w", err)
}
// delete runtime disk if disk in use and data deletion is requested
if diskInUse && data {
log.Println("deleting container data")
if err := limautil.DeleteDisk(); err != nil {
return fmt.Errorf("error deleting container data: %w", err)
}
if err := store.Reset(); err != nil {
log.Trace("error resetting store: %w", err)
}
}
log.Println("done")
if err := generateSSHConfig(false); err != nil {
log.Trace("error generating ssh_config: %w", err)
}
return nil
}
func (c colimaApp) SSH(args ...string) error {
ctx := context.Background()
if !c.guest.Running(ctx) {
return fmt.Errorf("%s not running", config.CurrentProfile().DisplayName)
}
workDir, err := os.Getwd()
if err != nil {
return fmt.Errorf("error retrieving current working directory: %w", err)
}
// peek the current directory to see if it is mounted to prevent `cd` errors
// with limactl ssh
if err := func() error {
conf, err := configmanager.LoadInstance()
if err != nil {
return err
}
pwd, err := util.CleanPath(workDir)
if err != nil {
return err
}
for _, m := range conf.MountsOrDefault() {
location := m.MountPoint
if location == "" {
location = m.Location
}
location, err := util.CleanPath(location)
if err != nil {
log.Trace(err)
continue
}
if strings.HasPrefix(pwd, location) {
return nil
}
}
return fmt.Errorf("not a mounted directory: %s", workDir)
}(); err != nil {
// the errors returned here is not critical and thereby silenced.
// the goal is to prevent unnecessary warning message from Lima.
log.Trace(fmt.Errorf("error checking if PWD is mounted: %w", err))
workDir = ""
}
guest := lima.New(host.New())
return guest.SSH(workDir, args...)
}
type statusInfo struct {
DisplayName string `json:"display_name"`
Driver string `json:"driver"`
Arch string `json:"arch"`
Runtime string `json:"runtime"`
MountType string `json:"mount_type"`
IPAddress string `json:"ip_address,omitempty"`
DockerSocket string `json:"docker_socket,omitempty"`
ContainerdSocket string `json:"containerd_socket,omitempty"`
BuildkitdSocket string `json:"buildkitd_socket,omitempty"`
IncusSocket string `json:"incus_socket,omitempty"`
Kubernetes bool `json:"kubernetes"`
CPU int `json:"cpu"`
Memory int64 `json:"memory"`
Disk int64 `json:"disk"`
}
func (c colimaApp) getStatus() (status statusInfo, err error) {
ctx := context.Background()
if !c.guest.Running(ctx) {
return status, fmt.Errorf("%s is not running", config.CurrentProfile().DisplayName)
}
currentRuntime, err := c.currentRuntime(ctx)
if err != nil {
return status, err
}
status.DisplayName = config.CurrentProfile().DisplayName
status.Driver = "QEMU"
conf, _ := configmanager.LoadInstance()
if !conf.Empty() {
status.Driver = conf.DriverLabel()
}
status.Arch = string(c.guest.Arch())
status.Runtime = currentRuntime
status.MountType = conf.MountType
ipAddress := limautil.IPAddress(config.CurrentProfile().ID)
if ipAddress != "127.0.0.1" {
status.IPAddress = ipAddress
}
if currentRuntime == docker.Name {
status.DockerSocket = "unix://" + docker.HostSocketFile()
status.ContainerdSocket = "unix://" + containerd.HostSocketFiles().Containerd
}
if currentRuntime == containerd.Name {
status.ContainerdSocket = "unix://" + containerd.HostSocketFiles().Containerd
status.BuildkitdSocket = "unix://" + containerd.HostSocketFiles().Buildkitd
}
if currentRuntime == incus.Name {
status.IncusSocket = "unix://" + incus.HostSocketFile()
}
if k, err := c.Kubernetes(); err == nil && k.Running(ctx) {
status.Kubernetes = true
}
if inst, err := limautil.Instance(); err == nil {
status.CPU = inst.CPU
status.Memory = inst.Memory
status.Disk = inst.Disk
}
return status, nil
}
func (c colimaApp) Status(extended bool, jsonOutput bool) error {
status, err := c.getStatus()
if err != nil {
return err
}
if jsonOutput {
if err := json.NewEncoder(os.Stdout).Encode(status); err != nil {
return fmt.Errorf("error encoding status as json: %w", err)
}
} else {
log.Println(config.CurrentProfile().DisplayName, "is running using", status.Driver)
log.Println("arch:", status.Arch)
log.Println("runtime:", status.Runtime)
if status.MountType != "" {
log.Println("mountType:", status.MountType)
}
// ip address
if status.IPAddress != "" {
log.Println("address:", status.IPAddress)
}
// docker socket
if status.DockerSocket != "" {
log.Println("docker socket:", status.DockerSocket)
}
if status.ContainerdSocket != "" {
log.Println("containerd socket:", status.ContainerdSocket)
}
if status.BuildkitdSocket != "" {
log.Println("buildkitd socket:", status.BuildkitdSocket)
}
if status.IncusSocket != "" {
log.Println("incus socket:", status.IncusSocket)
}
// kubernetes
if status.Kubernetes {
log.Println("kubernetes: enabled")
}
// additional details
if extended {
if status.CPU > 0 {
log.Println("cpu:", status.CPU)
}
if status.Memory > 0 {
log.Println("mem:", units.BytesSize(float64(status.Memory)))
}
if status.Disk > 0 {
log.Println("disk:", units.BytesSize(float64(status.Disk)))
}
}
}
return nil
}
func (c colimaApp) Version() error {
ctx := context.Background()
if !c.guest.Running(ctx) {
return nil
}
containerRuntimes, err := c.currentContainerEnvironments(ctx)
if err != nil {
return err
}
var kube environment.Container
for _, cont := range containerRuntimes {
if cont.Name() == kubernetes.Name {
kube = cont
continue
}
fmt.Println()
fmt.Println("runtime:", cont.Name())
fmt.Println("arch:", c.guest.Arch())
fmt.Println(cont.Version(ctx))
}
if kube != nil && kube.Version(ctx) != "" {
fmt.Println()
fmt.Println(kubernetes.Name)
fmt.Println(kube.Version(ctx))
}
return nil
}
func (c colimaApp) currentRuntime(ctx context.Context) (string, error) {
if !c.guest.Running(ctx) {
return "", fmt.Errorf("%s is not running", config.CurrentProfile().DisplayName)
}
r := c.guest.Get(environment.ContainerRuntimeKey)
if r == "" {
return "", fmt.Errorf("error retrieving current runtime: empty value")
}
return r, nil
}
func (c colimaApp) setRuntime(runtime string) error {
err := store.Set(func(s *store.Store) {
// update runtime if runtime disk is in use
if s.DiskFormatted {
s.DiskRuntime = runtime
}
})
if err != nil {
log.Traceln(fmt.Errorf("error persisting store: %w", err))
}
return c.guest.Set(environment.ContainerRuntimeKey, runtime)
}
func (c colimaApp) setKubernetes(conf config.Kubernetes) error {
b, err := json.Marshal(conf)
if err != nil {
return err
}
return c.guest.Set(kubernetes.ConfigKey, string(b))
}
func (c colimaApp) currentContainerEnvironments(ctx context.Context) ([]environment.Container, error) {
var containers []environment.Container
// runtime
{
runtime, err := c.currentRuntime(ctx)
if err != nil {
return nil, err
}
if environment.IsNoneRuntime(runtime) {
return nil, nil
}
env, err := c.containerEnvironment(runtime)
if err != nil {
return nil, err
}
containers = append(containers, env)
}
// detect and add kubernetes
if k, err := c.containerEnvironment(kubernetes.Name); err == nil && k.Running(ctx) {
containers = append(containers, k)
}
return containers, nil
}
func (c colimaApp) containerEnvironment(runtime string) (environment.Container, error) {
env, err := environment.NewContainer(runtime, c.guest.Host(), c.guest)
if err != nil {
return nil, fmt.Errorf("error initiating container runtime: %w", err)
}
if err := host.IsInstalled(env); err != nil {
return nil, fmt.Errorf("dependency check failed for %s: %w", runtime, err)
}
return env, nil
}
func (c colimaApp) Runtime() (string, error) {
return c.currentRuntime(context.Background())
}
func (c colimaApp) Kubernetes() (environment.Container, error) {
return c.containerEnvironment(kubernetes.Name)
}
func (c colimaApp) Active() bool {
return c.guest.Running(context.Background())
}
func (c *colimaApp) Update() error {
ctx := context.Background()
if !c.guest.Running(ctx) {
return fmt.Errorf("runtime cannot be updated, %s is not running", config.CurrentProfile().DisplayName)
}
runtime, err := c.currentRuntime(ctx)
if err != nil {
return err
}
container, err := c.containerEnvironment(runtime)
if err != nil {
return err
}
oldVersion := container.Version(ctx)
updated, err := container.Update(ctx)
if err != nil {
return err
}
if updated {
fmt.Println()
fmt.Println("Previous")
fmt.Println(oldVersion)
fmt.Println()
fmt.Println("Current")
fmt.Println(container.Version(ctx))
}
return nil
}
func generateSSHConfig(modifySSHConfig bool) error {
instances, err := limautil.Instances()
if err != nil {
return fmt.Errorf("error retrieving instances: %w", err)
}
var buf bytes.Buffer
for _, i := range instances {
if !i.Running() {
continue
}
profile := config.ProfileFromName(i.Name)
resp, err := limautil.ShowSSH(profile.ID)
if err != nil {
log.Trace(fmt.Errorf("error retrieving SSH config for '%s': %w", i.Name, err))
continue
}
fmt.Fprintln(&buf, resp.Output)
}
sshFileColima := config.SSHConfigFile()
if err := os.WriteFile(sshFileColima, buf.Bytes(), 0644); err != nil {
return fmt.Errorf("error writing ssh_config file: %w", err)
}
if !modifySSHConfig {
// ~/.ssh/config modification disabled
return nil
}
includeLine := "Include " + sshFileColima
sshFileSystem := filepath.Join(util.HomeDir(), ".ssh", "config")
// include the SSH config file if not included
// if ssh file missing, the only content will be the include
if _, err := os.Stat(sshFileSystem); err != nil {
if err := os.MkdirAll(filepath.Dir(sshFileSystem), 0700); err != nil {
return fmt.Errorf("error creating ssh directory: %w", err)
}
if err := os.WriteFile(sshFileSystem, []byte(includeLine), 0644); err != nil {
return fmt.Errorf("error modifying %s: %w", sshFileSystem, err)
}
return nil
}
sshContent, err := os.ReadFile(sshFileSystem)
if err != nil {
return fmt.Errorf("error reading ssh config: %w", err)
}
scanner := bufio.NewScanner(bytes.NewReader(sshContent))
for scanner.Scan() {
words := strings.Fields(scanner.Text())
// empty line
if len(words) == 0 {
continue
}
// comment
if strings.HasPrefix(words[0], "#") {
continue
}
// not an include line
if len(words) < 2 {
continue
}
if words[0] == "Include" {
sshConfig := words[1]
sshConfig = strings.Replace(sshConfig, "~/", "$HOME/", 1)
sshConfig = os.ExpandEnv(sshConfig)
if sshConfig == sshFileColima {
// already present
return nil
}
}
}
// not found, prepend file
if err := os.WriteFile(sshFileSystem, []byte(includeLine+"\n\n"+string(sshContent)), 0644); err != nil {
return fmt.Errorf("error modifying %s: %w", sshFileSystem, err)
}
return nil
}
================================================
FILE: cli/chain.go
================================================
package cli
import (
"context"
"fmt"
"io"
"time"
log "github.com/sirupsen/logrus"
)
// CtxKeyQuiet is the context key to mute the chain.
var CtxKeyQuiet = struct{ key string }{key: "quiet"}
// errNonFatal is a non fatal error
type errNonFatal struct {
err error
}
// Error implements error
func (e errNonFatal) Error() string { return e.err.Error() }
// ErrNonFatal creates a non-fatal error for a command chain.
// A warning would be printed instead of terminating the chain.
func ErrNonFatal(err error) error {
return errNonFatal{err}
}
// New creates a new runner instance.
func New(name string) CommandChain {
return &namedCommandChain{
name: name,
}
}
type cFunc struct {
f func() error
s string
}
// CommandChain is a chain of commands.
// commands are executed in order.
type CommandChain interface {
// Init initiates a new runner using the current instance.
Init(ctx context.Context) *ActiveCommandChain
// Logger returns the instance logger.
Logger(ctx context.Context) *log.Entry
}
var _ CommandChain = (*namedCommandChain)(nil)
type namedCommandChain struct {
name string
log *log.Entry
}
func (n *namedCommandChain) Logger(ctx context.Context) *log.Entry {
if quiet, _ := ctx.Value(CtxKeyQuiet).(bool); quiet {
l := log.New()
l.SetOutput(io.Discard)
return l.WithContext(ctx)
}
if n.log == nil {
n.log = log.WithField("context", n.name).WithContext(ctx)
}
return n.log
}
func (n *namedCommandChain) Init(ctx context.Context) *ActiveCommandChain {
return &ActiveCommandChain{
log: n.Logger(ctx),
}
}
// ActiveCommandChain is an active command chain.
type ActiveCommandChain struct {
funcs []cFunc
lastStage string
log *log.Entry
executing bool
}
// Logger returns the logger for the command chain.
func (a *ActiveCommandChain) Logger() *log.Entry { return a.log }
// Add adds a new function to the runner.
func (a *ActiveCommandChain) Add(f func() error) {
a.funcs = append(a.funcs, cFunc{f: f})
}
// Stage sets the current stage of the runner.
func (a *ActiveCommandChain) Stage(s string) {
if a.executing {
a.log.Println(s, "...")
return
}
a.funcs = append(a.funcs, cFunc{s: s})
}
// Stagef is like stage with string format.
func (a *ActiveCommandChain) Stagef(format string, s ...any) {
f := fmt.Sprintf(format, s...)
a.Stage(f)
}
// Exec executes the command chain.
// The first errored function terminates the chain and the
// error is returned. Otherwise, returns nil.
func (a *ActiveCommandChain) Exec() error {
a.executing = true
defer func() { a.executing = false }()
for _, f := range a.funcs {
if f.f == nil {
if f.s != "" {
a.log.Println(f.s, "...")
a.lastStage = f.s
}
continue
}
// success
err := f.f()
if err == nil {
continue
}
// warning
if _, ok := err.(errNonFatal); ok {
if a.lastStage == "" {
a.log.Warnln(err)
} else {
a.log.Warnln(fmt.Errorf("error at '%s': %w", a.lastStage, err))
}
continue
}
// error
if a.lastStage == "" {
return err
}
return fmt.Errorf("error at '%s': %w", a.lastStage, err)
}
return nil
}
// Retry retries `f` up to `count` times at interval.
// If after `count` attempts there is an error, the command chain is terminated with the final error.
// retryCount starts from 1.
func (a *ActiveCommandChain) Retry(stage string, interval time.Duration, count int, f func(retryCount int) error) {
a.Add(func() (err error) {
var i int
for err = f(i + 1); i < count && err != nil; i, err = i+1, f(i+1) {
if stage != "" {
a.log.Println(stage, "...")
}
time.Sleep(interval)
}
return err
})
}
================================================
FILE: cli/command.go
================================================
package cli
import (
"fmt"
"os"
"os/exec"
"strconv"
log "github.com/sirupsen/logrus"
)
var runner commandRunner = &defaultCommandRunner{}
// Settings is global cli settings
var Settings = struct {
// Verbose toggles verbose output for commands.
Verbose bool
}{}
// Command creates a new command.
func Command(command string, args ...string) *exec.Cmd { return runner.Command(command, args...) }
// CommandInteractive creates a new interactive command.
func CommandInteractive(command string, args ...string) *exec.Cmd {
return runner.CommandInteractive(command, args...)
}
type commandRunner interface {
Command(command string, args ...string) *exec.Cmd
CommandInteractive(command string, args ...string) *exec.Cmd
}
var _ commandRunner = (*defaultCommandRunner)(nil)
type defaultCommandRunner struct{}
func (d defaultCommandRunner) Command(command string, args ...string) *exec.Cmd {
cmd := exec.Command(command, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Trace("cmd ", quotedArgs(cmd.Args))
return cmd
}
func (d defaultCommandRunner) CommandInteractive(command string, args ...string) *exec.Cmd {
cmd := exec.Command(command, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Trace("cmd int ", quotedArgs(cmd.Args))
return cmd
}
func quotedArgs(args []string) string {
var q []string
for _, s := range args {
q = append(q, strconv.Quote(s))
}
return fmt.Sprintf("%v", q)
}
// Prompt prompts for input with a question. It returns true only if answer is y or Y.
func Prompt(question string) bool {
fmt.Print(question)
fmt.Print("? [y/N] ")
fmt.Print("\033[0m") // reset all formatting modes (if any) used by the question string
var answer string
_, _ = fmt.Scanln(&answer)
if answer == "" {
return false
}
return answer[0] == 'Y' || answer[0] == 'y'
}
================================================
FILE: cmd/clone.go
================================================
package cmd
import (
"fmt"
"os"
"path/filepath"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// stopCmd represents the stop command
var cloneCmd = &cobra.Command{
Use: "clone <profile> <new-profile>",
Short: "clone Colima profile",
Long: `Clone the Colima profile.`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
from := config.ProfileFromName(args[0])
to := config.ProfileFromName(args[1])
logrus.Infof("preparing to clone %s...", from.DisplayName)
{
// verify source profile exists
if stat, err := os.Stat(from.LimaInstanceDir()); err != nil || !stat.IsDir() {
return fmt.Errorf("colima profile '%s' does not exist", from.ShortName)
}
// verify destination profile does not exists
if stat, err := os.Stat(to.LimaInstanceDir()); err == nil && stat.IsDir() {
return fmt.Errorf("colima profile '%s' already exists, delete with `colima delete %s` and try again", to.ShortName, to.ShortName)
}
// copy source to destination
logrus.Info("cloning virtual machine...")
if err := cli.Command("mkdir", "-p", to.LimaInstanceDir()).Run(); err != nil {
return fmt.Errorf("error preparing to copy VM: %w", err)
}
if err := cli.Command("cp",
filepath.Join(from.LimaInstanceDir(), "basedisk"),
filepath.Join(from.LimaInstanceDir(), "diffdisk"),
filepath.Join(from.LimaInstanceDir(), "cidata.iso"),
filepath.Join(from.LimaInstanceDir(), "lima.yaml"),
to.LimaInstanceDir(),
).Run(); err != nil {
return fmt.Errorf("error copying VM: %w", err)
}
}
{
logrus.Info("copying config...")
// verify source config exists
if _, err := os.Stat(from.LimaInstanceDir()); err != nil {
return fmt.Errorf("config missing for colima profile '%s': %w", from.ShortName, err)
}
// ensure destination config directory
if err := cli.Command("mkdir", "-p", filepath.Dir(to.LimaInstanceDir())).Run(); err != nil {
return fmt.Errorf("cannot copy config to new profile '%s': %w", to.ShortName, err)
}
if err := cli.Command("cp", from.LimaInstanceDir(), to.LimaInstanceDir()).Run(); err != nil {
return fmt.Errorf("error copying VM config: %w", err)
}
}
logrus.Info("clone successful")
logrus.Infof("run `colima start %s` to start the newly cloned profile", to.ShortName)
return nil
},
}
func init() {
root.Cmd().AddCommand(cloneCmd)
cloneCmd.Hidden = true
}
================================================
FILE: cmd/colima/main.go
================================================
package main
import (
_ "github.com/abiosoft/colima/cmd" // for other commands
_ "github.com/abiosoft/colima/cmd/daemon" // for vmnet daemon
_ "github.com/abiosoft/colima/embedded" // for embedded assets
"github.com/abiosoft/colima/cmd/root"
)
func main() {
root.Execute()
}
================================================
FILE: cmd/completion.go
================================================
package cmd
import (
"os"
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)
// completionCmd represents the completion command
func completionCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Long: `To load completions:
Bash:
$ source <(colima completion bash)
# To load completions for each session, execute once:
# Linux:
$ colima completion bash > /etc/bash_completion.d/colima
# macOS:
$ colima completion bash > /usr/local/etc/bash_completion.d/colima
Zsh:
# If shell completion is not already enabled in your environment,
# you will need to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ colima completion zsh > "${fpath[1]}/_colima"
# You will need to start a new shell for this setup to take effect.
fish:
$ colima completion fish | source
# To load completions for each session, execute once:
$ colima completion fish > ~/.config/fish/completions/colima.fish
PowerShell:
PS> colima completion powershell | Out-String | Invoke-Expression
# To load completions for every new session, run:
PS> colima completion powershell > colima.ps1
# and source this file from your PowerShell profile.
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "bash":
_ = cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
_ = cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
_ = cmd.Root().GenFishCompletion(os.Stdout, true)
case "powershell":
_ = cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
}
},
}
return cmd
}
func init() {
root.Cmd().AddCommand(completionCmd())
}
================================================
FILE: cmd/daemon/cmd.go
================================================
package daemon
import (
"context"
"time"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/daemon/process/inotify"
"github.com/abiosoft/colima/daemon/process/vmnet"
"github.com/abiosoft/colima/environment/host"
"github.com/abiosoft/colima/environment/vm/lima"
"github.com/spf13/cobra"
)
var daemonCmd = &cobra.Command{
Use: "daemon",
Short: "daemon",
Long: `runner for background daemons.`,
Hidden: true,
}
var startCmd = &cobra.Command{
Use: "start [profile]",
Short: "start daemon",
Long: `start the daemon`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
config.SetProfile(args[0])
ctx := cmd.Context()
var processes []process.Process
if daemonArgs.vmnet.enabled {
processes = append(processes, vmnet.New(daemonArgs.vmnet.mode, daemonArgs.vmnet.netInterface))
}
if daemonArgs.inotify.enabled {
processes = append(processes, inotify.New())
guest := lima.New(host.New())
args := inotify.Args{
GuestActions: guest,
Runtime: daemonArgs.inotify.runtime,
Dirs: daemonArgs.inotify.dirs,
}
ctx = context.WithValue(ctx, inotify.CtxKeyArgs(), args)
}
return start(ctx, processes)
},
}
var stopCmd = &cobra.Command{
Use: "stop [profile]",
Short: "stop daemon",
Long: `stop the daemon`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
config.SetProfile(args[0])
// wait for 60 seconds
timeout := time.Second * 60
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return stop(ctx)
},
}
var statusCmd = &cobra.Command{
Use: "status",
Short: "status of the daemon",
Long: `status of the daemon`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
config.SetProfile(args[0])
return status()
},
}
var daemonArgs struct {
vmnet struct {
enabled bool
mode string
netInterface string
}
inotify struct {
enabled bool
dirs []string
runtime string
}
verbose bool
}
func init() {
root.Cmd().AddCommand(daemonCmd)
daemonCmd.AddCommand(startCmd)
daemonCmd.AddCommand(stopCmd)
daemonCmd.AddCommand(statusCmd)
startCmd.Flags().BoolVar(&daemonArgs.vmnet.enabled, "vmnet", false, "start vmnet")
startCmd.Flags().StringVar(&daemonArgs.vmnet.mode, "vmnet-mode", "shared", "vmnet mode (shared, bridged)")
startCmd.Flags().StringVar(&daemonArgs.vmnet.netInterface, "vmnet-interface", "en0", "vmnet interface for bridged mode")
startCmd.Flags().BoolVar(&daemonArgs.inotify.enabled, "inotify", false, "start inotify")
startCmd.Flags().StringSliceVar(&daemonArgs.inotify.dirs, "inotify-dir", nil, "set inotify directories")
startCmd.Flags().StringVar(&daemonArgs.inotify.runtime, "inotify-runtime", "docker", "set runtime")
}
================================================
FILE: cmd/daemon/daemon.go
================================================
package daemon
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"strconv"
"sync"
"syscall"
"time"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/util/fsutil"
godaemon "github.com/sevlyar/go-daemon"
"github.com/sirupsen/logrus"
)
var dir = process.Dir
// daemonize creates the daemon and returns if this is a child process
func daemonize() (ctx *godaemon.Context, child bool, err error) {
dir := dir()
if err := fsutil.MkdirAll(dir, 0755); err != nil {
return nil, false, fmt.Errorf("cannot make dir: %w", err)
}
info := Info()
ctx = &godaemon.Context{
PidFileName: info.PidFile,
PidFilePerm: 0644,
LogFileName: info.LogFile,
LogFilePerm: 0644,
}
d, err := ctx.Reborn()
if err != nil {
return ctx, false, fmt.Errorf("error starting daemon: %w", err)
}
if d != nil {
return ctx, false, nil
}
logrus.Info("- - - - - - - - - - - - - - -")
logrus.Info("daemon started by colima")
logrus.Infof("Run `/usr/bin/pkill -F %s` to kill the daemon", info.PidFile)
return ctx, true, nil
}
func start(ctx context.Context, processes []process.Process) error {
if status() == nil {
logrus.Info("daemon already running, startup ignored")
return nil
}
{
ctx, child, err := daemonize()
if err != nil {
return err
}
if ctx != nil {
defer func() {
_ = ctx.Release()
}()
}
if !child {
return nil
}
}
ctx, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
defer stop()
return RunProcesses(ctx, processes...)
}
func stop(ctx context.Context) error {
if status() != nil {
// not running
return nil
}
info := Info()
if err := cli.CommandInteractive("/usr/bin/pkill", "-F", info.PidFile).Run(); err != nil {
return fmt.Errorf("error sending sigterm to daemon: %w", err)
}
logrus.Info("waiting for process to terminate")
for {
alive := status() == nil
if !alive {
return nil
}
select {
case <-ctx.Done():
return ctx.Err()
default:
time.Sleep(time.Second * 1)
}
}
}
func status() error {
info := Info()
if _, err := os.Stat(info.PidFile); err != nil {
return fmt.Errorf("pid file not found: %w", err)
}
// check if process is actually running
p, err := os.ReadFile(info.PidFile)
if err != nil {
return fmt.Errorf("error reading pid file: %w", err)
}
pid, _ := strconv.Atoi(string(p))
if pid == 0 {
return fmt.Errorf("invalid pid: %v", string(p))
}
process, err := os.FindProcess(pid)
if err != nil {
return fmt.Errorf("process not found: %v", err)
}
if err := process.Signal(syscall.Signal(0)); err != nil {
return fmt.Errorf("process signal(0) returned error: %w", err)
}
return nil
}
const (
pidFileName = "daemon.pid"
logFileName = "daemon.log"
)
func Info() struct {
PidFile string
LogFile string
} {
dir := dir()
return struct {
PidFile string
LogFile string
}{
PidFile: filepath.Join(dir, pidFileName),
LogFile: filepath.Join(dir, logFileName),
}
}
// Run runs the daemon with background processes.
// NOTE: this must be called from the program entrypoint with minimal intermediary logic
// due to the creation of the daemon.
func RunProcesses(ctx context.Context, processes ...process.Process) error {
ctx, stop := context.WithCancel(ctx)
defer stop()
var wg sync.WaitGroup
wg.Add(len(processes))
for _, bg := range processes {
go func(bg process.Process) {
err := bg.Start(ctx)
if err != nil {
logrus.Error(fmt.Errorf("error starting %s: %w", bg.Name(), err))
stop()
}
wg.Done()
}(bg)
}
<-ctx.Done()
logrus.Info("terminate signal received")
wg.Wait()
return ctx.Err()
}
================================================
FILE: cmd/daemon/daemon_test.go
================================================
package daemon
import (
"context"
"os"
"os/exec"
"testing"
"time"
"github.com/abiosoft/colima/daemon/process"
)
var testDir string
func setDir(t *testing.T) {
if testDir == "" {
testDir = t.TempDir()
}
dir = func() string { return testDir }
}
func getProcesses() []process.Process {
var addresses = []string{
"localhost",
"127.0.0.1",
}
var processes []process.Process
for _, add := range addresses {
processes = append(processes, &pinger{address: add})
}
return processes
}
func TestStart(t *testing.T) {
setDir(t)
info := Info()
processes := getProcesses()
t.Log("pidfile", info.PidFile)
timeout := time.Second * 5
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// start the processes
if err := start(ctx, processes); err != nil {
t.Fatal(err)
}
t.Log("start successful")
{
loop:
for {
select {
case <-ctx.Done():
t.Skipf("daemon not supported: %v", ctx.Err())
default:
if p, err := os.ReadFile(info.PidFile); err == nil && len(p) > 0 {
break loop
} else if err != nil {
t.Logf("encountered err: %v", err)
}
time.Sleep(1 * time.Second)
}
}
}
// verify the processes are running
if err := status(); err != nil {
t.Error(err)
return
}
// stop the processes
if err := stop(ctx); err != nil {
t.Error(err)
}
// verify the processes are no longer running
if err := status(); err == nil {
t.Errorf("process with pidFile %s is still running", info.PidFile)
return
}
}
func TestRunProcesses(t *testing.T) {
processes := getProcesses()
timeout := time.Second * 5
ctx, cancel := context.WithTimeout(context.Background(), timeout)
// start the processes
done := make(chan error, 1)
go func() {
done <- RunProcesses(ctx, processes...)
}()
cancel()
select {
case <-ctx.Done():
if err := ctx.Err(); err != context.Canceled {
t.Error(err)
}
case err := <-done:
t.Error(err)
}
}
var _ process.Process = (*pinger)(nil)
type pinger struct {
address string
}
func (p pinger) Alive(ctx context.Context) error {
return nil
}
// Name implements BgProcess
func (pinger) Name() string { return "pinger" }
// Start implements BgProcess
func (p *pinger) Start(ctx context.Context) error {
return p.run(ctx, "ping", "-c10", p.address)
}
// Start implements BgProcess
func (p *pinger) Dependencies() ([]process.Dependency, bool) { return nil, false }
func (p *pinger) run(ctx context.Context, command string, args ...string) error {
cmd := exec.CommandContext(ctx, command, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
================================================
FILE: cmd/delete.go
================================================
package cmd
import (
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)
var deleteCmdArgs struct {
force bool
data bool
}
// deleteCmd represents the delete command
var deleteCmd = &cobra.Command{
Use: "delete [profile]",
Short: "delete and teardown Colima",
Long: `Delete and teardown Colima and all settings.
Use with caution. This deletes everything and a startup afterwards is like the
initial startup of Colima.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Delete(deleteCmdArgs.data, deleteCmdArgs.force)
},
}
func init() {
root.Cmd().AddCommand(deleteCmd)
deleteCmd.Flags().BoolVarP(&deleteCmdArgs.force, "force", "f", false, "do not prompt for yes/no")
deleteCmd.Flags().BoolVarP(&deleteCmdArgs.data, "data", "d", false, "delete container runtime data")
}
================================================
FILE: cmd/kubernetes.go
================================================
package cmd
import (
"context"
"fmt"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/container/kubernetes"
"github.com/spf13/cobra"
)
// kubernetesCmd represents the kubernetes command
var kubernetesCmd = &cobra.Command{
Use: "kubernetes",
Aliases: []string{"kube", "k8s", "k3s", "k"},
Short: "manage Kubernetes cluster",
Long: `Manage the Kubernetes cluster`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// cobra overrides PersistentPreRunE when redeclared.
// re-run rootCmd's.
if err := root.Cmd().PersistentPreRunE(cmd, args); err != nil {
return err
}
if !newApp().Active() {
return fmt.Errorf("%s is not running", config.CurrentProfile().DisplayName)
}
return nil
},
}
// kubernetesStartCmd represents the kubernetes start command
var kubernetesStartCmd = &cobra.Command{
Use: "start",
Short: "start the Kubernetes cluster",
Long: `Start the Kubernetes cluster.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
app := newApp()
k, err := app.Kubernetes()
if err != nil {
return err
}
if err := k.Provision(context.Background()); err != nil {
return err
}
return k.Start(context.Background())
},
}
// kubernetesStopCmd represents the kubernetes stop command
var kubernetesStopCmd = &cobra.Command{
Use: "stop",
Short: "stop the Kubernetes cluster",
Long: `Stop the Kubernetes cluster.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
app := newApp()
k, err := app.Kubernetes()
if err != nil {
return err
}
if !k.Running(ctx) {
return fmt.Errorf("%s is not enabled", kubernetes.Name)
}
return k.Stop(ctx, false)
},
}
// kubernetesDeleteCmd represents the kubernetes delete command
var kubernetesDeleteCmd = &cobra.Command{
Use: "delete",
Short: "delete the Kubernetes cluster",
Long: `Delete the Kubernetes cluster.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
app := newApp()
k, err := app.Kubernetes()
if err != nil {
return err
}
if !k.Running(ctx) {
return fmt.Errorf("%s is not enabled", kubernetes.Name)
}
return k.Teardown(ctx)
},
}
// kubernetesResetCmd represents the kubernetes reset command
var kubernetesResetCmd = &cobra.Command{
Use: "reset",
Short: "reset the Kubernetes cluster",
Long: `Reset the Kubernetes cluster.
This resets the Kubernetes cluster and all Kubernetes objects
will be deleted.
The Kubernetes images are cached making the startup (after reset) much faster.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
app := newApp()
k, err := app.Kubernetes()
if err != nil {
return err
}
if err := k.Teardown(context.Background()); err != nil {
return fmt.Errorf("error deleting %s: %w", kubernetes.Name, err)
}
ctx := context.Background()
if err := k.Provision(ctx); err != nil {
return err
}
if err := k.Start(ctx); err != nil {
return fmt.Errorf("error starting %s: %w", kubernetes.Name, err)
}
return nil
},
}
func init() {
root.Cmd().AddCommand(kubernetesCmd)
kubernetesCmd.AddCommand(kubernetesStartCmd)
kubernetesCmd.AddCommand(kubernetesStopCmd)
kubernetesCmd.AddCommand(kubernetesDeleteCmd)
kubernetesCmd.AddCommand(kubernetesResetCmd)
}
================================================
FILE: cmd/list.go
================================================
package cmd
import (
"encoding/json"
"fmt"
"text/tabwriter"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var listCmdArgs struct {
json bool
}
// listCmd represents the version command
var listCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "list instances",
Long: `List all created instances.
A new instance can be created during 'colima start' by specifying the '--profile' flag.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
profile := config.CurrentProfile()
profileArgs := []string{}
if profile.Changed {
profileArgs = append(profileArgs, profile.ID)
}
instances, err := limautil.Instances(profileArgs...)
if err != nil {
return err
}
if listCmdArgs.json {
encoder := json.NewEncoder(cmd.OutOrStdout())
// print instance per line to conform with Lima's output
for _, instance := range instances {
// dir should be hidden from the output
instance.Dir = ""
if err := encoder.Encode(instance); err != nil {
return err
}
}
return nil
}
w := tabwriter.NewWriter(cmd.OutOrStdout(), 4, 8, 4, ' ', 0)
_, _ = fmt.Fprintln(w, "PROFILE\tSTATUS\tARCH\tCPUS\tMEMORY\tDISK\tRUNTIME\tADDRESS")
if len(instances) == 0 {
logrus.Warn("No instance found. Run `colima start` to create an instance.")
}
for _, inst := range instances {
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%s\n",
inst.Name,
inst.Status,
inst.Arch,
inst.CPU,
units.BytesSize(float64(inst.Memory)),
units.BytesSize(float64(inst.Disk)),
inst.Runtime,
inst.IPAddress,
)
}
return w.Flush()
},
}
func init() {
root.Cmd().AddCommand(listCmd)
listCmd.Flags().BoolVarP(&listCmdArgs.json, "json", "j", false, "print json output")
}
================================================
FILE: cmd/model.go
================================================
package cmd
import (
"fmt"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config/configmanager"
"github.com/abiosoft/colima/model"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/terminal"
"github.com/spf13/cobra"
)
// modelCmdArgs holds command-line flags for the model command.
var modelCmdArgs struct {
Runner string
ServePort int
}
// modelCmd represents the model command
var modelCmd = &cobra.Command{
Use: "model",
Short: "manage AI models (requires docker runtime and krunkit VM type)",
Long: `Manage AI models inside the VM.
This requires docker runtime and krunkit VM type for GPU access.
Use --runner to select the model runner:
- docker: Docker Model Runner (default)
- ramalama: Ramalama
All arguments are passed to the selected AI model runner.
Specifying '--' will pass arguments to the underlying tool.
Examples:
colima model list
colima model pull ai/smollm2
colima model run ai/smollm2
colima model serve
colima model serve ai/smollm2 --port 8080
Multiple registries are supported.
`,
PreRunE: func(cmd *cobra.Command, args []string) error {
runner, err := getModelRunner()
if err != nil {
return err
}
return runner.ValidatePrerequisites(newApp())
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Help()
}
runner, err := getModelRunner()
if err != nil {
return err
}
a := newApp()
if err := runner.EnsureProvisioned(); err != nil {
return err
}
runnerArgs, err := runner.BuildArgs(args)
if err != nil {
return err
}
return a.SSH(runnerArgs...)
},
}
// modelSetupCmd reinstalls the model runner in the VM.
var modelSetupCmd = &cobra.Command{
Use: "setup",
Short: "install or update AI model runner in the VM",
Long: `Install or update AI model runner and its dependencies in the VM.`,
Aliases: []string{"update"},
PreRunE: func(cmd *cobra.Command, args []string) error {
runner, err := getModelRunner()
if err != nil {
return err
}
return runner.ValidatePrerequisites(newApp())
},
RunE: func(cmd *cobra.Command, args []string) error {
runner, err := getModelRunner()
if err != nil {
return err
}
// Check if setup is needed (on primary screen)
status, err := runner.CheckSetup()
if err != nil {
return err
}
// Print version info on primary screen
fmt.Println(runner.DisplayName())
if status.CurrentVersion != "" {
fmt.Printf("current: %s\n", status.CurrentVersion)
}
if status.LatestVersion != "" {
fmt.Printf("latest: %s\n", status.LatestVersion)
}
if !status.NeedsSetup {
fmt.Println()
fmt.Println("Already up to date")
return nil
}
// Build header for alternate screen
separator := "────────────────────────────────────────"
header := fmt.Sprintf("Colima - %s Setup\n%s", runner.DisplayName(), separator)
// Run setup in alternate screen
if err := terminal.WithAltScreen(func() error {
return runner.Setup()
}, header); err != nil {
return err
}
// Print new version on primary screen after update
if newVersion := runner.GetCurrentVersion(); newVersion != "" {
fmt.Printf("updated: %s\n", newVersion)
}
return nil
},
}
// modelServeCmd serves a model API.
var modelServeCmd = &cobra.Command{
Use: "serve [model]",
Short: "serve a model API",
Long: `Serve a model API.
This starts a model server providing:
- OpenAI-compatible API at http://localhost:<port>/v1
- Web UI for chat at http://localhost:<port>
Press Ctrl-C to stop the server.
`,
Args: cobra.MaximumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
runner, err := getModelRunner()
if err != nil {
return err
}
return runner.ValidatePrerequisites(newApp())
},
RunE: func(cmd *cobra.Command, args []string) error {
runner, err := getModelRunner()
if err != nil {
return err
}
// Determine the model to serve
var modelName string
if len(args) > 0 {
modelName = args[0]
} else if runner.Name() == model.RunnerDocker {
// For docker runner, get the first available model
firstModel, err := model.GetFirstModel()
if err != nil {
return err
}
if firstModel == "" {
return fmt.Errorf("no models available\nPull a model first: colima model pull ai/smollm2")
}
modelName = firstModel
} else {
return fmt.Errorf("model name is required for ramalama runner\nUsage: colima model serve <model>")
}
if err := runner.EnsureProvisioned(); err != nil {
return err
}
// Ensure the model is available (pull if necessary) - this happens outside alternate screen
normalizedModel, err := runner.EnsureModel(modelName)
if err != nil {
return err
}
// Determine the port to use
port := modelCmdArgs.ServePort
portExplicitlySet := cmd.Flags().Changed("port")
// If port was not explicitly set, find an available port starting from the default
const maxPortAttempts = 20
if !portExplicitlySet {
availablePort, found := util.FindAvailablePort(port, maxPortAttempts)
if !found {
return fmt.Errorf("no available port found in range %d-%d", port, port+maxPortAttempts-1)
}
if availablePort != port {
fmt.Printf("Port %d is in use, using port %d instead\n", port, availablePort)
}
port = availablePort
} else {
// User explicitly set the port, check if it's available
if _, found := util.FindAvailablePort(port, 1); !found {
return fmt.Errorf("port %d is already in use", port)
}
}
// Build header for alternate screen
separator := "────────────────────────────────────────"
header := fmt.Sprintf("Colima - Model Server (Ctrl-C to stop)\nWeb UI & API at http://localhost:%d\n%s", port, separator)
// Run in alternate screen with header
return terminal.WithAltScreen(func() error {
return runner.Serve(normalizedModel, port)
}, header)
},
}
func init() {
root.Cmd().AddCommand(modelCmd)
modelCmd.AddCommand(modelSetupCmd)
modelCmd.AddCommand(modelServeCmd)
// Add --runner flag with default from config or ramalama
modelCmd.PersistentFlags().StringVar(&modelCmdArgs.Runner, "runner", "", "AI model runner (docker, ramalama)")
// Add --port flag for serve command
modelServeCmd.Flags().IntVar(&modelCmdArgs.ServePort, "port", 8080, "port for the web UI")
}
// getModelRunner returns the appropriate runner based on flag or config.
func getModelRunner() (model.Runner, error) {
runnerType := modelCmdArgs.Runner
// If not specified via flag, check instance config
if runnerType == "" {
if conf, err := configmanager.LoadInstance(); err == nil && conf.ModelRunner != "" {
runnerType = conf.ModelRunner
}
}
// Default to docker
if runnerType == "" {
runnerType = string(model.RunnerDocker)
}
return model.GetRunner(model.RunnerType(runnerType))
}
================================================
FILE: cmd/nerdctl.go
================================================
package cmd
import (
"bytes"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/container/containerd"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/fsutil"
"github.com/abiosoft/colima/util/osutil"
"github.com/spf13/cobra"
)
var nerdctlCmdArgs struct {
force bool
path string
usrBinWriteable bool
isColimaScript bool
}
// nerdctlCmd represents the nerdctl command
var nerdctlCmd = &cobra.Command{
Use: "nerdctl",
Aliases: []string{"nerd", "n"},
Short: "run nerdctl (requires containerd runtime)",
Long: `Run nerdctl to interact with containerd.
This requires containerd runtime.
It is recommended to specify '--' to differentiate from Colima flags.
`,
RunE: func(cmd *cobra.Command, args []string) error {
app := newApp()
r, err := app.Runtime()
if err != nil {
return err
}
if r != containerd.Name {
return fmt.Errorf("nerdctl only supports %s runtime", containerd.Name)
}
// collect CONTAINERD_* and NERDCTL_* environment variables from the host
var envVars []string
for _, env := range os.Environ() {
if strings.HasPrefix(env, "CONTAINERD_") || strings.HasPrefix(env, "NERDCTL_") {
envVars = append(envVars, env)
}
}
var nerdctlArgs []string
if len(envVars) > 0 {
// use 'sudo env VAR=value ... nerdctl' to pass environment variables
nerdctlArgs = append([]string{"sudo", "env"}, envVars...)
nerdctlArgs = append(nerdctlArgs, "nerdctl")
} else {
nerdctlArgs = []string{"sudo", "nerdctl"}
}
nerdctlArgs = append(nerdctlArgs, args...)
return app.SSH(nerdctlArgs...)
},
}
// nerdctlLinkFunc represents the nerdctl command
var nerdctlLinkFunc = func() *cobra.Command {
return &cobra.Command{
Use: "install",
Short: "install nerdctl alias script on the host",
Long: `Install nerdctl alias script on the host. The script will be installed at ` + nerdctlDefaultInstallPath + `.`,
Args: cobra.NoArgs,
PreRun: func(cmd *cobra.Command, args []string) {
// check if /usr/local/bin is writeable and no need for sudo
// if the path is user-specified, ignore.
if nerdctlCmdArgs.path != nerdctlDefaultInstallPath {
return
}
// attempt writing to the /usr/local/bin
tmpFile := filepath.Join(filepath.Dir(nerdctlDefaultInstallPath), "colima.tmp")
if err := os.WriteFile(tmpFile, []byte("tmp"), 0777); err == nil {
nerdctlCmdArgs.usrBinWriteable = true
_ = os.Remove(tmpFile)
}
// check if the current file (if exists) is generated by colima
// in such case no need for confirmation before overwrite
// TODO: this is too basic, should be better
if b, err := os.ReadFile(nerdctlCmdArgs.path); err == nil {
if strings.Contains(string(b), "colima nerdctl ") {
nerdctlCmdArgs.isColimaScript = true
}
}
},
RunE: func(cmd *cobra.Command, args []string) error {
exists := false
if _, err := os.Stat(nerdctlCmdArgs.path); err == nil && !nerdctlCmdArgs.force && !nerdctlCmdArgs.isColimaScript {
return fmt.Errorf("%s exists, use --force to replace", nerdctlCmdArgs.path)
} else if err == nil {
exists = true
}
var values = struct {
ColimaApp string
Profile string
}{
ColimaApp: osutil.Executable(),
Profile: config.CurrentProfile().ShortName,
}
buf, err := util.ParseTemplate(nerdctlScript, values)
if err != nil {
return fmt.Errorf("error applying nerdctl script template: %w", err)
}
// /usr/local/bin writeable i.e. sudo not needed
// or user-specified install path, we assume user specified path is writeable
if nerdctlCmdArgs.usrBinWriteable || nerdctlCmdArgs.path != nerdctlDefaultInstallPath {
if exists {
if err := os.Rename(nerdctlCmdArgs.path, nerdctlCmdArgs.path+".moved"); err != nil {
return fmt.Errorf("error backing up existing file: %w", err)
}
}
if err := fsutil.MkdirAll("/usr/local/bin", 0755); err != nil {
return nil
}
return os.WriteFile(nerdctlCmdArgs.path, buf, 0755)
}
// sudo is needed for the default path
log.Println("/usr/local/bin not writable, sudo password required to install nerdctl binary")
if exists && !nerdctlCmdArgs.isColimaScript {
c := cli.CommandInteractive("sudo", "mv", nerdctlCmdArgs.path, nerdctlCmdArgs.path+".moved")
if err := c.Run(); err != nil {
return fmt.Errorf("error backing up existing file: %w", err)
}
}
// prepare dir
{
c := cli.CommandInteractive("sudo", "mkdir", "-p", "/usr/local/bin")
if err := c.Run(); err != nil {
return err
}
}
// install script
{
c := cli.CommandInteractive("sudo", "sh", "-c", "cat > "+nerdctlCmdArgs.path)
c.Stdin = bytes.NewReader(buf)
if err := c.Run(); err != nil {
return err
}
}
// ensure it is executable
if err := cli.Command("sudo", "chmod", "+x", nerdctlCmdArgs.path).Run(); err != nil {
return err
}
return nil
},
}
}
const nerdctlDefaultInstallPath = "/usr/local/bin/nerdctl"
const nerdctlScript = `#!/usr/bin/env sh
{{.ColimaApp}} nerdctl --profile {{.Profile}} -- "$@"
`
func init() {
root.Cmd().AddCommand(nerdctlCmd)
nerdctlLink := nerdctlLinkFunc()
nerdctlCmd.AddCommand(nerdctlLink)
nerdctlLink.Flags().BoolVarP(&nerdctlCmdArgs.force, "force", "f", false, "replace "+nerdctlDefaultInstallPath+" (if exists)")
nerdctlLink.Flags().StringVar(&nerdctlCmdArgs.path, "path", nerdctlDefaultInstallPath, "path to install nerdctl binary")
}
================================================
FILE: cmd/prune.go
================================================
package cmd
import (
"fmt"
"os"
"path/filepath"
"strconv"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var pruneCmdArgs struct {
force bool
all bool
}
// pruneCmd represents the prune command
var pruneCmd = &cobra.Command{
Use: "prune",
Short: "prune cached downloaded assets",
Long: `Prune cached downloaded assets`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
colimaCacheDir := config.CacheDir()
limaCacheDir := filepath.Join(filepath.Dir(colimaCacheDir), "lima")
if !pruneCmdArgs.force {
msg := "'" + colimaCacheDir + "' will be emptied, are you sure"
if pruneCmdArgs.all {
msg = "'" + colimaCacheDir + "' and '" + limaCacheDir + "' will be emptied, are you sure"
}
if y := cli.Prompt(msg); !y {
return nil
}
}
logrus.Info("Pruning ", strconv.Quote(config.CacheDir()))
if err := os.RemoveAll(config.CacheDir()); err != nil {
return fmt.Errorf("error during prune: %w", err)
}
if pruneCmdArgs.all {
cmd := limautil.Limactl("prune")
if err := cmd.Run(); err != nil {
return fmt.Errorf("error during Lima prune: %w", err)
}
}
return nil
},
}
func init() {
root.Cmd().AddCommand(pruneCmd)
pruneCmd.Flags().BoolVarP(&pruneCmdArgs.force, "force", "f", false, "do not prompt for yes/no")
pruneCmd.Flags().BoolVarP(&pruneCmdArgs.all, "all", "a", false, "include Lima assets")
}
================================================
FILE: cmd/restart.go
================================================
package cmd
import (
"time"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config/configmanager"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/spf13/cobra"
)
var restartCmdArgs struct {
force bool
}
// restartCmd represents the restart command
var restartCmd = &cobra.Command{
Use: "restart [profile]",
Short: "restart Colima",
Long: `Stop and then starts Colima.
The state of the VM is persisted at stop. A start afterwards
should return it back to its previous state.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// validate if the instance was previously created
if _, err := limautil.Instance(); err != nil {
return err
}
app := newApp()
if err := app.Stop(restartCmdArgs.force); err != nil {
return err
}
// delay a bit before starting
time.Sleep(time.Second * 3)
config, err := configmanager.Load()
if err != nil {
return err
}
return app.Start(config)
},
}
func init() {
root.Cmd().AddCommand(restartCmd)
restartCmd.Flags().BoolVarP(&restartCmdArgs.force, "force", "f", false, "during restart, do stop without graceful shutdown")
}
================================================
FILE: cmd/root/root.go
================================================
package root
import (
"log"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var versionInfo = config.AppVersion()
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "colima",
Short: "container runtimes on macOS with minimal setup",
Long: `Colima provides container runtimes on macOS with minimal setup.`,
Version: versionInfo.Version,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// use profile from environment variable if set
profile := config.EnvProfile()
switch cmd.Name() {
// special case handling for commands directly interacting with the VM
// start, stop, restart, delete, status, version, update, ssh-config
case "start",
"stop",
"restart",
"delete",
"status",
"list",
"version",
"update",
"ssh-config":
// if an arg is passed, assume it to be the profile (provided --profile is unset)
// i.e. colima start docker == colima start --profile=docker
// takes precedence over the environment variable
if len(args) > 0 && !cmd.Flag("profile").Changed {
profile = args[0]
}
}
// if profile is set via flag, use it
// takes precedence over the environment variable and arg
if cmd.Flag("profile").Changed {
profile = rootCmdArgs.Profile
}
if profile != "" {
config.SetProfile(profile)
}
initLog()
cmd.SilenceUsage = true
cmd.SilenceErrors = true
return nil
},
}
// Cmd returns the root command.
func Cmd() *cobra.Command {
return rootCmd
}
// rootCmdArgs holds all flags configured in root Cmd
var rootCmdArgs struct {
Profile string
Verbose bool
VeryVerbose bool
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
logrus.Fatal(err)
}
}
func init() {
rootCmd.PersistentFlags().BoolVarP(&rootCmdArgs.Verbose, "verbose", "v", rootCmdArgs.Verbose, "enable verbose log")
rootCmd.PersistentFlags().BoolVar(&rootCmdArgs.VeryVerbose, "very-verbose", rootCmdArgs.VeryVerbose, "enable more verbose log")
rootCmd.PersistentFlags().StringVarP(&rootCmdArgs.Profile, "profile", "p", "default", "profile name, for multiple instances")
}
func initLog() {
if rootCmdArgs.Verbose {
cli.Settings.Verbose = true
logrus.SetLevel(logrus.DebugLevel)
}
if rootCmdArgs.VeryVerbose {
cli.Settings.Verbose = true
logrus.SetLevel(logrus.TraceLevel)
}
// general log output
log.SetOutput(logrus.StandardLogger().Writer())
log.SetFlags(0)
}
================================================
FILE: cmd/ssh-config.go
================================================
package cmd
import (
"fmt"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/spf13/cobra"
)
// statusCmd represents the status command
var sshConfigCmd = &cobra.Command{
Use: "ssh-config [profile]",
Short: "show SSH connection config",
Long: `Show configuration of the SSH connection to the VM.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := limautil.ShowSSH(config.CurrentProfile().ID)
if err == nil {
fmt.Println(resp.Output)
}
return err
},
}
func init() {
root.Cmd().AddCommand(sshConfigCmd)
}
================================================
FILE: cmd/ssh.go
================================================
package cmd
import (
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)
// sshCmd represents the ssh command
var sshCmd = &cobra.Command{
Use: "ssh",
Aliases: []string{"exec", "x"},
Short: "SSH into the VM",
Long: `SSH into the VM.
Appending additional command runs the command instead.
e.g. 'colima ssh -- htop' will run htop.
It is recommended to specify '--' to differentiate from colima flags.`,
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().SSH(args...)
},
}
func init() {
root.Cmd().AddCommand(sshCmd)
}
================================================
FILE: cmd/start.go
================================================
package cmd
import (
"fmt"
"net"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/abiosoft/colima/app"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/config/configmanager"
"github.com/abiosoft/colima/core"
"github.com/abiosoft/colima/embedded"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/environment/container/docker"
"github.com/abiosoft/colima/environment/container/incus"
"github.com/abiosoft/colima/environment/container/kubernetes"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/downloader"
"github.com/abiosoft/colima/util/osutil"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// startCmd represents the start command
var startCmd = &cobra.Command{
Use: "start [profile]",
Short: "start Colima",
Long: `Start Colima with the specified container runtime and optional kubernetes.
Colima can also be configured with a YAML file.
Run 'colima template' to set the default configurations or 'colima start --edit' to customize before startup.
`,
Example: " colima start\n" +
" colima start --edit\n" +
" colima start --foreground\n" +
" colima start --runtime containerd\n" +
" colima start --kubernetes\n" +
" colima start --runtime containerd --kubernetes\n" +
" colima start --cpu 4 --memory 8 --disk 100\n" +
" colima start --arch aarch64\n" +
" colima start --dns 1.1.1.1 --dns 8.8.8.8\n" +
" colima start --dns-host example.com=1.2.3.4\n" +
" colima start --gateway-address 192.168.6.2\n" +
" colima start --kubernetes --k3s-arg='\"--disable=coredns,servicelb,traefik,local-storage,metrics-server\"'",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
app := newApp()
conf := startCmdArgs.Config
if !startCmdArgs.Flags.Edit {
if app.Active() {
log.Warnln("already running, ignoring")
return nil
}
return start(app, conf)
}
// edit flag is specified
conf, err := editConfigFile()
if err != nil {
return err
}
// validate config
if err := configmanager.ValidateConfig(conf); err != nil {
return fmt.Errorf("error in config file: %w", err)
}
if app.Active() {
if !cli.Prompt("colima is currently running, restart to apply changes") {
return nil
}
if err := app.Stop(false); err != nil {
return fmt.Errorf("error stopping :%w", err)
}
// pause before startup to prevent race condition
time.Sleep(time.Second * 3)
}
return start(app, conf)
},
PreRunE: func(cmd *cobra.Command, args []string) error {
// validate Lima version
if err := core.LimaVersionSupported(); err != nil {
return fmt.Errorf("lima compatibility error: %w", err)
}
// combine args and current config file(if any)
prepareConfig(cmd)
// validate config
if err := configmanager.ValidateConfig(startCmdArgs.Config); err != nil {
return fmt.Errorf("error in config: %w", err)
}
// persist in preparation for application start
if startCmdArgs.Flags.SaveConfig {
if err := configmanager.Save(startCmdArgs.Config); err != nil {
return fmt.Errorf("error preparing config file: %w", err)
}
}
// validate and set downloader if flag is specified (takes precedence over env var)
if cmd.Flag("downloader").Changed {
normalized, err := downloader.ValidateDownloader(startCmdArgs.Flags.Downloader)
if err != nil {
return err
}
downloader.SetDownloader(normalized)
}
return nil
},
}
const (
defaultCPU = 2
defaultMemory = 2
defaultDisk = 100
defaultRootDisk = 20
defaultKubernetesVersion = kubernetes.DefaultVersion
defaultMountTypeQEMU = "sshfs"
defaultMountTypeVZ = "virtiofs"
)
var (
defaultVMType = "qemu"
defaultK3sArgs = []string{"--disable=traefik"}
envSaveConfig = osutil.EnvVar("COLIMA_SAVE_CONFIG")
)
var startCmdArgs struct {
config.Config
Flags struct {
Mounts []string
LegacyKubernetes bool // for backward compatibility
LegacyKubernetesDisable []string
Edit bool
Editor string
ActivateRuntime bool
Binfmt bool
DNSHosts []string
Foreground bool
SaveConfig bool
LegacyCPU int // for backward compatibility
Template bool
Downloader string // downloader to use (native, curl)
}
}
func init() {
runtimes := strings.Join(environment.ContainerRuntimes(), ", ")
defaultArch := string(environment.HostArch())
defaultVMType = environment.DefaultVMType()
defaultMountType := defaultMountTypeQEMU
if defaultVMType == "vz" {
defaultMountType = defaultMountTypeVZ
}
mounts := strings.Join([]string{defaultMountTypeQEMU, "9p", "virtiofs"}, ", ")
vmTypes := []string{"qemu", "vz"}
if util.MacOS13OrNewerOnArm() {
vmTypes = append(vmTypes, "krunkit")
}
types := strings.Join(vmTypes, ", ")
saveConfigDefault := true
if envSaveConfig.Exists() {
saveConfigDefault = envSaveConfig.Bool()
}
root.Cmd().AddCommand(startCmd)
startCmd.Flags().StringVarP(&startCmdArgs.Runtime, "runtime", "r", docker.Name, "container runtime ("+runtimes+")")
startCmd.Flags().BoolVar(&startCmdArgs.Flags.ActivateRuntime, "activate", true, "set as active Docker/Kubernetes/Incus context on startup")
startCmd.Flags().IntVarP(&startCmdArgs.CPU, "cpus", "c", defaultCPU, "number of CPUs")
startCmd.Flags().StringVar(&startCmdArgs.CPUType, "cpu-type", "", "the CPU type, options can be checked with 'qemu-system-"+defaultArch+" -cpu help'")
startCmd.Flags().Float32VarP(&startCmdArgs.Memory, "memory", "m", defaultMemory, "memory in GiB")
startCmd.Flags().IntVarP(&startCmdArgs.Disk, "disk", "d", defaultDisk, "disk size in GiB")
startCmd.Flags().IntVar(&startCmdArgs.RootDisk, "root-disk", defaultRootDisk, "disk size in GiB for the root filesystem")
startCmd.Flags().StringVarP(&startCmdArgs.Arch, "arch", "a", defaultArch, "architecture (aarch64, x86_64)")
startCmd.Flags().BoolVarP(&startCmdArgs.Flags.Foreground, "foreground", "f", false, "Keep colima in the foreground")
startCmd.Flags().StringVar(&startCmdArgs.Hostname, "hostname", "", "custom hostname for the virtual machine")
startCmd.Flags().StringVarP(&startCmdArgs.DiskImage, "disk-image", "i", "", "file path to a custom disk image")
startCmd.Flags().BoolVar(&startCmdArgs.Flags.Template, "template", true, "use the template file for initial configuration")
// port forwarder
startCmd.Flags().StringVar(&startCmdArgs.PortForwarder, "port-forwarder", "ssh", "port forwarder to use (ssh, grpc, none)")
// retain cpu flag for backward compatibility
startCmd.Flags().IntVar(&startCmdArgs.Flags.LegacyCPU, "cpu", defaultCPU, "number of CPUs")
startCmd.Flag("cpu").Hidden = true
// host IP addresses
startCmd.Flags().BoolVar(&startCmdArgs.Network.HostAddresses, "network-host-addresses", false, "support port forwarding to specific host IP addresses")
binfmtDesc := "use binfmt for foreign architecture emulation"
if util.MacOS() {
// network address
startCmd.Flags().BoolVar(&startCmdArgs.Network.Address, "network-address", false, "assign reachable IP address to the VM")
startCmd.Flags().StringVar(&startCmdArgs.Network.Mode, "network-mode", "shared", "network mode (shared, bridged)")
startCmd.Flags().StringVar(&startCmdArgs.Network.BridgeInterface, "network-interface", "en0", "host network interface to use for bridged mode")
startCmd.Flags().BoolVar(&startCmdArgs.Network.PreferredRoute, "network-preferred-route", false, "use the assigned IP address as the preferred route for the VM (implies --network-address)")
// vm type
if util.MacOS13OrNewer() {
startCmd.Flags().StringVarP(&startCmdArgs.VMType, "vm-type", "t", defaultVMType, "virtual machine type ("+types+")")
if util.MacOS13OrNewerOnArm() {
startCmd.Flags().BoolVar(&startCmdArgs.VZRosetta, "vz-rosetta", false, "enable Rosetta for amd64 emulation")
startCmd.Flags().StringVar(&startCmdArgs.ModelRunner, "model-runner", "docker", "AI model runner (docker, ramalama)")
binfmtDesc += " (no-op if Rosetta is enabled)"
}
}
// nested virtualization
if util.MacOSNestedVirtualizationSupported() {
startCmd.Flags().BoolVarP(&startCmdArgs.NestedVirtualization, "nested-virtualization", "z", false, "enable nested virtualization")
}
}
// Gateway Address
startCmd.Flags().IPVar(&startCmdArgs.Network.GatewayAddress, "gateway-address", net.ParseIP("192.168.5.2"), "gateway address")
// binfmt
startCmd.Flags().BoolVar(&startCmdArgs.Flags.Binfmt, "binfmt", true, binfmtDesc)
// config
startCmd.Flags().BoolVarP(&startCmdArgs.Flags.Edit, "edit", "e", false, "edit the configuration file before starting")
startCmd.Flags().StringVar(&startCmdArgs.Flags.Editor, "editor", "", `editor to use for edit e.g. vim, nano, code (default "$EDITOR" env var)`)
startCmd.Flags().BoolVar(&startCmdArgs.Flags.SaveConfig, "save-config", saveConfigDefault, "persist and overwrite config file with (newly) specified flags")
// mounts
startCmd.Flags().StringSliceVarP(&startCmdArgs.Flags.Mounts, "mount", "V", nil, "directories to mount, suffix ':w' for writable, disable with 'none'")
startCmd.Flags().StringVar(&startCmdArgs.MountType, "mount-type", defaultMountType, "volume driver for the mount ("+mounts+")")
startCmd.Flags().BoolVar(&startCmdArgs.MountINotify, "mount-inotify", true, "propagate inotify file events to the VM")
// ssh
startCmd.Flags().BoolVarP(&startCmdArgs.ForwardAgent, "ssh-agent", "s", false, "forward SSH agent to the VM")
startCmd.Flags().BoolVar(&startCmdArgs.SSHConfig, "ssh-config", true, "generate SSH config in ~/.ssh/config")
startCmd.Flags().IntVar(&startCmdArgs.SSHPort, "ssh-port", 0, "SSH server port")
// k8s
startCmd.Flags().BoolVarP(&startCmdArgs.Kubernetes.Enabled, "kubernetes", "k", false, "start with Kubernetes")
startCmd.Flags().BoolVar(&startCmdArgs.Flags.LegacyKubernetes, "with-kubernetes", false, "start with Kubernetes")
startCmd.Flags().StringVar(&startCmdArgs.Kubernetes.Version, "kubernetes-version", defaultKubernetesVersion, "must match a k3s version https://github.com/k3s-io/k3s/releases")
startCmd.Flags().StringSliceVar(&startCmdArgs.Flags.LegacyKubernetesDisable, "kubernetes-disable", nil, "components to disable for k3s e.g. traefik,servicelb")
startCmd.Flags().StringSliceVar(&startCmdArgs.Kubernetes.K3sArgs, "k3s-arg", defaultK3sArgs, "additional args to pass to k3s")
startCmd.Flags().IntVar(&startCmdArgs.Kubernetes.Port, "k3s-listen-port", 0, "k3s server listen port")
startCmd.Flag("with-kubernetes").Hidden = true
startCmd.Flag("kubernetes-disable").Hidden = true
// env
startCmd.Flags().StringToStringVar(&startCmdArgs.Env, "env", nil, "environment variables for the VM")
// dns
startCmd.Flags().IPSliceVarP(&startCmdArgs.Network.DNSResolvers, "dns", "n", nil, "DNS resolvers for the VM")
startCmd.Flags().StringSliceVar(&startCmdArgs.Flags.DNSHosts, "dns-host", nil, "custom DNS names to provide to resolver")
// download options
startCmd.Flags().StringVar(&startCmdArgs.Flags.Downloader, "downloader", downloader.DownloaderNative, "downloader to use (native, curl)")
}
func dnsHostsFromFlag(hosts []string) map[string]string {
mapping := make(map[string]string)
for _, h := range hosts {
str := strings.SplitN(h, "=", 2)
if len(str) != 2 {
log.Warnf("unable to parse custom dns host: %v, skipping\n", h)
continue
}
src := str[0]
target := str[1]
mapping[src] = target
}
return mapping
}
// mountsFromFlag converts mounts from cli flag format to config file format
func mountsFromFlag(mounts []string) []config.Mount {
mnts := make([]config.Mount, len(mounts))
for i, mount := range mounts {
// if one of the parameters is none, treat as none.
if strings.ToLower(mount) == "none" {
return nil
}
str := strings.SplitN(mount, ":", 3)
mnt := config.Mount{Location: str[0]}
if len(str) > 1 {
if filepath.IsAbs(str[1]) {
mnt.MountPoint = str[1]
} else if str[1] == "w" {
mnt.Writable = true
}
}
if len(str) > 2 && str[2] == "w" {
mnt.Writable = true
}
mnts[i] = mnt
}
return mnts
}
func setFlagDefaults(cmd *cobra.Command) {
if startCmdArgs.VMType == "" {
startCmdArgs.VMType = defaultVMType
}
if util.MacOS13OrNewer() {
// changing to vz implies changing mount type to virtiofs
if cmd.Flag("vm-type").Changed && startCmdArgs.VMType == "vz" && !cmd.Flag("mount-type").Changed {
startCmdArgs.MountType = "virtiofs"
cmd.Flag("mount-type").Changed = true
}
}
// mount type
{
// convert mount type for qemu
if startCmdArgs.VMType != "vz" && startCmdArgs.VMType != "krunkit" && startCmdArgs.MountType == defaultMountTypeVZ {
startCmdArgs.MountType = defaultMountTypeQEMU
if cmd.Flag("mount-type").Changed {
log.Warnf("%s is only available for 'vz' vmType, using %s", defaultMountTypeVZ, defaultMountTypeQEMU)
}
}
// convert mount type for vz
if startCmdArgs.VMType == "vz" && startCmdArgs.MountType == "9p" {
startCmdArgs.MountType = "virtiofs"
if cmd.Flag("mount-type").Changed {
log.Warnf("9p is only available for 'qemu' vmType, using %s", defaultMountTypeVZ)
}
}
}
// always enable nested virtualization for incus, if supported and not explicitly disabled.
if util.MacOSNestedVirtualizationSupported() {
if !cmd.Flag("nested-virtualization").Changed {
if startCmdArgs.Runtime == incus.Name && (startCmdArgs.VMType == "vz" || startCmdArgs.VMType == "krunkit") {
startCmdArgs.NestedVirtualization = true
}
}
}
// always enable network address for incus, if supported and not explicitly disabled
if util.MacOS13OrNewer() {
if !cmd.Flag("network-address").Changed {
if startCmdArgs.Runtime == incus.Name && startCmdArgs.VMType == "vz" {
startCmdArgs.Network.Address = true
}
}
}
}
func setConfigDefaults(conf *config.Config) {
// handle macOS virtualization.framework transition
if conf.VMType == "" {
conf.VMType = defaultVMType
// if on macOS with no qemu, use vz
if err := util.AssertQemuImg(); err != nil && util.MacOS13OrNewer() {
conf.VMType = "vz"
}
}
if conf.MountType == "" {
conf.MountType = defaultMountTypeQEMU
if util.MacOS13OrNewer() && conf.VMType == "vz" {
conf.MountType = defaultMountTypeVZ
}
}
if conf.Hostname == "" {
conf.Hostname = config.CurrentProfile().ID
}
if conf.PortForwarder == "" {
conf.PortForwarder = "ssh"
}
}
func setFixedConfigs(conf *config.Config) {
fixedConf, err := configmanager.LoadFrom(config.CurrentProfile().StateFile())
if err != nil {
return
}
warnIfNotEqual := func(name, newVal, fixedVal string) {
if newVal != fixedVal {
log.Warnln(fmt.Errorf("'%s' cannot be updated after initial setup, discarded", name))
}
}
// override the fixed configs
// arch, vmType, mountType, runtime are fixed and cannot be changed
if fixedConf.Arch != "" {
warnIfNotEqual("architecture", conf.Arch, fixedConf.Arch)
conf.Arch = fixedConf.Arch
}
if fixedConf.VMType != "" {
warnIfNotEqual("virtual machine type", conf.VMType, fixedConf.VMType)
conf.VMType = fixedConf.VMType
}
if fixedConf.Runtime != "" {
warnIfNotEqual("runtime", conf.Runtime, fixedConf.Runtime)
conf.Runtime = fixedConf.Runtime
}
if fixedConf.MountType != "" {
warnIfNotEqual("volume mount type", conf.MountType, fixedConf.MountType)
conf.MountType = fixedConf.MountType
}
if fixedConf.Network.Address && !conf.Network.Address {
log.Warnln("network address cannot be disabled once enabled")
conf.Network.Address = true
}
if fixedConf.Network.Mode != "" {
warnIfNotEqual("network mode", conf.Network.Mode, fixedConf.Network.Mode)
conf.Network.Mode = fixedConf.Network.Mode
}
}
func prepareConfig(cmd *cobra.Command) {
current, err := configmanager.Load()
if err != nil {
// not fatal, will proceed with defaults
log.Warnln(fmt.Errorf("config load failed: %w", err))
log.Warnln("reverting to default settings")
}
// handle legacy kubernetes flag
if cmd.Flag("with-kubernetes").Changed {
startCmdArgs.Kubernetes.Enabled = startCmdArgs.Flags.LegacyKubernetes
cmd.Flag("kubernetes").Changed = true
}
// handle legacy cpu flag
if cmd.Flag("cpu").Changed && !cmd.Flag("cpus").Changed {
startCmdArgs.CPU = startCmdArgs.Flags.LegacyCPU
cmd.Flag("cpus").Changed = true
}
// convert cli to config file format
startCmdArgs.Mounts = mountsFromFlag(startCmdArgs.Flags.Mounts)
startCmdArgs.Network.DNSHosts = dnsHostsFromFlag(startCmdArgs.Flags.DNSHosts)
startCmdArgs.ActivateRuntime = &startCmdArgs.Flags.ActivateRuntime
startCmdArgs.Binfmt = &startCmdArgs.Flags.Binfmt
// handle legacy kubernetes-disable
for _, disable := range startCmdArgs.Flags.LegacyKubernetesDisable {
startCmdArgs.Kubernetes.K3sArgs = append(startCmdArgs.Kubernetes.K3sArgs, "--disable="+disable)
}
// set relevant missing default values
setFlagDefaults(cmd)
// if there is no existing settings
if current.Empty() {
templateUsed := false
// attempt template if enabled
if startCmdArgs.Flags.Template {
template, err := configmanager.LoadFrom(templateFile())
if err == nil {
current = template
templateUsed = true
}
}
if !templateUsed {
// use default config if there is no template or template is disabled
return
}
}
// set missing defaults in the current config
setConfigDefaults(¤t)
// docker can only be set in config file
startCmdArgs.Docker = current.Docker
// provision scripts can only be set in config file
startCmdArgs.Provision = current.Provision
// use current settings for unchanged configs
// otherwise may be reverted to their default values.
if !cmd.Flag("arch").Changed {
startCmdArgs.Arch = current.Arch
}
if !cmd.Flag("disk").Changed {
startCmdArgs.Disk = current.Disk
}
if !cmd.Flag("root-disk").Changed {
if current.RootDisk > 0 {
startCmdArgs.RootDisk = current.RootDisk
}
}
if !cmd.Flag("kubernetes").Changed {
startCmdArgs.Kubernetes.Enabled = current.Kubernetes.Enabled
}
if !cmd.Flag("kubernetes-version").Changed && current.Kubernetes.Version != "" {
startCmdArgs.Kubernetes.Version = current.Kubernetes.Version
}
if !cmd.Flag("k3s-arg").Changed && current.Kubernetes.K3sArgs != nil {
startCmdArgs.Kubernetes.K3sArgs = current.Kubernetes.K3sArgs
}
if !cmd.Flag("k3s-listen-port").Changed && current.Kubernetes.Port > 0 {
startCmdArgs.Kubernetes.Port = current.Kubernetes.Port
}
if !cmd.Flag("runtime").Changed {
startCmdArgs.Runtime = current.Runtime
}
if util.MacOS13OrNewerOnArm() {
if !cmd.Flag("model-runner").Changed {
startCmdArgs.ModelRunner = current.ModelRunner
}
}
if !cmd.Flag("cpus").Changed {
startCmdArgs.CPU = current.CPU
}
if !cmd.Flag("cpu-type").Changed {
startCmdArgs.CPUType = current.CPUType
}
if !cmd.Flag("memory").Changed {
startCmdArgs.Memory = current.Memory
}
if !cmd.Flag("mount").Changed {
startCmdArgs.Mounts = current.Mounts
}
if !cmd.Flag("mount-type").Changed {
startCmdArgs.MountType = current.MountType
}
if !cmd.Flag("mount-inotify").Changed {
startCmdArgs.MountINotify = current.MountINotify
}
if !cmd.Flag("ssh-agent").Changed {
startCmdArgs.ForwardAgent = current.ForwardAgent
}
if !cmd.Flag("ssh-config").Changed {
startCmdArgs.SSHConfig = current.SSHConfig
}
if !cmd.Flag("ssh-port").Changed {
startCmdArgs.SSHPort = current.SSHPort
}
if !cmd.Flag("port-forwarder").Changed {
startCmdArgs.PortForwarder = current.PortForwarder
}
if !cmd.Flag("dns").Changed {
startCmdArgs.Network.DNSResolvers = current.Network.DNSResolvers
}
if !cmd.Flag("dns-host").Changed {
startCmdArgs.Network.DNSHosts = current.Network.DNSHosts
}
if !cmd.Flag("gateway-address").Changed {
startCmdArgs.Network.GatewayAddress = current.Network.GatewayAddress
}
if !cmd.Flag("env").Changed {
startCmdArgs.Env = current.Env
}
if !cmd.Flag("hostname").Changed {
startCmdArgs.Hostname = current.Hostname
}
if !cmd.Flag("activate").Changed {
if current.ActivateRuntime != nil { // backward compatibility for `activate`
startCmdArgs.ActivateRuntime = current.ActivateRuntime
}
}
if !cmd.Flag("binfmt").Changed {
if current.Binfmt != nil {
startCmdArgs.Binfmt = current.Binfmt
}
}
if !cmd.Flag("network-host-addresses").Changed {
startCmdArgs.Network.HostAddresses = current.Network.HostAddresses
}
if util.MacOS() {
if !cmd.Flag("network-address").Changed {
startCmdArgs.Network.Address = current.Network.Address
}
if !cmd.Flag("network-mode").Changed {
startCmdArgs.Network.Mode = current.Network.Mode
}
if !cmd.Flag("network-interface").Changed {
startCmdArgs.Network.BridgeInterface = current.Network.BridgeInterface
}
if !cmd.Flag("network-preferred-route").Changed {
startCmdArgs.Network.PreferredRoute = current.Network.PreferredRoute
}
if util.MacOS13OrNewer() {
if !cmd.Flag("vm-type").Changed {
startCmdArgs.VMType = current.VMType
}
}
if util.MacOS13OrNewerOnArm() {
if !cmd.Flag("vz-rosetta").Changed {
startCmdArgs.VZRosetta = current.VZRosetta
}
}
if util.MacOSNestedVirtualizationSupported() {
if !cmd.Flag("nested-virtualization").Changed {
startCmdArgs.NestedVirtualization = current.NestedVirtualization
}
}
}
setFixedConfigs(&startCmdArgs.Config)
}
// editConfigFile launches an editor to edit the config file.
func editConfigFile() (config.Config, error) {
var c config.Config
// preserve the current file in case the user terminates
currentFile, err := os.ReadFile(config.CurrentProfile().File())
if err != nil {
return c, fmt.Errorf("error reading config file: %w", err)
}
// prepend the config file with termination instruction
abort, err := embedded.ReadString("defaults/abort.yaml")
if err != nil {
log.Warnln(fmt.Errorf("unable to read embedded file: %w", err))
}
tmpFile, err := waitForUserEdit(startCmdArgs.Flags.Editor, []byte(abort+"\n"+string(currentFile)))
if err != nil {
return c, fmt.Errorf("error editing config file: %w", err)
}
// if file is empty, abort
if tmpFile == "" {
return c, fmt.Errorf("empty file, startup aborted")
}
defer func() {
_ = os.Remove(tmpFile)
}()
if startCmdArgs.Flags.SaveConfig {
if err := configmanager.SaveFromFile(tmpFile); err != nil {
return c, err
}
}
return configmanager.LoadFrom(tmpFile)
}
func start(app app.App, conf config.Config) error {
if err := app.Start(conf); err != nil {
return err
}
if startCmdArgs.Flags.Foreground {
return awaitForInterruption(app)
}
return nil
}
func awaitForInterruption(app app.App) error {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
log.Println("keeping Colima in the foreground, press ctrl+c to exit...")
sig := <-c
log.Infof("interrupted by: %v", sig)
if err := app.Stop(false); err != nil {
log.Errorf("error stopping: %v", err)
return err
}
return nil
}
================================================
FILE: cmd/start_test.go
================================================
package cmd
import (
"reflect"
"strconv"
"testing"
"github.com/abiosoft/colima/config"
)
func Test_mountsFromFlag(t *testing.T) {
tests := []struct {
mounts []string
want []config.Mount
}{
{
mounts: []string{
"~:w",
},
want: []config.Mount{
{Location: "~", Writable: true},
},
},
{
mounts: []string{
"~",
},
want: []config.Mount{
{Location: "~"},
},
},
{
mounts: []string{
"/home/users", "/home/another:w", "/tmp",
},
want: []config.Mount{
{Location: "/home/users"},
{Location: "/home/another", Writable: true},
{Location: "/tmp"},
},
},
{
mounts: []string{
"/home/users:/home/users", "/home/another:w", "/tmp:/users/tmp", "/tmp:/users/tmp:w",
},
want: []config.Mount{
{Location: "/home/users", MountPoint: "/home/users"},
{Location: "/home/another", Writable: true},
{Location: "/tmp", MountPoint: "/users/tmp"},
{Location: "/tmp", MountPoint: "/users/tmp", Writable: true},
},
},
{
mounts: []string{
"none",
},
want: nil,
},
}
for i, tt := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
if got := mountsFromFlag(tt.mounts); !reflect.DeepEqual(got, tt.want) {
t.Errorf("mountsFromFlag() = %+v, want %+v", got, tt.want)
}
})
}
}
================================================
FILE: cmd/status.go
================================================
package cmd
import (
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)
var statusCmdArgs struct {
extended bool
json bool
}
// statusCmd represents the status command
var statusCmd = &cobra.Command{
Use: "status [profile]",
Short: "show the status of Colima",
Long: `Show the status of Colima`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Status(statusCmdArgs.extended, statusCmdArgs.json)
},
}
func init() {
root.Cmd().AddCommand(statusCmd)
statusCmd.Flags().BoolVarP(&statusCmdArgs.extended, "extended", "e", false, "include additional details")
statusCmd.Flags().BoolVarP(&statusCmdArgs.json, "json", "j", false, "print json output")
}
================================================
FILE: cmd/stop.go
================================================
package cmd
import (
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)
var stopCmdArgs struct {
force bool
}
// stopCmd represents the stop command
var stopCmd = &cobra.Command{
Use: "stop [profile]",
Short: "stop Colima",
Long: `Stop Colima to free up resources.
The state of the VM is persisted at stop. A start afterwards
should return it back to its previous state.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Stop(stopCmdArgs.force)
},
}
func init() {
root.Cmd().AddCommand(stopCmd)
stopCmd.Flags().BoolVarP(&stopCmdArgs.force, "force", "f", false, "stop without graceful shutdown")
}
================================================
FILE: cmd/template.go
================================================
package cmd
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/config/configmanager"
"github.com/abiosoft/colima/embedded"
"github.com/spf13/cobra"
)
// templateCmd represents the template command
var templateCmd = &cobra.Command{
Use: "template",
Aliases: []string{"tmpl", "tpl", "t"},
Short: "edit the template for default configurations",
Long: `Edit the template for default configurations of new instances.
`,
RunE: func(cmd *cobra.Command, args []string) error {
if templateCmdArgs.Print {
fmt.Println(templateFile())
return nil
}
// there are unwarranted []byte to string overheads.
// not a big deal in this case
abort, err := embedded.ReadString("defaults/abort.yaml")
if err != nil {
return fmt.Errorf("error reading embedded file: %w", err)
}
info, err := embedded.ReadString("defaults/template.yaml")
if err != nil {
return fmt.Errorf("error reading embedded file: %w", err)
}
template, err := templateFileOrDefault()
if err != nil {
return fmt.Errorf("error reading template file: %w", err)
}
tmpFile, err := waitForUserEdit(templateCmdArgs.Editor, []byte(abort+"\n"+info+"\n"+template))
if err != nil {
return fmt.Errorf("error editing template file: %w", err)
}
if tmpFile == "" {
return fmt.Errorf("empty file, template edit aborted")
}
defer func() {
_ = os.Remove(tmpFile)
}()
// load and resave template to ensure the format is correct
cf, err := configmanager.LoadFrom(tmpFile)
if err != nil {
return fmt.Errorf("error in template: %w", err)
}
if err := configmanager.SaveToFile(cf, templateFile()); err != nil {
return fmt.Errorf("error saving template: %w", err)
}
log.Println("configurations template saved")
return nil
},
}
func templateFile() string { return filepath.Join(config.TemplatesDir(), "default.yaml") }
func templateFileOrDefault() (string, error) {
tFile := templateFile()
if _, err := os.Stat(tFile); err == nil {
b, err := os.ReadFile(tFile)
if err == nil {
return string(b), nil
}
}
return embedded.ReadString("defaults/colima.yaml")
}
var templateCmdArgs struct {
Editor string
Print bool
}
func init() {
root.Cmd().AddCommand(templateCmd)
templateCmd.Flags().StringVar(&templateCmdArgs.Editor, "editor", "", `editor to use for edit e.g. vim, nano, code (default "$EDITOR" env var)`)
templateCmd.Flags().BoolVar(&templateCmdArgs.Print, "print", false, `print out the configuration file path, without editing`)
}
================================================
FILE: cmd/update.go
================================================
package cmd
import (
"github.com/abiosoft/colima/cmd/root"
"github.com/spf13/cobra"
)
// statusCmd represents the status command
var updateCmd = &cobra.Command{
Use: "update [profile]",
Aliases: []string{"u", "up"},
Short: "update the container runtime",
Long: `Update the current container runtime.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Update()
},
}
func init() {
root.Cmd().AddCommand(updateCmd)
}
================================================
FILE: cmd/util.go
================================================
package cmd
import (
"bytes"
"fmt"
"log"
"os"
"os/exec"
"strconv"
"strings"
"github.com/abiosoft/colima/app"
"github.com/abiosoft/colima/cli"
"github.com/sirupsen/logrus"
)
func newApp() app.App {
colimaApp, err := app.New()
if err != nil {
logrus.Fatal("Error: ", err)
}
return colimaApp
}
// waitForUserEdit launches a temporary file with content using editor,
// and waits for the user to close the editor.
// It returns the filename (if saved), empty file name (if aborted), and an error (if any).
func waitForUserEdit(editor string, content []byte) (string, error) {
tmp, err := os.CreateTemp("", "colima-*.yaml")
if err != nil {
return "", fmt.Errorf("error creating temporary file: %w", err)
}
if _, err := tmp.Write(content); err != nil {
return "", fmt.Errorf("error writing temporary file: %w", err)
}
if err := tmp.Close(); err != nil {
return "", fmt.Errorf("error closing temporary file: %w", err)
}
if err := launchEditor(editor, tmp.Name()); err != nil {
return "", err
}
// aborted
if f, err := os.ReadFile(tmp.Name()); err == nil && len(bytes.TrimSpace(f)) == 0 {
return "", nil
}
return tmp.Name(), nil
}
var editors = []string{
"vim",
"code --wait --new-window",
"nano",
}
func launchEditor(editor string, file string) error {
if editor != "" {
log.Println("editing in", editor)
}
// if not specified, prefer vscode if this a vscode terminal
if editor == "" {
if os.Getenv("TERM_PROGRAM") == "vscode" {
log.Println("vscode detected, editing in vscode")
editor = "code --wait"
}
}
// if not found, check the EDITOR env var
if editor == "" {
if e := os.Getenv("EDITOR"); e != "" {
log.Println("editing in", e, "from", "$EDITOR environment variable")
editor = e
}
}
// if not found, check the preferred editors
if editor == "" {
for _, e := range editors {
s := strings.Fields(e)
if _, err := exec.LookPath(s[0]); err == nil {
editor = e
log.Println("editing in", e)
break
}
}
}
// if still not found, abort
if editor == "" {
return fmt.Errorf("no editor found in $PATH, kindly set $EDITOR environment variable and try again")
}
// some editors need the wait flag, let us add it if the user has not.
switch editor {
case "code", "code-insiders", "code-oss", "codium", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code":
editor = strconv.Quote(editor) + " --wait --new-window"
case "mate", "/Applications/TextMate 2.app/Contents/MacOS/mate", "/Applications/TextMate 2.app/Contents/MacOS/TextMate":
editor = strconv.Quote(editor) + " --wait"
}
return cli.CommandInteractive("sh", "-c", editor+" "+file).Run()
}
================================================
FILE: cmd/version.go
================================================
package cmd
import (
"fmt"
"github.com/abiosoft/colima/app"
"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/model"
"github.com/abiosoft/colima/store"
"github.com/spf13/cobra"
)
// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version [profile]",
Short: "print the version of Colima",
Long: `Print the version of Colima`,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
version := config.AppVersion()
fmt.Println(config.AppName, "version", version.Version)
fmt.Println("git commit:", version.Revision)
if colimaApp, err := app.New(); err == nil {
_ = colimaApp.Version()
// Show AI model runner version if provisioned
s, _ := store.Load()
if s.RamalamaProvisioned {
if modelVersion := model.GetRamalamaVersion(); modelVersion != "" {
fmt.Println()
fmt.Println("AI model runner")
fmt.Println("version:", modelVersion)
}
}
}
},
}
func init() {
root.Cmd().AddCommand(versionCmd)
}
================================================
FILE: colima.nix
================================================
{ pkgs ? import <nixpkgs> }:
with pkgs;
buildGo123Module {
name = "colima";
pname = "colima";
src = ./.;
nativeBuildInputs = [ installShellFiles makeWrapper git ];
vendorHash = "sha256-ZwgzKCOEhgKK2LNRLjnWP6qHI4f6OGORvt3CREJf55I=";
CGO_ENABLED = 1;
subPackages = [ "cmd/colima" ];
# `nix-build` has .git folder but `nix build` does not, this caters for both cases
preConfigure = ''
export VERSION="$(git describe --tags --always || echo nix-build-at-"$(date +%s)")"
export REVISION="$(git rev-parse HEAD || echo nix-unknown)"
ldflags="-X github.com/abiosoft/colima/config.appVersion=$VERSION
-X github.com/abiosoft/colima/config.revision=$REVISION"
'';
postInstall = ''
wrapProgram $out/bin/colima \
--prefix PATH : ${lib.makeBinPath [ qemu lima ]}
installShellCompletion --cmd colima \
--bash <($out/bin/colima completion bash) \
--fish <($out/bin/colima completion fish) \
--zsh <($out/bin/colima completion zsh)
'';
}
================================================
FILE: config/config.go
================================================
package config
import (
"fmt"
"net"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/osutil"
)
const (
AppName = "colima"
envProfile = "COLIMA_PROFILE" // environment variable for profile name
)
// VersionInfo is the application version info.
type VersionInfo struct {
Version string
Revision string
}
func AppVersion() VersionInfo { return VersionInfo{Version: appVersion, Revision: revision} }
func EnvProfile() string { return osutil.EnvVar(envProfile).Val() }
var (
appVersion = "development"
revision = "unknown"
)
// Config is the application config.
type Config struct {
CPU int `yaml:"cpu,omitempty"`
Disk int `yaml:"disk,omitempty"`
RootDisk int `yaml:"rootDisk,omitempty"`
Memory float32 `yaml:"memory,omitempty"`
Arch string `yaml:"arch,omitempty"`
CPUType string `yaml:"cpuType,omitempty"`
Network Network `yaml:"network,omitempty"`
Env map[string]string `yaml:"env,omitempty"` // environment variables
Hostname string `yaml:"hostname"`
// SSH
SSHPort int `yaml:"sshPort,omitempty"`
ForwardAgent bool `yaml:"forwardAgent,omitempty"`
SSHConfig bool `yaml:"sshConfig,omitempty"` // config generation
// VM
VMType string `yaml:"vmType,omitempty"`
VZRosetta bool `yaml:"rosetta,omitempty"`
Binfmt *bool `yaml:"binfmt,omitempty"`
NestedVirtualization bool `yaml:"nestedVirtualization,omitempty"`
DiskImage string `yaml:"diskImage,omitempty"`
PortForwarder string `yaml:"portForwarder,omitempty"` // "ssh", "grpc"
// volume mounts
Mounts []Mount `yaml:"mounts,omitempty"`
MountType string `yaml:"mountType,omitempty"`
MountINotify bool `yaml:"mountInotify,omitempty"`
// Runtime is one of docker, containerd.
Runtime string `yaml:"runtime,omitempty"`
ActivateRuntime *bool `yaml:"autoActivate,omitempty"`
// ModelRunner is the AI model runner (docker, ramalama).
ModelRunner string `yaml:"modelRunner,omitempty"`
// Kubernetes configuration
Kubernetes Kubernetes `yaml:"kubernetes,omitempty"`
// Docker configuration
Docker map[string]any `yaml:"docker,omitempty"`
// provision scripts
Provision []Provision `yaml:"provision,omitempty"`
}
// Kubernetes is kubernetes configuration
type Kubernetes struct {
Enabled bool `yaml:"enabled"`
Version string `yaml:"version"`
K3sArgs []string `yaml:"k3sArgs"`
Port int `yaml:"port,omitempty"`
}
// Network is VM network configuration
type Network struct {
Address bool `yaml:"address"`
DNSResolvers []net.IP `yaml:"dns"`
DNSHosts map[string]string `yaml:"dnsHosts"`
HostAddresses bool `yaml:"hostAddresses"`
Mode string `yaml:"mode"` // shared, bridged
BridgeInterface string `yaml:"interface"`
PreferredRoute bool `yaml:"preferredRoute"`
GatewayAddress net.IP `yaml:"gatewayAddress"`
}
// Mount is volume mount
type Mount struct {
Location string `yaml:"location"`
MountPoint string `yaml:"mountPoint,omitempty"`
Writable bool `yaml:"writable"`
}
// Provision modes managed by Colima (not passed to Lima).
const (
ProvisionModeAfterBoot = "after-boot"
ProvisionModeReady = "ready"
)
type Provision struct {
Mode string `yaml:"mode"`
Script string `yaml:"script"`
}
// IsColimaMode returns true if the provision script is managed by Colima
// rather than being passed to Lima.
func (p Provision) IsColimaMode() bool {
return p.Mode == ProvisionModeAfterBoot || p.Mode == ProvisionModeReady
}
func (c Config) MountsOrDefault() []Mount {
// explicit empty list means mount home directory (matches yaml.go)
if c.Mounts != nil && len(c.Mounts) == 0 {
return []Mount{
{Location: util.HomeDir(), Writable: true},
}
}
// nil means no mounts, non-empty means user-specified mounts
return c.Mounts
}
// AutoActivate returns if auto-activation of host client config is enabled.
func (c Config) AutoActivate() bool {
if c.ActivateRuntime == nil {
return true
}
return *c.ActivateRuntime
}
// Empty checks if the configuration is empty.
func (c Config) Empty() bool { return c.Runtime == "" } // this may be better but not really needed.
func (c Config) DriverLabel() string {
if util.MacOS13OrNewer() && c.VMType == "vz" {
return "macOS Virtualization.Framework"
} else if util.MacOS13OrNewerOnArm() && c.VMType == "krunkit" {
return "Krunkit"
}
return "QEMU"
}
// Disk is an instance disk size
type Disk int
// GiB returns the string represent of the disk in GiB.
func (d Disk) GiB() string { return fmt.Sprintf("%dGiB", d) }
// Int returns the disk size in bytes.
func (d Disk) Int() int64 { return 1024 * 1024 * 1024 * int64(d) }
// CtxKey returns the context key for config.
func CtxKey() any {
return struct{ name string }{name: "colima_config"}
}
================================================
FILE: config/configmanager/configmanager.go
================================================
package configmanager
import (
"fmt"
"net"
"os"
"strings"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/yamlutil"
"gopkg.in/yaml.v3"
)
// Save saves the config.
func Save(c config.Config) error {
return yamlutil.Save(c, config.CurrentProfile().File())
}
// SaveFromFile loads configuration from file and save as config.
func SaveFromFile(file string) error {
c, err := LoadFrom(file)
if err != nil {
return err
}
return Save(c)
}
// SaveToFile saves configuration to file.
func SaveToFile(c config.Config, file string) error {
return yamlutil.Save(c, file)
}
// LoadFrom loads config from file.
func LoadFrom(file string) (config.Config, error) {
var c config.Config
b, err := os.ReadFile(file)
if err != nil {
return c, fmt.Errorf("could not load config from file: %w", err)
}
err = yaml.Unmarshal(b, &c)
if err != nil {
return c, fmt.Errorf("could not load config from file: %w", err)
}
return c, nil
}
// ValidateConfig validates config before we use it
func ValidateConfig(c config.Config) error {
validMountTypes := map[string]bool{"9p": true, "sshfs": true}
validPortForwarders := map[string]bool{"grpc": true, "ssh": true, "none": true}
if util.MacOS13OrNewer() {
validMountTypes["virtiofs"] = true
}
if _, ok := validMountTypes[c.MountType]; !ok {
return fmt.Errorf("invalid mountType: '%s'", c.MountType)
}
validVMTypes := map[string]bool{"qemu": true}
if util.MacOS13OrNewer() {
validVMTypes["vz"] = true
}
if util.MacOS13OrNewerOnArm() {
validVMTypes["krunkit"] = true
}
if c.VMType == "krunkit" && !util.MacOS13OrNewerOnArm() {
return fmt.Errorf("vmType 'krunkit' is only available on macOS with Apple Silicon")
}
if _, ok := validVMTypes[c.VMType]; !ok {
return fmt.Errorf("invalid vmType: '%s'", c.VMType)
}
if c.VMType == "qemu" {
if err := util.AssertQemuImg(); err != nil {
return fmt.Errorf("cannot use vmType: '%s', error: %w", c.VMType, err)
}
}
if c.VMType == "krunkit" {
if err := util.AssertKrunkit(); err != nil {
return fmt.Errorf("cannot use vmType: '%s', error: %w", c.VMType, err)
}
}
if c.DiskImage != "" {
if strings.HasPrefix(c.DiskImage, "http://") || strings.HasPrefix(c.DiskImage, "https://") {
return fmt.Errorf("cannot use diskImage: remote URLs not supported, only local files can be specified")
}
}
if _, ok := validPortForwarders[c.PortForwarder]; !ok {
return fmt.Errorf("invalid port forwarder: '%s'", c.PortForwarder)
}
if c.Network.GatewayAddress != nil {
if err := validateGatewayAddress(c.Network.GatewayAddress); err != nil {
return err
}
}
return nil
}
// Load loads the config.
// Error is only returned if the config file exists but could not be loaded.
// No error is returned if the config file does not exist.
func Load() (c config.Config, err error) {
f := config.CurrentProfile().File()
if _, err := os.Stat(f); err != nil {
return c, nil
}
return LoadFrom(f)
}
// LoadInstance is like Load but returns the config of the currently running instance.
func LoadInstance() (config.Config, error) {
return LoadFrom(config.CurrentProfile().StateFile())
}
// Teardown deletes the config.
func Teardown() error {
dir := config.CurrentProfile().ConfigDir()
if _, err := os.Stat(dir); err == nil {
return os.RemoveAll(dir)
}
return nil
}
// Validates that gateway is a valid IPv4 address and that the last octet is “2”.
// Lima uses the last octet as 2 for gateways.
func validateGatewayAddress(gateway net.IP) error {
ip4 := gateway.To4()
if ip4 == nil {
return fmt.Errorf("gateway %q is not IPv4", gateway)
}
// Check last octet
if ip4[3] != 2 {
return fmt.Errorf("the last octet of gateway %q is not 2", gateway)
}
return nil
}
================================================
FILE: config/files.go
================================================
package config
import (
"fmt"
"os"
"path/filepath"
"sync"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/fsutil"
"github.com/sirupsen/logrus"
)
// requiredDir is a directory that must exist on the filesystem
type requiredDir struct {
once sync.Once
// dir is a func to enable deferring the value of the directory
// until execution time.
// if dir() returns an error, a fatal error is triggered.
dir func() (string, error)
computedDir *string
}
// Dir returns the directory path.
// It ensures the directory is created on the filesystem by calling
// `mkdir` prior to returning the directory path.
func (r *requiredDir) Dir() string {
if r.computedDir != nil {
return *r.computedDir
}
dir, err := r.dir()
if err != nil {
logrus.Fatal(fmt.Errorf("cannot fetch required directory: %w", err))
}
r.once.Do(func() {
if err := fsutil.MkdirAll(dir, 0755); err != nil {
logrus.Fatal(fmt.Errorf("cannot make required directory: %w", err))
}
})
r.computedDir = &dir
return dir
}
var (
configBaseDir = requiredDir{
dir: func() (string, error) {
// colima home explicit config
dir := os.Getenv("COLIMA_HOME")
if _, err := os.Stat(dir); err == nil {
return dir, nil
}
// user home directory
homeDir, err := os.UserHomeDir()
if err != nil {
return "", err
}
// colima's config directory based on home directory
dir = filepath.Join(homeDir, ".colima")
// validate existence of colima's config directory
_, err = os.Stat(dir)
// extra xdg config directory
xdgDir, xdg := os.LookupEnv("XDG_CONFIG_HOME")
if err == nil {
// ~/.colima is found but xdg dir is set
if xdg {
logrus.Warnln("found ~/.colima, ignoring $XDG_CONFIG_HOME...")
logrus.Warnln("delete ~/.colima to use $XDG_CONFIG_HOME as config directory")
logrus.Warnf("or run `mv ~/.colima \"%s\"`", filepath.Join(xdgDir, "colima"))
}
return dir, nil
} else {
// ~/.colima is missing and xdg dir is set
if xdg {
return filepath.Join(xdgDir, "colima"), nil
}
}
// macOS users are accustomed to ~/.colima
if util.MacOS() {
return dir, nil
}
// other environments fall back to user config directory
dir, err = os.UserConfigDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "colima"), nil
},
}
cacheDir = requiredDir{
dir: func() (string, error) {
if dir := os.Getenv("COLIMA_CACHE_HOME"); dir != "" {
return dir, nil
}
if dir := os.Getenv("XDG_CACHE_HOME"); dir != "" {
return filepath.Join(dir, "colima"), nil
}
// else
dir, err := os.UserCacheDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "colima"), nil
},
}
templatesDir = requiredDir{
dir: func() (string, error) {
dir, err := configBaseDir.dir()
if err != nil {
return "", err
}
return filepath.Join(dir, "_templates"), nil
},
}
limaDir = requiredDir{
dir: func() (string, error) {
// if LIMA_HOME env var is set, obey it.
if dir := os.Getenv("LIMA_HOME"); dir != "" {
return dir, nil
}
dir, err := configBaseDir.dir()
if err != nil {
return "", err
}
return filepath.Join(dir, "_lima"), nil
},
}
storeDir = requiredDir{
dir: func() (string, error) {
dir, err := configBaseDir.dir()
if err != nil {
return "", err
}
return filepath.Join(dir, "_store"), nil
},
}
)
// CacheDir returns the cache directory.
func CacheDir() string { return cacheDir.Dir() }
// TemplatesDir returns the templates' directory.
func TemplatesDir() string { return templatesDir.Dir() }
// LimaDir returns Lima directory.
func LimaDir() string { return limaDir.Dir() }
const configFileName = "colima.yaml"
// SSHConfigFile returns the path to generated ssh config.
func SSHConfigFile() string { return filepath.Join(configBaseDir.Dir(), "ssh_config") }
================================================
FILE: config/profile.go
================================================
package config
import (
"path/filepath"
"strings"
)
var profile = &Profile{ID: AppName, DisplayName: AppName, ShortName: "default"}
// SetProfile sets the profile name for the application.
// This is an avenue to test Colima without breaking an existing stable setup.
// Not perfect, but good enough for testing.
func SetProfile(profileName string) {
profile = ProfileFromName(profileName)
profile.Changed = true
}
// ProfileFromName retrieves profile given name.
func ProfileFromName(name string) *Profile {
var i Profile
switch name {
case "", AppName, "default":
i.ID = AppName
i.DisplayName = AppName
i.ShortName = "default"
return &i
}
// sanitize
name = strings.TrimPrefix(name, "colima-")
// if custom profile is specified,
// use a prefix to prevent possible name clashes
i.ID = "colima-" + name
i.DisplayName = "colima [profile=" + name + "]"
i.ShortName = name
return &i
}
// CurrentProfile returns the current running profile.
func CurrentProfile() *Profile { return profile }
// Profile is colima profile.
type Profile struct {
ID string
DisplayName string
ShortName string
Changed bool // indicates if the profile has been changed
configDir *requiredDir
}
// ConfigDir returns the configuration directory.
func (p *Profile) ConfigDir() string {
if p.configDir == nil {
p.configDir = &requiredDir{
dir: func() (string, error) {
return filepath.Join(configBaseDir.Dir(), p.ShortName), nil
},
}
}
return p.configDir.Dir()
}
// LimaInstanceDir returns the directory for the Lima instance.
func (p *Profile) LimaInstanceDir() string {
return filepath.Join(limaDir.Dir(), p.ID)
}
// File returns the path to the config file.
func (p *Profile) File() string {
return filepath.Join(p.ConfigDir(), configFileName)
}
// LimaFile returns the path to the lima config file.
func (p *Profile) LimaFile() string {
return filepath.Join(p.LimaInstanceDir(), "lima.yaml")
}
// StateFile returns the path to the state file.
func (p *Profile) StateFile() string {
return filepath.Join(p.LimaInstanceDir(), configFileName)
}
func (p *Profile) StoreFile() string {
return filepath.Join(storeDir.Dir(), p.ID+".json")
}
var _ ProfileInfo = (*Profile)(nil)
// ProfileInfo is the information about a profile.
type ProfileInfo interface {
// ConfigDir returns the configuration directory.
ConfigDir() string
// LimaInstanceDir returns the directory for the Lima instance.
LimaInstanceDir() string
// File returns the path to the config file.
File() string
// LimaFile returns the path to the lima config file.
LimaFile() string
// StateFile returns the path to the state file.
StateFile() string
// StoreFile returns the path to the store file.
StoreFile() string
}
================================================
FILE: core/core.go
================================================
package core
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"github.com/sirupsen/logrus"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/environment"
"github.com/coreos/go-semver/semver"
)
const limaVersion = "v0.18.0" // minimum Lima version supported
type (
hostActions = environment.HostActions
guestActions = environment.GuestActions
)
// SetupBinfmt downloads and install binfmt
func SetupBinfmt(host hostActions, guest guestActions, arch environment.Arch) error {
qemuArch := environment.AARCH64
if arch.Value().GoArch() == "arm64" {
qemuArch = environment.X8664
}
install := func() error {
if err := guest.Run("sh", "-c", "sudo QEMU_PRESERVE_ARGV0=1 /usr/bin/binfmt --install 386,"+qemuArch.GoArch()); err != nil {
return fmt.Errorf("error installing binfmt: %w", err)
}
return nil
}
// validate binfmt
if err := guest.RunQuiet("command", "-v", "binfmt"); err != nil {
return fmt.Errorf("binfmt not found: %w", err)
}
return install()
}
// LimaVersionSupported checks if the currently installed Lima version is supported.
func LimaVersionSupported() error {
var values struct {
Version string `json:"version"`
}
var buf bytes.Buffer
cmd := cli.Command("limactl", "info")
cmd.Stdout = &buf
if err := cmd.Run(); err != nil {
return fmt.Errorf("error checking Lima version: %w", err)
}
if err := json.NewDecoder(&buf).Decode(&values); err != nil {
return fmt.Errorf("error decoding 'limactl info' json: %w", err)
}
// remove pre-release hyphen
parts := strings.SplitN(values.Version, "-", 2)
if len(parts) > 0 {
values.Version = parts[0]
}
if parts[0] == "HEAD" {
logrus.Warnf("to avoid compatibility issues, ensure lima development version (%s) in use is not lower than %s", values.Version, limaVersion)
return nil
}
min := semver.New(strings.TrimPrefix(limaVersion, "v"))
current, err := semver.NewVersion(strings.TrimPrefix(values.Version, "v"))
if err != nil {
return fmt.Errorf("invalid semver version for Lima: %w", err)
}
if min.Compare(*current) > 0 {
return fmt.Errorf("minimum Lima version supported is %s, current version is %s", limaVersion, values.Version)
}
return nil
}
================================================
FILE: daemon/daemon.go
================================================
package daemon
import (
"context"
"fmt"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/daemon/process/inotify"
"github.com/abiosoft/colima/daemon/process/vmnet"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/util"
"github.com/abiosoft/colima/util/fsutil"
"github.com/abiosoft/colima/util/osutil"
)
// Manager handles running background processes.
type Manager interface {
Start(context.Context, config.Config) error
Stop(context.Context, config.Config) error
Running(context.Context, config.Config) (Status, error)
Dependency(ctx context.Context, conf config.Config, name string) (deps process.Dependency, root bool)
}
type Status struct {
// Parent process
Running bool
// Subprocesses
Processes []processStatus
}
type processStatus struct {
Name string
Running bool
Error error
}
// NewManager creates a new process manager.
func NewManager(host environment.HostActions) Manager {
return &processManager{
host: host,
}
}
func CtxKey(s string) any { return struct{ key string }{key: s} }
var _ Manager = (*processManager)(nil)
type processManager struct {
host environment.HostActions
}
func (l processManager) Dependency(ctx context.Context, conf config.Config, name string) (deps process.Dependency, root bool) {
processes := processesFromConfig(conf)
for _, p := range processes {
if p.Name() == name {
return process.Dependencies(p)
}
}
return process.Dependencies()
}
func (l processManager) init() error {
// dependencies for network
if err := fsutil.MkdirAll(process.Dir(), 0755); err != nil {
return fmt.Errorf("error preparing vmnet: %w", err)
}
return nil
}
func (l processManager) Running(ctx context.Context, conf config.Config) (s Status, err error) {
err = l.host.RunQuiet(osutil.Executable(), "daemon", "status", config.CurrentProfile().ShortName)
if err != nil {
return
}
s.Running = true
ctx = context.WithValue(ctx, process.CtxKeyDaemon(), s.Running)
for _, p := range processesFromConfig(conf) {
pErr := p.Alive(ctx)
s.Processes = append(s.Processes, processStatus{
Name: p.Name(),
Running: pErr == nil,
Error: pErr,
})
}
return
}
func (l processManager) Start(ctx context.Context, conf config.Config) error {
_ = l.Stop(ctx, conf) // this is safe, nothing is done when not running
if err := l.init(); err != nil {
return fmt.Errorf("error preparing daemon directory: %w", err)
}
args := []string{osutil.Executable(), "daemon", "start", config.CurrentProfile().ShortName}
if conf.Network.Address {
args = append(args, "--vmnet")
args = append(args, "--vmnet-mode", conf.Network.Mode)
args = append(args, "--vmnet-interface", conf.Network.BridgeInterface)
}
if conf.MountINotify {
args = append(args, "--inotify")
args = append(args, "--inotify-runtime", conf.Runtime)
for _, mount := range conf.MountsOrDefault() {
p, err := util.CleanPath(mount.Location)
if err != nil {
return fmt.Errorf("error sanitising mount path for inotify: %w", err)
}
args = append(args, "--inotify-dir", p)
}
}
if cli.Settings.Verbose {
args = append(args, "--very-verbose")
}
host := l.host.WithDir(util.HomeDir())
return host.RunQuiet(args...)
}
func (l processManager) Stop(ctx context.Context, conf config.Config) error {
if s, err := l.Running(ctx, conf); err != nil || !s.Running {
return nil
}
return l.host.RunQuiet(osutil.Executable(), "daemon", "stop", config.CurrentProfile().ShortName)
}
func processesFromConfig(conf config.Config) []process.Process {
var processes []process.Process
if conf.Network.Address {
processes = append(processes, vmnet.New(conf.Network.Mode, conf.Network.BridgeInterface))
}
if conf.MountINotify {
processes = append(processes, inotify.New())
}
return processes
}
================================================
FILE: daemon/process/inotify/events.go
================================================
package inotify
import (
"context"
"fmt"
"io/fs"
"time"
)
type modEvent struct {
path string // filename
fs.FileMode
}
func (m modEvent) Mode() string { return fmt.Sprintf("%o", m.FileMode) }
func (f *inotifyProcess) handleEvents(ctx context.Context, watcher dirWatcher) error {
log := f.log
log.Trace("begin inotify event handler")
mod := make(chan modEvent)
vols := make(chan []string)
if err := f.monitorContainerVolumes(ctx, vols); err != nil {
return fmt.Errorf("error watching container volumes: %w", err)
}
var last time.Time
var cancelWatch context.CancelFunc
var currentVols []string
volsChanged := func(vols []string) bool {
if len(currentVols) != len(vols) {
return true
}
for i := range vols {
if vols[i] != currentVols[i] {
return true
}
}
return false
}
cache := map[string]struct{}{}
for {
select {
// exit signal
case <-ctx.Done():
close(mod)
return ctx.Err()
// watch only container volumes
case vols := <-vols:
if !volsChanged(vols) {
continue
}
log.Tracef("volumes changed from: %+v, to: %+v", currentVols, vols)
currentVols = vols
if cancel := cancelWatch; cancel != nil {
// delay a bit to avoid zero downtime
time.AfterFunc(time.Second*1, cancel)
}
ctx, cancel := context.WithCancel(ctx)
cancelWatch = cancel
go func(ctx context.Context, vols []string, mod chan<- modEvent) {
if err := watcher.Watch(ctx, vols, mod); err != nil {
log.Error(fmt.Errorf("error running watcher: %w", err))
}
}(ctx, vols, mod)
// handle modification events
case ev := <-mod:
now := time.Now()
// rate limit, handle at most 50 unique items every 500 ms
if now.Sub(last) < time.Millisecond*500 {
if _, ok := cache[ev.path]; ok {
continue // handled, ignore
}
if len(cache) > 50 {
continue
}
} else {
last = now
cache = map[string]struct{}{} // >500ms, reset unique cache
}
// cache current event
cache[ev.path] = struct{}{}
// validate that file exists
if err := f.guest.RunQuiet("stat", ev.path); err != nil {
log.Trace(fmt.Errorf("cannot stat '%s': %w", ev.path, err))
continue
}
log.Infof("syncing inotify event for %s ", ev.path)
if err := f.guest.RunQuiet("sudo", "/bin/chmod", ev.Mode(), ev.path); err != nil {
log.Trace(fmt.Errorf("error syncing inotify event: %w", err))
}
}
}
}
================================================
FILE: daemon/process/inotify/inotify.go
================================================
package inotify
import (
"context"
"fmt"
"time"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/environment"
"github.com/abiosoft/colima/environment/vm/lima/limautil"
"github.com/sirupsen/logrus"
)
const Name = "inotify"
const volumesInterval = 5 * time.Second
type Args struct {
environment.GuestActions
Dirs []string
Runtime string
}
func CtxKeyArgs() any { return struct{ name string }{name: "inotify_args"} }
// New returns inotify process.
func New() process.Process {
return &inotifyProcess{
log: logrus.WithField("context", "inotify"),
}
}
var _ process.Process = (*inotifyProcess)(nil)
type inotifyProcess struct {
vmVols []string
guest environment.GuestActions
runtime string
log *logrus.Entry
}
// Alive implements process.Process
func (f *inotifyProcess) Alive(ctx context.Context) error {
daemonRunning, _ := ctx.Value(process.CtxKeyDaemon()).(bool)
// if the parent is active, we can assume inotify is active.
if daemonRunning {
return nil
}
return fmt.Errorf("inotify not running")
}
// Dependencies implements process.Process
func (*inotifyProcess) Dependencies() (deps []process.Dependency, root bool) {
return nil, false
}
// Name implements process.Process
func (*inotifyProcess) Name() string {
return Name
}
// Start implements process.Process
func (f *inotifyProcess) Start(ctx context.Context) error {
args, ok := ctx.Value(CtxKeyArgs()).(Args)
if !ok {
return fmt.Errorf("args missing in context")
}
f.vmVols = omitChildrenDirectories(args.Dirs)
f.guest = args.GuestActions
f.runtime = args.Runtime
log := f.log
log.Info("waiting for VM to start")
f.waitForLima(ctx)
log.Info("VM started")
watcher := &defaultWatcher{log: log}
return f.handleEvents(ctx, watcher)
}
// waitForLima waits until lima starts and sets the directory to watch.
func (f *inotifyProcess) waitForLima(ctx context.Context) {
log := f.log
// wait for Lima to finish starting
for {
log.Info("waiting 5 secs for VM")
// 5 second interval
after := time.After(time.Second * 5)
select {
case <-ctx.Done():
return
case <-after:
i, err := limautil.Instance()
if err != nil || !i.Running() {
continue
}
if err := f.guest.RunQuiet("uname", "-a"); err == nil {
return
}
}
}
}
================================================
FILE: daemon/process/inotify/volumes.go
================================================
package inotify
import (
"bytes"
"context"
"encoding/json"
"fmt"
"sort"
"strings"
"time"
"github.com/abiosoft/colima/environment/container/containerd"
"github.com/abiosoft/colima/environment/container/docker"
)
func (f *inotifyProcess) monitorContainerVolumes(ctx context.Context, c chan<- []string) error {
log := f.log
if f.runtime == "" {
return fmt.Errorf("empty runtime")
}
fetch := func() ([]string, error) {
var vols []string
switch f.runtime {
case docker.Name:
vols, err := f.fetchVolumes(docker.Name)
if err != nil {
return nil, fmt.Errorf("error fetching docker volumes: %w", err)
}
return vols, nil
case containerd.Name:
var namespaces []string
out, err := f.guest.RunOutput("sudo", "nerdctl", "namespace", "list", "-q")
if err != nil {
return nil, fmt.Errorf("error retrieving containerd namespaces: %w", err)
}
if out != "" {
namespaces = strings.Fields(out)
}
for _, ns := range namespaces {
v, err := f.fetchVolumes("sudo", "nerdctl", "--namespace", ns)
if err != nil {
return nil, fmt.Errorf("error retrieving containerd volumes: %w", err)
}
if len(v) > 0 {
vols = append(vols, v...)
}
}
return vols, nil
}
return nil, nil
}
go func() {
for {
select {
case <-ctx.Done():
log.Trace("stop signal received")
err := ctx.Err()
if err != nil {
log.Trace(fmt.Errorf("error during stop: %w", err))
}
case <-time.After(volumesInterval):
if vols, err := fetch(); err != nil {
log.Error(err)
} else {
c <- vols
}
}
}
}()
return nil
}
func (f *inotifyProcess) fetchVolumes(cmdArgs ...string) ([]string, error) {
log := f.log
// fetch all containers
var containers []string
{
args := append([]string{}, cmdArgs...)
args = append(args, "ps", "-q")
out, err := f.guest.RunOutput(args...)
if err != nil {
return nil, fmt.Errorf("error listing containers: %w", err)
}
containers = strings.Fields(out)
if len(containers) == 0 {
return nil, nil
}
}
log.Tracef("found containers %+v", containers)
// fetch volumes
var resp []struct {
Mounts []struct {
Source string `json:"Source"`
} `json:"Mounts"`
}
{
args := append([]string{}, cmdArgs...)
args = append(args, "inspect")
args = append(args, containers...)
var buf bytes.Buffer
if err := f.guest.RunWith(nil, &buf, args...); err != nil {
return nil, fmt.Errorf("error inspecting containers: %w", err)
}
if err := json.NewDecoder(&buf).Decode(&resp); err != nil {
return nil, fmt.Errorf("error decoding docker response")
}
}
// process and discard redundant volumes
vols := []string{}
{
shouldMount := func(child string) bool {
// ignore all invalid directories.
// i.e. directories not within the mounted VM directories
for _, parent := range f.vmVols {
if strings.HasPrefix(child, parent) {
return true
}
}
return false
}
for _, r := range resp {
for _, mount := range r.Mounts {
if shouldMount(mount.Source) {
vols = append(vols, mount.Source)
}
}
}
vols = omitChildrenDirectories(vols)
log.Tracef("found volumes %+v", vols)
}
return vols, nil
}
func omitChildrenDirectories(dirs []string) []string {
sort.Strings(dirs) // sort to put the parent directories first
// keep track for uniqueness
set := map[string]struct{}{}
var newVols []string
omitted := map[int]struct{}{}
for i := 0; i < len(dirs); i++ {
// if the index is omitted, skip
if _, ok := omitted[i]; ok {
continue
}
parent := dirs[i]
if _, ok := set[parent]; !ok {
newVols = append(newVols, parent)
set[parent] = struct{}{}
}
for j := i + 1; j < len(dirs); j++ {
child := dirs[j]
if strings.HasPrefix(child, strings.TrimSuffix(parent, "/")+"/") {
omitted[j] = struct{}{}
}
}
}
return newVols
}
================================================
FILE: daemon/process/inotify/volumes_test.go
================================================
package inotify
import (
"reflect"
"strconv"
"testing"
)
func Test_omitChildrenDirectories(t *testing.T) {
tests := []struct {
args []string
want []string
}{
{
args: []string{"/", "/user", "/user/someone", "/a", "/a/ee", "/a/bb"},
want: []string{"/"},
},
{
args: []string{"/someone", "/user", "/user/someone", "/a", "/a/ee", "/a/bb", "/a"},
want: []string{"/a", "/someone", "/user"},
},
{
args: []string{"/someone", "/user/colima/projects/myworks", "/user/colima/projects", "/user/colima/projects/myworks", "/user/colima/projects", "/someone"},
want: []string{"/someone", "/user/colima/projects"},
},
{
args: []string{"/someone", "/user/colima/projects/myworks", "/user/colima/projects"},
want: []string{"/someone", "/user/colima/projects"},
},
{
args: []string{"/user/colima/projects"},
want: []string{"/user/colima/projects"},
},
}
for i, tt := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
if got := omitChildrenDirectories(tt.args); !reflect.DeepEqual(got, tt.want) {
t.Errorf("omitChildrenDirectories() = %v, want %v", got, tt.want)
}
})
}
}
================================================
FILE: daemon/process/inotify/watch.go
================================================
package inotify
import (
"context"
"fmt"
"os"
"github.com/abiosoft/colima/util"
"github.com/rjeczalik/notify"
"github.com/sirupsen/logrus"
)
type dirWatcher interface {
// Watch watches directories recursively for changes and sends message via c on
// modifications to files within the watched directories.
//
// Watch returns immediately and runs the watcher in the background.
// An error is returned when the watcher can not be started in background.
//
// The watcher terminates on fatal error or when ctx is done.
Watch(ctx context.Context, dirs []string, c chan<- modEvent) error
}
type defaultWatcher struct {
log *logrus.Entry
}
// Watch implements dirWatcher
func (d *defaultWatcher) Watch(ctx context.Context, dirs []string, mod chan<- modEvent) error {
log := d.log
c := make(chan notify.EventInfo, 1)
for _, dir := range dirs {
dir, err := util.CleanPath(dir)
if err != nil {
return fmt.Errorf("invalid directory: %w", err)
}
err = notify.Watch(dir+"...", c, notify.Write)
if err != nil {
return fmt.Errorf("error watching directory recursively '%s': %w", dir, err)
}
}
go func(ctx context.Context, c chan notify.EventInfo, mod chan<- modEvent) {
for {
select {
case <-ctx.Done():
notify.Stop(c)
log.Trace("stopping watcher")
if err := ctx.Err(); err != nil {
log.Trace(fmt.Errorf("error found in ctx: %w", err))
return
}
case e := <-c:
path := e.Path()
log.Tracef("received event %s for %s", e.Event().String(), path)
stat, err := os.Stat(path)
if err != nil {
log.Trace(fmt.Errorf("unable to stat inotify file '%s': %w", path, err))
continue
}
if stat.IsDir() {
log.Tracef("'%s' is directory, ignoring.", path)
continue
}
// send modification event
mod <- modEvent{path: path, FileMode: stat.Mode()}
}
}
}(ctx, c, mod)
return nil
}
var _ dirWatcher = (*defaultWatcher)(nil)
================================================
FILE: daemon/process/process.go
================================================
package process
import (
"context"
"fmt"
"path/filepath"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment"
)
func CtxKeyDaemon() any { return struct{ key string }{key: "colima_daemon"} }
// Process is a background process managed by the daemon.
type Process interface {
// Name for the background process
Name() string
// Start starts the background process.
// The process is expected to terminate when ctx is done.
Start(ctx context.Context) error
// Alive checks if the process is the alive.
Alive(ctx context.Context) error
// Dependencies are requirements for start to succeed.
// root should be true if root access is required for
// installing any of the dependencies.
Dependencies() (deps []Dependency, root bool)
}
// Dir is the directory for daemon files.
func Dir() string { return filepath.Join(config.CurrentProfile().ConfigDir(), "daemon") }
// Dependency is a requirement to be fulfilled before a process can be started.
type Dependency interface {
Installed() bool
Install(environment.HostActions) error
}
// Dependencies returns the dependencies for the processes.
// root returns if root access is required
func Dependencies(processes ...Process) (deps Dependency, root bool) {
// check rootful for user info message
rootful := false
for _, p := range processes {
deps, root := p.Dependencies()
for _, dep := range deps {
if !dep.Installed() && root {
rootful = true
break
}
}
}
return processDeps(processes), rootful
}
type processDeps []Process
func (p processDeps) Installed() bool {
for _, process := range p {
deps, _ := process.Dependencies()
for _, d := range deps {
if !d.Installed() {
return false
}
}
}
return true
}
func (p processDeps) Install(host environment.HostActions) error {
for _, process := range p {
deps, _ := process.Dependencies()
for _, d := range deps {
if !d.Installed() {
if err := d.Install(host); err != nil {
return fmt.Errorf("error occurred installing dependencies for '%s': %w", process.Name(), err)
}
}
}
}
return nil
}
================================================
FILE: daemon/process/vmnet/deps.go
================================================
package vmnet
import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/embedded"
"github.com/abiosoft/colima/environment"
)
var _ process.Dependency = sudoerFile{}
type sudoerFile struct{}
// Installed implements Dependency
func (s sudoerFile) Installed() bool { return embedded.SudoersInstalled() }
// Install implements Dependency
func (s sudoerFile) Install(host environment.HostActions) error {
return embedded.InstallSudoers(host)
}
var _ process.Dependency = vmnetFile{}
const BinaryPath = "/opt/colima/bin/socket_vmnet"
const ClientBinaryPath = "/opt/colima/bin/socket_vmnet_client"
type vmnetFile struct{}
// Installed implements Dependency
func (v vmnetFile) Installed() bool {
for _, bin := range v.bins() {
if _, err := os.Stat(bin); err != nil {
return false
}
}
return true
}
func (v vmnetFile) bins() []string {
return []string{BinaryPath, ClientBinaryPath}
}
func (v vmnetFile) Install(host environment.HostActions) error {
arch := "x86_64"
if runtime.GOARCH != "amd64" {
arch = "arm64"
}
// read the embedded file
gz, err := embedded.Read("network/vmnet_" + arch + ".tar.gz")
if err != nil {
return fmt.Errorf("error retrieving embedded vmnet file: %w", err)
}
// write tar to tmp directory
f, err := os.CreateTemp("", "vmnet.tar.gz")
if err != nil {
return fmt.Errorf("error creating temp file: %w", err)
}
if _, err := f.Write(gz); err != nil {
return fmt.Errorf("error writing temp file: %w", err)
}
_ = f.Close() // not a fatal error
defer func() {
_ = os.Remove(f.Name())
}()
// extract tar to desired location
dir := optDir
if err := host.RunInteractive("sudo", "mkdir", "-p", dir); err != nil {
return fmt.Errorf("error preparing colima privileged dir: %w", err)
}
if err := host.RunInteractive("sudo", "sh", "-c", fmt.Sprintf("cd %s && tar xfz %s 2>/dev/null", dir, f.Name())); err != nil {
return fmt.Errorf("error extracting vmnet archive: %w", err)
}
return nil
}
var _ process.Dependency = vmnetRunDir{}
type vmnetRunDir struct{}
// Install implements Dependency
func (v vmnetRunDir) Install(host environment.HostActions) error {
return host.RunInteractive("sudo", "mkdir", "-p", runDir())
}
// Installed implements Dependency
func (v vmnetRunDir) Installed() bool {
stat, err := os.Stat(runDir())
return err == nil && stat.IsDir()
}
const optDir = "/opt/colima"
// runDir is the directory to the rootful daemon run related files. e.g. pid files
func runDir() string { return filepath.Join(optDir, "run") }
================================================
FILE: daemon/process/vmnet/vmnet.go
================================================
package vmnet
import (
"context"
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/daemon/process"
"github.com/abiosoft/colima/util/osutil"
"github.com/sirupsen/logrus"
)
const Name = "vmnet"
const (
SubProcessEnvVar = "COLIMA_VMNET"
NetGateway = "192.168.106.1"
NetDHCPEnd = "192.168.106.254"
)
var _ process.Process = (*vmnetProcess)(nil)
func New(mode, netInterface string) process.Process {
return &vmnetProcess{
mode: mode,
netInterface: netInterface,
}
}
type vmnetProcess struct {
mode string
netInterface string
}
func (*vmnetProcess) Alive(ctx context.Context) error {
info := Info()
pidFile := info.PidFile
socketFile := info.Socket.File()
if _, err := os.Stat(pidFile); err == nil {
cmd := exec.CommandContext(ctx, "sudo", "/usr/bin/pkill", "-0", "-F", pidFile)
if err := cmd.Run(); err != nil {
return fmt.Errorf("error checking vmnet process: %w", err)
}
}
if _, err := os.Stat(socketFile); err != nil {
return fmt.Errorf("vmnet socket file not found error: %w", err)
}
if n, err := net.Dial("unix", socketFile); err != nil {
return fmt.Errorf("vmnet socket file error: %w", err)
} else {
if err := n.Close(); err != nil {
logrus.Debugln(fmt.Errorf("error closing ping socket connection: %w", err))
}
}
return nil
}
// Name implements process.BgProcess
func (*vmnetProcess) Name() string { return Name }
// Start implements process.BgProcess
func (v *vmnetProcess) Start(ctx context.Context) error {
info := Info()
socket := info.Socket.File()
pid := info.PidFile
// delete existing sockets if exist
// errors ignored on purpose
_ = forceDeleteFileIfExists(socket)
done := make(chan error, 1)
go func() {
// rootfully start the vmnet daemon
var command *exec.Cmd
if v.mode == "bridged" {
command = cli.CommandInteractive("sudo", BinaryPath,
"--vmnet-mode", "bridged",
"--socket-group", "staff",
"--vmnet-interface", v.netInterface,
"--pidfile", pid,
socket,
)
} else {
command = cli.CommandInteractive("sudo", BinaryPath,
"--vmnet-mode", "shared",
"--socket-group", "staff",
"--vmnet-gateway", NetGateway,
"--vmnet-dhcp-end", NetDHCPEnd,
"--pidfile", pid,
socket,
)
}
if cli.Settings.Verbose {
command.Env = append(command.Env, os.Environ()...)
command.Env = append(command.Env, "DEBUG=1")
}
done <- command.Run()
}()
select {
case <-ctx.Done():
if err := stop(pid); err != nil {
return fmt.Errorf("error stopping vmnet: %w", err)
}
case err := <-done:
if err != nil {
return fmt.Errorf("error running vmnet: %w", err)
}
}
return nil
}
func (vmnetProcess) Dependencies() (deps []process.Dependency, root bool) {
return []process.Dependency{
sudoerFile{},
vmnetFile{},
vmnetRunDir{},
}, true
}
func stop(pidFile string) error {
// rootfully kill the vmnet process.
// process is only assumed alive if the pidfile exists
if _, err := os.Stat(pidFile); err == nil {
if err := cli.CommandInteractive("sudo", "/usr/bin/pkill", "-F", pidFile).Run(); err != nil {
return fmt.Errorf("error killing vmnet process: %w", err)
}
}
return nil
}
func forceDeleteFileIfExists(name string) error {
if stat, err := os.Stat(name); err == nil && !stat.IsDir() {
return os.Remove(name)
}
return nil
}
func Info() struct {
PidFile string
Socket osutil.Socket
} {
return struct {
PidFile string
Socket osutil.Socket
}{
PidFile: filepath.Join(runDir(), "vmnet-"+config.CurrentProfile().ShortName+".pid"),
Socket: osutil.Socket(filepath.Join(process.Dir(), "vmnet.sock")),
}
}
================================================
FILE: default.nix
================================================
with import <nixpkgs> { };
callPackage (import ./colima.nix) { }
================================================
FILE: docs/CONTRIBUTE.md
================================================
# Contributing to Colima
Thank you for your interest in contributing to Colima!
## Getting Started
Colima is a Go project. To contribute, you will need Go installed (see the [Go installation guide](https://golang.org/doc/install)).
### 1. Fork the Repository
First, fork the Colima repository on GitHub. Then, clone your fork locally:
```sh
git clone https://github.com/<your-username>/colima.git
cd colima
```
### 2. Create a New Branch
Create a new branch for your changes:
```sh
git checkout -b my-feature-branch
```
### 3. Commit Your Changes
Commit your changes with a DCO signoff and the required commit message format. Each commit must include a signoff line:
```
Signed-off-by: Your Name <your.email@example.com>
```
You can add this automatically with:
```sh
git commit -s -m "component: <message>"
# Example:
git commit -s -m "cli: add my-command to colima start"
```
### 4. Push Your Branch
Push your branch to your fork:
```sh
git push origin my-feature-branch
```
### 5. Open a Pull Request
Open a Pull Request against the main Colima repository.
## 6. DCO Signoff
Colima requires all commits to be signed off using the [Developer Certificate of Origin (DCO)](https://developercertificate.org/). This is a simple statement that you, as a contributor, have the right to submit your changes.
## Contribution Guidelines
### Major Contributions
Major contributions (new features, significant changes) should be preceded by a GitHub issue discussing the proposed change.
### Minor Contributions
Minor contributions (small fixes, documentation e.t.c.) do not require a prior issue.
### LLM Usage Disclosure
If you use a Large Language Model (LLM) to generate code, you must fully disclose its usage in your pull request, including which parts were generated and to what extent.
### LLM Reviewability
Large code contributions generated by LLMs that are not easily reviewable or understandable will be rejected.
## Reviewing and Merging
All PRs are subject to review.
Kindly ensure that your PR passes all CI checks. You are also obliged to respond to review comments and update your PR as needed.
## Need Help?
If you have questions, open an [issue](https://github.com/abiosoft/colima/issues) or start a [discussion](https://github.com/abiosoft/colima/discussions) in the repository.
---
Thank you for helping to improve Colima!
================================================
FILE: docs/FAQ.md
================================================
# FAQs
- [FAQs](#faqs)
- [How does Colima compare to Lima?](#how-does-colima-compare-to-lima)
- [Are Apple Silicon Macs supported?](#are-apple-silicon-macs-supported)
- [Are AI workloads supported?](#are-ai-workloads-supported)
- [Are older macOS versions supported?](#are-older-macos-versions-supported)
- [Does Colima support autostart?](#does-colima-support-autostart)
- [Can config file be used instead of cli flags?](#can-config-file-be-used-instead-of-cli-flags)
- [Specifying the config location](#specifying-the-config-location)
- [Editing the config](#editing-the-config)
- [Setting the default config](#setting-the-default-config)
- [Specifying the config editor](#specifying-the-config-editor)
- [How do I change where Colima files are stored?](#how-do-i-change-where-colima-files-are-stored)
- [How do I pass custom environment variables into the VM?](#how-do-i-pass-custom-environment-variables-into-the-vm)
- [Docker](#docker)
- [Can it run alongside Docker for Mac?](#can-it-run-alongside-docker-for-mac)
- [Docker socket location](#docker-socket-location)
- [v0.3.4 or older](#v034-or-older)
- [v0.4.0 or newer](#v040-or-newer)
- [Listing Docker contexts](#listing-docker-contexts)
- [Changing the active Docker context](#changing-the-active-docker-context)
- [Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?](#cannot-connect-to-the-docker-daemon-at-unixvarrundockersock-is-the-docker-daemon-running)
- [How to customize Docker config (e.g., adding insecure registries or registry mirrors)?](#how-to-customize-docker-config-eg-adding-insecure-registries-or-registry-mirrors)
- [Docker buildx plugin is missing](#docker-buildx-plugin-is-missing)
- [Installing Buildx](#installing-buildx)
- [Containerd](#containerd)
- [How to customize Containerd config?](#how-to-customize-containerd-config)
- [Per-profile overrides](#per-profile-overrides)
- [How does Colima compare to minikube, Kind, K3d?](#how-does-colima-compare-to-minikube-kind-k3d)
- [For Kubernetes](#for-kubernetes)
- [For Docker](#for-docker)
- [Is another Distro supported?](#is-another-distro-supported)
- [Version v0.5.6 and lower](#version-v056-and-lower)
- [Enabling Ubuntu layer](#enabling-ubuntu-layer)
- [Accessing the underlying Virtual Machine](#accessing-the-underlying-virtual-machine)
- [Version v0.6.0 and newer](#version-v060-and-newer)
- [The Virtual Machine's IP is not reachable](#the-virtual-machines-ip-is-not-reachable)
- [Enable reachable IP address](#enable-reachable-ip-address)
- [Incus instances are not reachable from the host](#incus-instances-are-not-reachable-from-the-host)
- [How can disk space be recovered?](#how-can-disk-space-be-recovered)
- [Automatic](#automatic)
- [Manual](#manual)
- [How can disk size be increased?](#how-can-disk-size-be-increased)
- [Are Lima overrides supported?](#are-lima-overrides-supported)
- [Example: Adding provision scripts](#example-adding-provision-scripts)
- [How can the VM and its tools be updated?](#how-can-the-vm-and-its-tools-be-updated)
- [Updating Colima](#updating-colima)
- [Updating the container runtime](#updating-the-container-runtime)
- [Accessing the Virtual Machine](#accessing-the-virtual-machine)
- [Troubleshooting](#troubleshooting)
- [Colima not starting](#colima-not-starting)
- [Broken status](#broken-status)
- [FATA\[0000\] error starting vm: error at 'starting': exit status 1](#fata0000-error-starting-vm-error-at-starting-exit-status-1)
- [Issues after an upgrade](#issues-after-an-upgrade)
- [Colima cannot access the internet.](#colima-cannot-access-the-internet)
- [Docker Compose and Buildx showing runc error](#docker-compose-and-buildx-showing-runc-error)
- [Version v0.5.6 or lower](#version-v056-or-lower)
- [Issue with Docker bind mount showing empty](#issue-with-docker-bind-mount-showing-empty)
- [How can Docker version be updated?](#how-can-docker-version-be-updated)
- [How can I delete container data](#how-can-i-delete-container-data)
## How does Colima compare to Lima?
Colima is basically a higher level usage of Lima and utilises Lima to provide Docker, Containerd and/or Kubernetes.
## Are Apple Silicon Macs supported?
Colima supports and works on both Intel and Apple Silicon Macs.
Feedbacks would be appreciated.
## Are AI workloads supported?
Yes, Colima supports GPU accelerated containers for AI workloads on Apple Silicon Macs running macOS 13 or newer.
To get started, start Colima with Docker runtime and krunkit VM type:
```sh
colima start --runtime docker --vm-type krunkit
```
Then setup and run AI models:
```sh
colima model setup
colima model run gemma3
```
Multiple model registries are supported including HuggingFace (default) and Ollama:
```sh
colima model run hf://tinyllama
colima model run ollama://tinyllama
```
For more options, run `colima model --help`.
## Are older macOS versions supported?
Colima is supported and regularly tested on the latest macOS version. However, Colima requires macOS 13 or newer.
You may be able to build Colima and it's dependencies from source on older macOS version. Colima requires [Lima](https://github.com/lima-vm/lima) and [Qemu](https://www.qemu.org/).
## Does Colima support autostart?
Since v0.5.6 Colima supports foreground mode via the `--foreground` flag. i.e. `colima start --foreground`.
If Colima has been installed using brew, the easiest way to autostart Colima is to use brew services.
```sh
brew services start colima
```
## Can config file be used instead of cli flags?
Yes, from v0.4.0, Colima support YAML configuration file.
### Specifying the config location
Set the `$COLIMA_HOME` environment variable, otherwise it defaults to `$HOME/.colima`.
### Editing the config
```
colima start --edit
```
For manual edit, the config file is located at `$HOME/.colima/default/colima.yaml`.
For other profiles, `$HOME/.colima/<profile-name>/colima.yaml`
### Setting the default config
```
colima template
```
For manual edit, the template file is located at `$HOME/.colima/_templates/default.yaml`.
### Specifying the config editor
Set the `$EDITOR` environment variable or use the `--editor` flag.
```sh
colima start --edit --editor code # one-off config
colima template --editor code # default config
```
## How do I change where Colima files are stored?
Colima supports these environment variables, set on your host machine:
| Variable | Description |
|----------|-------------|
| `COLIMA_HOME` | Colima configuration directory (default: `$HOME/.colima`) |
| `COLIMA_CACHE_HOME` | Colima cache directory (default is host-specific, see [os.UserCacheDir()](https://pkg.go.dev/os#UserCacheDir)) |
| `COLIMA_PROFILE` | Active profile name (default: `default`) |
| `DOCKER_CONFIG` | Path to Docker client configuration directory (default: `~/.docker`) |
## How do I pass custom environment variables into the VM?
Pass environment variables into the VM at startup using the YAML configuration file:
```yaml
env:
MY_VAR: value
```
You can also use command-line flags:
```bash session
# On your host machine...
$ colima start --env MY_VAR=value
# Then, within the VM...
$ colima ssh
user@colima:~$ env | grep MY_VAR
MY_VAR=value
```
## Docker
### Can it run alongside Docker for Mac?
Yes, from version v0.3.0 Colima leverages Docker contexts and can thereby run alongside Docker for Mac.
Colima makes itself the default Docker context on startup and should work straight away.
### Docker socket location
#### v0.3.4 or older
Docker socket is located at `$HOME/.colima/docker.sock`
#### v0.4.0 or newer
Docker socket is located at `$HOME/.colima/default/docker.sock`
It can also be retrieved by checking status
```
colima status
```
#### Listing Docker contexts
```
docker context list
```
#### Changing the active Docker context
```
docker context use <context-name>
```
### Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Colima uses Docker contexts to allow co-existence with other Docker servers and sets itself as the default Docker context on startup.
However, some applications are not aware of Docker contexts and may lead to the error.
This can be fixed by any of the following approaches. Ensure the Docker socket path by checking the [socket location](#docker-socket-location).
1. Setting application specific Docker socket path if supported by the application. e.g. JetBrains IDEs.
2. Setting the `DOCKER_HOST` environment variable to point to Colima socket.
```sh
export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"
```
3. Linking the Colima socket to the default socket path. **Note** that this may break other Docker servers.
```sh
sudo ln -sf $HOME/.colima/default/docker.sock /var/run/docker.sock
```
### How to customize Docker config (e.g., adding insecure registries or registry mirrors)?
* v0.3.4 or lower
On first startup, Colima generates Docker daemon.json file at `$HOME/.colima/docker/daemon.json`.
Modify the daemon.json file accordingly and restart Colima.
* v0.4.0 or newer
Start Colima with `--edit` flag.
```sh
colima start --edit
```
Add the Docker config to the `docker` section.
```diff
- docker: {}
+ docker:
+ insecure-registries:
+ - myregistry.com:5000
+ - host.docker.internal:5000
```
**Note:** In order for the Docker client to respect (at least some) configuration value changes, modification of the host ~/.docker/daemon.json file may also be required.
For example, if adding registry mirrors, modifications are needed as follows:
First, colima:
```sh
colima start --edit
```
```diff
- docker: {}
+ docker:
+ registry-mirrors:
+ - https://my.dockerhub.mirror.something
+ - https://my.quayio.mirror.something
```
As an alternative approach to the **colima start --edit**, make the changes via the **template** command (affecting the configuration for any new instances):
```sh
colima template
```
Then, the Docker ~/.docker/daemon.json file (as compared to the default):
```diff
- "experimental": false,
+ "experimental": false,
+ "registry-mirrors": [
+ "https://my.dockerhub.mirror.something",
+ "https://my.quayio.mirror.something"
+ ]
```
### Docker buildx plugin is missing
`buildx` can be installed as a Docker plugin
#### Installing Buildx
Using homebrew
```sh
brew install docker-buildx
# Follow the caveats mentioned in the install instructions:
# mkdir -p ~/.docker/cli-plugins
# ln -sfn $(which docker-buildx) ~/.docker/cli-plugins/docker-buildx
docker buildx version # verify installation
```
Alternatively
```sh
ARCH=amd64 # change to 'arm64' for m1
VERSION=v0.11.2
curl -LO https://github.com/docker/buildx/releases/download/${VERSION}/buildx-${VERSION}.darwin-${ARCH}
mkdir -p ~/.docker/cli-plugins
mv buildx-${VERSION}.darwin-${ARCH} ~/.docker/cli-plugins/docker-buildx
chmod +x ~/.docker/cli-plugins/docker-buildx
docker buildx version # verify installation
```
## Containerd
### How to customize Containerd config?
On first startup with the containerd runtime, Colima generates default config files at the standard user config locations:
| File | Location |
|------|----------|
| Containerd config | `~/.config/containerd/config.toml` |
| BuildKit config | `~/.config/buildkit/buildkitd.toml` |
These follow the standard rootless containerd/buildkit config paths and are shared across all Colima profiles.
Modify the files accordingly and restart Colima for changes to take effect.
```sh
# edit the containerd config
$EDITOR ~/.config/containerd/config.toml
# restart colima
colima stop && colima start --runtime containerd
```
#### Per-profile overrides
To use a different config for a specific profile, place the config file at `$HOME/.colima/<profile-name>/containerd/config.toml` (or `buildkitd.toml`). Per-profile configs take priority over the central config.
The resolution order is:
1. `~/.colima/<profile>/containerd/<file>` (per-profile override)
2. `~/.config/containerd/<file>` or `~/.config/buildkit/<file>` (central)
3. Embedded default
**Note:** `$XDG_CONFIG_HOME` is respected for the central config location if set.
## How does Colima compare to minikube, Kind, K3d?
### For Kubernetes
Yes, you can create a Kubernetes cluster with minikube (with Docker driver), Kind or K3d instead of enabling Kubernetes
in Colima.
Those are better options if you need multiple clusters, or do not need Docker and Kubernetes to share the same images and runtime.
Colima with Docker runtime is fully compatible with Minikube (with Docker driver), Kind and K3d.
### For Docker
Minikube with Docker runtime can expose the cluster's Docker with `minikube docker-env`. But there are some caveats.
- Kubernetes is not optional, even if you only need Docker.
- All of minikube's free drivers for macOS fall-short in one of performance, port forwarding or volumes. While port-forwarding and volumes are non-issue for Kubernetes, they can be a deal breaker for Docker-only use.
## Is another Distro supported?
### Version v0.5.6 and lower
Colima uses a lightweight Alpine image with bundled dependencies.
Therefore, user interaction with the Virtual Machine is expected to be minimal (if any).
However, Colima optionally provides Ubuntu container as a layer.
#### Enabling Ubuntu layer
* CLI
```
colima start --layer=true
```
* Config
```diff
- layer: false
+ layer: true
```
#### Accessing the underlying Virtual Machine
When the layer is enabled, the underlying Virtual Machine is abstracted and both the `ssh` and `ssh-config` commands routes to the layer.
The underlying Virtual Machine is still accessible by specifying `--layer=false` to the `ssh` and `ssh-config` commands, or by running `colima` in the SSH session.
### Version v0.6.0 and newer
Colima uses Ubuntu as the underlying image. Other distros are not supported.
## The Virtual Machine's IP is not reachable
Reachable IP address is not enabled by default due to root privilege and slower startup time.
### Enable reachable IP address
**NOTE:** this is only supported on macOS
* CLI
```
colima start --network-address
```
* Config
```diff
network:
- address: false
+ address: true
```
## Incus instances are not reachable from the host
<small>**Requires v0.10.0**</small>
Incus containers and virtual machines are not reachable from the host by default. This is because network address is not enabled by default.
To fix this, stop Colima and restart with network address enabled:
```sh
colima stop
colima start --network-address
```
Or enable it in the config file:
```sh
colima start --edit
```
```diff
network:
- address: false
+ address: true
```
## How can disk space be recovered?
Disk space can be freed in the VM by removing containers or running `docker system prune`.
However, it will not reflect on the host on Colima versions v0.4.x or lower.
### Automatic
For Colima v0.5.0 and above, unused disk space in the VM is released on startup. A restart would suffice.
### Manual
For Colima v0.5.0 and above, user can manually recover the disk space by running `sudo fstrim -a` in the VM.
```sh
# '-v' may be added for verbose output
colima ssh -- sudo fstrim -a
```
## How can disk size be increased?
Disk size is automatically increased on start up based on configuration in `colima.yaml`
```diff
- disk: 150
+ disk: 250
```
__Note:__ This feature is available from Version 0.5.3.
## Are Lima overrides supported?
Yes, however this should only be done by advanced users.
Lima supports `override.yaml` and `default.yaml` files that can modify the VM configuration.
The override file is located at `$HOME/.colima/_lima/_config/override.yaml` (or `$LIMA_HOME/_config/override.yaml` if `LIMA_HOME` is set).
Settings in `override.yaml` are applied **before** the instance config, while settings in `default.yaml` are applied **after** (as fallback defaults).
**Note:** Overriding the image is not supported as Colima's image includes bundled dependencies that would be missing in a user-specified image.
### Example: Adding provision scripts
Provision scripts can be added via Lima overrides to run commands during VM boot.
```yaml
# $HOME/.colima/_lima/_config/override.yaml
provision:
- mode: system
script: |
#!/bin/bash
set -eux -o pipefail
# install additional packages
apt-get update && apt-get install -y curl
```
Alternatively, provision scripts can be specified directly in `colima.yaml`:
```sh
colima start --edit
```
```diff
- provision: []
+ provision:
+ - mode: system
+ script: |
+ #!/bin/bash
+ set -eux -o pipefail
+ apt-get update && apt-get install -y curl
```
## How can the VM and its tools be updated?
### Updating Colima
```sh
brew upgrade colima
```
After upgrading, delete and recreate the instance to use the latest VM image:
```sh
colima delete
colima start
```
To test the upgrade without affecting the existing setup, use a separate profile:
```sh
colima start debug
```
### Updating the container runtime
From v0.7.6, the container runtime (Docker, containerd) can be updated independently:
```sh
colima update
```
This updates Docker (or containerd) to the latest version without needing to update Colima itself.
### Accessing the Virtual Machine
SSH into the VM to inspect or modify it directly:
```sh
colima ssh
```
Run a single command without an interactive session:
```sh
colima ssh -- uname -a
```
## Troubleshooting
These are some common issues reported by users and how to troubleshoot them.
### Colima not starting
There are multiple reasons that could cause Colima to fail to start.
#### Broken status
This is the case when the output of `colima list` shows a broken status. This can happen due to macOS restart.
```
colima list
PROFILE STATUS ARCH CPUS MEMORY DISK RUNTIME ADDRESS
default Broken aarch64 2 2GiB 60GiB
```
This can be fixed by forcefully stopping Colima. The state will be changed to `Stopped` and it should start up normally afterwards.
```
colima stop --force
```
#### FATA[0000] error starting vm: error at 'starting': exit status 1
This indicates that a fatal error is preventing Colima from starting, you can enable the debug log with `--verbose` flag to get more info.
If the log output includes `exiting, status={Running:false Degraded:false Exiting:true Errors:[] SSHLocalPort:0}` then it is most certainly due to one of the following.
1. Running on a device without virtualization support.
2. Running an x86_64 version of homebrew (and Colima) on an M1 device.
### Issues after an upgrade
The recommended way to troubleshoot after an upgrade is to test with a separate profile.
```sh
# start with a profile named 'debug'
colima start debug
```
If the separate profile starts successfully without issues, then the issue would be resolved by resetting the default profile.
```
colima delete
colima start
```
### Colima cannot access the internet.
Failure for Colima to access the internet is usually down to DNS.
Try custom DNS server(s)
```sh
colima start --dns 8.8.8.8 --dns 1.1.1.1
```
Ping an internet address from within the VM to ascertain
```
colima ssh -- ping -c4 google.com
PING google.com (216.58.223.238): 56 data bytes
64 bytes from 216.58.223.238: seq=0 ttl=42 time=0.082 ms
64 bytes from 216.58.223.238: seq=1 ttl=42 time=0.557 ms
64 bytes from 216.58.223.238: seq=2 ttl=42 time=0.465 ms
64 bytes from 216.58.223.238: seq=3 ttl=42 time=0.457 ms
--- google.com ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.082/0.390/0.557 ms
```
### Docker Compose and Buildx showing runc error
#### Version v0.5.6 or lower
Recent versions of Buildkit may show the following error.
```console
runc run failed: unable to start container process: error during container init: error mounting "cgroup" to rootfs at "/sys/fs/cgroup": mount cgroup:/sys/fs/cgroup/openrc (via /proc/self/fd/6), flags: 0xf, data: openrc: invalid argument
```
From v0.5.6, start Colima with `--cgroups-v2` flag as a workaround.
**This is fixed in v0.6.0.**
### Issue with Docker bind mount showing empty
When using docker to bind mount a volume (e.g. using `-v` or `--mount`) from the host where the volume is not contained within `/Users/$USER`, the container will start without raising any errors but the mapped mountpoint on the container will be empty.
This is rectified by mounting the volume on the VM, and only then can docker map the volume or any subdirectory. Edit `$HOME/.colima/default/colima.yaml` and add to the `mounts` section (examples are provided within the yaml file), and then run `colima restart`. Start the container again with the desired bind mount and it should show up correctly.
## How can Docker version be updated?
Each Colima release includes the latest Docker version at the time of release.
From v0.7.6, there is a new `colima update` command to update the container runtime without needing to update Colima or to wait for the next Colima release.
## How can I delete container data
From v0.9.0, Colima utilises a different disk for the container runtime data. This guards against accidental data loss after deletion and the container data should be reinstated on `colima start`.
To clear all data, `colima delete --data` should be run instead. The `--data` flag ensures that the container data is also deleted.
================================================
FILE: docs/INSTALL.md
================================================
# Installation Options
## Homebrew
Stable Version
```
brew install colima
```
Development Version
```
brew install --HEAD colima
```
## MacPorts
Stable version
```
sudo port install colima
```
## Nix
Only stable Version
```
nix-env -i colima
```
Or using solely in a `nix-shell`
```
nix-shell -p colima
```
## Arch
Install dependencies
```
sudo pacman -S qemu-full go docker
```
Install Lima and Colima from Aur
```
yay -S lima-bin colima-bin
```
## Binary
Binaries are available with every release on the [releases page](https://github.com/abiosoft/colima/releases).
```sh
# download binary
curl -LO https://github.com/abiosoft/colima/releases/latest/download/colima-$(uname)-$(uname -m)
# install in $PATH
sudo install colima-$(uname)-$(uname -m) /usr/local/bin/colima
```
## Building from Source
Requires [Go](https://golang.org).
```sh
# clone repo and cd into it
git clone https://github.com/abiosoft/colima
cd colima
make
sudo make install
```
================================================
FILE: embedded/defaults/abort.yaml
================================================
# ============================================================================================ #
# To abort, delete the contents of this file including the comments and save as an empty file
# ============================================================================================ #
================================================
FILE: embedded/defaults/colima.yaml
================================================
# Number of CPUs to be allocated to the virtual machine.
# Default: 2
cpu: 2
# Size of the disk in GiB to be allocated to the virtual machine for container data.
# NOTE: value can only be increased after virtual machine has been created.
#
# Default: 100
disk: 100
# Size of the memory in GiB to be allocated to the virtual machine.
# Default: 2
memory: 2
# Architecture of the virtual machine (x86_64, aarch64, host).
#
# NOTE: value cannot be changed after virtual machine is created.
# Default: host
arch: host
# Container runtime to be used (docker, containerd).
#
# NOTE: value cannot be changed after virtual machine is created.
# Default: docker
runtime: docker
# AI model runner (docker, ramalama).
# Both require krunkit VM type for GPU access.
# docker: Uses Docker Model Runner.
# ramalama: Uses Ramalama.
#
# Default: docker
modelRunner: docker
# Set custom hostname for the virtual machine.
# Default: colima
# colima-profile_name for other profiles
hostname: null
# Kubernetes configuration for the virtual machine.
kubernetes:
# Enable kubernetes.
# Default: false
enabled: false
# Kubernetes version to use.
# This needs to exactly match a k3s version https://github.com/k3s-io/k3s/releases
# Default: latest stable release
version: v1.35.0+k3s1
# Additional args to pass to k3s https://docs.k3s.io/cli/server
# Default: traefik is disabled
k3sArgs: [--disable=traefik]
# Kubernetes port to listen on
# A common port is 6443, though left unbound to ensure no port conflicts
# Default: pick random unbound port
port: 0
# Auto-activate on the Host for client access.
# Setting to true does the following on startup
# - sets as active Docker context (for Docker runtime).
# - sets as active Kubernetes context (if Kubernetes is enabled).
# - sets as active Incus remote (for Incus runtime).
# Default: true
autoActivate: true
# Network configurations for the virtual machine.
network:
# Assign reachable IP address to the virtual machine.
# NOTE: this is currently macOS only and ignored on Linux.
# Default: false
address: false
# Network mode for the virtual machine (shared, bridged).
# NOTE: this is currently macOS only and ignored on Linux.
# Default: shared
mode: shared
# Network interface to use for bridged mode.
# This is only used when mode is set to bridged.
# NOTE: this is currently macOS only and ignored on Linux.
# Default: en0
interface: en0
# Use the assigned IP address as the preferred route for the VM.
# Note: this only has an effect when `address` is set
gitextract_xof0cru8/
├── .editorconfig
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yaml
│ │ └── feature_request.yaml
│ ├── dependabot.yaml
│ └── workflows/
│ ├── go.yml
│ ├── golang-ci.yml
│ └── integration.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── app/
│ └── app.go
├── cli/
│ ├── chain.go
│ └── command.go
├── cmd/
│ ├── clone.go
│ ├── colima/
│ │ └── main.go
│ ├── completion.go
│ ├── daemon/
│ │ ├── cmd.go
│ │ ├── daemon.go
│ │ └── daemon_test.go
│ ├── delete.go
│ ├── kubernetes.go
│ ├── list.go
│ ├── model.go
│ ├── nerdctl.go
│ ├── prune.go
│ ├── restart.go
│ ├── root/
│ │ └── root.go
│ ├── ssh-config.go
│ ├── ssh.go
│ ├── start.go
│ ├── start_test.go
│ ├── status.go
│ ├── stop.go
│ ├── template.go
│ ├── update.go
│ ├── util.go
│ └── version.go
├── colima.nix
├── config/
│ ├── config.go
│ ├── configmanager/
│ │ └── configmanager.go
│ ├── files.go
│ └── profile.go
├── core/
│ └── core.go
├── daemon/
│ ├── daemon.go
│ └── process/
│ ├── inotify/
│ │ ├── events.go
│ │ ├── inotify.go
│ │ ├── volumes.go
│ │ ├── volumes_test.go
│ │ └── watch.go
│ ├── process.go
│ └── vmnet/
│ ├── deps.go
│ └── vmnet.go
├── default.nix
├── docs/
│ ├── CONTRIBUTE.md
│ ├── FAQ.md
│ └── INSTALL.md
├── embedded/
│ ├── defaults/
│ │ ├── abort.yaml
│ │ ├── colima.yaml
│ │ └── template.yaml
│ ├── embed.go
│ ├── images/
│ │ ├── images.txt
│ │ └── images_sha.sh
│ ├── k3s/
│ │ └── flannel.json
│ ├── network/
│ │ └── sudo.txt
│ └── sudoers.go
├── environment/
│ ├── container/
│ │ ├── containerd/
│ │ │ ├── buildkitd.toml
│ │ │ ├── config.toml
│ │ │ └── containerd.go
│ │ ├── docker/
│ │ │ ├── config.toml
│ │ │ ├── containerd.go
│ │ │ ├── context.go
│ │ │ ├── daemon.go
│ │ │ ├── docker.go
│ │ │ └── proxy.go
│ │ ├── incus/
│ │ │ ├── config.yaml
│ │ │ ├── incus.go
│ │ │ └── route.go
│ │ └── kubernetes/
│ │ ├── cni.go
│ │ ├── k3s.go
│ │ ├── kubeconfig.go
│ │ └── kubernetes.go
│ ├── container.go
│ ├── environment.go
│ ├── guest/
│ │ └── systemctl/
│ │ ├── systemctl.go
│ │ └── systemctl_test.go
│ ├── host/
│ │ └── host.go
│ ├── host.go
│ ├── vm/
│ │ └── lima/
│ │ ├── certs.go
│ │ ├── config.go
│ │ ├── daemon.go
│ │ ├── disk.go
│ │ ├── disk.sh
│ │ ├── dns.go
│ │ ├── file.go
│ │ ├── lima.go
│ │ ├── limaconfig/
│ │ │ └── config.go
│ │ ├── limautil/
│ │ │ ├── disk.go
│ │ │ ├── files.go
│ │ │ ├── image.go
│ │ │ ├── instance.go
│ │ │ ├── limautil.go
│ │ │ ├── network.go
│ │ │ └── ssh.go
│ │ ├── network.go
│ │ ├── shell.go
│ │ ├── yaml.go
│ │ └── yaml_test.go
│ └── vm.go
├── flake.nix
├── go.mod
├── go.sum
├── integration/
│ └── Dockerfile
├── model/
│ ├── docker.go
│ ├── ramalama.go
│ ├── runner.go
│ └── runner_test.go
├── scripts/
│ ├── build_vmnet.sh
│ └── integration.sh
├── shell.nix
├── store/
│ └── store.go
└── util/
├── debutil/
│ └── debutil.go
├── downloader/
│ ├── curl.go
│ ├── download.go
│ ├── errors.go
│ ├── http.go
│ ├── native.go
│ └── sha.go
├── fsutil/
│ └── fs.go
├── macos.go
├── macos_test.go
├── osutil/
│ └── os.go
├── qemu.go
├── shautil/
│ └── sha.go
├── template.go
├── terminal/
│ ├── output.go
│ └── terminal.go
├── util.go
└── yamlutil/
├── yaml.go
└── yaml_test.go
SYMBOL INDEX (790 symbols across 105 files)
FILE: app/app.go
type App (line 30) | type App interface
function New (line 46) | func New() (App, error) {
type colimaApp (line 57) | type colimaApp struct
method startWithRuntime (line 61) | func (c colimaApp) startWithRuntime(conf config.Config) ([]environment...
method Start (line 102) | func (c colimaApp) Start(conf config.Config) error {
method runProvisionScripts (line 163) | func (c colimaApp) runProvisionScripts(conf config.Config, mode string) {
method Stop (line 178) | func (c colimaApp) Stop(force bool) error {
method Delete (line 222) | func (c colimaApp) Delete(data, force bool) error {
method SSH (line 302) | func (c colimaApp) SSH(args ...string) error {
method getStatus (line 366) | func (c colimaApp) getStatus() (status statusInfo, err error) {
method Status (line 412) | func (c colimaApp) Status(extended bool, jsonOutput bool) error {
method Version (line 470) | func (c colimaApp) Version() error {
method currentRuntime (line 503) | func (c colimaApp) currentRuntime(ctx context.Context) (string, error) {
method setRuntime (line 516) | func (c colimaApp) setRuntime(runtime string) error {
method setKubernetes (line 531) | func (c colimaApp) setKubernetes(conf config.Kubernetes) error {
method currentContainerEnvironments (line 540) | func (c colimaApp) currentContainerEnvironments(ctx context.Context) (...
method containerEnvironment (line 568) | func (c colimaApp) containerEnvironment(runtime string) (environment.C...
method Runtime (line 580) | func (c colimaApp) Runtime() (string, error) {
method Kubernetes (line 584) | func (c colimaApp) Kubernetes() (environment.Container, error) {
method Active (line 588) | func (c colimaApp) Active() bool {
method Update (line 592) | func (c *colimaApp) Update() error {
type statusInfo (line 349) | type statusInfo struct
function generateSSHConfig (line 627) | func generateSSHConfig(modifySSHConfig bool) error {
FILE: cli/chain.go
type errNonFatal (line 16) | type errNonFatal struct
method Error (line 21) | func (e errNonFatal) Error() string { return e.err.Error() }
function ErrNonFatal (line 25) | func ErrNonFatal(err error) error {
function New (line 30) | func New(name string) CommandChain {
type cFunc (line 36) | type cFunc struct
type CommandChain (line 43) | type CommandChain interface
type namedCommandChain (line 52) | type namedCommandChain struct
method Logger (line 57) | func (n *namedCommandChain) Logger(ctx context.Context) *log.Entry {
method Init (line 69) | func (n *namedCommandChain) Init(ctx context.Context) *ActiveCommandCh...
type ActiveCommandChain (line 76) | type ActiveCommandChain struct
method Logger (line 85) | func (a *ActiveCommandChain) Logger() *log.Entry { return a.log }
method Add (line 88) | func (a *ActiveCommandChain) Add(f func() error) {
method Stage (line 93) | func (a *ActiveCommandChain) Stage(s string) {
method Stagef (line 102) | func (a *ActiveCommandChain) Stagef(format string, s ...any) {
method Exec (line 110) | func (a *ActiveCommandChain) Exec() error {
method Retry (line 151) | func (a *ActiveCommandChain) Retry(stage string, interval time.Duratio...
FILE: cli/command.go
function Command (line 21) | func Command(command string, args ...string) *exec.Cmd { return runner.C...
function CommandInteractive (line 24) | func CommandInteractive(command string, args ...string) *exec.Cmd {
type commandRunner (line 28) | type commandRunner interface
type defaultCommandRunner (line 35) | type defaultCommandRunner struct
method Command (line 37) | func (d defaultCommandRunner) Command(command string, args ...string) ...
method CommandInteractive (line 47) | func (d defaultCommandRunner) CommandInteractive(command string, args ...
function quotedArgs (line 58) | func quotedArgs(args []string) string {
function Prompt (line 67) | func Prompt(question string) bool {
FILE: cmd/clone.go
function init (line 77) | func init() {
FILE: cmd/colima/main.go
function main (line 11) | func main() {
FILE: cmd/completion.go
function completionCmd (line 11) | func completionCmd() *cobra.Command {
function init (line 72) | func init() {
FILE: cmd/daemon/cmd.go
function init (line 96) | func init() {
FILE: cmd/daemon/daemon.go
function daemonize (line 24) | func daemonize() (ctx *godaemon.Context, child bool, err error) {
function start (line 54) | func start(ctx context.Context, processes []process.Process) error {
function stop (line 83) | func stop(ctx context.Context) error {
function status (line 112) | func status() error {
constant pidFileName (line 141) | pidFileName = "daemon.pid"
constant logFileName (line 142) | logFileName = "daemon.log"
function Info (line 145) | func Info() struct {
function RunProcesses (line 162) | func RunProcesses(ctx context.Context, processes ...process.Process) err...
FILE: cmd/daemon/daemon_test.go
function setDir (line 15) | func setDir(t *testing.T) {
function getProcesses (line 22) | func getProcesses() []process.Process {
function TestStart (line 36) | func TestStart(t *testing.T) {
function TestRunProcesses (line 90) | func TestRunProcesses(t *testing.T) {
type pinger (line 117) | type pinger struct
method Alive (line 121) | func (p pinger) Alive(ctx context.Context) error {
method Name (line 126) | func (pinger) Name() string { return "pinger" }
method Start (line 129) | func (p *pinger) Start(ctx context.Context) error {
method Dependencies (line 134) | func (p *pinger) Dependencies() ([]process.Dependency, bool) { return ...
method run (line 136) | func (p *pinger) run(ctx context.Context, command string, args ...stri...
FILE: cmd/delete.go
function init (line 27) | func init() {
FILE: cmd/kubernetes.go
function init (line 131) | func init() {
FILE: cmd/list.go
function init (line 79) | func init() {
FILE: cmd/model.go
function init (line 221) | func init() {
function getModelRunner (line 234) | func getModelRunner() (model.Runner, error) {
FILE: cmd/nerdctl.go
constant nerdctlDefaultInstallPath (line 169) | nerdctlDefaultInstallPath = "/usr/local/bin/nerdctl"
constant nerdctlScript (line 171) | nerdctlScript = `#!/usr/bin/env sh
function init (line 176) | func init() {
FILE: cmd/prune.go
function init (line 56) | func init() {
FILE: cmd/restart.go
function init (line 49) | func init() {
FILE: cmd/root/root.go
function Cmd (line 65) | func Cmd() *cobra.Command {
function Execute (line 78) | func Execute() {
function init (line 84) | func init() {
function initLog (line 90) | func initLog() {
FILE: cmd/ssh-config.go
function init (line 27) | func init() {
FILE: cmd/ssh.go
function init (line 24) | func init() {
FILE: cmd/start.go
constant defaultCPU (line 124) | defaultCPU = 2
constant defaultMemory (line 125) | defaultMemory = 2
constant defaultDisk (line 126) | defaultDisk = 100
constant defaultRootDisk (line 127) | defaultRootDisk = 20
constant defaultKubernetesVersion (line 128) | defaultKubernetesVersion = kubernetes.DefaultVersion
constant defaultMountTypeQEMU (line 130) | defaultMountTypeQEMU = "sshfs"
constant defaultMountTypeVZ (line 131) | defaultMountTypeVZ = "virtiofs"
function init (line 160) | func init() {
function dnsHostsFromFlag (line 274) | func dnsHostsFromFlag(hosts []string) map[string]string {
function mountsFromFlag (line 292) | func mountsFromFlag(mounts []string) []config.Mount {
function setFlagDefaults (line 320) | func setFlagDefaults(cmd *cobra.Command) {
function setConfigDefaults (line 370) | func setConfigDefaults(conf *config.Config) {
function setFixedConfigs (line 396) | func setFixedConfigs(conf *config.Config) {
function prepareConfig (line 436) | func prepareConfig(cmd *cobra.Command) {
function editConfigFile (line 622) | func editConfigFile() (config.Config, error) {
function start (line 658) | func start(app app.App, conf config.Config) error {
function awaitForInterruption (line 668) | func awaitForInterruption(app app.App) error {
FILE: cmd/start_test.go
function Test_mountsFromFlag (line 11) | func Test_mountsFromFlag(t *testing.T) {
FILE: cmd/status.go
function init (line 24) | func init() {
FILE: cmd/stop.go
function init (line 26) | func init() {
FILE: cmd/template.go
function templateFile (line 70) | func templateFile() string { return filepath.Join(config.TemplatesDir(),...
function templateFileOrDefault (line 72) | func templateFileOrDefault() (string, error) {
function init (line 89) | func init() {
FILE: cmd/update.go
function init (line 20) | func init() {
FILE: cmd/util.go
function newApp (line 17) | func newApp() app.App {
function waitForUserEdit (line 28) | func waitForUserEdit(editor string, content []byte) (string, error) {
function launchEditor (line 58) | func launchEditor(editor string, file string) error {
FILE: cmd/version.go
function init (line 41) | func init() {
FILE: config/config.go
constant AppName (line 12) | AppName = "colima"
constant envProfile (line 13) | envProfile = "COLIMA_PROFILE"
type VersionInfo (line 17) | type VersionInfo struct
function AppVersion (line 22) | func AppVersion() VersionInfo { return VersionInfo{Version: appVersion, ...
function EnvProfile (line 23) | func EnvProfile() string { return osutil.EnvVar(envProfile).Val() }
type Config (line 31) | type Config struct
method MountsOrDefault (line 121) | func (c Config) MountsOrDefault() []Mount {
method AutoActivate (line 134) | func (c Config) AutoActivate() bool {
method Empty (line 142) | func (c Config) Empty() bool { return c.Runtime == "" }
method DriverLabel (line 144) | func (c Config) DriverLabel() string {
type Kubernetes (line 78) | type Kubernetes struct
type Network (line 86) | type Network struct
type Mount (line 98) | type Mount struct
constant ProvisionModeAfterBoot (line 106) | ProvisionModeAfterBoot = "after-boot"
constant ProvisionModeReady (line 107) | ProvisionModeReady = "ready"
type Provision (line 110) | type Provision struct
method IsColimaMode (line 117) | func (p Provision) IsColimaMode() bool {
type Disk (line 154) | type Disk
method GiB (line 157) | func (d Disk) GiB() string { return fmt.Sprintf("%dGiB", d) }
method Int (line 160) | func (d Disk) Int() int64 { return 1024 * 1024 * 1024 * int64(d) }
function CtxKey (line 163) | func CtxKey() any {
FILE: config/configmanager/configmanager.go
function Save (line 16) | func Save(c config.Config) error {
function SaveFromFile (line 21) | func SaveFromFile(file string) error {
function SaveToFile (line 30) | func SaveToFile(c config.Config, file string) error {
function LoadFrom (line 35) | func LoadFrom(file string) (config.Config, error) {
function ValidateConfig (line 51) | func ValidateConfig(c config.Config) error {
function Load (line 107) | func Load() (c config.Config, err error) {
function LoadInstance (line 117) | func LoadInstance() (config.Config, error) {
function Teardown (line 122) | func Teardown() error {
function validateGatewayAddress (line 132) | func validateGatewayAddress(gateway net.IP) error {
FILE: config/files.go
type requiredDir (line 15) | type requiredDir struct
method Dir (line 29) | func (r *requiredDir) Dir() string {
function CacheDir (line 156) | func CacheDir() string { return cacheDir.Dir() }
function TemplatesDir (line 159) | func TemplatesDir() string { return templatesDir.Dir() }
function LimaDir (line 162) | func LimaDir() string { return limaDir.Dir() }
constant configFileName (line 164) | configFileName = "colima.yaml"
function SSHConfigFile (line 167) | func SSHConfigFile() string { return filepath.Join(configBaseDir.Dir(), ...
FILE: config/profile.go
function SetProfile (line 13) | func SetProfile(profileName string) {
function ProfileFromName (line 19) | func ProfileFromName(name string) *Profile {
function CurrentProfile (line 42) | func CurrentProfile() *Profile { return profile }
type Profile (line 45) | type Profile struct
method ConfigDir (line 56) | func (p *Profile) ConfigDir() string {
method LimaInstanceDir (line 68) | func (p *Profile) LimaInstanceDir() string {
method File (line 73) | func (p *Profile) File() string {
method LimaFile (line 78) | func (p *Profile) LimaFile() string {
method StateFile (line 83) | func (p *Profile) StateFile() string {
method StoreFile (line 87) | func (p *Profile) StoreFile() string {
type ProfileInfo (line 94) | type ProfileInfo interface
FILE: core/core.go
constant limaVersion (line 16) | limaVersion = "v0.18.0"
function SetupBinfmt (line 24) | func SetupBinfmt(host hostActions, guest guestActions, arch environment....
function LimaVersionSupported (line 46) | func LimaVersionSupported() error {
FILE: daemon/daemon.go
type Manager (line 19) | type Manager interface
type Status (line 26) | type Status struct
type processStatus (line 32) | type processStatus struct
function NewManager (line 39) | func NewManager(host environment.HostActions) Manager {
function CtxKey (line 45) | func CtxKey(s string) any { return struct{ key string }{key: s} }
type processManager (line 49) | type processManager struct
method Dependency (line 53) | func (l processManager) Dependency(ctx context.Context, conf config.Co...
method init (line 65) | func (l processManager) init() error {
method Running (line 73) | func (l processManager) Running(ctx context.Context, conf config.Confi...
method Start (line 93) | func (l processManager) Start(ctx context.Context, conf config.Config)...
method Stop (line 126) | func (l processManager) Stop(ctx context.Context, conf config.Config) ...
function processesFromConfig (line 133) | func processesFromConfig(conf config.Config) []process.Process {
FILE: daemon/process/inotify/events.go
type modEvent (line 10) | type modEvent struct
method Mode (line 15) | func (m modEvent) Mode() string { return fmt.Sprintf("%o", m.FileMode) }
method handleEvents (line 17) | func (f *inotifyProcess) handleEvents(ctx context.Context, watcher dirWa...
FILE: daemon/process/inotify/inotify.go
constant Name (line 14) | Name = "inotify"
constant volumesInterval (line 15) | volumesInterval = 5 * time.Second
type Args (line 17) | type Args struct
function CtxKeyArgs (line 23) | func CtxKeyArgs() any { return struct{ name string }{name: "inotify_args...
function New (line 26) | func New() process.Process {
type inotifyProcess (line 34) | type inotifyProcess struct
method Alive (line 43) | func (f *inotifyProcess) Alive(ctx context.Context) error {
method Dependencies (line 54) | func (*inotifyProcess) Dependencies() (deps []process.Dependency, root...
method Name (line 59) | func (*inotifyProcess) Name() string {
method Start (line 64) | func (f *inotifyProcess) Start(ctx context.Context) error {
method waitForLima (line 85) | func (f *inotifyProcess) waitForLima(ctx context.Context) {
FILE: daemon/process/inotify/volumes.go
method monitorContainerVolumes (line 16) | func (f *inotifyProcess) monitorContainerVolumes(ctx context.Context, c ...
method fetchVolumes (line 83) | func (f *inotifyProcess) fetchVolumes(cmdArgs ...string) ([]string, erro...
function omitChildrenDirectories (line 152) | func omitChildrenDirectories(dirs []string) []string {
FILE: daemon/process/inotify/volumes_test.go
function Test_omitChildrenDirectories (line 9) | func Test_omitChildrenDirectories(t *testing.T) {
FILE: daemon/process/inotify/watch.go
type dirWatcher (line 13) | type dirWatcher interface
type defaultWatcher (line 24) | type defaultWatcher struct
method Watch (line 29) | func (d *defaultWatcher) Watch(ctx context.Context, dirs []string, mod...
FILE: daemon/process/process.go
function CtxKeyDaemon (line 13) | func CtxKeyDaemon() any { return struct{ key string }{key: "colima_daemo...
type Process (line 16) | type Process interface
function Dir (line 31) | func Dir() string { return filepath.Join(config.CurrentProfile().ConfigD...
type Dependency (line 34) | type Dependency interface
function Dependencies (line 41) | func Dependencies(processes ...Process) (deps Dependency, root bool) {
type processDeps (line 57) | type processDeps
method Installed (line 59) | func (p processDeps) Installed() bool {
method Install (line 72) | func (p processDeps) Install(host environment.HostActions) error {
FILE: daemon/process/vmnet/deps.go
type sudoerFile (line 16) | type sudoerFile struct
method Installed (line 19) | func (s sudoerFile) Installed() bool { return embedded.SudoersInstalle...
method Install (line 22) | func (s sudoerFile) Install(host environment.HostActions) error {
constant BinaryPath (line 28) | BinaryPath = "/opt/colima/bin/socket_vmnet"
constant ClientBinaryPath (line 29) | ClientBinaryPath = "/opt/colima/bin/socket_vmnet_client"
type vmnetFile (line 31) | type vmnetFile struct
method Installed (line 34) | func (v vmnetFile) Installed() bool {
method bins (line 43) | func (v vmnetFile) bins() []string {
method Install (line 46) | func (v vmnetFile) Install(host environment.HostActions) error {
type vmnetRunDir (line 86) | type vmnetRunDir struct
method Install (line 89) | func (v vmnetRunDir) Install(host environment.HostActions) error {
method Installed (line 94) | func (v vmnetRunDir) Installed() bool {
constant optDir (line 99) | optDir = "/opt/colima"
function runDir (line 102) | func runDir() string { return filepath.Join(optDir, "run") }
FILE: daemon/process/vmnet/vmnet.go
constant Name (line 18) | Name = "vmnet"
constant SubProcessEnvVar (line 21) | SubProcessEnvVar = "COLIMA_VMNET"
constant NetGateway (line 23) | NetGateway = "192.168.106.1"
constant NetDHCPEnd (line 24) | NetDHCPEnd = "192.168.106.254"
function New (line 29) | func New(mode, netInterface string) process.Process {
type vmnetProcess (line 36) | type vmnetProcess struct
method Alive (line 41) | func (*vmnetProcess) Alive(ctx context.Context) error {
method Name (line 68) | func (*vmnetProcess) Name() string { return Name }
method Start (line 71) | func (v *vmnetProcess) Start(ctx context.Context) error {
method Dependencies (line 127) | func (vmnetProcess) Dependencies() (deps []process.Dependency, root bo...
function stop (line 135) | func stop(pidFile string) error {
function forceDeleteFileIfExists (line 147) | func forceDeleteFileIfExists(name string) error {
function Info (line 154) | func Info() struct {
FILE: embedded/embed.go
function FS (line 11) | func FS() embed.FS { return fs }
function read (line 13) | func read(file string) ([]byte, error) { return fs.ReadFile(file) }
function Read (line 16) | func Read(file string) ([]byte, error) { return read(file) }
function ReadString (line 19) | func ReadString(file string) (string, error) {
FILE: embedded/sudoers.go
constant sudoersPath (line 14) | sudoersPath = "/etc/sudoers.d/colima"
constant sudoersEmbeddedPath (line 15) | sudoersEmbeddedPath = "network/sudo.txt"
type SudoersInstaller (line 19) | type SudoersInstaller interface
function SudoersInstalled (line 25) | func SudoersInstalled() bool {
function InstallSudoers (line 39) | func InstallSudoers(host SudoersInstaller) error {
FILE: environment/container.go
function IsNoneRuntime (line 10) | func IsNoneRuntime(runtime string) bool { return runtime == "none" }
type Container (line 13) | type Container interface
function NewContainer (line 37) | func NewContainer(runtime string, host HostActions, guest GuestActions) ...
type NewContainerFunc (line 46) | type NewContainerFunc
type containerRuntimeFunc (line 50) | type containerRuntimeFunc struct
function RegisterContainer (line 57) | func RegisterContainer(name string, f NewContainerFunc, hidden bool) {
function ContainerRuntimes (line 65) | func ContainerRuntimes() (names []string) {
type DataDisk (line 76) | type DataDisk struct
type DiskDir (line 83) | type DiskDir struct
FILE: environment/container/containerd/containerd.go
constant Name (line 18) | Name = "containerd"
function HostSocketFiles (line 23) | func HostSocketFiles() (files struct {
constant containerdConfFile (line 43) | containerdConfFile = "/etc/containerd/config.toml"
constant buildKitConfFile (line 44) | buildKitConfFile = "/etc/buildkit/buildkitd.toml"
function newRuntime (line 46) | func newRuntime(host environment.HostActions, guest environment.GuestAct...
function init (line 55) | func init() {
type containerdRuntime (line 61) | type containerdRuntime struct
method Name (line 68) | func (c containerdRuntime) Name() string {
method Provision (line 72) | func (c containerdRuntime) Provision(ctx context.Context) error {
method provisionConfig (line 114) | func (c containerdRuntime) provisionConfig(profilePath, centralPath, g...
method Start (line 137) | func (c containerdRuntime) Start(ctx context.Context) error {
method Running (line 156) | func (c containerdRuntime) Running(ctx context.Context) bool {
method Stop (line 160) | func (c containerdRuntime) Stop(ctx context.Context, force bool) error {
method Teardown (line 168) | func (c containerdRuntime) Teardown(context.Context) error {
method Dependencies (line 173) | func (c containerdRuntime) Dependencies() []string {
method Version (line 178) | func (c containerdRuntime) Version(ctx context.Context) string {
method Update (line 183) | func (c *containerdRuntime) Update(ctx context.Context) (bool, error) {
function userConfigDir (line 95) | func userConfigDir() string {
function DataDisk (line 188) | func DataDisk() environment.DataDisk {
FILE: environment/container/docker/containerd.go
constant containerdConfFile (line 9) | containerdConfFile = "/etc/containerd/config.toml"
constant containerdConfFileBackup (line 10) | containerdConfFileBackup = "/etc/containerd/config.colima.bak.toml"
method provisionContainerd (line 15) | func (d dockerRuntime) provisionContainerd(ctx context.Context) error {
FILE: environment/container/docker/context.go
function HostSocketFile (line 12) | func HostSocketFile() string { return filepath.Join(configDir(), "docker...
function LegacyDefaultHostSocketFile (line 13) | func LegacyDefaultHostSocketFile() string {
method contextCreated (line 17) | func (d dockerRuntime) contextCreated() bool {
method setupContext (line 21) | func (d dockerRuntime) setupContext() error {
method useContext (line 34) | func (d dockerRuntime) useContext() error {
method teardownContext (line 38) | func (d dockerRuntime) teardownContext() error {
FILE: environment/container/docker/daemon.go
constant daemonFile (line 10) | daemonFile = "/etc/docker/daemon.json"
constant hostGatewayIPKey (line 11) | hostGatewayIPKey = "host-gateway-ip"
function getHostGatewayIp (line 13) | func getHostGatewayIp(d dockerRuntime, conf map[string]any) (string, err...
function resolveHostProxy (line 32) | func resolveHostProxy(hostProxy, hostGateway string) string {
method createDaemonFile (line 55) | func (d dockerRuntime) createDaemonFile(conf map[string]any, env map[str...
method addHostGateway (line 105) | func (d dockerRuntime) addHostGateway(conf map[string]any) error {
method reloadAndRestartSystemdService (line 121) | func (d dockerRuntime) reloadAndRestartSystemdService() error {
constant systemdUnitFilename (line 131) | systemdUnitFilename = "/etc/systemd/system/docker.service.d/docker.conf"
constant systemdUnitFileContent (line 132) | systemdUnitFileContent string = `
FILE: environment/container/docker/docker.go
constant Name (line 18) | Name = "docker"
function init (line 22) | func init() {
type dockerRuntime (line 26) | type dockerRuntime struct
method Name (line 43) | func (d dockerRuntime) Name() string {
method Provision (line 47) | func (d dockerRuntime) Provision(ctx context.Context) error {
method Start (line 82) | func (d dockerRuntime) Start(ctx context.Context) error {
method Running (line 107) | func (d dockerRuntime) Running(ctx context.Context) bool {
method Stop (line 111) | func (d dockerRuntime) Stop(ctx context.Context, force bool) error {
method Teardown (line 129) | func (d dockerRuntime) Teardown(ctx context.Context) error {
method Dependencies (line 138) | func (d dockerRuntime) Dependencies() []string {
method Version (line 142) | func (d dockerRuntime) Version(ctx context.Context) string {
method Update (line 147) | func (d *dockerRuntime) Update(ctx context.Context) (bool, error) {
function newRuntime (line 34) | func newRuntime(host environment.HostActions, guest environment.GuestAct...
function DataDisk (line 158) | func DataDisk() environment.DataDisk {
function DockerDir (line 178) | func DockerDir() string {
FILE: environment/container/docker/proxy.go
type proxyVars (line 8) | type proxyVars struct
method empty (line 14) | func (p proxyVars) empty() bool {
type proxyVarKey (line 18) | type proxyVarKey
method Keys (line 28) | func (p proxyVarKey) Keys() []string {
method proxyEnvVars (line 32) | func (d dockerRuntime) proxyEnvVars(env map[string]string) proxyVars {
FILE: environment/container/incus/incus.go
constant incusBridgeInterface (line 21) | incusBridgeInterface = "incusbr0"
function newRuntime (line 23) | func newRuntime(host environment.HostActions, guest environment.GuestAct...
function HostSocketFile (line 35) | func HostSocketFile() string { return filepath.Join(configDir(), "incus....
constant Name (line 38) | Name = "incus"
constant storageDriver (line 40) | storageDriver = "zfs"
constant poolName (line 42) | poolName = "default"
constant poolMetaDir (line 43) | poolMetaDir = "/var/lib/incus/storage-pools/" + poolName
constant poolDisksDir (line 45) | poolDisksDir = "/var/lib/incus/disks"
constant poolDiskFile (line 46) | poolDiskFile = poolDisksDir + "/" + poolName + ".img"
function init (line 49) | func init() {
type incusRuntime (line 55) | type incusRuntime struct
method Dependencies (line 63) | func (c *incusRuntime) Dependencies() []string {
method Provision (line 68) | func (c *incusRuntime) Provision(ctx context.Context) error {
method Running (line 144) | func (c *incusRuntime) Running(ctx context.Context) bool {
method Start (line 149) | func (c *incusRuntime) Start(ctx context.Context) error {
method Stop (line 212) | func (c *incusRuntime) Stop(ctx context.Context, force bool) error {
method Teardown (line 230) | func (c *incusRuntime) Teardown(ctx context.Context) error {
method Version (line 244) | func (c *incusRuntime) Version(ctx context.Context) string {
method Name (line 249) | func (c incusRuntime) Name() string {
method setRemote (line 253) | func (c incusRuntime) setRemote(activate bool) error {
method unsetRemote (line 271) | func (c incusRuntime) unsetRemote() error {
method hasRemote (line 287) | func (c incusRuntime) hasRemote(name string) bool {
method fetchRemotes (line 297) | func (c incusRuntime) fetchRemotes() (remoteInfo, error) {
method isDefaultRemote (line 311) | func (c incusRuntime) isDefaultRemote() bool {
method addDockerRemote (line 316) | func (c incusRuntime) addDockerRemote() error {
method findNetwork (line 325) | func (c incusRuntime) findNetwork(interfaceName string) (found bool, i...
method Update (line 356) | func (c *incusRuntime) Update(ctx context.Context) (bool, error) {
method poolImported (line 368) | func (c *incusRuntime) poolImported() bool {
method recoverDisk (line 375) | func (c *incusRuntime) recoverDisk(ctx context.Context) error {
method wipeDisk (line 415) | func (c *incusRuntime) wipeDisk(size int) error {
type remoteInfo (line 346) | type remoteInfo
type networkInfo (line 350) | type networkInfo struct
function migrationScript (line 434) | func migrationScript() string {
function DataDisk (line 452) | func DataDisk() environment.DataDisk {
FILE: environment/container/incus/route.go
constant BridgeSubnet (line 13) | BridgeSubnet = "192.168.100.0/24"
constant bridgeGateway (line 14) | bridgeGateway = "192.168.100.1/24"
method addContainerRoute (line 18) | func (c *incusRuntime) addContainerRoute() error {
method removeContainerRoute (line 48) | func (c *incusRuntime) removeContainerRoute() error {
FILE: environment/container/kubernetes/cni.go
function installCniConfig (line 13) | func installCniConfig(guest environment.GuestActions, a *cli.ActiveComma...
FILE: environment/container/kubernetes/k3s.go
constant listenPortKey (line 20) | listenPortKey = "k3s_listen_port"
function hasK3sArg (line 22) | func hasK3sArg(k3sArgs []string, argName string) bool {
function installK3s (line 37) | func installK3s(host environment.HostActions,
function installK3sBinary (line 51) | func installK3sBinary(
function installK3sCache (line 79) | func installK3sCache(
function installK3sCluster (line 138) | func installK3sCluster(
function getPortNumber (line 204) | func getPortNumber(guest environment.GuestActions, k3sListenPort int) (i...
FILE: environment/container/kubernetes/kubeconfig.go
constant masterAddressKey (line 15) | masterAddressKey = "master_address"
method provisionKubeconfig (line 17) | func (c kubernetesRuntime) provisionKubeconfig(ctx context.Context) error {
method unsetKubeconfig (line 123) | func (c kubernetesRuntime) unsetKubeconfig(a *cli.ActiveCommandChain) {
method teardownKubeconfig (line 143) | func (c kubernetesRuntime) teardownKubeconfig(a *cli.ActiveCommandChain) {
FILE: environment/container/kubernetes/kubernetes.go
constant Name (line 21) | Name = "kubernetes"
constant DefaultVersion (line 22) | DefaultVersion = "v1.35.0+k3s1"
constant ConfigKey (line 24) | ConfigKey = "kubernetes_config"
function newRuntime (line 27) | func newRuntime(host environment.HostActions, guest environment.GuestAct...
function init (line 36) | func init() {
type kubernetesRuntime (line 42) | type kubernetesRuntime struct
method Name (line 49) | func (c kubernetesRuntime) Name() string {
method isInstalled (line 53) | func (c kubernetesRuntime) isInstalled() bool {
method isVersionInstalled (line 58) | func (c kubernetesRuntime) isVersionInstalled(version string) bool {
method Running (line 67) | func (c kubernetesRuntime) Running(context.Context) bool {
method runtime (line 71) | func (c kubernetesRuntime) runtime() string {
method config (line 75) | func (c kubernetesRuntime) config() config.Kubernetes {
method setConfig (line 83) | func (c kubernetesRuntime) setConfig(conf config.Kubernetes) error {
method Provision (line 92) | func (c *kubernetesRuntime) Provision(ctx context.Context) error {
method Start (line 149) | func (c kubernetesRuntime) Start(ctx context.Context) error {
method Stop (line 171) | func (c kubernetesRuntime) Stop(ctx context.Context, force bool) error {
method deleteAllContainers (line 186) | func (c kubernetesRuntime) deleteAllContainers() error {
method stopAllContainers (line 208) | func (c kubernetesRuntime) stopAllContainers() error {
method runningContainerIDs (line 230) | func (c kubernetesRuntime) runningContainerIDs() string {
method Teardown (line 249) | func (c kubernetesRuntime) Teardown(ctx context.Context) error {
method Dependencies (line 267) | func (c kubernetesRuntime) Dependencies() []string {
method Version (line 271) | func (c kubernetesRuntime) Version(context.Context) string {
method Update (line 276) | func (c *kubernetesRuntime) Update(ctx context.Context) (bool, error) {
FILE: environment/environment.go
type runActions (line 11) | type runActions interface
type fileActions (line 25) | type fileActions interface
type HostActions (line 32) | type HostActions interface
type GuestActions (line 46) | type GuestActions interface
type Dependencies (line 74) | type Dependencies interface
FILE: environment/guest/systemctl/systemctl.go
type Runner (line 7) | type Runner interface
type Systemctl (line 16) | type Systemctl struct
method Start (line 26) | func (s Systemctl) Start(service string) error {
method Restart (line 31) | func (s Systemctl) Restart(service string) error {
method Stop (line 36) | func (s Systemctl) Stop(service string, force bool) error {
method Active (line 45) | func (s Systemctl) Active(service string) bool {
method DaemonReload (line 50) | func (s Systemctl) DaemonReload() error {
function New (line 21) | func New(guest Runner) Systemctl {
FILE: environment/guest/systemctl/systemctl_test.go
type mockGuest (line 9) | type mockGuest struct
method Run (line 14) | func (m *mockGuest) Run(args ...string) error { m.lastArgs = args...
method RunQuiet (line 15) | func (m *mockGuest) RunQuiet(args ...string) error { m.lastArgs = args...
function TestStart (line 17) | func TestStart(t *testing.T) {
function TestRestart (line 28) | func TestRestart(t *testing.T) {
function TestStop (line 39) | func TestStop(t *testing.T) {
function TestActive (line 63) | func TestActive(t *testing.T) {
function TestDaemonReload (line 91) | func TestDaemonReload(t *testing.T) {
function assertArgs (line 103) | func assertArgs(t *testing.T, got, want []string) {
FILE: environment/host.go
type Host (line 4) | type Host interface
FILE: environment/host/host.go
function New (line 20) | func New() environment.Host {
type hostEnv (line 26) | type hostEnv struct
method clone (line 31) | func (h hostEnv) clone() hostEnv {
method WithEnv (line 38) | func (h hostEnv) WithEnv(env ...string) environment.HostActions {
method WithDir (line 45) | func (h hostEnv) WithDir(dir string) environment.HostActions {
method Run (line 51) | func (h hostEnv) Run(args ...string) error {
method RunQuiet (line 77) | func (h hostEnv) RunQuiet(args ...string) error {
method RunOutput (line 99) | func (h hostEnv) RunOutput(args ...string) (string, error) {
method RunInteractive (line 132) | func (h hostEnv) RunInteractive(args ...string) error {
method RunWith (line 144) | func (h hostEnv) RunWith(stdin io.Reader, stdout io.Writer, args ...st...
method Env (line 167) | func (h hostEnv) Env(s string) string {
method Read (line 171) | func (h hostEnv) Read(fileName string) (string, error) {
method Write (line 176) | func (h hostEnv) Write(fileName string, body []byte) error {
method Stat (line 180) | func (h hostEnv) Stat(fileName string) (os.FileInfo, error) {
function errCmd (line 122) | func errCmd(args []string, stderr bytes.Buffer, err error) error {
function IsInstalled (line 185) | func IsInstalled(dependencies environment.Dependencies) error {
FILE: environment/vm.go
type VM (line 11) | type VM interface
constant ContainerRuntimeKey (line 21) | ContainerRuntimeKey = "runtime"
type Arch (line 25) | type Arch
method GoArch (line 38) | func (a Arch) GoArch() string {
method Value (line 50) | func (a Arch) Value() Arch {
constant X8664 (line 28) | X8664 Arch = "x86_64"
constant AARCH64 (line 29) | AARCH64 Arch = "aarch64"
function HostArch (line 33) | func HostArch() Arch {
function DefaultVMType (line 66) | func DefaultVMType() string {
FILE: environment/vm/lima/certs.go
method copyCerts (line 12) | func (l limaVM) copyCerts() error {
FILE: environment/vm/lima/config.go
constant configFile (line 10) | configFile = "/etc/colima/colima.json"
method getConf (line 12) | func (l limaVM) getConf() map[string]string {
method Get (line 28) | func (l limaVM) Get(key string) string {
method Set (line 36) | func (l limaVM) Set(key, value string) error {
FILE: environment/vm/lima/daemon.go
method startDaemon (line 16) | func (l *limaVM) startDaemon(ctx context.Context, conf config.Config) (c...
FILE: environment/vm/lima/disk.go
method createRuntimeDisk (line 27) | func (l *limaVM) createRuntimeDisk(conf config.Config) error {
method useRuntimeDisk (line 61) | func (l *limaVM) useRuntimeDisk(conf config.Config) {
function dataDisk (line 82) | func dataDisk(runtime string) environment.DataDisk {
function diskMountScript (line 95) | func diskMountScript(format bool) string {
method mountRuntimeDisk (line 112) | func (l *limaVM) mountRuntimeDisk(conf config.Config, format bool) {
method downloadDiskImage (line 145) | func (l *limaVM) downloadDiskImage(ctx context.Context, conf config.Conf...
method setDiskImage (line 186) | func (l *limaVM) setDiskImage() error {
method syncDiskSize (line 200) | func (l *limaVM) syncDiskSize(ctx context.Context, conf config.Config) c...
FILE: environment/vm/lima/dns.go
constant localhostAddr (line 12) | localhostAddr = "127.0.0.1"
constant defaultGatewayAddress (line 13) | defaultGatewayAddress = "192.168.5.2"
function hasDnsmasq (line 16) | func hasDnsmasq(l *limaVM) bool {
method setupDNS (line 21) | func (l *limaVM) setupDNS(conf config.Config) error {
FILE: environment/vm/lima/file.go
method Read (line 16) | func (l limaVM) Read(fileName string) (string, error) {
method Write (line 24) | func (l *limaVM) Write(fileName string, body []byte) error {
method Stat (line 33) | func (l *limaVM) Stat(fileName string) (os.FileInfo, error) {
type fileInfo (line 39) | type fileInfo struct
method IsDir (line 78) | func (f fileInfo) IsDir() bool { return f.isDir }
method ModTime (line 81) | func (f fileInfo) ModTime() time.Time { return f.modTime }
method Mode (line 84) | func (f fileInfo) Mode() fs.FileMode { return f.mode }
method Name (line 87) | func (f fileInfo) Name() string { return f.name }
method Size (line 90) | func (f fileInfo) Size() int64 { return f.size }
method Sys (line 93) | func (fileInfo) Sys() any { return nil }
function newFileInfo (line 47) | func newFileInfo(guest environment.GuestActions, filename string) (fileI...
function statError (line 73) | func statError(filename string, err error) error {
FILE: environment/vm/lima/lima.go
function New (line 27) | func New(host environment.HostActions) environment.VM {
constant envLimaInstance (line 48) | envLimaInstance = "LIMA_INSTANCE"
constant lima (line 49) | lima = "lima"
constant limactl (line 50) | limactl = limautil.LimactlCommand
type limaVM (line 55) | type limaVM struct
method Dependencies (line 72) | func (l limaVM) Dependencies() []string {
method Start (line 78) | func (l *limaVM) Start(ctx context.Context, conf config.Config) error {
method resume (line 134) | func (l *limaVM) resume(ctx context.Context, conf config.Config) error {
method Running (line 182) | func (l limaVM) Running(_ context.Context) bool {
method Stop (line 191) | func (l limaVM) Stop(ctx context.Context, force bool) error {
method Teardown (line 226) | func (l limaVM) Teardown(ctx context.Context) error {
method Restart (line 243) | func (l limaVM) Restart(ctx context.Context) error {
method Host (line 262) | func (l limaVM) Host() environment.HostActions {
method Env (line 266) | func (l limaVM) Env(s string) (string, error) {
method Created (line 274) | func (l limaVM) Created() bool {
method User (line 279) | func (l limaVM) User() (string, error) {
method Arch (line 283) | func (l limaVM) Arch() environment.Arch {
method addPostStartActions (line 288) | func (l *limaVM) addPostStartActions(a *cli.ActiveCommandChain, conf c...
method assertQemu (line 367) | func (l *limaVM) assertQemu() error {
method prepareHost (line 381) | func (l *limaVM) prepareHost(conf config.Config) {
constant envLimaSSHPortForwarder (line 379) | envLimaSSHPortForwarder = "LIMA_SSH_PORT_FORWARDER"
FILE: environment/vm/lima/limaconfig/config.go
type Config (line 12) | type Config struct
type File (line 35) | type File struct
type Mount (line 41) | type Mount struct
type Disk (line 48) | type Disk struct
type SSH (line 55) | type SSH struct
type Containerd (line 61) | type Containerd struct
type Firmware (line 66) | type Firmware struct
constant TCP (line 79) | TCP Proto = "tcp"
constant UDP (line 80) | UDP Proto = "udp"
constant REVSSHFS (line 82) | REVSSHFS MountType = "reverse-sshfs"
constant NINEP (line 83) | NINEP MountType = "9p"
constant VIRTIOFS (line 84) | VIRTIOFS MountType = "virtiofs"
constant Krunkit (line 86) | Krunkit VMType = "krunkit"
constant QEMU (line 87) | QEMU VMType = "qemu"
constant VZ (line 88) | VZ VMType = "vz"
type PortForward (line 91) | type PortForward struct
type HostResolver (line 105) | type HostResolver struct
type Network (line 111) | type Network struct
constant ProvisionModeSystem (line 132) | ProvisionModeSystem ProvisionMode = "system"
constant ProvisionModeUser (line 133) | ProvisionModeUser ProvisionMode = "user"
constant ProvisionModeBoot (line 134) | ProvisionModeBoot ProvisionMode = "boot"
constant ProvisionModeDependency (line 135) | ProvisionModeDependency ProvisionMode = "dependency"
type Provision (line 138) | type Provision struct
type NineP (line 144) | type NineP struct
type VMOpts (line 151) | type VMOpts struct
type QEMUOpts (line 156) | type QEMUOpts struct
type VZOpts (line 161) | type VZOpts struct
type Rosetta (line 165) | type Rosetta struct
FILE: environment/vm/lima/limautil/disk.go
function HasDisk (line 13) | func HasDisk() bool {
function CreateDisk (line 37) | func CreateDisk(size int) error {
function ResizeDisk (line 53) | func ResizeDisk(size int) error {
function DeleteDisk (line 69) | func DeleteDisk() error {
function MountPoint (line 85) | func MountPoint() string { return fmt.Sprintf("/mnt/lima-%s", config.Cur...
function DiskProvisioned (line 88) | func DiskProvisioned(runtime string) bool {
FILE: environment/vm/lima/limautil/files.go
constant colimaDiffDiskFile (line 9) | colimaDiffDiskFile = "diffdisk"
function ColimaDiffDisk (line 12) | func ColimaDiffDisk(profileID string) string {
constant networkFile (line 16) | networkFile = "networks.yaml"
function NetworkFile (line 19) | func NetworkFile() string {
function NetworkAssetsDirectory (line 24) | func NetworkAssetsDirectory() string {
FILE: environment/vm/lima/limautil/image.go
function init (line 20) | func init() {
function ImageCached (line 28) | func ImageCached(arch environment.Arch, runtime string) (limaconfig.File...
function findImage (line 42) | func findImage(arch environment.Arch, runtime string) (f limaconfig.File...
function Image (line 57) | func Image(arch environment.Arch, runtime string) (limaconfig.File, erro...
function DownloadImage (line 62) | func DownloadImage(arch environment.Arch, runtime string) (f limaconfig....
type diskImages (line 99) | type diskImages
function loadImages (line 101) | func loadImages() error {
function loadImagesFromBytes (line 110) | func loadImagesFromBytes(b []byte) error {
function downloadImage (line 142) | func downloadImage(host environment.HostActions, file limaconfig.File) (...
function qcow2ToRaw (line 158) | func qcow2ToRaw(host environment.Host, image diskImageFile) (string, err...
type diskImageFile (line 174) | type diskImageFile
method String (line 176) | func (d diskImageFile) String() string { return strings.TrimSuffix(str...
method Raw (line 177) | func (d diskImageFile) Raw() string { return d.String() + ".raw" }
method Generated (line 178) | func (d diskImageFile) Generated() bool {
method Location (line 184) | func (d diskImageFile) Location() string {
FILE: environment/vm/lima/limautil/instance.go
function Instance (line 15) | func Instance() (InstanceInfo, error) {
type InstanceInfo (line 20) | type InstanceInfo struct
method Running (line 37) | func (i InstanceInfo) Running() bool { return i.Status == limaStatusRu...
method Config (line 40) | func (i InstanceInfo) Config() (config.Config, error) {
constant limaStatusRunning (line 46) | limaStatusRunning = "Running"
function getInstance (line 49) | func getInstance(profileID string) (InstanceInfo, error) {
function Instances (line 77) | func Instances(ids ...string) ([]InstanceInfo, error) {
function RunningInstances (line 135) | func RunningInstances() ([]InstanceInfo, error) {
function getRuntime (line 151) | func getRuntime(conf config.Config) string {
FILE: environment/vm/lima/limautil/limautil.go
constant EnvLimaHome (line 12) | EnvLimaHome = "LIMA_HOME"
constant EnvLimaDrivers (line 15) | EnvLimaDrivers = "LIMA_DRIVERS_PATH"
constant LimactlCommand (line 18) | LimactlCommand = "limactl"
function Limactl (line 21) | func Limactl(args ...string) *exec.Cmd {
FILE: environment/vm/lima/limautil/network.go
constant NetInterface (line 10) | NetInterface = "col0"
constant NetMetric (line 13) | NetMetric uint32 = 300
constant NetMetricPreferred (line 14) | NetMetricPreferred uint32 = 100
function IPAddress (line 21) | func IPAddress(profileID string) string {
function InternalIPAddress (line 40) | func InternalIPAddress(profileID string) string {
function getIPAddress (line 44) | func getIPAddress(profileID, interfaceName string) string {
type LimaNetworkConfig (line 56) | type LimaNetworkConfig struct
type LimaNetwork (line 62) | type LimaNetwork struct
FILE: environment/vm/lima/limautil/ssh.go
function ShowSSH (line 16) | func ShowSSH(profileID string) (resp struct {
function replaceSSHConfig (line 35) | func replaceSSHConfig(conf string, profileID string) string {
constant sshConfigFile (line 53) | sshConfigFile = "ssh.config"
type sshConfig (line 56) | type sshConfig
method Contents (line 59) | func (s sshConfig) Contents() (string, error) {
method File (line 69) | func (s sshConfig) File() string {
FILE: environment/vm/lima/network.go
method writeNetworkFile (line 30) | func (l *limaVM) writeNetworkFile(conf config.Config) error {
method replicateHostAddresses (line 61) | func (l *limaVM) replicateHostAddresses(conf config.Config) error {
method removeHostAddresses (line 72) | func (l *limaVM) removeHostAddresses() {
method removeIncusContainerRoute (line 83) | func (l *limaVM) removeIncusContainerRoute() {
FILE: environment/vm/lima/shell.go
method Run (line 10) | func (l limaVM) Run(args ...string) error {
method SSH (line 22) | func (l limaVM) SSH(workingDir string, args ...string) error {
method RunInteractive (line 38) | func (l limaVM) RunInteractive(args ...string) error {
method RunWith (line 50) | func (l limaVM) RunWith(stdin io.Reader, stdout io.Writer, args ...strin...
method RunOutput (line 62) | func (l limaVM) RunOutput(args ...string) (out string, err error) {
method RunQuiet (line 76) | func (l limaVM) RunQuiet(args ...string) (err error) {
FILE: environment/vm/lima/yaml.go
function newConf (line 24) | func newConf(ctx context.Context, conf config.Config) (l limaconfig.Conf...
function selectPath (line 424) | func selectPath(m config.Mount) (string, error) {
function checkOverlappingMounts (line 432) | func checkOverlappingMounts(mounts []config.Mount) error {
function ingressDisabled (line 452) | func ingressDisabled(disableFlags []string) bool {
constant diskLabelMaxLength (line 475) | diskLabelMaxLength = 16
function diskByLabelPath (line 477) | func diskByLabelPath(instanceId string) string {
FILE: environment/vm/lima/yaml_test.go
function Test_checkOverlappingMounts (line 16) | func Test_checkOverlappingMounts(t *testing.T) {
function Test_config_Mounts (line 48) | func Test_config_Mounts(t *testing.T) {
function Test_ingressDisabled (line 105) | func Test_ingressDisabled(t *testing.T) {
FILE: model/docker.go
type DockerModelInfo (line 17) | type DockerModelInfo struct
method Hash (line 30) | func (m *DockerModelInfo) Hash() string {
type ociManifest (line 38) | type ociManifest struct
function findGGUFPath (line 48) | func findGGUFPath(guest environment.VM, modelHash string) (string, error) {
function InspectDockerModel (line 98) | func InspectDockerModel(modelName string) (*DockerModelInfo, error) {
function SetupOrUpdateDocker (line 114) | func SetupOrUpdateDocker() error {
function GetDockerModelVersion (line 137) | func GetDockerModelVersion() string {
function EnsureDockerModel (line 148) | func EnsureDockerModel(modelName string) (string, error) {
type DockerModelServeConfig (line 173) | type DockerModelServeConfig struct
function ServeDockerModel (line 184) | func ServeDockerModel(cfg DockerModelServeConfig) error {
function ensureDockerModelRunner (line 266) | func ensureDockerModelRunner(guest environment.VM) error {
function getDockerModelRunnerIP (line 282) | func getDockerModelRunnerIP(guest environment.VM) (string, error) {
function startSocat (line 298) | func startSocat(guest environment.VM, port int, containerIP string) error {
function stopSocat (line 305) | func stopSocat(guest environment.VM, port int) {
function StopDockerModelServe (line 311) | func StopDockerModelServe(port int) error {
function IsDockerModelServeRunning (line 328) | func IsDockerModelServeRunning(port int) bool {
FILE: model/ramalama.go
constant ramalamaReleasesURL (line 16) | ramalamaReleasesURL = "https://api.github.com/repos/containers/ramalama/...
function SetupOrUpdateRamalama (line 20) | func SetupOrUpdateRamalama() error {
function GetRamalamaVersion (line 26) | func GetRamalamaVersion() string {
function getLatestRamalamaVersion (line 41) | func getLatestRamalamaVersion() (string, error) {
type ramalamaModel (line 66) | type ramalamaModel struct
function listRamalamaModels (line 73) | func listRamalamaModels() ([]ramalamaModel, error) {
function ramalamaModelExists (line 94) | func ramalamaModelExists(modelName string) bool {
function normalizeRamalamaModelName (line 115) | func normalizeRamalamaModelName(name string) string {
function EnsureRamalamaModel (line 128) | func EnsureRamalamaModel(modelName string) error {
function ProvisionRamalama (line 148) | func ProvisionRamalama() error {
FILE: model/runner.go
type RunnerType (line 24) | type RunnerType
constant RunnerDocker (line 27) | RunnerDocker RunnerType = "docker"
constant RunnerRamalama (line 28) | RunnerRamalama RunnerType = "ramalama"
type SetupStatus (line 32) | type SetupStatus struct
type Runner (line 42) | type Runner interface
function GetRunner (line 72) | func GetRunner(runnerType RunnerType) (Runner, error) {
function validateCommonPrerequisites (line 84) | func validateCommonPrerequisites(a app.App) error {
type dockerRunner (line 119) | type dockerRunner struct
method Name (line 121) | func (d *dockerRunner) Name() RunnerType {
method DisplayName (line 125) | func (d *dockerRunner) DisplayName() string {
method ValidatePrerequisites (line 129) | func (d *dockerRunner) ValidatePrerequisites(a app.App) error {
method EnsureProvisioned (line 133) | func (d *dockerRunner) EnsureProvisioned() error {
method BuildArgs (line 138) | func (d *dockerRunner) BuildArgs(args []string) ([]string, error) {
method EnsureModel (line 145) | func (d *dockerRunner) EnsureModel(modelName string) (string, error) {
method Serve (line 150) | func (d *dockerRunner) Serve(modelName string, port int) error {
method CheckSetup (line 283) | func (d *dockerRunner) CheckSetup() (SetupStatus, error) {
method Setup (line 291) | func (d *dockerRunner) Setup() error {
method GetCurrentVersion (line 295) | func (d *dockerRunner) GetCurrentVersion() string {
type dockerModel (line 158) | type dockerModel struct
function GetFirstModel (line 165) | func GetFirstModel() (string, error) {
function listDockerModels (line 181) | func listDockerModels() ([]dockerModel, error) {
function ResolveModelName (line 208) | func ResolveModelName(name string) (string, error) {
function matchesModel (line 226) | func matchesModel(name, tag string) bool {
function normalizeModelName (line 273) | func normalizeModelName(name string) string {
type ramalamaRunner (line 309) | type ramalamaRunner struct
method Name (line 311) | func (r *ramalamaRunner) Name() RunnerType {
method DisplayName (line 315) | func (r *ramalamaRunner) DisplayName() string {
method ValidatePrerequisites (line 319) | func (r *ramalamaRunner) ValidatePrerequisites(a app.App) error {
method EnsureProvisioned (line 323) | func (r *ramalamaRunner) EnsureProvisioned() error {
method BuildArgs (line 340) | func (r *ramalamaRunner) BuildArgs(args []string) ([]string, error) {
method EnsureModel (line 345) | func (r *ramalamaRunner) EnsureModel(modelName string) (string, error) {
method Serve (line 353) | func (r *ramalamaRunner) Serve(modelName string, port int) error {
method buildRamalamaArgs (line 365) | func (r *ramalamaRunner) buildRamalamaArgs(args []string) []string {
method CheckSetup (line 381) | func (r *ramalamaRunner) CheckSetup() (SetupStatus, error) {
method Setup (line 434) | func (r *ramalamaRunner) Setup() error {
method GetCurrentVersion (line 438) | func (r *ramalamaRunner) GetCurrentVersion() string {
FILE: model/runner_test.go
function TestNormalizeModelName (line 7) | func TestNormalizeModelName(t *testing.T) {
function TestMatchesModel (line 55) | func TestMatchesModel(t *testing.T) {
function TestResolveModelNameWithMockData (line 199) | func TestResolveModelNameWithMockData(t *testing.T) {
FILE: store/store.go
type Store (line 13) | type Store struct
function storeFile (line 22) | func storeFile() string { return config.CurrentProfile().StoreFile() }
function Load (line 25) | func Load() (s Store, err error) {
function save (line 39) | func save(s Store) error {
function Set (line 53) | func Set(f func(*Store)) error {
function Reset (line 69) | func Reset() error {
FILE: util/debutil/debutil.go
type packages (line 13) | type packages
method Upgradable (line 17) | func (p packages) Upgradable() string {
method Install (line 27) | func (p packages) Install() string {
function UpdateRuntime (line 31) | func UpdateRuntime(
FILE: util/downloader/curl.go
constant DownloaderNative (line 15) | DownloaderNative = "native"
constant DownloaderCurl (line 17) | DownloaderCurl = "curl"
constant envDownloader (line 19) | envDownloader = "COLIMA_DOWNLOADER"
function ValidateDownloader (line 24) | func ValidateDownloader(v string) (string, error) {
type curlDownloader (line 36) | type curlDownloader struct
method Download (line 39) | func (c *curlDownloader) Download(r Request, destPath string) error {
FILE: util/downloader/download.go
type Request (line 23) | type Request struct
type FileDownloader (line 29) | type FileDownloader interface
function SetDownloader (line 38) | func SetDownloader(v string) {
function init (line 46) | func init() {
function DownloadToGuest (line 60) | func DownloadToGuest(host hostActions, guest guestActions, r Request, fi...
function CopyToGuest (line 75) | func CopyToGuest(host hostActions, src, dest string) error {
function Download (line 81) | func Download(host hostActions, r Request) (string, error) {
type downloader (line 93) | type downloader struct
method cacheDownloadingFileName (line 100) | func (d downloader) cacheDownloadingFileName(url string) string {
method resumeInfoPath (line 104) | func (d downloader) resumeInfoPath(url string) string {
method downloadFile (line 108) | func (d downloader) downloadFile(r Request) (err error) {
method saveResumeInfo (line 138) | func (d downloader) saveResumeInfo(url, etag string, bytesWritten int6...
method hasCache (line 144) | func (d downloader) hasCache(url string) bool {
function CacheFilename (line 96) | func CacheFilename(url string) string {
FILE: util/downloader/errors.go
type NetworkError (line 21) | type NetworkError struct
method Error (line 27) | func (e *NetworkError) Error() string {
method Unwrap (line 31) | func (e *NetworkError) Unwrap() error {
method friendlyMessage (line 35) | func (e *NetworkError) friendlyMessage() string {
type HTTPStatusError (line 65) | type HTTPStatusError struct
method Error (line 71) | func (e *HTTPStatusError) Error() string {
method Unwrap (line 88) | func (e *HTTPStatusError) Unwrap() error {
type ResumeError (line 93) | type ResumeError struct
method Error (line 98) | func (e *ResumeError) Error() string {
method Unwrap (line 102) | func (e *ResumeError) Unwrap() error {
type SHAValidationError (line 107) | type SHAValidationError struct
method Error (line 114) | func (e *SHAValidationError) Error() string {
method Unwrap (line 119) | func (e *SHAValidationError) Unwrap() error {
FILE: util/downloader/http.go
type HTTPClient (line 20) | type HTTPClient struct
method GetFinalURL (line 73) | func (h *HTTPClient) GetFinalURL(ctx context.Context, rawURL string) (...
method Download (line 100) | func (h *HTTPClient) Download(ctx context.Context, opts DownloadOption...
method Fetch (line 221) | func (h *HTTPClient) Fetch(ctx context.Context, url string) ([]byte, e...
method createProgressBar (line 247) | func (h *HTTPClient) createProgressBar(totalBytes, startOffset int64) ...
type DownloadOptions (line 26) | type DownloadOptions struct
type DownloadResult (line 35) | type DownloadResult struct
type ResumeInfo (line 43) | type ResumeInfo struct
function NewHTTPClient (line 49) | func NewHTTPClient() *HTTPClient {
function parseContentRangeTotal (line 284) | func parseContentRangeTotal(header string) int64 {
function isTerminal (line 300) | func isTerminal() bool {
FILE: util/downloader/native.go
type nativeDownloader (line 13) | type nativeDownloader struct
method Download (line 16) | func (n *nativeDownloader) Download(r Request, destPath string) error {
FILE: util/downloader/sha.go
type SHA (line 19) | type SHA struct
method ValidateFile (line 27) | func (s SHA) ValidateFile(host hostActions, file string) error {
method validateFile (line 32) | func (s SHA) validateFile(file string) error {
method validateDownload (line 73) | func (s SHA) validateDownload(url string, filename string) error {
function fetchSHAFromURL (line 98) | func fetchSHAFromURL(shaURL, targetFilename string) (string, error) {
function parseSHAContent (line 123) | func parseSHAContent(data []byte, targetFilename string) (string, error) {
FILE: util/fsutil/fs.go
function MkdirAll (line 13) | func MkdirAll(path string, perm os.FileMode) error { return FS.MkdirAll(...
function Open (line 16) | func Open(name string) (fs.File, error) { return FS.Open(name) }
type FileSystem (line 19) | type FileSystem interface
type DefaultFS (line 28) | type DefaultFS struct
method Open (line 31) | func (DefaultFS) Open(name string) (fs.File, error) { return os.Open(n...
method MkdirAll (line 34) | func (DefaultFS) MkdirAll(path string, perm fs.FileMode) error { retur...
type fakeFS (line 41) | type fakeFS struct
method Open (line 44) | func (fakeFS) Open(name string) (fs.File, error) {
method MkdirAll (line 51) | func (fakeFS) MkdirAll(path string, perm fs.FileMode) error { return n...
FILE: util/macos.go
function MacOS (line 19) | func MacOS() bool {
function MacOS13OrNewerOnArm (line 24) | func MacOS13OrNewerOnArm() bool {
function MacOS13OrNewer (line 29) | func MacOS13OrNewer() bool { return minMacOSVersion("13.0.0") }
function MacOS15OrNewer (line 32) | func MacOS15OrNewer() bool { return minMacOSVersion("15.0.0") }
function MacOSNestedVirtualizationSupported (line 35) | func MacOSNestedVirtualizationSupported() bool {
function minMacOSVersion (line 39) | func minMacOSVersion(version string) bool {
function IsMxOrNewer (line 60) | func IsMxOrNewer(min int) bool {
type chipTypeDetector (line 74) | type chipTypeDetector interface
type systemProfilerChipDetector (line 80) | type systemProfilerChipDetector struct
method GetChipType (line 82) | func (d systemProfilerChipDetector) GetChipType() (string, error) {
function parseMNumber (line 117) | func parseMNumber(s string) (int, bool) {
function RosettaRunning (line 133) | func RosettaRunning() bool {
function macOSProductVersion (line 144) | func macOSProductVersion() (*semver.Version, error) {
FILE: util/macos_test.go
type fakeDetector (line 8) | type fakeDetector struct
method GetChipType (line 13) | func (f fakeDetector) GetChipType() (string, error) { return f.v, f.e }
function TestParseMNumber (line 15) | func TestParseMNumber(t *testing.T) {
function TestIsMxOrNewer (line 39) | func TestIsMxOrNewer(t *testing.T) {
FILE: util/osutil/os.go
type EnvVar (line 15) | type EnvVar
method Exists (line 18) | func (e EnvVar) Exists() bool {
method Bool (line 24) | func (e EnvVar) Bool() bool {
method Val (line 30) | func (e EnvVar) Val() string {
method ValOr (line 35) | func (e EnvVar) ValOr(val string) string {
method WithPath (line 43) | func (e EnvVar) WithPath(p string) string {
constant EnvColimaBinary (line 50) | EnvColimaBinary = "COLIMA_BINARY"
function Executable (line 54) | func Executable() string {
type Socket (line 89) | type Socket
method Unix (line 92) | func (s Socket) Unix() string { return "unix://" + s.File() }
method File (line 95) | func (s Socket) File() string { return strings.TrimPrefix(string(s), "...
FILE: util/qemu.go
function AssertQemuImg (line 9) | func AssertQemuImg() error {
function AssertKrunkit (line 19) | func AssertKrunkit() error {
FILE: util/shautil/sha.go
type SHA (line 10) | type SHA interface
type s1 (line 15) | type s1
method String (line 17) | func (s s1) String() string { return fmt.Sprintf("%x", s[:]) }
method Bytes (line 18) | func (s s1) Bytes() []byte { return s[:] }
type s256 (line 20) | type s256
method String (line 22) | func (s s256) String() string { return fmt.Sprintf("%x", s[:]) }
method Bytes (line 23) | func (s s256) Bytes() []byte { return s[:] }
function SHA256 (line 26) | func SHA256(s string) SHA {
function SHA1 (line 31) | func SHA1(s string) SHA {
FILE: util/template.go
function WriteTemplate (line 11) | func WriteTemplate(body string, file string, values any) error {
function ParseTemplate (line 20) | func ParseTemplate(body string, values any) ([]byte, error) {
FILE: util/terminal/output.go
type verboseWriter (line 19) | type verboseWriter struct
method Write (line 39) | func (v *verboseWriter) Write(p []byte) (n int, err error) {
method printLineVerbose (line 62) | func (v *verboseWriter) printLineVerbose() {
method refresh (line 68) | func (v *verboseWriter) refresh() error {
method addLine (line 74) | func (v *verboseWriter) addLine() {
method Close (line 89) | func (v *verboseWriter) Close() error {
method sanitizeLine (line 103) | func (v *verboseWriter) sanitizeLine(line string) string {
method printScreen (line 115) | func (v *verboseWriter) printScreen() error {
method clearScreen (line 135) | func (v *verboseWriter) clearScreen() {
method updateTerm (line 141) | func (v *verboseWriter) updateTerm() error {
function NewVerboseWriter (line 35) | func NewVerboseWriter(lineHeight int) io.WriteCloser {
FILE: util/terminal/terminal.go
function IsTerminal (line 15) | func IsTerminal() bool {
function ClearLine (line 20) | func ClearLine() {
function EnterAltScreen (line 31) | func EnterAltScreen() {
function ExitAltScreen (line 41) | func ExitAltScreen() {
function WithAltScreen (line 55) | func WithAltScreen(fn func() error, header ...string) error {
function countLines (line 127) | func countLines(s string, termWidth int) int {
FILE: util/util.go
function HomeDir (line 16) | func HomeDir() string {
function RandomAvailablePort (line 26) | func RandomAvailablePort() int {
function isPortAvailable (line 40) | func isPortAvailable(port int) bool {
function FindAvailablePort (line 54) | func FindAvailablePort(startPort, maxAttempts int) (int, bool) {
function HostIPAddresses (line 65) | func HostIPAddresses() []net.IP {
function SubnetAvailable (line 85) | func SubnetAvailable(subnet string) bool {
function RouteExists (line 113) | func RouteExists(subnet string) bool {
function ShellSplit (line 143) | func ShellSplit(cmd string) []string {
function CleanPath (line 156) | func CleanPath(location string) (string, error) {
FILE: util/yamlutil/yaml.go
function WriteYAML (line 17) | func WriteYAML(value any, file string) error {
function Save (line 27) | func Save(c config.Config, file string) error {
function encodeYAML (line 39) | func encodeYAML(conf config.Config) ([]byte, error) {
function traverseConfig (line 112) | func traverseConfig(parentKey string, s any, vals map[string]any) {
function traverseNode (line 140) | func traverseNode(parentKey string, node *yaml.Node, vals map[string]*ya...
function encode (line 186) | func encode(v any) ([]byte, error) {
FILE: util/yamlutil/yaml_test.go
function Test_encode_Docker (line 12) | func Test_encode_Docker(t *testing.T) {
Condensed preview — 143 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (487K chars).
[
{
"path": ".editorconfig",
"chars": 25,
"preview": "[*.go]\nindent_style = tab"
},
{
"path": ".github/FUNDING.yml",
"chars": 81,
"preview": "github: abiosoft\ncustom:\n - \"https://buymeacoffee.com/abiosoft\"\npatreon: colima\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yaml",
"chars": 1567,
"preview": "name: Bug report\ndescription: Report a bug or issue\nbody:\n - type: textarea\n attributes:\n label: Description\n "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yaml",
"chars": 127,
"preview": "name: Feature request\ndescription: Request a missing feature\nbody:\n - type: textarea\n attributes:\n label: Descr"
},
{
"path": ".github/dependabot.yaml",
"chars": 220,
"preview": "version: 2\nupdates:\n- package-ecosystem: \"gomod\"\n directory: \"/\"\n schedule:\n interval: \"daily\"\n open-pull-requests"
},
{
"path": ".github/workflows/go.yml",
"chars": 3675,
"preview": "name: Go\n\non:\n push:\n tags: [\"v*\"]\n paths-ignore:\n - \"**/*.md\"\n - \"**/*.nix\"\n - \"**/*.lock\"\n pull"
},
{
"path": ".github/workflows/golang-ci.yml",
"chars": 730,
"preview": "name: golangci-lint\non:\n push:\n tags: [v*]\n branches: [main]\n paths-ignore:\n - \"**/*.md\"\n - \"**/*.ni"
},
{
"path": ".github/workflows/integration.yml",
"chars": 8349,
"preview": "name: Integration\n\non:\n push:\n tags: [\"v*\"]\n branches: [main]\n paths-ignore:\n - \"**/*.md\"\n - \"**/*.n"
},
{
"path": ".gitignore",
"chars": 53,
"preview": ".idea/\n.fleet/\n.vscode/\n_output/\n_build/\nbin/\nresult\n"
},
{
"path": ".golangci.yml",
"chars": 47,
"preview": "version: \"2\"\nlinters:\n enable:\n - gocritic\n"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2021 Abiola Ibrahim\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "Makefile",
"chars": 1928,
"preview": "\nOS ?= $(shell uname)\nARCH ?= $(shell uname -m)\n\nGOOS ?= $(shell echo \"$(OS)\" | tr '[:upper:]' '[:lower:]')\nGOARCH_x86_6"
},
{
"path": "README.md",
"chars": 6847,
"preview": "\n\n## Colima - container runtimes on macOS (and Linux) with minimal setup.\n\n[\n\n// CtxKeyQuiet is the contex"
},
{
"path": "cli/command.go",
"chars": 1855,
"preview": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar runner commandRunner "
},
{
"path": "cmd/clone.go",
"chars": 2536,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft/colima/cmd/"
},
{
"path": "cmd/colima/main.go",
"chars": 292,
"preview": "package main\n\nimport (\n\t_ \"github.com/abiosoft/colima/cmd\" // for other commands\n\t_ \"github.com/abiosoft/colima/c"
},
{
"path": "cmd/completion.go",
"chars": 1985,
"preview": "package cmd\n\nimport (\n\t\"os\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/spf13/cobra\"\n)\n\n// completionCmd repres"
},
{
"path": "cmd/daemon/cmd.go",
"chars": 2897,
"preview": "package daemon\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abiosoft/colima/config\""
},
{
"path": "cmd/daemon/daemon.go",
"chars": 3663,
"preview": "package daemon\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\""
},
{
"path": "cmd/daemon/daemon_test.go",
"chars": 2620,
"preview": "package daemon\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/daemon/process\"\n)\n"
},
{
"path": "cmd/delete.go",
"chars": 857,
"preview": "package cmd\n\nimport (\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar deleteCmdArgs struct {\n\tfo"
},
{
"path": "cmd/kubernetes.go",
"chars": 3420,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abiosoft/colima/config\"\n\t\"g"
},
{
"path": "cmd/list.go",
"chars": 1970,
"preview": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"text/tabwriter\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abi"
},
{
"path": "cmd/model.go",
"chars": 6811,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abiosoft/colima/config/configmanager\"\n"
},
{
"path": "cmd/nerdctl.go",
"chars": 5612,
"preview": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"gith"
},
{
"path": "cmd/prune.go",
"chars": 1582,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft/"
},
{
"path": "cmd/restart.go",
"chars": 1183,
"preview": "package cmd\n\nimport (\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abiosoft/colima/config/configmanager\""
},
{
"path": "cmd/root/root.go",
"chars": 2701,
"preview": "package root\n\nimport (\n\t\"log\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/sirup"
},
{
"path": "cmd/ssh-config.go",
"chars": 674,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/a"
},
{
"path": "cmd/ssh.go",
"chars": 570,
"preview": "package cmd\n\nimport (\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/spf13/cobra\"\n)\n\n// sshCmd represents the ssh c"
},
{
"path": "cmd/start.go",
"chars": 23054,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/abio"
},
{
"path": "cmd/start_test.go",
"chars": 1305,
"preview": "package cmd\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/abiosoft/colima/config\"\n)\n\nfunc Test_mountsFromFlag"
},
{
"path": "cmd/status.go",
"chars": 737,
"preview": "package cmd\n\nimport (\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar statusCmdArgs struct {\n\tex"
},
{
"path": "cmd/stop.go",
"chars": 683,
"preview": "package cmd\n\nimport (\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar stopCmdArgs struct {\n\tforc"
},
{
"path": "cmd/template.go",
"chars": 2586,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abiosoft"
},
{
"path": "cmd/update.go",
"chars": 491,
"preview": "package cmd\n\nimport (\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/spf13/cobra\"\n)\n\n// statusCmd represents the st"
},
{
"path": "cmd/util.go",
"chars": 2674,
"preview": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/app\"\n\t"
},
{
"path": "cmd/version.go",
"chars": 1066,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/app\"\n\t\"github.com/abiosoft/colima/cmd/root\"\n\t\"github.com/abio"
},
{
"path": "colima.nix",
"chars": 1009,
"preview": "{ pkgs ? import <nixpkgs> }:\n\nwith pkgs;\n\nbuildGo123Module {\n name = \"colima\";\n pname = \"colima\";\n src = ./.;\n nativ"
},
{
"path": "config/config.go",
"chars": 4990,
"preview": "package config\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/abiosoft/colima/util\"\n\t\"github.com/abiosoft/colima/util/osutil\"\n)\n\n"
},
{
"path": "config/configmanager/configmanager.go",
"chars": 3773,
"preview": "package configmanager\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abioso"
},
{
"path": "config/files.go",
"chars": 3901,
"preview": "package config\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"github.com/abiosoft/colima/util\"\n\t\"github.com/abiosoft"
},
{
"path": "config/profile.go",
"chars": 2750,
"preview": "package config\n\nimport (\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nvar profile = &Profile{ID: AppName, DisplayName: AppName, ShortN"
},
{
"path": "core/core.go",
"chars": 2191,
"preview": "package core\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/abiosoft"
},
{
"path": "daemon/daemon.go",
"chars": 3881,
"preview": "package daemon\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft/colima/config\"\n\t\"git"
},
{
"path": "daemon/process/inotify/events.go",
"chars": 2414,
"preview": "package inotify\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"time\"\n)\n\ntype modEvent struct {\n\tpath string // filename\n\tfs.File"
},
{
"path": "daemon/process/inotify/inotify.go",
"chars": 2297,
"preview": "package inotify\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/daemon/process\"\n\t\"github.com/abiosoft/"
},
{
"path": "daemon/process/inotify/volumes.go",
"chars": 3880,
"preview": "package inotify\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abiosoft/"
},
{
"path": "daemon/process/inotify/volumes_test.go",
"chars": 1137,
"preview": "package inotify\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\t\"testing\"\n)\n\nfunc Test_omitChildrenDirectories(t *testing.T) {\n\ttests :"
},
{
"path": "daemon/process/inotify/watch.go",
"chars": 1941,
"preview": "package inotify\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/abiosoft/colima/util\"\n\t\"github.com/rjeczalik/notify\"\n\t\"g"
},
{
"path": "daemon/process/process.go",
"chars": 2105,
"preview": "package process\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/config\"\n\n\t\"github.com/abiosof"
},
{
"path": "daemon/process/vmnet/deps.go",
"chars": 2577,
"preview": "package vmnet\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\n\t\"github.com/abiosoft/colima/daemon/process\"\n\t\"github."
},
{
"path": "daemon/process/vmnet/vmnet.go",
"chars": 3699,
"preview": "package vmnet\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\""
},
{
"path": "default.nix",
"chars": 65,
"preview": "with import <nixpkgs> { };\ncallPackage (import ./colima.nix) { }\n"
},
{
"path": "docs/CONTRIBUTE.md",
"chars": 2368,
"preview": "# Contributing to Colima\n\nThank you for your interest in contributing to Colima!\n\n## Getting Started\n\nColima is a Go pro"
},
{
"path": "docs/FAQ.md",
"chars": 21664,
"preview": "# FAQs\n\n- [FAQs](#faqs)\n - [How does Colima compare to Lima?](#how-does-colima-compare-to-lima)\n - [Are Apple Silicon "
},
{
"path": "docs/INSTALL.md",
"chars": 973,
"preview": "# Installation Options\n\n## Homebrew\n\nStable Version\n\n```\nbrew install colima\n```\n\nDevelopment Version\n\n```\nbrew install "
},
{
"path": "embedded/defaults/abort.yaml",
"chars": 288,
"preview": "# ============================================================================================ #\n# To abort, delete the "
},
{
"path": "embedded/defaults/colima.yaml",
"chars": 8287,
"preview": "# Number of CPUs to be allocated to the virtual machine.\n# Default: 2\ncpu: 2\n\n# Size of the disk in GiB to be allocated "
},
{
"path": "embedded/defaults/template.yaml",
"chars": 67,
"preview": "# New instances will be created with the following configurations.\n"
},
{
"path": "embedded/embed.go",
"chars": 476,
"preview": "package embedded\n\nimport (\n\t\"embed\"\n)\n\n//go:embed network k3s defaults images\nvar fs embed.FS\n\n// FS returns the underly"
},
{
"path": "embedded/images/images.txt",
"chars": 2462,
"preview": "arm64 none https://github.com/abiosoft/colima-core/releases/download/v0.10.1/ubuntu-24.04-minimal-cloudimg-arm64-none.qc"
},
{
"path": "embedded/images/images_sha.sh",
"chars": 550,
"preview": "#!/usr/bin/env bash\n\nset -eux\n\nBASE_URL=https://github.com/abiosoft/colima-core/releases/download\nBASE_FILENAME=ubuntu-2"
},
{
"path": "embedded/k3s/flannel.json",
"chars": 413,
"preview": "{\n \"name\": \"cbr0\",\n \"cniVersion\": \"0.3.1\",\n \"plugins\": [\n {\n \"type\": \"flannel\",\n \""
},
{
"path": "embedded/network/sudo.txt",
"chars": 793,
"preview": "# starting vmnet daemon\n%staff ALL=(root:wheel) NOPASSWD:NOSETENV: /opt/colima/bin/socket_vmnet --vmnet-mode shared --so"
},
{
"path": "embedded/sudoers.go",
"chars": 1622,
"preview": "package embedded\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n"
},
{
"path": "environment/container/containerd/buildkitd.toml",
"chars": 84,
"preview": "[worker.oci]\nenabled = false\n\n[worker.containerd]\nenabled = true\n\n[grpc]\ngid = 1000\n"
},
{
"path": "environment/container/containerd/config.toml",
"chars": 18,
"preview": "[grpc]\ngid = 1000\n"
},
{
"path": "environment/container/containerd/containerd.go",
"chars": 5910,
"preview": "package containerd\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/c"
},
{
"path": "environment/container/docker/config.toml",
"chars": 46,
"preview": "disabled_plugins = [\"cri\"]\n\n[grpc]\ngid = 1000\n"
},
{
"path": "environment/container/docker/containerd.go",
"chars": 1057,
"preview": "package docker\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n)\n\nconst containerdConfFile = \"/etc/containerd/config.toml\"\nconst "
},
{
"path": "environment/container/docker/context.go",
"chars": 1141,
"preview": "package docker\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/config\"\n)\n\nvar configDir = func() string { retur"
},
{
"path": "environment/container/docker/daemon.go",
"chars": 3711,
"preview": "package docker\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n)\n\nconst daemonFile = \"/etc/docker/daemon.json\"\nconst"
},
{
"path": "environment/container/docker/docker.go",
"chars": 4388,
"preview": "package docker\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abios"
},
{
"path": "environment/container/docker/proxy.go",
"chars": 939,
"preview": "package docker\n\nimport (\n\t\"os\"\n\t\"strings\"\n)\n\ntype proxyVars struct {\n\thttp string\n\thttps string\n\tno string\n}\n\nfunc ("
},
{
"path": "environment/container/incus/config.yaml",
"chars": 578,
"preview": "networks:\n - config:\n ipv4.address: {{.BridgeGateway}}\n ipv4.nat: \"true\"\n ipv6.address: auto\n descrip"
},
{
"path": "environment/container/incus/incus.go",
"chars": 11739,
"preview": "package incus\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com"
},
{
"path": "environment/container/incus/route.go",
"chars": 1544,
"preview": "package incus\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abiosoft/colima/embedded\"\n\t\"github.com"
},
{
"path": "environment/container/kubernetes/cni.go",
"chars": 736,
"preview": "package kubernetes\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft"
},
{
"path": "environment/container/kubernetes/k3s.go",
"chars": 6475,
"preview": "package kubernetes\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abioso"
},
{
"path": "environment/container/kubernetes/kubeconfig.go",
"chars": 4038,
"preview": "package kubernetes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\""
},
{
"path": "environment/container/kubernetes/kubernetes.go",
"chars": 6642,
"preview": "package kubernetes\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\""
},
{
"path": "environment/container.go",
"chars": 2728,
"preview": "package environment\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n)\n\n// IsNoneRuntime returns if runtime is none.\nfunc IsNoneRuntim"
},
{
"path": "environment/environment.go",
"chars": 2422,
"preview": "package environment\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/abiosoft/colima/config\"\n)\n\ntype runActions interface "
},
{
"path": "environment/guest/systemctl/systemctl.go",
"chars": 1615,
"preview": "package systemctl\n\nimport \"github.com/abiosoft/colima/environment\"\n\n// Runner is the subset of environment.GuestActions "
},
{
"path": "environment/guest/systemctl/systemctl_test.go",
"chars": 2551,
"preview": "package systemctl\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\n// mockGuest records args passed to Run/RunQuiet and controls whether th"
},
{
"path": "environment/host/host.go",
"chars": 4193,
"preview": "package host\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/col"
},
{
"path": "environment/host.go",
"chars": 91,
"preview": "package environment\n\n// Host is the host environment.\ntype Host interface {\n\tHostActions\n}\n"
},
{
"path": "environment/vm/lima/certs.go",
"chars": 1435,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/environment/container/docker\"\n\t\""
},
{
"path": "environment/vm/lima/config.go",
"chars": 1019,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path/filepath\"\n)\n\nconst configFile = \"/etc/colima/colima.jso"
},
{
"path": "environment/vm/lima/daemon.go",
"chars": 3913,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abiosoft/colima/daem"
},
{
"path": "environment/vm/lima/disk.go",
"chars": 6045,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/"
},
{
"path": "environment/vm/lima/disk.sh",
"chars": 903,
"preview": "#!/usr/bin/env sh\n\n# Steps:\n# 1. Check if directory is already mounted, if yes, skip setup\n# 2. Idenify disk e.g. /dev/v"
},
{
"path": "environment/vm/lima/dns.go",
"chars": 2962,
"preview": "package lima\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abiosoft/colima/environment/vm"
},
{
"path": "environment/vm/lima/file.go",
"chars": 2317,
"preview": "package lima\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abios"
},
{
"path": "environment/vm/lima/lima.go",
"chars": 9085,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\""
},
{
"path": "environment/vm/lima/limaconfig/config.go",
"chars": 6819,
"preview": "package limaconfig\n\nimport (\n\t\"net\"\n\n\t\"github.com/abiosoft/colima/environment\"\n)\n\ntype Arch = environment.Arch\n\n// Confi"
},
{
"path": "environment/vm/lima/limautil/disk.go",
"chars": 2144,
"preview": "package limautil\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abiosoft/"
},
{
"path": "environment/vm/lima/limautil/files.go",
"chars": 692,
"preview": "package limautil\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/config\"\n)\n\nconst colimaDiffDiskFile = \"diffdis"
},
{
"path": "environment/vm/lima/limautil/image.go",
"chars": 4716,
"preview": "package limautil\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/embedded\"\n\t\"git"
},
{
"path": "environment/vm/lima/limautil/instance.go",
"chars": 3937,
"preview": "package limautil\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\""
},
{
"path": "environment/vm/lima/limautil/limautil.go",
"chars": 668,
"preview": "package limautil\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft/colima/config\"\n)\n\n/"
},
{
"path": "environment/vm/lima/limautil/network.go",
"chars": 1598,
"preview": "package limautil\n\nimport (\n\t\"bytes\"\n\t\"net\"\n\t\"strings\"\n)\n\n// network interface for shared network in the virtual machine."
},
{
"path": "environment/vm/lima/limautil/ssh.go",
"chars": 1718,
"preview": "package limautil\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/conf"
},
{
"path": "environment/vm/lima/network.go",
"chars": 2671,
"preview": "package lima\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/abiosoft/"
},
{
"path": "environment/vm/lima/shell.go",
"chars": 1640,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/abiosoft/colima/config\"\n)\n\nfunc (l limaVM) Run(args ...string) err"
},
{
"path": "environment/vm/lima/yaml.go",
"chars": 13813,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/daemon\"\n\t\"github.com/abio"
},
{
"path": "environment/vm/lima/yaml_test.go",
"chars": 3531,
"preview": "package lima\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github"
},
{
"path": "environment/vm.go",
"chars": 1362,
"preview": "package environment\n\nimport (\n\t\"context\"\n\t\"runtime\"\n\n\t\"github.com/abiosoft/colima/util\"\n)\n\n// VM is virtual machine.\ntyp"
},
{
"path": "flake.nix",
"chars": 602,
"preview": "{\n description = \"Container runtimes on macOS (and Linux) with minimal setup\";\n\n # Last revision with go_1_23\n inputs"
},
{
"path": "go.mod",
"chars": 905,
"preview": "module github.com/abiosoft/colima\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/coreos/go-semver v0.3.1\n\tgithub.com/docker/go-units "
},
{
"path": "go.sum",
"chars": 5145,
"preview": "github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=\ngithub.com/chengxilo/virtualterm"
},
{
"path": "integration/Dockerfile",
"chars": 104,
"preview": "# sample dockerfile to test image building\n# without pulling from docker hub\nFROM scratch\n\nCOPY . /files"
},
{
"path": "model/docker.go",
"chars": 11267,
"preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/environment\"\n\t\"github.c"
},
{
"path": "model/ramalama.go",
"chars": 5439,
"preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/abiosoft/colima/environment"
},
{
"path": "model/runner.go",
"chars": 12908,
"preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/app\"\n\t\"github.com/abiosoft/coli"
},
{
"path": "model/runner_test.go",
"chars": 6320,
"preview": "package model\n\nimport (\n\t\"testing\"\n)\n\nfunc TestNormalizeModelName(t *testing.T) {\n\ttests := []struct {\n\t\tname string"
},
{
"path": "scripts/build_vmnet.sh",
"chars": 1634,
"preview": "#!/usr/bin/env sh\n\nset -ex\n\nexport DIR_BUILD=$PWD/_build/network\nexport DIR_VMNET=$DIR_BUILD/socket_vmnet\nexport EMBED_D"
},
{
"path": "scripts/integration.sh",
"chars": 1595,
"preview": "#!/usr/bin/env bash\n\nset -ex\n\nalias colima=\"$COLIMA_BINARY\"\nDOCKER_CONTEXT=\"$(docker info -f '{{json .}}' | jq -r '.Clie"
},
{
"path": "shell.nix",
"chars": 510,
"preview": "{ pkgs ? import <nixpkgs> { } }:\n\npkgs.mkShell {\n # nativeBuildInputs is usually what you want -- tools you need to run"
},
{
"path": "store/store.go",
"chars": 1784,
"preview": "package store\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"github.com/sirupsen/logrus"
},
{
"path": "util/debutil/debutil.go",
"chars": 1773,
"preview": "package debutil\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/cli\"\n\t\"github.com/abiosoft/colima/e"
},
{
"path": "util/downloader/curl.go",
"chars": 1584,
"preview": "package downloader\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/util/terminal\"\n)\n\n"
},
{
"path": "util/downloader/download.go",
"chars": 4188,
"preview": "package downloader\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/co"
},
{
"path": "util/downloader/errors.go",
"chars": 3283,
"preview": "package downloader\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"path\"\n\t\"syscall\"\n)\n\n// Sentinel errors for type checki"
},
{
"path": "util/downloader/http.go",
"chars": 8222,
"preview": "package downloader\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.co"
},
{
"path": "util/downloader/native.go",
"chars": 1632,
"preview": "package downloader\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"time\"\n)\n\n// nativeDownloader uses Go's n"
},
{
"path": "util/downloader/sha.go",
"chars": 3666,
"preview": "package downloader\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"fmt\"\n\t\"hash\"\n\t\"io\"\n\t\"os\"\n\t"
},
{
"path": "util/fsutil/fs.go",
"chars": 1292,
"preview": "package fsutil\n\nimport (\n\t\"io/fs\"\n\t\"os\"\n\t\"testing/fstest\"\n)\n\n// FS is the host filesystem implementation.\nvar FS FileSys"
},
{
"path": "util/macos.go",
"chars": 4093,
"preview": "package util\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github."
},
{
"path": "util/macos_test.go",
"chars": 1716,
"preview": "package util\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\ntype fakeDetector struct {\n\tv string\n\te error\n}\n\nfunc (f fakeDetector) GetCh"
},
{
"path": "util/osutil/os.go",
"chars": 2158,
"preview": "package osutil\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/sirupsen/logrus\"\n)"
},
{
"path": "util/qemu.go",
"chars": 550,
"preview": "package util\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n)\n\n// AssertQemuImg checks if qemu-img is available.\nfunc AssertQemuImg() error"
},
{
"path": "util/shautil/sha.go",
"chars": 637,
"preview": "package shautil\n\nimport (\n\t\"crypto/sha1\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n)\n\n// SHA is a sha computation\ntype SHA interface {\n\tSt"
},
{
"path": "util/template.go",
"chars": 743,
"preview": "package util\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"text/template\"\n)\n\n// WriteTemplate writes template with body to file afte"
},
{
"path": "util/terminal/output.go",
"chars": 3187,
"preview": "package terminal\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/fatih/color\"\n"
},
{
"path": "util/terminal/terminal.go",
"chars": 3222,
"preview": "package terminal\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\n\t\"golang.org/x/term\"\n)\n\nvar isTerminal = term.IsTermina"
},
{
"path": "util/util.go",
"chars": 3991,
"preview": "package util\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/google/shlex\"\n\t\"github.c"
},
{
"path": "util/yamlutil/yaml.go",
"chars": 4594,
"preview": "package yamlutil\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/abiosoft/colima/config\"\n"
},
{
"path": "util/yamlutil/yaml_test.go",
"chars": 1064,
"preview": "package yamlutil\n\nimport (\n\t\"net\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/abiosoft/colima/config\"\n\t\"gopkg.in/yaml.v3\"\n)\n\nfun"
}
]
About this extraction
This page contains the full source code of the abiosoft/colima GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 143 files (429.4 KB), approximately 126.5k tokens, and a symbol index with 790 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.