This workflow corresponds to n8n.io template #10302 — we link there as the canonical source.
This workflow follows the Executecommand → Readwritefile recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "gxs56vcXTIHjKDlf",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automated Kubernetes Testing with Robot Framework, ArgoCD & Complete KinD Lifecycle",
"tags": [],
"nodes": [
{
"id": "3eedbba8-b070-4f4c-b752-f997880ac0f7",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-352,
480
],
"parameters": {},
"typeVersion": 1
},
{
"id": "606d3f93-213c-46ca-aa68-fcd50a42f0ca",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-352,
336
],
"parameters": {
"path": "gitlab-commit",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "4095dc2e-75df-4f26-8ff6-c2c20691706e",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-352,
192
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 1
}
]
}
},
"typeVersion": 1.2
},
{
"id": "caab1bc5-d6dc-4634-bf40-08f893075842",
"name": "Get a file - ROBOT Script",
"type": "n8n-nodes-base.gitlab",
"position": [
560,
352
],
"parameters": {
"owner": "n8n",
"filePath": "={{ $('Set Parameters').item.json.ROBOT_SCRIPT }}",
"resource": "file",
"operation": "get",
"repository": "testing",
"authentication": "oAuth2",
"binaryPropertyName": "process_it.robot",
"additionalParameters": {
"reference": "main"
}
},
"credentials": {
"gitlabOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "3b88f0a7-f384-4ad2-bdd4-0aefce909042",
"name": "Set Parameters",
"type": "n8n-nodes-base.set",
"position": [
0,
336
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0339db45-ae7f-461c-b89c-bb5c31b47178",
"name": "target_host",
"type": "string",
"value": "target_host_ip"
},
{
"id": "a98775c9-d110-4e77-a17e-bdec61c543f2",
"name": "target_port",
"type": "string",
"value": "target_host_ssh_port"
},
{
"id": "42debc80-9b3e-4b05-ad5e-4a8f4f6f1655",
"name": "target_user",
"type": "string",
"value": "target_host_username"
},
{
"id": "afeb1cba-cea7-455c-a519-e158628e524e",
"name": "target_password",
"type": "string",
"value": "target_host_password"
},
{
"id": "b220bff0-46de-430e-b7c3-3014151d1aff",
"name": "progress",
"type": "string",
"value": "INIT"
},
{
"id": "f4e0a984-d39a-4092-95ba-fd64884de843",
"name": "progress_only",
"type": "string",
"value": "false"
},
{
"id": "717c7fba-515e-4b47-9862-ee83a6c4d4e8",
"name": "KIND_CONFIG",
"type": "string",
"value": "config.yaml"
},
{
"id": "4dd919fe-b9ea-4c2d-bfba-0e458fa54c38",
"name": "ROBOT_SCRIPT",
"type": "string",
"value": "test.robot"
},
{
"id": "ed490c1b-92a9-472a-a5bb-188c094309c9",
"name": "ARGOCD_APPSET",
"type": "string",
"value": "demo-applicationSet.yaml"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "07caf13e-4f09-43aa-b253-52236dfab04c",
"name": "Robot Framework",
"type": "n8n-nodes-robotframework.robotFramework",
"position": [
1696,
352
],
"parameters": {
"robotScript": "={{ $json.stdout }}",
"includeLogHtml": true
},
"typeVersion": 1
},
{
"id": "4e7e8d45-f5e2-430d-aa91-bf33b8779465",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
288
],
"parameters": {
"color": 2,
"width": 2096,
"height": 432,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Testing KinD and deployment with Robot Framework"
},
"typeVersion": 1
},
{
"id": "2e5c6a83-4da1-4370-912e-c61e811338ec",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
208,
320
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "init",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "05d26e07-8a5f-4cc1-8d7e-4235631d4299",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.progress }}",
"rightValue": "INIT"
}
]
},
"renameOutput": true
},
{
"outputKey": "test",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2d3905d1-0182-4426-9e40-260c02453c40",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.progress }}",
"rightValue": "TEST"
}
]
},
"renameOutput": true
},
{
"outputKey": "destroy",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "17cfb80d-7424-4abb-a19a-fd29bf5b4be8",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.progress }}",
"rightValue": "DESTROY"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "c9903a44-5877-49cd-969c-d7e8a1591d17",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
-720
],
"parameters": {
"color": 5,
"width": 2096,
"height": 800,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Install Docker in Target and init KinD Custer with the testable deployment"
},
"typeVersion": 1
},
{
"id": "976bedbe-55d3-4f40-b270-994bb1625ebc",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
896
],
"parameters": {
"color": 3,
"width": 2096,
"height": 624,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Destroy KinD Cluster with the tested deployment and uninstall Docker in Target"
},
"typeVersion": 1
},
{
"id": "a44d76ec-8070-46e0-8ea0-aa64cde68850",
"name": "Set Initialized",
"type": "n8n-nodes-base.set",
"position": [
2432,
-160
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b220bff0-46de-430e-b7c3-3014151d1aff",
"name": "progress",
"type": "string",
"value": "TEST"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ec172786-0c6d-42a1-b1b3-4dc613bf2b7c",
"name": "Set Tested",
"type": "n8n-nodes-base.set",
"position": [
2432,
480
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b220bff0-46de-430e-b7c3-3014151d1aff",
"name": "progress",
"type": "string",
"value": "DESTROY"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "d3259144-6d39-4a56-be29-907386a2563b",
"name": "Set Destroyed",
"type": "n8n-nodes-base.set",
"position": [
2192,
1312
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b220bff0-46de-430e-b7c3-3014151d1aff",
"name": "progress",
"type": "string",
"value": "CLEAR"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cd48e173-0ed3-4f65-9cdf-35e713aa2414",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1680,
144
],
"parameters": {
"color": 7,
"width": 304,
"height": 176,
"content": "## Important! \nIf you are using a script in Robot Framework that works in a browser, then in the **\"New Browser\"** line you must specify the **\"executablePath=/usr/bin/chromium-browser\"** parameter"
},
"typeVersion": 1
},
{
"id": "edeabedf-e0be-477f-886b-1a54904bd4bf",
"name": "Write Dowloaded ROBOT Script",
"type": "n8n-nodes-base.readWriteFile",
"position": [
768,
352
],
"parameters": {
"options": {},
"fileName": "/tmp/process_it.robot",
"operation": "write",
"dataPropertyName": "process_it.robot"
},
"typeVersion": 1
},
{
"id": "232d3d9b-ceb6-445e-8de2-1c55ad418e4f",
"name": "Add Robot Framework, Browser Library, Chromium Driver",
"type": "n8n-nodes-base.executeCommand",
"position": [
976,
352
],
"parameters": {
"command": "=apk update\n\napk add --no-cache python3 py3-pip gcc musl-dev python3-dev libffi-dev openssl-dev cargo make nodejs npm\n\napk add --no-cache chromium chromium-chromedriver harfbuzz nss freetype ttf-freefont font-noto-emoji wqy-zenhei glib gobject-introspection at-spi2-core cups-libs libxcomposite libxdamage libxext libxfixes libxrandr libxrender libxtst pango cairo dbus-libs mesa-gl mesa-dri-gallium\n\npip3 install --break-system-packages --root-user-action=ignore robotframework\n\npip3 install --break-system-packages --root-user-action=ignore robotframework-seleniumlibrary robotframework-browser robotframework-requests robotframework-sshlibrary robotframework-databaselibrary\n\nrfbrowser init\n\npython3 -m Browser.entry init chromium\n\nexport PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright\nexport CHROMIUM_FLAGS=\"--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage\"\n"
},
"typeVersion": 1
},
{
"id": "7bdbe27a-bb4d-4445-9f98-9885331cee27",
"name": "Read ROBOT Script to Execute",
"type": "n8n-nodes-base.readWriteFile",
"position": [
1328,
352
],
"parameters": {
"options": {
"fileName": "={{ $('Write Dowloaded ROBOT Script').item.json.fileName }}",
"dataPropertyName": "process_it.robot"
},
"fileSelector": "={{ $('Write Dowloaded ROBOT Script').item.json.fileName }}"
},
"typeVersion": 1
},
{
"id": "a394d031-70b4-4267-a068-b21bae80726d",
"name": "Pack ROBOT Script Exports",
"type": "n8n-nodes-base.executeCommand",
"position": [
1872,
352
],
"parameters": {
"command": "=cd /tmp\npacking=$(tar -czvf testing-export-pack.tar.gz /root/n8n_robot_logs)\ncleaning=$(rm -rf /root/n8n_robot_logs)\necho \"/tmp/testing-export-pack.tar.gz\""
},
"typeVersion": 1
},
{
"id": "da6a48e3-5fb1-48ee-bd78-b023ff21f995",
"name": "Read ROBOT Script Exports to Send",
"type": "n8n-nodes-base.readWriteFile",
"position": [
2048,
352
],
"parameters": {
"options": {
"fileName": "={{ $json.stdout }}",
"dataPropertyName": "testing-export-pack.tar.gz"
},
"fileSelector": "={{ $json.stdout }}"
},
"typeVersion": 1
},
{
"id": "bb5d31e3-3183-4f17-aa6b-331c5944eab9",
"name": "Send ROBOT Script Export Pack",
"type": "n8n-nodes-base.telegram",
"position": [
2224,
352
],
"parameters": {
"chatId": "123456789",
"operation": "sendDocument",
"binaryData": true,
"additionalFields": {},
"binaryPropertyName": "=testing-export-pack.tar.gz"
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "9806fc1e-1d94-4208-b41a-5c22ea802746",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1680,
528
],
"parameters": {
"color": 7,
"width": 384,
"height": 112,
"content": "## Important! \nTo \u200b\u200buse this workflow, you MUST INSTALL the **n8n-nodes-robotframework** node in the **Community Nodes** section!"
},
"typeVersion": 1
},
{
"id": "3cc7cd5c-96bc-4534-86af-bb46311b120b",
"name": "Check Sshpass Exist Local",
"type": "n8n-nodes-base.executeCommand",
"position": [
544,
-688
],
"parameters": {
"command": "which sshpass"
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "33907525-976e-48e3-92e6-4b94fc41e05e",
"name": "Is Installed Local?",
"type": "n8n-nodes-base.if",
"position": [
736,
-688
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.exitCode }}",
"operation": "smallerEqual"
}
],
"string": [
{
"value1": "={{ $json.error }}",
"value2": "sshpass",
"operation": "notContains"
}
]
}
},
"typeVersion": 1
},
{
"id": "5a8750e9-fd35-4128-9fab-0e3abd75d274",
"name": "Install Sshpass Local",
"type": "n8n-nodes-base.executeCommand",
"position": [
992,
-640
],
"parameters": {
"command": "=if command -v apt-get &> /dev/null; then\n apt-get update && apt-get install -y sshpass rsync\nelif command -v yum &> /dev/null; then\n yum install -y epel-release && yum install -y sshpass rsync\nelif command -v dnf &> /dev/null; then\n dnf install -y sshpass rsync\nelif command -v apk &> /dev/null; then\n apk add sshpass rsync\nelse\n echo \"Unsupported package manager\"\n exit 1\nfi"
},
"typeVersion": 1
},
{
"id": "09350879-6eae-42af-94f3-f5735dd83473",
"name": "Check Docker on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
1216,
-688
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"which docker\""
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "9bbc3483-90f4-47dd-9934-8c8db45188e3",
"name": "Is Docker Installed on Target?",
"type": "n8n-nodes-base.if",
"position": [
1440,
-688
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.exitCode }}",
"operation": "smallerEqual"
}
],
"string": [
{
"value1": "={{ $json.error }}",
"value2": "docker",
"operation": "notContains"
}
]
}
},
"typeVersion": 1
},
{
"id": "d7967b95-3295-4972-9de1-ee3d7d353d6c",
"name": "Install Docker on Target",
"type": "n8n-nodes-base.executeCommand",
"onError": "continueRegularOutput",
"position": [
1648,
-624
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -f /etc/apt/sources.list.d/docker.list && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -f /etc/apt/keyrings/docker.gpg && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get update && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get autoremove -y && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get autoclean\"\n\nsshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"if command -v apt-get &> /dev/null; then . /etc/os-release && if [ \\\"\\$ID\\\" = \\\"ubuntu\\\" ]; then DOCKER_REPO=\\\"ubuntu\\\"; else DOCKER_REPO=\\\"debian\\\"; fi && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get update && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get install -y ca-certificates curl gnupg && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S install -m 0755 -d /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/\\$DOCKER_REPO/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S chmod a+r /etc/apt/keyrings/docker.gpg && echo \\\"deb [arch=\\$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/\\$DOCKER_REPO \\$VERSION_CODENAME stable\\\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get update && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl start docker && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl enable docker; elif command -v yum &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum install -y yum-utils && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl start docker && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl enable docker; elif command -v dnf &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf -y install dnf-plugins-core && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl start docker && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl enable docker; elif command -v apk &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apk add --no-cache docker docker-cli docker-compose && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rc-update add docker boot && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S service docker start; else echo 'Unsupported package manager'; exit 1; fi\""
},
"typeVersion": 1
},
{
"id": "cfd28b6f-3cfa-4f64-a572-334a7ea27625",
"name": "Install KinD on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
2304,
-592
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"if command -v apt-get &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get update && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get install -y curl && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64 && chmod +x ./kind && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S mv ./kind /usr/local/bin/kind; elif command -v yum &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum install -y curl && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64 && chmod +x ./kind && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S mv ./kind /usr/local/bin/kind; elif command -v dnf &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf install -y curl && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64 && chmod +x ./kind && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S mv ./kind /usr/local/bin/kind; elif command -v apk &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apk add --no-cache curl && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64 && chmod +x ./kind && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S mv ./kind /usr/local/bin/kind; else echo 'Unsupported package manager'; exit 1; fi\""
},
"typeVersion": 1
},
{
"id": "cca6856b-6e6f-414d-83ba-3de47ab7afdc",
"name": "Is KinD Installed on Target?",
"type": "n8n-nodes-base.if",
"position": [
2080,
-688
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.exitCode }}",
"operation": "smallerEqual"
}
],
"string": [
{
"value1": "={{ $json.error }}",
"value2": "kind",
"operation": "notContains"
}
]
}
},
"typeVersion": 1
},
{
"id": "f2c9d96f-e5f7-4b0f-815e-26ca8ec76718",
"name": "Check KinD on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
1856,
-688
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"which kind\""
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "6afe2a50-53dc-4647-910a-e7cbac67037e",
"name": "Get a file - KinD Config",
"type": "n8n-nodes-base.gitlab",
"position": [
560,
-368
],
"parameters": {
"owner": "n8n",
"filePath": "={{ $('Set Parameters').item.json.KIND_CONFIG }}",
"resource": "file",
"operation": "get",
"repository": "testing",
"authentication": "oAuth2",
"binaryPropertyName": "config.yaml",
"additionalParameters": {
"reference": "main"
}
},
"credentials": {
"gitlabOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "0b205c63-1bea-4602-b6b6-a0d22c52a012",
"name": "Write Dowloaded KinD Config",
"type": "n8n-nodes-base.readWriteFile",
"position": [
784,
-368
],
"parameters": {
"options": {},
"fileName": "/tmp/config.yaml",
"operation": "write",
"dataPropertyName": "config.yaml"
},
"typeVersion": 1
},
{
"id": "767099dd-8b50-4b29-bc1d-a35456c3ff32",
"name": "Open KinD Config",
"type": "n8n-nodes-base.executeCommand",
"position": [
992,
-368
],
"parameters": {
"command": "=cat {{ $json.fileName }}"
},
"typeVersion": 1
},
{
"id": "99091217-262f-4589-b0f4-38ae2ac74026",
"name": "Create KinD Cluster on Target",
"type": "n8n-nodes-base.executeCommand",
"onError": "continueRegularOutput",
"position": [
1200,
-368
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"cat > /tmp/config.yaml << 'EOF'\n{{ $json.stdout }}\nEOF\nkind create cluster --name automate-tst --config /tmp/config.yaml\""
},
"typeVersion": 1
},
{
"id": "96cbb13c-ff1e-4a07-90c3-71dfb619ff87",
"name": "Is Docker Installed on Target?1",
"type": "n8n-nodes-base.if",
"position": [
784,
1296
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.exitCode }}",
"operation": "smallerEqual"
}
],
"string": [
{
"value1": "={{ $json.error }}",
"value2": "docker",
"operation": "notContains"
}
]
}
},
"typeVersion": 1
},
{
"id": "a2224dd5-6460-4064-9b35-a0fb3c87ecc3",
"name": "Is KinD Installed on Target?1",
"type": "n8n-nodes-base.if",
"position": [
1888,
928
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.exitCode }}",
"operation": "smallerEqual"
}
],
"string": [
{
"value1": "={{ $json.error }}",
"value2": "kind",
"operation": "notContains"
}
]
}
},
"typeVersion": 1
},
{
"id": "c8244168-25ad-4704-b1df-863e4a9c7f4c",
"name": "Check Sshpass Exist Local (D)",
"type": "n8n-nodes-base.executeCommand",
"position": [
576,
928
],
"parameters": {
"command": "which sshpass"
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "917cbbc3-4900-4914-87ee-ec5691fe5c3e",
"name": "Is Installed Local? (D)",
"type": "n8n-nodes-base.if",
"position": [
768,
928
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.exitCode }}",
"operation": "smallerEqual"
}
]
}
},
"typeVersion": 1
},
{
"id": "33ec5f41-f4df-42d4-a6db-a1515d43b6a3",
"name": "Install Sshpass Local (D)",
"type": "n8n-nodes-base.executeCommand",
"position": [
1008,
976
],
"parameters": {
"command": "=if command -v apt-get &> /dev/null; then\n apt-get update && apt-get install -y sshpass rsync\nelif command -v yum &> /dev/null; then\n yum install -y epel-release && yum install -y sshpass rsync\nelif command -v dnf &> /dev/null; then\n dnf install -y sshpass rsync\nelif command -v apk &> /dev/null; then\n apk add sshpass rsync\nelse\n echo \"Unsupported package manager\"\n exit 1\nfi"
},
"typeVersion": 1
},
{
"id": "e7dc7914-8352-4060-844b-daa561b01aea",
"name": "Check Docker on Target (D)",
"type": "n8n-nodes-base.executeCommand",
"position": [
576,
1296
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"which docker\""
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "465c84d3-b0ba-45df-999a-2c29fca75ede",
"name": "Delete KinD Cluster on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
1440,
912
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"kind delete cluster --name automate-tst\""
},
"typeVersion": 1
},
{
"id": "83511d71-310c-4be4-8765-a9cd40859807",
"name": "Check KinD on Target (D)",
"type": "n8n-nodes-base.executeCommand",
"position": [
1664,
928
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"which kind\""
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "ae9ecbe9-58b7-4080-8496-f5c4763c24e1",
"name": "UnInstall KinD on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
2128,
976
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -rf /usr/local/bin/kind\""
},
"typeVersion": 1
},
{
"id": "502870b0-31ba-4bb6-b7ea-87d7d0846249",
"name": "UnInstall Docker on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
992,
1200
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"if command -v apt-get &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -f /etc/apt/sources.list.d/docker.list && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -f /etc/apt/keyrings/docker.gpg && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get update && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get autoremove -y && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get autoclean; elif command -v yum &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl stop docker 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl disable docker 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 2>/dev/null || true; elif command -v dnf &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl stop docker 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl disable docker 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 2>/dev/null || true; elif command -v apk &> /dev/null; then echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S service docker stop 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rc-update del docker boot 2>/dev/null || true && echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apk del docker docker-cli docker-compose 2>/dev/null || true; else echo 'Unsupported package manager'; exit 1; fi && rm -rf $(which docker)\""
},
"typeVersion": 1
},
{
"id": "b8079542-34e2-4fae-87aa-04539df7066c",
"name": "Process Finish Report --- Telegam & SMS1",
"type": "n8n-nodes-base.executeCommand",
"onError": "continueRegularOutput",
"position": [
2416,
1312
],
"parameters": {
"command": "=apk add curl\n\nexport TOKEN=\"6395628144:AAGYh1d9ZohaK14Tymw7n-5lA6LSC9e3oEo\"\nexport CHAT_ID=\"-1234567890123\"\nexport MESSAGE=\"Automate KinD Build and Application Test Ended! Testing Resource Pack Sent!\"\n\ncurl -s -X POST \"https://api.telegram.org/bot$TOKEN/sendMessage\" -d chat_id=\"$CHAT_ID\" -d text=\"$MESSAGE\"\n\nNUMBERS=\"+36301234567\"\n\nfor PHONE in $NUMBERS; do\n # curl -X POST https://textbelt.com/text --data-urlencode phone=\"$PHONE\" --data-urlencode message=\"$MESSAGE\" -d key=YOUR-TEXTBELT-API-KEY\ndone"
},
"typeVersion": 1
},
{
"id": "ac243f29-13f8-4e18-84b7-f3f53a6f6704",
"name": "Install Helm and Nginx-Ingress in KinD Cluster",
"type": "n8n-nodes-base.executeCommand",
"position": [
1424,
-368
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\n\ndocker exec -i automate-tst-control-plane bash << 'DOCKEREOF'\n\ncurl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 > gethelmfile\n\nchmod +x ./gethelmfile\n\nwhile ! command -v helm &> /dev/null; do\n timeout 10s bash -c './gethelmfile'\n sleep 5\ndone\n\nhelm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx\nhelm repo update\n\nhelm install ingress-nginx ingress-nginx/ingress-nginx \\\n --namespace ingress-nginx \\\n --create-namespace \\\n --set controller.service.type=NodePort \\\n --set controller.service.nodePorts.http=30080 \\\n --set controller.service.nodePorts.https=30443 \\\n --wait \\\n --timeout 5m\n\nkubectl get pods -n ingress-nginx\nkubectl get svc -n ingress-nginx\n\nDOCKEREOF\n\""
},
"typeVersion": 1
},
{
"id": "fe9eac0d-749f-4553-89e3-2f831d020761",
"name": "Install HAProxy on Target and Config Port-80 to KinD",
"type": "n8n-nodes-base.executeCommand",
"position": [
1648,
-368
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\n\nif command -v apt-get &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get update\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get install -y haproxy\nelif command -v yum &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum install -y haproxy\nelif command -v dnf &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf install -y haproxy\nelif command -v apk &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apk add --no-cache haproxy\nelse\n echo 'Unsupported package manager'\n exit 1\nfi\n\n\necho '{{ $('Set Parameters').item.json.target_password }}' | sudo -S tee /etc/haproxy/haproxy.cfg > /dev/null << 'EOF'\nglobal\n log /dev/log local0\n log /dev/log local1 notice\n chroot /var/lib/haproxy\n stats socket /run/haproxy/admin.sock mode 660 level admin\n stats timeout 30s\n user haproxy\n group haproxy\n daemon\n\ndefaults\n log global\n mode http\n option httplog\n option dontlognull\n timeout connect 5000\n timeout client 50000\n timeout server 50000\n\nfrontend http_front\n bind *:80\n mode tcp\n default_backend http_back\n\nbackend http_back\n mode tcp\n server kind_ingress 127.0.0.1:60080 check\nEOF\n\n\nif command -v systemctl &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl restart haproxy\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl enable haproxy\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl status haproxy\nelif command -v service &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S service haproxy restart\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rc-update add haproxy default 2>/dev/null || true\nfi\n\"\n\nsshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\n\nif ! grep -qE '^127\\.0\\.0\\.1[[:space:]]+autotest\\.innersite([[:space:]]|$)' /etc/hosts; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S sh -c 'echo \\\"\\\" >> /etc/hosts && echo \\\"127.0.0.1 autotest.innersite\\\" >> /etc/hosts'\n echo 'Host entry added: 127.0.0.1 autotest.innersite'\nelse\n echo 'Host entry already exists: 127.0.0.1 autotest.innersite'\nfi\n\necho '---'\necho 'Current /etc/hosts content:'\ngrep -E '^127\\.0\\.0\\.1' /etc/hosts\n\""
},
"typeVersion": 1
},
{
"id": "19bd956a-395d-4210-9d9d-e4980311403b",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"position": [
2432,
112
],
"parameters": {},
"typeVersion": 1
},
{
"id": "6c314b47-9578-4564-8a9c-d208dbe2a6a0",
"name": "Is INIT Only?",
"type": "n8n-nodes-base.if",
"position": [
2224,
-160
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $('Set Parameters').item.json.progress_only }}",
"value2": "false"
}
]
}
},
"typeVersion": 1
},
{
"id": "9f10a302-78e6-4fc1-9e9e-1d07acd71f98",
"name": "Is TEST Only?",
"type": "n8n-nodes-base.if",
"position": [
2432,
336
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $('Set Parameters').item.json.progress_only }}",
"value2": "false"
}
]
}
},
"typeVersion": 1
},
{
"id": "38397b70-ff06-4295-bf96-ffdc6db9cf26",
"name": "Delete HAProxy on Target",
"type": "n8n-nodes-base.executeCommand",
"position": [
1216,
912
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\n\nif command -v apt-get &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl stop haproxy 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl disable haproxy 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get remove -y haproxy\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get purge -y haproxy\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apt-get autoremove -y\nelif command -v yum &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl stop haproxy 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl disable haproxy 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S yum remove -y haproxy\nelif command -v dnf &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl stop haproxy 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S systemctl disable haproxy 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S dnf remove -y haproxy\nelif command -v apk &> /dev/null; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S service haproxy stop 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rc-update del haproxy default 2>/dev/null || true\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S apk del haproxy\nelse\n echo 'Unsupported package manager'\n exit 1\nfi\n\n\necho '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -rf /etc/haproxy 2>/dev/null || true\necho '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -rf /var/lib/haproxy 2>/dev/null || true\necho '{{ $('Set Parameters').item.json.target_password }}' | sudo -S rm -rf /run/haproxy 2>/dev/null || true\n\necho 'HAProxy successfully removed'\n\"\n\nsshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\n\nif grep -qE '^127\\.0\\.0\\.1[[:space:]]+autotest\\.innersite([[:space:]]|$)' /etc/hosts; then\n echo '{{ $('Set Parameters').item.json.target_password }}' | sudo -S sed -i '/^127\\.0\\.0\\.1[[:space:]]\\+autotest\\.innersite\\([[:space:]]\\|$\\)/d' /etc/hosts\n echo 'Host entry removed: 127.0.0.1 autotest.innersite'\nelse\n echo 'Host entry not found: 127.0.0.1 autotest.innersite'\nfi\n\necho '{{ $('Set Parameters').item.json.target_password }}' | sudo -S sed -i -e :a -e '/^\\n*$/{$d;N;ba' -e '}' /etc/hosts\n\necho '---'\necho 'Current /etc/hosts content:'\ngrep -E '^127\\.0\\.0\\.1' /etc/hosts || echo 'No 127.0.0.1 entries found'\n\""
},
"typeVersion": 1
},
{
"id": "3d976844-91c3-41c9-9d0a-1c9e8521fa8c",
"name": "Open ROBOT Script to Framework",
"type": "n8n-nodes-base.executeCommand",
"position": [
1520,
352
],
"parameters": {
"command": "=cat {{ $json.fileName }}"
},
"typeVersion": 1
},
{
"id": "fcc0449e-fe7f-4788-a37e-263a2fb30f9e",
"name": "Add Target to Hosts",
"type": "n8n-nodes-base.executeCommand",
"position": [
1152,
352
],
"parameters": {
"command": "=TARGET_IP='{{ $('Set Parameters').item.json.target_host }}'\n\nif ! grep -qE \"^${TARGET_IP}[[:space:]]+autotest\\.innersite([[:space:]]|$)\" /etc/hosts; then\n echo \"\" | tee -a /etc/hosts > /dev/null\n echo \"${TARGET_IP} autotest.innersite\" | tee -a /etc/hosts > /dev/null\n echo \"Host entry added: ${TARGET_IP} autotest.innersite\"\nelse\n echo \"Host entry already exists: ${TARGET_IP} autotest.innersite\"\nfi\n\necho '---'\necho 'Current /etc/hosts relevant entries:'\ngrep -E 'autotest\\.innersite' /etc/hosts || echo 'No autotest.innersite entries found'"
},
"typeVersion": 1
},
{
"id": "fbcd1a7d-1ada-41a7-95ae-9f019e89ce77",
"name": "Remove Target from Hosts",
"type": "n8n-nodes-base.executeCommand",
"position": [
1312,
1312
],
"parameters": {
"command": "=TARGET_IP='{{ $('Set Parameters').item.json.target_host }}'\n\nif grep -qE \"^${TARGET_IP}[[:space:]]+autotest\\.innersite([[:space:]]|$)\" /etc/hosts; then\n sed -i \"/^${TARGET_IP}[[:space:]]\\+autotest\\.innersite\\([[:space:]]\\|$\\)/d\" /etc/hosts\n echo \"Host entry removed: ${TARGET_IP} autotest.innersite\"\nelse\n echo \"Host entry not found: ${TARGET_IP} autotest.innersite\"\nfi\n\nsed -i -e :a -e '/^\\n*$/{$d;N;ba' -e '}' /etc/hosts\n\necho '---'\necho 'Current /etc/hosts content:'\ngrep -E \"^${TARGET_IP}\" /etc/hosts || echo \"No ${TARGET_IP} entries found\""
},
"typeVersion": 1
},
{
"id": "3885b7b3-5528-4407-9934-ecd24e95c24f",
"name": "Install ArgoCD to KinD Cluster",
"type": "n8n-nodes-base.executeCommand",
"position": [
1856,
-368
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\ndocker exec -i automate-tst-control-plane bash << 'DOCKEREOF'\n\nhelm repo add argo https://argoproj.github.io/argo-helm\nhelm repo update\n\nhelm install argocd argo/argo-cd \\\n --namespace argocd \\\n --create-namespace \\\n --set server.insecure=true \\\n --set server.extraArgs[0]=--insecure \\\n --set configs.params.server\\\\.insecure=true \\\n --set configs.cm.url=http://autotest.innersite \\\n --set server.service.type=ClusterIP \\\n --wait \\\n --timeout 10m\n\nkubectl wait --for=condition=ready pod -l app.kubernetes.io/name=argocd-server -n argocd --timeout=300s\n\nkubectl apply -f - << 'INGRESSEOF'\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: argocd-server-ingress\n namespace: argocd\n annotations:\n nginx.ingress.kubernetes.io/force-ssl-redirect: \\\"false\\\"\n nginx.ingress.kubernetes.io/ssl-redirect: \\\"false\\\"\n nginx.ingress.kubernetes.io/backend-protocol: \\\"HTTP\\\"\nspec:\n ingressClassName: nginx\n rules:\n - host: autotest.innersite\n http:\n paths:\n - path: /\n pathType: Prefix\n backend:\n service:\n name: argocd-server\n port:\n number: 80\nINGRESSEOF\n\nif ! command -v htpasswd &> /dev/null; then\n apt-get update && apt-get install -y apache2-utils\nfi\n\nkubectl -n argocd rollout restart deployment argocd-server\nkubectl -n argocd rollout status deployment argocd-server --timeout=300s\n\nDOCKEREOF\n\"\n\n\nsshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\ndocker exec -i automate-tst-control-plane bash << 'ADDUSEROFF'\n\nUSERNAME='autotest'\nPASSWORD='autotest'\nROLE='admin'\nNAMESPACE='argocd'\nMTIME='2025-09-25T10:00:00Z'\n\nPASSWORD_HASH=\\`htpasswd -bnBC 10 '' \\\"\\$PASSWORD\\\" | tr -d ':\\\\n' | sed 's/\\$2y/\\$2a/'\\`\nPASSWORD_B64=\\`echo -n \\\"\\$PASSWORD_HASH\\\" | base64 -w0\\`\nMTIME_B64=\\`echo -n \\\"\\$MTIME\\\" | base64 -w0\\`\n\nkubectl patch secret argocd-secret -n \\$NAMESPACE --type=json -p='[\n {\\\"op\\\":\\\"add\\\",\\\"path\\\":\\\"/data/accounts.'\\$USERNAME'.password\\\",\\\"value\\\":\\\"'\\$PASSWORD_B64'\\\"},\n {\\\"op\\\":\\\"add\\\",\\\"path\\\":\\\"/data/accounts.'\\$USERNAME'.passwordMtime\\\",\\\"value\\\":\\\"'\\$MTIME_B64'\\\"}\n]'\n\nkubectl patch configmap argocd-cm -n \\$NAMESPACE --type=merge -p='{\\\"data\\\":{\\\"accounts.'\\$USERNAME'\\\":\\\"login\\\"}}'\n\nkubectl patch configmap argocd-rbac-cm -n \\$NAMESPACE --type=merge -p='{\\\"data\\\":{\\\"policy.csv\\\":\\\"g, '\\$USERNAME', role:'\\$ROLE'\\\"}}'\n\necho \\\"---\\\"\necho \\\"ArgoCD Pods:\\\"\nkubectl get pods -n argocd\n\necho \\\"---\\\"\necho \\\"ArgoCD Services:\\\"\nkubectl get svc -n argocd\n\necho \\\"---\\\"\necho \\\"ArgoCD Ingress:\\\"\nkubectl get ingress -n argocd\n\necho \\\"---\\\"\necho \\\"ArgoCD available at: http://autotest.innersite\\\"\necho \\\"Username: \\$USERNAME\\\"\necho \\\"Password: \\$PASSWORD\\\"\n\nADDUSEROFF\n\""
},
"typeVersion": 1
},
{
"id": "5b139746-1c91-431c-b293-2586d8adbbe8",
"name": "Get a file - ArgoCD ApplicationSet",
"type": "n8n-nodes-base.gitlab",
"position": [
560,
-160
],
"parameters": {
"owner": "n8n",
"filePath": "={{ $('Set Parameters').item.json.ARGOCD_APPSET }}",
"resource": "file",
"operation": "get",
"repository": "testing",
"authentication": "oAuth2",
"binaryPropertyName": "demo-applicationSet.yaml",
"additionalParameters": {
"reference": "main"
}
},
"credentials": {
"gitlabOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "42e32eaf-f604-400b-8511-a6e4682d318e",
"name": "Write Dowloaded ArgoCD ApplicationSet",
"type": "n8n-nodes-base.readWriteFile",
"position": [
784,
-160
],
"parameters": {
"options": {},
"fileName": "/tmp/demo-applicationSet.yaml",
"operation": "write",
"dataPropertyName": "demo-applicationSet.yaml"
},
"typeVersion": 1
},
{
"id": "b8a4e1c5-bb96-4efe-b70e-c7dfd7d83821",
"name": "Open ArgoCD ApplicationSet",
"type": "n8n-nodes-base.executeCommand",
"position": [
992,
-160
],
"parameters": {
"command": "=cat {{ $json.fileName }}"
},
"typeVersion": 1
},
{
"id": "1c585a8c-1a89-4f38-8ac2-c54f0d1926b9",
"name": "Apply ArgoCD ApplicationSet",
"type": "n8n-nodes-base.executeCommand",
"position": [
1200,
-160
],
"parameters": {
"command": "=sshpass -p '{{ $('Set Parameters').item.json.target_password }}' ssh -o StrictHostKeyChecking=no -p {{ $('Set Parameters').item.json.target_port }} {{ $('Set Parameters').item.json.target_user }}@{{ $('Set Parameters').item.json.target_host }} \"\ndocker exec -i automate-tst-control-plane bash << 'APPLYEOF'\nkubectl apply -n argocd -f - << 'YAMLEOF'\n{{ $json.stdout }}\nYAMLEOF\n\nkubectl get applicationsets -n argocd\nAPPLYEOF\n\""
},
"typeVersion": 1
},
{
"id": "3f49e20c-b627-4066-828e-7a2f15a4e4ab",
"name": "Workflow Overview Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
-880,
16
],
"parameters": {
"color": 7,
"width": 450,
"height": 344,
"content": "## Workflow Overview\n\nThis workflow automates the complete lifecycle of Kubernetes testing:\n\nINIT Phase: Sets up Docker, KinD cluster, Helm, Ingress, HAProxy, and ArgoCD on a remote host\n\nTEST Phase: Runs automated Robot Framework tests with browser automation and sends results via Telegram\n\nDESTROY Phase: Cleans up all infrastructure and removes installed components\n\nThe workflow can run the full pipeline automatically or execute individual phases for debugging."
},
"typeVersion": 1
},
{
"id": "9d2efdf4-fee9-4950-874a-629c4104ccfd",
"name": "Trigger Configuration Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
-880,
416
],
"parameters": {
"color": 7,
"width": 448,
"height": 328,
"content": "## Trigger Configuration\n\nThis workflow supports three trigger methods:\n\nManual Trigger: Click to execute on-demand for testing and debugging\n\nWebhook: Integrate with GitLab CI/CD for automated execution on commits\n\nSchedule: Run automatically at specified times (default: daily at 1 AM)\n\nConfigure the Schedule Trigger to adjust execution frequency."
},
"typeVersion": 1
},
{
"id": "a24a6219-9704-4cfe-bb25-da4146997c16",
"name": "Configuration Guide Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
-144,
512
],
"parameters": {
"color": 7,
"width": 380,
"height": 360,
"content": "## Required Configuration\n\nUpdate these parameters before running:\n\ntarget_host: IP address of your remote server\ntarget_port: SSH port (usually 22)\ntarget_user: SSH username\ntarget_password: SSH password (consider using credentials)\n\nprogress: Starting phase (INIT/TEST/DESTROY)\nprogress_only: false for full pipeline, true for single phase\n\nKIND_CONFIG: Path to KinD config in GitLab\nROBOT_SCRIPT: Path to test script in GitLab\nARGOCD_APPSET: Path to ApplicationSet in GitLab"
},
"typeVersion": 1
},
{
"id": "51a455f4-c8b3-4bcc-88b9-c29127f61b94",
"name": "GitLab Setup Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
16,
-464
],
"parameters": {
"color": 7,
"width": 450,
"height": 276,
"content": "## GitLab Integration\n\nThese nodes download configuration files from your GitLab repository:\n\nconfig.yaml: KinD cluster configuration\ntest.robot: Robot Framework test script\ndemo-applicationSet.yaml: ArgoCD applications to deploy\n\nConfigure GitLab OAuth2 credentials in each GitLab node.\nUpdate the owner, repository, and branch settings to match your GitLab setup."
},
"typeVersion": 1
},
{
"id": "7fe8456d-8a20-43bf-9a8d-aa087a7f5857",
"name": "Phase Control Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
-48
],
"parameters": {
"color": 7,
"width": 420,
"height": 348,
"content": "## Phase Control Logic\n\nThe Switch node routes execution based on the progress parameter:\n\nprogress = INIT: Starts infrastructure setup\nprogress = TEST: Runs tests (assumes infrastructure exists)\nprogress = DESTROY: Cleanup phase\n\nprogress_only controls continuation:\nfalse: Automatically progress to next phase (INIT \u2192 TEST \u2192 DESTROY)\ntrue: Stop after completing current phase\n\nUse progress_only = true for debugging individual phases."
},
"typeVersion": 1
},
{
"id": "18604e04-a554-40be-a167-fc7b4a7fb151",
"name": "Telegram Configuration Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
2080,
528
],
"parameters": {
"color": 7,
"width": 496,
"height": 332,
"content": "## Telegram Notification\n\nConfigure this node to receive test results:\n\n1. Update chatId with your Telegram chat ID\n2. Configure Telegram API credentials\n3. Results are sent as a compressed archive containing:\n - Test execution logs\n - HTML reports\n - Screenshots from browser tests\n\nTo find your chat ID:\n- Personal: Message your bot and check /getUpdates\n- Group: Add bot to group and check /getUpdates (negative number)"
},
"typeVersion": 1
},
{
"id": "3a9ca7b8-fd69-4953-b93b-dad70e982640",
"name": "INIT Phase Summary Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
2608,
-720
],
"parameters": {
"color": 5,
"width": 450,
"height": 332,
"content": "## INIT Phase Summary\n\nThis phase prepares the complete testing infrastructure:\n\n1. Installs sshpass for SSH automation\n2. Installs Docker on remote host\n3. Installs KinD (Kubernetes in Docker)\n4. Creates KinD cluster from downloaded config\n5. Installs Helm and Nginx Ingress Controller\n6. Installs HAProxy for port 80 proxying\n7. Deploys ArgoCD with HTTP access\n8. Applies ApplicationSet to deploy test applications\n\nDuration: 15-25 minutes"
},
"typeVersion": 1
},
{
"id": "32dd93fe-8243-4e28-b28f-6b0703806580",
"name": "TEST Phase Summary Sticky",
"type": "n8n-nodes-base.stickyNote",
"position": [
2608,
288
],
"parameters": {
"color": 2,
"width": 450,
"height": 312,
"content": "## TEST Phase Summary\n\nThis phase executes automated tests:\n\n1. Downloads Robot Framework test script from GitLab\n2. Installs Python, Robot Framework, and Browser library\n3. Installs Chromium browser for web testing\n4. Adds target host to /etc/hosts for DNS resolution\n5. Executes Robot Framework tests with browser automation\n6. Packages test results (logs, reports, screenshots)\n7. Sends results package via Telegram\n\nDuration: 5-10 minutes"
},
"typeVersion": 1
},
{
"id": "0fd0bfbe-12da-49e3-b512-f91eb19422bc",
"name": "DESTROY Phase Summary Sticky",
"type": "n8n-nodes-base
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gitlabOAuth2ApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
How this works
This workflow automatically provisions a temporary Kubernetes cluster with KinD, runs Robot Framework tests against your application, and tears down the environment once complete. It suits developers and platform teams who need reliable, repeatable validation of Kubernetes workloads without maintaining permanent test infrastructure. The key step is the Robot Framework node executing your test scripts after the cluster is ready and the application deployed via Argo CD.
Use it for pull-request validation or scheduled regression checks on Kubernetes changes; avoid it for production environments or when tests require persistent data stores. Variations include swapping the GitLab trigger for webhook events from other repositories or adding Telegram alerts for test failures.
About this workflow
This n8n workflow provides automated CI/CD testing for Kubernetes applications using KinD (Kubernetes in Docker). It creates temporary infrastructure, runs tests, and cleans up everything automatically. Installs dependencies (sshpass, Docker, KinD) Creates KinD cluster Installs…
Source: https://n8n.io/workflows/10302/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This automated n8n workflow delivers an instant DevOps toolkit by installing Docker, K3s, Jenkins, Grafana, and more on a Linux server within 10 seconds. It optimizes performance, enhances security, a
Code Github. Uses manualTrigger, stickyNote, httpRequest, noOp. Event-driven trigger; 24 nodes.
Triggers manually or on schedule (03:00 daily by default) Fetches workflows tagged via n8n API Normalizes workflow names and applies tag convention Prepares JSON in the same structure as an n8n UI exp
Gitlab Code. Uses manualTrigger, noOp, splitInBatches, gitlab. Event-driven trigger; 21 nodes.
This n8n workflow template uses community nodes and is only compatible with the self-hosted version of n8n.