mirror of https://github.com/containers/podman.git
Merge pull request #21384 from Luap99/connections
rework system connection and farm storage
This commit is contained in:
commit
1a8cb15aa6
|
@ -837,15 +837,15 @@ func AutoCompleteFarms(cmd *cobra.Command, args []string, toComplete string) ([]
|
||||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
}
|
}
|
||||||
suggestions := []string{}
|
farms, err := podmanConfig.ContainersConfDefaultsRO.GetAllFarms()
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cobra.CompErrorln(err.Error())
|
cobra.CompErrorln(err.Error())
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range cfg.Farms.List {
|
suggestions := make([]string, 0, len(farms))
|
||||||
suggestions = append(suggestions, k)
|
for _, farm := range farms {
|
||||||
|
suggestions = append(suggestions, farm.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
@ -856,16 +856,17 @@ func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete
|
||||||
if !validCurrentCmdLine(cmd, args, toComplete) {
|
if !validCurrentCmdLine(cmd, args, toComplete) {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
}
|
}
|
||||||
suggestions := []string{}
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
cons, err := podmanConfig.ContainersConfDefaultsRO.GetAllConnections()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cobra.CompErrorln(err.Error())
|
cobra.CompErrorln(err.Error())
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range cfg.Engine.ServiceDestinations {
|
suggestions := make([]string, 0, len(cons))
|
||||||
|
for _, con := range cons {
|
||||||
// the URI will be show as description in shells like zsh
|
// the URI will be show as description in shells like zsh
|
||||||
suggestions = append(suggestions, k+"\t"+v.URI)
|
suggestions = append(suggestions, con.Name+"\t"+con.URI)
|
||||||
}
|
}
|
||||||
|
|
||||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/pkg/errorhandling"
|
"github.com/containers/podman/v4/pkg/errorhandling"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
|
@ -114,15 +113,10 @@ func composeDockerHost() (string, error) {
|
||||||
return registry.DefaultAPIAddress(), nil
|
return registry.DefaultAPIAddress(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
// TODO need to add support for --connection and --url
|
||||||
|
connection, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetConnection("", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
logrus.Info(err)
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: podman --connection=foo and --url=... are injected
|
|
||||||
// into the default connection below in `root.go`.
|
|
||||||
defaultConnection := cfg.Engine.ActiveService
|
|
||||||
if defaultConnection == "" {
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
// If no default connection is set on Linux or FreeBSD,
|
// If no default connection is set on Linux or FreeBSD,
|
||||||
// we just use the local socket by default - just as
|
// we just use the local socket by default - just as
|
||||||
|
@ -137,10 +131,6 @@ func composeDockerHost() (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connection, ok := cfg.Engine.ServiceDestinations[defaultConnection]
|
|
||||||
if !ok {
|
|
||||||
return "", fmt.Errorf("internal error: default connection %q not found in database", defaultConnection)
|
|
||||||
}
|
|
||||||
parsedConnection, err := url.Parse(connection.URI)
|
parsedConnection, err := url.Parse(connection.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("preparing connection to remote machine: %w", err)
|
return "", fmt.Errorf("preparing connection to remote machine: %w", err)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/common"
|
"github.com/containers/podman/v4/cmd/podman/common"
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/cmd/podman/utils"
|
"github.com/containers/podman/v4/cmd/podman/utils"
|
||||||
|
@ -50,14 +49,8 @@ func init() {
|
||||||
cleanupFlag := "cleanup"
|
cleanupFlag := "cleanup"
|
||||||
flags.BoolVar(&buildOpts.buildOptions.Cleanup, cleanupFlag, false, "Remove built images from farm nodes on success")
|
flags.BoolVar(&buildOpts.buildOptions.Cleanup, cleanupFlag, false, "Remove built images from farm nodes on success")
|
||||||
|
|
||||||
podmanConfig := registry.PodmanConfig()
|
|
||||||
farmFlagName := "farm"
|
farmFlagName := "farm"
|
||||||
// If remote, don't read the client's containers.conf file
|
flags.StringVar(&buildOpts.farm, farmFlagName, "", "Farm to use for builds")
|
||||||
defaultFarm := ""
|
|
||||||
if !registry.IsRemote() {
|
|
||||||
defaultFarm = podmanConfig.ContainersConfDefaultsRO.Farms.Default
|
|
||||||
}
|
|
||||||
flags.StringVar(&buildOpts.farm, farmFlagName, defaultFarm, "Farm to use for builds")
|
|
||||||
_ = buildCommand.RegisterFlagCompletionFunc(farmFlagName, common.AutoCompleteFarms)
|
_ = buildCommand.RegisterFlagCompletionFunc(farmFlagName, common.AutoCompleteFarms)
|
||||||
|
|
||||||
localFlagName := "local"
|
localFlagName := "local"
|
||||||
|
@ -122,23 +115,9 @@ func build(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
opts.SkipTLSVerify = !tlsVerify
|
opts.SkipTLSVerify = !tlsVerify
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultFarm := cfg.Farms.Default
|
|
||||||
if cmd.Flags().Changed("farm") {
|
|
||||||
f, err := cmd.Flags().GetString("farm")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defaultFarm = f
|
|
||||||
}
|
|
||||||
|
|
||||||
localEngine := registry.ImageEngine()
|
localEngine := registry.ImageEngine()
|
||||||
ctx := registry.Context()
|
ctx := registry.Context()
|
||||||
farm, err := farm.NewFarm(ctx, defaultFarm, localEngine, buildOpts.local)
|
farm, err := farm.NewFarm(ctx, buildOpts.farm, localEngine, buildOpts.local)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("initializing: %w", err)
|
return fmt.Errorf("initializing: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,43 +41,39 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
farmName := args[0]
|
farmName := args[0]
|
||||||
connections := args[1:]
|
connections := args[1:]
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
err := config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if err != nil {
|
if _, ok := cfg.Farm.List[farmName]; ok {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := cfg.Farms.List[farmName]; ok {
|
|
||||||
// if farm exists return an error
|
// if farm exists return an error
|
||||||
return fmt.Errorf("farm with name %q already exists", farmName)
|
return fmt.Errorf("farm with name %q already exists", farmName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can create an empty farm without any connections
|
// Can create an empty farm without any connections
|
||||||
if len(connections) == 0 {
|
if len(connections) == 0 {
|
||||||
cfg.Farms.List[farmName] = []string{}
|
cfg.Farm.List[farmName] = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range connections {
|
for _, c := range connections {
|
||||||
if _, ok := cfg.Engine.ServiceDestinations[c]; ok {
|
if _, ok := cfg.Connection.Connections[c]; ok {
|
||||||
if slices.Contains(cfg.Farms.List[farmName], c) {
|
if slices.Contains(cfg.Farm.List[farmName], c) {
|
||||||
// Don't add duplicate connections to a farm
|
// Don't add duplicate connections to a farm
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cfg.Farms.List[farmName] = append(cfg.Farms.List[farmName], c)
|
cfg.Farm.List[farmName] = append(cfg.Farm.List[farmName], c)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("cannot create farm, %q is not a system connection", c)
|
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 this is the first farm being created, set it as the default farm
|
||||||
if len(cfg.Farms.List) == 1 {
|
if len(cfg.Farm.List) == 1 {
|
||||||
cfg.Farms.Default = farmName
|
cfg.Farm.Default = farmName
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cfg.Write()
|
return nil
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Farm %q created\n", farmName)
|
fmt.Printf("Farm %q created\n", farmName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,50 +46,29 @@ func init() {
|
||||||
|
|
||||||
formatFlagName := "format"
|
formatFlagName := "format"
|
||||||
flags.StringVar(&lsOpts.Format, formatFlagName, "", "Format farm output using Go template")
|
flags.StringVar(&lsOpts.Format, formatFlagName, "", "Format farm output using Go template")
|
||||||
_ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&farmOut{}))
|
_ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&config.Farm{}))
|
||||||
}
|
|
||||||
|
|
||||||
type farmOut struct {
|
|
||||||
Name string
|
|
||||||
Connections []string
|
|
||||||
Default bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func list(cmd *cobra.Command, args []string) error {
|
func list(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
format := lsOpts.Format
|
format := lsOpts.Format
|
||||||
if format == "" && len(args) > 0 {
|
if format == "" && len(args) > 0 {
|
||||||
format = "json"
|
format = "json"
|
||||||
}
|
}
|
||||||
|
|
||||||
rows := make([]farmOut, 0)
|
farms, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetAllFarms()
|
||||||
for k, v := range cfg.Farms.List {
|
if err != nil {
|
||||||
defaultFarm := false
|
return err
|
||||||
if k == cfg.Farms.Default {
|
|
||||||
defaultFarm = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r := farmOut{
|
sort.Slice(farms, func(i, j int) bool {
|
||||||
Name: k,
|
return farms[i].Name < farms[j].Name
|
||||||
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())
|
rpt := report.New(os.Stdout, cmd.Name())
|
||||||
defer rpt.Flush()
|
defer rpt.Flush()
|
||||||
|
|
||||||
if report.IsJSON(format) {
|
if report.IsJSON(format) {
|
||||||
buf, err := registry.JSONLibrary().MarshalIndent(rows, "", " ")
|
buf, err := registry.JSONLibrary().MarshalIndent(farms, "", " ")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println(string(buf))
|
fmt.Println(string(buf))
|
||||||
}
|
}
|
||||||
|
@ -100,7 +79,7 @@ func list(cmd *cobra.Command, args []string) error {
|
||||||
rpt, err = rpt.Parse(report.OriginUser, format)
|
rpt, err = rpt.Parse(report.OriginUser, format)
|
||||||
} else {
|
} else {
|
||||||
rpt, err = rpt.Parse(report.OriginPodman,
|
rpt, err = rpt.Parse(report.OriginPodman,
|
||||||
"{{range .}}{{.Name}}\t{{.Connections}}\t{{.Default}}\n{{end -}}")
|
"{{range .}}{{.Name}}\t{{.Connections}}\t{{.Default}}\t{{.ReadWrite}}\n{{end -}}")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -111,11 +90,12 @@ func list(cmd *cobra.Command, args []string) error {
|
||||||
"Default": "Default",
|
"Default": "Default",
|
||||||
"Connections": "Connections",
|
"Connections": "Connections",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
|
"ReadWrite": "ReadWrite",
|
||||||
}})
|
}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpt.Execute(rows)
|
return rpt.Execute(farms)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,18 +43,11 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func rm(cmd *cobra.Command, args []string) error {
|
func rm(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
deletedFarms := []string{}
|
||||||
if err != nil {
|
err := config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rmOpts.All {
|
if rmOpts.All {
|
||||||
cfg.Farms.List = make(map[string][]string)
|
cfg.Farm.List = make(map[string][]string)
|
||||||
cfg.Farms.Default = ""
|
cfg.Farm.Default = ""
|
||||||
if err := cfg.Write(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("All farms have been deleted")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,20 +56,19 @@ func rm(cmd *cobra.Command, args []string) error {
|
||||||
return errors.New("requires at lease 1 arg(s), received 0")
|
return errors.New("requires at lease 1 arg(s), received 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.Farms.List) == 0 {
|
if len(cfg.Farm.List) == 0 {
|
||||||
return errors.New("no existing farms; nothing to remove")
|
return errors.New("no existing farms; nothing to remove")
|
||||||
}
|
}
|
||||||
|
|
||||||
deletedFarms := []string{}
|
|
||||||
for _, k := range args {
|
for _, k := range args {
|
||||||
if _, ok := cfg.Farms.List[k]; !ok {
|
if _, ok := cfg.Farm.List[k]; !ok {
|
||||||
logrus.Warnf("farm %q doesn't exist; nothing to remove", k)
|
logrus.Warnf("farm %q doesn't exist; nothing to remove", k)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delete(cfg.Farms.List, k)
|
delete(cfg.Farm.List, k)
|
||||||
deletedFarms = append(deletedFarms, k)
|
deletedFarms = append(deletedFarms, k)
|
||||||
if k == cfg.Farms.Default {
|
if k == cfg.Farm.Default {
|
||||||
cfg.Farms.Default = ""
|
cfg.Farm.Default = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Return error if none of the given farms were deleted
|
// Return error if none of the given farms were deleted
|
||||||
|
@ -85,15 +77,21 @@ func rm(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a new default farm if the current default farm has been removed
|
// Set a new default farm if the current default farm has been removed
|
||||||
if cfg.Farms.Default == "" && cfg.Farms.List != nil {
|
if cfg.Farm.Default == "" && cfg.Farm.List != nil {
|
||||||
for k := range cfg.Farms.List {
|
for k := range cfg.Farm.List {
|
||||||
cfg.Farms.Default = k
|
cfg.Farm.Default = k
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := cfg.Write(); err != nil {
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if rmOpts.All {
|
||||||
|
fmt.Println("All farms have been deleted")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, k := range deletedFarms {
|
for _, k := range deletedFarms {
|
||||||
fmt.Printf("Farm %q deleted\n", k)
|
fmt.Printf("Farm %q deleted\n", k)
|
||||||
|
|
|
@ -63,37 +63,33 @@ func farmUpdate(cmd *cobra.Command, args []string) error {
|
||||||
return fmt.Errorf("nothing to update for farm %q, please use the --add, --remove, or --default flags to update a farm", farmName)
|
return fmt.Errorf("nothing to update for farm %q, please use the --add, --remove, or --default flags to update a farm", farmName)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
err := config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if err != nil {
|
if len(cfg.Farm.List) == 0 {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.Farms.List) == 0 {
|
|
||||||
return errors.New("no farms are created at this time, there is nothing to update")
|
return errors.New("no farms are created at this time, there is nothing to update")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := cfg.Farms.List[farmName]; !ok {
|
if _, ok := cfg.Farm.List[farmName]; !ok {
|
||||||
return fmt.Errorf("cannot update farm, %q farm doesn't exist", farmName)
|
return fmt.Errorf("cannot update farm, %q farm doesn't exist", farmName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if defChanged {
|
if defChanged {
|
||||||
// Change the default to the given farm if --default=true
|
// Change the default to the given farm if --default=true
|
||||||
if updateOpts.Default {
|
if updateOpts.Default {
|
||||||
cfg.Farms.Default = farmName
|
cfg.Farm.Default = farmName
|
||||||
} else {
|
} else {
|
||||||
// if --default=false, user doesn't want any farms to be default so clear the DefaultFarm
|
// if --default=false, user doesn't want any farms to be default so clear the DefaultFarm
|
||||||
cfg.Farms.Default = ""
|
cfg.Farm.Default = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := cfg.Farms.List[farmName]; ok {
|
if val, ok := cfg.Farm.List[farmName]; ok {
|
||||||
cMap := make(map[string]int)
|
cMap := make(map[string]int)
|
||||||
for _, c := range val {
|
for _, c := range val {
|
||||||
cMap[c] = 0
|
cMap[c] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cRemove := range updateOpts.Remove {
|
for _, cRemove := range updateOpts.Remove {
|
||||||
connections := cfg.Farms.List[farmName]
|
connections := cfg.Farm.List[farmName]
|
||||||
if slices.Contains(connections, cRemove) {
|
if slices.Contains(connections, cRemove) {
|
||||||
delete(cMap, cRemove)
|
delete(cMap, cRemove)
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,7 +98,7 @@ func farmUpdate(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cAdd := range updateOpts.Add {
|
for _, cAdd := range updateOpts.Add {
|
||||||
if _, ok := cfg.Engine.ServiceDestinations[cAdd]; ok {
|
if _, ok := cfg.Connection.Connections[cAdd]; ok {
|
||||||
if _, ok := cMap[cAdd]; !ok {
|
if _, ok := cMap[cAdd]; !ok {
|
||||||
cMap[cAdd] = 0
|
cMap[cAdd] = 0
|
||||||
}
|
}
|
||||||
|
@ -115,10 +111,11 @@ func farmUpdate(cmd *cobra.Command, args []string) error {
|
||||||
for k := range cMap {
|
for k := range cMap {
|
||||||
updatedConnections = append(updatedConnections, k)
|
updatedConnections = append(updatedConnections, k)
|
||||||
}
|
}
|
||||||
cfg.Farms.List[farmName] = updatedConnections
|
cfg.Farm.List[farmName] = updatedConnections
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
if err := cfg.Write(); err != nil {
|
})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Farm %q updated\n", farmName)
|
fmt.Printf("Farm %q updated\n", farmName)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
"github.com/containers/common/pkg/report"
|
"github.com/containers/common/pkg/report"
|
||||||
"github.com/containers/podman/v4/cmd/podman/common"
|
"github.com/containers/podman/v4/cmd/podman/common"
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
|
@ -108,16 +107,18 @@ func hostInfo() (*entities.MachineHostInfo, error) {
|
||||||
|
|
||||||
host.NumberOfMachines = len(listResponse)
|
host.NumberOfMachines = len(listResponse)
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
defaultCon := ""
|
||||||
if err != nil {
|
con, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetConnection("", true)
|
||||||
return nil, err
|
if err == nil {
|
||||||
|
// ignore the error here we only want to know if we have a default connection to show it in list
|
||||||
|
defaultCon = con.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default state of machine is stopped
|
// Default state of machine is stopped
|
||||||
host.MachineState = "Stopped"
|
host.MachineState = "Stopped"
|
||||||
for _, vm := range listResponse {
|
for _, vm := range listResponse {
|
||||||
// Set default machine if found
|
// Set default machine if found
|
||||||
if vm.Name == cfg.Engine.ActiveService {
|
if vm.Name == defaultCon {
|
||||||
host.DefaultMachine = vm.Name
|
host.DefaultMachine = vm.Name
|
||||||
}
|
}
|
||||||
// If machine is running or starting, it is automatically the current machine
|
// If machine is running or starting, it is automatically the current machine
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"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/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/libpod/events"
|
"github.com/containers/podman/v4/libpod/events"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
|
@ -150,17 +149,20 @@ func initMachine(cmd *cobra.Command, args []string) error {
|
||||||
return fmt.Errorf("%s: %w", initOpts.Name, machine.ErrVMAlreadyExists)
|
return fmt.Errorf("%s: %w", initOpts.Name, machine.ErrVMAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
// check if a system connection already exists
|
||||||
|
cons, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetAllConnections()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, con := range cons {
|
||||||
// check if a system connection already exists
|
if con.ReadWrite {
|
||||||
for _, connection := range []string{initOpts.Name, fmt.Sprintf("%s-root", initOpts.Name)} {
|
for _, connection := range []string{initOpts.Name, fmt.Sprintf("%s-root", initOpts.Name)} {
|
||||||
if _, valueFound := cfg.Engine.ServiceDestinations[connection]; valueFound {
|
if con.Name == connection {
|
||||||
return fmt.Errorf("system connection %q already exists. consider a different machine name or remove the connection with `podman system connection rm`", connection)
|
return fmt.Errorf("system connection %q already exists. consider a different machine name or remove the connection with `podman system connection rm`", connection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for idx, vol := range initOpts.Volumes {
|
for idx, vol := range initOpts.Volumes {
|
||||||
initOpts.Volumes[idx] = os.ExpandEnv(vol)
|
initOpts.Volumes[idx] = os.ExpandEnv(vol)
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
"github.com/containers/common/pkg/report"
|
"github.com/containers/common/pkg/report"
|
||||||
"github.com/containers/podman/v4/cmd/podman/common"
|
"github.com/containers/podman/v4/cmd/podman/common"
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
|
@ -79,12 +78,15 @@ func list(cmd *cobra.Command, args []string) error {
|
||||||
return listResponse[i].Running
|
return listResponse[i].Running
|
||||||
})
|
})
|
||||||
|
|
||||||
if report.IsJSON(listFlag.format) {
|
defaultCon := ""
|
||||||
machineReporter, err := toMachineFormat(listResponse)
|
con, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetConnection("", true)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return err
|
// ignore the error here we only want to know if we have a default connection to show it in list
|
||||||
|
defaultCon = con.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if report.IsJSON(listFlag.format) {
|
||||||
|
machineReporter := toMachineFormat(listResponse, defaultCon)
|
||||||
b, err := json.MarshalIndent(machineReporter, "", " ")
|
b, err := json.MarshalIndent(machineReporter, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -93,11 +95,7 @@ func list(cmd *cobra.Command, args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
machineReporter, err := toHumanFormat(listResponse)
|
machineReporter := toHumanFormat(listResponse, defaultCon)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputTemplate(cmd, machineReporter)
|
return outputTemplate(cmd, machineReporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,16 +151,11 @@ func streamName(imageStream string) string {
|
||||||
return imageStream
|
return imageStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func toMachineFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error) {
|
func toMachineFormat(vms []*machine.ListResponse, defaultCon string) []*entities.ListReporter {
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
machineResponses := make([]*entities.ListReporter, 0, len(vms))
|
machineResponses := make([]*entities.ListReporter, 0, len(vms))
|
||||||
for _, vm := range vms {
|
for _, vm := range vms {
|
||||||
response := new(entities.ListReporter)
|
response := new(entities.ListReporter)
|
||||||
response.Default = vm.Name == cfg.Engine.ActiveService
|
response.Default = vm.Name == defaultCon
|
||||||
response.Name = vm.Name
|
response.Name = vm.Name
|
||||||
response.Running = vm.Running
|
response.Running = vm.Running
|
||||||
response.LastUp = strTime(vm.LastUp)
|
response.LastUp = strTime(vm.LastUp)
|
||||||
|
@ -180,19 +173,14 @@ func toMachineFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, err
|
||||||
|
|
||||||
machineResponses = append(machineResponses, response)
|
machineResponses = append(machineResponses, response)
|
||||||
}
|
}
|
||||||
return machineResponses, nil
|
return machineResponses
|
||||||
}
|
}
|
||||||
|
|
||||||
func toHumanFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error) {
|
func toHumanFormat(vms []*machine.ListResponse, defaultCon string) []*entities.ListReporter {
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
humanResponses := make([]*entities.ListReporter, 0, len(vms))
|
humanResponses := make([]*entities.ListReporter, 0, len(vms))
|
||||||
for _, vm := range vms {
|
for _, vm := range vms {
|
||||||
response := new(entities.ListReporter)
|
response := new(entities.ListReporter)
|
||||||
if vm.Name == cfg.Engine.ActiveService {
|
if vm.Name == defaultCon {
|
||||||
response.Name = vm.Name + "*"
|
response.Name = vm.Name + "*"
|
||||||
response.Default = true
|
response.Default = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -218,5 +206,5 @@ func toHumanFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, error
|
||||||
|
|
||||||
humanResponses = append(humanResponses, response)
|
humanResponses = append(humanResponses, response)
|
||||||
}
|
}
|
||||||
return humanResponses, nil
|
return humanResponses
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"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/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/cmd/podman/utils"
|
"github.com/containers/podman/v4/cmd/podman/utils"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
|
@ -93,12 +92,12 @@ func ssh(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func remoteConnectionUsername() (string, error) {
|
func remoteConnectionUsername() (string, error) {
|
||||||
cfg, err := config.ReadCustomConfig()
|
con, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetConnection("", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
dest := cfg.Engine.ServiceDestinations[cfg.Engine.ActiveService].URI
|
|
||||||
uri, err := url.Parse(dest)
|
uri, err := url.Parse(con.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ func Execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// readRemoteCliFlags reads cli flags related to operating podman remotely
|
// readRemoteCliFlags reads cli flags related to operating podman remotely
|
||||||
func readRemoteCliFlags(cmd *cobra.Command, podmanConfig *entities.PodmanConfig) (err error) {
|
func readRemoteCliFlags(cmd *cobra.Command, podmanConfig *entities.PodmanConfig) error {
|
||||||
conf := podmanConfig.ContainersConfDefaultsRO
|
conf := podmanConfig.ContainersConfDefaultsRO
|
||||||
contextConn, host := cmd.Root().LocalFlags().Lookup("context"), cmd.Root().LocalFlags().Lookup("host")
|
contextConn, host := cmd.Root().LocalFlags().Lookup("context"), cmd.Root().LocalFlags().Lookup("host")
|
||||||
conn, url := cmd.Root().LocalFlags().Lookup("connection"), cmd.Root().LocalFlags().Lookup("url")
|
conn, url := cmd.Root().LocalFlags().Lookup("connection"), cmd.Root().LocalFlags().Lookup("url")
|
||||||
|
@ -151,35 +151,32 @@ func readRemoteCliFlags(cmd *cobra.Command, podmanConfig *entities.PodmanConfig)
|
||||||
switch {
|
switch {
|
||||||
case conn != nil && conn.Changed:
|
case conn != nil && conn.Changed:
|
||||||
if contextConn != nil && contextConn.Changed {
|
if contextConn != nil && contextConn.Changed {
|
||||||
err = fmt.Errorf("use of --connection and --context at the same time is not allowed")
|
return fmt.Errorf("use of --connection and --context at the same time is not allowed")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if dest, ok := conf.Engine.ServiceDestinations[conn.Value.String()]; ok {
|
con, err := conf.GetConnection(conn.Value.String(), false)
|
||||||
podmanConfig.URI = dest.URI
|
if err != nil {
|
||||||
podmanConfig.Identity = dest.Identity
|
return err
|
||||||
podmanConfig.MachineMode = dest.IsMachine
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("connection %q not found", conn.Value.String())
|
podmanConfig.URI = con.URI
|
||||||
return
|
podmanConfig.Identity = con.Identity
|
||||||
|
podmanConfig.MachineMode = con.IsMachine
|
||||||
case url.Changed:
|
case url.Changed:
|
||||||
podmanConfig.URI = url.Value.String()
|
podmanConfig.URI = url.Value.String()
|
||||||
return
|
|
||||||
case contextConn != nil && contextConn.Changed:
|
case contextConn != nil && contextConn.Changed:
|
||||||
service := contextConn.Value.String()
|
service := contextConn.Value.String()
|
||||||
if service != "default" {
|
if service != "default" {
|
||||||
if dest, ok := conf.Engine.ServiceDestinations[contextConn.Value.String()]; ok {
|
con, err := conf.GetConnection(service, false)
|
||||||
podmanConfig.URI = dest.URI
|
if err != nil {
|
||||||
podmanConfig.Identity = dest.Identity
|
return err
|
||||||
podmanConfig.MachineMode = dest.IsMachine
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("connection %q not found", service)
|
podmanConfig.URI = con.URI
|
||||||
|
podmanConfig.Identity = con.Identity
|
||||||
|
podmanConfig.MachineMode = con.IsMachine
|
||||||
}
|
}
|
||||||
case host.Changed:
|
case host.Changed:
|
||||||
podmanConfig.URI = host.Value.String()
|
podmanConfig.URI = host.Value.String()
|
||||||
}
|
}
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupRemoteConnection returns information about the active service destination
|
// setupRemoteConnection returns information about the active service destination
|
||||||
|
@ -191,29 +188,31 @@ func readRemoteCliFlags(cmd *cobra.Command, podmanConfig *entities.PodmanConfig)
|
||||||
func setupRemoteConnection(podmanConfig *entities.PodmanConfig) error {
|
func setupRemoteConnection(podmanConfig *entities.PodmanConfig) error {
|
||||||
conf := podmanConfig.ContainersConfDefaultsRO
|
conf := podmanConfig.ContainersConfDefaultsRO
|
||||||
connEnv, hostEnv, sshkeyEnv := os.Getenv("CONTAINER_CONNECTION"), os.Getenv("CONTAINER_HOST"), os.Getenv("CONTAINER_SSHKEY")
|
connEnv, hostEnv, sshkeyEnv := os.Getenv("CONTAINER_CONNECTION"), os.Getenv("CONTAINER_HOST"), os.Getenv("CONTAINER_SSHKEY")
|
||||||
dest, destFound := conf.Engine.ServiceDestinations[conf.Engine.ActiveService]
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case connEnv != "":
|
case connEnv != "":
|
||||||
if ConnEnvDest, ok := conf.Engine.ServiceDestinations[connEnv]; ok {
|
con, err := conf.GetConnection(connEnv, false)
|
||||||
podmanConfig.URI = ConnEnvDest.URI
|
if err != nil {
|
||||||
podmanConfig.Identity = ConnEnvDest.Identity
|
return err
|
||||||
podmanConfig.MachineMode = ConnEnvDest.IsMachine
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("connection %q not found", connEnv)
|
podmanConfig.URI = con.URI
|
||||||
|
podmanConfig.Identity = con.Identity
|
||||||
|
podmanConfig.MachineMode = con.IsMachine
|
||||||
case hostEnv != "":
|
case hostEnv != "":
|
||||||
if sshkeyEnv != "" {
|
if sshkeyEnv != "" {
|
||||||
podmanConfig.Identity = sshkeyEnv
|
podmanConfig.Identity = sshkeyEnv
|
||||||
}
|
}
|
||||||
podmanConfig.URI = hostEnv
|
podmanConfig.URI = hostEnv
|
||||||
case destFound:
|
|
||||||
podmanConfig.URI = dest.URI
|
|
||||||
podmanConfig.Identity = dest.Identity
|
|
||||||
podmanConfig.MachineMode = dest.IsMachine
|
|
||||||
default:
|
default:
|
||||||
|
con, err := conf.GetConnection("", true)
|
||||||
|
if err == nil {
|
||||||
|
podmanConfig.URI = con.URI
|
||||||
|
podmanConfig.Identity = con.Identity
|
||||||
|
podmanConfig.MachineMode = con.IsMachine
|
||||||
|
} else {
|
||||||
podmanConfig.URI = registry.DefaultAPIAddress()
|
podmanConfig.URI = registry.DefaultAPIAddress()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,49 +176,39 @@ func add(cmd *cobra.Command, args []string) error {
|
||||||
logrus.Warnf("%q unknown scheme, no validation provided", uri.Scheme)
|
logrus.Warnf("%q unknown scheme, no validation provided", uri.Scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.Flags().Changed("default") {
|
|
||||||
if cOpts.Default {
|
|
||||||
cfg.Engine.ActiveService = args[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dst := config.Destination{
|
dst := config.Destination{
|
||||||
URI: uri.String(),
|
URI: uri.String(),
|
||||||
|
Identity: cOpts.Identity,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Flags().Changed("identity") {
|
connection := args[0]
|
||||||
dst.Identity = cOpts.Identity
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
|
if cOpts.Default {
|
||||||
|
cfg.Connection.Default = connection
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Engine.ServiceDestinations == nil {
|
if cfg.Connection.Connections == nil {
|
||||||
cfg.Engine.ServiceDestinations = map[string]config.Destination{
|
cfg.Connection.Connections = map[string]config.Destination{
|
||||||
args[0]: dst,
|
connection: dst,
|
||||||
}
|
}
|
||||||
cfg.Engine.ActiveService = args[0]
|
cfg.Connection.Default = connection
|
||||||
} else {
|
} else {
|
||||||
cfg.Engine.ServiceDestinations[args[0]] = dst
|
cfg.Connection.Connections[connection] = dst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create or update an existing farm with the connection being added
|
||||||
if cOpts.Farm != "" {
|
if cOpts.Farm != "" {
|
||||||
if cfg.Farms.List == nil {
|
if len(cfg.Farm.List) == 0 {
|
||||||
cfg.Farms.List = map[string][]string{
|
cfg.Farm.Default = cOpts.Farm
|
||||||
cOpts.Farm: {args[0]},
|
|
||||||
}
|
}
|
||||||
cfg.Farms.Default = cOpts.Farm
|
if val, ok := cfg.Farm.List[cOpts.Farm]; ok {
|
||||||
|
cfg.Farm.List[cOpts.Farm] = append(val, connection)
|
||||||
} else {
|
} else {
|
||||||
if val, ok := cfg.Farms.List[cOpts.Farm]; ok {
|
cfg.Farm.List[cOpts.Farm] = []string{connection}
|
||||||
cfg.Farms.List[cOpts.Farm] = append(val, args[0])
|
|
||||||
} else {
|
|
||||||
cfg.Farms.List[cOpts.Farm] = []string{args[0]}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return nil
|
||||||
return cfg.Write()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(cmd *cobra.Command, args []string) error {
|
func create(cmd *cobra.Command, args []string) error {
|
||||||
|
@ -237,24 +227,21 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dst := config.Destination{
|
dst := config.Destination{
|
||||||
URI: uri.String(),
|
URI: uri.String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Engine.ServiceDestinations == nil {
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
cfg.Engine.ServiceDestinations = map[string]config.Destination{
|
if cfg.Connection.Connections == nil {
|
||||||
|
cfg.Connection.Connections = map[string]config.Destination{
|
||||||
args[0]: dst,
|
args[0]: dst,
|
||||||
}
|
}
|
||||||
cfg.Engine.ActiveService = args[0]
|
cfg.Connection.Default = args[0]
|
||||||
} else {
|
} else {
|
||||||
cfg.Engine.ServiceDestinations[args[0]] = dst
|
cfg.Connection.Connections[args[0]] = dst
|
||||||
}
|
}
|
||||||
return cfg.Write()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateDest(path string) (string, error) {
|
func translateDest(path string) (string, error) {
|
||||||
|
|
|
@ -45,15 +45,13 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultRunE(cmd *cobra.Command, args []string) error {
|
func defaultRunE(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
connection := args[0]
|
||||||
if err != nil {
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
return err
|
if _, found := cfg.Connection.Connections[connection]; !found {
|
||||||
|
return fmt.Errorf("%q destination is not defined. See \"podman system connection add ...\" to create a connection", connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, found := cfg.Engine.ServiceDestinations[args[0]]; !found {
|
cfg.Connection.Default = connection
|
||||||
return fmt.Errorf("%q destination is not defined. See \"podman system connection add ...\" to create a connection", args[0])
|
return nil
|
||||||
}
|
})
|
||||||
|
|
||||||
cfg.Engine.ActiveService = args[0]
|
|
||||||
return cfg.Write()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
initFlags := func(cmd *cobra.Command) {
|
initFlags := func(cmd *cobra.Command) {
|
||||||
cmd.Flags().StringP("format", "f", "", "Custom Go template for printing connections")
|
cmd.Flags().StringP("format", "f", "", "Custom Go template for printing connections")
|
||||||
_ = cmd.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(&namedDestination{}))
|
_ = cmd.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(&config.Connection{}))
|
||||||
cmd.Flags().BoolP("quiet", "q", false, "Custom Go template for printing connections")
|
cmd.Flags().BoolP("quiet", "q", false, "Custom Go template for printing connections")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,22 +62,11 @@ func init() {
|
||||||
initFlags(inspectCmd)
|
initFlags(inspectCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
type namedDestination struct {
|
|
||||||
Name string
|
|
||||||
config.Destination
|
|
||||||
Default bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func list(cmd *cobra.Command, _ []string) error {
|
func list(cmd *cobra.Command, _ []string) error {
|
||||||
return inspect(cmd, nil)
|
return inspect(cmd, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspect(cmd *cobra.Command, args []string) error {
|
func inspect(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
format := cmd.Flag("format").Value.String()
|
format := cmd.Flag("format").Value.String()
|
||||||
if format == "" && args != nil {
|
if format == "" && args != nil {
|
||||||
format = "json"
|
format = "json"
|
||||||
|
@ -87,31 +76,23 @@ func inspect(cmd *cobra.Command, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows := make([]namedDestination, 0)
|
|
||||||
for k, v := range cfg.Engine.ServiceDestinations {
|
cons, err := registry.PodmanConfig().ContainersConfDefaultsRO.GetAllConnections()
|
||||||
if args != nil && !slices.Contains(args, k) {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rows := make([]config.Connection, 0, len(cons))
|
||||||
|
for _, con := range cons {
|
||||||
|
if args != nil && !slices.Contains(args, con.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if quiet {
|
if quiet {
|
||||||
fmt.Println(k)
|
fmt.Println(con.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
def := false
|
|
||||||
if k == cfg.Engine.ActiveService {
|
|
||||||
def = true
|
|
||||||
}
|
|
||||||
|
|
||||||
r := namedDestination{
|
rows = append(rows, con)
|
||||||
Name: k,
|
|
||||||
Destination: config.Destination{
|
|
||||||
Identity: v.Identity,
|
|
||||||
URI: v.URI,
|
|
||||||
IsMachine: v.IsMachine,
|
|
||||||
},
|
|
||||||
Default: def,
|
|
||||||
}
|
|
||||||
rows = append(rows, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if quiet {
|
if quiet {
|
||||||
|
@ -137,7 +118,7 @@ func inspect(cmd *cobra.Command, args []string) error {
|
||||||
rpt, err = rpt.Parse(report.OriginUser, format)
|
rpt, err = rpt.Parse(report.OriginUser, format)
|
||||||
} else {
|
} else {
|
||||||
rpt, err = rpt.Parse(report.OriginPodman,
|
rpt, err = rpt.Parse(report.OriginPodman,
|
||||||
"{{range .}}{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\n{{end -}}")
|
"{{range .}}{{.Name}}\t{{.URI}}\t{{.Identity}}\t{{.Default}}\t{{.ReadWrite}}\n{{end -}}")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -149,6 +130,7 @@ func inspect(cmd *cobra.Command, args []string) error {
|
||||||
"Identity": "Identity",
|
"Identity": "Identity",
|
||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"URI": "URI",
|
"URI": "URI",
|
||||||
|
"ReadWrite": "ReadWrite",
|
||||||
}})
|
}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -48,43 +48,35 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func rm(cmd *cobra.Command, args []string) error {
|
func rm(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rmOpts.All {
|
if rmOpts.All {
|
||||||
for k := range cfg.Engine.ServiceDestinations {
|
cfg.Connection.Connections = nil
|
||||||
delete(cfg.Engine.ServiceDestinations, k)
|
cfg.Connection.Default = ""
|
||||||
}
|
|
||||||
cfg.Engine.ActiveService = ""
|
|
||||||
|
|
||||||
// Clear all the connections in any existing farms
|
// Clear all the connections in any existing farms
|
||||||
for k := range cfg.Farms.List {
|
for k := range cfg.Farm.List {
|
||||||
cfg.Farms.List[k] = []string{}
|
cfg.Farm.List[k] = []string{}
|
||||||
}
|
}
|
||||||
return cfg.Write()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return errors.New("accepts 1 arg(s), received 0")
|
return errors.New("accepts 1 arg(s), received 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Engine.ServiceDestinations != nil {
|
delete(cfg.Connection.Connections, args[0])
|
||||||
delete(cfg.Engine.ServiceDestinations, args[0])
|
if cfg.Connection.Default == args[0] {
|
||||||
}
|
cfg.Connection.Default = ""
|
||||||
|
|
||||||
if cfg.Engine.ActiveService == args[0] {
|
|
||||||
cfg.Engine.ActiveService = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are existing farm, remove the deleted connection that might be part of a farm
|
// If there are existing farm, remove the deleted connection that might be part of a farm
|
||||||
for k, v := range cfg.Farms.List {
|
for k, v := range cfg.Farm.List {
|
||||||
index := slices.Index(v, args[0])
|
index := slices.Index(v, args[0])
|
||||||
if index > -1 {
|
if index > -1 {
|
||||||
cfg.Farms.List[k] = append(v[:index], v[index+1:]...)
|
cfg.Farm.List[k] = append(v[:index], v[index+1:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg.Write()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,21 +33,18 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func rename(cmd *cobra.Command, args []string) error {
|
func rename(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if err != nil {
|
if _, found := cfg.Connection.Connections[args[0]]; !found {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, found := cfg.Engine.ServiceDestinations[args[0]]; !found {
|
|
||||||
return fmt.Errorf("%q destination is not defined. See \"podman system connection add ...\" to create a connection", args[0])
|
return fmt.Errorf("%q destination is not defined. See \"podman system connection add ...\" to create a connection", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Engine.ServiceDestinations[args[1]] = cfg.Engine.ServiceDestinations[args[0]]
|
cfg.Connection.Connections[args[1]] = cfg.Connection.Connections[args[0]]
|
||||||
delete(cfg.Engine.ServiceDestinations, args[0])
|
delete(cfg.Connection.Connections, args[0])
|
||||||
|
|
||||||
if cfg.Engine.ActiveService == args[0] {
|
if cfg.Connection.Default == args[0] {
|
||||||
cfg.Engine.ActiveService = args[1]
|
cfg.Connection.Default = args[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg.Write()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,17 +19,18 @@ Change the default output format. This can be of a supported type like 'json' o
|
||||||
Valid placeholders for the Go template listed below:
|
Valid placeholders for the Go template listed below:
|
||||||
|
|
||||||
| **Placeholder** | **Description** |
|
| **Placeholder** | **Description** |
|
||||||
| --------------- | ------------------------------------------ |
|
| --------------- | --------------------------------------------------------------------- |
|
||||||
| .Connections | List of all system connections in the farm |
|
| .Connections | List of all system connections in the farm |
|
||||||
| .Default | Indicates whether farm is the default |
|
| .Default | Indicates whether farm is the default |
|
||||||
| .Name | Farm name |
|
| .Name | Farm name |
|
||||||
|
| .ReadWrite | Indicates if this farm can be modified using the podman farm commands |
|
||||||
|
|
||||||
## EXAMPLE
|
## EXAMPLE
|
||||||
```
|
```
|
||||||
$ podman farm list
|
$ podman farm list
|
||||||
Name Connections Default
|
Name Connections Default ReadWrite
|
||||||
farm1 [f38 f37] false
|
farm1 [f38 f37] false true
|
||||||
farm2 [f37] true
|
farm2 [f37] true true
|
||||||
```
|
```
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
**[podman(1)](podman.1.md)**, **[podman-farm(1)](podman-farm.1.md)**
|
**[podman(1)](podman.1.md)**, **[podman-farm(1)](podman-farm.1.md)**
|
||||||
|
|
|
@ -23,6 +23,7 @@ Valid placeholders for the Go template listed below:
|
||||||
| .Default | Indicates whether connection is the default |
|
| .Default | Indicates whether connection is the default |
|
||||||
| .Identity | Path to file containing SSH identity |
|
| .Identity | Path to file containing SSH identity |
|
||||||
| .Name | Connection Name/Identifier |
|
| .Name | Connection Name/Identifier |
|
||||||
|
| .ReadWrite | Indicates if this connection can be modified using the system connection commands |
|
||||||
| .URI | URI to podman service. Valid schemes are ssh://[user@]*host*[:port]*Unix domain socket*[?secure=True], unix://*Unix domain socket*, and tcp://localhost[:*port*] |
|
| .URI | URI to podman service. Valid schemes are ssh://[user@]*host*[:port]*Unix domain socket*[?secure=True], unix://*Unix domain socket*, and tcp://localhost[:*port*] |
|
||||||
|
|
||||||
#### **--quiet**, **-q**
|
#### **--quiet**, **-q**
|
||||||
|
@ -32,9 +33,9 @@ Only show connection names
|
||||||
## EXAMPLE
|
## EXAMPLE
|
||||||
```
|
```
|
||||||
$ podman system connection list
|
$ podman system connection list
|
||||||
Name URI Identity Default
|
Name URI Identity Default ReadWrite
|
||||||
devl ssh://root@example.com:/run/podman/podman.sock ~/.ssh/id_rsa True
|
deva ssh://root@example.com:/run/podman/podman.sock ~/.ssh/id_rsa true true
|
||||||
devl ssh://user@example.com:/run/user/1000/podman/podman.sock ~/.ssh/id_rsa False
|
devb ssh://user@example.com:/run/user/1000/podman/podman.sock ~/.ssh/id_rsa false true
|
||||||
```
|
```
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
**[podman(1)](podman.1.md)**, **[podman-system(1)](podman-system.1.md)**, **[podman-system-connection(1)](podman-system-connection.1.md)**
|
**[podman(1)](podman.1.md)**, **[podman-system(1)](podman-system.1.md)**, **[podman-system-connection(1)](podman-system-connection.1.md)**
|
||||||
|
|
|
@ -252,6 +252,11 @@ Set default `--url` value to access Podman service. Automatically enables --remo
|
||||||
|
|
||||||
Set default `--identity` path to ssh key file value used to access Podman service.
|
Set default `--identity` path to ssh key file value used to access Podman service.
|
||||||
|
|
||||||
|
#### **PODMAN_CONNECTIONS_CONF**
|
||||||
|
|
||||||
|
The path to the file where the system connections and farms created with `podman system connection add`
|
||||||
|
and `podman farm add` are stored, by default it uses `~/.config/containers/podman-connections.conf`.
|
||||||
|
|
||||||
#### **STORAGE_DRIVER**
|
#### **STORAGE_DRIVER**
|
||||||
|
|
||||||
Set default `--storage-driver` value.
|
Set default `--storage-driver` value.
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -11,14 +11,14 @@ require (
|
||||||
github.com/checkpoint-restore/go-criu/v7 v7.0.0
|
github.com/checkpoint-restore/go-criu/v7 v7.0.0
|
||||||
github.com/containernetworking/plugins v1.4.0
|
github.com/containernetworking/plugins v1.4.0
|
||||||
github.com/containers/buildah v1.33.2-0.20231121195905-d1a1c53c8e1c
|
github.com/containers/buildah v1.33.2-0.20231121195905-d1a1c53c8e1c
|
||||||
github.com/containers/common v0.57.1-0.20240129201029-3310a75e3608
|
github.com/containers/common v0.57.1-0.20240130143645-b26099256b92
|
||||||
github.com/containers/conmon v2.0.20+incompatible
|
github.com/containers/conmon v2.0.20+incompatible
|
||||||
github.com/containers/gvisor-tap-vsock v0.7.2
|
github.com/containers/gvisor-tap-vsock v0.7.2
|
||||||
github.com/containers/image/v5 v5.29.2-0.20240129204525-816800b5daf7
|
github.com/containers/image/v5 v5.29.2-0.20240130233108-e66a1ade2efc
|
||||||
github.com/containers/libhvee v0.6.0
|
github.com/containers/libhvee v0.6.0
|
||||||
github.com/containers/ocicrypt v1.1.9
|
github.com/containers/ocicrypt v1.1.9
|
||||||
github.com/containers/psgo v1.8.0
|
github.com/containers/psgo v1.8.0
|
||||||
github.com/containers/storage v1.52.1-0.20240129173630-7a525ce0e2bc
|
github.com/containers/storage v1.52.1-0.20240130205044-62997abeaf2f
|
||||||
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09
|
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09
|
||||||
github.com/coreos/stream-metadata-go v0.4.4
|
github.com/coreos/stream-metadata-go v0.4.4
|
||||||
github.com/crc-org/vfkit v0.5.0
|
github.com/crc-org/vfkit v0.5.0
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -257,14 +257,14 @@ github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7w
|
||||||
github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0=
|
github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0=
|
||||||
github.com/containers/buildah v1.33.2-0.20231121195905-d1a1c53c8e1c h1:E7nxvH3N3kpyson0waJv1X+eY9hAs+x2zQswsK+//yY=
|
github.com/containers/buildah v1.33.2-0.20231121195905-d1a1c53c8e1c h1:E7nxvH3N3kpyson0waJv1X+eY9hAs+x2zQswsK+//yY=
|
||||||
github.com/containers/buildah v1.33.2-0.20231121195905-d1a1c53c8e1c/go.mod h1:oMNfVrZGEfWVOxXTNOYPMdZzDfSo2umURK/TO0d8TRk=
|
github.com/containers/buildah v1.33.2-0.20231121195905-d1a1c53c8e1c/go.mod h1:oMNfVrZGEfWVOxXTNOYPMdZzDfSo2umURK/TO0d8TRk=
|
||||||
github.com/containers/common v0.57.1-0.20240129201029-3310a75e3608 h1:P+3HLEBeuFr/XcFtyZIS8uk5zdbcvtrHKCSzHlUUbdY=
|
github.com/containers/common v0.57.1-0.20240130143645-b26099256b92 h1:Q60+ofGhDjVxY5lvYmmcVN8aeS9gtQ6pAn/pyLh7rRM=
|
||||||
github.com/containers/common v0.57.1-0.20240129201029-3310a75e3608/go.mod h1:Na7hGh5WnmB0RdGkKyb6JQb6DtKrs5qoIGrPucuR8t0=
|
github.com/containers/common v0.57.1-0.20240130143645-b26099256b92/go.mod h1:Na7hGh5WnmB0RdGkKyb6JQb6DtKrs5qoIGrPucuR8t0=
|
||||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||||
github.com/containers/gvisor-tap-vsock v0.7.2 h1:6CyU5D85C0/DciRRd7W0bPljK4FAS+DPrrHEQMHfZKY=
|
github.com/containers/gvisor-tap-vsock v0.7.2 h1:6CyU5D85C0/DciRRd7W0bPljK4FAS+DPrrHEQMHfZKY=
|
||||||
github.com/containers/gvisor-tap-vsock v0.7.2/go.mod h1:6NiTxh2GCVxZQLPzfuEB78/Osp2Usd9uf6nLdd6PiUY=
|
github.com/containers/gvisor-tap-vsock v0.7.2/go.mod h1:6NiTxh2GCVxZQLPzfuEB78/Osp2Usd9uf6nLdd6PiUY=
|
||||||
github.com/containers/image/v5 v5.29.2-0.20240129204525-816800b5daf7 h1:xnnFpYdUjDn2MZYXmvcopGEvWVO/J0V8OexEnlnIGf0=
|
github.com/containers/image/v5 v5.29.2-0.20240130233108-e66a1ade2efc h1:3I5+mrrG7Fuv4aA13t1hAMQcjN3rTAQInfbxa5P+XH4=
|
||||||
github.com/containers/image/v5 v5.29.2-0.20240129204525-816800b5daf7/go.mod h1:op1w+ftmdbE3UNW/6as8mruL1i5AMq6nH+btNOykMcU=
|
github.com/containers/image/v5 v5.29.2-0.20240130233108-e66a1ade2efc/go.mod h1:oMMRA6avp1Na54lVPCj/OvcfXDMLlzfy3H7xeRiWmmI=
|
||||||
github.com/containers/libhvee v0.6.0 h1:tUzwSz8R0GjR6IctgDnkTMjdtCk5Mxhpai4Vyv6UeF4=
|
github.com/containers/libhvee v0.6.0 h1:tUzwSz8R0GjR6IctgDnkTMjdtCk5Mxhpai4Vyv6UeF4=
|
||||||
github.com/containers/libhvee v0.6.0/go.mod h1:f/q1wCdQqOLiK3IZqqBfOD7exMZYBU5pDYsrMa/pSFg=
|
github.com/containers/libhvee v0.6.0/go.mod h1:f/q1wCdQqOLiK3IZqqBfOD7exMZYBU5pDYsrMa/pSFg=
|
||||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
||||||
|
@ -279,8 +279,8 @@ github.com/containers/ocicrypt v1.1.9/go.mod h1:dTKx1918d8TDkxXvarscpNVY+lyPakPN
|
||||||
github.com/containers/psgo v1.8.0 h1:2loGekmGAxM9ir5OsXWEfGwFxorMPYnc6gEDsGFQvhY=
|
github.com/containers/psgo v1.8.0 h1:2loGekmGAxM9ir5OsXWEfGwFxorMPYnc6gEDsGFQvhY=
|
||||||
github.com/containers/psgo v1.8.0/go.mod h1:T8ZxnX3Ur4RvnhxFJ7t8xJ1F48RhiZB4rSrOaR/qGHc=
|
github.com/containers/psgo v1.8.0/go.mod h1:T8ZxnX3Ur4RvnhxFJ7t8xJ1F48RhiZB4rSrOaR/qGHc=
|
||||||
github.com/containers/storage v1.43.0/go.mod h1:uZ147thiIFGdVTjMmIw19knttQnUCl3y9zjreHrg11s=
|
github.com/containers/storage v1.43.0/go.mod h1:uZ147thiIFGdVTjMmIw19knttQnUCl3y9zjreHrg11s=
|
||||||
github.com/containers/storage v1.52.1-0.20240129173630-7a525ce0e2bc h1:Cfv5hg2OtNZnIZLfOVmLjObX0DuJb+aqkTl+2+dNweA=
|
github.com/containers/storage v1.52.1-0.20240130205044-62997abeaf2f h1:BJSLHe7f1tgu53d8mGIK/y2KhEev5lggWlIk1rWYT7k=
|
||||||
github.com/containers/storage v1.52.1-0.20240129173630-7a525ce0e2bc/go.mod h1:T/ZMocbhShnMLIF0pdkiLPwpkwlGlyUWJeSXnfC/uew=
|
github.com/containers/storage v1.52.1-0.20240130205044-62997abeaf2f/go.mod h1:T/ZMocbhShnMLIF0pdkiLPwpkwlGlyUWJeSXnfC/uew=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||||
|
|
|
@ -33,11 +33,6 @@ func ExecuteTransfer(src, dst string, parentFlags []string, quiet bool, sshMode
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
confR, err := config.New(nil) // create a hand made config for the remote engine since we might use remote and native at once
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, nil, fmt.Errorf("could not make config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
locations := []*entities.ImageScpOptions{}
|
locations := []*entities.ImageScpOptions{}
|
||||||
cliConnections := []string{}
|
cliConnections := []string{}
|
||||||
args := []string{src}
|
args := []string{src}
|
||||||
|
@ -84,17 +79,15 @@ func ExecuteTransfer(src, dst string, parentFlags []string, quiet bool, sshMode
|
||||||
cliConnections = []string{}
|
cliConnections = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig() // get ready to set ssh destination if necessary
|
cfg, err := config.Default()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
var serv map[string]config.Destination
|
err = GetServiceInformation(&sshInfo, cliConnections, cfg)
|
||||||
serv, err = GetServiceInformation(&sshInfo, cliConnections, cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
confR.Engine = config.EngineConfig{Remote: true, CgroupManager: "cgroupfs", ServiceDestinations: serv} // pass the service dest (either remote or something else) to engine
|
|
||||||
saveCmd, loadCmd := CreateCommands(source, dest, parentFlags, podman)
|
saveCmd, loadCmd := CreateCommands(source, dest, parentFlags, podman)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -401,15 +394,15 @@ func RemoteArgLength(input string, side int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetServiceInformation takes the parsed list of hosts to connect to and validates the information
|
// GetServiceInformation takes the parsed list of hosts to connect to and validates the information
|
||||||
func GetServiceInformation(sshInfo *entities.ImageScpConnections, cliConnections []string, cfg *config.Config) (map[string]config.Destination, error) {
|
func GetServiceInformation(sshInfo *entities.ImageScpConnections, cliConnections []string, cfg *config.Config) error {
|
||||||
var serv map[string]config.Destination
|
|
||||||
var urlS string
|
var urlS string
|
||||||
var iden string
|
var iden string
|
||||||
for i, val := range cliConnections {
|
for i, val := range cliConnections {
|
||||||
connection, _, _ := strings.Cut(val, "::")
|
connection, _, _ := strings.Cut(val, "::")
|
||||||
sshInfo.Connections = append(sshInfo.Connections, connection)
|
sshInfo.Connections = append(sshInfo.Connections, connection)
|
||||||
conn, found := cfg.Engine.ServiceDestinations[sshInfo.Connections[i]]
|
conn, err := cfg.GetConnection(sshInfo.Connections[i], false)
|
||||||
if found {
|
if err == nil {
|
||||||
|
// connection found
|
||||||
urlS = conn.URI
|
urlS = conn.URI
|
||||||
iden = conn.Identity
|
iden = conn.Identity
|
||||||
} else { // no match, warn user and do a manual connection.
|
} else { // no match, warn user and do a manual connection.
|
||||||
|
@ -419,17 +412,17 @@ func GetServiceInformation(sshInfo *entities.ImageScpConnections, cliConnections
|
||||||
}
|
}
|
||||||
urlFinal, err := url.Parse(urlS) // create an actual url to pass to exec command
|
urlFinal, err := url.Parse(urlS) // create an actual url to pass to exec command
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
if urlFinal.User.Username() == "" {
|
if urlFinal.User.Username() == "" {
|
||||||
if urlFinal.User, err = GetUserInfo(urlFinal); err != nil {
|
if urlFinal.User, err = GetUserInfo(urlFinal); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sshInfo.URI = append(sshInfo.URI, urlFinal)
|
sshInfo.URI = append(sshInfo.URI, urlFinal)
|
||||||
sshInfo.Identities = append(sshInfo.Identities, iden)
|
sshInfo.Identities = append(sshInfo.Identities, iden)
|
||||||
}
|
}
|
||||||
return serv, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserInfo(uri *url.URL) (*url.Userinfo, error) {
|
func GetUserInfo(uri *url.URL) (*url.Userinfo, error) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ type Schedule struct {
|
||||||
platformBuilders map[string]string // target->connection
|
platformBuilders map[string]string // target->connection
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFarmWithBuilders(_ context.Context, name string, destinations *map[string]config.Destination, localEngine entities.ImageEngine, buildLocal bool) (*Farm, error) {
|
func newFarmWithBuilders(_ context.Context, name string, cons []config.Connection, localEngine entities.ImageEngine, buildLocal bool) (*Farm, error) {
|
||||||
farm := &Farm{
|
farm := &Farm{
|
||||||
builders: make(map[string]entities.ImageEngine),
|
builders: make(map[string]entities.ImageEngine),
|
||||||
localEngine: localEngine,
|
localEngine: localEngine,
|
||||||
|
@ -43,22 +43,22 @@ func newFarmWithBuilders(_ context.Context, name string, destinations *map[strin
|
||||||
builderGroup multierror.Group
|
builderGroup multierror.Group
|
||||||
)
|
)
|
||||||
// Set up the remote connections to handle the builds
|
// Set up the remote connections to handle the builds
|
||||||
for name, dest := range *destinations {
|
for _, con := range cons {
|
||||||
name, dest := name, dest
|
con := con
|
||||||
builderGroup.Go(func() error {
|
builderGroup.Go(func() error {
|
||||||
fmt.Printf("Connecting to %q\n", name)
|
fmt.Printf("Connecting to %q\n", con.Name)
|
||||||
engine, err := infra.NewImageEngine(&entities.PodmanConfig{
|
engine, err := infra.NewImageEngine(&entities.PodmanConfig{
|
||||||
EngineMode: entities.TunnelMode,
|
EngineMode: entities.TunnelMode,
|
||||||
URI: dest.URI,
|
URI: con.URI,
|
||||||
Identity: dest.Identity,
|
Identity: con.Identity,
|
||||||
MachineMode: dest.IsMachine,
|
MachineMode: con.IsMachine,
|
||||||
FarmNodeName: name,
|
FarmNodeName: con.Name,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("initializing image engine at %q: %w", dest.URI, err)
|
return fmt.Errorf("initializing image engine at %q: %w", con.URI, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer fmt.Printf("Builder %q ready\n", name)
|
defer fmt.Printf("Builder %q ready\n", con.Name)
|
||||||
builderMutex.Lock()
|
builderMutex.Lock()
|
||||||
defer builderMutex.Unlock()
|
defer builderMutex.Unlock()
|
||||||
farm.builders[name] = engine
|
farm.builders[name] = engine
|
||||||
|
@ -90,12 +90,12 @@ func newFarmWithBuilders(_ context.Context, name string, destinations *map[strin
|
||||||
|
|
||||||
func NewFarm(ctx context.Context, name string, localEngine entities.ImageEngine, buildLocal bool) (*Farm, error) {
|
func NewFarm(ctx context.Context, name string, localEngine entities.ImageEngine, buildLocal bool) (*Farm, error) {
|
||||||
// Get the destinations of the connections specified in the farm
|
// Get the destinations of the connections specified in the farm
|
||||||
destinations, err := getFarmDestinations(name)
|
name, destinations, err := getFarmDestinations(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newFarmWithBuilders(ctx, name, &destinations, localEngine, buildLocal)
|
return newFarmWithBuilders(ctx, name, destinations, localEngine, buildLocal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done performs any necessary end-of-process cleanup for the farm's members.
|
// Done performs any necessary end-of-process cleanup for the farm's members.
|
||||||
|
@ -460,22 +460,21 @@ func (f *Farm) Build(ctx context.Context, schedule Schedule, options entities.Bu
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFarmDestinations(name string) (map[string]config.Destination, error) {
|
func getFarmDestinations(name string) (string, []config.Connection, error) {
|
||||||
dest := make(map[string]config.Destination)
|
cfg, err := config.Default()
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dest, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no farm name is given, then grab all the service destinations available
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return cfg.Engine.ServiceDestinations, nil
|
if name, cons, err := cfg.GetDefaultFarmConnections(); err == nil {
|
||||||
|
// Use default farm if is there is one
|
||||||
|
return name, cons, nil
|
||||||
}
|
}
|
||||||
|
// If no farm name is given, then grab all the service destinations available
|
||||||
// Go through the connections in the farm and get their destination
|
cons, err := cfg.GetAllConnections()
|
||||||
for _, c := range cfg.Farms.List[name] {
|
return name, cons, err
|
||||||
dest[c] = cfg.Engine.ServiceDestinations[c]
|
|
||||||
}
|
}
|
||||||
|
cons, err := cfg.GetFarmConnections(name)
|
||||||
return dest, nil
|
return name, cons, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,93 +17,81 @@ func AddConnection(uri fmt.Stringer, name, identity string, isDefault bool) erro
|
||||||
if len(identity) < 1 {
|
if len(identity) < 1 {
|
||||||
return errors.New("identity must be defined")
|
return errors.New("identity must be defined")
|
||||||
}
|
}
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
return err
|
if _, ok := cfg.Connection.Connections[name]; ok {
|
||||||
}
|
|
||||||
if _, ok := cfg.Engine.ServiceDestinations[name]; ok {
|
|
||||||
return errors.New("cannot overwrite connection")
|
return errors.New("cannot overwrite connection")
|
||||||
}
|
}
|
||||||
if isDefault {
|
|
||||||
cfg.Engine.ActiveService = name
|
|
||||||
}
|
|
||||||
dst := config.Destination{
|
dst := config.Destination{
|
||||||
URI: uri.String(),
|
URI: uri.String(),
|
||||||
IsMachine: true,
|
IsMachine: true,
|
||||||
|
Identity: identity,
|
||||||
}
|
}
|
||||||
dst.Identity = identity
|
|
||||||
if cfg.Engine.ServiceDestinations == nil {
|
if isDefault {
|
||||||
cfg.Engine.ServiceDestinations = map[string]config.Destination{
|
cfg.Connection.Default = name
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Connection.Connections == nil {
|
||||||
|
cfg.Connection.Connections = map[string]config.Destination{
|
||||||
name: dst,
|
name: dst,
|
||||||
}
|
}
|
||||||
cfg.Engine.ActiveService = name
|
cfg.Connection.Default = name
|
||||||
} else {
|
} else {
|
||||||
cfg.Engine.ServiceDestinations[name] = dst
|
cfg.Connection.Connections[name] = dst
|
||||||
}
|
|
||||||
return cfg.Write()
|
|
||||||
}
|
|
||||||
|
|
||||||
func AnyConnectionDefault(name ...string) (bool, error) {
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
for _, n := range name {
|
|
||||||
if n == cfg.Engine.ActiveService {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeConnectionURI(name string, uri fmt.Stringer) error {
|
func ChangeConnectionURI(name string, uri fmt.Stringer) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if err != nil {
|
dst, ok := cfg.Connection.Connections[name]
|
||||||
return err
|
|
||||||
}
|
|
||||||
dst, ok := cfg.Engine.ServiceDestinations[name]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("connection not found")
|
return errors.New("connection not found")
|
||||||
}
|
}
|
||||||
dst.URI = uri.String()
|
dst.URI = uri.String()
|
||||||
cfg.Engine.ServiceDestinations[name] = dst
|
cfg.Connection.Connections[name] = dst
|
||||||
|
|
||||||
return cfg.Write()
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeDefault(name string) error {
|
// UpdateConnectionIfDefault updates the default connection to the rootful/rootless when depending
|
||||||
cfg, err := config.ReadCustomConfig()
|
// on the bool but only if other rootful/less connection was already the default.
|
||||||
if err != nil {
|
// Returns true if it modified the default
|
||||||
return err
|
func UpdateConnectionIfDefault(rootful bool, name, rootfulName string) error {
|
||||||
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
|
if name == cfg.Connection.Default && rootful {
|
||||||
|
cfg.Connection.Default = rootfulName
|
||||||
|
} else if rootfulName == cfg.Connection.Default && !rootful {
|
||||||
|
cfg.Connection.Default = name
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
cfg.Engine.ActiveService = name
|
})
|
||||||
|
|
||||||
return cfg.Write()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveConnections(names ...string) error {
|
func RemoveConnections(names ...string) error {
|
||||||
cfg, err := config.ReadCustomConfig()
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if _, ok := cfg.Engine.ServiceDestinations[name]; ok {
|
if _, ok := cfg.Connection.Connections[name]; ok {
|
||||||
delete(cfg.Engine.ServiceDestinations, name)
|
delete(cfg.Connection.Connections, name)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("unable to find connection named %q", name)
|
return fmt.Errorf("unable to find connection named %q", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Engine.ActiveService == name {
|
if cfg.Connection.Default == name {
|
||||||
cfg.Engine.ActiveService = ""
|
cfg.Connection.Default = ""
|
||||||
for service := range cfg.Engine.ServiceDestinations {
|
}
|
||||||
cfg.Engine.ActiveService = service
|
}
|
||||||
|
for service := range cfg.Connection.Connections {
|
||||||
|
cfg.Connection.Default = service
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
return nil
|
||||||
}
|
})
|
||||||
return cfg.Write()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeFilesAndConnections removes any files and connections with the given names
|
// removeFilesAndConnections removes any files and connections with the given names
|
||||||
|
|
|
@ -158,22 +158,7 @@ following command in your terminal session:
|
||||||
// SetRootful modifies the machine's default connection to be either rootful or
|
// SetRootful modifies the machine's default connection to be either rootful or
|
||||||
// rootless
|
// rootless
|
||||||
func SetRootful(rootful bool, name, rootfulName string) error {
|
func SetRootful(rootful bool, name, rootfulName string) error {
|
||||||
changeCon, err := AnyConnectionDefault(name, rootfulName)
|
return UpdateConnectionIfDefault(rootful, name, rootfulName)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if changeCon {
|
|
||||||
newDefault := name
|
|
||||||
if rootful {
|
|
||||||
newDefault += "-root"
|
|
||||||
}
|
|
||||||
err := ChangeDefault(newDefault)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteConfig writes the machine's JSON config file
|
// WriteConfig writes the machine's JSON config file
|
||||||
|
|
|
@ -122,6 +122,7 @@ var (
|
||||||
// invalid containers.conf files to fail the cleanup.
|
// invalid containers.conf files to fail the cleanup.
|
||||||
os.Unsetenv("CONTAINERS_CONF")
|
os.Unsetenv("CONTAINERS_CONF")
|
||||||
os.Unsetenv("CONTAINERS_CONF_OVERRIDE")
|
os.Unsetenv("CONTAINERS_CONF_OVERRIDE")
|
||||||
|
os.Unsetenv("PODMAN_CONNECTIONS_CONF")
|
||||||
podmanTest.Cleanup()
|
podmanTest.Cleanup()
|
||||||
f := CurrentSpecReport()
|
f := CurrentSpecReport()
|
||||||
processTestResult(f)
|
processTestResult(f)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
. "github.com/containers/podman/v4/test/utils"
|
. "github.com/containers/podman/v4/test/utils"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
@ -13,21 +12,20 @@ import (
|
||||||
|
|
||||||
func setupContainersConfWithSystemConnections() {
|
func setupContainersConfWithSystemConnections() {
|
||||||
// make sure connections are not written to real user config on host
|
// make sure connections are not written to real user config on host
|
||||||
file := filepath.Join(podmanTest.TempDir, "containersconf")
|
file := filepath.Join(podmanTest.TempDir, "containers.conf")
|
||||||
f, err := os.Create(file)
|
f, err := os.Create(file)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
connections := `
|
|
||||||
[engine]
|
|
||||||
active_service = "QA"
|
|
||||||
[engine.service_destinations]
|
|
||||||
[engine.service_destinations.QA]
|
|
||||||
uri = "ssh://root@podman.test:2222/run/podman/podman.sock"
|
|
||||||
[engine.service_destinations.QB]
|
|
||||||
uri = "ssh://root@podman.test:3333/run/podman/podman.sock"`
|
|
||||||
_, err = f.WriteString(connections)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
f.Close()
|
f.Close()
|
||||||
os.Setenv("CONTAINERS_CONF", file)
|
os.Setenv("CONTAINERS_CONF", file)
|
||||||
|
|
||||||
|
file = filepath.Join(podmanTest.TempDir, "connections.conf")
|
||||||
|
f, err = os.Create(file)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
connections := `{"connection":{"default":"QA","connections":{"QA":{"uri":"ssh://root@podman.test:2222/run/podman/podman.sock"},"QB":{"uri":"ssh://root@podman.test:3333/run/podman/podman.sock"}}}}`
|
||||||
|
_, err = f.WriteString(connections)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
f.Close()
|
||||||
|
os.Setenv("PODMAN_CONNECTIONS_CONF", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Describe("podman farm", func() {
|
var _ = Describe("podman farm", func() {
|
||||||
|
@ -36,19 +34,12 @@ var _ = Describe("podman farm", func() {
|
||||||
|
|
||||||
Context("without running API service", func() {
|
Context("without running API service", func() {
|
||||||
It("verify system connections exist", func() {
|
It("verify system connections exist", func() {
|
||||||
cfg, err := config.ReadCustomConfig()
|
session := podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg).Should(HaveActiveService("QA"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg).Should(VerifyService(
|
Expect(string(session.Out.Contents())).To(Equal(`QA ssh://root@podman.test:2222/run/podman/podman.sock true true
|
||||||
"QA",
|
QB ssh://root@podman.test:3333/run/podman/podman.sock false true
|
||||||
"ssh://root@podman.test:2222/run/podman/podman.sock",
|
`))
|
||||||
"",
|
|
||||||
))
|
|
||||||
Expect(cfg).Should(VerifyService(
|
|
||||||
"QB",
|
|
||||||
"ssh://root@podman.test:3333/run/podman/podman.sock",
|
|
||||||
"",
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("create farm", func() {
|
It("create farm", func() {
|
||||||
|
@ -73,12 +64,13 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm3\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm3\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [QA QB] true true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
farm2 [QA] false true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm3", []string{}))
|
farm3 [] false true
|
||||||
|
`))
|
||||||
|
|
||||||
// create existing farm should exit with error
|
// create existing farm should exit with error
|
||||||
cmd = []string{"farm", "create", "farm3"}
|
cmd = []string{"farm", "create", "farm3"}
|
||||||
|
@ -109,12 +101,13 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm3\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm3\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [QA QB] true true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
farm2 [QA] false true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm3", []string{}))
|
farm3 [] false true
|
||||||
|
`))
|
||||||
|
|
||||||
// update farm1 to remove the QA connection from it
|
// update farm1 to remove the QA connection from it
|
||||||
cmd = []string{"farm", "update", "--remove", "QA,QB", "farm1"}
|
cmd = []string{"farm", "update", "--remove", "QA,QB", "farm1"}
|
||||||
|
@ -137,12 +130,13 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" updated"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" updated"))
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm2"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{}))
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [] false true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
farm2 [QA] true true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm3", []string{"QB"}))
|
farm3 [QB] false true
|
||||||
|
`))
|
||||||
|
|
||||||
// update farm2 to not be the default, no farms should be the default
|
// update farm2 to not be the default, no farms should be the default
|
||||||
cmd = []string{"farm", "update", "--default=false", "farm2"}
|
cmd = []string{"farm", "update", "--default=false", "farm2"}
|
||||||
|
@ -151,9 +145,13 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" updated"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" updated"))
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(BeEmpty())
|
Expect(session).Should(ExitCleanly())
|
||||||
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [] false true
|
||||||
|
farm2 [QA] false true
|
||||||
|
farm3 [QB] false true
|
||||||
|
`))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("update farm with non-existing connections", func() {
|
It("update farm with non-existing connections", func() {
|
||||||
|
@ -171,11 +169,12 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [QA QB] true true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
farm2 [QA] false true
|
||||||
|
`))
|
||||||
|
|
||||||
// update farm1 to add no-node connection to it
|
// update farm1 to add no-node connection to it
|
||||||
cmd = []string{"farm", "update", "--add", "no-node", "farm1"}
|
cmd = []string{"farm", "update", "--add", "no-node", "farm1"}
|
||||||
|
@ -189,12 +188,13 @@ var _ = Describe("podman farm", func() {
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(ExitWithError())
|
Expect(session).Should(ExitWithError())
|
||||||
|
|
||||||
// read config again to ensure that nothing has changed
|
// check again to ensure that nothing has changed
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [QA QB] true true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
farm2 [QA] false true
|
||||||
|
`))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("update non-existent farm", func() {
|
It("update non-existent farm", func() {
|
||||||
|
@ -205,11 +205,6 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm1\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm1\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
|
||||||
|
|
||||||
// update non-existent farm to add QA connection to it
|
// update non-existent farm to add QA connection to it
|
||||||
cmd = []string{"farm", "update", "--add", "no-node", "non-existent"}
|
cmd = []string{"farm", "update", "--add", "no-node", "non-existent"}
|
||||||
session = podmanTest.Podman(cmd)
|
session = podmanTest.Podman(cmd)
|
||||||
|
@ -222,11 +217,10 @@ var _ = Describe("podman farm", func() {
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(ExitWithError())
|
Expect(session).Should(ExitWithError())
|
||||||
|
|
||||||
// read config again and ensure nothing has changed
|
session = podmanTest.Podman(farmListCmd)
|
||||||
cfg, err = config.ReadCustomConfig()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
Expect(session.OutputToString()).To(Equal(`farm1 [QA QB] true true`))
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("remove farms", func() {
|
It("remove farms", func() {
|
||||||
|
@ -244,11 +238,12 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
Expect(string(session.Out.Contents())).To(Equal(`farm1 [QA QB] true true
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
farm2 [QA] false true
|
||||||
|
`))
|
||||||
|
|
||||||
// remove farm1 and a non-existent farm
|
// remove farm1 and a non-existent farm
|
||||||
// farm 1 should be removed and a warning printed for nonexistent-farm
|
// farm 1 should be removed and a warning printed for nonexistent-farm
|
||||||
|
@ -259,11 +254,10 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm1\" deleted"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm1\" deleted"))
|
||||||
Expect(session.ErrorToString()).Should(ContainSubstring("doesn't exist; nothing to remove"))
|
Expect(session.ErrorToString()).Should(ContainSubstring("doesn't exist; nothing to remove"))
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm2"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
Expect(session.OutputToString()).To(Equal(`farm2 [QA] true true`))
|
||||||
Expect(cfg.Farms.List).Should(Not(HaveKey("farm1")))
|
|
||||||
|
|
||||||
// remove all non-existent farms and expect an error
|
// remove all non-existent farms and expect an error
|
||||||
cmd = []string{"farm", "rm", "foo", "bar"}
|
cmd = []string{"farm", "rm", "foo", "bar"}
|
||||||
|
@ -287,12 +281,6 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"farm2\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
Expect(cfg.Farms.Default).Should(Equal("farm1"))
|
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA", "QB"}))
|
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm2", []string{"QA"}))
|
|
||||||
|
|
||||||
// remove --all
|
// remove --all
|
||||||
cmd = []string{"farm", "rm", "--all"}
|
cmd = []string{"farm", "rm", "--all"}
|
||||||
session = podmanTest.Podman(cmd)
|
session = podmanTest.Podman(cmd)
|
||||||
|
@ -300,10 +288,10 @@ var _ = Describe("podman farm", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("All farms have been deleted"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("All farms have been deleted"))
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(farmListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Farms.Default).Should(BeEmpty())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Farms.List).Should(BeEmpty())
|
Expect(session.OutputToString()).To(Equal(""))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
. "github.com/containers/podman/v4/test/utils"
|
. "github.com/containers/podman/v4/test/utils"
|
||||||
"github.com/containers/storage/pkg/homedir"
|
"github.com/containers/storage/pkg/homedir"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
@ -13,7 +12,7 @@ import (
|
||||||
|
|
||||||
var _ = Describe("podman image scp", func() {
|
var _ = Describe("podman image scp", func() {
|
||||||
|
|
||||||
BeforeEach(setupEmptyContainersConf)
|
BeforeEach(setupConnectionsConf)
|
||||||
|
|
||||||
It("podman image scp bogus image", func() {
|
It("podman image scp bogus image", func() {
|
||||||
scp := podmanTest.Podman([]string{"image", "scp", "FOOBAR"})
|
scp := podmanTest.Podman([]string{"image", "scp", "FOOBAR"})
|
||||||
|
@ -34,15 +33,6 @@ var _ = Describe("podman image scp", func() {
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
Expect(cfg.Engine).Should(HaveField("ActiveService", "QA"))
|
|
||||||
Expect(cfg.Engine.ServiceDestinations).To(HaveKeyWithValue("QA",
|
|
||||||
config.Destination{
|
|
||||||
URI: "ssh://root@podman.test:2222/run/podman/podman.sock",
|
|
||||||
},
|
|
||||||
))
|
|
||||||
|
|
||||||
scp := podmanTest.Podman([]string{"image", "scp", ALPINE, "QA::"})
|
scp := podmanTest.Podman([]string{"image", "scp", ALPINE, "QA::"})
|
||||||
scp.WaitWithDefaultTimeout()
|
scp.WaitWithDefaultTimeout()
|
||||||
// exit with error because we cannot make an actual ssh connection
|
// exit with error because we cannot make an actual ssh connection
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
. "github.com/containers/podman/v4/test/utils"
|
. "github.com/containers/podman/v4/test/utils"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
@ -16,18 +15,24 @@ import (
|
||||||
. "github.com/onsi/gomega/gexec"
|
. "github.com/onsi/gomega/gexec"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupEmptyContainersConf() {
|
func setupConnectionsConf() {
|
||||||
// make sure connections are not written to real user config on host
|
// make sure connections are not written to real user config on host
|
||||||
file := filepath.Join(podmanTest.TempDir, "containersconf")
|
file := filepath.Join(podmanTest.TempDir, "containers.conf")
|
||||||
f, err := os.Create(file)
|
f, err := os.Create(file)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
f.Close()
|
f.Close()
|
||||||
os.Setenv("CONTAINERS_CONF", file)
|
os.Setenv("CONTAINERS_CONF", file)
|
||||||
|
|
||||||
|
file = filepath.Join(podmanTest.TempDir, "connections.conf")
|
||||||
|
os.Setenv("PODMAN_CONNECTIONS_CONF", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var systemConnectionListCmd = []string{"system", "connection", "ls", "--format", "{{.Name}} {{.URI}} {{.Identity}} {{.Default}} {{.ReadWrite}}"}
|
||||||
|
var farmListCmd = []string{"farm", "ls", "--format", "{{.Name}} {{.Connections}} {{.Default}} {{.ReadWrite}}"}
|
||||||
|
|
||||||
var _ = Describe("podman system connection", func() {
|
var _ = Describe("podman system connection", func() {
|
||||||
|
|
||||||
BeforeEach(setupEmptyContainersConf)
|
BeforeEach(setupConnectionsConf)
|
||||||
|
|
||||||
Context("without running API service", func() {
|
Context("without running API service", func() {
|
||||||
It("add ssh://", func() {
|
It("add ssh://", func() {
|
||||||
|
@ -42,14 +47,10 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg).Should(HaveActiveService("QA"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg).Should(VerifyService(
|
Expect(session.OutputToString()).To(Equal("QA ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa true true"))
|
||||||
"QA",
|
|
||||||
"ssh://root@podman.test:2222/run/podman/podman.sock",
|
|
||||||
"~/.ssh/id_rsa",
|
|
||||||
))
|
|
||||||
|
|
||||||
cmd = []string{"system", "connection", "rename",
|
cmd = []string{"system", "connection", "rename",
|
||||||
"QA",
|
"QA",
|
||||||
|
@ -59,7 +60,10 @@ var _ = Describe("podman system connection", func() {
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
|
|
||||||
Expect(config.ReadCustomConfig()).Should(HaveActiveService("QE"))
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(ExitCleanly())
|
||||||
|
Expect(session.OutputToString()).To(Equal("QE ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa true true"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("add UDS", func() {
|
It("add UDS", func() {
|
||||||
|
@ -74,11 +78,10 @@ var _ = Describe("podman system connection", func() {
|
||||||
// stderr will probably warn (ENOENT or EACCESS) about socket
|
// stderr will probably warn (ENOENT or EACCESS) about socket
|
||||||
// but it's too unreliable to test for.
|
// but it's too unreliable to test for.
|
||||||
|
|
||||||
Expect(config.ReadCustomConfig()).Should(VerifyService(
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
"QA-UDS",
|
session.WaitWithDefaultTimeout()
|
||||||
"unix:///run/podman/podman.sock",
|
Expect(session).Should(ExitCleanly())
|
||||||
"",
|
Expect(session.OutputToString()).To(Equal("QA-UDS unix:///run/podman/podman.sock true true"))
|
||||||
))
|
|
||||||
|
|
||||||
cmd = []string{"system", "connection", "add",
|
cmd = []string{"system", "connection", "add",
|
||||||
"QA-UDS1",
|
"QA-UDS1",
|
||||||
|
@ -90,12 +93,12 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
Expect(config.ReadCustomConfig()).Should(HaveActiveService("QA-UDS"))
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(config.ReadCustomConfig()).Should(VerifyService(
|
session.WaitWithDefaultTimeout()
|
||||||
"QA-UDS1",
|
Expect(session).Should(ExitCleanly())
|
||||||
"unix:///run/user/podman/podman.sock",
|
Expect(string(session.Out.Contents())).To(Equal(`QA-UDS unix:///run/podman/podman.sock true true
|
||||||
"",
|
QA-UDS1 unix:///run/user/podman/podman.sock false true
|
||||||
))
|
`))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("add tcp", func() {
|
It("add tcp", func() {
|
||||||
|
@ -108,18 +111,13 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
Expect(config.ReadCustomConfig()).Should(VerifyService(
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
"QA-TCP",
|
session.WaitWithDefaultTimeout()
|
||||||
"tcp://localhost:8888",
|
Expect(session).Should(ExitCleanly())
|
||||||
"",
|
Expect(session.OutputToString()).To(Equal("QA-TCP tcp://localhost:8888 true true"))
|
||||||
))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("add to new farm", func() {
|
It("add to new farm", func() {
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
Expect(cfg.Farms.List).Should(BeEmpty())
|
|
||||||
|
|
||||||
cmd := []string{"system", "connection", "add",
|
cmd := []string{"system", "connection", "add",
|
||||||
"--default",
|
"--default",
|
||||||
"--identity", "~/.ssh/id_rsa",
|
"--identity", "~/.ssh/id_rsa",
|
||||||
|
@ -132,15 +130,14 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg).Should(HaveActiveService("QA"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg).Should(VerifyService(
|
Expect(session.OutputToString()).To(Equal("QA ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa true true"))
|
||||||
"QA",
|
session = podmanTest.Podman(farmListCmd)
|
||||||
"ssh://root@podman.test:2222/run/podman/podman.sock",
|
session.WaitWithDefaultTimeout()
|
||||||
"~/.ssh/id_rsa",
|
Expect(session).Should(ExitCleanly())
|
||||||
))
|
Expect(session.OutputToString()).To(Equal("farm1 [QA] true true"))
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA"}))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("add to existing farm", func() {
|
It("add to existing farm", func() {
|
||||||
|
@ -151,10 +148,6 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"empty-farm\" created"))
|
Expect(session.Out.Contents()).Should(ContainSubstring("Farm \"empty-farm\" created"))
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("empty-farm", []string{}))
|
|
||||||
|
|
||||||
cmd = []string{"system", "connection", "add",
|
cmd = []string{"system", "connection", "add",
|
||||||
"--default",
|
"--default",
|
||||||
"--identity", "~/.ssh/id_rsa",
|
"--identity", "~/.ssh/id_rsa",
|
||||||
|
@ -167,22 +160,17 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg).Should(HaveActiveService("QA"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg).Should(VerifyService(
|
Expect(session.OutputToString()).To(Equal("QA ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa true true"))
|
||||||
"QA",
|
session = podmanTest.Podman(farmListCmd)
|
||||||
"ssh://root@podman.test:2222/run/podman/podman.sock",
|
session.WaitWithDefaultTimeout()
|
||||||
"~/.ssh/id_rsa",
|
Expect(session).Should(ExitCleanly())
|
||||||
))
|
Expect(session.OutputToString()).To(Equal("empty-farm [QA] true true"))
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("empty-farm", []string{"QA"}))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("removing connection should remove from farm also", func() {
|
It("removing connection should remove from farm also", func() {
|
||||||
cfg, err := config.ReadCustomConfig()
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
Expect(cfg.Farms.List).Should(BeEmpty())
|
|
||||||
|
|
||||||
cmd := []string{"system", "connection", "add",
|
cmd := []string{"system", "connection", "add",
|
||||||
"--default",
|
"--default",
|
||||||
"--identity", "~/.ssh/id_rsa",
|
"--identity", "~/.ssh/id_rsa",
|
||||||
|
@ -195,15 +183,14 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg).Should(HaveActiveService("QA"))
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg).Should(VerifyService(
|
Expect(session.OutputToString()).To(Equal("QA ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa true true"))
|
||||||
"QA",
|
session = podmanTest.Podman(farmListCmd)
|
||||||
"ssh://root@podman.test:2222/run/podman/podman.sock",
|
session.WaitWithDefaultTimeout()
|
||||||
"~/.ssh/id_rsa",
|
Expect(session).Should(ExitCleanly())
|
||||||
))
|
Expect(session.OutputToString()).To(Equal("farm1 [QA] true true"))
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{"QA"}))
|
|
||||||
|
|
||||||
// Remove the QA connection
|
// Remove the QA connection
|
||||||
session = podmanTest.Podman([]string{"system", "connection", "remove", "QA"})
|
session = podmanTest.Podman([]string{"system", "connection", "remove", "QA"})
|
||||||
|
@ -211,11 +198,14 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
cfg, err = config.ReadCustomConfig()
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Engine.ActiveService).Should(BeEmpty())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty())
|
Expect(session.OutputToString()).To(Equal(""))
|
||||||
Expect(cfg.Farms.List).Should(HaveKeyWithValue("farm1", []string{}))
|
session = podmanTest.Podman(farmListCmd)
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(ExitCleanly())
|
||||||
|
Expect(session.OutputToString()).To(Equal("farm1 [] true true"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("remove", func() {
|
It("remove", func() {
|
||||||
|
@ -235,10 +225,10 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(cfg.Engine.ActiveService).Should(BeEmpty())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty())
|
Expect(session.OutputToString()).To(Equal(""))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -261,6 +251,7 @@ var _ = Describe("podman system connection", func() {
|
||||||
session = podmanTest.Podman([]string{"system", "connection", "list"})
|
session = podmanTest.Podman([]string{"system", "connection", "list"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
|
Expect(session.OutputToStringArray()).To(HaveLen(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("default", func() {
|
It("default", func() {
|
||||||
|
@ -282,19 +273,18 @@ var _ = Describe("podman system connection", func() {
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out.Contents()).Should(BeEmpty())
|
Expect(session.Out.Contents()).Should(BeEmpty())
|
||||||
|
|
||||||
Expect(config.ReadCustomConfig()).Should(HaveActiveService("devl"))
|
session = podmanTest.Podman(systemConnectionListCmd)
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(ExitCleanly())
|
||||||
|
Expect(string(session.Out.Contents())).To(Equal(`devl ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa true true
|
||||||
|
qe ssh://root@podman.test:2222/run/podman/podman.sock ~/.ssh/id_rsa false true
|
||||||
|
`))
|
||||||
|
|
||||||
cmd = []string{"system", "connection", "list"}
|
cmd = []string{"system", "connection", "list"}
|
||||||
session = podmanTest.Podman(cmd)
|
session = podmanTest.Podman(cmd)
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(ExitCleanly())
|
Expect(session).Should(ExitCleanly())
|
||||||
Expect(session.Out).Should(Say("Name *URI *Identity *Default"))
|
Expect(session.Out).Should(Say("Name *URI *Identity *Default"))
|
||||||
|
|
||||||
cmd = []string{"system", "connection", "list", "--format", "{{.Name}}"}
|
|
||||||
session = podmanTest.Podman(cmd)
|
|
||||||
session.WaitWithDefaultTimeout()
|
|
||||||
Expect(session).Should(ExitCleanly())
|
|
||||||
Expect(session.OutputToString()).Should(Equal("devl qe"))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("failed default", func() {
|
It("failed default", func() {
|
||||||
|
@ -382,12 +372,12 @@ var _ = Describe("podman system connection", func() {
|
||||||
Path: fmt.Sprintf("/run/user/%s/podman/podman.sock", u.Uid),
|
Path: fmt.Sprintf("/run/user/%s/podman/podman.sock", u.Uid),
|
||||||
}
|
}
|
||||||
|
|
||||||
Expect(config.ReadCustomConfig()).Should(HaveActiveService("QA"))
|
cmd = exec.Command(podmanTest.RemotePodmanBinary, systemConnectionListCmd...)
|
||||||
Expect(config.ReadCustomConfig()).Should(VerifyService(
|
lsSession, err := Start(cmd, GinkgoWriter, GinkgoWriter)
|
||||||
"QA",
|
Expect(err).ToNot(HaveOccurred())
|
||||||
uri.String(),
|
lsSession.Wait(DefaultWaitTimeout)
|
||||||
filepath.Join(u.HomeDir, ".ssh", "id_ed25519"),
|
Expect(lsSession).Should(Exit(0))
|
||||||
))
|
Expect(string(lsSession.Out.Contents())).To(Equal("QA " + uri.String() + " " + filepath.Join(u.HomeDir, ".ssh", "id_ed25519") + " true true\n"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -51,7 +51,7 @@ function _run_podman_remote() {
|
||||||
# Very basic test, does not actually connect at any time
|
# Very basic test, does not actually connect at any time
|
||||||
@test "podman system connection - basic add / ls / remove" {
|
@test "podman system connection - basic add / ls / remove" {
|
||||||
run_podman system connection ls
|
run_podman system connection ls
|
||||||
is "$output" "Name URI Identity Default" \
|
is "$output" "Name URI Identity Default ReadWrite" \
|
||||||
"system connection ls: no connections"
|
"system connection ls: no connections"
|
||||||
|
|
||||||
c1="c1_$(random_string 15)"
|
c1="c1_$(random_string 15)"
|
||||||
|
@ -61,8 +61,8 @@ function _run_podman_remote() {
|
||||||
run_podman context create --docker "host=tcp://localhost:54321" $c2
|
run_podman context create --docker "host=tcp://localhost:54321" $c2
|
||||||
run_podman system connection ls
|
run_podman system connection ls
|
||||||
is "$output" \
|
is "$output" \
|
||||||
".*$c1[ ]\+tcp://localhost:12345[ ]\+true
|
".*$c1[ ]\+tcp://localhost:12345[ ]\+true[ ]\+true
|
||||||
$c2[ ]\+tcp://localhost:54321[ ]\+false" \
|
$c2[ ]\+tcp://localhost:54321[ ]\+false[ ]\+true" \
|
||||||
"system connection ls"
|
"system connection ls"
|
||||||
run_podman system connection ls -q
|
run_podman system connection ls -q
|
||||||
is "$(echo $(sort <<<$output))" \
|
is "$(echo $(sort <<<$output))" \
|
||||||
|
@ -75,14 +75,14 @@ $c2[ ]\+tcp://localhost:54321[ ]\+false" \
|
||||||
run_podman context use $c2
|
run_podman context use $c2
|
||||||
run_podman system connection ls
|
run_podman system connection ls
|
||||||
is "$output" \
|
is "$output" \
|
||||||
".*$c1[ ]\+tcp://localhost:12345[ ]\+false
|
".*$c1[ ]\+tcp://localhost:12345[ ]\+false[ ]\+true
|
||||||
$c2[ ]\+tcp://localhost:54321[ ]\+true" \
|
$c2[ ]\+tcp://localhost:54321[ ]\+true[ ]\+true" \
|
||||||
"system connection ls"
|
"system connection ls"
|
||||||
|
|
||||||
# Remove default connection; the remaining one should still not be default
|
# Remove default connection; the remaining one should still not be default
|
||||||
run_podman system connection rm $c2
|
run_podman system connection rm $c2
|
||||||
run_podman context ls
|
run_podman context ls
|
||||||
is "$output" ".*$c1[ ]\+tcp://localhost:12345[ ]\+false" \
|
is "$output" ".*$c1[ ]\+tcp://localhost:12345[ ]\+false[ ]\+true" \
|
||||||
"system connection ls (after removing default connection)"
|
"system connection ls (after removing default connection)"
|
||||||
|
|
||||||
run_podman context rm $c1
|
run_podman context rm $c1
|
||||||
|
|
|
@ -3,116 +3,12 @@ package utils
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
|
||||||
. "github.com/onsi/gomega" //nolint:revive,stylecheck
|
|
||||||
"github.com/onsi/gomega/format"
|
"github.com/onsi/gomega/format"
|
||||||
"github.com/onsi/gomega/gexec"
|
"github.com/onsi/gomega/gexec"
|
||||||
"github.com/onsi/gomega/matchers"
|
|
||||||
"github.com/onsi/gomega/types"
|
"github.com/onsi/gomega/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HaveActiveService verifies the given service is the active service.
|
|
||||||
func HaveActiveService(name interface{}) OmegaMatcher {
|
|
||||||
return WithTransform(
|
|
||||||
func(cfg *config.Config) string {
|
|
||||||
return cfg.Engine.ActiveService
|
|
||||||
},
|
|
||||||
Equal(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServiceMatcher struct {
|
|
||||||
types.GomegaMatcher
|
|
||||||
Name interface{}
|
|
||||||
URI interface{}
|
|
||||||
Identity interface{}
|
|
||||||
failureMessage string
|
|
||||||
negatedFailureMessage string
|
|
||||||
}
|
|
||||||
|
|
||||||
func VerifyService(name, uri, identity interface{}) OmegaMatcher {
|
|
||||||
return &ServiceMatcher{
|
|
||||||
Name: name,
|
|
||||||
URI: uri,
|
|
||||||
Identity: identity,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (matcher *ServiceMatcher) Match(actual interface{}) (success bool, err error) {
|
|
||||||
cfg, ok := actual.(*config.Config)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("ServiceMatcher matcher expects a config.Config")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = url.Parse(matcher.URI.(string)); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
success, err = HaveKey(matcher.Name).Match(cfg.Engine.ServiceDestinations)
|
|
||||||
if !success || err != nil {
|
|
||||||
matcher.failureMessage = HaveKey(matcher.Name).FailureMessage(cfg.Engine.ServiceDestinations)
|
|
||||||
matcher.negatedFailureMessage = HaveKey(matcher.Name).NegatedFailureMessage(cfg.Engine.ServiceDestinations)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sd := cfg.Engine.ServiceDestinations[matcher.Name.(string)]
|
|
||||||
success, err = Equal(matcher.URI).Match(sd.URI)
|
|
||||||
if !success || err != nil {
|
|
||||||
matcher.failureMessage = Equal(matcher.URI).FailureMessage(sd.URI)
|
|
||||||
matcher.negatedFailureMessage = Equal(matcher.URI).NegatedFailureMessage(sd.URI)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
success, err = Equal(matcher.Identity).Match(sd.Identity)
|
|
||||||
if !success || err != nil {
|
|
||||||
matcher.failureMessage = Equal(matcher.Identity).FailureMessage(sd.Identity)
|
|
||||||
matcher.negatedFailureMessage = Equal(matcher.Identity).NegatedFailureMessage(sd.Identity)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (matcher *ServiceMatcher) FailureMessage(_ interface{}) string {
|
|
||||||
return matcher.failureMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (matcher *ServiceMatcher) NegatedFailureMessage(_ interface{}) string {
|
|
||||||
return matcher.negatedFailureMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
type URLMatcher struct {
|
|
||||||
matchers.EqualMatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyURL matches when actual is a valid URL and matches expected.
|
|
||||||
func VerifyURL(uri interface{}) OmegaMatcher {
|
|
||||||
return &URLMatcher{matchers.EqualMatcher{Expected: uri}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (matcher *URLMatcher) Match(actual interface{}) (bool, error) {
|
|
||||||
e, ok := matcher.Expected.(string)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("VerifyURL requires string inputs %T is not supported", matcher.Expected)
|
|
||||||
}
|
|
||||||
eURI, err := url.Parse(e)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
a, ok := actual.(string)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("VerifyURL requires string inputs %T is not supported", actual)
|
|
||||||
}
|
|
||||||
aURI, err := url.Parse(a)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return (&matchers.EqualMatcher{Expected: eURI}).Match(aURI)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExitMatcher struct {
|
type ExitMatcher struct {
|
||||||
types.GomegaMatcher
|
types.GomegaMatcher
|
||||||
Expected int
|
Expected int
|
||||||
|
|
|
@ -9,11 +9,9 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
"github.com/containers/common/internal/attributedstring"
|
"github.com/containers/common/internal/attributedstring"
|
||||||
"github.com/containers/common/libnetwork/types"
|
"github.com/containers/common/libnetwork/types"
|
||||||
"github.com/containers/common/pkg/capabilities"
|
"github.com/containers/common/pkg/capabilities"
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
|
||||||
"github.com/containers/storage/pkg/unshare"
|
"github.com/containers/storage/pkg/unshare"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||||
|
@ -667,9 +665,9 @@ type MachineConfig struct {
|
||||||
// FarmConfig represents the "farm" TOML config tables
|
// FarmConfig represents the "farm" TOML config tables
|
||||||
type FarmConfig struct {
|
type FarmConfig struct {
|
||||||
// Default is the default farm to be used when farming out builds
|
// Default is the default farm to be used when farming out builds
|
||||||
Default string `toml:"default,omitempty"`
|
Default string `json:",omitempty" toml:"default,omitempty"`
|
||||||
// List is a map of farms created where key=farm-name and value=list of connections
|
// List is a map of farms created where key=farm-name and value=list of connections
|
||||||
List map[string][]string `toml:"list,omitempty"`
|
List map[string][]string `json:",omitempty" toml:"list,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination represents destination for remote service
|
// Destination represents destination for remote service
|
||||||
|
@ -678,10 +676,10 @@ type Destination struct {
|
||||||
URI string `toml:"uri"`
|
URI string `toml:"uri"`
|
||||||
|
|
||||||
// Identity file with ssh key, optional
|
// Identity file with ssh key, optional
|
||||||
Identity string `toml:"identity,omitempty"`
|
Identity string `json:",omitempty" toml:"identity,omitempty"`
|
||||||
|
|
||||||
// isMachine describes if the remote destination is a machine.
|
// isMachine describes if the remote destination is a machine.
|
||||||
IsMachine bool `toml:"is_machine,omitempty"`
|
IsMachine bool `json:",omitempty" toml:"is_machine,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consumes container image's os and arch and returns if any dedicated runtime was
|
// Consumes container image's os and arch and returns if any dedicated runtime was
|
||||||
|
@ -1008,82 +1006,6 @@ func IsValidDeviceMode(mode string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func rootlessConfigPath() (string, error) {
|
|
||||||
if configHome := os.Getenv("XDG_CONFIG_HOME"); configHome != "" {
|
|
||||||
return filepath.Join(configHome, _configPath), nil
|
|
||||||
}
|
|
||||||
home, err := unshare.HomeDir()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.Join(home, UserOverrideContainersConfig), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Path() string {
|
|
||||||
if path := os.Getenv("CONTAINERS_CONF"); path != "" {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
if unshare.IsRootless() {
|
|
||||||
if rpath, err := rootlessConfigPath(); err == nil {
|
|
||||||
return rpath
|
|
||||||
}
|
|
||||||
return "$HOME/" + UserOverrideContainersConfig
|
|
||||||
}
|
|
||||||
return OverrideContainersConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadCustomConfig reads the custom config and only generates a config based on it
|
|
||||||
// If the custom config file does not exists, function will return an empty config
|
|
||||||
func ReadCustomConfig() (*Config, error) {
|
|
||||||
path, err := customConfigFile()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newConfig := &Config{}
|
|
||||||
if _, err := os.Stat(path); err == nil {
|
|
||||||
if err := readConfigFromFile(path, newConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Let's always initialize the farm list so it is never nil
|
|
||||||
if newConfig.Farms.List == nil {
|
|
||||||
newConfig.Farms.List = make(map[string][]string)
|
|
||||||
}
|
|
||||||
return newConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes the configuration to the default file
|
|
||||||
func (c *Config) Write() error {
|
|
||||||
var err error
|
|
||||||
path, err := customConfigFile()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := &ioutils.AtomicFileWriterOptions{ExplicitCommit: true}
|
|
||||||
configFile, err := ioutils.NewAtomicFileWriterWithOpts(path, 0o644, opts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer configFile.Close()
|
|
||||||
|
|
||||||
enc := toml.NewEncoder(configFile)
|
|
||||||
if err := enc.Encode(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no errors commit the changes to the config file
|
|
||||||
return configFile.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload clean the cached config and reloads the configuration from containers.conf files
|
// Reload clean the cached config and reloads the configuration from containers.conf files
|
||||||
// This function is meant to be used for long-running processes that need to reload potential changes made to
|
// This function is meant to be used for long-running processes that need to reload potential changes made to
|
||||||
// the cached containers.conf files.
|
// the cached containers.conf files.
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// OverrideContainersConfig holds the default config path overridden by the root user
|
// OverrideContainersConfig holds the default config path overridden by the root user
|
||||||
OverrideContainersConfig = "/etc/" + _configPath
|
OverrideContainersConfig = "/etc/" + _configPath
|
||||||
|
@ -16,18 +12,6 @@ const (
|
||||||
DefaultSignaturePolicyPath = "/etc/containers/policy.json"
|
DefaultSignaturePolicyPath = "/etc/containers/policy.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// podman remote clients on darwin cannot use unshare.isRootless() to determine the configuration file locations.
|
|
||||||
func customConfigFile() (string, error) {
|
|
||||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
return rootlessConfigPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ifRootlessConfigPath() (string, error) {
|
|
||||||
return rootlessConfigPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultHelperBinariesDir = []string{
|
var defaultHelperBinariesDir = []string{
|
||||||
// Relative to the binary directory
|
// Relative to the binary directory
|
||||||
"$BINDIR/../libexec/podman",
|
"$BINDIR/../libexec/podman",
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// OverrideContainersConfig holds the default config path overridden by the root user
|
// OverrideContainersConfig holds the default config path overridden by the root user
|
||||||
OverrideContainersConfig = "/usr/local/etc/" + _configPath
|
OverrideContainersConfig = "/usr/local/etc/" + _configPath
|
||||||
|
@ -16,18 +12,6 @@ const (
|
||||||
DefaultSignaturePolicyPath = "/usr/local/etc/containers/policy.json"
|
DefaultSignaturePolicyPath = "/usr/local/etc/containers/policy.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// podman remote clients on freebsd cannot use unshare.isRootless() to determine the configuration file locations.
|
|
||||||
func customConfigFile() (string, error) {
|
|
||||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
return rootlessConfigPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ifRootlessConfigPath() (string, error) {
|
|
||||||
return rootlessConfigPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultHelperBinariesDir = []string{
|
var defaultHelperBinariesDir = []string{
|
||||||
"/usr/local/bin",
|
"/usr/local/bin",
|
||||||
"/usr/local/libexec/podman",
|
"/usr/local/libexec/podman",
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/unshare"
|
|
||||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,31 +20,6 @@ func selinuxEnabled() bool {
|
||||||
return selinux.GetEnabled()
|
return selinux.GetEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
func customConfigFile() (string, error) {
|
|
||||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
if unshare.GetRootlessUID() > 0 {
|
|
||||||
path, err := rootlessConfigPath()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
return OverrideContainersConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ifRootlessConfigPath() (string, error) {
|
|
||||||
if unshare.GetRootlessUID() > 0 {
|
|
||||||
path, err := rootlessConfigPath()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultHelperBinariesDir = []string{
|
var defaultHelperBinariesDir = []string{
|
||||||
"/usr/local/libexec/podman",
|
"/usr/local/libexec/podman",
|
||||||
"/usr/local/lib/podman",
|
"/usr/local/lib/podman",
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/containers/storage/pkg/unshare"
|
||||||
|
)
|
||||||
|
|
||||||
|
// userConfigPath returns the path to the users local config that is
|
||||||
|
// not shared with other users. It uses $XDG_CONFIG_HOME/containers...
|
||||||
|
// if set or $HOME/.config/containers... if not.
|
||||||
|
func userConfigPath() (string, error) {
|
||||||
|
if configHome := os.Getenv("XDG_CONFIG_HOME"); configHome != "" {
|
||||||
|
return filepath.Join(configHome, _configPath), nil
|
||||||
|
}
|
||||||
|
home, err := unshare.HomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(home, UserOverrideContainersConfig), nil
|
||||||
|
}
|
|
@ -17,15 +17,9 @@ const (
|
||||||
_typeBind = "bind"
|
_typeBind = "bind"
|
||||||
)
|
)
|
||||||
|
|
||||||
// podman remote clients on windows cannot use unshare.isRootless() to determine the configuration file locations.
|
// userConfigPath returns the path to the users local config that is
|
||||||
func customConfigFile() (string, error) {
|
// not shared with other users. It uses $APPDATA/containers...
|
||||||
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
|
func userConfigPath() (string, error) {
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
return os.Getenv("APPDATA") + "\\containers\\containers.conf", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ifRootlessConfigPath() (string, error) {
|
|
||||||
return os.Getenv("APPDATA") + "\\containers\\containers.conf", nil
|
return os.Getenv("APPDATA") + "\\containers\\containers.conf", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,286 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const connectionsFile = "podman-connections.conf"
|
||||||
|
|
||||||
|
// connectionsConfigFile returns the path to the rw connections config file
|
||||||
|
func connectionsConfigFile() (string, error) {
|
||||||
|
if path, found := os.LookupEnv("PODMAN_CONNECTIONS_CONF"); found {
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
path, err := userConfigPath()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// file is stored next to containers.conf
|
||||||
|
return filepath.Join(filepath.Dir(path), connectionsFile), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionConfig struct {
|
||||||
|
Default string `json:",omitempty"`
|
||||||
|
Connections map[string]Destination `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionsFile struct {
|
||||||
|
Connection ConnectionConfig `json:",omitempty"`
|
||||||
|
Farm FarmConfig `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
// Name of the connection
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Destination for this connection
|
||||||
|
Destination
|
||||||
|
|
||||||
|
// Default if this connection is the default
|
||||||
|
Default bool
|
||||||
|
|
||||||
|
// ReadWrite if true the connection is stored in the connections file
|
||||||
|
ReadWrite bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Farm struct {
|
||||||
|
// Name of the farm
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
Connections []string
|
||||||
|
|
||||||
|
// Default if this is the default farm
|
||||||
|
Default bool
|
||||||
|
|
||||||
|
// ReadWrite if true the farm is stored in the connections file
|
||||||
|
ReadWrite bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func readConnectionConf() (*ConnectionsFile, string, error) {
|
||||||
|
path, err := connectionsConfigFile()
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
conf := new(ConnectionsFile)
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
// return empty config if file does not exists
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return conf, path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
err = json.NewDecoder(f).Decode(conf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", fmt.Errorf("parse %q: %w", path, err)
|
||||||
|
}
|
||||||
|
return conf, path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeConnectionConf(path string, conf *ConnectionsFile) error {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &ioutils.AtomicFileWriterOptions{ExplicitCommit: true}
|
||||||
|
configFile, err := ioutils.NewAtomicFileWriterWithOpts(path, 0o644, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer configFile.Close()
|
||||||
|
|
||||||
|
err = json.NewEncoder(configFile).Encode(conf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no errors commit the changes to the config file
|
||||||
|
return configFile.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditConnectionConfig must be used to edit the connections config.
|
||||||
|
// The function will read and write the file automatically and the
|
||||||
|
// callback function just needs to modify the cfg as needed.
|
||||||
|
func EditConnectionConfig(callback func(cfg *ConnectionsFile) error) error {
|
||||||
|
conf, path, err := readConnectionConf()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("read connections file: %w", err)
|
||||||
|
}
|
||||||
|
if conf.Farm.List == nil {
|
||||||
|
conf.Farm.List = make(map[string][]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := callback(conf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeConnectionConf(path, conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeConnection(name string, dst Destination, def, readWrite bool) *Connection {
|
||||||
|
return &Connection{
|
||||||
|
Name: name,
|
||||||
|
Destination: dst,
|
||||||
|
Default: def,
|
||||||
|
ReadWrite: readWrite,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConnection return the connection for the given name or if def is set to true then return the default connection.
|
||||||
|
func (c *Config) GetConnection(name string, def bool) (*Connection, error) {
|
||||||
|
conConf, _, err := readConnectionConf()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultCon := conConf.Connection.Default
|
||||||
|
if defaultCon == "" {
|
||||||
|
defaultCon = c.Engine.ActiveService
|
||||||
|
}
|
||||||
|
if def {
|
||||||
|
if defaultCon == "" {
|
||||||
|
return nil, errors.New("no default connection found")
|
||||||
|
}
|
||||||
|
name = defaultCon
|
||||||
|
} else {
|
||||||
|
def = defaultCon == name
|
||||||
|
}
|
||||||
|
|
||||||
|
if dst, ok := conConf.Connection.Connections[name]; ok {
|
||||||
|
return makeConnection(name, dst, def, true), nil
|
||||||
|
}
|
||||||
|
if dst, ok := c.Engine.ServiceDestinations[name]; ok {
|
||||||
|
return makeConnection(name, dst, def, false), nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("connection %q not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllConnections return all configured connections
|
||||||
|
func (c *Config) GetAllConnections() ([]Connection, error) {
|
||||||
|
conConf, _, err := readConnectionConf()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultCon := conConf.Connection.Default
|
||||||
|
if defaultCon == "" {
|
||||||
|
defaultCon = c.Engine.ActiveService
|
||||||
|
}
|
||||||
|
|
||||||
|
connections := make([]Connection, 0, len(conConf.Connection.Connections))
|
||||||
|
for name, dst := range conConf.Connection.Connections {
|
||||||
|
def := defaultCon == name
|
||||||
|
connections = append(connections, *makeConnection(name, dst, def, true))
|
||||||
|
}
|
||||||
|
for name, dst := range c.Engine.ServiceDestinations {
|
||||||
|
if _, ok := conConf.Connection.Connections[name]; ok {
|
||||||
|
// connection name is overwritten by connections file
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
def := defaultCon == name
|
||||||
|
connections = append(connections, *makeConnection(name, dst, def, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
return connections, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConnections(cons []string, dests map[string]Destination) ([]Connection, error) {
|
||||||
|
connections := make([]Connection, 0, len(cons))
|
||||||
|
for _, name := range cons {
|
||||||
|
if dst, ok := dests[name]; ok {
|
||||||
|
connections = append(connections, *makeConnection(name, dst, false, false))
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("connection %q not found", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return connections, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFarmConnections return all the connections for the given farm.
|
||||||
|
func (c *Config) GetFarmConnections(name string) ([]Connection, error) {
|
||||||
|
_, cons, err := c.getFarmConnections(name, false)
|
||||||
|
return cons, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultFarmConnections returns the name of the default farm
|
||||||
|
// and the connections.
|
||||||
|
func (c *Config) GetDefaultFarmConnections() (string, []Connection, error) {
|
||||||
|
return c.getFarmConnections("", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFarmConnections returns all connections for the given farm,
|
||||||
|
// if def is true it will use the default farm instead of the name.
|
||||||
|
// Returns the name of the farm and the connections for it.
|
||||||
|
func (c *Config) getFarmConnections(name string, def bool) (string, []Connection, error) {
|
||||||
|
conConf, _, err := readConnectionConf()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
defaultFarm := conConf.Farm.Default
|
||||||
|
if defaultFarm == "" {
|
||||||
|
defaultFarm = c.Farms.Default
|
||||||
|
}
|
||||||
|
if def {
|
||||||
|
if defaultFarm == "" {
|
||||||
|
return "", nil, errors.New("no default farm found")
|
||||||
|
}
|
||||||
|
name = defaultFarm
|
||||||
|
}
|
||||||
|
|
||||||
|
if cons, ok := conConf.Farm.List[name]; ok {
|
||||||
|
cons, err := getConnections(cons, conConf.Connection.Connections)
|
||||||
|
return name, cons, err
|
||||||
|
}
|
||||||
|
if cons, ok := c.Farms.List[name]; ok {
|
||||||
|
cons, err := getConnections(cons, c.Engine.ServiceDestinations)
|
||||||
|
return name, cons, err
|
||||||
|
}
|
||||||
|
return "", nil, fmt.Errorf("farm %q not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeFarm(name string, cons []string, def, readWrite bool) Farm {
|
||||||
|
return Farm{
|
||||||
|
Name: name,
|
||||||
|
Connections: cons,
|
||||||
|
Default: def,
|
||||||
|
ReadWrite: readWrite,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllFarms returns all configured farms
|
||||||
|
func (c *Config) GetAllFarms() ([]Farm, error) {
|
||||||
|
conConf, _, err := readConnectionConf()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defaultFarm := conConf.Farm.Default
|
||||||
|
if defaultFarm == "" {
|
||||||
|
defaultFarm = c.Farms.Default
|
||||||
|
}
|
||||||
|
|
||||||
|
farms := make([]Farm, 0, len(conConf.Farm.List))
|
||||||
|
for name, cons := range conConf.Farm.List {
|
||||||
|
def := defaultFarm == name
|
||||||
|
farms = append(farms, makeFarm(name, cons, def, true))
|
||||||
|
}
|
||||||
|
for name, cons := range c.Farms.List {
|
||||||
|
if _, ok := conConf.Farm.List[name]; ok {
|
||||||
|
// farm name is overwritten by connections file
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
def := defaultFarm == name
|
||||||
|
farms = append(farms, makeFarm(name, cons, def, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
return farms, nil
|
||||||
|
}
|
|
@ -10,7 +10,8 @@
|
||||||
# locations in the following order:
|
# locations in the following order:
|
||||||
# 1. /usr/share/containers/containers.conf
|
# 1. /usr/share/containers/containers.conf
|
||||||
# 2. /etc/containers/containers.conf
|
# 2. /etc/containers/containers.conf
|
||||||
# 3. $HOME/.config/containers/containers.conf (Rootless containers ONLY)
|
# 3. $XDG_CONFIG_HOME/containers/containers.conf or
|
||||||
|
# $HOME/.config/containers/containers.conf if $XDG_CONFIG_HOME is not set
|
||||||
# Items specified in the latter containers.conf, if they exist, override the
|
# Items specified in the latter containers.conf, if they exist, override the
|
||||||
# previous containers.conf settings, or the default settings.
|
# previous containers.conf settings, or the default settings.
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// FIXME: update code base and tests to use the two constants below.
|
|
||||||
containersConfEnv = "CONTAINERS_CONF"
|
containersConfEnv = "CONTAINERS_CONF"
|
||||||
containersConfOverrideEnv = containersConfEnv + "_OVERRIDE"
|
containersConfOverrideEnv = containersConfEnv + "_OVERRIDE"
|
||||||
)
|
)
|
||||||
|
@ -79,15 +78,34 @@ func newLocked(options *Options) (*Config, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("finding config on system: %w", err)
|
return nil, fmt.Errorf("finding config on system: %w", err)
|
||||||
}
|
}
|
||||||
|
// connectionsPath, err := connectionsConfigFile()
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
for _, path := range configs {
|
for _, path := range configs {
|
||||||
|
// var dests []*Destination
|
||||||
|
// if path == connectionsPath {
|
||||||
|
// // Store the dest pointers so we know after the load if there are new pointers
|
||||||
|
// // the connection changed and thus is read write.
|
||||||
|
// dests = maps.Values(config.Engine.ServiceDestinations)
|
||||||
|
// }
|
||||||
|
|
||||||
// Merge changes in later configs with the previous configs.
|
// Merge changes in later configs with the previous configs.
|
||||||
// Each config file that specified fields, will override the
|
// Each config file that specified fields, will override the
|
||||||
// previous fields.
|
// previous fields.
|
||||||
if err = readConfigFromFile(path, config); err != nil {
|
if err = readConfigFromFile(path, config, true); err != nil {
|
||||||
return nil, fmt.Errorf("reading system config %q: %w", path, err)
|
return nil, fmt.Errorf("reading system config %q: %w", path, err)
|
||||||
}
|
}
|
||||||
logrus.Debugf("Merged system config %q", path)
|
logrus.Debugf("Merged system config %q", path)
|
||||||
logrus.Tracef("%+v", config)
|
logrus.Tracef("%+v", config)
|
||||||
|
|
||||||
|
// // if there is a new dest now we know it is read write as it was in the connections.conf file
|
||||||
|
// for _, dest := range config.Engine.ServiceDestinations {
|
||||||
|
// if !slices.Contains(dests, dest) {
|
||||||
|
// dest.ReadWrite = true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
modules, err := options.modules()
|
modules, err := options.modules()
|
||||||
|
@ -115,7 +133,7 @@ func newLocked(options *Options) (*Config, error) {
|
||||||
}
|
}
|
||||||
// readConfigFromFile reads in container config in the specified
|
// readConfigFromFile reads in container config in the specified
|
||||||
// file and then merge changes with the current default.
|
// file and then merge changes with the current default.
|
||||||
if err := readConfigFromFile(add, config); err != nil {
|
if err := readConfigFromFile(add, config, false); err != nil {
|
||||||
return nil, fmt.Errorf("reading additional config %q: %w", add, err)
|
return nil, fmt.Errorf("reading additional config %q: %w", add, err)
|
||||||
}
|
}
|
||||||
logrus.Debugf("Merged additional config %q", add)
|
logrus.Debugf("Merged additional config %q", add)
|
||||||
|
@ -157,12 +175,8 @@ func systemConfigs() (configs []string, finalErr error) {
|
||||||
}
|
}
|
||||||
return append(configs, path), nil
|
return append(configs, path), nil
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(DefaultContainersConfig); err == nil {
|
|
||||||
configs = append(configs, DefaultContainersConfig)
|
configs = append(configs, DefaultContainersConfig)
|
||||||
}
|
|
||||||
if _, err := os.Stat(OverrideContainersConfig); err == nil {
|
|
||||||
configs = append(configs, OverrideContainersConfig)
|
configs = append(configs, OverrideContainersConfig)
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
configs, err = addConfigs(OverrideContainersConfig+".d", configs)
|
configs, err = addConfigs(OverrideContainersConfig+".d", configs)
|
||||||
|
@ -170,19 +184,15 @@ func systemConfigs() (configs []string, finalErr error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := ifRootlessConfigPath()
|
path, err := userConfigPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if path != "" {
|
|
||||||
if _, err := os.Stat(path); err == nil {
|
|
||||||
configs = append(configs, path)
|
configs = append(configs, path)
|
||||||
}
|
|
||||||
configs, err = addConfigs(path+".d", configs)
|
configs, err = addConfigs(path+".d", configs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return configs, nil
|
return configs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,10 +235,13 @@ func addConfigs(dirPath string, configs []string) ([]string, error) {
|
||||||
// unmarshal its content into a Config. The config param specifies the previous
|
// unmarshal its content into a Config. The config param specifies the previous
|
||||||
// default config. If the path, only specifies a few fields in the Toml file
|
// default config. If the path, only specifies a few fields in the Toml file
|
||||||
// the defaults from the config parameter will be used for all other fields.
|
// the defaults from the config parameter will be used for all other fields.
|
||||||
func readConfigFromFile(path string, config *Config) error {
|
func readConfigFromFile(path string, config *Config, ignoreErrNotExist bool) error {
|
||||||
logrus.Tracef("Reading configuration file %q", path)
|
logrus.Tracef("Reading configuration file %q", path)
|
||||||
meta, err := toml.DecodeFile(path, config)
|
meta, err := toml.DecodeFile(path, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ignoreErrNotExist && errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return fmt.Errorf("decode configuration %v: %w", path, err)
|
return fmt.Errorf("decode configuration %v: %w", path, err)
|
||||||
}
|
}
|
||||||
keys := meta.Undecoded()
|
keys := meta.Undecoded()
|
||||||
|
|
|
@ -19,6 +19,7 @@ type List interface {
|
||||||
Remove(instanceDigest digest.Digest) error
|
Remove(instanceDigest digest.Digest) error
|
||||||
SetURLs(instanceDigest digest.Digest, urls []string) error
|
SetURLs(instanceDigest digest.Digest, urls []string) error
|
||||||
URLs(instanceDigest digest.Digest) ([]string, error)
|
URLs(instanceDigest digest.Digest) ([]string, error)
|
||||||
|
ClearAnnotations(instanceDigest *digest.Digest) error
|
||||||
SetAnnotations(instanceDigest *digest.Digest, annotations map[string]string) error
|
SetAnnotations(instanceDigest *digest.Digest, annotations map[string]string) error
|
||||||
Annotations(instanceDigest *digest.Digest) (map[string]string, error)
|
Annotations(instanceDigest *digest.Digest) (map[string]string, error)
|
||||||
SetOS(instanceDigest digest.Digest, os string) error
|
SetOS(instanceDigest digest.Digest, os string) error
|
||||||
|
@ -100,18 +101,21 @@ func (l *list) AddInstance(manifestDigest digest.Digest, manifestSize int64, man
|
||||||
Platform: schema2platform,
|
Platform: schema2platform,
|
||||||
})
|
})
|
||||||
|
|
||||||
ociv1platform := v1.Platform{
|
ociv1platform := &v1.Platform{
|
||||||
Architecture: architecture,
|
Architecture: architecture,
|
||||||
OS: osName,
|
OS: osName,
|
||||||
OSVersion: osVersion,
|
OSVersion: osVersion,
|
||||||
OSFeatures: osFeatures,
|
OSFeatures: osFeatures,
|
||||||
Variant: variant,
|
Variant: variant,
|
||||||
}
|
}
|
||||||
|
if ociv1platform.Architecture == "" && ociv1platform.OS == "" && ociv1platform.OSVersion == "" && ociv1platform.Variant == "" && len(ociv1platform.OSFeatures) == 0 {
|
||||||
|
ociv1platform = nil
|
||||||
|
}
|
||||||
l.oci.Manifests = append(l.oci.Manifests, v1.Descriptor{
|
l.oci.Manifests = append(l.oci.Manifests, v1.Descriptor{
|
||||||
MediaType: manifestType,
|
MediaType: manifestType,
|
||||||
Size: manifestSize,
|
Size: manifestSize,
|
||||||
Digest: manifestDigest,
|
Digest: manifestDigest,
|
||||||
Platform: &ociv1platform,
|
Platform: ociv1platform,
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -170,7 +174,13 @@ func (l *list) SetURLs(instanceDigest digest.Digest, urls []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
oci.URLs = append([]string{}, urls...)
|
oci.URLs = append([]string{}, urls...)
|
||||||
|
if len(oci.URLs) == 0 {
|
||||||
|
oci.URLs = nil
|
||||||
|
}
|
||||||
docker.URLs = append([]string{}, urls...)
|
docker.URLs = append([]string{}, urls...)
|
||||||
|
if len(docker.URLs) == 0 {
|
||||||
|
docker.URLs = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +193,24 @@ func (l *list) URLs(instanceDigest digest.Digest) ([]string, error) {
|
||||||
return append([]string{}, oci.URLs...), nil
|
return append([]string{}, oci.URLs...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAnnotations sets annotations on the image index, or on a specific manifest.
|
// ClearAnnotations removes all annotations from the image index, or from a
|
||||||
|
// specific manifest.
|
||||||
|
// The field is specific to the OCI image index format, and is not present in Docker manifest lists.
|
||||||
|
func (l *list) ClearAnnotations(instanceDigest *digest.Digest) error {
|
||||||
|
a := &l.oci.Annotations
|
||||||
|
if instanceDigest != nil {
|
||||||
|
oci, err := l.findOCIv1(*instanceDigest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a = &oci.Annotations
|
||||||
|
}
|
||||||
|
*a = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAnnotations sets annotations on the image index, or on a specific
|
||||||
|
// manifest.
|
||||||
// The field is specific to the OCI image index format, and is not present in Docker manifest lists.
|
// The field is specific to the OCI image index format, and is not present in Docker manifest lists.
|
||||||
func (l *list) SetAnnotations(instanceDigest *digest.Digest, annotations map[string]string) error {
|
func (l *list) SetAnnotations(instanceDigest *digest.Digest, annotations map[string]string) error {
|
||||||
a := &l.oci.Annotations
|
a := &l.oci.Annotations
|
||||||
|
@ -194,10 +221,15 @@ func (l *list) SetAnnotations(instanceDigest *digest.Digest, annotations map[str
|
||||||
}
|
}
|
||||||
a = &oci.Annotations
|
a = &oci.Annotations
|
||||||
}
|
}
|
||||||
|
if *a == nil {
|
||||||
(*a) = make(map[string]string)
|
(*a) = make(map[string]string)
|
||||||
|
}
|
||||||
for k, v := range annotations {
|
for k, v := range annotations {
|
||||||
(*a)[k] = v
|
(*a)[k] = v
|
||||||
}
|
}
|
||||||
|
if len(*a) == 0 {
|
||||||
|
*a = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +262,13 @@ func (l *list) SetOS(instanceDigest digest.Digest, os string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
docker.Platform.OS = os
|
docker.Platform.OS = os
|
||||||
|
if oci.Platform == nil {
|
||||||
|
oci.Platform = &v1.Platform{}
|
||||||
|
}
|
||||||
oci.Platform.OS = os
|
oci.Platform.OS = os
|
||||||
|
if oci.Platform.Architecture == "" && oci.Platform.OS == "" && oci.Platform.OSVersion == "" && oci.Platform.Variant == "" && len(oci.Platform.OSFeatures) == 0 {
|
||||||
|
oci.Platform = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +278,11 @@ func (l *list) OS(instanceDigest digest.Digest) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return oci.Platform.OS, nil
|
platform := oci.Platform
|
||||||
|
if platform == nil {
|
||||||
|
platform = &v1.Platform{}
|
||||||
|
}
|
||||||
|
return platform.OS, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetArchitecture sets the Architecture field in the platform information associated with the instance with the specified digest.
|
// SetArchitecture sets the Architecture field in the platform information associated with the instance with the specified digest.
|
||||||
|
@ -254,7 +296,13 @@ func (l *list) SetArchitecture(instanceDigest digest.Digest, arch string) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
docker.Platform.Architecture = arch
|
docker.Platform.Architecture = arch
|
||||||
|
if oci.Platform == nil {
|
||||||
|
oci.Platform = &v1.Platform{}
|
||||||
|
}
|
||||||
oci.Platform.Architecture = arch
|
oci.Platform.Architecture = arch
|
||||||
|
if oci.Platform.Architecture == "" && oci.Platform.OS == "" && oci.Platform.OSVersion == "" && oci.Platform.Variant == "" && len(oci.Platform.OSFeatures) == 0 {
|
||||||
|
oci.Platform = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +312,11 @@ func (l *list) Architecture(instanceDigest digest.Digest) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return oci.Platform.Architecture, nil
|
platform := oci.Platform
|
||||||
|
if platform == nil {
|
||||||
|
platform = &v1.Platform{}
|
||||||
|
}
|
||||||
|
return platform.Architecture, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetOSVersion sets the OSVersion field in the platform information associated with the instance with the specified digest.
|
// SetOSVersion sets the OSVersion field in the platform information associated with the instance with the specified digest.
|
||||||
|
@ -278,7 +330,13 @@ func (l *list) SetOSVersion(instanceDigest digest.Digest, osVersion string) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
docker.Platform.OSVersion = osVersion
|
docker.Platform.OSVersion = osVersion
|
||||||
|
if oci.Platform == nil {
|
||||||
|
oci.Platform = &v1.Platform{}
|
||||||
|
}
|
||||||
oci.Platform.OSVersion = osVersion
|
oci.Platform.OSVersion = osVersion
|
||||||
|
if oci.Platform.Architecture == "" && oci.Platform.OS == "" && oci.Platform.OSVersion == "" && oci.Platform.Variant == "" && len(oci.Platform.OSFeatures) == 0 {
|
||||||
|
oci.Platform = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +346,11 @@ func (l *list) OSVersion(instanceDigest digest.Digest) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return oci.Platform.OSVersion, nil
|
platform := oci.Platform
|
||||||
|
if platform == nil {
|
||||||
|
platform = &v1.Platform{}
|
||||||
|
}
|
||||||
|
return platform.OSVersion, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVariant sets the Variant field in the platform information associated with the instance with the specified digest.
|
// SetVariant sets the Variant field in the platform information associated with the instance with the specified digest.
|
||||||
|
@ -302,7 +364,13 @@ func (l *list) SetVariant(instanceDigest digest.Digest, variant string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
docker.Platform.Variant = variant
|
docker.Platform.Variant = variant
|
||||||
|
if oci.Platform == nil {
|
||||||
|
oci.Platform = &v1.Platform{}
|
||||||
|
}
|
||||||
oci.Platform.Variant = variant
|
oci.Platform.Variant = variant
|
||||||
|
if oci.Platform.Architecture == "" && oci.Platform.OS == "" && oci.Platform.OSVersion == "" && oci.Platform.Variant == "" && len(oci.Platform.OSFeatures) == 0 {
|
||||||
|
oci.Platform = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +380,11 @@ func (l *list) Variant(instanceDigest digest.Digest) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return oci.Platform.Variant, nil
|
platform := oci.Platform
|
||||||
|
if platform == nil {
|
||||||
|
platform = &v1.Platform{}
|
||||||
|
}
|
||||||
|
return platform.Variant, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFeatures sets the features list in the platform information associated with the instance with the specified digest.
|
// SetFeatures sets the features list in the platform information associated with the instance with the specified digest.
|
||||||
|
@ -323,6 +395,9 @@ func (l *list) SetFeatures(instanceDigest digest.Digest, features []string) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
docker.Platform.Features = append([]string{}, features...)
|
docker.Platform.Features = append([]string{}, features...)
|
||||||
|
if len(docker.Platform.Features) == 0 {
|
||||||
|
docker.Platform.Features = nil
|
||||||
|
}
|
||||||
// no OCI equivalent
|
// no OCI equivalent
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -348,7 +423,16 @@ func (l *list) SetOSFeatures(instanceDigest digest.Digest, osFeatures []string)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
docker.Platform.OSFeatures = append([]string{}, osFeatures...)
|
docker.Platform.OSFeatures = append([]string{}, osFeatures...)
|
||||||
|
if oci.Platform == nil {
|
||||||
|
oci.Platform = &v1.Platform{}
|
||||||
|
}
|
||||||
oci.Platform.OSFeatures = append([]string{}, osFeatures...)
|
oci.Platform.OSFeatures = append([]string{}, osFeatures...)
|
||||||
|
if len(oci.Platform.OSFeatures) == 0 {
|
||||||
|
oci.Platform.OSFeatures = nil
|
||||||
|
}
|
||||||
|
if oci.Platform.Architecture == "" && oci.Platform.OS == "" && oci.Platform.OSVersion == "" && oci.Platform.Variant == "" && len(oci.Platform.OSFeatures) == 0 {
|
||||||
|
oci.Platform = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +442,11 @@ func (l *list) OSFeatures(instanceDigest digest.Digest) ([]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return append([]string{}, oci.Platform.OSFeatures...), nil
|
platform := oci.Platform
|
||||||
|
if platform == nil {
|
||||||
|
platform = &v1.Platform{}
|
||||||
|
}
|
||||||
|
return append([]string{}, platform.OSFeatures...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMediaType sets the MediaType field in the instance with the specified digest.
|
// SetMediaType sets the MediaType field in the instance with the specified digest.
|
||||||
|
|
|
@ -53,32 +53,32 @@ func golangConnectionCreate(options ConnectionCreateOptions) error {
|
||||||
dst.URI += uri.Path
|
dst.URI += uri.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
// TODO this really should not live here, it must be in podman where we write the other connections as well.
|
||||||
if err != nil {
|
// This duplicates the code for no reason and I have a really hard time to make any sense of why this code
|
||||||
return err
|
// was added in the first place.
|
||||||
}
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if cfg.Engine.ServiceDestinations == nil {
|
if cfg.Connection.Connections == nil {
|
||||||
cfg.Engine.ServiceDestinations = map[string]config.Destination{
|
cfg.Connection.Connections = map[string]config.Destination{
|
||||||
options.Name: *dst,
|
options.Name: *dst,
|
||||||
}
|
}
|
||||||
cfg.Engine.ActiveService = options.Name
|
cfg.Connection.Default = options.Name
|
||||||
} else {
|
} else {
|
||||||
cfg.Engine.ServiceDestinations[options.Name] = *dst
|
cfg.Connection.Connections[options.Name] = *dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or update an existing farm with the connection being added
|
// Create or update an existing farm with the connection being added
|
||||||
if options.Farm != "" {
|
if options.Farm != "" {
|
||||||
if len(cfg.Farms.List) == 0 {
|
if len(cfg.Farm.List) == 0 {
|
||||||
cfg.Farms.Default = options.Farm
|
cfg.Farm.Default = options.Farm
|
||||||
}
|
}
|
||||||
if val, ok := cfg.Farms.List[options.Farm]; ok {
|
if val, ok := cfg.Farm.List[options.Farm]; ok {
|
||||||
cfg.Farms.List[options.Farm] = append(val, options.Name)
|
cfg.Farm.List[options.Farm] = append(val, options.Name)
|
||||||
} else {
|
} else {
|
||||||
cfg.Farms.List[options.Farm] = []string{options.Name}
|
cfg.Farm.List[options.Farm] = []string{options.Name}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return cfg.Write()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func golangConnectionDial(options ConnectionDialOptions) (*ConnectionDialReport, error) {
|
func golangConnectionDial(options ConnectionDialOptions) (*ConnectionDialReport, error) {
|
||||||
|
|
|
@ -72,24 +72,32 @@ func nativeConnectionCreate(options ConnectionCreateOptions) error {
|
||||||
return fmt.Errorf("remote podman %q failed to report its UDS socket", uri.Host)
|
return fmt.Errorf("remote podman %q failed to report its UDS socket", uri.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := config.ReadCustomConfig()
|
// TODO this really should not live here, it must be in podman where we write the other connections as well.
|
||||||
if err != nil {
|
// This duplicates the code for no reason and I have a really hard time to make any sense of why this code
|
||||||
return err
|
// was added in the first place.
|
||||||
}
|
return config.EditConnectionConfig(func(cfg *config.ConnectionsFile) error {
|
||||||
if options.Default {
|
if cfg.Connection.Connections == nil {
|
||||||
cfg.Engine.ActiveService = options.Name
|
cfg.Connection.Connections = map[string]config.Destination{
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Engine.ServiceDestinations == nil {
|
|
||||||
cfg.Engine.ServiceDestinations = map[string]config.Destination{
|
|
||||||
options.Name: *dst,
|
options.Name: *dst,
|
||||||
}
|
}
|
||||||
cfg.Engine.ActiveService = options.Name
|
cfg.Connection.Default = options.Name
|
||||||
} else {
|
} else {
|
||||||
cfg.Engine.ServiceDestinations[options.Name] = *dst
|
cfg.Connection.Connections[options.Name] = *dst
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg.Write()
|
// Create or update an existing farm with the connection being added
|
||||||
|
if options.Farm != "" {
|
||||||
|
if len(cfg.Farm.List) == 0 {
|
||||||
|
cfg.Farm.Default = options.Farm
|
||||||
|
}
|
||||||
|
if val, ok := cfg.Farm.List[options.Farm]; ok {
|
||||||
|
cfg.Farm.List[options.Farm] = append(val, options.Name)
|
||||||
|
} else {
|
||||||
|
cfg.Farm.List[options.Farm] = []string{options.Name}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func nativeConnectionExec(options ConnectionExecOptions) (*ConnectionExecReport, error) {
|
func nativeConnectionExec(options ConnectionExecOptions) (*ConnectionExecReport, error) {
|
||||||
|
|
|
@ -6,9 +6,9 @@ const (
|
||||||
// VersionMajor is for an API incompatible changes
|
// VersionMajor is for an API incompatible changes
|
||||||
VersionMajor = 5
|
VersionMajor = 5
|
||||||
// VersionMinor is for functionality in a backwards-compatible manner
|
// VersionMinor is for functionality in a backwards-compatible manner
|
||||||
VersionMinor = 29
|
VersionMinor = 30
|
||||||
// VersionPatch is for backwards-compatible bug fixes
|
// VersionPatch is for backwards-compatible bug fixes
|
||||||
VersionPatch = 2
|
VersionPatch = 0
|
||||||
|
|
||||||
// VersionDev indicates development branch. Releases will be empty string.
|
// VersionDev indicates development branch. Releases will be empty string.
|
||||||
VersionDev = "-dev"
|
VersionDev = "-dev"
|
||||||
|
|
|
@ -41,7 +41,7 @@ containers-storage: ## build using gc on the host
|
||||||
$(GO) build -compiler gc $(BUILDFLAGS) ./cmd/containers-storage
|
$(GO) build -compiler gc $(BUILDFLAGS) ./cmd/containers-storage
|
||||||
|
|
||||||
codespell:
|
codespell:
|
||||||
codespell -S Makefile,build,buildah,buildah.spec,imgtype,copy,AUTHORS,bin,vendor,.git,go.sum,CHANGELOG.md,changelog.txt,seccomp.json,.cirrus.yml,"*.xz,*.gz,*.tar,*.tgz,*ico,*.png,*.1,*.5,*.orig,*.rej" -L worl,flate,uint,iff,od,ERRO -w
|
codespell -S Makefile,build,buildah,buildah.spec,imgtype,copy,AUTHORS,bin,vendor,.git,go.sum,CHANGELOG.md,changelog.txt,seccomp.json,.cirrus.yml,"*.xz,*.gz,*.tar,*.tgz,*ico,*.png,*.1,*.5,*.orig,*.rej" -L plack,worl,flate,uint,iff,od,ERRO -w
|
||||||
|
|
||||||
binary local-binary: containers-storage
|
binary local-binary: containers-storage
|
||||||
|
|
||||||
|
|
|
@ -73,11 +73,9 @@ type chunkedDiffer struct {
|
||||||
zstdReader *zstd.Decoder
|
zstdReader *zstd.Decoder
|
||||||
rawReader io.Reader
|
rawReader io.Reader
|
||||||
|
|
||||||
// contentDigest is the digest of the uncompressed content
|
// tocDigest is the digest of the TOC document when the layer
|
||||||
// (diffID) when the layer is fully retrieved. If the layer
|
// is partially pulled.
|
||||||
// is not fully retrieved, instead of using the digest of the
|
tocDigest digest.Digest
|
||||||
// uncompressed content, it refers to the digest of the TOC.
|
|
||||||
contentDigest digest.Digest
|
|
||||||
|
|
||||||
// convertedToZstdChunked is set to true if the layer needs to
|
// convertedToZstdChunked is set to true if the layer needs to
|
||||||
// be converted to the zstd:chunked format before it can be
|
// be converted to the zstd:chunked format before it can be
|
||||||
|
@ -292,7 +290,7 @@ func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize in
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contentDigest, err := digest.Parse(annotations[internal.ManifestChecksumKey])
|
tocDigest, err := digest.Parse(annotations[internal.ManifestChecksumKey])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse TOC digest %q: %w", annotations[internal.ManifestChecksumKey], err)
|
return nil, fmt.Errorf("parse TOC digest %q: %w", annotations[internal.ManifestChecksumKey], err)
|
||||||
}
|
}
|
||||||
|
@ -300,7 +298,7 @@ func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize in
|
||||||
return &chunkedDiffer{
|
return &chunkedDiffer{
|
||||||
fsVerityDigests: make(map[string]string),
|
fsVerityDigests: make(map[string]string),
|
||||||
blobSize: blobSize,
|
blobSize: blobSize,
|
||||||
contentDigest: contentDigest,
|
tocDigest: tocDigest,
|
||||||
copyBuffer: makeCopyBuffer(),
|
copyBuffer: makeCopyBuffer(),
|
||||||
fileType: fileTypeZstdChunked,
|
fileType: fileTypeZstdChunked,
|
||||||
layersCache: layersCache,
|
layersCache: layersCache,
|
||||||
|
@ -322,7 +320,7 @@ func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contentDigest, err := digest.Parse(annotations[estargz.TOCJSONDigestAnnotation])
|
tocDigest, err := digest.Parse(annotations[estargz.TOCJSONDigestAnnotation])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse TOC digest %q: %w", annotations[estargz.TOCJSONDigestAnnotation], err)
|
return nil, fmt.Errorf("parse TOC digest %q: %w", annotations[estargz.TOCJSONDigestAnnotation], err)
|
||||||
}
|
}
|
||||||
|
@ -330,7 +328,7 @@ func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize
|
||||||
return &chunkedDiffer{
|
return &chunkedDiffer{
|
||||||
fsVerityDigests: make(map[string]string),
|
fsVerityDigests: make(map[string]string),
|
||||||
blobSize: blobSize,
|
blobSize: blobSize,
|
||||||
contentDigest: contentDigest,
|
tocDigest: tocDigest,
|
||||||
copyBuffer: makeCopyBuffer(),
|
copyBuffer: makeCopyBuffer(),
|
||||||
fileType: fileTypeEstargz,
|
fileType: fileTypeEstargz,
|
||||||
layersCache: layersCache,
|
layersCache: layersCache,
|
||||||
|
@ -1613,6 +1611,9 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
// stream to use for reading the zstd:chunked or Estargz file.
|
// stream to use for reading the zstd:chunked or Estargz file.
|
||||||
stream := c.stream
|
stream := c.stream
|
||||||
|
|
||||||
|
var uncompressedDigest digest.Digest
|
||||||
|
tocDigest := c.tocDigest
|
||||||
|
|
||||||
if c.convertToZstdChunked {
|
if c.convertToZstdChunked {
|
||||||
fd, err := unix.Open(dest, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600)
|
fd, err := unix.Open(dest, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1663,13 +1664,13 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
c.fileType = fileTypeZstdChunked
|
c.fileType = fileTypeZstdChunked
|
||||||
c.manifest = manifest
|
c.manifest = manifest
|
||||||
c.tarSplit = tarSplit
|
c.tarSplit = tarSplit
|
||||||
|
|
||||||
// since we retrieved the whole file and it was validated, use the diffID instead of the TOC digest.
|
|
||||||
c.contentDigest = diffID
|
|
||||||
c.tocOffset = tocOffset
|
c.tocOffset = tocOffset
|
||||||
|
|
||||||
// the file was generated by us and the digest for each file was already computed, no need to validate it again.
|
// the file was generated by us and the digest for each file was already computed, no need to validate it again.
|
||||||
c.skipValidation = true
|
c.skipValidation = true
|
||||||
|
// since we retrieved the whole file and it was validated, do not use the TOC digest, but set the uncompressed digest.
|
||||||
|
tocDigest = ""
|
||||||
|
uncompressedDigest = diffID
|
||||||
}
|
}
|
||||||
|
|
||||||
lcd := chunkedLayerData{
|
lcd := chunkedLayerData{
|
||||||
|
@ -1698,7 +1699,8 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
Artifacts: map[string]interface{}{
|
Artifacts: map[string]interface{}{
|
||||||
tocKey: toc,
|
tocKey: toc,
|
||||||
},
|
},
|
||||||
TOCDigest: c.contentDigest,
|
TOCDigest: tocDigest,
|
||||||
|
UncompressedDigest: uncompressedDigest,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !parseBooleanPullOption(c.storeOpts, "enable_partial_images", false) {
|
if !parseBooleanPullOption(c.storeOpts, "enable_partial_images", false) {
|
||||||
|
|
|
@ -167,7 +167,7 @@ github.com/containers/buildah/pkg/sshagent
|
||||||
github.com/containers/buildah/pkg/util
|
github.com/containers/buildah/pkg/util
|
||||||
github.com/containers/buildah/pkg/volumes
|
github.com/containers/buildah/pkg/volumes
|
||||||
github.com/containers/buildah/util
|
github.com/containers/buildah/util
|
||||||
# github.com/containers/common v0.57.1-0.20240129201029-3310a75e3608
|
# github.com/containers/common v0.57.1-0.20240130143645-b26099256b92
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
github.com/containers/common/internal/attributedstring
|
github.com/containers/common/internal/attributedstring
|
||||||
github.com/containers/common/libimage
|
github.com/containers/common/libimage
|
||||||
|
@ -236,7 +236,7 @@ github.com/containers/conmon/runner/config
|
||||||
# github.com/containers/gvisor-tap-vsock v0.7.2
|
# github.com/containers/gvisor-tap-vsock v0.7.2
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
github.com/containers/gvisor-tap-vsock/pkg/types
|
github.com/containers/gvisor-tap-vsock/pkg/types
|
||||||
# github.com/containers/image/v5 v5.29.2-0.20240129204525-816800b5daf7
|
# github.com/containers/image/v5 v5.29.2-0.20240130233108-e66a1ade2efc
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
github.com/containers/image/v5/copy
|
github.com/containers/image/v5/copy
|
||||||
github.com/containers/image/v5/directory
|
github.com/containers/image/v5/directory
|
||||||
|
@ -346,7 +346,7 @@ github.com/containers/psgo/internal/dev
|
||||||
github.com/containers/psgo/internal/host
|
github.com/containers/psgo/internal/host
|
||||||
github.com/containers/psgo/internal/proc
|
github.com/containers/psgo/internal/proc
|
||||||
github.com/containers/psgo/internal/process
|
github.com/containers/psgo/internal/process
|
||||||
# github.com/containers/storage v1.52.1-0.20240129173630-7a525ce0e2bc
|
# github.com/containers/storage v1.52.1-0.20240130205044-62997abeaf2f
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
github.com/containers/storage
|
github.com/containers/storage
|
||||||
github.com/containers/storage/drivers
|
github.com/containers/storage/drivers
|
||||||
|
|
Loading…
Reference in New Issue