Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions debian/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
VENDOR=Debian
NAME=Debian
IMAGE_FORMAT=qcow2
IMAGE_GLOB=*.qcow2

# match versions like:
# debian-bookworm-genericcloud.qcow2
VERSION=$(shell echo $(IMAGE) | sed -e 's/debian-\([a-z]\+\)-genericcloud.*/\1/')


-include ../makefile-sanity.include
-include ../makefile.include

download:
/bin/bash download.sh

build: download
$(MAKE) docker-image
21 changes: 21 additions & 0 deletions debian/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Debian VM

To download a compatible image of the Debian VM execute the [download.sh](download.sh) script that will download a cloud-init image of Debian from <https://cloud.debian.org/images/cloud>. The version is set in the script and can be changed manually.

Once the qcow2 image is downloaded, build the container with the following command:

```bash
make
```

The resulting container will be tagged as `vrnetlab/vr-debian:<version>`, e.g. `vrnetlab/vr-debian:bookworm`.

## Host requirements

* 1 vCPU, 512 MB RAM

## Configuration

Initial config is carried out via cloud-init.

* `9.9.9.9` configured as the DNS resolver. Change it with `resolvectl` if required.
33 changes: 33 additions & 0 deletions debian/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
FROM debian:bookworm-slim

ARG DEBIAN_FRONTEND=noninteractive
ARG DISK_SIZE=4G

Comment on lines +1 to +5
Copy link
Member

Choose a reason for hiding this comment

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

do you mind checking if you can substitute this Dockerfile with the new version we started to use:

FROM ghcr.io/srl-labs/vrnetlab-base:0.2.1

ARG VERSION
ENV VERSION=${VERSION}
ARG IMAGE
COPY $IMAGE* /
COPY *.py /4
COPY backup.sh /
COPY copy_etc_and_run_startupscript.sh /

Copy link
Author

Choose a reason for hiding this comment

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

Do you want me to replace the whole Dockerfile? Will it be possible to resize the disk within the clab yaml?

I assume that "4" after "COPY *.py /" is a mistake.

Copy link
Author

Choose a reason for hiding this comment

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

I replaced the Dockerfile with yours and got:

2025-03-11 17:24:20,571: vrnetlab   DEBUG    Creating overlay disk image
Traceback (most recent call last):
  File "/launch.py", line 250, in <module>
    vr = Debian(
         ^^^^^^^
  File "/launch.py", line 221, in __init__
    self.vms = [Debian_vm(hostname, username, password, nics, conn_mode)]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/launch.py", line 64, in __init__
    self.create_boot_image()
  File "/launch.py", line 114, in create_boot_image
    subprocess.Popen(cloud_localds_args)
  File "/root/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/python3.12/subprocess.py", line 1026, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/root/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/python3.12/subprocess.py", line 1955, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'cloud-localds'

Do I need a new launch.py as well?

Copy link
Member

Choose a reason for hiding this comment

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

I think you need to add another RUN command that installs cloud-utils

RUN apt-get update -qy \
   && apt-get install -y --no-install-recommends \
cloud-utils

Copy link
Author

Choose a reason for hiding this comment

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

If I only change the FROM statement to ghcr.io/srl-labs/vrnetlab-base:0.2.1, then it works. If you're happy with that, then I'll amend the pull request. Then the Dockerfile would look like this:

FROM ghcr.io/srl-labs/vrnetlab-base:0.2.1

ARG DISK_SIZE=4G

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qy \
   && apt-get install -y \
   bridge-utils \
   iproute2 \
   socat \
   qemu-kvm \
   tcpdump \
   ssh \
   inetutils-ping \
   dnsutils \
   iptables \
   nftables \
   telnet \
   cloud-utils \
   sshpass \
   && rm -rf /var/lib/apt/lists/*

ARG VERSION
ENV VERSION=${VERSION}
ARG IMAGE
COPY $IMAGE* /
COPY *.py /
COPY backup.sh /
COPY copy_etc_and_run_startupscript.sh /

RUN qemu-img resize /${IMAGE} ${DISK_SIZE}

EXPOSE 22 5000 10000-10099
HEALTHCHECK CMD ["/healthcheck.py"]
ENTRYPOINT ["/launch.py"]

Copy link
Member

Choose a reason for hiding this comment

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

no need to keep everything. I think this should be fine:

FROM ghcr.io/srl-labs/vrnetlab-base:0.2.1

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qy \
   && apt-get install -y --no-install-recommends \
   cloud-utils

ARG VERSION
ENV VERSION=${VERSION}
ARG IMAGE
COPY $IMAGE* /
COPY *.py /
COPY backup.sh /
COPY copy_etc_and_run_startupscript.sh /

RUN apt-get update -qy \
&& apt-get install -y \
bridge-utils \
iproute2 \
socat \
qemu-kvm \
tcpdump \
ssh \
inetutils-ping \
dnsutils \
iptables \
nftables \
telnet \
cloud-utils \
sshpass \
&& rm -rf /var/lib/apt/lists/*

ARG IMAGE
COPY $IMAGE* /
COPY *.py /
COPY backup.sh /
COPY copy_etc_and_run_startupscript.sh /

RUN qemu-img resize /${IMAGE} ${DISK_SIZE}

EXPOSE 22 5000 10000-10099
HEALTHCHECK CMD ["/healthcheck.py"]
ENTRYPOINT ["/launch.py"]
84 changes: 84 additions & 0 deletions debian/docker/backup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash

DEFAULT_USER="admin"
DEFAULT_PASSWORD="admin"
BACKUP_FILE="backup.tar.gz"
BACKUP_PATH=/config/$BACKUP_FILE
REMOTE_BACKUP_PATH=/tmp/$BACKUP_FILE

handle_args() {
# Parse options
while getopts 'u:p:' OPTION; do
case "$OPTION" in
u)
user="$OPTARG"
;;
p)
password="$OPTARG"
;;
?)
usage
exit 1
;;
esac
done
shift "$(($OPTIND -1))"

# Assign defaults if options weren't provided
if [ -z "$user" ] ; then
user=$DEFAULT_USER
fi
if [ -z "$password" ] ; then
password=$DEFAULT_PASSWORD
fi

SSH_CMD="sshpass -p $password ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p22"
SCP_CMD="sshpass -p $password scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P22"
HOST="$user@localhost"

# Parse commands
case $1 in

backup)
backup
;;

restore)
restore
;;

*)
usage
;;
esac
}

usage() {
echo "Usage: $(basename $0) [-u USERNAME] [-p PASSWORD] COMMAND"
echo "Options:"
echo " -u USERNAME VM SSH username (default: clab)"
echo " -p PASSWORD VM SSH password (default: clab@123)"
echo
echo "Commands:"
echo " backup Backup VM /etc directory to $BACKUP_PATH"
echo " restore Restore VM /etc directory from $BACKUP_PATH"
exit 0;
}

backup() {
echo "Backing up..."
$SSH_CMD $HOST "sudo tar zcf $REMOTE_BACKUP_PATH /etc > & /dev/null"
$SCP_CMD $HOST:$REMOTE_BACKUP_PATH $BACKUP_PATH
}

restore() {
if [ -f "$BACKUP_PATH" ]; then
echo "Restoring from backup..."
# Put backup file to VM, untar, and reboot.
$SCP_CMD $BACKUP_PATH $HOST:$REMOTE_BACKUP_PATH && $SSH_CMD $HOST "sudo tar xzf $REMOTE_BACKUP_PATH -C /" && $SSH_CMD $HOST "sudo shutdown -r now || true"
else
echo "$BACKUP_PATH not found. Nothing to restore."
fi
}

handle_args "$@"
89 changes: 89 additions & 0 deletions debian/docker/copy_etc_and_run_startupscript.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/bin/bash

DEFAULT_USER="admin"
DEFAULT_PASSWORD="admin"
DOCKER_ETC_PATH=/config/etc
REMOTE_TMP_PATH=/tmp/etc
# location of startup script in the docker container
STARTUPSCRIPT=/config/startup.sh

handle_args() {
# Parse options
while getopts 'u:p:' OPTION; do
case "$OPTION" in
u)
user="$OPTARG"
;;
p)
password="$OPTARG"
;;
?)
usage
exit 1
;;
esac
done
shift "$(($OPTIND -1))"

# Assign defaults if options weren't provided
if [ -z "$user" ] ; then
user=$DEFAULT_USER
fi
if [ -z "$password" ] ; then
password=$DEFAULT_PASSWORD
fi

SSH_CMD="sshpass -p $password ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p22"
SCP_CMD="sshpass -p $password scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P22"
HOST="$user@localhost"

# Parse commands
case $1 in

startupconfig)
startupconfig
;;

copyetc)
copyetc
;;

*)
usage
;;
esac
}

usage() {
echo "Usage: $(basename $0) [-u USERNAME] [-p PASSWORD] COMMAND"
echo "Options:"
echo " -u USERNAME VM SSH username (default: admin)"
echo " -p PASSWORD VM SSH password (default: admin)"
echo
echo "Commands:"
echo " startupconfig copy $STARTUPSCRIPT to vm and run it"
echo " copyetc copy $DOCKER_ETC_PATH to /etc on the vm"
exit 0;
}

startupconfig() {
if [ -f "$STARTUPSCRIPT" ]; then
echo "copy_etc_and_run_startupscript.sh startupconfig(): Copying $STARTUPSCRIPT to vm..."
# Put startupfile file to VM under ~/ (/home/clab for the debian image).
$SCP_CMD $STARTUPSCRIPT $HOST:startup.sh && $SSH_CMD $HOST "sudo chmod +x startup.sh && sudo ./startup.sh || true"
else
echo "copy_etc_and_run_startupscript.sh startupconfig(): $STARTUPSCRIPT not found. No startupscript to upload."
fi
}

copyetc() {
if [ -d "$DOCKER_ETC_PATH" ]; then
echo "copy_etc_and_run_startupscript.sh copyetc(): Copying $DOCKER_ETC_PATH to vm..."
# Copy /config/etc to /etc in the VM.
$SCP_CMD -r $DOCKER_ETC_PATH $HOST:$REMOTE_TMP_PATH && $SSH_CMD $HOST "sudo cp -r $REMOTE_TMP_PATH/* /etc" && $SSH_CMD $HOST "sudo shutdown -r now || true"
else
echo "copy_etc_and_run_startupscript.sh copyetc(): $DOCKER_ETC_PATH not found. Nothing to upload."
fi
}

handle_args "$@"
Loading