Skip to content
Draft
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ install: install-create-container install-pull-config
install-create-container:
cd create-a-container && npm install --production
cd create-a-container && npm run db:migrate
install -m644 -oroot -groot create-a-container/container-creator.service /etc/systemd/system/container-creator.service
install -m644 -oroot -groot create-a-container/systemd/container-creator.service /etc/systemd/system/container-creator.service
systemctl daemon-reload || true
systemctl enable container-creator.service
systemctl start container-creator.service || true
Expand Down
30 changes: 30 additions & 0 deletions create-a-container/bin/hookscript.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash
# /var/lib/vz/snippets/register_proxy_hook.sh

echo "GUEST HOOK: $*"

# First argument is the vmid
vmid="$1"

# Second argument is the phase
phase="$2"

case "$phase" in
'pre-start')
# shellcheck disable=SC2016
echo 'Setting AppArmor profile to `unconfined`'
conffile="/etc/pve/lxc/$vmid.conf"
if grep -qE '^lxc\.apparmor\.profile' "$conffile"; then
sed -i -E 's/^lxc\.apparmor\.profile: .*$/lxc.apparmor.profile: unconfined/' "$conffile"
else
echo 'lxc.apparmor.profile: unconfined' >>"$conffile"
fi
;;
'post-start') ;;
'pre-stop') ;;
'post-stop') ;;
*)
echo "got unknown phase '$phase'" >&2
exit 255
;;
esac
15 changes: 11 additions & 4 deletions create-a-container/routers/containers.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ router.post('/', async (req, res) => {
})
});
const vmid = await client.nextId();
const upid = await client.createLxc(node.name, {
const lxcData = {
ostemplate,
vmid,
cores: 4,
features: 'nesting=1', // allow nested containers
features: 'nesting=1,keyctl=1,fuse=1', // allow nested containers with Docker/Podman
hostname,
memory: 4096, // 4GB RAM
net0: 'name=eth0,ip=dhcp,bridge=vmbr0',
Expand All @@ -242,7 +242,14 @@ router.post('/', async (req, res) => {
start: 1, // start the container immediately after creation
tags: req.session.user,
unprivileged: 1
});
};
// check if the hookscript is available
const availableSnippets = await client.listStorageContent(node.name, 'local', 'snippets');
const hookscript = availableSnippets.find(s => s.volid === 'local:snippets/hookscript.sh')?.volid;
if (hookscript) {
lxcData.hookscript = hookscript;
}
const upid = await client.createLxc(node.name, lxcData);

// wait for the task to complete
while (true) {
Expand All @@ -267,7 +274,7 @@ router.post('/', async (req, res) => {
}
}
console.error('DNS lookup failed after maximum retries');
return null
return null;
})();

const container = await Container.create({
Expand Down
24 changes: 24 additions & 0 deletions create-a-container/utils/proxmox-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,30 @@ class ProxmoxApi {

return response.data;
}

/**
* List storage content
* @param {string} node - The cluster node name
* @param {string} storage - The storage identifier
* @param {string} [content] - Only list content of this type
* @param {number} [vmid] - Only list content for this VMID
* @returns {Promise<object[]>} - The storage content list
*/
async listStorageContent(node, storage, content = null, vmid = null) {
const params = {};
if (content) params.content = content;
if (vmid) params.vmid = vmid;

const response = await axios.get(
`${this.baseUrl}/api2/json/nodes/${node}/storage/${storage}/content`,
{
params,
...this.options
}
);

return response.data.data;
}
}

module.exports = ProxmoxApi;
Loading