Mdarende
Mdarende

Reputation: 739

I try to export all stacks from a remote portainer.io server with C# but I get definitely more stacks then I can see manually on the UI?

I try to export all stacks from a remote portainer.io server with C# but I get definitely more stacks then I can see on the UI?

Let's say for an endpoint there are 10 stacks listed in the UI, but I get over 20 exported for the same endpoint.

I have nothing filtered on the UI and the credentials that I use in my script is the same as I log in manually to the UI.

In the same code I am also listing all the stacks according to the endpoints (containers). Listing results as expected. Only that stacks are listed that I can also see in the UI.

What could be the problem? Is it possible that I export additionally stacks that are not active? If yes How can I export just the active one?

    static async Task Main(string[] args)
    {
        string baseUrl = "https://myserver/portainer"; 
        string username = "myuser";
        string password = "mypassword";
        string exportPath = @"C:\temp\Portainer\Export"; for export
        string stacksFilePath = @"C:\temp\Portainer\Export\stacks.txt"; 

        try
        {
            // Authenticate and get token
            string token = await Authenticate(baseUrl, username, password);

            // List endpoints and stacks
            await ListEndpointsAndStacks(baseUrl, token, stacksFilePath);

            // Export all stacks
            await ExportAllStacks(baseUrl, token, exportPath);
            Console.WriteLine("All stacks exported successfully.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"An error occurred: {ex.Message}");
            Console.ReadKey();
        }
    }
    


    private static async Task<string> Authenticate(string baseUrl, string username, string password)
    {
        using (var client = new HttpClient())
        {
            var authData = new { Username = username, Password = password };
            var content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(authData));
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            var response = await client.PostAsync($"{baseUrl}/api/auth", content);
            response.EnsureSuccessStatusCode();

            var responseData = await response.Content.ReadAsStringAsync();
            return JObject.Parse(responseData)["jwt"].ToString(); // Extract JWT token
        }
    }

    private static async Task ListEndpointsAndStacks(string baseUrl, string token, string filePath)
    {
        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            var sb = new StringBuilder();

            // Fetch all endpoints
            var endpointsResponse = await client.GetAsync($"{baseUrl}/api/endpoints");
            endpointsResponse.EnsureSuccessStatusCode();

            var endpoints = JArray.Parse(await endpointsResponse.Content.ReadAsStringAsync());

            // Fetch all stacks globally
            var stacksResponse = await client.GetAsync($"{baseUrl}/api/stacks");
            stacksResponse.EnsureSuccessStatusCode();

            var stacks = JArray.Parse(await stacksResponse.Content.ReadAsStringAsync());

            sb.AppendLine("Endpoints and Stacks:");
            sb.AppendLine("=====================");

            foreach (var endpoint in endpoints)
            {
                string endpointId = endpoint["Id"].ToString();
                string endpointName = endpoint["Name"].ToString();

                sb.AppendLine($"Endpoint: {endpointName} (ID: {endpointId})");

                // Filter stacks for this endpoint
                var stacksForEndpoint = stacks.Where(stack => stack["EndpointId"].ToString() == endpointId);

                if (!stacksForEndpoint.Any())
                {
                    sb.AppendLine("  No stacks found.");
                }
                else
                {
                    foreach (var stack in stacksForEndpoint)
                    {
                        string stackName = stack["Name"].ToString();
                        sb.AppendLine($"  Stack: {stackName}");
                    }
                }

                sb.AppendLine(); // Blank line between endpoints
            }

            // Write all data to file
            File.WriteAllText(filePath, sb.ToString());

            Console.WriteLine($"Endpoints and stack names written to: {filePath}");
        }
    }


    private static async Task ExportAllStacks(string baseUrl, string token, string exportPath)
    {
        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            // Ensure the export directory exists
            Directory.CreateDirectory(exportPath);

            // Fetch all endpoints
            var endpointsResponse = await client.GetAsync($"{baseUrl}/api/endpoints");
            endpointsResponse.EnsureSuccessStatusCode();

            var endpoints = JArray.Parse(await endpointsResponse.Content.ReadAsStringAsync());

            foreach (var endpoint in endpoints)
            {
                string endpointId = endpoint["Id"].ToString();
                string endpointName = endpoint["Name"].ToString();

                Console.WriteLine($"Processing Endpoint: {endpointName} (ID: {endpointId})");

                // Fetch all stacks in this endpoint
                var stacksResponse = await client.GetAsync($"{baseUrl}/api/stacks");
                stacksResponse.EnsureSuccessStatusCode();

                var stacks = JArray.Parse(await stacksResponse.Content.ReadAsStringAsync());

                foreach (var stack in stacks)
                {
                    string stackId = stack["Id"].ToString();
                    string stackName = stack["Name"].ToString();

                    try
                    {
                        Console.WriteLine($"Exporting Stack: {stackName} (ID: {stackId})");

                        // Fetch stack file content
                        var stackFileResponse = await client.GetAsync($"{baseUrl}/api/stacks/{stackId}/file");

                        if (!stackFileResponse.IsSuccessStatusCode)
                        {
                            Console.WriteLine($"  Failed to export stack '{stackName}': {stackFileResponse.ReasonPhrase}");
                            continue; // Skip this stack and continue with the next one
                        }

                        string stackFileContent = await stackFileResponse.Content.ReadAsStringAsync();

                        // Save to a file
                        string sanitizedFileName = Path.Combine(exportPath, $"{endpointName}_{stackName.Replace(" ", "_")}.txt");
                        File.WriteAllText(sanitizedFileName, stackFileContent);

                        Console.WriteLine($"  Stack '{stackName}' exported to '{sanitizedFileName}'");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"  Error exporting stack '{stackName}': {ex.Message}");
                    }
                }
            }
        }
    }

My code:

Upvotes: 0

Views: 21

Answers (0)

Related Questions