aboutsummaryrefslogtreecommitdiff
path: root/kvm-lab-create.bak
blob: 43d2926164ad1d50d5598ea87c090a1d08998149 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env bash
set -euo pipefail

URI="qemu:///system"

IMGROOT="/var/lib/libvirt/images"
BASEDIR="$IMGROOT/base"
LABDIR="$IMGROOT/lab"

TEMPLATE_DOMAIN="debian13-template"
TEMPLATE_BASE="$BASEDIR/debian13-template.qcow2"

usage() {
  echo "Usage: kvm-lab-create <lab-name> [--base template|work01|/abs/path.qcow2] [--start]"
  echo "Examples:"
  echo "  kvm-lab-create lab10 --base template --start"
  echo "  kvm-lab-create lab11 --base work01 --start"
  echo "  kvm-lab-create lab12 --base /var/lib/libvirt/images/base/custom.qcow2 --start"
}

# --- Parse args ---
NAME="${1:-}"
shift || true

BASESEL="template"
START="no"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --base)
      BASESEL="${2:-}"
      shift 2
      ;;
    --start)
      START="yes"
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "ERROR: Unknown argument: $1"
      usage
      exit 1
      ;;
  esac
done

if [[ -z "$NAME" ]]; then
  usage
  exit 1
fi

DISK="${LABDIR}/${NAME}.qcow2"
XML_TMP="$(mktemp "/tmp/${NAME}.xml.XXXXXX")"
cleanup() { rm -f "$XML_TMP"; }
trap cleanup EXIT

# --- Resolve base selection ---
resolve_base() {
  local sel="$1"
  if [[ "$sel" == "template" ]]; then
    echo "$TEMPLATE_BASE"
    return 0
  fi

  if [[ "$sel" == "work01" ]]; then
    # Pick newest promoted work01 base (must exist first)
    local latest
    latest="$(ls -1t "$BASEDIR"/work01-base-*.qcow2 2>/dev/null | head -n 1 || true)"
    if [[ -z "$latest" ]]; then
      echo "ERROR: No work01 base found in $BASEDIR (expected work01-base-*.qcow2)."
      echo "Action: run your promote script to create one."
      return 1
    fi
    echo "$latest"
    return 0
  fi

  # Absolute path base
  if [[ "$sel" == /* ]]; then
    echo "$sel"
    return 0
  fi

  echo "ERROR: Invalid --base '$sel' (use template|work01|/abs/path.qcow2)"
  return 1
}

BASE="$(resolve_base "$BASESEL")"

# --- Preconditions (read-only checks) ---
if [[ ! -d "$LABDIR" ]]; then
  echo "ERROR: Lab directory missing: $LABDIR"
  exit 1
fi

if ! sudo test -r "$BASE"; then
  echo "ERROR: Base image not readable (via sudo): $BASE"
  exit 1
fi

if [[ -e "$DISK" ]]; then
  echo "ERROR: Disk already exists: $DISK"
  exit 1
fi

if virsh -c "$URI" dominfo "$NAME" &>/dev/null; then
  echo "ERROR: Domain already exists: $NAME"
  exit 1
fi

if ! virsh -c "$URI" dominfo "$TEMPLATE_DOMAIN" &>/dev/null; then
  echo "ERROR: Template domain not found in $URI: $TEMPLATE_DOMAIN"
  exit 1
fi

# --- Create overlay disk ---
echo "Using base: $BASE"
echo "Creating overlay disk: $DISK"
sudo qemu-img create -f qcow2 -F qcow2 -b "$BASE" "$DISK" >/dev/null
sudo chown libvirt-qemu:libvirt "$DISK"
sudo chmod 0660 "$DISK"

echo "Validating backing file..."
sudo qemu-img info "$DISK" | grep -E "file format:|virtual size:|backing file:" || true

# --- Clone domain XML ---
echo "Cloning domain XML from: $TEMPLATE_DOMAIN"
virsh -c "$URI" dumpxml "$TEMPLATE_DOMAIN" > "$XML_TMP"

# Set name, disk path, and force NAT-only network "default"
sed -i \
  -e "s|<name>${TEMPLATE_DOMAIN}</name>|<name>${NAME}</name>|" \
  -e "s|${TEMPLATE_BASE}|${DISK}|g" \
  -e "s|<source network='[^']*'|<source network='default'|g" \
  "$XML_TMP"

# Remove UUID to avoid collision with template
sed -i -E '/<uuid>[^<]*<\/uuid>/d' "$XML_TMP"

# Remove any host filesystem passthrough (if present)
perl -0777 -i -pe 's/<filesystem[\s\S]*?<\/filesystem>\n?//g' "$XML_TMP"

# --- Define domain ---
echo "Defining domain: $NAME"
virsh -c "$URI" define "$XML_TMP" >/dev/null

# --- Optional start ---
if [[ "$START" == "yes" ]]; then
  echo "Starting domain: $NAME"
  virsh -c "$URI" start "$NAME" >/dev/null
fi

echo "OK: Lab '$NAME' created (disk: $DISK)."
if [[ "$START" != "yes" ]]; then
  echo "To start: virsh -c $URI start $NAME"
fi