package main import ( "fmt" "github.com/spf13/cobra" ) func deployCommand() *cobra.Command { var containerFlag string cmd := &cobra.Command{ Use: "deploy ", Short: "Deploy a service to a node", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { cfg, err := loadCfg() if err != nil { return err } svc, err := cfg.FindService(args[0]) if err != nil { return err } node, err := cfg.FindNode(args[1]) if err != nil { return err } host := node.Host if node.User != "" { host = node.User + "@" + node.Host } // Build the set of service images for filtering containers. svcImages := make(map[string]bool) for _, img := range svc.Images { svcImages[img] = true } // Collect containers belonging to this service. type target struct { name string ctr *ContainerConfig } var targets []target for name, ctr := range node.Containers { if containerFlag != "" { if name != containerFlag { continue } } else if !svcImages[ctr.Image] { continue } targets = append(targets, target{name: name, ctr: ctr}) } if len(targets) == 0 { return fmt.Errorf("no containers for service %q on node %q", svc.Name, args[1]) } for _, t := range targets { fmt.Printf("\n=== Deploying container %s ===\n", t.name) ref := cfg.ImageRef(t.ctr.Image) + ":latest" // Pull latest image. if err := sshRun(host, "podman pull "+ref); err != nil { return fmt.Errorf("pull %s: %w", ref, err) } // Stop existing container (ignore errors). _ = sshRun(host, "podman stop "+t.name) // Remove existing container (ignore errors). _ = sshRun(host, "podman rm "+t.name) // Build podman run command. runCmd := "podman run -d --name " + t.name if t.ctr.Network != "" { runCmd += " --network " + t.ctr.Network } if t.ctr.User != "" { runCmd += " --user " + t.ctr.User } for _, vol := range t.ctr.Volumes { runCmd += " -v " + vol } for _, port := range t.ctr.Ports { runCmd += " -p " + port } if t.ctr.Restart != "" { runCmd += " --restart " + t.ctr.Restart } runCmd += " " + ref for _, arg := range t.ctr.Cmd { runCmd += " " + arg } // Start new container. if err := sshRun(host, runCmd); err != nil { return fmt.Errorf("run %s: %w", t.name, err) } // Verify container is running. status, err := sshOutput(host, "podman ps --filter name="+t.name+" --format '{{.Status}}'") if err != nil { return fmt.Errorf("verify %s: %w", t.name, err) } fmt.Printf("Status: %s\n", status) } fmt.Printf("\nDeployed %d container(s) to %s\n", len(targets), args[1]) return nil }, } cmd.Flags().StringVar(&containerFlag, "container", "", "deploy only this container") return cmd }