forked from containers/podman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request containers#19358 from umohnani8/buildfarm-2
Add phase 1 of podman farm subcommands
- Loading branch information
Showing
63 changed files
with
3,728 additions
and
13,261 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package farm | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/containers/common/pkg/completion" | ||
"github.com/containers/common/pkg/config" | ||
"github.com/containers/podman/v4/cmd/podman/registry" | ||
"github.com/containers/podman/v4/pkg/util" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
farmCreateDescription = `Create a new farm with connections added via podman system connection add. | ||
The "podman system connection add --farm" command can be used to add a new connection to a new or existing farm.` | ||
|
||
createCommand = &cobra.Command{ | ||
Use: "create [options] NAME [CONNECTIONS...]", | ||
Args: cobra.MinimumNArgs(1), | ||
Short: "Create a new farm", | ||
Long: farmCreateDescription, | ||
RunE: create, | ||
ValidArgsFunction: completion.AutocompleteNone, | ||
Example: `podman farm create myfarm connection1 | ||
podman farm create myfarm`, | ||
} | ||
) | ||
|
||
func init() { | ||
registry.Commands = append(registry.Commands, registry.CliCommand{ | ||
Command: createCommand, | ||
Parent: farmCmd, | ||
}) | ||
} | ||
|
||
func create(cmd *cobra.Command, args []string) error { | ||
farmName := args[0] | ||
connections := args[1:] | ||
|
||
cfg, err := config.ReadCustomConfig() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if _, ok := cfg.Farms.List[farmName]; ok { | ||
// if farm exists return an error | ||
return fmt.Errorf("farm with name %q already exists", farmName) | ||
} | ||
|
||
// Can create an empty farm without any connections | ||
if len(connections) == 0 { | ||
cfg.Farms.List[farmName] = []string{} | ||
} | ||
|
||
for _, c := range connections { | ||
if _, ok := cfg.Engine.ServiceDestinations[c]; ok { | ||
if util.StringInSlice(c, cfg.Farms.List[farmName]) { | ||
// Don't add duplicate connections to a farm | ||
continue | ||
} | ||
cfg.Farms.List[farmName] = append(cfg.Farms.List[farmName], c) | ||
} else { | ||
return fmt.Errorf("cannot create farm, %q is not a system connection", c) | ||
} | ||
} | ||
|
||
// If this is the first farm being created, set it as the default farm | ||
if len(cfg.Farms.List) == 1 { | ||
cfg.Farms.Default = farmName | ||
} | ||
|
||
err = cfg.Write() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Printf("Farm %q created\n", farmName) | ||
return nil | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package farm | ||
|
||
import ( | ||
"github.com/containers/podman/v4/cmd/podman/registry" | ||
"github.com/containers/podman/v4/cmd/podman/validate" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
// Command: podman _farm_ | ||
farmCmd = &cobra.Command{ | ||
Use: "farm", | ||
Short: "Farm out builds to remote machines", | ||
Long: "Farm out builds to remote machines that podman can connect to via podman system connection", | ||
RunE: validate.SubCommandExists, | ||
} | ||
) | ||
|
||
var ( | ||
// Temporary struct to hold cli values. | ||
farmOpts = struct { | ||
Farm string | ||
Local bool | ||
}{} | ||
) | ||
|
||
func init() { | ||
registry.Commands = append(registry.Commands, registry.CliCommand{ | ||
Command: farmCmd, | ||
}) | ||
farmCmd.Hidden = true | ||
|
||
flags := farmCmd.Flags() | ||
podmanConfig := registry.PodmanConfig() | ||
|
||
farmFlagName := "farm" | ||
// If remote, don't read the client's containers.conf file | ||
defaultFarm := "" | ||
if !registry.IsRemote() { | ||
defaultFarm = podmanConfig.ContainersConfDefaultsRO.Farms.Default | ||
} | ||
flags.StringVarP(&farmOpts.Farm, farmFlagName, "f", defaultFarm, "Farm to use for builds") | ||
|
||
localFlagName := "local" | ||
// Default for local is true and hide this flag for the remote use case | ||
if !registry.IsRemote() { | ||
flags.BoolVarP(&farmOpts.Local, localFlagName, "l", true, "Build image on local machine including on farm nodes") | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package farm | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"sort" | ||
|
||
"github.com/containers/common/pkg/completion" | ||
"github.com/containers/common/pkg/config" | ||
"github.com/containers/common/pkg/report" | ||
"github.com/containers/podman/v4/cmd/podman/common" | ||
"github.com/containers/podman/v4/cmd/podman/registry" | ||
"github.com/containers/podman/v4/cmd/podman/validate" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
farmLsDescription = `podman farm ls | ||
List all available farms. The output of the farms can be filtered | ||
and the output format can be changed to JSON or a user specified Go template.` | ||
lsCommand = &cobra.Command{ | ||
Use: "list [options]", | ||
Aliases: []string{"ls"}, | ||
Args: validate.NoArgs, | ||
Short: "List all existing farms", | ||
Long: farmLsDescription, | ||
RunE: list, | ||
ValidArgsFunction: completion.AutocompleteNone, | ||
} | ||
|
||
// Temporary struct to hold cli values. | ||
lsOpts = struct { | ||
Format string | ||
}{} | ||
) | ||
|
||
func init() { | ||
registry.Commands = append(registry.Commands, registry.CliCommand{ | ||
Command: lsCommand, | ||
Parent: farmCmd, | ||
}) | ||
flags := lsCommand.Flags() | ||
|
||
formatFlagName := "format" | ||
flags.StringVar(&lsOpts.Format, formatFlagName, "", "Format farm output using Go template") | ||
_ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&farmOut{})) | ||
} | ||
|
||
type farmOut struct { | ||
Name string | ||
Connections []string | ||
Default bool | ||
} | ||
|
||
func list(cmd *cobra.Command, args []string) error { | ||
cfg, err := config.ReadCustomConfig() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
format := lsOpts.Format | ||
if format == "" && len(args) > 0 { | ||
format = "json" | ||
} | ||
|
||
rows := make([]farmOut, 0) | ||
for k, v := range cfg.Farms.List { | ||
defaultFarm := false | ||
if k == cfg.Farms.Default { | ||
defaultFarm = true | ||
} | ||
|
||
r := farmOut{ | ||
Name: k, | ||
Connections: v, | ||
Default: defaultFarm, | ||
} | ||
rows = append(rows, r) | ||
} | ||
|
||
sort.Slice(rows, func(i, j int) bool { | ||
return rows[i].Name < rows[j].Name | ||
}) | ||
|
||
rpt := report.New(os.Stdout, cmd.Name()) | ||
defer rpt.Flush() | ||
|
||
if report.IsJSON(format) { | ||
buf, err := registry.JSONLibrary().MarshalIndent(rows, "", " ") | ||
if err == nil { | ||
fmt.Println(string(buf)) | ||
} | ||
return err | ||
} | ||
|
||
if format != "" { | ||
rpt, err = rpt.Parse(report.OriginUser, format) | ||
} else { | ||
rpt, err = rpt.Parse(report.OriginPodman, | ||
"{{range .}}{{.Name}}\t{{.Connections}}\t{{.Default}}\n{{end -}}") | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if rpt.RenderHeaders { | ||
err = rpt.Execute([]map[string]string{{ | ||
"Default": "Default", | ||
"Connections": "Connections", | ||
"Name": "Name", | ||
}}) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return rpt.Execute(rows) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package farm | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/containers/common/pkg/config" | ||
"github.com/containers/podman/v4/cmd/podman/common" | ||
"github.com/containers/podman/v4/cmd/podman/registry" | ||
"github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
farmRmDescription = `Remove one or more existing farms.` | ||
rmCommand = &cobra.Command{ | ||
Use: "remove [options] [FARM...]", | ||
Aliases: []string{"rm"}, | ||
Short: "Remove one or more farms", | ||
Long: farmRmDescription, | ||
RunE: rm, | ||
ValidArgsFunction: common.AutoCompleteFarms, | ||
Example: `podman farm rm myfarm1 myfarm2 | ||
podman farm rm --all`, | ||
} | ||
|
||
// Temporary struct to hold cli values. | ||
rmOpts = struct { | ||
All bool | ||
}{} | ||
) | ||
|
||
func init() { | ||
registry.Commands = append(registry.Commands, registry.CliCommand{ | ||
Command: rmCommand, | ||
Parent: farmCmd, | ||
}) | ||
flags := rmCommand.Flags() | ||
flags.BoolVarP(&rmOpts.All, "all", "a", false, "Remove all farms") | ||
} | ||
|
||
func rm(cmd *cobra.Command, args []string) error { | ||
cfg, err := config.ReadCustomConfig() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if rmOpts.All { | ||
cfg.Farms.List = make(map[string][]string) | ||
cfg.Farms.Default = "" | ||
if err := cfg.Write(); err != nil { | ||
return err | ||
} | ||
fmt.Println("All farms have been deleted") | ||
return nil | ||
} | ||
|
||
// If the --all is not set, we require at least one arg | ||
if len(args) == 0 { | ||
return errors.New("requires at lease 1 arg(s), received 0") | ||
} | ||
|
||
if len(cfg.Farms.List) == 0 { | ||
return errors.New("no existing farms; nothing to remove") | ||
} | ||
|
||
deletedFarms := []string{} | ||
for _, k := range args { | ||
if _, ok := cfg.Farms.List[k]; !ok { | ||
logrus.Warnf("farm %q doesn't exists; nothing to remove", k) | ||
continue | ||
} | ||
delete(cfg.Farms.List, k) | ||
deletedFarms = append(deletedFarms, k) | ||
if k == cfg.Farms.Default { | ||
cfg.Farms.Default = "" | ||
} | ||
} | ||
// Return error if none of the given farms were deleted | ||
if len(deletedFarms) == 0 { | ||
return fmt.Errorf("failed to delete farms %q", args) | ||
} | ||
|
||
// Set a new default farm if the current default farm has been removed | ||
if cfg.Farms.Default == "" && cfg.Farms.List != nil { | ||
for k := range cfg.Farms.List { | ||
cfg.Farms.Default = k | ||
break | ||
} | ||
} | ||
if err := cfg.Write(); err != nil { | ||
return err | ||
} | ||
|
||
for _, k := range deletedFarms { | ||
fmt.Printf("Farm %q deleted\n", k) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.