Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jaredcat/c5b26e20bbae39c7707313ebd0f66b1c to your computer and use it in GitHub Desktop.
Save jaredcat/c5b26e20bbae39c7707313ebd0f66b1c to your computer and use it in GitHub Desktop.
Poratiner Stack Migration Postman Collection
{
"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