Created
March 22, 2025 00:17
-
-
Save jaredcat/c5b26e20bbae39c7707313ebd0f66b1c to your computer and use it in GitHub Desktop.
Poratiner Stack Migration Postman Collection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"info": { | |
"_postman_id": "17f859a5-038e-4dd0-9b38-428cc9201f06", | |
"name": "Portainer Stack Migration", | |
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", | |
"_exporter_id": "857619" | |
}, | |
"item": [ | |
{ | |
"name": "1. Get CSRF Token", | |
"event": [ | |
{ | |
"listen": "test", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"// Extract the CSRF token from the response cookies", | |
"var cookieJar = pm.cookies.get(\"X-CSRF-Token\");", | |
"", | |
"if (cookieJar) {", | |
" // Save the CSRF token to a variable", | |
" pm.collectionVariables.set(\"csrf_token\", cookieJar);", | |
" console.log(\"CSRF Token extracted: \" + cookieJar);", | |
" ", | |
" // Run the next request automatically", | |
" setTimeout(function() {", | |
" pm.test(\"Moving to authentication request\", function() {", | |
" postman.setNextRequest(\"2. Authenticate\");", | |
" });", | |
" }, 500);", | |
"} else {", | |
" // Check response headers for the token", | |
" var csrfToken = pm.response.headers.get(\"X-CSRF-Token\");", | |
" ", | |
" if (csrfToken) {", | |
" pm.collectionVariables.set(\"csrf_token\", csrfToken);", | |
" console.log(\"CSRF Token found in headers: \" + csrfToken);", | |
" ", | |
" // Run the next request automatically", | |
" setTimeout(function() {", | |
" pm.test(\"Moving to authentication request\", function() {", | |
" postman.setNextRequest(\"2. Authenticate\");", | |
" });", | |
" }, 500);", | |
" } else {", | |
" console.error(\"No CSRF token found in cookies or headers. Trying to extract from response body...\");", | |
" ", | |
" // Some Portainer versions might return the token in the response body", | |
" try {", | |
" var jsonData = JSON.parse(responseBody);", | |
" if (jsonData && jsonData.csrfToken) {", | |
" pm.collectionVariables.set(\"csrf_token\", jsonData.csrfToken);", | |
" console.log(\"CSRF Token found in response body: \" + jsonData.csrfToken);", | |
" ", | |
" // Run the next request automatically", | |
" setTimeout(function() {", | |
" pm.test(\"Moving to authentication request\", function() {", | |
" postman.setNextRequest(\"2. Authenticate\");", | |
" });", | |
" }, 500);", | |
" } else {", | |
" console.error(\"CSRF token not found in response body either.\");", | |
" console.log(\"Response body:\", responseBody);", | |
" }", | |
" } catch (e) {", | |
" console.error(\"Error parsing response or finding CSRF token: \" + e.message);", | |
" console.log(\"Raw response:\", responseBody);", | |
" }", | |
" }", | |
"}" | |
] | |
} | |
} | |
], | |
"request": { | |
"method": "GET", | |
"header": [], | |
"url": { | |
"raw": "{{ip_base}}/", | |
"host": [ | |
"{{ip_base}}" | |
], | |
"path": [ | |
"" | |
] | |
}, | |
"description": "Gets the CSRF token from Portainer" | |
}, | |
"response": [] | |
}, | |
{ | |
"name": "2. Authenticate", | |
"event": [ | |
{ | |
"listen": "test", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"try {", | |
" var jsonData = JSON.parse(responseBody);", | |
" ", | |
" // Check if we got a JWT token", | |
" if (jsonData.jwt) {", | |
" pm.collectionVariables.set(\"token\", jsonData.jwt);", | |
" console.log(\"JWT token saved to variable\");", | |
" ", | |
" // Run the next request automatically", | |
" setTimeout(function() {", | |
" pm.test(\"Moving to next request automatically\", function() {", | |
" postman.setNextRequest(\"3. Get All Stacks\");", | |
" });", | |
" }, 500);", | |
" } else {", | |
" console.error(\"No JWT token found in response\");", | |
" console.log(\"Response:\", responseBody);", | |
" }", | |
"} catch (e) {", | |
" console.error(\"Error parsing response: \" + e.message);", | |
" console.log(\"Raw response:\", responseBody);", | |
"}" | |
] | |
} | |
} | |
], | |
"request": { | |
"method": "POST", | |
"header": [ | |
{ | |
"key": "X-CSRF-Token", | |
"value": "{{csrf_token}}", | |
"type": "text" | |
} | |
], | |
"body": { | |
"mode": "raw", | |
"raw": "{\n \"password\": \"{{password}}\",\n \"username\": \"{{user}}\"\n}", | |
"options": { | |
"raw": { | |
"language": "json" | |
} | |
} | |
}, | |
"url": { | |
"raw": "{{ip}}/auth", | |
"host": [ | |
"{{ip}}" | |
], | |
"path": [ | |
"auth" | |
] | |
}, | |
"description": "Authenticates with Portainer using the CSRF token and stores the JWT token in the collection variable" | |
}, | |
"response": [] | |
}, | |
{ | |
"name": "3. Get All Stacks", | |
"event": [ | |
{ | |
"listen": "test", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"var jsonData = JSON.parse(responseBody);", | |
"", | |
"// Store all stack IDs in an environment variable as JSON array", | |
"var stackIds = [];", | |
"var stackData = {};", | |
"", | |
"jsonData.forEach(function(stack) {", | |
" // Only include Swarm stacks", | |
" if (stack.Type === 1) {", | |
" stackIds.push(stack.Id);", | |
" ", | |
" // Store each stack's data indexed by ID", | |
" stackData[stack.Id] = {", | |
" name: stack.Name,", | |
" endpointId: stack.EndpointId", | |
" };", | |
" }", | |
"});", | |
"", | |
"// Save to collection variables", | |
"pm.collectionVariables.set(\"stackIds\", JSON.stringify(stackIds));", | |
"pm.collectionVariables.set(\"stackData\", JSON.stringify(stackData));", | |
"", | |
"console.log(\"Found \" + stackIds.length + \" Swarm stacks to migrate\");", | |
"console.log(\"Stack IDs: \" + JSON.stringify(stackIds));", | |
"console.log(\"Stack Data: \" + JSON.stringify(stackData));", | |
"", | |
"// Run the next request automatically", | |
"setTimeout(function() {", | |
" pm.test(\"Moving to next request automatically\", function() {", | |
" postman.setNextRequest(\"4. Get Endpoints\");", | |
" });", | |
"}, 500);" | |
] | |
} | |
} | |
], | |
"request": { | |
"auth": { | |
"type": "bearer", | |
"bearer": [ | |
{ | |
"key": "token", | |
"value": "{{token}}", | |
"type": "string" | |
} | |
] | |
}, | |
"method": "GET", | |
"header": [ | |
{ | |
"key": "X-CSRF-Token", | |
"value": "{{csrf_token}}", | |
"type": "text" | |
} | |
], | |
"url": { | |
"raw": "{{ip}}/stacks", | |
"host": [ | |
"{{ip}}" | |
], | |
"path": [ | |
"stacks" | |
] | |
}, | |
"description": "Gets all stacks and stores their IDs to a collection variable for migration" | |
}, | |
"response": [] | |
}, | |
{ | |
"name": "4. Get Endpoints", | |
"event": [ | |
{ | |
"listen": "test", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"var jsonData = JSON.parse(responseBody);", | |
"", | |
"// Look for Docker Swarm endpoint (Type 2)", | |
"var swarmEndpoint = null;", | |
"", | |
"jsonData.forEach(function(endpoint) {", | |
" if (endpoint.Type === 2) {", | |
" // Take the first available Swarm endpoint", | |
" if (!swarmEndpoint) {", | |
" swarmEndpoint = endpoint;", | |
" }", | |
" }", | |
"});", | |
"", | |
"if (swarmEndpoint) {", | |
" pm.collectionVariables.set(\"newEndpointId\", swarmEndpoint.Id);", | |
" console.log(\"New Swarm Endpoint ID: \" + swarmEndpoint.Id);", | |
" ", | |
" // Run the next request automatically", | |
" setTimeout(function() {", | |
" pm.test(\"Moving to next request automatically\", function() {", | |
" postman.setNextRequest(\"5. Get Swarm Info\");", | |
" });", | |
" }, 500);", | |
"} else {", | |
" console.error(\"No Swarm endpoint found! Migration will fail.\");", | |
" postman.setNextRequest(null);", | |
"}" | |
] | |
} | |
} | |
], | |
"request": { | |
"auth": { | |
"type": "bearer", | |
"bearer": [ | |
{ | |
"key": "token", | |
"value": "{{token}}", | |
"type": "string" | |
} | |
] | |
}, | |
"method": "GET", | |
"header": [ | |
{ | |
"key": "X-CSRF-Token", | |
"value": "{{csrf_token}}", | |
"type": "text" | |
} | |
], | |
"url": { | |
"raw": "{{ip}}/endpoints", | |
"host": [ | |
"{{ip}}" | |
], | |
"path": [ | |
"endpoints" | |
] | |
}, | |
"description": "Gets all endpoints to find the new Swarm endpoint ID" | |
}, | |
"response": [] | |
}, | |
{ | |
"name": "5. Get Swarm Info", | |
"event": [ | |
{ | |
"listen": "test", | |
"script": { | |
"exec": [ | |
"try {", | |
" var jsonData = JSON.parse(responseBody);", | |
" ", | |
" // Extract the Swarm ID from the response", | |
" if (jsonData && jsonData.Swarm?.Cluster?.ID) {", | |
" pm.collectionVariables.set(\"newSwarmId\", jsonData.Swarm.Cluster.ID);", | |
" console.log(\"New Swarm ID: \" + jsonData.Swarm.Cluster.ID);", | |
" ", | |
" // Set up for the first stack migration", | |
" var stackIds = JSON.parse(pm.collectionVariables.get(\"stackIds\"));", | |
" var stackData = JSON.parse(pm.collectionVariables.get(\"stackData\"));", | |
" ", | |
" if (stackIds && stackIds.length > 0) {", | |
" // Get the first stack ID", | |
" var currentStackId = stackIds[0];", | |
" pm.collectionVariables.set(\"currentStackId\", currentStackId);", | |
" ", | |
" // Get the first stack name", | |
" var currentStackName = stackData[currentStackId].name;", | |
" pm.collectionVariables.set(\"currentStackName\", currentStackName);", | |
" ", | |
" console.log(\"Set up first stack migration:\");", | |
" console.log(\"- Current Stack ID: \" + currentStackId);", | |
" console.log(\"- Current Stack Name: \" + currentStackName);", | |
" ", | |
" // Remove the first stack from the list", | |
" stackIds.shift();", | |
" pm.collectionVariables.set(\"stackIds\", JSON.stringify(stackIds));", | |
" ", | |
" // Run the migrate stack request next", | |
" setTimeout(function() {", | |
" pm.test(\"Starting stack migration process\", function() {", | |
" postman.setNextRequest(\"6. Migrate Stack\");", | |
" });", | |
" }, 500);", | |
" } else {", | |
" console.log(\"No stacks to migrate\");", | |
" postman.setNextRequest(null);", | |
" }", | |
" } else {", | |
" console.error(\"Could not find Swarm ID in response!\");", | |
" console.log(\"Raw response:\", responseBody);", | |
" postman.setNextRequest(null);", | |
" }", | |
"} catch (e) {", | |
" console.error(\"Error parsing response: \" + e.message);", | |
" console.log(\"Raw response:\", responseBody);", | |
" postman.setNextRequest(null);", | |
"}" | |
], | |
"type": "text/javascript", | |
"packages": {} | |
} | |
} | |
], | |
"request": { | |
"auth": { | |
"type": "bearer", | |
"bearer": [ | |
{ | |
"key": "token", | |
"value": "{{token}}", | |
"type": "string" | |
} | |
] | |
}, | |
"method": "GET", | |
"header": [ | |
{ | |
"key": "X-CSRF-Token", | |
"value": "{{csrf_token}}", | |
"type": "text" | |
} | |
], | |
"url": { | |
"raw": "{{ip}}/endpoints/{{newEndpointId}}/docker/info", | |
"host": [ | |
"{{ip}}" | |
], | |
"path": [ | |
"endpoints", | |
"{{newEndpointId}}", | |
"docker", | |
"info" | |
] | |
}, | |
"description": "Gets the Docker info to extract the new Swarm ID" | |
}, | |
"response": [] | |
}, | |
{ | |
"name": "6. Migrate Stack", | |
"event": [ | |
{ | |
"listen": "test", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"// Log the response", | |
"console.log(\"Migration response:\", responseBody);", | |
"", | |
"try {", | |
" // Try to parse as JSON - not critical if it fails", | |
" var jsonResponse = JSON.parse(responseBody);", | |
" console.log(\"Migrated stack successfully:\", jsonResponse);", | |
"} catch (e) {", | |
" console.log(\"Could not parse response as JSON\");", | |
"}", | |
"", | |
"// Get the remaining stack IDs", | |
"var stackIds = JSON.parse(pm.collectionVariables.get(\"stackIds\"));", | |
"var stackData = JSON.parse(pm.collectionVariables.get(\"stackData\"));", | |
"", | |
"// Check if we have more stacks to process", | |
"if (stackIds && stackIds.length > 0) {", | |
" // Get the next stack ID", | |
" var nextStackId = stackIds[0];", | |
" pm.collectionVariables.set(\"currentStackId\", nextStackId);", | |
" ", | |
" // Get the next stack name", | |
" var nextStackName = stackData[nextStackId].name;", | |
" pm.collectionVariables.set(\"currentStackName\", nextStackName);", | |
" ", | |
" // Remove the next stack from the list", | |
" stackIds.shift();", | |
" pm.collectionVariables.set(\"stackIds\", JSON.stringify(stackIds));", | |
" ", | |
" console.log(\"Moving to next stack migration:\");", | |
" console.log(\"- Next Stack ID: \" + nextStackId);", | |
" console.log(\"- Next Stack Name: \" + nextStackName);", | |
" console.log(\"- Remaining stacks: \" + stackIds.length);", | |
" ", | |
" // Run this request again for the next stack", | |
" setTimeout(function() {", | |
" pm.test(\"Continuing stack migration process\", function() {", | |
" postman.setNextRequest(\"6. Migrate Stack\");", | |
" });", | |
" }, 1000); // Wait 1 second between migrations", | |
"} else {", | |
" console.log(\"All stacks have been migrated!\");", | |
" postman.setNextRequest(null);", | |
"}" | |
] | |
} | |
} | |
], | |
"request": { | |
"auth": { | |
"type": "bearer", | |
"bearer": [ | |
{ | |
"key": "token", | |
"value": "{{token}}", | |
"type": "string" | |
} | |
] | |
}, | |
"method": "POST", | |
"header": [ | |
{ | |
"key": "X-CSRF-Token", | |
"value": "{{csrf_token}}", | |
"type": "text" | |
} | |
], | |
"body": { | |
"mode": "raw", | |
"raw": "{\n \"endpointId\": {{newEndpointId}},\n \"name\": \"{{currentStackName}}\",\n \"swarmID\": \"{{newSwarmId}}\"\n}", | |
"options": { | |
"raw": { | |
"language": "json" | |
} | |
} | |
}, | |
"url": { | |
"raw": "{{ip}}/stacks/{{currentStackId}}/migrate", | |
"host": [ | |
"{{ip}}" | |
], | |
"path": [ | |
"stacks", | |
"{{currentStackId}}", | |
"migrate" | |
] | |
}, | |
"description": "Migrates a stack to the new Swarm environment. This request will automatically continue to the next stack until all are migrated." | |
}, | |
"response": [] | |
} | |
], | |
"event": [ | |
{ | |
"listen": "prerequest", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"" | |
] | |
} | |
}, | |
{ | |
"listen": "test", | |
"script": { | |
"type": "text/javascript", | |
"exec": [ | |
"" | |
] | |
} | |
} | |
], | |
"variable": [ | |
{ | |
"key": "ip", | |
"value": "https://192.168.1.1:9443/api", | |
"type": "string" | |
}, | |
{ | |
"key": "ip_base", | |
"value": "https://192.168.1.1:9443", | |
"type": "string" | |
}, | |
{ | |
"key": "user", | |
"value": "admin", | |
"type": "string" | |
}, | |
{ | |
"key": "password", | |
"value": "", | |
"type": "string" | |
}, | |
{ | |
"key": "token", | |
"value": "", | |
"type": "string" | |
}, | |
{ | |
"key": "csrf_token", | |
"value": "", | |
"type": "string" | |
}, | |
{ | |
"key": "stackIds", | |
"value": "[]", | |
"type": "string" | |
}, | |
{ | |
"key": "stackData", | |
"value": "{}", | |
"type": "string" | |
}, | |
{ | |
"key": "newEndpointId", | |
"value": "", | |
"type": "string" | |
}, | |
{ | |
"key": "newSwarmId", | |
"value": "", | |
"type": "string" | |
}, | |
{ | |
"key": "currentStackId", | |
"value": "", | |
"type": "string" | |
}, | |
{ | |
"key": "currentStackName", | |
"value": "", | |
"type": "string" | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment