feat/added check if dockerfile extists before deployment

This commit is contained in:
biersoeckli
2024-12-25 14:28:59 +00:00
parent 167ad63aa9
commit 77d094d26e
4 changed files with 154 additions and 61 deletions
+36 -30
View File
@@ -16,47 +16,53 @@ fi
k3sUrl="$1" k3sUrl="$1"
joinToken="$2" joinToken="$2"
wait_until_all_pods_running() {
# Waits another 5 seconds to make sure all pods are registered for the first time. select_network_interface() {
sleep 5 echo "Detecting network interfaces with IPv4 addresses..."
interfaces_with_ips=$(ip -o -4 addr show | awk '{print $2, $4}' | sort -u)
while true; do if [ $(echo "$interfaces_with_ips" | wc -l) -eq 1 ]; then
OUTPUT=$(sudo k3s kubectl get pods -A --no-headers 2>&1) # If only one interface is found, use it by default
selected_iface=$(echo "$interfaces_with_ips" | awk '{print $1}')
selected_ip=$(echo "$interfaces_with_ips" | awk '{print $2}')
echo "Only one network interface detected: $selected_iface ($selected_ip)"
else
echo ""
echo "*******************************************************************************************************"
echo ""
echo "Multiple network interfaces detected:"
echo "Please select the ip address wich is in the same network as the master node."
echo "If you havent configured a private network between the nodes, select the public ip address."
echo ""
options=()
while read -r iface ip; do
options+=("$iface ($ip)")
done <<< "$interfaces_with_ips"
# Checks if there are no resources found --> Kubernetes ist still starting up PS3="Please select the network interface to use: "
if echo "$OUTPUT" | grep -q "No resources found"; then select entry in "${options[@]}"; do
echo "Kubernetes is still starting up..." if [ -n "$entry" ]; then
else selected_iface=$(echo "$entry" | awk -F' ' '{print $1}')
# Extracts the STATUS column from the kubectl output and filters out the values "Running" and "Completed". selected_ip=$(echo "$entry" | awk -F'[()]' '{print $2}')
STATUS=$(echo "$OUTPUT" | awk '{print $4}' | grep -vE '^(Running|Completed)$') echo "Selected interface: $selected_iface ($selected_ip)"
break
# If the STATUS variable is empty, all pods are running and the loop can be exited.
if [ -z "$STATUS" ]; then
echo "Pods started successfully."
break
else else
echo "Waiting for all pods to come online..." echo "Invalid selection. Please try again."
fi fi
fi done
fi
# Waits for X seconds before checking the pod status again. echo "Using network interface: $selected_iface with IP address: $selected_ip"
sleep 10
done
# Waits another 5 seconds to make sure all pods are ready.
sleep 5
sudo kubectl get node
sudo kubectl get pods -A
} }
# install nfs-common
# install nfs-common and open-iscsi
sudo apt-get update sudo apt-get update
sudo apt-get install nfs-common -y sudo apt-get install open-iscsi nfs-common -y
# Installation of k3s # Installation of k3s
curl -sfL https://get.k3s.io | K3S_URL=${K3S_URL} K3S_TOKEN=${JOIN_TOKEN} sh - echo "Installing k3s with --flannel-iface=$selected_iface"
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--flannel-iface=$selected_iface" INSTALL_K3S_VERSION="v1.31.3+k3s1" K3S_URL=${K3S_URL} K3S_TOKEN=${JOIN_TOKEN} sh -
echo "" echo ""
echo "-----------------------------------------------------------------------------------------------------------" echo "-----------------------------------------------------------------------------------------------------------"
+61 -5
View File
@@ -2,6 +2,46 @@
# curl -sfL https://get.quickstack.dev/setup.sh | sh - # curl -sfL https://get.quickstack.dev/setup.sh | sh -
select_network_interface() {
echo "Detecting network interfaces with IPv4 addresses..."
interfaces_with_ips=$(ip -o -4 addr show | awk '{print $2, $4}' | sort -u)
if [ $(echo "$interfaces_with_ips" | wc -l) -eq 1 ]; then
# If only one interface is found, use it by default
selected_iface=$(echo "$interfaces_with_ips" | awk '{print $1}')
selected_ip=$(echo "$interfaces_with_ips" | awk '{print $2}')
echo "Only one network interface detected: $selected_iface ($selected_ip)"
else
echo ""
echo "*******************************************************************************************************"
echo ""
echo "Multiple network interfaces detected:"
echo "If you plan to use QuickStack in a cluster using multiple servers in multiple Networks (private/public),"
echo "choose the network Interface you want to use for the communication between the servers."
echo ""
echo "If you plan to use QuickStack in a single server setup, choose the network Interface with the public IP."
echo ""
options=()
while read -r iface ip; do
options+=("$iface ($ip)")
done <<< "$interfaces_with_ips"
PS3="Please select the network interface to use: "
select entry in "${options[@]}"; do
if [ -n "$entry" ]; then
selected_iface=$(echo "$entry" | awk -F' ' '{print $1}')
selected_ip=$(echo "$entry" | awk -F'[()]' '{print $2}')
echo "Selected interface: $selected_iface ($selected_ip)"
break
else
echo "Invalid selection. Please try again."
fi
done
fi
echo "Using network interface: $selected_iface with IP address: $selected_ip"
}
wait_until_all_pods_running() { wait_until_all_pods_running() {
# Waits another 5 seconds to make sure all pods are registered for the first time. # Waits another 5 seconds to make sure all pods are registered for the first time.
@@ -37,8 +77,19 @@ wait_until_all_pods_running() {
sudo kubectl get pods -A sudo kubectl get pods -A
} }
# Prompt for network interface
select_network_interface
# install nfs-common and open-iscsi
echo "Installing nfs-common..."
sudo apt-get update
sudo apt-get install open-iscsi nfs-common -y
# Installation of k3s # Installation of k3s
curl -sfL https://get.k3s.io | sh - #curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--node-ip=192.168.1.2 --advertise-address=192.168.1.2 --node-external-ip=188.245.236.232 --flannel-iface=enp7s0" INSTALL_K3S_VERSION="v1.31.3+k3s1" sh -
echo "Installing k3s with --flannel-iface=$selected_iface"
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--flannel-iface=$selected_iface" INSTALL_K3S_VERSION="v1.31.3+k3s1" sh -
# Todo: Check for Ready node, takes ~30 seconds # Todo: Check for Ready node, takes ~30 seconds
sudo k3s kubectl get node sudo k3s kubectl get node
@@ -46,16 +97,16 @@ echo "Waiting for Kubernetes to start..."
wait_until_all_pods_running wait_until_all_pods_running
# Installation of Longhorn # Installation of Longhorn
sudo kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.0/deploy/longhorn.yaml sudo kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml
echo "Waiting for Longhorn to start..." echo "Waiting for Longhorn to start..."
wait_until_all_pods_running wait_until_all_pods_running
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# THIS MUST BE INSTALLED ON ALL NODES --> https://longhorn.io/docs/1.7.2/deploy/install/#installing-nfsv4-client # THIS MUST BE INSTALLED ON ALL NODES --> https://longhorn.io/docs/1.7.2/deploy/install/#installing-nfsv4-client
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
echo "Installing nfs-common..."
sudo kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/prerequisite/longhorn-nfs-installation.yaml #sudo kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.0/deploy/prerequisite/longhorn-nfs-installation.yaml
wait_until_all_pods_running #wait_until_all_pods_running
# Installation of Cert-Manager # Installation of Cert-Manager
sudo kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml sudo kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml
@@ -63,6 +114,11 @@ echo "Waiting for Cert-Manager to start..."
wait_until_all_pods_running wait_until_all_pods_running
sudo kubectl -n cert-manager get pod sudo kubectl -n cert-manager get pod
# Checking installation of Longhorn
sudo apt-get install jq -y
sudo curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/scripts/environment_check.sh | bash
joinTokenForOtherNodes=$(sudo cat /var/lib/rancher/k3s/server/node-token) joinTokenForOtherNodes=$(sudo cat /var/lib/rancher/k3s/server/node-token)
# deploy QuickStack # deploy QuickStack
+4 -1
View File
@@ -32,7 +32,10 @@ class BuildService {
// Check if last build is already up to date with data in git repo // Check if last build is already up to date with data in git repo
const latestSuccessfulBuld = buildsForApp.find(x => x.status === 'SUCCEEDED'); const latestSuccessfulBuld = buildsForApp.find(x => x.status === 'SUCCEEDED');
const latestRemoteGitHash = await gitService.getLatestRemoteCommitHash(app); const latestRemoteGitHash = await gitService.openGitContext(app, async (ctx) => {
await ctx.checkIfDockerfileExists();
return await ctx.getLatestRemoteCommitHash();
});
dlog(deploymentId, `Cloned repository successfully`); dlog(deploymentId, `Cloned repository successfully`);
dlog(deploymentId, `Latest remote git hash: ${latestRemoteGitHash}`); dlog(deploymentId, `Latest remote git hash: ${latestRemoteGitHash}`);
+53 -25
View File
@@ -1,37 +1,38 @@
import { ServiceException } from "@/shared/model/service.exception.model"; import { ServiceException } from "@/shared/model/service.exception.model";
import { AppExtendedModel } from "@/shared/model/app-extended.model"; import { AppExtendedModel } from "@/shared/model/app-extended.model";
import simpleGit from "simple-git"; import simpleGit, { SimpleGit } from "simple-git";
import { PathUtils } from "../utils/path.utils"; import { PathUtils } from "../utils/path.utils";
import { FsUtils } from "../utils/fs.utils"; import { FsUtils } from "../utils/fs.utils";
import path from "path";
class GitService { class GitService {
async getLatestRemoteCommitHash(app: AppExtendedModel) { async openGitContext<T>(app: AppExtendedModel, action: (ctx: InternalGitService) => Promise<T>): Promise<T> {
try { try {
const git = await this.pullLatestChangesFromRepo(app); let git: SimpleGit | undefined = undefined;
let internalGitService: InternalGitService | undefined = undefined;
// Get the latest commit hash on the default branch (e.g., 'origin/main') try {
const log = await git.log(['origin/' + app.gitBranch]); // Replace 'main' with your branch name if needed git = await this.pullLatestChangesFromRepo(app);
internalGitService = new InternalGitService(git, app);
if (log.latest) { } catch (error) {
return log.latest.hash; console.error('Error while connecting to the git repository:', error);
} else { throw new ServiceException("Error while connecting to the git repository.");
throw new ServiceException("The git repository is empty.");
} }
return await action(internalGitService);
} catch (error) { } catch (error) {
console.error('Error while connecting to the git repository:', error); throw error;
throw new ServiceException("Error while connecting to the git repository.");
} finally { } finally {
await this.cleanupLocalGitDataForApp(app); await this.cleanupLocalGitDataForApp(app);
} }
} }
async cleanupLocalGitDataForApp(app: AppExtendedModel) { private async cleanupLocalGitDataForApp(app: AppExtendedModel) {
const gitPath = PathUtils.gitRootPathForApp(app.id); const gitPath = PathUtils.gitRootPathForApp(app.id);
await FsUtils.deleteDirIfExistsAsync(gitPath, true); await FsUtils.deleteDirIfExistsAsync(gitPath, true);
} }
async pullLatestChangesFromRepo(app: AppExtendedModel) { private async pullLatestChangesFromRepo(app: AppExtendedModel) {
console.log(`Pulling latest source for app ${app.id}...`); console.log(`Pulling latest source for app ${app.id}...`);
const gitPath = PathUtils.gitRootPathForApp(app.id); const gitPath = PathUtils.gitRootPathForApp(app.id);
@@ -49,9 +50,36 @@ class GitService {
return git; return git;
} }
private getGitUrl(app: AppExtendedModel) {
if (app.gitUsername && app.gitToken) {
return app.gitUrl!.replace('https://', `https://${app.gitUsername}:${app.gitToken}@`);
}
return app.gitUrl!;
}
}
async checkIfLocalRepoIsUpToDate(app: AppExtendedModel) { class InternalGitService {
const gitPath = PathUtils.gitRootPathForApp(app.id);
constructor(private readonly git: SimpleGit,
private readonly app: AppExtendedModel
) { }
async checkIfDockerfileExists() {
const gitPath = PathUtils.gitRootPathForApp(this.app.id);
const dockerFilePath = this.app.dockerfilePath;
if (!dockerFilePath) {
throw new ServiceException("Dockerfile path is not set.");
}
const absolutePath = path.join(gitPath, dockerFilePath);
console.log(`Checking if Dockerfile exists at ${absolutePath}`);
if (!await FsUtils.fileExists(absolutePath)) {
throw new ServiceException(`Dockerfile does not exists at ${dockerFilePath}`);
}
}
async checkIfLocalRepoIsUpToDate() {
const gitPath = PathUtils.gitRootPathForApp(this.app.id);
if (!FsUtils.directoryExists(gitPath)) { if (!FsUtils.directoryExists(gitPath)) {
return false; return false;
} }
@@ -60,10 +88,9 @@ class GitService {
return false; return false;
} }
const git = simpleGit(gitPath); await this.git.fetch();
await git.fetch();
const status = await git.status(); const status = await this.git.status();
if (status.behind > 0) { if (status.behind > 0) {
console.log(`The local repository is behind by ${status.behind} commits and needs to be updated.`); console.log(`The local repository is behind by ${status.behind} commits and needs to be updated.`);
return false; return false;
@@ -75,12 +102,13 @@ class GitService {
return true return true
} }
async getLatestRemoteCommitHash() {
private getGitUrl(app: AppExtendedModel) { const log = await this.git.log();
if (app.gitUsername && app.gitToken) { if (log.latest) {
return app.gitUrl!.replace('https://', `https://${app.gitUsername}:${app.gitToken}@`); return log.latest.hash;
} else {
throw new ServiceException("The git repository is empty.");
} }
return app.gitUrl!;
} }
} }