README & other things
This commit is contained in:
parent
eddf850c4f
commit
c207a8a038
|
|
@ -0,0 +1,107 @@
|
|||
# lxcd
|
||||
|
||||
A Distrobox-like wrapper for LXD: it creates, manages, and enters LXD dev
|
||||
containers as drop-in development environments, mapped to your host workspace
|
||||
and home.
|
||||
|
||||
## Requirements
|
||||
|
||||
- LXD (`lxc`) reachable on your host — either the user is in the `lxd`
|
||||
group (invoked directly) or `sudo lxc` is used
|
||||
- Python 3.9+
|
||||
- Bash completion (optional): `lxcd.completion`
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
make install # copies lxcd.py to /usr/local/bin/lxcd + installs completion
|
||||
```
|
||||
|
||||
Or run in place from this directory:
|
||||
|
||||
```sh
|
||||
./lxcd.py --help
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
lxcd init # write ~/.lxcdrc (never shown; edit with -e)
|
||||
lxcd init -e # open the config in $EDITOR, created first if missing
|
||||
|
||||
lxcd create web1 # new container "web1" (defaults from ~/.lxcdrc)
|
||||
lxcd ls # alias for "list"
|
||||
lxcd enter web1 # cloud-init workspaces + mappings auto-applied
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
| --- | --- |
|
||||
| `init` | Write/edit the `~/.lxcdrc` config |
|
||||
| `create` | Create a new container (defaults from config) |
|
||||
| `clone <src> <name>` | Clone an existing managed container |
|
||||
| `rename\|mv <old> <new>` | Rename a container |
|
||||
| `enter <name>` | Enter a container (applies workspace + mappings) |
|
||||
| `list\|ls` | List managed containers |
|
||||
| `delete\|stop\|start\|restart` | Operate on containers (`-a` for all) |
|
||||
|
||||
Run `lxcd <command> --help` for full options.
|
||||
|
||||
## Config (`~/.lxcdrc`)
|
||||
|
||||
INI format. Keys:
|
||||
|
||||
- `[options]` — `workspace`, `image`, `nested`, `aptcache`, `ssh`
|
||||
(absolute paths OK for `workspace`/`image` when used as-is)
|
||||
- `[packages]` — default apt packages installed at create time
|
||||
- `[mappings]` under `[options]` or top-level — a list of host paths to
|
||||
mount into every container. A spec ending in `/` mounts a directory;
|
||||
an absolute host path (starting with `/`) is used **as-is** (not relative to
|
||||
`~`) and mounts at the same path in the container.
|
||||
|
||||
Example:
|
||||
|
||||
```ini
|
||||
[options]
|
||||
workspace=/home/andrew/Code # absolute — mounted as-is
|
||||
image=ubuntu:
|
||||
nested=true
|
||||
aptcache=http://10.0.0.1:3142
|
||||
ssh=ssh-ed25519 AAAA...andrew@host
|
||||
|
||||
[packages]
|
||||
git
|
||||
vim
|
||||
|
||||
[mappings]
|
||||
configs/ # directory: ~/configs -> /home/<user>/configs/
|
||||
notes # file: ~/notes -> /home/<user>/notes
|
||||
/etc/hosts # absolute: used as-is
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- Containers are tagged with `user.lxcd=true` for listing.
|
||||
- `security.nesting` is enabled when `nested=true` (cli `-n/--nested`).
|
||||
- Disk mounts use `shift=true` so container writes map cleanly to the host.
|
||||
- `enter` mounts the `[options] workspace=` host dir into the container and
|
||||
applies `[mappings]` before running an interactive shell as the host user.
|
||||
|
||||
## Completion
|
||||
|
||||
`lxcd.completion` (bash). Keep it sourced for container-name + option
|
||||
completion, including `lxcd list --brief [cols]`.
|
||||
|
||||
## Building a snap
|
||||
|
||||
```sh
|
||||
snapcraft --destructive-mode -v
|
||||
```
|
||||
|
||||
produces `lxcd_0.1.0_amd64.snap` (version pinned in `snap/snapcraft.yaml`).
|
||||
|
||||
## License
|
||||
|
||||
MIT.
|
||||
</content>
|
||||
|
|
@ -66,6 +66,14 @@ _lxcd_completion() {
|
|||
fi
|
||||
;;
|
||||
|
||||
list|ls)
|
||||
if [[ "$cur" == -* ]]; then
|
||||
COMPREPLY=($(compgen -W "-b --brief" -- "$cur"))
|
||||
else
|
||||
COMPREPLY=($(compgen -W "ipv4 status,ipv4 image,ipv4 packages,ipv4 opts image,packages,opts ipv4,image,packages" -- "$cur"))
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
|
|
|
|||
13
lxcd.py
13
lxcd.py
|
|
@ -433,12 +433,17 @@ def apply_mappings(name, host_username, host_home):
|
|||
paths = cfg.get("mappings")
|
||||
if not isinstance(paths, list) or not paths:
|
||||
return
|
||||
for idx, path in enumerate(paths):
|
||||
host_path = host_home / path
|
||||
container_path = f"/home/{host_username}/{path}"
|
||||
for idx, spec in enumerate(paths):
|
||||
is_dir = spec.endswith("/")
|
||||
if spec.startswith("/"):
|
||||
host_path = spec.rstrip("/")
|
||||
container_path = spec
|
||||
else:
|
||||
host_path = str(host_home / spec.rstrip("/"))
|
||||
container_path = f"/home/{host_username}/{spec}"
|
||||
lxc_subprocess(["config", "device", "remove", name, f"map-{idx}"],
|
||||
capture_output=True, text=True, check=False)
|
||||
if host_path.exists():
|
||||
if os.path.exists(host_path):
|
||||
lxc_run(["config", "device", "add", name, f"map-{idx}", "disk",
|
||||
f"source={host_path}",
|
||||
f"path={container_path}",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name: lxcd
|
||||
base: core22
|
||||
version: git
|
||||
version: 0.1.0
|
||||
summary: A Distrobox-like wrapper for LXD
|
||||
description: |
|
||||
lxcd provides a Distrobox-like experience using LXD containers.
|
||||
|
|
|
|||
Loading…
Reference in New Issue