retry
This commit is contained in:
parent
aeea4e7f8c
commit
8fb4e0f3da
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
123
main.go
123
main.go
|
@ -32,6 +32,8 @@ func main() {
|
|||
for _, container := range containers {
|
||||
project := container.Labels["com.docker.compose.project"]
|
||||
stackNamespace := container.Labels["com.docker.stack.namespace"]
|
||||
|
||||
// Use project name if available; otherwise, use stack namespace
|
||||
stackKey := project
|
||||
if stackNamespace != "" {
|
||||
stackKey = stackNamespace
|
||||
|
@ -61,12 +63,24 @@ func main() {
|
|||
log.Fatalf("Stack or project '%s' not found.", *stackName)
|
||||
}
|
||||
|
||||
// Export the specified stack/project to a docker-compose.yml file
|
||||
err = exportStackToComposeFile(*stackName, containers, *outputFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error exporting stack %s: %v", *stackName, err)
|
||||
// Determine if this is a Docker Swarm stack or a Docker Compose project
|
||||
isSwarm := isDockerSwarmStack(*stackName, containers)
|
||||
|
||||
if isSwarm {
|
||||
// Handle Docker Swarm stack export
|
||||
err = exportSwarmStackToComposeFile(*stackName, *outputFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error exporting Docker Swarm stack %s: %v", *stackName, err)
|
||||
}
|
||||
fmt.Printf("docker-compose.yml generated successfully for Docker Swarm stack '%s' in %s\n", *stackName, *outputFile)
|
||||
} else {
|
||||
// Handle Docker Compose project export
|
||||
err = exportComposeProjectToComposeFile(*stackName, containers, *outputFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error exporting Docker Compose project %s: %v", *stackName, err)
|
||||
}
|
||||
fmt.Printf("docker-compose.yml generated successfully for Docker Compose project '%s' in %s\n", *stackName, *outputFile)
|
||||
}
|
||||
fmt.Printf("docker-compose.yml generated successfully for stack '%s' in %s\n", *stackName, *outputFile)
|
||||
}
|
||||
|
||||
// Container represents basic Docker container information.
|
||||
|
@ -95,8 +109,8 @@ func listContainers() ([]Container, error) {
|
|||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
|
||||
// Check that there are at least 5 fields before accessing them
|
||||
if len(fields) < 5 {
|
||||
// Check that there are at least 3 fields (ID, Name, Image)
|
||||
if len(fields) < 3 {
|
||||
log.Printf("Warning: Skipping incomplete line: %s", scanner.Text())
|
||||
continue
|
||||
}
|
||||
|
@ -104,9 +118,20 @@ func listContainers() ([]Container, error) {
|
|||
id := fields[0]
|
||||
name := fields[1]
|
||||
image := fields[2]
|
||||
|
||||
// Handle cases where project or stackNamespace might be missing
|
||||
project := ""
|
||||
stackNamespace := ""
|
||||
if len(fields) > 3 {
|
||||
project = fields[3]
|
||||
}
|
||||
if len(fields) > 4 {
|
||||
stackNamespace = fields[4]
|
||||
}
|
||||
|
||||
labels := map[string]string{
|
||||
"com.docker.compose.project": fields[3],
|
||||
"com.docker.stack.namespace": fields[4],
|
||||
"com.docker.compose.project": project,
|
||||
"com.docker.stack.namespace": stackNamespace,
|
||||
}
|
||||
|
||||
// Run 'docker inspect' to get detailed container information.
|
||||
|
@ -139,15 +164,89 @@ func inspectContainer(containerID string) ([]string, []string, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Split output into environment variables and network names
|
||||
parts := strings.Split(out.String(), " ")
|
||||
if len(parts) < 2 {
|
||||
// Handle cases where no networks are listed
|
||||
parts = append(parts, "")
|
||||
}
|
||||
envVars := strings.Fields(parts[0])
|
||||
networks := strings.Fields(parts[1])
|
||||
|
||||
return envVars, networks, nil
|
||||
}
|
||||
|
||||
// exportStackToComposeFile generates a docker-compose.yml for a given stack or project.
|
||||
func exportStackToComposeFile(stack string, containers []Container, outputFile string) error {
|
||||
// isDockerSwarmStack checks if the stack is a Docker Swarm stack based on the container names.
|
||||
func isDockerSwarmStack(stackName string, containers []Container) bool {
|
||||
for _, container := range containers {
|
||||
if strings.Contains(container.Name, ".") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// exportSwarmStackToComposeFile exports a Docker Swarm stack to a docker-compose.yml file.
|
||||
func exportSwarmStackToComposeFile(stackName string, outputFile string) error {
|
||||
// Fetch stack details using `docker stack services` and construct the docker-compose.yml
|
||||
cmd := exec.Command("docker", "stack", "services", stackName, "--format", "{{.Name}} {{.Image}} {{.Ports}} {{.Replicas}}")
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching Docker Swarm stack services: %v", err)
|
||||
}
|
||||
|
||||
composeConfig := make(map[string]interface{})
|
||||
composeConfig["services"] = make(map[string]interface{})
|
||||
|
||||
scanner := bufio.NewScanner(&out)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName := fields[0]
|
||||
image := fields[1]
|
||||
|
||||
serviceConfig := map[string]interface{}{
|
||||
"image": image,
|
||||
}
|
||||
|
||||
// Handle additional fields like ports and replicas
|
||||
if len(fields) > 2 {
|
||||
// Parse ports and replicas if available
|
||||
ports := fields[2]
|
||||
replicas := fields[3]
|
||||
serviceConfig["deploy"] = map[string]interface{}{
|
||||
"replicas": replicas,
|
||||
}
|
||||
if ports != "" {
|
||||
serviceConfig["ports"] = []string{ports}
|
||||
}
|
||||
}
|
||||
|
||||
composeConfig["services"].(map[string]interface{})[serviceName] = serviceConfig
|
||||
}
|
||||
|
||||
// Convert to YAML
|
||||
yamlData, err := yaml.Marshal(&composeConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating YAML for Docker Swarm stack %s: %v", stackName, err)
|
||||
}
|
||||
|
||||
// Write YAML to a file
|
||||
err = os.WriteFile(outputFile, yamlData, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing to file %s: %v", outputFile, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// exportComposeProjectToComposeFile exports a Docker Compose project to a docker-compose.yml file.
|
||||
func exportComposeProjectToComposeFile(stack string, containers []Container, outputFile string) error {
|
||||
// Map to hold docker-compose configuration
|
||||
composeConfig := make(map[string]interface{})
|
||||
composeConfig["services"] = make(map[string]interface{})
|
||||
|
@ -179,7 +278,7 @@ func exportStackToComposeFile(stack string, containers []Container, outputFile s
|
|||
// Convert to YAML
|
||||
yamlData, err := yaml.Marshal(&composeConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating YAML for stack %s: %v", stack, err)
|
||||
return fmt.Errorf("error generating YAML for Docker Compose project %s: %v", stack, err)
|
||||
}
|
||||
|
||||
// Write YAML to a file
|
||||
|
|
Loading…
Reference in New Issue