Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/libvirt #125

Merged
merged 12 commits into from
Jan 8, 2025
26 changes: 17 additions & 9 deletions command-handler/src/commands/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,27 +92,27 @@ export default {
//delete the server
hetzner.deleteServer({ app, body, serverName });
} else if (actionId === 'button_start_libvirt') {
const { serverName } = JSON.parse(body.actions[0].value);
const { serverName, region } = JSON.parse(body.actions[0].value);

libvirt.startServer({ app, body, serverName });
libvirt.startServer({ app, body, serverName, region });
} else if (actionId === 'button_stop_libvirt') {
const { serverName } = JSON.parse(body.actions[0].value);
const { serverName, region } = JSON.parse(body.actions[0].value);

libvirt.stopServer({ app, body, serverName });
libvirt.stopServer({ app, body, serverName, region });
} else if (actionId === 'button_delete_libvirt') {
const { serverName } = JSON.parse(body.actions[0].value);
const { serverName, region } = JSON.parse(body.actions[0].value);

//delete the server
libvirt.deleteServer({ app, body, serverName });
libvirt.deleteServer({ app, body, serverName, region });
} else if (actionId.startsWith('button_create_image_aws')) {
const { imageName, ami, region, instanceType } = JSON.parse(body.actions[0].value);
aws.createServer({ app, body, imageName, ami, region, instanceType });
} else if (actionId.startsWith('button_create_image_hetzner')) {
const { imageID, imageName, region, serverType } = JSON.parse(body.actions[0].value);
hetzner.createServer({ app, body, imageID, imageName, region, serverType });
} else if (actionId.startsWith('button_create_image_libvirt')) {
const { imageName } = JSON.parse(body.actions[0].value);
libvirt.createServer({ app, body, imageName });
const { imageName, region, instanceType } = JSON.parse(body.actions[0].value);
libvirt.createServer({ app, body, imageName, region, instanceType });
} else if (actionId === 'button_create_vm_hetzner') {
//select the hetzner server to create before calling the create server
hetzner.selectRegion({ app, body });
Expand All @@ -121,7 +121,7 @@ export default {
aws.selectRegion({ app, body });
} else if (actionId === 'button_create_vm_libvirt') {
//select the libvirt image to create before calling the create server
libvirt.selectImage({ app, body });
libvirt.selectRegion({ app, body });
} else if (actionId.startsWith('button_select_hetzner_server')) {
const data = JSON.parse(body.actions[0].value);
//select the hetzner server to create before calling the create server
Expand All @@ -130,6 +130,10 @@ export default {
const data = JSON.parse(body.actions[0].value);
//select the asw server to create before calling the create server
aws.selectServer({ app, body, data });
} else if (actionId.startsWith('button_select_libvirt_server')) {
const data = JSON.parse(body.actions[0].value);
//select the libvirt server type to create before calling the create server
libvirt.selectServer({ app, body, data });
} else if (actionId.startsWith('button_select_hetzner_image')) {
const data = JSON.parse(body.actions[0].value);
//select the hetzner server to create before calling the create server
Expand All @@ -138,6 +142,10 @@ export default {
const data = JSON.parse(body.actions[0].value);
//select the asw server to create before calling the create server
aws.selectImage({ app, body, data });
} else if (actionId.startsWith('button_select_libvirt_image')) {
const data = JSON.parse(body.actions[0].value);
//select the hetzner server to create before calling the create server
libvirt.selectImage({ app, body, data });
} else {
response({
text: `This button is registered with the vm command, but does not have an action associated with it.`
Expand Down
106 changes: 79 additions & 27 deletions command-handler/src/util/libvirt/libvirt-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const delay = (ms) => {
}

export default {
createServer: async({ app, body, imageName }) => {
createServer: async({ app, body, imageName, region, instanceType }) => {
//auto generate the name
const serverName = uniqueNamesGenerator({
dictionaries: [ colors, animals ],
Expand Down Expand Up @@ -56,18 +56,18 @@ export default {
{
"vm_name": serverName,
"tags": {
"owner": {
"name": userEmail
}
"owner": userEmail,
},
"user_data": Buffer.from(configUserData(serverName)).toString('base64'),
"image": imageName
"image": imageName,
"region_name": region,
"instance_type": instanceType
}, {
headers: {
'Authorization': `${process.env.PROVISIONER_API_TOKEN}`,
'Content-Type': 'application/json'
},
timeout: 1000 * 60 * 2
timeout: 1000 * 60 * 5
});
} catch (error) {
log.error('There was an error creating the server', axiosError(error));
Expand All @@ -81,16 +81,6 @@ export default {
return;
}

if (serverRes.data !== 'Success') {
app.client.chat.postEphemeral({
channel: `${body.channel.id}`,
user: `${body.user.id}`,
text: `Failed to create a server.`
});

return;
}

let attempts;

let maxRetries = 13;
Expand Down Expand Up @@ -133,7 +123,7 @@ export default {
});
},

deleteServer: async ({ app, body, serverName }) => {
deleteServer: async ({ app, body, serverName, region }) => {
//get servers from tailscale
const { deviceId } = await getDevices(serverName)

Expand All @@ -151,7 +141,10 @@ export default {

try {
await axios.delete(`${process.env.PROVISIONER_URL}/v1/delete`, {
data: { "vm_name": serverName },
data: {
"vm_name": serverName,
"region_name": region
},
headers: {
'Authorization': `${process.env.PROVISIONER_API_TOKEN}`
}
Expand Down Expand Up @@ -194,7 +187,7 @@ export default {
log.error('Failed to get servers from libvirt', axiosError(error));
});

const data = response.data;
const data = response?.data;

if (!data) {
app.client.chat.postEphemeral({
Expand All @@ -208,7 +201,7 @@ export default {

for (const server of data) {

const owner = server.description.owner.name;
const owner = server.tags.owner;

const { deviceIP } = await getDevices(server.name);

Expand All @@ -217,6 +210,7 @@ export default {
servers.push({
cloud: "libvirt",
serverName: `${server.name}`,
region: `${server.region_name}`,
status: `${server.state}`,
connect: `https://login.tailscale.com/admin/machines/${deviceIP}`
});
Expand All @@ -226,10 +220,11 @@ export default {
return servers;
},

startServer: async({ app, body, serverName }) => {
startServer: async({ app, body, serverName, region }) => {
try {
await axios.post(`${process.env.PROVISIONER_URL}/v1/start`, {
"vm_name": serverName
"vm_name": serverName,
"region_name": region
}, {
headers: {
'Authorization': `${process.env.PROVISIONER_API_TOKEN}`
Expand All @@ -252,10 +247,11 @@ export default {
}
},

stopServer: async({ app, body, serverName }) => {
stopServer: async({ app, body, serverName, region }) => {
try {
await axios.post(`${process.env.PROVISIONER_URL}/v1/stop`, {
"vm_name": serverName
"vm_name": serverName,
"region_name": region
}, {
headers: {
'Authorization': `${process.env.PROVISIONER_API_TOKEN}`
Expand All @@ -278,7 +274,46 @@ export default {
}
},

selectImage: async({ app, body }) => {
selectRegion: async ({app, body }) => {
const buttonsArray = [];
//get the regions from the env variable
const response = await axios.get(`${process.env.PROVISIONER_URL}/v1/regions`, {
headers: {
'Authorization': `${process.env.PROVISIONER_API_TOKEN}`
},
timeout: 1000 * 60 * 5
})
.catch(error => {
log.error('Failed to get regions from libvirt', axiosError(error));
});

const regions = response?.data;

//return if it fails to get a response from libvirt.
if (!regions) {
app.client.chat.postEphemeral({
channel: `${body.channel.id}`,
user: `${body.user.id}`,
text: `Failed to get region data from libvirt`
});

return;
}

//build button for user to select
for (const region of regions) {
buttonsArray.push({ text: region.region_name, actionId: `button_select_libvirt_server${region.region_name}`, value: JSON.stringify({ region: region.region_name, instances: region.available_instance_types }) });
}
const buttons = buttonBuilder({ buttonsArray, headerText: 'Select a region', fallbackText: 'unsupported device' });
app.client.chat.postEphemeral({
channel: `${body.channel.id}`,
user: `${body.user.id}`,
text: 'select a region',
...buttons
});
},

selectImage: async({ app, body, data }) => {
//get the libvirt images

// Fetch tags from the repository
Expand Down Expand Up @@ -306,7 +341,8 @@ export default {

//build button for user to select
for (const image of images) {
buttonsArray.push({ text: image, actionId: `button_create_image_libvirt_${image}`, value: JSON.stringify({ imageName: image }) })
data.imageName = image;
buttonsArray.push({ text: image, actionId: `button_create_image_libvirt_${image}`, value: JSON.stringify(data) })
}

const buttons = buttonBuilder({ buttonsArray, headerText: 'Select an image', fallbackText: 'unsupported device' });
Expand All @@ -317,4 +353,20 @@ export default {
...buttons
});
},
};

selectServer: async ({app, body, data }) => {
const buttonsArray = [];

for (const serverType of data.instances) {
data.instanceType = serverType.instance_type;
buttonsArray.push({ text: serverType.instance_type, actionId: `button_select_libvirt_image_${serverType.instance_type}`, value: JSON.stringify(data) });
};
const buttons = buttonBuilder({ buttonsArray, headerText: 'Select a server', fallbackText: 'unsupported device' });
app.client.chat.postEphemeral({
channel: `${body.channel.id}`,
user: `${body.user.id}`,
text: 'select a server',
...buttons
});
}
};
Loading