Compare commits
36 Commits
Author | SHA1 | Date |
---|---|---|
|
66fc1cc64f | |
|
04b6c47895 | |
|
fe095fd4b3 | |
|
a2eb9b4823 | |
|
d6ba7488b2 | |
|
58b4fbdc03 | |
|
7f9559b3ac | |
|
9ed811d204 | |
|
31dce751c8 | |
|
6e59fa69eb | |
|
cd74eeb550 | |
|
5e89744b23 | |
|
196004fe46 | |
|
b7e0b93adb | |
|
e3242f37c7 | |
|
897f8ddae1 | |
|
92b9653353 | |
|
a89d6d6ef0 | |
|
6cb9178d24 | |
|
5fc3515715 | |
|
5a9541f97f | |
|
785b690989 | |
|
5ab12464fb | |
|
0b65653d80 | |
|
6294d7d1ee | |
|
136c5f75df | |
|
b02ec6036f | |
|
ef10f184b1 | |
|
3eabf12196 | |
|
7f02a36e85 | |
|
164ca27d7f | |
|
2a7c6195b4 | |
|
70fd604f0f | |
|
c9527473cf | |
|
42293a3a71 | |
|
f902cdff07 |
15
.packit.yaml
15
.packit.yaml
|
@ -12,14 +12,17 @@ jobs:
|
|||
- openssl-devel
|
||||
- rpkg
|
||||
targets:
|
||||
- fedora-latest-stable-x86_64
|
||||
- fedora-latest-stable-aarch64
|
||||
- fedora-development-x86_64
|
||||
- fedora-development-aarch64
|
||||
- fedora-all-x86_64
|
||||
- fedora-all-aarch64
|
||||
- epel-9-x86_64
|
||||
- epel-9-aarch64
|
||||
# temporary disabled since epel10 running go v1.23.1 and we need 1.23.3
|
||||
# - epel-10-x86_64
|
||||
# - epel-10-aarch64
|
||||
- centos-stream-9-x86_64
|
||||
- centos-stream-9-aarch64
|
||||
- centos-stream-10-x86_64
|
||||
- centos-stream-10-aarch64
|
||||
# - centos-stream-10-x86_64
|
||||
# - centos-stream-10-aarch64
|
||||
|
||||
actions:
|
||||
post-upstream-clone:
|
||||
|
|
|
@ -39,7 +39,7 @@ type App struct {
|
|||
currentPage string
|
||||
needInitUI bool
|
||||
fastRefreshChan chan bool
|
||||
config *config.Config
|
||||
config config.Config
|
||||
}
|
||||
|
||||
// NewApp returns new app.
|
||||
|
@ -73,10 +73,10 @@ func NewApp(name string, version string) *App {
|
|||
app.secrets = secrets.NewSecrets()
|
||||
app.system = system.NewSystem()
|
||||
|
||||
app.system.SetConnectionListFunc(app.config.ServicesConnections)
|
||||
app.system.SetConnectionListFunc(app.config.RemoteConnections)
|
||||
app.system.SetConnectionSetDefaultFunc(func(name string) error {
|
||||
err := app.config.SetDefaultService(name)
|
||||
app.system.UpdateConnectionsData()
|
||||
err := app.config.SetDefaultConnection(name)
|
||||
app.system.UpdateData()
|
||||
|
||||
return err
|
||||
})
|
||||
|
|
|
@ -13,7 +13,7 @@ func (app *App) initUI() {
|
|||
app.initInfoBar()
|
||||
}
|
||||
|
||||
app.system.UpdateConnectionsData()
|
||||
app.system.UpdateData()
|
||||
}
|
||||
|
||||
func (app *App) initInfoBar() {
|
||||
|
|
|
@ -71,7 +71,7 @@ func (app *App) refreshNotConnOK() {
|
|||
app.switchToScreen(app.system.GetTitle())
|
||||
}
|
||||
|
||||
app.system.UpdateConnectionsData()
|
||||
app.system.UpdateData()
|
||||
|
||||
app.needInitUI = true
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ func (app *App) updatePageData(page string) {
|
|||
|
||||
switch page {
|
||||
case app.system.GetTitle():
|
||||
app.system.UpdateConnectionsData()
|
||||
app.system.UpdateData()
|
||||
case app.pods.GetTitle():
|
||||
app.pods.UpdateData()
|
||||
case app.containers.GetTitle():
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
appVersion = "1.5.0"
|
||||
appVersion = "1.7.0-dev"
|
||||
)
|
||||
|
||||
// versionCmd represents the version command.
|
||||
|
|
133
config/add.go
133
config/add.go
|
@ -1,133 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/containers/podman-tui/ui/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Add adds new service connection.
|
||||
func (c *Config) Add(name string, uri string, identity string) error {
|
||||
log.Debug().Msgf("config: adding new service %s %s %s", name, uri, identity)
|
||||
|
||||
newService, err := validateNewService(name, uri, identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.add(name, newService); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.reload()
|
||||
}
|
||||
|
||||
func (c *Config) add(name string, newService Service) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for serviceName := range c.Services {
|
||||
if serviceName == name {
|
||||
return ErrDuplicatedServiceName
|
||||
}
|
||||
}
|
||||
|
||||
c.Services[name] = newService
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// most of codes are from:
|
||||
// https://github.com/containers/podman/blob/main/cmd/podman/system/connection/add.go.
|
||||
func validateNewService(name string, dest string, identity string) (Service, error) { //nolint:cyclop
|
||||
var (
|
||||
service Service
|
||||
serviceIdentity string
|
||||
)
|
||||
|
||||
if name == "" {
|
||||
return service, ErrEmptyServiceName
|
||||
}
|
||||
|
||||
if dest == "" {
|
||||
return service, ErrEmptyURIDestination
|
||||
}
|
||||
|
||||
if match, err := regexp.Match("^[A-Za-z][A-Za-z0-9+.-]*://", []byte(dest)); err != nil { //nolint:mirror
|
||||
return service, fmt.Errorf("%w invalid destition", err)
|
||||
} else if !match {
|
||||
dest = "ssh://" + dest
|
||||
}
|
||||
|
||||
uri, err := url.Parse(dest)
|
||||
if err != nil {
|
||||
return service, err
|
||||
}
|
||||
|
||||
switch uri.Scheme {
|
||||
case "ssh":
|
||||
if uri.User.Username() == "" {
|
||||
if uri.User, err = getUserInfo(uri); err != nil {
|
||||
return service, err
|
||||
}
|
||||
}
|
||||
|
||||
serviceIdentity, err = utils.ResolveHomeDir(identity)
|
||||
if err != nil {
|
||||
return service, err
|
||||
}
|
||||
|
||||
if identity == "" {
|
||||
return service, ErrEmptySSHIdentity
|
||||
}
|
||||
|
||||
if uri.Port() == "" {
|
||||
uri.Host = net.JoinHostPort(uri.Hostname(), "22")
|
||||
}
|
||||
|
||||
if uri.Path == "" || uri.Path == "/" {
|
||||
if uri.Path, err = getUDS(uri, serviceIdentity); err != nil {
|
||||
return service, err
|
||||
}
|
||||
}
|
||||
case "unix":
|
||||
if identity != "" {
|
||||
return service, fmt.Errorf("%w identity", ErrInvalidUnixSchemaOption)
|
||||
}
|
||||
|
||||
info, err := os.Stat(uri.Path)
|
||||
|
||||
switch {
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
log.Warn().Msgf("config: %q does not exists", uri.Path)
|
||||
case errors.Is(err, os.ErrPermission):
|
||||
log.Warn().Msgf("config: You do not have permission to read %q", uri.Path)
|
||||
case err != nil:
|
||||
return service, err
|
||||
case info.Mode()&os.ModeSocket == 0:
|
||||
return service, fmt.Errorf("%w %q", ErrFileNotUnixSocket, uri.Path)
|
||||
}
|
||||
case "tcp":
|
||||
if identity != "" {
|
||||
return service, fmt.Errorf("%w identity", ErrInvalidTCPSchemaOption)
|
||||
}
|
||||
default:
|
||||
return service, fmt.Errorf("%w %q", ErrInvalidURISchemaName, uri.Scheme)
|
||||
}
|
||||
|
||||
service.Identity = serviceIdentity
|
||||
service.URI = uri.String()
|
||||
service.Default = false
|
||||
|
||||
return service, nil
|
||||
}
|
123
config/config.go
123
config/config.go
|
@ -1,124 +1,43 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/podman-tui/config/pconfig"
|
||||
"github.com/containers/podman-tui/config/tconfig"
|
||||
"github.com/containers/podman-tui/pdcs/registry"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// _configPath is the path to the podman-tui/podman-tui.conf
|
||||
// inside a given config directory.
|
||||
_configPath = "podman-tui/podman-tui.conf"
|
||||
// UserAppConfig holds the user podman-tui config path.
|
||||
UserAppConfig = ".config/" + _configPath
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRemotePodmanUDSReport = errors.New("remote podman failed to report its UDS socket")
|
||||
ErrInvalidURISchemaName = errors.New("invalid schema name")
|
||||
ErrInvalidTCPSchemaOption = errors.New("invalid option for tcp")
|
||||
ErrInvalidUnixSchemaOption = errors.New("invalid option for unix")
|
||||
ErrFileNotUnixSocket = errors.New("not a unix domain socket")
|
||||
ErrEmptySSHIdentity = errors.New("empty identity field for SSH connection")
|
||||
ErrEmptyURIDestination = errors.New("empty URI destination")
|
||||
ErrEmptyServiceName = errors.New("empty service name")
|
||||
ErrDuplicatedServiceName = errors.New("duplicated service name")
|
||||
)
|
||||
|
||||
// Config contains configuration options for container tools.
|
||||
type Config struct {
|
||||
mu sync.Mutex
|
||||
// Services specify the service destination connections
|
||||
Services map[string]Service `toml:"services,omitempty"`
|
||||
type Config interface {
|
||||
RemoteConnections() []registry.Connection
|
||||
SetDefaultConnection(name string) error
|
||||
GetDefaultConnection() registry.Connection
|
||||
Add(name string, uri string, identity string) error
|
||||
Remove(name string) error
|
||||
}
|
||||
|
||||
// Service represents remote service destination.
|
||||
type Service struct {
|
||||
// URI, required. Example: ssh://root@example.com:22/run/podman/podman.sock
|
||||
URI string `toml:"uri"`
|
||||
func NewConfig() (Config, error) { //nolint:ireturn
|
||||
var cfg Config
|
||||
|
||||
// Identity file with ssh key, optional
|
||||
Identity string `toml:"identity,omitempty"`
|
||||
|
||||
// Default if its default service, optional
|
||||
Default bool `toml:"default,omitempty"`
|
||||
}
|
||||
|
||||
// NewConfig returns new config.
|
||||
func NewConfig() (*Config, error) {
|
||||
log.Debug().Msgf("config: new")
|
||||
|
||||
path, err := configPath()
|
||||
pconfig, err := pconfig.NewConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newConfig := &Config{}
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
if err := newConfig.readConfigFromFile(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
premoteConns := pconfig.RemoteConnections()
|
||||
if len(premoteConns) > 0 {
|
||||
cfg = pconfig
|
||||
} else {
|
||||
if !os.IsNotExist(err) {
|
||||
tconfig, err := tconfig.NewConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg = tconfig
|
||||
}
|
||||
|
||||
newConfig.addLocalHostIfEmptyConfig()
|
||||
|
||||
defaultConn := newConfig.getDefault()
|
||||
if defaultConn.URI != "" {
|
||||
defaultConn := cfg.GetDefaultConnection()
|
||||
if defaultConn.URI != "" && defaultConn.Name != "" {
|
||||
registry.SetConnection(defaultConn)
|
||||
}
|
||||
|
||||
return newConfig, nil
|
||||
}
|
||||
|
||||
func (c *Config) addLocalHostIfEmptyConfig() {
|
||||
if len(c.Services) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.Services = make(map[string]Service)
|
||||
c.Services["localhost"] = Service{
|
||||
URI: localNodeUnixSocket(),
|
||||
Default: true,
|
||||
}
|
||||
}
|
||||
|
||||
// ServicesConnections returns list of available connections.
|
||||
func (c *Config) ServicesConnections() []registry.Connection {
|
||||
conn := make([]registry.Connection, 0)
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for name, service := range c.Services {
|
||||
conn = append(conn, registry.Connection{
|
||||
Name: name,
|
||||
URI: service.URI,
|
||||
Identity: service.Identity,
|
||||
Default: service.Default,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Sort(connectionListSortedName{conn})
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
type connSort []registry.Connection
|
||||
|
||||
func (a connSort) Len() int { return len(a) }
|
||||
func (a connSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
type connectionListSortedName struct{ connSort }
|
||||
|
||||
func (a connectionListSortedName) Less(i, j int) bool {
|
||||
return a.connSort[i].Name < a.connSort[j].Name
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/containers/podman-tui/pdcs/registry"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// SetDefaultService sets default service name.
|
||||
func (c *Config) SetDefaultService(name string) error {
|
||||
log.Debug().Msgf("config: set %s as default service", name)
|
||||
|
||||
if err := c.setDef(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.reload()
|
||||
}
|
||||
|
||||
func (c *Config) setDef(name string) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for key := range c.Services {
|
||||
dest := c.Services[key]
|
||||
dest.Default = false
|
||||
|
||||
if key == name {
|
||||
dest.Default = true
|
||||
}
|
||||
|
||||
c.Services[key] = dest
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) getDefault() registry.Connection {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for name, service := range c.Services {
|
||||
if service.Default {
|
||||
return registry.Connection{
|
||||
Name: name,
|
||||
Identity: service.Identity,
|
||||
URI: service.URI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return registry.Connection{}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package pconfig
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
cconfig "github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman-tui/config/utils"
|
||||
"github.com/containers/podman-tui/pdcs/registry"
|
||||
"github.com/containers/podman/v5/pkg/domain/entities"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
podmanOptions *entities.PodmanConfig
|
||||
}
|
||||
|
||||
func NewConfig() (*Config, error) {
|
||||
log.Debug().Msg("config: loading podman remote connections")
|
||||
|
||||
newConfig := &Config{}
|
||||
|
||||
defaultConfig, err := cconfig.New(&cconfig.Options{
|
||||
SetDefault: true,
|
||||
Modules: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podmanOptions := entities.PodmanConfig{ContainersConf: &cconfig.Config{}, ContainersConfDefaultsRO: defaultConfig}
|
||||
newConfig.podmanOptions = &podmanOptions
|
||||
|
||||
return newConfig, nil
|
||||
}
|
||||
|
||||
func (c *Config) RemoteConnections() []registry.Connection {
|
||||
rconn := make([]registry.Connection, 0)
|
||||
|
||||
conns, err := c.podmanOptions.ContainersConfDefaultsRO.GetAllConnections()
|
||||
if err != nil {
|
||||
log.Err(err).Msgf("config: podman remote connection")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug().Msgf("connections: %v", conns)
|
||||
|
||||
for _, conn := range conns {
|
||||
rconn = append(rconn, registry.Connection{
|
||||
Name: conn.Name,
|
||||
URI: conn.URI,
|
||||
Identity: conn.Identity,
|
||||
Default: conn.Default,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Sort(utils.ConnectionListSortedName{rconn}) //nolint:govet
|
||||
|
||||
return rconn
|
||||
}
|
||||
|
||||
func (c *Config) Remove(name string) error {
|
||||
return cconfig.EditConnectionConfig(func(cfg *cconfig.ConnectionsFile) error {
|
||||
delete(cfg.Connection.Connections, name)
|
||||
|
||||
if cfg.Connection.Default == name {
|
||||
cfg.Connection.Default = ""
|
||||
}
|
||||
|
||||
// If there are existing farm, remove the deleted connection that might be part of a farm
|
||||
for k, v := range cfg.Farm.List {
|
||||
index := slices.Index(v, name)
|
||||
if index > -1 {
|
||||
cfg.Farm.List[k] = append(v[:index], v[index+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Config) Add(name string, uri string, identity string) error {
|
||||
connURI, err := utils.ValidateNewConnection(name, uri, identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dst := cconfig.Destination{
|
||||
URI: connURI,
|
||||
Identity: identity,
|
||||
}
|
||||
|
||||
return cconfig.EditConnectionConfig(func(cfg *cconfig.ConnectionsFile) error {
|
||||
if cfg.Connection.Connections == nil {
|
||||
cfg.Connection.Connections = map[string]cconfig.Destination{
|
||||
name: dst,
|
||||
}
|
||||
cfg.Connection.Default = name
|
||||
} else {
|
||||
cfg.Connection.Connections[name] = dst
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Config) SetDefaultConnection(name string) error {
|
||||
return cconfig.EditConnectionConfig(func(cfg *cconfig.ConnectionsFile) error {
|
||||
if _, found := cfg.Connection.Connections[name]; !found {
|
||||
return utils.ErrConnectionNotFound
|
||||
}
|
||||
|
||||
cfg.Connection.Default = name
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Config) GetDefaultConnection() registry.Connection {
|
||||
for _, conn := range c.RemoteConnections() {
|
||||
if conn.Default {
|
||||
return registry.Connection{
|
||||
Name: conn.Name,
|
||||
Identity: conn.Identity,
|
||||
URI: conn.URI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return registry.Connection{}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package config
|
||||
|
||||
import "github.com/rs/zerolog/log"
|
||||
|
||||
// Remove removes a service from config.
|
||||
func (c *Config) Remove(name string) error {
|
||||
log.Debug().Msgf("config: remove service %q", name)
|
||||
|
||||
c.remove(name)
|
||||
|
||||
if err := c.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.reload()
|
||||
}
|
||||
|
||||
func (c *Config) remove(name string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for serviceName := range c.Services {
|
||||
if serviceName == name {
|
||||
delete(c.Services, name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package tconfig
|
||||
|
||||
import (
|
||||
"github.com/containers/podman-tui/config/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Add adds a new remote connection.
|
||||
func (c *Config) Add(name string, uri string, identity string) error {
|
||||
log.Debug().Msgf("config: adding new remote connection %s %s %s", name, uri, identity)
|
||||
|
||||
connURI, err := utils.ValidateNewConnection(name, uri, identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn := RemoteConnection{
|
||||
URI: connURI,
|
||||
Identity: identity,
|
||||
Default: false,
|
||||
}
|
||||
|
||||
if err := c.add(name, conn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.reload()
|
||||
}
|
||||
|
||||
func (c *Config) add(name string, conn RemoteConnection) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for connName := range c.Connection.Connections {
|
||||
if connName == name {
|
||||
return ErrDuplicatedConnectionName
|
||||
}
|
||||
}
|
||||
|
||||
c.Connection.Connections[name] = conn
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package tconfig
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/podman-tui/config/utils"
|
||||
"github.com/containers/podman-tui/pdcs/registry"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// _configPath is the path to the podman-tui/podman-tui.json
|
||||
// inside a given config directory.
|
||||
_configPath = "podman-tui/podman-tui.json"
|
||||
// UserAppConfig holds the user podman-tui config path.
|
||||
UserAppConfig = ".config/" + _configPath
|
||||
)
|
||||
|
||||
var ErrDuplicatedConnectionName = errors.New("duplicated connection name")
|
||||
|
||||
// Config contains configuration options for container tools.
|
||||
type Config struct {
|
||||
mu sync.Mutex
|
||||
Connection RemoteConnections
|
||||
}
|
||||
|
||||
type RemoteConnections struct {
|
||||
Connections map[string]RemoteConnection `json:"connections"`
|
||||
}
|
||||
|
||||
type RemoteConnection struct {
|
||||
// URI, required. Example: ssh://root@example.com:22/run/podman/podman.sock
|
||||
URI string `json:"uri"`
|
||||
|
||||
// Identity file with ssh key, optional
|
||||
Identity string `json:"identity,omitempty"`
|
||||
|
||||
// Default if its default connection, optional
|
||||
Default bool `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
// NewConfig returns new config.
|
||||
func NewConfig() (*Config, error) {
|
||||
path, err := utils.ConfigPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("config: loading from %q", path)
|
||||
|
||||
newConfig := &Config{}
|
||||
newConfig.Connection.Connections = make(map[string]RemoteConnection)
|
||||
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
if err := newConfig.readConfigFromFile(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
newConfig.addLocalHostIfEmptyConfig()
|
||||
|
||||
return newConfig, nil
|
||||
}
|
||||
|
||||
func (c *Config) addLocalHostIfEmptyConfig() {
|
||||
if len(c.Connection.Connections) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.Connection.Connections = make(map[string]RemoteConnection)
|
||||
c.Connection.Connections["localhost"] = RemoteConnection{
|
||||
URI: utils.LocalNodeUnixSocket(),
|
||||
Default: true,
|
||||
}
|
||||
}
|
||||
|
||||
// RemoteConnections returns list of available connections.
|
||||
func (c *Config) RemoteConnections() []registry.Connection {
|
||||
rconn := make([]registry.Connection, 0)
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for name, conn := range c.Connection.Connections {
|
||||
rconn = append(rconn, registry.Connection{
|
||||
Name: name,
|
||||
URI: conn.URI,
|
||||
Identity: conn.Identity,
|
||||
Default: conn.Default,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Sort(utils.ConnectionListSortedName{rconn}) //nolint:govet
|
||||
|
||||
return rconn
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package tconfig
|
||||
|
||||
import (
|
||||
"github.com/containers/podman-tui/config/utils"
|
||||
"github.com/containers/podman-tui/pdcs/registry"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// SetDefaultConnection sets default connection.
|
||||
func (c *Config) SetDefaultConnection(name string) error {
|
||||
log.Debug().Msgf("config: set %s as default connection", name)
|
||||
|
||||
if err := c.setDef(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.reload()
|
||||
}
|
||||
|
||||
func (c *Config) setDef(name string) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for connName := range c.Connection.Connections {
|
||||
if connName == name {
|
||||
dest := c.Connection.Connections[connName]
|
||||
dest.Default = true
|
||||
c.Connection.Connections[connName] = dest
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return utils.ErrConnectionNotFound
|
||||
}
|
||||
|
||||
func (c *Config) GetDefaultConnection() registry.Connection {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for connName, conn := range c.Connection.Connections {
|
||||
if conn.Default {
|
||||
return registry.Connection{
|
||||
Name: connName,
|
||||
Identity: conn.Identity,
|
||||
URI: conn.URI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return registry.Connection{}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
package config
|
||||
package tconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containers/podman-tui/config/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
|
@ -14,30 +16,23 @@ func (c *Config) readConfigFromFile(path string) error {
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
rawConfig, err := os.ReadFile(path)
|
||||
cfgFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config: %w open configuration %q", err, path)
|
||||
}
|
||||
|
||||
cfgData, err := io.ReadAll(cfgFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config: %w read configuration %q", err, path)
|
||||
}
|
||||
|
||||
config := os.ExpandEnv(string(rawConfig))
|
||||
|
||||
meta, err := toml.Decode(config, c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config: %w decode configuration %q", err, path)
|
||||
}
|
||||
|
||||
keys := meta.Undecoded()
|
||||
if len(keys) > 0 {
|
||||
log.Debug().Msgf("config: failed to decode the keys %q from %q.", keys, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
return json.Unmarshal(cfgData, &c.Connection)
|
||||
}
|
||||
|
||||
func (c *Config) reload() error {
|
||||
log.Debug().Msgf("config: reload configuration")
|
||||
|
||||
path, err := configPath()
|
||||
path, err := utils.ConfigPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package tconfig
|
||||
|
||||
import "github.com/rs/zerolog/log"
|
||||
|
||||
// Remove removes a connection from config.
|
||||
func (c *Config) Remove(name string) error {
|
||||
log.Debug().Msgf("config: remove remote connection %q", name)
|
||||
|
||||
c.remove(name)
|
||||
|
||||
if err := c.write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.reload()
|
||||
}
|
||||
|
||||
func (c *Config) remove(name string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for connName := range c.Connection.Connections {
|
||||
if connName != name {
|
||||
delete(c.Connection.Connections, name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +1,23 @@
|
|||
package config
|
||||
package tconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containers/podman-tui/config/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Write writes config.
|
||||
func (c *Config) Write() error {
|
||||
func (c *Config) write() error {
|
||||
var err error
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
path, err := configPath()
|
||||
path, err := utils.ConfigPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -33,7 +35,14 @@ func (c *Config) Write() error {
|
|||
|
||||
defer configFile.Close()
|
||||
|
||||
enc := toml.NewEncoder(configFile)
|
||||
jsonData, err := json.Marshal(c.Connection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("config: configuration json marshal %w", err)
|
||||
}
|
||||
|
||||
return enc.Encode(c)
|
||||
if _, err := configFile.Write(jsonData); err != nil {
|
||||
return fmt.Errorf("config: %w write configuration %q", err, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/containers/podman-tui/ui/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidURISchemaName = errors.New("invalid schema name")
|
||||
ErrInvalidTCPSchemaOption = errors.New("invalid option for tcp")
|
||||
ErrInvalidUnixSchemaOption = errors.New("invalid option for unix")
|
||||
ErrFileNotUnixSocket = errors.New("not a unix domain socket")
|
||||
ErrEmptySSHIdentity = errors.New("empty identity field for SSH connection")
|
||||
ErrEmptyURIDestination = errors.New("empty URI destination")
|
||||
ErrEmptyConnectionName = errors.New("empty connection name")
|
||||
ErrConnectionNotFound = errors.New("connection not found")
|
||||
)
|
||||
|
||||
func ValidateNewConnection(name string, dest string, identity string) (string, error) { //nolint:cyclop
|
||||
var connIdentity string
|
||||
|
||||
if name == "" {
|
||||
return "", ErrEmptyConnectionName
|
||||
}
|
||||
|
||||
if dest == "" {
|
||||
return "", ErrEmptyURIDestination
|
||||
}
|
||||
|
||||
if match, err := regexp.Match("^[A-Za-z][A-Za-z0-9+.-]*://", []byte(dest)); err != nil { //nolint:mirror
|
||||
return "", fmt.Errorf("%w invalid destition", err)
|
||||
} else if !match {
|
||||
dest = "ssh://" + dest
|
||||
}
|
||||
|
||||
uri, err := url.Parse(dest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch uri.Scheme {
|
||||
case "ssh":
|
||||
if uri.User.Username() == "" {
|
||||
if uri.User, err = getUserInfo(uri); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
connIdentity, err = utils.ResolveHomeDir(identity)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if identity == "" {
|
||||
return "", ErrEmptySSHIdentity
|
||||
}
|
||||
|
||||
if uri.Port() == "" {
|
||||
uri.Host = net.JoinHostPort(uri.Hostname(), "22")
|
||||
}
|
||||
|
||||
if uri.Path == "" || uri.Path == "/" {
|
||||
if uri.Path, err = getUDS(uri, connIdentity); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
case "unix":
|
||||
if identity != "" {
|
||||
return "", fmt.Errorf("%w identity", ErrInvalidUnixSchemaOption)
|
||||
}
|
||||
|
||||
info, err := os.Stat(uri.Path)
|
||||
|
||||
switch {
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
log.Warn().Msgf("config: %q does not exists", uri.Path)
|
||||
case errors.Is(err, os.ErrPermission):
|
||||
log.Warn().Msgf("config: You do not have permission to read %q", uri.Path)
|
||||
case err != nil:
|
||||
return "", err
|
||||
case info.Mode()&os.ModeSocket == 0:
|
||||
return "", fmt.Errorf("%w %q", ErrFileNotUnixSocket, uri.Path)
|
||||
}
|
||||
case "tcp":
|
||||
if identity != "" {
|
||||
return "", fmt.Errorf("%w identity", ErrInvalidTCPSchemaOption)
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("%w %q", ErrInvalidURISchemaName, uri.Scheme)
|
||||
}
|
||||
|
||||
return uri.String(), nil
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package utils
|
||||
|
||||
import "github.com/containers/podman-tui/pdcs/registry"
|
||||
|
||||
type ConnSort []registry.Connection
|
||||
|
||||
func (a ConnSort) Len() int { return len(a) }
|
||||
func (a ConnSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
type ConnectionListSortedName struct{ ConnSort }
|
||||
|
||||
func (a ConnectionListSortedName) Less(i, j int) bool {
|
||||
return a.ConnSort[i].Name < a.ConnSort[j].Name
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package config
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
|
@ -19,7 +20,17 @@ import (
|
|||
"golang.org/x/crypto/ssh/agent"
|
||||
)
|
||||
|
||||
func configPath() (string, error) {
|
||||
const (
|
||||
// _configPath is the path to the podman-tui/podman-tui.json
|
||||
// inside a given config directory.
|
||||
_configPath = "podman-tui/podman-tui.json"
|
||||
// UserAppConfig holds the user podman-tui config path.
|
||||
UserAppConfig = ".config/" + _configPath
|
||||
)
|
||||
|
||||
var ErrRemotePodmanUDSReport = errors.New("remote podman failed to report its UDS socket")
|
||||
|
||||
func ConfigPath() (string, error) {
|
||||
if configHome := os.Getenv("XDG_CONFIG_HOME"); configHome != "" {
|
||||
return filepath.Join(configHome, _configPath), nil
|
||||
}
|
||||
|
@ -32,8 +43,8 @@ func configPath() (string, error) {
|
|||
return filepath.Join(home, UserAppConfig), nil
|
||||
}
|
||||
|
||||
// localNodeUnixSocket return local node unix socket file.
|
||||
func localNodeUnixSocket() string {
|
||||
// LocalNodeUnixSocket return local node unix socket file.
|
||||
func LocalNodeUnixSocket() string {
|
||||
var (
|
||||
sockDir string
|
||||
socket string
|
||||
|
@ -48,7 +59,7 @@ func localNodeUnixSocket() string {
|
|||
sockDir = os.Getenv("XDG_RUNTIME_DIR")
|
||||
}
|
||||
|
||||
socket = "unix:" + sockDir + "/podman/podman.sock"
|
||||
socket = "unix:/" + sockDir + "/podman/podman.sock"
|
||||
|
||||
return socket
|
||||
}
|
|
@ -112,22 +112,27 @@ $ podman run -it --name podman-tui-app \
|
|||
|
||||
## Configuration Files
|
||||
|
||||
### podman-tui.conf
|
||||
### podman-tui.json
|
||||
|
||||
~/.config/podman-tui/podman-tui.conf
|
||||
~/.config/podman-tui/podman-tui.json
|
||||
|
||||
podman-tui.conf is the configuration file which specifies local and remotes podman systems connections details.
|
||||
podman-tui.json is the configuration file which specifies local and remotes podman systems connections details.
|
||||
|
||||
```shell
|
||||
[services]
|
||||
|
||||
[services.fc36node01]
|
||||
uri = "ssh://navid@fc36node01:22/run/user/1000/podman/podman.sock"
|
||||
identity = "/home/navid/.ssh/id_ed25519"
|
||||
[services.fc36node02]
|
||||
uri = "ssh://navid@fc36node02:22/run/user/1000/podman/podman.sock"
|
||||
identity = "/home/navid/.ssh/id_ed25519"
|
||||
default = true
|
||||
[services.localhost]
|
||||
uri = "unix://run/user/1000/podman/podman.sock"
|
||||
{
|
||||
"connections": {
|
||||
"f42node01": {
|
||||
"uri": "ssh://navid@f42node01:22/run/user/1000/podman/podman.sock",
|
||||
"identity": "/home/navid/.ssh/id_ed25519"
|
||||
},
|
||||
"fc42node02": {
|
||||
"uri": "ssh://navid@f42node02:22/run/user/1000/podman/podman.sock",
|
||||
"identity": "/home/navid/.ssh/id_ed25519"
|
||||
},
|
||||
"localhost": {
|
||||
"uri": "unix://run/user/1000/podman/podman.sock",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
118
go.mod
118
go.mod
|
@ -1,32 +1,32 @@
|
|||
module github.com/containers/podman-tui
|
||||
|
||||
go 1.23.0
|
||||
go 1.23.3
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0
|
||||
github.com/containers/buildah v1.39.4
|
||||
github.com/containers/common v0.62.3
|
||||
github.com/containers/podman/v5 v5.4.2
|
||||
github.com/containers/storage v1.57.2
|
||||
github.com/containers/buildah v1.40.1
|
||||
github.com/containers/common v0.63.1
|
||||
github.com/containers/podman/v5 v5.5.1
|
||||
github.com/containers/storage v1.58.0
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/gdamore/tcell/v2 v2.8.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02
|
||||
github.com/navidys/tvxwidgets v0.4.1
|
||||
github.com/onsi/ginkgo/v2 v2.22.2
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.9.1
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/crypto v0.39.0
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.9 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
|
@ -34,50 +34,50 @@ require (
|
|||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.5 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v1.0.0-rc.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.2.3 // indirect
|
||||
github.com/containers/image/v5 v5.34.3 // indirect
|
||||
github.com/containers/image/v5 v5.35.0 // indirect
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
|
||||
github.com/containers/ocicrypt v1.2.1 // indirect
|
||||
github.com/containers/psgo v1.9.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/disiqueira/gotree/v3 v3.0.2 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v27.5.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/docker v28.1.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/loads v0.22.0 // indirect
|
||||
github.com/go-openapi/runtime v0.28.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20241109141217-c266b19b28e9 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.2 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.3 // indirect
|
||||
github.com/google/go-intervals v0.0.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
|
@ -87,77 +87,79 @@ require (
|
|||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.24 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.28 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/sys/capability v0.4.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/user v0.3.0 // indirect
|
||||
github.com/moby/sys/user v0.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/nxadm/tail v1.4.11 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/opencontainers/cgroups v0.0.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/runc v1.2.4 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20241108202711-f7e3563b0271 // indirect
|
||||
github.com/opencontainers/selinux v1.11.1 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runc v1.2.6 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.1 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250303011046-260e151b8552 // indirect
|
||||
github.com/opencontainers/selinux v1.12.0 // indirect
|
||||
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f // indirect
|
||||
github.com/pkg/sftp v1.13.7 // indirect
|
||||
github.com/pkg/sftp v1.13.9 // indirect
|
||||
github.com/proglottis/gpgme v0.1.4 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
|
||||
github.com/sigstore/fulcio v1.6.4 // indirect
|
||||
github.com/sigstore/rekor v1.3.8 // indirect
|
||||
github.com/sigstore/sigstore v1.8.12 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/sigstore/fulcio v1.6.6 // indirect
|
||||
github.com/sigstore/protobuf-specs v0.4.1 // indirect
|
||||
github.com/sigstore/rekor v1.3.10 // indirect
|
||||
github.com/sigstore/sigstore v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/smallstep/pkcs7 v0.1.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
|
||||
github.com/sylabs/sif/v2 v2.20.2 // indirect
|
||||
github.com/sylabs/sif/v2 v2.21.1 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/vbatts/tar-split v0.11.7 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.9.1 // indirect
|
||||
github.com/vbatts/tar-split v0.12.1 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.9.3 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
|
||||
go.opentelemetry.io/otel v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
|
||||
google.golang.org/grpc v1.69.4 // indirect
|
||||
google.golang.org/protobuf v1.36.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
tags.cncf.io/container-device-interface v0.8.0 // indirect
|
||||
tags.cncf.io/container-device-interface v1.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.1-0.20240131200429-02120488a4c0
|
||||
|
|
282
go.sum
282
go.sum
|
@ -38,8 +38,8 @@ github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
|||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
|
||||
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
|
||||
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
|
||||
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||
|
@ -52,32 +52,32 @@ github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRcc
|
|||
github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU=
|
||||
github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=
|
||||
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
|
||||
github.com/containers/buildah v1.39.4 h1:XTL1+N9wJcSAqXUl4ReFK286QWLTIGp44jBqs9Qd2y0=
|
||||
github.com/containers/buildah v1.39.4/go.mod h1:EPFAYD/27eXceT8shzWxKg+asgorc8nzrjiG9qFCqTk=
|
||||
github.com/containers/common v0.62.3 h1:aOGryqXfW6aKBbHbqOveH7zB+ihavUN03X/2pUSvWFI=
|
||||
github.com/containers/common v0.62.3/go.mod h1:3R8kDox2prC9uj/a2hmXj/YjZz5sBEUNrcDiw51S0Lo=
|
||||
github.com/containers/image/v5 v5.34.3 h1:/cMgfyA4Y7ILH7nzWP/kqpkE5Df35Ek4bp5ZPvJOVmI=
|
||||
github.com/containers/image/v5 v5.34.3/go.mod h1:MG++slvQSZVq5ejAcLdu4APGsKGMb0YHHnAo7X28fdE=
|
||||
github.com/containers/buildah v1.40.1 h1:RW+Fbelwblzg1mJfKfyGZPS4Nbc5QtT866fJ9pYFtYo=
|
||||
github.com/containers/buildah v1.40.1/go.mod h1:1UCQBc3LZrT4u5R/u7igGgUQxeDlJmn/OyYDQ9mumFk=
|
||||
github.com/containers/common v0.63.1 h1:6g02gbW34PaRVH4Heb2Pk11x0SdbQ+8AfeKKeQGqYBE=
|
||||
github.com/containers/common v0.63.1/go.mod h1:+3GCotSqNdIqM3sPs152VvW7m5+Mg8Kk+PExT3G9hZw=
|
||||
github.com/containers/image/v5 v5.35.0 h1:T1OeyWp3GjObt47bchwD9cqiaAm/u4O4R9hIWdrdrP8=
|
||||
github.com/containers/image/v5 v5.35.0/go.mod h1:8vTsgb+1gKcBL7cnjyNOInhJQfTUQjJoO2WWkKDoebM=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v1.2.1 h1:0qIOTT9DoYwcKmxSt8QJt+VzMY18onl9jUXsxpVhSmM=
|
||||
github.com/containers/ocicrypt v1.2.1/go.mod h1:aD0AAqfMp0MtwqWgHM1bUwe1anx0VazI108CRrSKINQ=
|
||||
github.com/containers/podman/v5 v5.4.2 h1:r1Rv6GiH0YCFS91B+f0DEgEZK8yfzzkjiECVLjLjcuQ=
|
||||
github.com/containers/podman/v5 v5.4.2/go.mod h1:LpcnC+53Ln+wVP7XlGR54RrK6wDlgbuknb5jS6G2+fE=
|
||||
github.com/containers/podman/v5 v5.5.1 h1:nFqybTuKX6kLvnQ67hScE0/ihba5k+qHFArXdopnqlI=
|
||||
github.com/containers/podman/v5 v5.5.1/go.mod h1:mxncFv2XqD6ZlXZnBk4JpGmQfkx1+k7KyuBTy1d4Xfc=
|
||||
github.com/containers/psgo v1.9.0 h1:eJ74jzSaCHnWt26OlKZROSyUyRcGDf+gYBdXnxrMW4g=
|
||||
github.com/containers/psgo v1.9.0/go.mod h1:0YoluUm43Mz2UnBIh1P+6V6NWcbpTL5uRtXyOcH0B5A=
|
||||
github.com/containers/storage v1.57.2 h1:2roCtTyE9pzIaBDHibK72DTnYkPmwWaq5uXxZdaWK4U=
|
||||
github.com/containers/storage v1.57.2/go.mod h1:i/Hb4lu7YgFr9G0K6BMjqW0BLJO1sFsnWQwj2UoWCUM=
|
||||
github.com/containers/storage v1.58.0 h1:Q7SyyCCjqgT3wYNgRNIL8o/wUS92heIj2/cc8Sewvcc=
|
||||
github.com/containers/storage v1.58.0/go.mod h1:w7Jl6oG+OpeLGLzlLyOZPkmUso40kjpzgrHUk5tyBlo=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 h1:OoRAFlvDGCUqDLampLQjk0yeeSGdF9zzst/3G9IkBbc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09/go.mod h1:m2r/smMKsKwgMSAoFKHaa68ImdCSNuKE1MxvQ64xuCQ=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
|
@ -86,14 +86,14 @@ github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWh
|
|||
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY=
|
||||
github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.0.4+incompatible h1:pBJSJeNd9QeIWPjRcV91RVJihd/TXB77q1ef64XEu4A=
|
||||
github.com/docker/cli v28.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8=
|
||||
github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
|
||||
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
|
@ -107,8 +107,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||
|
@ -124,8 +124,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
|
||||
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
|
||||
github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
|
||||
github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
|
||||
github.com/go-openapi/errors v0.22.1 h1:kslMRRnK7NCb/CvR1q1VWuEQCEIsBGn5GgKD9e+HYhU=
|
||||
github.com/go-openapi/errors v0.22.1/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
|
@ -138,8 +138,8 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z
|
|||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
|
||||
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||
github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
|
||||
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
|
@ -154,8 +154,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -175,15 +175,16 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo=
|
||||
github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI=
|
||||
github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI=
|
||||
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
||||
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
@ -192,8 +193,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
|||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
|
||||
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
|
@ -215,8 +216,8 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
|
|||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
|
@ -229,8 +230,8 @@ github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2T
|
|||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
|
||||
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
|
@ -242,8 +243,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mistifyio/go-zfs/v3 v3.0.1 h1:YaoXgBePoMA12+S1u/ddkv+QqxcfiZK4prI6HPnkFiU=
|
||||
|
@ -252,12 +253,18 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
|||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
||||
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -275,40 +282,44 @@ github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
|
|||
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/opencontainers/cgroups v0.0.1 h1:MXjMkkFpKv6kpuirUa4USFBas573sSAY082B4CiHEVA=
|
||||
github.com/opencontainers/cgroups v0.0.1/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/runc v1.1.1-0.20240131200429-02120488a4c0 h1:NwSQ/5rex97Rum/xZOMjlDQbbZ8YJKOTihf9sxqHxtE=
|
||||
github.com/opencontainers/runc v1.1.1-0.20240131200429-02120488a4c0/go.mod h1:tBsQqk9ETVlXxzXjk2Xh/1VjxC/U3Gaq5ps/rC/cadE=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20241108202711-f7e3563b0271 h1:TPj0pMLCTy1CKwmrat3hqTxoZfqOuTy0asG0ccpGk8Q=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20241108202711-f7e3563b0271/go.mod h1:oIH6VwKkaDOO+SIYZpdwrC/0wKYqrfO6E1sG1j3UVws=
|
||||
github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
|
||||
github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/opencontainers/runc v1.2.6 h1:P7Hqg40bsMvQGCS4S7DJYhUZOISMLJOB2iGX5COWiPk=
|
||||
github.com/opencontainers/runc v1.2.6/go.mod h1:dOQeFo29xZKBNeRBI0B19mJtfHv68YgCTh1X+YphA+4=
|
||||
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
||||
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250303011046-260e151b8552 h1:CkXngT0nixZqQUPDVfwVs3GiuhfTqCMk0V+OoHpxIvA=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250303011046-260e151b8552/go.mod h1:T487Kf80NeF2i0OyVXHiylg217e0buz8pQsa0T791RA=
|
||||
github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8=
|
||||
github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U=
|
||||
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M=
|
||||
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM=
|
||||
github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/proglottis/gpgme v0.1.4 h1:3nE7YNA70o2aLjcg63tXMOhPD7bplfE5CBdV+hLAm2M=
|
||||
github.com/proglottis/gpgme v0.1.4/go.mod h1:5LoXMgpE4bttgwwdv9bLs/vwqv3qV7F4glEEZ7mRKrM=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
|
||||
github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 h1:xe+mmCnDN82KhC010l3NfYlA8ZbOuzbXAzSYBa6wbMc=
|
||||
|
@ -317,28 +328,32 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
|||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/sebdah/goldie/v2 v2.5.5 h1:rx1mwF95RxZ3/83sdS4Yp7t2C5TCokvWP4TBRbAyEWY=
|
||||
github.com/sebdah/goldie/v2 v2.5.5/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/sigstore/fulcio v1.6.4 h1:d86obfxUAG3Y6CYwOx1pdwCZwKmROB6w6927pKOVIRY=
|
||||
github.com/sigstore/fulcio v1.6.4/go.mod h1:Y6bn3i3KGhXpaHsAtYP3Z4Np0+VzCo1fLv8Ci6mbPDs=
|
||||
github.com/sigstore/rekor v1.3.8 h1:B8kJI8mpSIXova4Jxa6vXdJyysRxFGsEsLKBDl0rRjA=
|
||||
github.com/sigstore/rekor v1.3.8/go.mod h1:/dHFYKSuxEygfDRnEwyJ+ZD6qoVYNXQdi1mJrKvKWsI=
|
||||
github.com/sigstore/sigstore v1.8.12 h1:S8xMVZbE2z9ZBuQUEG737pxdLjnbOIcFi5v9UFfkJFc=
|
||||
github.com/sigstore/sigstore v1.8.12/go.mod h1:+PYQAa8rfw0QdPpBcT+Gl3egKD9c+TUgAlF12H3Nmjo=
|
||||
github.com/sigstore/fulcio v1.6.6 h1:XaMYX6TNT+8n7Npe8D94nyZ7/ERjEsNGFC+REdi/wzw=
|
||||
github.com/sigstore/fulcio v1.6.6/go.mod h1:BhQ22lwaebDgIxVBEYOOqLRcN5+xOV+C9bh/GUXRhOk=
|
||||
github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby1BxGU7Zc=
|
||||
github.com/sigstore/protobuf-specs v0.4.1/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc=
|
||||
github.com/sigstore/rekor v1.3.10 h1:/mSvRo4MZ/59ECIlARhyykAlQlkmeAQpvBPlmJtZOCU=
|
||||
github.com/sigstore/rekor v1.3.10/go.mod h1:JvryKJ40O0XA48MdzYUPu0y4fyvqt0C4iSY7ri9iu3A=
|
||||
github.com/sigstore/sigstore v1.9.3 h1:y2qlTj+vh+Or3ictKuR3JUFawZPdDxAjrWkeFhon0OQ=
|
||||
github.com/sigstore/sigstore v1.9.3/go.mod h1:VwYkiw0G0dRtwL25KSs04hCyVFF6CYMd/qvNeYrl7EQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/smallstep/pkcs7 v0.1.1 h1:x+rPdt2W088V9Vkjho4KtoggyktZJlMduZAtRHm68LU=
|
||||
github.com/smallstep/pkcs7 v0.1.1/go.mod h1:dL6j5AIz9GHjVEBTXtW+QliALcgM19RtXaTeyxI+AfA=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
|
@ -357,8 +372,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/sylabs/sif/v2 v2.20.2 h1:HGEPzauCHhIosw5o6xmT3jczuKEuaFzSfdjAsH33vYw=
|
||||
github.com/sylabs/sif/v2 v2.20.2/go.mod h1:WyYryGRaR4Wp21SAymm5pK0p45qzZCSRiZMFvUZiuhc=
|
||||
github.com/sylabs/sif/v2 v2.21.1 h1:GZ0b5//AFAqJEChd8wHV/uSKx/l1iuGYwjR8nx+4wPI=
|
||||
github.com/sylabs/sif/v2 v2.21.1/go.mod h1:YoqEGQnb5x/ItV653bawXHZJOXQaEWpGwHsSD3YePJI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tchap/go-patricia/v2 v2.3.2 h1:xTHFutuitO2zqKAQ5rCROYgUb7Or/+IC3fts9/Yc7nM=
|
||||
|
@ -367,10 +382,10 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C
|
|||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vbatts/tar-split v0.11.7 h1:ixZ93pO/GmvaZw4Vq9OwmfZK/kc2zKdPfu0B+gYqs3U=
|
||||
github.com/vbatts/tar-split v0.11.7/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/vbauerster/mpb/v8 v8.9.1 h1:LH5R3lXPfE2e3lIGxN7WNWv3Hl5nWO6LRi2B0L0ERHw=
|
||||
github.com/vbauerster/mpb/v8 v8.9.1/go.mod h1:4XMvznPh8nfe2NpnDo1QTPvW9MVkUhbG90mPWvmOzcQ=
|
||||
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
|
||||
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/vbauerster/mpb/v8 v8.9.3 h1:PnMeF+sMvYv9u23l6DO6Q3+Mdj408mjLRXIzmUmU2Z8=
|
||||
github.com/vbauerster/mpb/v8 v8.9.3/go.mod h1:hxS8Hz4C6ijnppDSIX6LjG8FYJSoPo9iIOcE53Zik0c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
|
@ -384,38 +399,40 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd
|
|||
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
|
||||
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4=
|
||||
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
|
||||
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
|
||||
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
|
||||
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
|
||||
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
|
||||
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
|
@ -442,8 +459,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -456,8 +473,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -477,13 +494,12 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -492,13 +508,12 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
|
|||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
@ -509,10 +524,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
@ -525,8 +540,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -536,18 +551,17 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
|
||||
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -557,8 +571,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
@ -567,13 +581,11 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc=
|
||||
tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
|
||||
tags.cncf.io/container-device-interface v1.0.1 h1:KqQDr4vIlxwfYh0Ed/uJGVgX+CHAkahrgabg6Q8GYxc=
|
||||
tags.cncf.io/container-device-interface v1.0.1/go.mod h1:JojJIOeW3hNbcnOH2q0NrWNha/JuHoDZcmYxAZwb2i0=
|
||||
|
|
|
@ -76,6 +76,9 @@ type CreateOptions struct {
|
|||
HealthStartupRetries string
|
||||
HealthStartupSuccess string
|
||||
HealthStartupTimeout string
|
||||
HealthLogDestination string
|
||||
HealthMaxLogSize string
|
||||
HealthMaxLogCount string
|
||||
Memory string
|
||||
MemoryReservation string
|
||||
MemorySwap string
|
||||
|
@ -90,6 +93,15 @@ type CreateOptions struct {
|
|||
CPUSetMems string
|
||||
SHMSize string
|
||||
SHMSizeSystemd string
|
||||
NamespaceCgroup string
|
||||
NamespacePid string
|
||||
NamespaceIpc string
|
||||
NamespaceUser string
|
||||
NamespaceUts string
|
||||
NamespaceUidmap string
|
||||
NamespaceSubuidName string
|
||||
NamespaceGidmap string
|
||||
NamespaceSubgidName string
|
||||
}
|
||||
|
||||
// Create creates a new container.
|
||||
|
@ -338,6 +350,43 @@ func Create(opts CreateOptions, run bool) ([]string, string, error) { //nolint:c
|
|||
createOptions.ShmSizeSystemd = opts.SHMSizeSystemd
|
||||
}
|
||||
|
||||
// namespace options
|
||||
if opts.NamespaceCgroup != "" {
|
||||
createOptions.CgroupNS = opts.NamespaceCgroup
|
||||
}
|
||||
|
||||
if opts.NamespaceIpc != "" {
|
||||
createOptions.IPC = opts.NamespaceIpc
|
||||
}
|
||||
|
||||
if opts.NamespacePid != "" {
|
||||
createOptions.PID = opts.NamespacePid
|
||||
}
|
||||
|
||||
if opts.NamespaceUser != "" {
|
||||
createOptions.UserNS = opts.NamespaceUser
|
||||
}
|
||||
|
||||
if opts.NamespaceUts != "" {
|
||||
createOptions.UTS = opts.NamespaceUts
|
||||
}
|
||||
|
||||
if opts.NamespaceUidmap != "" {
|
||||
createOptions.UIDMap = []string{opts.NamespaceUidmap}
|
||||
}
|
||||
|
||||
if opts.NamespaceSubuidName != "" {
|
||||
createOptions.SubUIDName = opts.NamespaceSubuidName
|
||||
}
|
||||
|
||||
if opts.NamespaceGidmap != "" {
|
||||
createOptions.GIDMap = []string{opts.NamespaceGidmap}
|
||||
}
|
||||
|
||||
if opts.NamespaceSubgidName != "" {
|
||||
createOptions.SubGIDName = opts.NamespaceSubgidName
|
||||
}
|
||||
|
||||
// generate spec
|
||||
s := specgen.NewSpecGenerator(opts.Name, false)
|
||||
if err := specgenutil.FillOutSpecGen(s, &createOptions, nil); err != nil {
|
||||
|
@ -377,6 +426,7 @@ func containerHealthOptions(createOptions *entities.ContainerCreateOptions, opts
|
|||
createOptions.HealthTimeout = define.DefaultHealthCheckTimeout
|
||||
createOptions.StartupHCTimeout = define.DefaultHealthCheckTimeout
|
||||
createOptions.HealthOnFailure = opts.HealthOnFailure
|
||||
createOptions.HealthLogDestination = opts.HealthLogDestination
|
||||
|
||||
if opts.HealthCmd == "" {
|
||||
createOptions.HealthCmd = "none"
|
||||
|
@ -386,6 +436,26 @@ func containerHealthOptions(createOptions *entities.ContainerCreateOptions, opts
|
|||
|
||||
createOptions.HealthCmd = opts.HealthCmd
|
||||
|
||||
if opts.HealthMaxLogCount != "" {
|
||||
logCount, err := strconv.ParseUint(opts.HealthMaxLogCount, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logCountWd := uint(logCount)
|
||||
createOptions.HealthMaxLogCount = logCountWd
|
||||
}
|
||||
|
||||
if opts.HealthMaxLogSize != "" {
|
||||
logSize, err := strconv.ParseUint(opts.HealthMaxLogSize, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSizeWd := uint(logSize)
|
||||
createOptions.HealthMaxLogSize = logSizeWd
|
||||
}
|
||||
|
||||
if opts.HealthInterval != "" {
|
||||
createOptions.HealthInterval = opts.HealthInterval
|
||||
}
|
||||
|
|
|
@ -20,34 +20,42 @@ import (
|
|||
|
||||
// CreateOptions implements pods create spec options.
|
||||
type CreateOptions struct {
|
||||
Name string
|
||||
NoHost bool
|
||||
Labels map[string]string
|
||||
DNSServer []string
|
||||
DNSOptions []string
|
||||
DNSSearchDomain []string
|
||||
Infra bool
|
||||
InfraCommand string
|
||||
InfraImage string
|
||||
Hostname string
|
||||
IPAddress string
|
||||
MacAddress string
|
||||
AddHost []string
|
||||
Network string
|
||||
Publish []string
|
||||
SecurityOpts []string
|
||||
Memory string
|
||||
MemorySwap string
|
||||
CPUs string
|
||||
CPUShares string
|
||||
CPUSetCPUs string
|
||||
CPUSetMems string
|
||||
ShmSize string
|
||||
ShmSizeSystemd string
|
||||
Name string
|
||||
NoHost bool
|
||||
Labels map[string]string
|
||||
DNSServer []string
|
||||
DNSOptions []string
|
||||
DNSSearchDomain []string
|
||||
Infra bool
|
||||
InfraCommand string
|
||||
InfraImage string
|
||||
Hostname string
|
||||
IPAddress string
|
||||
MacAddress string
|
||||
AddHost []string
|
||||
Network string
|
||||
Publish []string
|
||||
SecurityOpts []string
|
||||
Memory string
|
||||
MemorySwap string
|
||||
CPUs string
|
||||
CPUShares string
|
||||
CPUSetCPUs string
|
||||
CPUSetMems string
|
||||
ShmSize string
|
||||
ShmSizeSystemd string
|
||||
NamespaceShare []string
|
||||
NamespacePid string
|
||||
NamespaceUser string
|
||||
NamespaceUts string
|
||||
NamespaceUidmap string
|
||||
NamespaceSubuidName string
|
||||
NamespaceGidmap string
|
||||
NamespaceSubgidName string
|
||||
}
|
||||
|
||||
// Create creates a new pod.
|
||||
func Create(opts CreateOptions) error { //nolint:cyclop,gocognit
|
||||
func Create(opts CreateOptions) error { //nolint:cyclop,gocognit,gocyclo
|
||||
log.Debug().Msgf("pdcs: podman pod create %v", opts)
|
||||
|
||||
var createOptions entities.PodCreateOptions
|
||||
|
@ -66,6 +74,7 @@ func Create(opts CreateOptions) error { //nolint:cyclop,gocognit
|
|||
|
||||
createOptions.Name = opts.Name
|
||||
createOptions.Labels = opts.Labels
|
||||
createOptions.Infra = opts.Infra
|
||||
|
||||
// resources
|
||||
if opts.Memory != "" {
|
||||
|
@ -110,14 +119,50 @@ func Create(opts CreateOptions) error { //nolint:cyclop,gocognit
|
|||
infraOptions.ShmSizeSystemd = opts.ShmSizeSystemd
|
||||
}
|
||||
|
||||
// namespace
|
||||
if len(opts.NamespaceShare) > 0 {
|
||||
createOptions.Share = opts.NamespaceShare
|
||||
}
|
||||
|
||||
if opts.NamespacePid != "" {
|
||||
createOptions.Pid = opts.NamespacePid
|
||||
}
|
||||
|
||||
if opts.NamespaceUser != "" {
|
||||
userns, err := specgen.ParseUserNamespace(opts.NamespaceUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createOptions.Userns = userns
|
||||
}
|
||||
|
||||
if opts.NamespaceUts != "" {
|
||||
createOptions.Uts = opts.NamespaceUts
|
||||
}
|
||||
|
||||
if opts.NamespaceUidmap != "" {
|
||||
infraOptions.UIDMap = []string{opts.NamespaceUidmap}
|
||||
}
|
||||
|
||||
if opts.NamespaceSubuidName != "" {
|
||||
infraOptions.SubUIDName = opts.NamespaceSubuidName
|
||||
}
|
||||
|
||||
if opts.NamespaceGidmap != "" {
|
||||
infraOptions.GIDMap = []string{opts.NamespaceGidmap}
|
||||
}
|
||||
|
||||
if opts.NamespaceSubgidName != "" {
|
||||
infraOptions.SubGIDName = opts.NamespaceSubgidName
|
||||
}
|
||||
|
||||
// network options
|
||||
podNetworkOptions, err := podNetworkOptions(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createOptions.Infra = opts.Infra
|
||||
|
||||
if createOptions.Infra { //nolint:nestif
|
||||
if opts.InfraImage != "" {
|
||||
createOptions.InfraImage = opts.InfraImage
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
%global git0 https://%{import_path}
|
||||
|
||||
Name: podman-tui
|
||||
Version: 1.5.0
|
||||
Release: 1%{?dist}
|
||||
Version: 1.7.0
|
||||
Release: dev.1%{?dist}
|
||||
Summary: Podman Terminal User Interface
|
||||
License: ASL 2.0
|
||||
URL: %{git0}
|
||||
|
@ -60,6 +60,22 @@ install -p ./bin/%{name} %{buildroot}%{_bindir}
|
|||
%{_bindir}/%{name}
|
||||
|
||||
%changelog
|
||||
* Wed May 28 2025 Navid Yaghoobi <navidys@fedoraproject.org> 1.7.0-dev-1
|
||||
|
||||
* Wed May 28 2025 Navid Yaghoobi <navidys@fedoraproject.org> 1.6.0-1
|
||||
- Added container create health log dest, max count and size options
|
||||
- Set default values for container create/run health log options
|
||||
- Fix bats test for network connect
|
||||
- Running golang-lint
|
||||
- Bump github.com/containers/podman/v5 from 5.4.2 to 5.5.0
|
||||
- Bump github.com/containers/buildah from 1.39.4 to 1.40.0
|
||||
- Bump github.com/containers/common from 0.62.3 to 0.63.0
|
||||
- Bump github.com/containers/storage from 1.57.2 to 1.58.0
|
||||
- Bump github.com/onsi/ginkgo/v2 from 2.22.2 to 2.23.4
|
||||
- Bump github.com/onsi/gomega from 1.36.2 to 1.37.0
|
||||
- Bump golang.org/x/net from 0.36.0 to 0.38.0
|
||||
- Bump golang.org/x/crypto from 0.36.0 to 0.38.0
|
||||
|
||||
* Sun Apr 06 2025 Navid Yaghoobi <navidys@fedoraproject.org> 1.5.0-1
|
||||
- Go update to v1.23.0 + Golangci-lint update to v1.64.4
|
||||
- UI input check trim spaces
|
||||
|
|
|
@ -19,7 +19,7 @@ load helpers_tui
|
|||
podman_tui_set_view "networks"
|
||||
podman_tui_select_network_cmd "connect"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
podman_tui_send_inputs "Tab" "Tab"
|
||||
podman_tui_send_inputs "Tab"
|
||||
podman_tui_send_inputs $TEST_NETWORK_CONNECT_ALIAS
|
||||
podman_tui_send_inputs "Tab" "Tab" "Tab" "Tab"
|
||||
podman_tui_send_inputs "Tab" "Enter"
|
||||
|
@ -40,7 +40,7 @@ load helpers_tui
|
|||
podman_tui_set_view "networks"
|
||||
podman_tui_select_network_cmd "disconnect"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
podman_tui_send_inputs "Tab" "Tab" "Tab" "Enter"
|
||||
podman_tui_send_inputs "Tab" "Tab" "Enter"
|
||||
|
||||
run_helper podman container inspect $TEST_CONTAINER_NAME --format "{{ .NetworkSettings.Networks.$TEST_NETWORK_CONNECT }}"
|
||||
assert "$output" == "<no value>" "expected $TEST_NETWORK_CONNECT_ALIAS to be removed from container"
|
||||
|
|
|
@ -227,15 +227,11 @@ load helpers_tui
|
|||
|
||||
# switch to "health check" create view
|
||||
podman_tui_send_inputs "Down" "Down" "Down" "Down" "Tab"
|
||||
podman_tui_send_inputs $TEST_CONTAINER_HEALTH_CMD "Tab" "Tab"
|
||||
podman_tui_send_inputs $TEST_CONTAINER_HEALTH_CMD "Tab" "Tab" "Tab" "Tab" "Tab"
|
||||
podman_tui_send_inputs "Enter" "Down" "Down" "Enter"
|
||||
podman_tui_send_inputs "Tab" "Tab" "Tab"
|
||||
podman_tui_send_inputs $TEST_CONTAINER_HEALTH_INTERVAL
|
||||
podman_tui_send_inputs "Tab" "Tab"
|
||||
podman_tui_send_inputs $TEST_CONTAINER_HEALTH_RETRIES
|
||||
podman_tui_send_inputs "Tab" "Tab"
|
||||
podman_tui_send_inputs $TEST_CONTAINER_HEALTH_TIMEOUT
|
||||
podman_tui_send_inputs "Tab" "Tab" "Tab"
|
||||
podman_tui_send_inputs "Tab" "Tab" "Tab" "Tab"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
podman_tui_send_inputs "Tab"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
|
|
|
@ -20,9 +20,8 @@ load helpers_tui
|
|||
podman_tui_send_inputs "Tab" "Tab" "Tab" "Enter"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
|
||||
run_helper tail -2 $PODMAN_TUI_CONFIG_FILE
|
||||
assert "$output" =~ "[services.${TEST_SYSTEM_CONN_NAME}]" "expected [services.${TEST_SYSTEM_CONN_NAME}] in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
assert "$output" =~ "uri = \"unix://run/podman/podman.sock\"" "expected ${TEST_SYSTEM_CONN_URI} in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
run_helper jq ".connections.${TEST_SYSTEM_CONN_NAME}.uri" ${PODMAN_TUI_CONFIG_FILE}
|
||||
assert "$output" == "\"$TEST_SYSTEM_CONN_URI\"" "expected ${TEST_SYSTEM_CONN_URI} in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
}
|
||||
|
||||
@test "system set default" {
|
||||
|
@ -34,10 +33,11 @@ load helpers_tui
|
|||
podman_tui_select_system_cmd "default"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
|
||||
run_helper tail -3 $PODMAN_TUI_CONFIG_FILE
|
||||
assert "$output" =~ "[services.${TEST_SYSTEM_CONN_NAME}]" "expected [services.${TEST_SYSTEM_CONN_NAME}] in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
assert "$output" =~ "uri = \"unix://run/podman/podman.sock\"" "expected ${TEST_SYSTEM_CONN_URI} in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
assert "$output" =~ "default = true" "expected 'default = true' in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
run_helper jq ".connections.${TEST_SYSTEN_CONN_LOCAL}.uri" ${PODMAN_TUI_CONFIG_FILE}
|
||||
assert "$output" == "\"$TEST_SYSTEM_CONN_URI\"" "expected ${TEST_SYSTEM_CONN_URI} in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
|
||||
run_helper jq ".connections.${TEST_SYSTEN_CONN_LOCAL}.default" ${PODMAN_TUI_CONFIG_FILE}
|
||||
assert "$output" == "true" "expected 'default = true' in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
}
|
||||
|
||||
@test "system remove" {
|
||||
|
@ -51,8 +51,8 @@ load helpers_tui
|
|||
podman_tui_send_inputs "Enter"
|
||||
sleep $TEST_TIMEOUT_LOW
|
||||
|
||||
run_helper tail -3 $PODMAN_TUI_CONFIG_FILE
|
||||
assert "$output" !~ "services.${TEST_SYSTEM_CONN_NAME}" "expected [services.${TEST_SYSTEM_CONN_NAME}] not in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
run_helper jq ".connections.${TEST_SYSTEN_CONN_LOCAL}" ${PODMAN_TUI_CONFIG_FILE}
|
||||
assert "$output" == "null" "expected ${TEST_SYSTEN_CONN_LOCAL} connection to be removed from in ${PODMAN_TUI_CONFIG_FILE}"
|
||||
}
|
||||
|
||||
@test "system disconnect" {
|
||||
|
|
|
@ -5,7 +5,7 @@ PODMAN_TUI=${PODMAN_TUI:-./bin/podman-tui}
|
|||
PODMAN_TUI_DEBUG="$PODMAN_TUI -d"
|
||||
PODMAN_TUI_LOG="podman-tui.log"
|
||||
PODMAN_TUI_CONFIG_DIR="/root/.config/podman-tui"
|
||||
PODMAN_TUI_CONFIG_FILE="${PODMAN_TUI_CONFIG_DIR}/podman-tui.conf"
|
||||
PODMAN_TUI_CONFIG_FILE="${PODMAN_TUI_CONFIG_DIR}/podman-tui.json"
|
||||
TMUX_SESSION="podman_tui_test"
|
||||
|
||||
|
||||
|
@ -13,12 +13,7 @@ function setup() {
|
|||
# setup config file
|
||||
[ ! -d "${PODMAN_TUI_CONFIG_DIR}" ] && mkdir -p ${PODMAN_TUI_CONFIG_DIR}
|
||||
cat > ${PODMAN_TUI_CONFIG_FILE} << EOF
|
||||
[services]
|
||||
[services.localhost]
|
||||
uri = "unix://run/podman/podman.sock"
|
||||
default = true
|
||||
[services.localhost_test]
|
||||
uri = "unix://run/podman/podman.sock"
|
||||
{"connections":{"localhost":{"uri":"unix://run/podman/podman.sock","default":true},"localhost_test":{"uri":"unix://run/podman/podman.sock"}}}
|
||||
EOF
|
||||
|
||||
# start podman socket
|
||||
|
|
|
@ -11,9 +11,9 @@ TEST_POD_NETWORK_NAME="${TEST_NAME}_pod01_net"
|
|||
TEST_CONTAINER_NAME="${TEST_NAME}_cnt01"
|
||||
TEST_CONTAINER_CHECKPOINT_NAME="${TEST_NAME}_checkpoint"
|
||||
TEST_CONTAINER_HEALTH_CMD="date"
|
||||
TEST_CONTAINER_HEALTH_INTERVAL="60s"
|
||||
TEST_CONTAINER_HEALTH_TIMEOUT="60s"
|
||||
TEST_CONTAINER_HEALTH_RETRIES="6"
|
||||
TEST_CONTAINER_HEALTH_INTERVAL="30s"
|
||||
TEST_CONTAINER_HEALTH_TIMEOUT="30s"
|
||||
TEST_CONTAINER_HEALTH_RETRIES="3"
|
||||
TEST_CONTAINER_HEALTH_ONFAILURE="restart"
|
||||
TEST_CONTAINER_POD_NAME="${TEST_NAME}_cnt01_pod"
|
||||
TEST_CONTAINER_NETWORK_NAME="${TEST_NAME}_cnt01_net"
|
||||
|
@ -32,6 +32,7 @@ TEST_CONTAINER_RUN_CMD="/bin/sh"
|
|||
TEST_LABEL_NAME="test"
|
||||
TEST_LABEL_VALUE="$TEST_NAME"
|
||||
TEST_LABEL="${TEST_LABEL_NAME}=${TEST_LABEL_VALUE}"
|
||||
TEST_SYSTEN_CONN_LOCAL="localhost_test"
|
||||
TEST_SYSTEM_CONN_NAME="localhost_test_tui"
|
||||
TEST_SYSTEM_CONN_URI="unix://run/podman/podman.sock"
|
||||
TEST_IMAGE_BUILD_CONTEXT_DIR="$(realpath .)/test/testdata/"
|
||||
|
|
|
@ -87,6 +87,9 @@ const (
|
|||
createContainerHealthStartupRetriesFieldFocus
|
||||
createContainerHealthStartPeriodFieldFocus
|
||||
createContainerHealthStartupSuccessFieldFocus
|
||||
createContainerHealthLogDestFocus
|
||||
createContainerHealthMaxLogCountFocus
|
||||
createContainerHealthMaxLogSizeFocus
|
||||
createContainerMemoryFieldFocus
|
||||
createContainerMemoryReservatoinFieldFocus
|
||||
createContainerMemorySwapFieldFocus
|
||||
|
@ -101,6 +104,15 @@ const (
|
|||
createContainerCPUSetMemsFieldFocus
|
||||
createContainerShmSizeFieldFocus
|
||||
createContainerShmSizeSystemdFieldFocus
|
||||
createContainerNamespaceCgroupFieldFocus
|
||||
createContainerNamespaceIpcFieldFocus
|
||||
createContainerNamespacePidFieldFocus
|
||||
createContainerNamespaceUserFieldFocus
|
||||
createContainerNamespaceUtsFieldFocus
|
||||
createContainerNamespaceUidmapFieldFocus
|
||||
createContainerNamespaceGidmapFieldFocus
|
||||
createContainerNamespaceSubuidNameFieldFocus
|
||||
createContainerNamespaceSubgidNameFieldFocus
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -114,6 +126,7 @@ const (
|
|||
createContainerSecurityOptsPageIndex
|
||||
createContainerVolumePageIndex
|
||||
createContainerResourcePageIndex
|
||||
createContainerNamespacePageIndex
|
||||
)
|
||||
|
||||
type ContainerCreateDialogMode int
|
||||
|
@ -136,6 +149,7 @@ type ContainerCreateDialog struct {
|
|||
volumePage *tview.Flex
|
||||
healthPage *tview.Flex
|
||||
resourcePage *tview.Flex
|
||||
namespacePage *tview.Flex
|
||||
form *tview.Form
|
||||
display bool
|
||||
activePageIndex int
|
||||
|
@ -193,6 +207,9 @@ type ContainerCreateDialog struct {
|
|||
containerHealthStartupRetriesField *tview.InputField
|
||||
containerHealthStartupSuccessField *tview.InputField
|
||||
containerHealthStartupTimeoutField *tview.InputField
|
||||
containerHealthLogDestField *tview.InputField
|
||||
containerHealthMaxLogCountField *tview.InputField
|
||||
containerHealthMaxLogSizeField *tview.InputField
|
||||
containerVolumeField *tview.InputField
|
||||
containerImageVolumeField *tview.DropDown
|
||||
containerMountField *tview.InputField
|
||||
|
@ -210,6 +227,15 @@ type ContainerCreateDialog struct {
|
|||
containerCPUSetMemsField *tview.InputField
|
||||
containerShmSizeField *tview.InputField
|
||||
containerShmSizeSystemdField *tview.InputField
|
||||
containerNamespaceCgroupField *tview.InputField
|
||||
containerNamespaceIpcField *tview.InputField
|
||||
containerNamespacePidField *tview.InputField
|
||||
containerNamespaceUserField *tview.InputField
|
||||
containerNamespaceUtsField *tview.InputField
|
||||
containerNamespaceUidmapField *tview.InputField
|
||||
containerNamespaceGidmapField *tview.InputField
|
||||
containerNamespaceSubuidNameField *tview.InputField
|
||||
containerNamespaceSubgidNameField *tview.InputField
|
||||
cancelHandler func()
|
||||
enterHandler func()
|
||||
}
|
||||
|
@ -232,6 +258,7 @@ func NewContainerCreateDialog(mode ContainerCreateDialogMode) *ContainerCreateDi
|
|||
volumePage: tview.NewFlex(),
|
||||
healthPage: tview.NewFlex(),
|
||||
resourcePage: tview.NewFlex(),
|
||||
namespacePage: tview.NewFlex(),
|
||||
form: tview.NewForm(),
|
||||
categoryLabels: []string{
|
||||
"Container",
|
||||
|
@ -244,6 +271,7 @@ func NewContainerCreateDialog(mode ContainerCreateDialogMode) *ContainerCreateDi
|
|||
"Security Options",
|
||||
"Volumes Settings",
|
||||
"Resource Settings",
|
||||
"Namespace Options",
|
||||
},
|
||||
activePageIndex: 0,
|
||||
display: false,
|
||||
|
@ -301,6 +329,9 @@ func NewContainerCreateDialog(mode ContainerCreateDialogMode) *ContainerCreateDi
|
|||
containerHealthStartupRetriesField: tview.NewInputField(),
|
||||
containerHealthStartupSuccessField: tview.NewInputField(),
|
||||
containerHealthStartupTimeoutField: tview.NewInputField(),
|
||||
containerHealthLogDestField: tview.NewInputField(),
|
||||
containerHealthMaxLogCountField: tview.NewInputField(),
|
||||
containerHealthMaxLogSizeField: tview.NewInputField(),
|
||||
containerMemoryField: tview.NewInputField(),
|
||||
containerMemoryReservationField: tview.NewInputField(),
|
||||
containerMemorySwapField: tview.NewInputField(),
|
||||
|
@ -315,6 +346,15 @@ func NewContainerCreateDialog(mode ContainerCreateDialogMode) *ContainerCreateDi
|
|||
containerCPUSetMemsField: tview.NewInputField(),
|
||||
containerShmSizeField: tview.NewInputField(),
|
||||
containerShmSizeSystemdField: tview.NewInputField(),
|
||||
containerNamespaceCgroupField: tview.NewInputField(),
|
||||
containerNamespacePidField: tview.NewInputField(),
|
||||
containerNamespaceIpcField: tview.NewInputField(),
|
||||
containerNamespaceUserField: tview.NewInputField(),
|
||||
containerNamespaceUtsField: tview.NewInputField(),
|
||||
containerNamespaceUidmapField: tview.NewInputField(),
|
||||
containerNamespaceGidmapField: tview.NewInputField(),
|
||||
containerNamespaceSubuidNameField: tview.NewInputField(),
|
||||
containerNamespaceSubgidNameField: tview.NewInputField(),
|
||||
}
|
||||
|
||||
containerDialog.setupLayout()
|
||||
|
@ -349,6 +389,7 @@ func (d *ContainerCreateDialog) setupLayout() {
|
|||
d.setupPortsPageUI()
|
||||
d.setupSecurityPageUI()
|
||||
d.setupVolumePageUI()
|
||||
d.setupNamespacePageUI()
|
||||
|
||||
// form
|
||||
d.form.SetBackgroundColor(bgColor)
|
||||
|
@ -374,6 +415,7 @@ func (d *ContainerCreateDialog) setupLayout() {
|
|||
d.categoryPages.AddPage(d.categoryLabels[createContainerSecurityOptsPageIndex], d.securityOptsPage, true, true)
|
||||
d.categoryPages.AddPage(d.categoryLabels[createContainerVolumePageIndex], d.volumePage, true, true)
|
||||
d.categoryPages.AddPage(d.categoryLabels[createContainerResourcePageIndex], d.resourcePage, true, true)
|
||||
d.categoryPages.AddPage(d.categoryLabels[createContainerNamespacePageIndex], d.namespacePage, true, true)
|
||||
|
||||
// add it to layout.
|
||||
d.layout.SetBackgroundColor(bgColor)
|
||||
|
@ -728,47 +770,46 @@ func (d *ContainerCreateDialog) setupHealthPageUI() {
|
|||
d.containerHealthStartupCmdField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupCmdField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
d.containerHealthLogDestField.SetLabel("Log dest:")
|
||||
d.containerHealthLogDestField.SetLabelWidth(healthPageLabelWidth)
|
||||
d.containerHealthLogDestField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthLogDestField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthLogDestField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// multi primitive row01
|
||||
// startup success
|
||||
d.containerHealthStartupSuccessField.SetLabel("Startup success:")
|
||||
d.containerHealthStartupSuccessField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupSuccessField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupSuccessField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupSuccessField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupSuccessField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
// max log size
|
||||
d.containerHealthMaxLogSizeField.SetLabel("Max log size:")
|
||||
d.containerHealthMaxLogSizeField.SetLabelWidth(healthPageLabelWidth)
|
||||
d.containerHealthMaxLogSizeField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthMaxLogSizeField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthMaxLogSizeField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthMaxLogSizeField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// max log count
|
||||
d.containerHealthMaxLogCountField.SetLabel("Max log count:")
|
||||
d.containerHealthMaxLogCountField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthMaxLogCountField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthMaxLogCountField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthMaxLogCountField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthMaxLogCountField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// on-failure
|
||||
onfailureLabel := fmt.Sprintf("%17s: ", "On failure")
|
||||
|
||||
d.containerHealthOnFailureField.SetOptions([]string{"none", "kill", "restart", "stop"}, nil)
|
||||
d.containerHealthOnFailureField.SetLabel("On failure:")
|
||||
d.containerHealthOnFailureField.SetLabelWidth(healthPageLabelWidth)
|
||||
d.containerHealthOnFailureField.SetLabel(onfailureLabel)
|
||||
d.containerHealthOnFailureField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthOnFailureField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthOnFailureField.SetListStyles(ddUnselectedStyle, ddselectedStyle)
|
||||
d.containerHealthOnFailureField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// start period
|
||||
startPeroidLabel := fmt.Sprintf("%15s: ", "Start period")
|
||||
d.containerHealthStartPeriodField.SetLabel(startPeroidLabel)
|
||||
d.containerHealthStartPeriodField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartPeriodField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartPeriodField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartPeriodField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
multiItemRow01 := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
multiItemRow01.AddItem(d.containerHealthMaxLogSizeField, 0, 1, true)
|
||||
multiItemRow01.AddItem(d.containerHealthMaxLogCountField, 0, 1, true)
|
||||
multiItemRow01.AddItem(d.containerHealthOnFailureField, 0, 1, true)
|
||||
multiItemRow01.AddItem(d.containerHealthStartupSuccessField, 0, 1, true)
|
||||
multiItemRow01.AddItem(d.containerHealthStartPeriodField, 0, 1, true)
|
||||
multiItemRow01.SetBackgroundColor(bgColor)
|
||||
|
||||
// multi primitive row02
|
||||
// startup interval
|
||||
d.containerHealthStartupIntervalField.SetLabel("Startup interval:")
|
||||
d.containerHealthStartupIntervalField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupIntervalField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupIntervalField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupIntervalField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupIntervalField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// interval
|
||||
d.containerHealthIntervalField.SetLabel("Interval:")
|
||||
d.containerHealthIntervalField.SetLabelWidth(healthPageLabelWidth)
|
||||
|
@ -777,21 +818,29 @@ func (d *ContainerCreateDialog) setupHealthPageUI() {
|
|||
d.containerHealthIntervalField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthIntervalField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// startup interval
|
||||
d.containerHealthStartupIntervalField.SetLabel("Startup interval:")
|
||||
d.containerHealthStartupIntervalField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupIntervalField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupIntervalField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupIntervalField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupIntervalField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// start period
|
||||
startPeroidLabel := fmt.Sprintf("%17s: ", "Start period")
|
||||
d.containerHealthStartPeriodField.SetLabel(startPeroidLabel)
|
||||
d.containerHealthStartPeriodField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartPeriodField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartPeriodField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartPeriodField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
multiItemRow02 := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
multiItemRow02.AddItem(d.containerHealthIntervalField, 0, 1, true)
|
||||
multiItemRow02.AddItem(d.containerHealthStartupIntervalField, 0, 1, true)
|
||||
multiItemRow02.AddItem(utils.EmptyBoxSpace(bgColor), 0, 1, true)
|
||||
multiItemRow02.AddItem(d.containerHealthStartPeriodField, 0, 1, true)
|
||||
multiItemRow02.SetBackgroundColor(bgColor)
|
||||
|
||||
// multi primitive row03
|
||||
// startup retries
|
||||
d.containerHealthStartupRetriesField.SetLabel("Startup retries:")
|
||||
d.containerHealthStartupRetriesField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupRetriesField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupRetriesField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupRetriesField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupRetriesField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// retires
|
||||
d.containerHealthRetriesField.SetLabel("Retries:")
|
||||
d.containerHealthRetriesField.SetLabelWidth(healthPageLabelWidth)
|
||||
|
@ -800,21 +849,29 @@ func (d *ContainerCreateDialog) setupHealthPageUI() {
|
|||
d.containerHealthRetriesField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthRetriesField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// startup retries
|
||||
d.containerHealthStartupRetriesField.SetLabel("Startup retries:")
|
||||
d.containerHealthStartupRetriesField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupRetriesField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupRetriesField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupRetriesField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupRetriesField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// startup success
|
||||
startupSuccessLabel := fmt.Sprintf("%17s: ", "Startup success")
|
||||
d.containerHealthStartupSuccessField.SetLabel(startupSuccessLabel)
|
||||
d.containerHealthStartupSuccessField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupSuccessField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupSuccessField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupSuccessField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
multiItemRow03 := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
multiItemRow03.AddItem(d.containerHealthRetriesField, 0, 1, true)
|
||||
multiItemRow03.AddItem(d.containerHealthStartupRetriesField, 0, 1, true)
|
||||
multiItemRow03.AddItem(utils.EmptyBoxSpace(bgColor), 0, 1, true)
|
||||
multiItemRow03.AddItem(d.containerHealthStartupSuccessField, 0, 1, true)
|
||||
multiItemRow03.SetBackgroundColor(bgColor)
|
||||
|
||||
// multi primitive row04
|
||||
// startup timeout
|
||||
d.containerHealthStartupTimeoutField.SetLabel("Startup timeout:")
|
||||
d.containerHealthStartupTimeoutField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupTimeoutField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupTimeoutField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupTimeoutField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupTimeoutField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
// timeout
|
||||
d.containerHealthTimeoutField.SetLabel("Timeout:")
|
||||
d.containerHealthTimeoutField.SetLabelWidth(healthPageLabelWidth)
|
||||
|
@ -822,6 +879,13 @@ func (d *ContainerCreateDialog) setupHealthPageUI() {
|
|||
d.containerHealthTimeoutField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthTimeoutField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthTimeoutField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
// startup timeout
|
||||
d.containerHealthStartupTimeoutField.SetLabel("Startup timeout:")
|
||||
d.containerHealthStartupTimeoutField.SetLabelWidth(healthPageSecColLabelWidth)
|
||||
d.containerHealthStartupTimeoutField.SetBackgroundColor(bgColor)
|
||||
d.containerHealthStartupTimeoutField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerHealthStartupTimeoutField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
d.containerHealthStartupTimeoutField.SetFieldWidth(healthPageMultiRowFieldWidth)
|
||||
|
||||
multiItemRow04 := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
multiItemRow04.AddItem(d.containerHealthTimeoutField, 0, 1, true)
|
||||
|
@ -835,6 +899,8 @@ func (d *ContainerCreateDialog) setupHealthPageUI() {
|
|||
d.healthPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.healthPage.AddItem(d.containerHealthStartupCmdField, 1, 0, true)
|
||||
d.healthPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.healthPage.AddItem(d.containerHealthLogDestField, 1, 0, true)
|
||||
d.healthPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.healthPage.AddItem(multiItemRow01, 1, 0, true)
|
||||
d.healthPage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.healthPage.AddItem(multiItemRow02, 1, 0, true)
|
||||
|
@ -1215,6 +1281,105 @@ func (d *ContainerCreateDialog) setupResourcePageUI() {
|
|||
d.resourcePage.SetBackgroundColor(bgColor)
|
||||
}
|
||||
|
||||
func (d *ContainerCreateDialog) setupNamespacePageUI() {
|
||||
bgColor := style.DialogBgColor
|
||||
inputFieldBgColor := style.InputFieldBgColor
|
||||
namespacePageLabelWidth := 10
|
||||
|
||||
// cgroupns
|
||||
d.containerNamespaceCgroupField.SetLabel("cgroupns:")
|
||||
d.containerNamespaceCgroupField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespaceCgroupField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceCgroupField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceCgroupField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// ipc
|
||||
d.containerNamespaceIpcField.SetLabel("ipc:")
|
||||
d.containerNamespaceIpcField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespaceIpcField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceIpcField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceIpcField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// pid
|
||||
d.containerNamespacePidField.SetLabel("pid:")
|
||||
d.containerNamespacePidField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespacePidField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespacePidField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespacePidField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// userns
|
||||
d.containerNamespaceUserField.SetLabel("userns:")
|
||||
d.containerNamespaceUserField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespaceUserField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceUserField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceUserField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// uts
|
||||
d.containerNamespaceUtsField.SetLabel("uts:")
|
||||
d.containerNamespaceUtsField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespaceUtsField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceUtsField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceUtsField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// uidmap
|
||||
d.containerNamespaceUidmapField.SetLabel("uidmap:")
|
||||
d.containerNamespaceUidmapField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespaceUidmapField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceUidmapField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceUidmapField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// subuidname
|
||||
d.containerNamespaceSubuidNameField.SetLabel("subuidname: ")
|
||||
d.containerNamespaceSubuidNameField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceSubuidNameField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceSubuidNameField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// gidmap
|
||||
d.containerNamespaceGidmapField.SetLabel("gidmap:")
|
||||
d.containerNamespaceGidmapField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.containerNamespaceGidmapField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceGidmapField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceGidmapField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// subgidname
|
||||
d.containerNamespaceSubgidNameField.SetLabel("subgidname: ")
|
||||
d.containerNamespaceSubgidNameField.SetBackgroundColor(bgColor)
|
||||
d.containerNamespaceSubgidNameField.SetLabelColor(style.DialogFgColor)
|
||||
d.containerNamespaceSubgidNameField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// mapRow01Layout
|
||||
mapRow01Layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
mapRow01Layout.AddItem(d.containerNamespaceUidmapField, 0, 1, true)
|
||||
mapRow01Layout.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
mapRow01Layout.AddItem(d.containerNamespaceSubuidNameField, 0, 1, true)
|
||||
mapRow01Layout.SetBackgroundColor(bgColor)
|
||||
|
||||
// mapRow02Layout
|
||||
mapRow02Layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
mapRow02Layout.AddItem(d.containerNamespaceGidmapField, 0, 1, true)
|
||||
mapRow02Layout.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
mapRow02Layout.AddItem(d.containerNamespaceSubgidNameField, 0, 1, true)
|
||||
mapRow02Layout.SetBackgroundColor(bgColor)
|
||||
|
||||
// namespace options page
|
||||
d.namespacePage.SetDirection(tview.FlexRow)
|
||||
d.namespacePage.AddItem(d.containerNamespaceCgroupField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.containerNamespaceIpcField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.containerNamespacePidField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.containerNamespaceUserField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.containerNamespaceUtsField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(mapRow01Layout, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(mapRow02Layout, 1, 0, true)
|
||||
|
||||
d.namespacePage.SetBackgroundColor(bgColor)
|
||||
}
|
||||
|
||||
// Display displays this primitive.
|
||||
func (d *ContainerCreateDialog) Display() {
|
||||
d.display = true
|
||||
|
@ -1421,6 +1586,12 @@ func (d *ContainerCreateDialog) Focus(delegate func(p tview.Primitive)) { //noli
|
|||
delegate(d.containerHealthStartPeriodField)
|
||||
case createContainerHealthStartupSuccessFieldFocus:
|
||||
delegate(d.containerHealthStartupSuccessField)
|
||||
case createContainerHealthLogDestFocus:
|
||||
delegate(d.containerHealthLogDestField)
|
||||
case createContainerHealthMaxLogCountFocus:
|
||||
delegate(d.containerHealthMaxLogCountField)
|
||||
case createContainerHealthMaxLogSizeFocus:
|
||||
delegate(d.containerHealthMaxLogSizeField)
|
||||
// resource page
|
||||
case createContainerMemoryFieldFocus:
|
||||
delegate(d.containerMemoryField)
|
||||
|
@ -1450,6 +1621,25 @@ func (d *ContainerCreateDialog) Focus(delegate func(p tview.Primitive)) { //noli
|
|||
delegate(d.containerShmSizeField)
|
||||
case createContainerShmSizeSystemdFieldFocus:
|
||||
delegate(d.containerShmSizeSystemdField)
|
||||
// namespace page
|
||||
case createContainerNamespaceCgroupFieldFocus:
|
||||
delegate(d.containerNamespaceCgroupField)
|
||||
case createContainerNamespaceIpcFieldFocus:
|
||||
delegate(d.containerNamespaceIpcField)
|
||||
case createContainerNamespacePidFieldFocus:
|
||||
delegate(d.containerNamespacePidField)
|
||||
case createContainerNamespaceUserFieldFocus:
|
||||
delegate(d.containerNamespaceUserField)
|
||||
case createContainerNamespaceUtsFieldFocus:
|
||||
delegate(d.containerNamespaceUtsField)
|
||||
case createContainerNamespaceUidmapFieldFocus:
|
||||
delegate(d.containerNamespaceUidmapField)
|
||||
case createContainerNamespaceSubuidNameFieldFocus:
|
||||
delegate(d.containerNamespaceSubuidNameField)
|
||||
case createContainerNamespaceGidmapFieldFocus:
|
||||
delegate(d.containerNamespaceGidmapField)
|
||||
case createContainerNamespaceSubgidNameFieldFocus:
|
||||
delegate(d.containerNamespaceSubgidNameField)
|
||||
// category page
|
||||
case createCategoryPagesFocus:
|
||||
delegate(d.categoryPages)
|
||||
|
@ -1617,6 +1807,18 @@ func (d *ContainerCreateDialog) InputHandler() func(event *tcell.EventKey, setFo
|
|||
}
|
||||
}
|
||||
|
||||
if d.namespacePage.HasFocus() {
|
||||
if handler := d.namespacePage.InputHandler(); handler != nil {
|
||||
if event.Key() == tcell.KeyTab {
|
||||
d.setNamespaceOptionsPageNextFocus()
|
||||
}
|
||||
|
||||
handler(event, setFocus)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if d.categories.HasFocus() {
|
||||
if categroryHandler := d.categories.InputHandler(); categroryHandler != nil {
|
||||
categroryHandler(event, setFocus)
|
||||
|
@ -1839,14 +2041,17 @@ func (d *ContainerCreateDialog) initData() {
|
|||
d.containerHealthCmdField.SetText("")
|
||||
d.containerHealthStartupCmdField.SetText("")
|
||||
d.containerHealthOnFailureField.SetCurrentOption(0)
|
||||
d.containerHealthIntervalField.SetText("")
|
||||
d.containerHealthStartupIntervalField.SetText("")
|
||||
d.containerHealthTimeoutField.SetText("")
|
||||
d.containerHealthStartupTimeoutField.SetText("")
|
||||
d.containerHealthRetriesField.SetText("")
|
||||
d.containerHealthIntervalField.SetText("30s")
|
||||
d.containerHealthStartupIntervalField.SetText("30s")
|
||||
d.containerHealthTimeoutField.SetText("30s")
|
||||
d.containerHealthStartupTimeoutField.SetText("30s")
|
||||
d.containerHealthRetriesField.SetText("3")
|
||||
d.containerHealthStartupRetriesField.SetText("")
|
||||
d.containerHealthStartPeriodField.SetText("")
|
||||
d.containerHealthStartPeriodField.SetText("0s")
|
||||
d.containerHealthStartupSuccessField.SetText("")
|
||||
d.containerHealthLogDestField.SetText("local")
|
||||
d.containerHealthMaxLogCountField.SetText("5")
|
||||
d.containerHealthMaxLogSizeField.SetText("500")
|
||||
|
||||
// network settings category
|
||||
d.containerHostnameField.SetText("")
|
||||
|
@ -1889,6 +2094,17 @@ func (d *ContainerCreateDialog) initData() {
|
|||
d.containerCPUSetMemsField.SetText("")
|
||||
d.containerShmSizeField.SetText("")
|
||||
d.containerShmSizeSystemdField.SetText("")
|
||||
|
||||
// namespace options category
|
||||
d.containerNamespaceCgroupField.SetText("")
|
||||
d.containerNamespaceIpcField.SetText("")
|
||||
d.containerNamespacePidField.SetText("")
|
||||
d.containerNamespaceUserField.SetText("")
|
||||
d.containerNamespaceUtsField.SetText("")
|
||||
d.containerNamespaceUidmapField.SetText("")
|
||||
d.containerNamespaceGidmapField.SetText("")
|
||||
d.containerNamespaceSubuidNameField.SetText("")
|
||||
d.containerNamespaceSubgidNameField.SetText("")
|
||||
}
|
||||
|
||||
func (d *ContainerCreateDialog) setPortPageNextFocus() {
|
||||
|
@ -1907,6 +2123,58 @@ func (d *ContainerCreateDialog) setPortPageNextFocus() {
|
|||
d.focusElement = createContainerFormFocus
|
||||
}
|
||||
|
||||
func (d *ContainerCreateDialog) setNamespaceOptionsPageNextFocus() {
|
||||
if d.containerNamespaceCgroupField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceIpcFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespaceIpcField.HasFocus() {
|
||||
d.focusElement = createContainerNamespacePidFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespacePidField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceUserFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespaceUserField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceUtsFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespaceUtsField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceUidmapFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespaceUidmapField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceSubuidNameFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespaceSubuidNameField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceGidmapFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerNamespaceGidmapField.HasFocus() {
|
||||
d.focusElement = createContainerNamespaceSubgidNameFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.focusElement = createContainerFormFocus
|
||||
}
|
||||
|
||||
func (d *ContainerCreateDialog) setContainerInfoPageNextFocus() { //nolint:cyclop
|
||||
if d.containerNameField.HasFocus() {
|
||||
d.focusElement = createContainerCommandFieldFocus
|
||||
|
@ -2123,7 +2391,7 @@ func (d *ContainerCreateDialog) setDNSSettingsPageNextFocus() {
|
|||
d.focusElement = createContainerFormFocus
|
||||
}
|
||||
|
||||
func (d *ContainerCreateDialog) setResourceSettingsPageNextFocus() { //nolint:cyclop
|
||||
func (d *ContainerCreateDialog) setResourceSettingsPageNextFocus() { //nolint:cyclop,dupl
|
||||
if d.containerMemoryField.HasFocus() {
|
||||
d.focusElement = createContainerMemoryReservatoinFieldFocus
|
||||
|
||||
|
@ -2205,7 +2473,7 @@ func (d *ContainerCreateDialog) setResourceSettingsPageNextFocus() { //nolint:cy
|
|||
d.focusElement = createContainerFormFocus
|
||||
}
|
||||
|
||||
func (d *ContainerCreateDialog) setHealthSettingsPageNextFocus() { //nolint:cyclop
|
||||
func (d *ContainerCreateDialog) setHealthSettingsPageNextFocus() { //nolint:cyclop,dupl
|
||||
if d.containerHealthCmdField.HasFocus() {
|
||||
d.focusElement = createContainerHealthStartupCmdFieldFocus
|
||||
|
||||
|
@ -2213,24 +2481,30 @@ func (d *ContainerCreateDialog) setHealthSettingsPageNextFocus() { //nolint:cycl
|
|||
}
|
||||
|
||||
if d.containerHealthStartupCmdField.HasFocus() {
|
||||
d.focusElement = createContainerHealthLogDestFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthLogDestField.HasFocus() {
|
||||
d.focusElement = createContainerHealthMaxLogSizeFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthMaxLogSizeField.HasFocus() {
|
||||
d.focusElement = createContainerHealthMaxLogCountFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthMaxLogCountField.HasFocus() {
|
||||
d.focusElement = createContainerHealthOnFailureFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthOnFailureField.HasFocus() {
|
||||
d.focusElement = createContainerHealthStartupSuccessFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthStartupSuccessField.HasFocus() {
|
||||
d.focusElement = createContainerHealthStartPeriodFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthStartPeriodField.HasFocus() {
|
||||
d.focusElement = createContainerHealthIntervalFieldFocus
|
||||
|
||||
return
|
||||
|
@ -2243,6 +2517,12 @@ func (d *ContainerCreateDialog) setHealthSettingsPageNextFocus() { //nolint:cycl
|
|||
}
|
||||
|
||||
if d.containerHealthStartupIntervalField.HasFocus() {
|
||||
d.focusElement = createContainerHealthStartPeriodFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthStartPeriodField.HasFocus() {
|
||||
d.focusElement = createContainerHealthRetriesFieldFocus
|
||||
|
||||
return
|
||||
|
@ -2255,6 +2535,12 @@ func (d *ContainerCreateDialog) setHealthSettingsPageNextFocus() { //nolint:cycl
|
|||
}
|
||||
|
||||
if d.containerHealthStartupRetriesField.HasFocus() {
|
||||
d.focusElement = createContainerHealthStartupSuccessFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.containerHealthStartupSuccessField.HasFocus() {
|
||||
d.focusElement = createContainerHealthTimeoutFieldFocus
|
||||
|
||||
return
|
||||
|
@ -2464,6 +2750,9 @@ func (d *ContainerCreateDialog) ContainerCreateOptions() containers.CreateOption
|
|||
HealthStartupRetries: strings.TrimSpace(d.containerHealthStartupRetriesField.GetText()),
|
||||
HealthStartupSuccess: strings.TrimSpace(d.containerHealthStartupSuccessField.GetText()),
|
||||
HealthStartupTimeout: strings.TrimSpace(d.containerHealthStartupTimeoutField.GetText()),
|
||||
HealthLogDestination: strings.TrimSpace(d.containerHealthLogDestField.GetText()),
|
||||
HealthMaxLogSize: strings.TrimSpace(d.containerHealthMaxLogSizeField.GetText()),
|
||||
HealthMaxLogCount: strings.TrimSpace(d.containerHealthMaxLogCountField.GetText()),
|
||||
Memory: strings.TrimSpace(d.containerMemoryField.GetText()),
|
||||
MemoryReservation: strings.TrimSpace(d.containerMemoryReservationField.GetText()),
|
||||
MemorySwap: strings.TrimSpace(d.containerMemorySwapField.GetText()),
|
||||
|
@ -2478,6 +2767,15 @@ func (d *ContainerCreateDialog) ContainerCreateOptions() containers.CreateOption
|
|||
CPUSetMems: strings.TrimSpace(d.containerCPUSetMemsField.GetText()),
|
||||
SHMSize: strings.TrimSpace(d.containerShmSizeField.GetText()),
|
||||
SHMSizeSystemd: strings.TrimSpace(d.containerShmSizeSystemdField.GetText()),
|
||||
NamespaceCgroup: strings.TrimSpace(d.containerNamespaceCgroupField.GetText()),
|
||||
NamespaceIpc: strings.TrimSpace(d.containerNamespaceIpcField.GetText()),
|
||||
NamespacePid: strings.TrimSpace(d.containerNamespacePidField.GetText()),
|
||||
NamespaceUser: strings.TrimSpace(d.containerNamespaceUserField.GetText()),
|
||||
NamespaceUts: strings.TrimSpace(d.containerNamespaceUtsField.GetText()),
|
||||
NamespaceUidmap: strings.TrimSpace(d.containerNamespaceUidmapField.GetText()),
|
||||
NamespaceSubuidName: strings.TrimSpace(d.containerNamespaceSubuidNameField.GetText()),
|
||||
NamespaceGidmap: strings.TrimSpace(d.containerNamespaceGidmapField.GetText()),
|
||||
NamespaceSubgidName: strings.TrimSpace(d.containerNamespaceSubgidNameField.GetText()),
|
||||
}
|
||||
|
||||
return opts
|
||||
|
|
|
@ -26,14 +26,16 @@ func (cnt *Containers) UpdateData() {
|
|||
}
|
||||
|
||||
cnt.containersList.mu.Lock()
|
||||
defer cnt.containersList.mu.Unlock()
|
||||
|
||||
cnt.containersList.report = cntList
|
||||
cnt.containersList.mu.Unlock()
|
||||
}
|
||||
|
||||
func (cnt *Containers) getData() []entities.ListContainer {
|
||||
cnt.containersList.mu.Lock()
|
||||
defer cnt.containersList.mu.Unlock()
|
||||
|
||||
data := cnt.containersList.report
|
||||
cnt.containersList.mu.Unlock()
|
||||
|
||||
return data
|
||||
}
|
||||
|
@ -41,8 +43,9 @@ func (cnt *Containers) getData() []entities.ListContainer {
|
|||
// ClearData clears table data.
|
||||
func (cnt *Containers) ClearData() {
|
||||
cnt.containersList.mu.Lock()
|
||||
defer cnt.containersList.mu.Unlock()
|
||||
|
||||
cnt.containersList.report = nil
|
||||
cnt.containersList.mu.Unlock()
|
||||
cnt.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (cnt *Containers) Draw(screen tcell.Screen) { //nolint:cyclop
|
||||
cnt.refresh()
|
||||
cnt.Box.DrawForSubclass(screen, cnt)
|
||||
cnt.Box.SetBorder(false)
|
||||
|
||||
cntViewX, cntViewY, cntViewW, cntViewH := cnt.GetInnerRect()
|
||||
|
||||
cnt.refresh(cntViewW)
|
||||
cnt.table.SetRect(cntViewX, cntViewY, cntViewW, cntViewH)
|
||||
cnt.table.SetBorder(true)
|
||||
cnt.table.Draw(screen)
|
||||
|
|
|
@ -12,7 +12,9 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func (cnt *Containers) refresh() {
|
||||
func (cnt *Containers) refresh(maxWidth int) {
|
||||
imageColMaxWidth := maxWidth / 5 //nolint:mnd
|
||||
|
||||
cnt.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
@ -72,6 +74,7 @@ func (cnt *Containers) refresh() {
|
|||
// image name column
|
||||
cnt.table.SetCell(rowIndex, viewContainersImageColIndex,
|
||||
tview.NewTableCell(cntImage).
|
||||
SetMaxWidth(imageColMaxWidth).
|
||||
SetTextColor(cellTextColor).
|
||||
SetExpansion(expand).
|
||||
SetAlign(alignment))
|
||||
|
|
|
@ -22,14 +22,16 @@ func (img *Images) UpdateData() {
|
|||
}
|
||||
|
||||
img.imagesList.mu.Lock()
|
||||
defer img.imagesList.mu.Unlock()
|
||||
|
||||
img.imagesList.report = images
|
||||
img.imagesList.mu.Unlock()
|
||||
}
|
||||
|
||||
func (img *Images) getData() []images.ImageListReporter {
|
||||
img.imagesList.mu.Lock()
|
||||
defer img.imagesList.mu.Unlock()
|
||||
|
||||
data := img.imagesList.report
|
||||
img.imagesList.mu.Unlock()
|
||||
|
||||
return data
|
||||
}
|
||||
|
@ -37,8 +39,10 @@ func (img *Images) getData() []images.ImageListReporter {
|
|||
// ClearData clears table data.
|
||||
func (img *Images) ClearData() {
|
||||
img.imagesList.mu.Lock()
|
||||
defer img.imagesList.mu.Unlock()
|
||||
|
||||
img.imagesList.report = nil
|
||||
img.imagesList.mu.Unlock()
|
||||
|
||||
img.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (img *Images) Draw(screen tcell.Screen) { //nolint:cyclop
|
||||
img.refresh()
|
||||
img.Box.DrawForSubclass(screen, img)
|
||||
img.Box.SetBorder(false)
|
||||
|
||||
imagewViewX, imagewViewY, imagewViewW, imagewViewH := img.GetInnerRect()
|
||||
|
||||
img.refresh(imagewViewW)
|
||||
img.table.SetRect(imagewViewX, imagewViewY, imagewViewW, imagewViewH)
|
||||
img.table.SetBorder(true)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func (img *Images) refresh() {
|
||||
func (img *Images) refresh(_ int) {
|
||||
img.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package networks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman-tui/pdcs/networks"
|
||||
"github.com/containers/podman-tui/ui/style"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// UpdateData retrieves networks list data.
|
||||
func (nets *Networks) UpdateData() {
|
||||
netList, err := networks.List()
|
||||
if err != nil {
|
||||
log.Error().Msgf("view: networks update %v", err)
|
||||
nets.errorDialog.SetText(fmt.Sprintf("%v", err))
|
||||
nets.errorDialog.Display()
|
||||
}
|
||||
|
||||
nets.networkList.mu.Lock()
|
||||
defer nets.networkList.mu.Unlock()
|
||||
|
||||
nets.networkList.report = netList
|
||||
}
|
||||
|
||||
func (nets *Networks) getData() [][]string {
|
||||
nets.networkList.mu.Lock()
|
||||
defer nets.networkList.mu.Unlock()
|
||||
|
||||
data := nets.networkList.report
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// ClearData clears table data.
|
||||
func (nets *Networks) ClearData() {
|
||||
nets.networkList.mu.Lock()
|
||||
defer nets.networkList.mu.Unlock()
|
||||
|
||||
nets.networkList.report = nil
|
||||
|
||||
nets.table.Clear()
|
||||
|
||||
expand := 1
|
||||
fgColor := style.PageHeaderFgColor
|
||||
bgColor := style.PageHeaderBgColor
|
||||
|
||||
for i := range nets.headers {
|
||||
nets.table.SetCell(0, i,
|
||||
tview.NewTableCell(fmt.Sprintf("[::b]%s", strings.ToUpper(nets.headers[i]))). //nolint:perfsprint
|
||||
SetExpansion(expand).
|
||||
SetBackgroundColor(bgColor).
|
||||
SetTextColor(fgColor).
|
||||
SetAlign(tview.AlignLeft).
|
||||
SetSelectable(false))
|
||||
}
|
||||
|
||||
nets.table.SetTitle(fmt.Sprintf("[::b]%s[0]", strings.ToUpper(nets.title)))
|
||||
}
|
|
@ -12,6 +12,7 @@ func (nets *Networks) Draw(screen tcell.Screen) {
|
|||
netViewX, netViewY, netViewW, netViewH := nets.GetInnerRect()
|
||||
|
||||
nets.table.SetRect(netViewX, netViewY, netViewW, netViewH)
|
||||
nets.refresh(netViewW)
|
||||
nets.table.SetBorder(true)
|
||||
|
||||
nets.table.Draw(screen)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/podman-tui/ui/dialogs"
|
||||
"github.com/containers/podman-tui/ui/networks/netdialogs"
|
||||
|
@ -38,11 +39,17 @@ type Networks struct {
|
|||
createDialog *netdialogs.NetworkCreateDialog
|
||||
connectDialog *netdialogs.NetworkConnectDialog
|
||||
disconnectDialog *netdialogs.NetworkDisconnectDialog
|
||||
networkList networkListReport
|
||||
selectedID string
|
||||
confirmData string
|
||||
appFocusHandler func()
|
||||
}
|
||||
|
||||
type networkListReport struct {
|
||||
mu sync.Mutex
|
||||
report [][]string
|
||||
}
|
||||
|
||||
// NewNetworks returns nets page view.
|
||||
func NewNetworks() *Networks {
|
||||
nets := &Networks{
|
||||
|
|
|
@ -4,21 +4,11 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman-tui/pdcs/networks"
|
||||
"github.com/containers/podman-tui/ui/style"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// UpdateData retrieves networks list data.
|
||||
func (nets *Networks) UpdateData() {
|
||||
netList, err := networks.List()
|
||||
if err != nil {
|
||||
log.Error().Msgf("view: networks update %v", err)
|
||||
nets.errorDialog.SetText(fmt.Sprintf("%v", err))
|
||||
nets.errorDialog.Display()
|
||||
}
|
||||
|
||||
func (nets *Networks) refresh(_ int) {
|
||||
nets.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
@ -35,6 +25,7 @@ func (nets *Networks) UpdateData() {
|
|||
}
|
||||
|
||||
rowIndex := 1
|
||||
netList := nets.getData()
|
||||
|
||||
nets.table.SetTitle(fmt.Sprintf("[::b]%s[%d]", strings.ToUpper(nets.title), len(netList)))
|
||||
|
||||
|
@ -64,24 +55,3 @@ func (nets *Networks) UpdateData() {
|
|||
rowIndex++
|
||||
}
|
||||
}
|
||||
|
||||
// ClearData clears table data.
|
||||
func (nets *Networks) ClearData() {
|
||||
nets.table.Clear()
|
||||
|
||||
expand := 1
|
||||
fgColor := style.PageHeaderFgColor
|
||||
bgColor := style.PageHeaderBgColor
|
||||
|
||||
for i := range nets.headers {
|
||||
nets.table.SetCell(0, i,
|
||||
tview.NewTableCell(fmt.Sprintf("[::b]%s", strings.ToUpper(nets.headers[i]))). //nolint:perfsprint
|
||||
SetExpansion(expand).
|
||||
SetBackgroundColor(bgColor).
|
||||
SetTextColor(fgColor).
|
||||
SetAlign(tview.AlignLeft).
|
||||
SetSelectable(false))
|
||||
}
|
||||
|
||||
nets.table.SetTitle(fmt.Sprintf("[::b]%s[0]", strings.ToUpper(nets.title)))
|
||||
}
|
||||
|
|
|
@ -23,14 +23,16 @@ func (pods *Pods) UpdateData() {
|
|||
}
|
||||
|
||||
pods.podsList.mu.Lock()
|
||||
defer pods.podsList.mu.Unlock()
|
||||
|
||||
pods.podsList.report = podList
|
||||
pods.podsList.mu.Unlock()
|
||||
}
|
||||
|
||||
func (pods *Pods) getData() []*entities.ListPodsReport {
|
||||
pods.podsList.mu.Lock()
|
||||
defer pods.podsList.mu.Unlock()
|
||||
|
||||
data := pods.podsList.report
|
||||
pods.podsList.mu.Unlock()
|
||||
|
||||
return data
|
||||
}
|
||||
|
@ -38,8 +40,10 @@ func (pods *Pods) getData() []*entities.ListPodsReport {
|
|||
// ClearData clears table data.
|
||||
func (pods *Pods) ClearData() { //nolint:stylecheck
|
||||
pods.podsList.mu.Lock()
|
||||
defer pods.podsList.mu.Unlock()
|
||||
|
||||
pods.podsList.report = nil
|
||||
pods.podsList.mu.Unlock()
|
||||
|
||||
pods.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (pods *Pods) Draw(screen tcell.Screen) {
|
||||
pods.refresh()
|
||||
pods.Box.DrawForSubclass(screen, pods)
|
||||
pods.Box.SetBorder(false)
|
||||
|
||||
podViewX, podViewY, podViewW, podViewH := pods.GetInnerRect()
|
||||
|
||||
pods.refresh(podViewW)
|
||||
pods.table.SetRect(podViewX, podViewY, podViewW, podViewH)
|
||||
pods.table.SetBorder(true)
|
||||
|
||||
|
|
|
@ -52,6 +52,14 @@ const (
|
|||
createPodCPUSetMemsFieldFocus
|
||||
createPodShmSizeFieldFocus
|
||||
createPodShmSizeSystemdFieldFocus
|
||||
createPodNamespaceShareFieldFocus
|
||||
createPodNamespacePidFieldFocus
|
||||
createPodNamespaceUserFieldFocus
|
||||
createPodNamespaceUtsFieldFocus
|
||||
createPodNamespaceUidmapFieldFocus
|
||||
createPodNamespaceSubuidNameFieldFocus
|
||||
createPodNamespaceGidmapFieldFocus
|
||||
createPodNamespaceSubgidNameFieldFocus
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -61,56 +69,66 @@ const (
|
|||
createPodNetworkingPageIndex
|
||||
createPodSecurityOptsPageIndex
|
||||
createPodResourceSettingsPageIndex
|
||||
createPodNamespaceOptionsPageIndex
|
||||
)
|
||||
|
||||
// PodCreateDialog implements pod create dialog.
|
||||
type PodCreateDialog struct {
|
||||
*tview.Box
|
||||
layout *tview.Flex
|
||||
categoryLabels []string
|
||||
categories *tview.TextView
|
||||
categoryPages *tview.Pages
|
||||
basicInfoPage *tview.Flex
|
||||
securityOptsPage *tview.Flex
|
||||
dnsSetupPage *tview.Flex
|
||||
infraSetupPage *tview.Flex
|
||||
networkingPage *tview.Flex
|
||||
resourcePage *tview.Flex
|
||||
form *tview.Form
|
||||
display bool
|
||||
activePageIndex int
|
||||
focusElement int
|
||||
podNameField *tview.InputField
|
||||
podNoHostsCheckBox *tview.Checkbox
|
||||
podLabelsField *tview.InputField
|
||||
podSelinuxLabelField *tview.InputField
|
||||
podApparmorField *tview.InputField
|
||||
podSeccompField *tview.InputField
|
||||
podMaskField *tview.InputField
|
||||
podUnmaskField *tview.InputField
|
||||
podNoNewPrivField *tview.Checkbox
|
||||
podDNSServerField *tview.InputField
|
||||
podDNSOptionsField *tview.InputField
|
||||
podDNSSearchDomaindField *tview.InputField
|
||||
podInfraCheckBox *tview.Checkbox
|
||||
podInfraCommandField *tview.InputField
|
||||
podInfraImageField *tview.InputField
|
||||
podHostnameField *tview.InputField
|
||||
podIPAddressField *tview.InputField
|
||||
podMacAddressField *tview.InputField
|
||||
podAddHostField *tview.InputField
|
||||
podNetworkField *tview.DropDown
|
||||
podPublishField *tview.InputField
|
||||
podMemoryField *tview.InputField
|
||||
podMemorySwapField *tview.InputField
|
||||
podCPUsField *tview.InputField
|
||||
podCPUSharesField *tview.InputField
|
||||
podCPUSetCPUsField *tview.InputField
|
||||
podCPUSetMemsField *tview.InputField
|
||||
podShmSizeField *tview.InputField
|
||||
podShmSizeSystemdField *tview.InputField
|
||||
cancelHandler func()
|
||||
createHandler func()
|
||||
layout *tview.Flex
|
||||
categoryLabels []string
|
||||
categories *tview.TextView
|
||||
categoryPages *tview.Pages
|
||||
basicInfoPage *tview.Flex
|
||||
securityOptsPage *tview.Flex
|
||||
dnsSetupPage *tview.Flex
|
||||
infraSetupPage *tview.Flex
|
||||
networkingPage *tview.Flex
|
||||
resourcePage *tview.Flex
|
||||
namespacePage *tview.Flex
|
||||
form *tview.Form
|
||||
display bool
|
||||
activePageIndex int
|
||||
focusElement int
|
||||
podNameField *tview.InputField
|
||||
podNoHostsCheckBox *tview.Checkbox
|
||||
podLabelsField *tview.InputField
|
||||
podSelinuxLabelField *tview.InputField
|
||||
podApparmorField *tview.InputField
|
||||
podSeccompField *tview.InputField
|
||||
podMaskField *tview.InputField
|
||||
podUnmaskField *tview.InputField
|
||||
podNoNewPrivField *tview.Checkbox
|
||||
podDNSServerField *tview.InputField
|
||||
podDNSOptionsField *tview.InputField
|
||||
podDNSSearchDomaindField *tview.InputField
|
||||
podInfraCheckBox *tview.Checkbox
|
||||
podInfraCommandField *tview.InputField
|
||||
podInfraImageField *tview.InputField
|
||||
podHostnameField *tview.InputField
|
||||
podIPAddressField *tview.InputField
|
||||
podMacAddressField *tview.InputField
|
||||
podAddHostField *tview.InputField
|
||||
podNetworkField *tview.DropDown
|
||||
podPublishField *tview.InputField
|
||||
podMemoryField *tview.InputField
|
||||
podMemorySwapField *tview.InputField
|
||||
podCPUsField *tview.InputField
|
||||
podCPUSharesField *tview.InputField
|
||||
podCPUSetCPUsField *tview.InputField
|
||||
podCPUSetMemsField *tview.InputField
|
||||
podShmSizeField *tview.InputField
|
||||
podShmSizeSystemdField *tview.InputField
|
||||
podNamespaceShareField *tview.InputField
|
||||
podNamespacePidField *tview.InputField
|
||||
podNamespaceUserField *tview.InputField
|
||||
podNamespaceUtsField *tview.InputField
|
||||
podNamespaceUidmapField *tview.InputField
|
||||
podNamespaceSubuidNameField *tview.InputField
|
||||
podNamespaceGidmapField *tview.InputField
|
||||
podNamespaceSubgidNameField *tview.InputField
|
||||
cancelHandler func()
|
||||
createHandler func()
|
||||
}
|
||||
|
||||
// NewPodCreateDialog returns new pod create dialog primitive PodCreateDialog.
|
||||
|
@ -126,6 +144,7 @@ func NewPodCreateDialog() *PodCreateDialog {
|
|||
infraSetupPage: tview.NewFlex(),
|
||||
networkingPage: tview.NewFlex(),
|
||||
resourcePage: tview.NewFlex(),
|
||||
namespacePage: tview.NewFlex(),
|
||||
form: tview.NewForm(),
|
||||
categoryLabels: []string{
|
||||
"Basic Information",
|
||||
|
@ -134,38 +153,47 @@ func NewPodCreateDialog() *PodCreateDialog {
|
|||
"Networking",
|
||||
"Security Options",
|
||||
"Resource Settings",
|
||||
"Namespace Options",
|
||||
},
|
||||
activePageIndex: 0,
|
||||
display: false,
|
||||
podNameField: tview.NewInputField(),
|
||||
podNoHostsCheckBox: tview.NewCheckbox(),
|
||||
podLabelsField: tview.NewInputField(),
|
||||
podSelinuxLabelField: tview.NewInputField(),
|
||||
podApparmorField: tview.NewInputField(),
|
||||
podSeccompField: tview.NewInputField(),
|
||||
podMaskField: tview.NewInputField(),
|
||||
podUnmaskField: tview.NewInputField(),
|
||||
podNoNewPrivField: tview.NewCheckbox(),
|
||||
podDNSServerField: tview.NewInputField(),
|
||||
podDNSOptionsField: tview.NewInputField(),
|
||||
podDNSSearchDomaindField: tview.NewInputField(),
|
||||
podInfraCheckBox: tview.NewCheckbox(),
|
||||
podInfraCommandField: tview.NewInputField(),
|
||||
podInfraImageField: tview.NewInputField(),
|
||||
podHostnameField: tview.NewInputField(),
|
||||
podIPAddressField: tview.NewInputField(),
|
||||
podMacAddressField: tview.NewInputField(),
|
||||
podAddHostField: tview.NewInputField(),
|
||||
podNetworkField: tview.NewDropDown(),
|
||||
podPublishField: tview.NewInputField(),
|
||||
podMemoryField: tview.NewInputField(),
|
||||
podMemorySwapField: tview.NewInputField(),
|
||||
podCPUsField: tview.NewInputField(),
|
||||
podCPUSharesField: tview.NewInputField(),
|
||||
podCPUSetCPUsField: tview.NewInputField(),
|
||||
podCPUSetMemsField: tview.NewInputField(),
|
||||
podShmSizeField: tview.NewInputField(),
|
||||
podShmSizeSystemdField: tview.NewInputField(),
|
||||
activePageIndex: 0,
|
||||
display: false,
|
||||
podNameField: tview.NewInputField(),
|
||||
podNoHostsCheckBox: tview.NewCheckbox(),
|
||||
podLabelsField: tview.NewInputField(),
|
||||
podSelinuxLabelField: tview.NewInputField(),
|
||||
podApparmorField: tview.NewInputField(),
|
||||
podSeccompField: tview.NewInputField(),
|
||||
podMaskField: tview.NewInputField(),
|
||||
podUnmaskField: tview.NewInputField(),
|
||||
podNoNewPrivField: tview.NewCheckbox(),
|
||||
podDNSServerField: tview.NewInputField(),
|
||||
podDNSOptionsField: tview.NewInputField(),
|
||||
podDNSSearchDomaindField: tview.NewInputField(),
|
||||
podInfraCheckBox: tview.NewCheckbox(),
|
||||
podInfraCommandField: tview.NewInputField(),
|
||||
podInfraImageField: tview.NewInputField(),
|
||||
podHostnameField: tview.NewInputField(),
|
||||
podIPAddressField: tview.NewInputField(),
|
||||
podMacAddressField: tview.NewInputField(),
|
||||
podAddHostField: tview.NewInputField(),
|
||||
podNetworkField: tview.NewDropDown(),
|
||||
podPublishField: tview.NewInputField(),
|
||||
podMemoryField: tview.NewInputField(),
|
||||
podMemorySwapField: tview.NewInputField(),
|
||||
podCPUsField: tview.NewInputField(),
|
||||
podCPUSharesField: tview.NewInputField(),
|
||||
podCPUSetCPUsField: tview.NewInputField(),
|
||||
podCPUSetMemsField: tview.NewInputField(),
|
||||
podShmSizeField: tview.NewInputField(),
|
||||
podShmSizeSystemdField: tview.NewInputField(),
|
||||
podNamespaceShareField: tview.NewInputField(),
|
||||
podNamespacePidField: tview.NewInputField(),
|
||||
podNamespaceUserField: tview.NewInputField(),
|
||||
podNamespaceUtsField: tview.NewInputField(),
|
||||
podNamespaceUidmapField: tview.NewInputField(),
|
||||
podNamespaceSubuidNameField: tview.NewInputField(),
|
||||
podNamespaceGidmapField: tview.NewInputField(),
|
||||
podNamespaceSubgidNameField: tview.NewInputField(),
|
||||
}
|
||||
|
||||
podDialog.categories.SetDynamicColors(true).
|
||||
|
@ -208,6 +236,7 @@ func (d *PodCreateDialog) setupLayout() {
|
|||
d.setupNetworkingUI()
|
||||
d.setupSecurityOptionsUI()
|
||||
d.setupResourceSettingsUI()
|
||||
d.setupNamespaceOptionsUI()
|
||||
|
||||
// adding category pages
|
||||
d.categoryPages.AddPage(d.categoryLabels[createPodBasicInfoPageIndex], d.basicInfoPage, true, true)
|
||||
|
@ -216,6 +245,7 @@ func (d *PodCreateDialog) setupLayout() {
|
|||
d.categoryPages.AddPage(d.categoryLabels[createPodNetworkingPageIndex], d.networkingPage, true, true)
|
||||
d.categoryPages.AddPage(d.categoryLabels[createPodSecurityOptsPageIndex], d.securityOptsPage, true, true)
|
||||
d.categoryPages.AddPage(d.categoryLabels[createPodResourceSettingsPageIndex], d.resourcePage, true, true)
|
||||
d.categoryPages.AddPage(d.categoryLabels[createPodNamespaceOptionsPageIndex], d.namespacePage, true, true)
|
||||
|
||||
// add it to layout.
|
||||
_, layoutWidth := utils.AlignStringListWidth(d.categoryLabels)
|
||||
|
@ -557,6 +587,96 @@ func (d *PodCreateDialog) setupResourceSettingsUI() {
|
|||
d.resourcePage.SetBackgroundColor(style.DialogBgColor)
|
||||
}
|
||||
|
||||
func (d *PodCreateDialog) setupNamespaceOptionsUI() {
|
||||
bgColor := style.DialogBgColor
|
||||
inputFieldBgColor := style.InputFieldBgColor
|
||||
namespacePageLabelWidth := 8
|
||||
|
||||
// share
|
||||
d.podNamespaceShareField.SetLabel("share:")
|
||||
d.podNamespaceShareField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.podNamespaceShareField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceShareField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceShareField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// pid
|
||||
d.podNamespacePidField.SetLabel("pid:")
|
||||
d.podNamespacePidField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.podNamespacePidField.SetBackgroundColor(bgColor)
|
||||
d.podNamespacePidField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespacePidField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// userns
|
||||
d.podNamespaceUserField.SetLabel("userns:")
|
||||
d.podNamespaceUserField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.podNamespaceUserField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceUserField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceUserField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// uts
|
||||
d.podNamespaceUtsField.SetLabel("uts:")
|
||||
d.podNamespaceUtsField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.podNamespaceUtsField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceUtsField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceUtsField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// uidmap
|
||||
d.podNamespaceUidmapField.SetLabel("uidmap:")
|
||||
d.podNamespaceUidmapField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.podNamespaceUidmapField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceUidmapField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceUidmapField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// subuidname
|
||||
d.podNamespaceSubuidNameField.SetLabel("subuidname: ")
|
||||
d.podNamespaceSubuidNameField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceSubuidNameField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceSubuidNameField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// gidmap
|
||||
d.podNamespaceGidmapField.SetLabel("gidmap:")
|
||||
d.podNamespaceGidmapField.SetLabelWidth(namespacePageLabelWidth)
|
||||
d.podNamespaceGidmapField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceGidmapField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceGidmapField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// subgidname
|
||||
d.podNamespaceSubgidNameField.SetLabel("subgidname: ")
|
||||
d.podNamespaceSubgidNameField.SetBackgroundColor(bgColor)
|
||||
d.podNamespaceSubgidNameField.SetLabelColor(style.DialogFgColor)
|
||||
d.podNamespaceSubgidNameField.SetFieldBackgroundColor(inputFieldBgColor)
|
||||
|
||||
// mapRow01Layout
|
||||
mapRow01Layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
mapRow01Layout.AddItem(d.podNamespaceUidmapField, 0, 1, true)
|
||||
mapRow01Layout.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
mapRow01Layout.AddItem(d.podNamespaceSubuidNameField, 0, 1, true)
|
||||
mapRow01Layout.SetBackgroundColor(bgColor)
|
||||
|
||||
// mapRow02Layout
|
||||
mapRow02Layout := tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
mapRow02Layout.AddItem(d.podNamespaceGidmapField, 0, 1, true)
|
||||
mapRow02Layout.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
mapRow02Layout.AddItem(d.podNamespaceSubgidNameField, 0, 1, true)
|
||||
mapRow02Layout.SetBackgroundColor(bgColor)
|
||||
|
||||
// namespace options page
|
||||
d.namespacePage.SetDirection(tview.FlexRow)
|
||||
d.namespacePage.AddItem(d.podNamespaceShareField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.podNamespacePidField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.podNamespaceUserField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(d.podNamespaceUtsField, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(mapRow01Layout, 1, 0, true)
|
||||
d.namespacePage.AddItem(utils.EmptyBoxSpace(bgColor), 1, 0, true)
|
||||
d.namespacePage.AddItem(mapRow02Layout, 1, 0, true)
|
||||
|
||||
d.namespacePage.SetBackgroundColor(bgColor)
|
||||
}
|
||||
|
||||
// Display displays this primitive.
|
||||
func (d *PodCreateDialog) Display() {
|
||||
d.display = true
|
||||
|
@ -692,6 +812,23 @@ func (d *PodCreateDialog) Focus(delegate func(p tview.Primitive)) { //nolint:cyc
|
|||
delegate(d.podShmSizeField)
|
||||
case createPodShmSizeSystemdFieldFocus:
|
||||
delegate(d.podShmSizeSystemdField)
|
||||
// namespace page
|
||||
case createPodNamespaceShareFieldFocus:
|
||||
delegate(d.podNamespaceShareField)
|
||||
case createPodNamespacePidFieldFocus:
|
||||
delegate(d.podNamespacePidField)
|
||||
case createPodNamespaceUserFieldFocus:
|
||||
delegate(d.podNamespaceUserField)
|
||||
case createPodNamespaceUtsFieldFocus:
|
||||
delegate(d.podNamespaceUtsField)
|
||||
case createPodNamespaceUidmapFieldFocus:
|
||||
delegate(d.podNamespaceUidmapField)
|
||||
case createPodNamespaceSubuidNameFieldFocus:
|
||||
delegate(d.podNamespaceSubuidNameField)
|
||||
case createPodNamespaceGidmapFieldFocus:
|
||||
delegate(d.podNamespaceGidmapField)
|
||||
case createPodNamespaceSubgidNameFieldFocus:
|
||||
delegate(d.podNamespaceSubgidNameField)
|
||||
// category page
|
||||
case createPodCategoryPagesFocus:
|
||||
delegate(d.categoryPages)
|
||||
|
@ -790,6 +927,18 @@ func (d *PodCreateDialog) InputHandler() func(event *tcell.EventKey, setFocus fu
|
|||
}
|
||||
}
|
||||
|
||||
if d.namespacePage.HasFocus() {
|
||||
if handler := d.namespacePage.InputHandler(); handler != nil {
|
||||
if event.Key() == tcell.KeyTab {
|
||||
d.setNamespacePageNextFocus()
|
||||
}
|
||||
|
||||
handler(event, setFocus)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if d.categories.HasFocus() {
|
||||
if categroryHandler := d.categories.InputHandler(); categroryHandler != nil {
|
||||
categroryHandler(event, setFocus)
|
||||
|
@ -964,6 +1113,16 @@ func (d *PodCreateDialog) initData() {
|
|||
d.podCPUSetMemsField.SetText("")
|
||||
d.podShmSizeField.SetText("")
|
||||
d.podShmSizeSystemdField.SetText("")
|
||||
|
||||
// namespace
|
||||
d.podNamespaceShareField.SetText("")
|
||||
d.podNamespacePidField.SetText("")
|
||||
d.podNamespaceUserField.SetText("")
|
||||
d.podNamespaceUtsField.SetText("")
|
||||
d.podNamespaceUidmapField.SetText("")
|
||||
d.podNamespaceSubuidNameField.SetText("")
|
||||
d.podNamespaceGidmapField.SetText("")
|
||||
d.podNamespaceSubgidNameField.SetText("")
|
||||
}
|
||||
|
||||
func (d *PodCreateDialog) setResourcePagePageNextFocus() {
|
||||
|
@ -1128,6 +1287,52 @@ func (d *PodCreateDialog) setNetworkingPageNextFocus() {
|
|||
d.focusElement = createPodFormFocus
|
||||
}
|
||||
|
||||
func (d *PodCreateDialog) setNamespacePageNextFocus() {
|
||||
if d.podNamespaceShareField.HasFocus() {
|
||||
d.focusElement = createPodNamespacePidFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.podNamespacePidField.HasFocus() {
|
||||
d.focusElement = createPodNamespaceUserFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.podNamespaceUserField.HasFocus() {
|
||||
d.focusElement = createPodNamespaceUtsFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.podNamespaceUtsField.HasFocus() {
|
||||
d.focusElement = createPodNamespaceUidmapFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.podNamespaceUidmapField.HasFocus() {
|
||||
d.focusElement = createPodNamespaceSubuidNameFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.podNamespaceSubuidNameField.HasFocus() {
|
||||
d.focusElement = createPodNamespaceGidmapFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if d.podNamespaceGidmapField.HasFocus() {
|
||||
d.focusElement = createPodNamespaceSubgidNameFieldFocus
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.focusElement = createPodFormFocus
|
||||
}
|
||||
|
||||
// GetPodSpec returns pod create option spec.
|
||||
func (d *PodCreateDialog) GetPodSpec() pods.CreateOptions { //nolint:gocognit,cyclop
|
||||
var (
|
||||
|
@ -1139,8 +1344,15 @@ func (d *PodCreateDialog) GetPodSpec() pods.CreateOptions { //nolint:gocognit,cy
|
|||
network string
|
||||
securityOpts []string
|
||||
publish []string
|
||||
namespaceShare []string
|
||||
)
|
||||
|
||||
for _, nsshare := range strings.Split(d.podNamespaceShareField.GetText(), " ") {
|
||||
if nsshare != "" {
|
||||
namespaceShare = append(namespaceShare, nsshare)
|
||||
}
|
||||
}
|
||||
|
||||
for _, label := range strings.Split(d.podLabelsField.GetText(), " ") {
|
||||
if label != "" {
|
||||
split := strings.Split(label, "=")
|
||||
|
@ -1222,30 +1434,38 @@ func (d *PodCreateDialog) GetPodSpec() pods.CreateOptions { //nolint:gocognit,cy
|
|||
}
|
||||
|
||||
opts := pods.CreateOptions{
|
||||
Name: strings.TrimSpace(d.podNameField.GetText()),
|
||||
NoHost: d.podNoHostsCheckBox.IsChecked(),
|
||||
Labels: labels,
|
||||
DNSServer: dnsServers,
|
||||
DNSOptions: dnsOptions,
|
||||
DNSSearchDomain: dnsSearchDomains,
|
||||
Infra: d.podInfraCheckBox.IsChecked(),
|
||||
InfraImage: strings.TrimSpace(d.podInfraImageField.GetText()),
|
||||
InfraCommand: strings.TrimSpace(d.podInfraCommandField.GetText()),
|
||||
Hostname: strings.TrimSpace(d.podHostnameField.GetText()),
|
||||
IPAddress: strings.TrimSpace(d.podIPAddressField.GetText()),
|
||||
MacAddress: strings.TrimSpace(d.podMacAddressField.GetText()),
|
||||
AddHost: addHost,
|
||||
Network: network,
|
||||
SecurityOpts: securityOpts,
|
||||
Publish: publish,
|
||||
Memory: strings.TrimSpace(d.podMemoryField.GetText()),
|
||||
MemorySwap: strings.TrimSpace(d.podMemorySwapField.GetText()),
|
||||
CPUs: strings.TrimSpace(d.podCPUsField.GetText()),
|
||||
CPUShares: strings.TrimSpace(d.podCPUSharesField.GetText()),
|
||||
CPUSetCPUs: strings.TrimSpace(d.podCPUSetCPUsField.GetText()),
|
||||
CPUSetMems: strings.TrimSpace(d.podCPUSetMemsField.GetText()),
|
||||
ShmSize: strings.TrimSpace(d.podShmSizeField.GetText()),
|
||||
ShmSizeSystemd: strings.TrimSpace(d.podShmSizeSystemdField.GetText()),
|
||||
Name: strings.TrimSpace(d.podNameField.GetText()),
|
||||
NoHost: d.podNoHostsCheckBox.IsChecked(),
|
||||
Labels: labels,
|
||||
DNSServer: dnsServers,
|
||||
DNSOptions: dnsOptions,
|
||||
DNSSearchDomain: dnsSearchDomains,
|
||||
Infra: d.podInfraCheckBox.IsChecked(),
|
||||
InfraImage: strings.TrimSpace(d.podInfraImageField.GetText()),
|
||||
InfraCommand: strings.TrimSpace(d.podInfraCommandField.GetText()),
|
||||
Hostname: strings.TrimSpace(d.podHostnameField.GetText()),
|
||||
IPAddress: strings.TrimSpace(d.podIPAddressField.GetText()),
|
||||
MacAddress: strings.TrimSpace(d.podMacAddressField.GetText()),
|
||||
AddHost: addHost,
|
||||
Network: network,
|
||||
SecurityOpts: securityOpts,
|
||||
Publish: publish,
|
||||
Memory: strings.TrimSpace(d.podMemoryField.GetText()),
|
||||
MemorySwap: strings.TrimSpace(d.podMemorySwapField.GetText()),
|
||||
CPUs: strings.TrimSpace(d.podCPUsField.GetText()),
|
||||
CPUShares: strings.TrimSpace(d.podCPUSharesField.GetText()),
|
||||
CPUSetCPUs: strings.TrimSpace(d.podCPUSetCPUsField.GetText()),
|
||||
CPUSetMems: strings.TrimSpace(d.podCPUSetMemsField.GetText()),
|
||||
ShmSize: strings.TrimSpace(d.podShmSizeField.GetText()),
|
||||
ShmSizeSystemd: strings.TrimSpace(d.podShmSizeSystemdField.GetText()),
|
||||
NamespaceShare: namespaceShare,
|
||||
NamespacePid: strings.TrimSpace(d.podNamespacePidField.GetText()),
|
||||
NamespaceUser: strings.TrimSpace(d.podNamespaceUserField.GetText()),
|
||||
NamespaceUts: strings.TrimSpace(d.podNamespaceUtsField.GetText()),
|
||||
NamespaceUidmap: strings.TrimSpace(d.podNamespaceUidmapField.GetText()),
|
||||
NamespaceSubuidName: strings.TrimSpace(d.podNamespaceSubuidNameField.GetText()),
|
||||
NamespaceGidmap: strings.TrimSpace(d.podNamespaceGidmapField.GetText()),
|
||||
NamespaceSubgidName: strings.TrimSpace(d.podNamespaceSubgidNameField.GetText()),
|
||||
}
|
||||
|
||||
return opts
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func (pods *Pods) refresh() {
|
||||
func (pods *Pods) refresh(_ int) {
|
||||
pods.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package secrets
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/podman-tui/pdcs/secrets"
|
||||
"github.com/containers/podman-tui/ui/style"
|
||||
"github.com/containers/podman/v5/pkg/domain/entities/types"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// UpdateData retrieves secrets list data.
|
||||
func (s *Secrets) UpdateData() {
|
||||
secResponse, err := secrets.List()
|
||||
if err != nil {
|
||||
log.Error().Msgf("view: secrets update %v", err)
|
||||
|
||||
s.errorDialog.SetText(fmt.Sprintf("%v", err))
|
||||
s.errorDialog.Display()
|
||||
}
|
||||
|
||||
s.secretList.mu.Lock()
|
||||
defer s.secretList.mu.Unlock()
|
||||
|
||||
s.secretList.report = secResponse
|
||||
}
|
||||
|
||||
func (s *Secrets) getData() []*types.SecretInfoReport {
|
||||
s.secretList.mu.Lock()
|
||||
defer s.secretList.mu.Unlock()
|
||||
|
||||
data := s.secretList.report
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// ClearData clears table data.
|
||||
func (s *Secrets) ClearData() {
|
||||
s.secretList.mu.Lock()
|
||||
defer s.secretList.mu.Unlock()
|
||||
|
||||
s.secretList.report = nil
|
||||
|
||||
s.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
||||
for i := range s.headers {
|
||||
s.table.SetCell(0, i,
|
||||
tview.NewTableCell(fmt.Sprintf("[::b]%s", strings.ToUpper(s.headers[i]))). //nolint:perfsprint
|
||||
SetExpansion(expand).
|
||||
SetBackgroundColor(style.PageHeaderBgColor).
|
||||
SetTextColor(style.PageHeaderFgColor).
|
||||
SetAlign(tview.AlignLeft).
|
||||
SetSelectable(false))
|
||||
}
|
||||
|
||||
s.table.SetTitle(fmt.Sprintf("[::b]%s[0]", strings.ToUpper(s.title)))
|
||||
}
|
|
@ -10,6 +10,7 @@ func (s *Secrets) Draw(screen tcell.Screen) {
|
|||
secretViewX, secretViewY, secretViewW, secretViewH := s.GetInnerRect()
|
||||
|
||||
s.table.SetRect(secretViewX, secretViewY, secretViewW, secretViewH)
|
||||
s.refresh(secretViewW)
|
||||
s.table.SetBorder(true)
|
||||
s.table.Draw(screen)
|
||||
|
||||
|
|
|
@ -5,23 +5,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman-tui/pdcs/secrets"
|
||||
"github.com/containers/podman-tui/ui/style"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// UpdateData retrieves secrets list data.
|
||||
func (s *Secrets) UpdateData() {
|
||||
secResponse, err := secrets.List()
|
||||
if err != nil {
|
||||
log.Error().Msgf("view: secrets update %v", err)
|
||||
|
||||
s.errorDialog.SetText(fmt.Sprintf("%v", err))
|
||||
s.errorDialog.Display()
|
||||
}
|
||||
|
||||
func (s *Secrets) refresh(_ int) {
|
||||
s.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
@ -38,6 +27,7 @@ func (s *Secrets) UpdateData() {
|
|||
}
|
||||
|
||||
rowIndex := 1
|
||||
secResponse := s.getData()
|
||||
|
||||
s.table.SetTitle(fmt.Sprintf("[::b]%s[%d]", strings.ToUpper(s.title), len(secResponse)))
|
||||
|
||||
|
@ -81,22 +71,3 @@ func (s *Secrets) UpdateData() {
|
|||
rowIndex++
|
||||
}
|
||||
}
|
||||
|
||||
// ClearData clears table data.
|
||||
func (s *Secrets) ClearData() {
|
||||
s.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
||||
for i := range s.headers {
|
||||
s.table.SetCell(0, i,
|
||||
tview.NewTableCell(fmt.Sprintf("[::b]%s", strings.ToUpper(s.headers[i]))). //nolint:perfsprint
|
||||
SetExpansion(expand).
|
||||
SetBackgroundColor(style.PageHeaderBgColor).
|
||||
SetTextColor(style.PageHeaderFgColor).
|
||||
SetAlign(tview.AlignLeft).
|
||||
SetSelectable(false))
|
||||
}
|
||||
|
||||
s.table.SetTitle(fmt.Sprintf("[::b]%s[0]", strings.ToUpper(s.title)))
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/podman-tui/ui/dialogs"
|
||||
"github.com/containers/podman-tui/ui/secrets/secdialogs"
|
||||
"github.com/containers/podman-tui/ui/style"
|
||||
"github.com/containers/podman/v5/pkg/domain/entities/types"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
|
@ -38,9 +40,15 @@ type Secrets struct {
|
|||
progressDialog *dialogs.ProgressDialog
|
||||
confirmDialog *dialogs.ConfirmDialog
|
||||
createDialog *secdialogs.SecretCreateDialog
|
||||
secretList secretListReport
|
||||
appFocusHandler func()
|
||||
}
|
||||
|
||||
type secretListReport struct {
|
||||
mu sync.Mutex
|
||||
report []*types.SecretInfoReport
|
||||
}
|
||||
|
||||
// NewSecrets returns secrets page view.
|
||||
func NewSecrets() *Secrets {
|
||||
secrets := &Secrets{
|
||||
|
|
|
@ -50,7 +50,7 @@ func (sys *System) addConnection() {
|
|||
go func() {
|
||||
err := sys.connectionAddFunc(name, uri, identity)
|
||||
sys.progressDialog.Hide()
|
||||
sys.UpdateConnectionsData()
|
||||
sys.UpdateData()
|
||||
|
||||
if err != nil {
|
||||
sys.displayError("ADD NEW CONNECTION ERROR", err)
|
||||
|
@ -76,13 +76,13 @@ func (sys *System) connect() {
|
|||
|
||||
sys.eventDialog.SetText("")
|
||||
sys.connectionConnectFunc(dest)
|
||||
sys.UpdateConnectionsData()
|
||||
sys.UpdateData()
|
||||
}
|
||||
|
||||
func (sys *System) disconnect() {
|
||||
sys.connectionDisconnectFunc()
|
||||
sys.eventDialog.SetText("")
|
||||
sys.UpdateConnectionsData()
|
||||
sys.UpdateData()
|
||||
}
|
||||
|
||||
func (sys *System) df() {
|
||||
|
@ -229,7 +229,7 @@ func (sys *System) remove() {
|
|||
return
|
||||
}
|
||||
|
||||
sys.UpdateConnectionsData()
|
||||
sys.UpdateData()
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,16 @@ import (
|
|||
"github.com/containers/podman-tui/ui/style"
|
||||
)
|
||||
|
||||
// UpdateConnectionsData retrieves connections list data.
|
||||
func (sys *System) UpdateConnectionsData() {
|
||||
// UpdateData retrieves connections list data.
|
||||
func (sys *System) UpdateData() {
|
||||
destinations := sys.connectionListFunc()
|
||||
|
||||
sys.connectionList.mu.Lock()
|
||||
|
||||
sys.connectionList.report = destinations
|
||||
|
||||
sys.connectionList.mu.Unlock()
|
||||
|
||||
sys.udpateConnectionDataStatus()
|
||||
}
|
||||
|
||||
|
@ -34,8 +38,9 @@ func (sys *System) udpateConnectionDataStatus() {
|
|||
|
||||
func (sys *System) getConnectionsData() []registry.Connection {
|
||||
sys.connectionList.mu.Lock()
|
||||
defer sys.connectionList.mu.Unlock()
|
||||
|
||||
destReport := sys.connectionList.report
|
||||
sys.connectionList.mu.Unlock()
|
||||
|
||||
return destReport
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (sys *System) Draw(screen tcell.Screen) { //nolint:cyclop
|
||||
sys.refresh()
|
||||
sys.Box.DrawForSubclass(screen, sys)
|
||||
|
||||
sysViewX, sysViewY, sysViewW, sysViewH := sys.GetInnerRect()
|
||||
|
||||
sys.connTable.SetRect(sysViewX, sysViewY, sysViewW, sysViewH)
|
||||
sys.refresh(sysViewW)
|
||||
sys.connTable.Draw(screen)
|
||||
|
||||
x, y, width, height := sys.connTable.GetInnerRect()
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func (sys *System) refresh() {
|
||||
func (sys *System) refresh(_ int) {
|
||||
connections := sys.getConnectionsData()
|
||||
sys.connTable.Clear()
|
||||
sys.updateConnTableTitle(len(connections))
|
||||
|
|
|
@ -148,7 +148,7 @@ func NewSystem() *System {
|
|||
sys.connPrgDialog.Hide()
|
||||
registry.UnsetConnection()
|
||||
sys.eventDialog.SetText("")
|
||||
sys.UpdateConnectionsData()
|
||||
sys.UpdateData()
|
||||
})
|
||||
|
||||
// set connection create dialog functions
|
||||
|
|
|
@ -23,14 +23,16 @@ func (vols *Volumes) UpdateData() {
|
|||
}
|
||||
|
||||
vols.volumeList.mu.Lock()
|
||||
defer vols.volumeList.mu.Unlock()
|
||||
|
||||
vols.volumeList.report = volList
|
||||
vols.volumeList.mu.Unlock()
|
||||
}
|
||||
|
||||
func (vols *Volumes) getData() []*entities.VolumeListReport {
|
||||
vols.volumeList.mu.Lock()
|
||||
defer vols.volumeList.mu.Unlock()
|
||||
|
||||
data := vols.volumeList.report
|
||||
vols.volumeList.mu.Unlock()
|
||||
|
||||
return data
|
||||
}
|
||||
|
@ -38,8 +40,9 @@ func (vols *Volumes) getData() []*entities.VolumeListReport {
|
|||
// ClearData clears table data.
|
||||
func (vols *Volumes) ClearData() {
|
||||
vols.volumeList.mu.Lock()
|
||||
defer vols.volumeList.mu.Unlock()
|
||||
|
||||
vols.volumeList.report = nil
|
||||
vols.volumeList.mu.Unlock()
|
||||
|
||||
vols.table.Clear()
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (vols *Volumes) Draw(screen tcell.Screen) {
|
||||
vols.refresh()
|
||||
vols.Box.DrawForSubclass(screen, vols)
|
||||
vols.Box.SetBorder(false)
|
||||
|
||||
x, y, width, height := vols.GetInnerRect()
|
||||
|
||||
vols.refresh(width)
|
||||
vols.table.SetRect(x, y, width, height)
|
||||
vols.table.SetBorder(true)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const (
|
|||
volsTableMountPointColIndex
|
||||
)
|
||||
|
||||
func (vols *Volumes) refresh() {
|
||||
func (vols *Volumes) refresh(_ int) {
|
||||
vols.table.Clear()
|
||||
|
||||
expand := 1
|
||||
|
|
|
@ -187,7 +187,7 @@ type BuildOptions struct {
|
|||
// Log is a callback that will print a progress message. If no value
|
||||
// is supplied, the message will be sent to Err (or os.Stderr, if Err
|
||||
// is nil) by default.
|
||||
Log func(format string, args ...interface{})
|
||||
Log func(format string, args ...any)
|
||||
// In is connected to stdin for RUN instructions.
|
||||
In io.Reader
|
||||
// Out is a place where non-error log messages are sent.
|
||||
|
@ -236,6 +236,9 @@ type BuildOptions struct {
|
|||
// ID mapping options to use if we're setting up our own user namespace
|
||||
// when handling RUN instructions.
|
||||
IDMappingOptions *IDMappingOptions
|
||||
// InheritLabels controls whether or not built images will retain the labels
|
||||
// which were set in their base images
|
||||
InheritLabels types.OptionalBool
|
||||
// AddCapabilities is a list of capabilities to add to the default set when
|
||||
// handling RUN instructions.
|
||||
AddCapabilities []string
|
||||
|
|
|
@ -29,7 +29,7 @@ const (
|
|||
// identify working containers.
|
||||
Package = "buildah"
|
||||
// Version for the Package. Also used by .packit.sh for Packit builds.
|
||||
Version = "1.39.4"
|
||||
Version = "1.40.1"
|
||||
|
||||
// DefaultRuntime if containers.conf fails.
|
||||
DefaultRuntime = "runc"
|
||||
|
@ -260,13 +260,6 @@ func parseGitBuildContext(url string) (string, string, string) {
|
|||
return gitBranchPart[0], gitSubdir, gitBranch
|
||||
}
|
||||
|
||||
func isGitTag(remote, ref string) bool {
|
||||
if _, err := exec.Command("git", "ls-remote", "--exit-code", remote, ref).Output(); err != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func cloneToDirectory(url, dir string) ([]byte, string, error) {
|
||||
var cmd *exec.Cmd
|
||||
gitRepo, gitSubdir, gitRef := parseGitBuildContext(url)
|
||||
|
@ -274,20 +267,18 @@ func cloneToDirectory(url, dir string) ([]byte, string, error) {
|
|||
cmd = exec.Command("git", "init", dir)
|
||||
combinedOutput, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git init`: %w", err)
|
||||
// Return err.Error() instead of err as we want buildah to override error code with more predictable
|
||||
// value.
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git init`: %s", err.Error())
|
||||
}
|
||||
// add origin
|
||||
cmd = exec.Command("git", "remote", "add", "origin", gitRepo)
|
||||
cmd.Dir = dir
|
||||
combinedOutput, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git remote add`: %w", err)
|
||||
}
|
||||
|
||||
if gitRef != "" {
|
||||
if ok := isGitTag(url, gitRef); ok {
|
||||
gitRef += ":refs/tags/" + gitRef
|
||||
}
|
||||
// Return err.Error() instead of err as we want buildah to override error code with more predictable
|
||||
// value.
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git remote add`: %s", err.Error())
|
||||
}
|
||||
|
||||
logrus.Debugf("fetching repo %q and branch (or commit ID) %q to %q", gitRepo, gitRef, dir)
|
||||
|
@ -296,14 +287,18 @@ func cloneToDirectory(url, dir string) ([]byte, string, error) {
|
|||
cmd.Dir = dir
|
||||
combinedOutput, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git fetch`: %w", err)
|
||||
// Return err.Error() instead of err as we want buildah to override error code with more predictable
|
||||
// value.
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git fetch`: %s", err.Error())
|
||||
}
|
||||
|
||||
cmd = exec.Command("git", "checkout", "FETCH_HEAD")
|
||||
cmd.Dir = dir
|
||||
combinedOutput, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git checkout`: %w", err)
|
||||
// Return err.Error() instead of err as we want buildah to override error code with more predictable
|
||||
// value.
|
||||
return combinedOutput, gitSubdir, fmt.Errorf("failed while performing `git checkout`: %s", err.Error())
|
||||
}
|
||||
return combinedOutput, gitSubdir, nil
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// DeepCopyDescriptor copies a Descriptor, deeply copying its contents
|
||||
|
|
|
@ -21,8 +21,10 @@ import (
|
|||
"github.com/containers/image/v5/signature"
|
||||
"github.com/containers/image/v5/signature/signer"
|
||||
storageTransport "github.com/containers/image/v5/storage"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
encconfig "github.com/containers/ocicrypt/config"
|
||||
"github.com/containers/storage"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -175,8 +177,8 @@ type Copier struct {
|
|||
// newCopier creates a Copier based on a runtime's system context.
|
||||
// Note that fields in options *may* overwrite the counterparts of
|
||||
// the specified system context. Please make sure to call `(*Copier).Close()`.
|
||||
func (r *Runtime) newCopier(options *CopyOptions, reportResolvedReference *types.ImageReference) (*Copier, error) {
|
||||
return NewCopier(options, r.SystemContext(), reportResolvedReference)
|
||||
func (r *Runtime) newCopier(options *CopyOptions) (*Copier, error) {
|
||||
return NewCopier(options, r.SystemContext())
|
||||
}
|
||||
|
||||
// storageAllowedPolicyScopes overrides the policy for local storage
|
||||
|
@ -223,7 +225,7 @@ func getDockerAuthConfig(name, passwd, creds, idToken string) (*types.DockerAuth
|
|||
// NewCopier creates a Copier based on a provided system context.
|
||||
// Note that fields in options *may* overwrite the counterparts of
|
||||
// the specified system context. Please make sure to call `(*Copier).Close()`.
|
||||
func NewCopier(options *CopyOptions, sc *types.SystemContext, reportResolvedReference *types.ImageReference) (*Copier, error) {
|
||||
func NewCopier(options *CopyOptions, sc *types.SystemContext) (*Copier, error) {
|
||||
c := Copier{extendTimeoutSocket: options.extendTimeoutSocket}
|
||||
sysContextCopy := *sc
|
||||
c.systemContext = &sysContextCopy
|
||||
|
@ -330,7 +332,6 @@ func NewCopier(options *CopyOptions, sc *types.SystemContext, reportResolvedRefe
|
|||
c.imageCopyOptions.SignBySigstorePrivateKeyFile = options.SignBySigstorePrivateKeyFile
|
||||
c.imageCopyOptions.SignSigstorePrivateKeyPassphrase = options.SignSigstorePrivateKeyPassphrase
|
||||
c.imageCopyOptions.ReportWriter = options.Writer
|
||||
c.imageCopyOptions.ReportResolvedReference = reportResolvedReference
|
||||
|
||||
defaultContainerConfig, err := config.Default()
|
||||
if err != nil {
|
||||
|
@ -350,6 +351,12 @@ func (c *Copier) Close() error {
|
|||
// Copy the source to the destination. Returns the bytes of the copied
|
||||
// manifest which may be used for digest computation.
|
||||
func (c *Copier) Copy(ctx context.Context, source, destination types.ImageReference) ([]byte, error) {
|
||||
return c.copyInternal(ctx, source, destination, nil)
|
||||
}
|
||||
|
||||
// Copy the source to the destination. Returns the bytes of the copied
|
||||
// manifest which may be used for digest computation.
|
||||
func (c *Copier) copyInternal(ctx context.Context, source, destination types.ImageReference, reportResolvedReference *types.ImageReference) ([]byte, error) {
|
||||
logrus.Debugf("Copying source image %s to destination image %s", source.StringWithinTransport(), destination.StringWithinTransport())
|
||||
|
||||
// Avoid running out of time when running inside a systemd unit by
|
||||
|
@ -454,6 +461,11 @@ func (c *Copier) Copy(ctx context.Context, source, destination types.ImageRefere
|
|||
var returnManifest []byte
|
||||
f := func() error {
|
||||
opts := c.imageCopyOptions
|
||||
// This is already set when `newCopier` was called but there is an option
|
||||
// to override it by callers if needed.
|
||||
if reportResolvedReference != nil {
|
||||
opts.ReportResolvedReference = reportResolvedReference
|
||||
}
|
||||
if sourceInsecure != nil {
|
||||
value := types.NewOptionalBool(*sourceInsecure)
|
||||
opts.SourceCtx.DockerInsecureSkipTLSVerify = value
|
||||
|
@ -472,6 +484,22 @@ func (c *Copier) Copy(ctx context.Context, source, destination types.ImageRefere
|
|||
return returnManifest, retry.IfNecessary(ctx, f, &c.retryOptions)
|
||||
}
|
||||
|
||||
func (c *Copier) copyToStorage(ctx context.Context, source, destination types.ImageReference) (*storage.Image, error) {
|
||||
var resolvedReference types.ImageReference
|
||||
_, err := c.copyInternal(ctx, source, destination, &resolvedReference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("internal error: unable to copy from source %s: %w", transports.ImageName(source), err)
|
||||
}
|
||||
if resolvedReference == nil {
|
||||
return nil, fmt.Errorf("internal error: After attempting to copy %s, resolvedReference is nil", source)
|
||||
}
|
||||
_, image, err := storageTransport.ResolveReference(resolvedReference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolving an already-resolved reference %q to the pulled image: %w", transports.ImageName(resolvedReference), err)
|
||||
}
|
||||
return image, nil
|
||||
}
|
||||
|
||||
// checkRegistrySourcesAllows checks the $BUILD_REGISTRY_SOURCES environment
|
||||
// variable, if it's set. The contents are expected to be a JSON-encoded
|
||||
// github.com/openshift/api/config/v1.Image, set by an OpenShift build
|
||||
|
|
|
@ -5,6 +5,9 @@ package libimage
|
|||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ImageDiskUsage reports the total size of an image. That is the size
|
||||
|
@ -36,49 +39,49 @@ func (r *Runtime) DiskUsage(ctx context.Context) ([]ImageDiskUsage, int64, error
|
|||
return nil, -1, err
|
||||
}
|
||||
|
||||
layerTree, err := r.newLayerTreeFromData(images, layers)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
var totalSize int64
|
||||
layerMap := make(map[string]*storage.Layer)
|
||||
for _, layer := range layers {
|
||||
layerMap[layer.ID] = &layer
|
||||
if layer.UncompressedSize == -1 {
|
||||
// size is unknown, we must manually diff the layer size which
|
||||
// can be quite slow as it might have to walk all files
|
||||
size, err := r.store.DiffSize("", layer.ID)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
// cache the size now
|
||||
layer.UncompressedSize = size
|
||||
}
|
||||
// count the total layer size here so we know we only count each layer once
|
||||
totalSize += layer.UncompressedSize
|
||||
}
|
||||
|
||||
var totalSize int64
|
||||
visitedImages := make(map[string]bool)
|
||||
visistedLayers := make(map[string]bool)
|
||||
// First walk all images to count how often each layer is used.
|
||||
// This is done so we know if the size for an image is shared between
|
||||
// images that use the same layer or unique.
|
||||
layerCount := make(map[string]int)
|
||||
for _, image := range images {
|
||||
walkImageLayers(image, layerMap, func(layer *storage.Layer) {
|
||||
// Increment the count for each layer visit
|
||||
layerCount[layer.ID] += 1
|
||||
})
|
||||
}
|
||||
|
||||
// Now that we actually have all the info walk again to add the sizes.
|
||||
var allUsages []ImageDiskUsage
|
||||
for _, image := range images {
|
||||
usages, err := diskUsageForImage(ctx, image, layerTree)
|
||||
usages, err := diskUsageForImage(ctx, image, layerMap, layerCount, &totalSize)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
allUsages = append(allUsages, usages...)
|
||||
|
||||
if _, ok := visitedImages[image.ID()]; ok {
|
||||
// Do not count an image twice
|
||||
continue
|
||||
}
|
||||
visitedImages[image.ID()] = true
|
||||
|
||||
size, err := image.Size()
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
for _, layer := range layerTree.layersOf(image) {
|
||||
if _, ok := visistedLayers[layer.ID]; ok {
|
||||
// Do not count a layer twice, so remove its
|
||||
// size from the image size.
|
||||
size -= layer.UncompressedSize
|
||||
continue
|
||||
}
|
||||
visistedLayers[layer.ID] = true
|
||||
}
|
||||
totalSize += size
|
||||
}
|
||||
return allUsages, totalSize, err
|
||||
}
|
||||
|
||||
// diskUsageForImage returns the disk-usage baseistics for the specified image.
|
||||
func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) ([]ImageDiskUsage, error) {
|
||||
func diskUsageForImage(ctx context.Context, image *Image, layerMap map[string]*storage.Layer, layerCount map[string]int, totalSize *int64) ([]ImageDiskUsage, error) {
|
||||
if err := image.isCorrupted(ctx, ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -90,36 +93,25 @@ func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) ([]Im
|
|||
Tag: "<none>",
|
||||
}
|
||||
|
||||
// Shared, unique and total size.
|
||||
parent, err := tree.parent(ctx, image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
childIDs, err := tree.children(ctx, image, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Optimistically set unique size to the full size of the image.
|
||||
size, err := image.Size()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.UniqueSize = size
|
||||
|
||||
if len(childIDs) > 0 {
|
||||
// If we have children, we share everything.
|
||||
base.SharedSize = base.UniqueSize
|
||||
base.UniqueSize = 0
|
||||
} else if parent != nil {
|
||||
// If we have no children but a parent, remove the parent
|
||||
// (shared) size from the unique one.
|
||||
size, err := parent.Size()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
walkImageLayers(image, layerMap, func(layer *storage.Layer) {
|
||||
// If the layer used by more than one image it shares its size
|
||||
if layerCount[layer.ID] > 1 {
|
||||
base.SharedSize += layer.UncompressedSize
|
||||
} else {
|
||||
base.UniqueSize += layer.UncompressedSize
|
||||
}
|
||||
base.UniqueSize -= size
|
||||
base.SharedSize = size
|
||||
})
|
||||
|
||||
// Count the image specific big data as well.
|
||||
// store.BigDataSize() is not used intentionally, it is slower (has to take
|
||||
// locks) and can fail.
|
||||
// BigDataSizes is always correctly populated on new stores since c/storage
|
||||
// commit a7d7fe8c9a (2016). It should be safe to assume that no such old
|
||||
// store+image exist now so we don't bother. Worst case we report a few
|
||||
// bytes to little.
|
||||
for _, size := range image.storageImage.BigDataSizes {
|
||||
base.UniqueSize += size
|
||||
*totalSize += size
|
||||
}
|
||||
|
||||
base.Size = base.SharedSize + base.UniqueSize
|
||||
|
@ -155,3 +147,33 @@ func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) ([]Im
|
|||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// walkImageLayers walks all layers in an image and calls the given function for each layer.
|
||||
func walkImageLayers(image *Image, layerMap map[string]*storage.Layer, f func(layer *storage.Layer)) {
|
||||
visited := make(map[string]struct{})
|
||||
// Layers are walked recursively until it has no parent which means we reached the end.
|
||||
// We must account for the fact that an image might have several top layers when id mappings are used.
|
||||
layers := append([]string{image.storageImage.TopLayer}, image.storageImage.MappedTopLayers...)
|
||||
for _, layerID := range layers {
|
||||
for layerID != "" {
|
||||
layer := layerMap[layerID]
|
||||
if layer == nil {
|
||||
logrus.Errorf("Local Storage is corrupt, layer %q missing from the storage", layerID)
|
||||
break
|
||||
}
|
||||
if _, ok := visited[layerID]; ok {
|
||||
// We have seen this layer before. Break here to
|
||||
// a) Do not count the same layer twice that was shared between
|
||||
// the TopLayer and MappedTopLayers layer chain.
|
||||
// b) Prevent infinite loops, should not happen per c/storage
|
||||
// design but it is good to be safer.
|
||||
break
|
||||
}
|
||||
visited[layerID] = struct{}{}
|
||||
|
||||
f(layer)
|
||||
// Set the layer for the next iteration, parent is empty if we reach the end.
|
||||
layerID = layer.Parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/containerd/platforms"
|
||||
"github.com/containers/common/libimage/platform"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
storageTransport "github.com/containers/image/v5/storage"
|
||||
"github.com/containers/image/v5/types"
|
||||
|
@ -190,13 +191,21 @@ func (i *Image) IsReadOnly() bool {
|
|||
}
|
||||
|
||||
// IsDangling returns true if the image is dangling, that is an untagged image
|
||||
// without children.
|
||||
// without children and not used in a manifest list.
|
||||
func (i *Image) IsDangling(ctx context.Context) (bool, error) {
|
||||
return i.isDangling(ctx, nil)
|
||||
images, layers, err := i.runtime.getImagesAndLayers()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
tree, err := i.runtime.newLayerTreeFromData(images, layers, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return i.isDangling(ctx, tree)
|
||||
}
|
||||
|
||||
// isDangling returns true if the image is dangling, that is an untagged image
|
||||
// without children. If tree is nil, it will created for this invocation only.
|
||||
// without children and not used in a manifest list. If tree is nil, it will created for this invocation only.
|
||||
func (i *Image) isDangling(ctx context.Context, tree *layerTree) (bool, error) {
|
||||
if len(i.Names()) > 0 {
|
||||
return false, nil
|
||||
|
@ -205,7 +214,8 @@ func (i *Image) isDangling(ctx context.Context, tree *layerTree) (bool, error) {
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return len(children) == 0, nil
|
||||
_, usedInManfiestList := tree.manifestListDigests[i.Digest()]
|
||||
return (len(children) == 0 && !usedInManfiestList), nil
|
||||
}
|
||||
|
||||
// IsIntermediate returns true if the image is an intermediate image, that is
|
||||
|
@ -453,13 +463,13 @@ func (i *Image) removeRecursive(ctx context.Context, rmMap map[string]*RemoveIma
|
|||
skipRemove := false
|
||||
numNames := len(i.Names())
|
||||
|
||||
// NOTE: the `numNames == 1` check is not only a performance
|
||||
// NOTE: the `numNames != 1` check is not only a performance
|
||||
// optimization but also preserves existing Podman/Docker behaviour.
|
||||
// If image "foo" is used by a container and has only this tag/name,
|
||||
// an `rmi foo` will not untag "foo" but instead attempt to remove the
|
||||
// entire image. If there's a container using "foo", we should get an
|
||||
// error.
|
||||
if !(referencedBy == "" || numNames == 1) {
|
||||
if referencedBy != "" && numNames != 1 {
|
||||
byID := strings.HasPrefix(i.ID(), referencedBy)
|
||||
byDigest := strings.HasPrefix(referencedBy, "sha256:")
|
||||
if !options.Force {
|
||||
|
@ -788,27 +798,25 @@ func (i *Image) Mount(_ context.Context, mountOptions []string, mountLabel strin
|
|||
// Mountpoint returns the path to image's mount point. The path is empty if
|
||||
// the image is not mounted.
|
||||
func (i *Image) Mountpoint() (string, error) {
|
||||
mountedTimes, err := i.runtime.store.Mounted(i.TopLayer())
|
||||
if err != nil || mountedTimes == 0 {
|
||||
if errors.Is(err, storage.ErrLayerUnknown) {
|
||||
// Can happen, Podman did it, but there's no
|
||||
// explanation why.
|
||||
err = nil
|
||||
for _, layerID := range append([]string{i.TopLayer()}, i.storageImage.MappedTopLayers...) {
|
||||
mountedTimes, err := i.runtime.store.Mounted(layerID)
|
||||
if err != nil {
|
||||
if errors.Is(err, storage.ErrLayerUnknown) {
|
||||
// Can happen, Podman did it, but there's no
|
||||
// explanation why.
|
||||
continue
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
if mountedTimes > 0 {
|
||||
layer, err := i.runtime.store.Layer(layerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.EvalSymlinks(layer.MountPoint)
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
layer, err := i.runtime.store.Layer(i.TopLayer())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
mountPoint, err := filepath.EvalSymlinks(layer.MountPoint)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return mountPoint, nil
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Unmount the image. Use force to ignore the reference counter and forcefully
|
||||
|
@ -1002,7 +1010,7 @@ func (i *Image) Manifest(ctx context.Context) (rawManifest []byte, mimeType stri
|
|||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return src.GetManifest(ctx, nil)
|
||||
return image.UnparsedInstance(src, nil).Manifest(ctx)
|
||||
}
|
||||
|
||||
// getImageID creates an image object and uses the hex value of the config
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package libimage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
// Tree generates a tree for the specified image and its layers. Use
|
||||
// `traverseChildren` to traverse the layers of all children. By default, only
|
||||
// layers of the image are printed.
|
||||
func (i *Image) Tree(traverseChildren bool) (string, error) {
|
||||
func (i *Image) Tree(ctx context.Context, traverseChildren bool) (string, error) {
|
||||
// NOTE: a string builder prevents us from copying to much data around
|
||||
// and compile the string when and where needed.
|
||||
sb := &strings.Builder{}
|
||||
|
|
|
@ -104,7 +104,7 @@ func (r *Runtime) Import(ctx context.Context, path string, options *ImportOption
|
|||
return "", err
|
||||
}
|
||||
|
||||
c, err := r.newCopier(&options.CopyOptions, nil)
|
||||
c, err := r.newCopier(&options.CopyOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -159,7 +160,7 @@ func (i *Image) Inspect(ctx context.Context, options *InspectOptions) (*ImageDat
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
manifestRaw, manifestType, err := src.GetManifest(ctx, nil)
|
||||
manifestRaw, manifestType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/containers/storage"
|
||||
storageTypes "github.com/containers/storage/types"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -22,6 +23,10 @@ type layerTree struct {
|
|||
// emptyImages do not have any top-layer so we cannot create a
|
||||
// *layerNode for them.
|
||||
emptyImages []*Image
|
||||
// manifestList keep track of images based on their digest.
|
||||
// Library will use this map when checking if a image is dangling.
|
||||
// If an image is used in a manifestList it is NOT dangling
|
||||
manifestListDigests map[digest.Digest]struct{}
|
||||
}
|
||||
|
||||
// node returns a layerNode for the specified layerID.
|
||||
|
@ -95,15 +100,16 @@ func (r *Runtime) newFreshLayerTree() (*layerTree, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.newLayerTreeFromData(images, layers)
|
||||
return r.newLayerTreeFromData(images, layers, false)
|
||||
}
|
||||
|
||||
// newLayerTreeFromData extracts a layerTree from the given the layers and images.
|
||||
// The caller is responsible for (layers, images) being consistent.
|
||||
func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer) (*layerTree, error) {
|
||||
func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer, generateManifestDigestList bool) (*layerTree, error) {
|
||||
tree := layerTree{
|
||||
nodes: make(map[string]*layerNode),
|
||||
ociCache: make(map[string]*ociv1.Image),
|
||||
nodes: make(map[string]*layerNode),
|
||||
ociCache: make(map[string]*ociv1.Image),
|
||||
manifestListDigests: make(map[digest.Digest]struct{}),
|
||||
}
|
||||
|
||||
// First build a tree purely based on layer information.
|
||||
|
@ -124,6 +130,30 @@ func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer)
|
|||
topLayer := img.TopLayer()
|
||||
if topLayer == "" {
|
||||
tree.emptyImages = append(tree.emptyImages, img)
|
||||
// When img is a manifest list, cache the lists of
|
||||
// digests refereenced in manifest list. Digests can
|
||||
// be used to check for dangling images.
|
||||
if !generateManifestDigestList {
|
||||
continue
|
||||
}
|
||||
// ignore errors, common errors are
|
||||
// - image is not manifest
|
||||
// - image has been removed from the store in the meantime
|
||||
// In all cases we should ensure image listing still works and not error out.
|
||||
mlist, err := img.ToManifestList()
|
||||
if err != nil {
|
||||
// If it is not a manifest it likely is a regular image so just ignore it.
|
||||
// If the image is unknown that likely means there was a race where the image/manifest
|
||||
// was removed after out MultiList() call so we ignore that as well.
|
||||
if errors.Is(err, ErrNotAManifestList) || errors.Is(err, storageTypes.ErrImageUnknown) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, digest := range mlist.list.Instances() {
|
||||
tree.manifestListDigests[digest] = struct{}{}
|
||||
}
|
||||
continue
|
||||
}
|
||||
node, exists := tree.nodes[topLayer]
|
||||
|
@ -141,19 +171,6 @@ func (r *Runtime) newLayerTreeFromData(images []*Image, layers []storage.Layer)
|
|||
return &tree, nil
|
||||
}
|
||||
|
||||
// layersOf returns all storage layers of the specified image.
|
||||
func (t *layerTree) layersOf(image *Image) []*storage.Layer {
|
||||
var layers []*storage.Layer
|
||||
node := t.node(image.TopLayer())
|
||||
for node != nil {
|
||||
if node.layer != nil {
|
||||
layers = append(layers, node.layer)
|
||||
}
|
||||
node = node.parent
|
||||
}
|
||||
return layers
|
||||
}
|
||||
|
||||
// children returns the child images of parent. Child images are images with
|
||||
// either the same top layer as parent or parent being the true parent layer.
|
||||
// Furthermore, the history of the parent and child images must match with the
|
||||
|
|
|
@ -30,7 +30,7 @@ func (r *Runtime) doLoadReference(ctx context.Context, ref types.ImageReference,
|
|||
case dockerArchiveTransport.Transport.Name():
|
||||
images, err = r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions)
|
||||
default:
|
||||
images, err = r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
||||
_, images, err = r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
||||
}
|
||||
return images, ref.Transport().Name(), err
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ func (r *Runtime) LoadReference(ctx context.Context, ref types.ImageReference, o
|
|||
// Load loads one or more images (depending on the transport) from the
|
||||
// specified path. The path may point to an image the following transports:
|
||||
// oci, oci-archive, dir, docker-archive.
|
||||
//
|
||||
// Load returns a string slice with names of recently loaded images.
|
||||
// If images are unnamed in the source, it returns a string slice of image IDs instead.
|
||||
func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ([]string, error) {
|
||||
logrus.Debugf("Loading image from %q", path)
|
||||
|
||||
|
@ -112,7 +115,7 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) (
|
|||
|
||||
// Give a decent error message if nothing above worked.
|
||||
// we want the colon here for the multiline error
|
||||
//nolint:revive
|
||||
//nolint:revive,staticcheck
|
||||
loadError := errors.New("payload does not match any of the supported image formats:")
|
||||
for _, err := range loadErrors {
|
||||
loadError = fmt.Errorf("%v\n * %v", loadError, err)
|
||||
|
@ -142,7 +145,8 @@ func (r *Runtime) loadMultiImageDockerArchive(ctx context.Context, ref types.Ima
|
|||
// should.
|
||||
path := ref.StringWithinTransport()
|
||||
if err := fileutils.Exists(path); err != nil {
|
||||
return r.copyFromDockerArchive(ctx, ref, options)
|
||||
_, names, err := r.copyFromDockerArchive(ctx, ref, options)
|
||||
return names, err
|
||||
}
|
||||
|
||||
reader, err := dockerArchiveTransport.NewReader(r.systemContextCopy(), path)
|
||||
|
@ -163,7 +167,7 @@ func (r *Runtime) loadMultiImageDockerArchive(ctx context.Context, ref types.Ima
|
|||
var copiedImages []string
|
||||
for _, list := range refLists {
|
||||
for _, listRef := range list {
|
||||
names, err := r.copyFromDockerArchiveReaderReference(ctx, reader, listRef, options)
|
||||
_, names, err := r.copyFromDockerArchiveReaderReference(ctx, reader, listRef, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/containers/common/pkg/supplemented"
|
||||
imageCopy "github.com/containers/image/v5/copy"
|
||||
"github.com/containers/image/v5/docker"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/oci/layout"
|
||||
"github.com/containers/image/v5/signature"
|
||||
|
@ -370,11 +371,12 @@ func (i *Image) IsManifestList(ctx context.Context) (bool, error) {
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
imgRef, err := ref.NewImageSource(ctx, i.runtime.systemContextCopy())
|
||||
imgSrc, err := ref.NewImageSource(ctx, i.runtime.systemContextCopy())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, manifestType, err := imgRef.GetManifest(ctx, nil)
|
||||
defer imgSrc.Close()
|
||||
_, manifestType, err := image.UnparsedInstance(imgSrc, nil).Manifest(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -717,7 +719,7 @@ func (m *ManifestList) AnnotateInstance(d digest.Digest, options *ManifestListAn
|
|||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
subjectManifestBytes, subjectManifestType, err := src.GetManifest(ctx, nil)
|
||||
subjectManifestBytes, subjectManifestType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -792,7 +794,7 @@ func (m *ManifestList) Push(ctx context.Context, destination string, options *Ma
|
|||
// NOTE: we're using the logic in copier to create a proper
|
||||
// types.SystemContext. This prevents us from having an error prone
|
||||
// code duplicate here.
|
||||
copier, err := m.image.runtime.newCopier(&options.CopyOptions, nil)
|
||||
copier, err := m.image.runtime.newCopier(&options.CopyOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ func LoadFromImage(store storage.Store, image string) (string, List, error) {
|
|||
}
|
||||
manifestList, err := manifests.FromBlob(manifestBytes)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
return "", nil, fmt.Errorf("decoding manifest blob for image %q: %w", image, err)
|
||||
}
|
||||
list := &list{
|
||||
List: manifestList,
|
||||
|
@ -526,7 +526,7 @@ func (l *list) Add(ctx context.Context, sys *types.SystemContext, ref types.Imag
|
|||
var instanceInfos []instanceInfo
|
||||
var manifestDigest digest.Digest
|
||||
|
||||
primaryManifestBytes, primaryManifestType, err := src.GetManifest(ctx, nil)
|
||||
primaryManifestBytes, primaryManifestType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading manifest from %q: %w", transports.ImageName(ref), err)
|
||||
}
|
||||
|
@ -613,7 +613,8 @@ func (l *list) Add(ctx context.Context, sys *types.SystemContext, ref types.Imag
|
|||
|
||||
knownConfigTypes := []string{manifest.DockerV2Schema2ConfigMediaType, v1.MediaTypeImageConfig}
|
||||
for _, instanceInfo := range instanceInfos {
|
||||
manifestBytes, manifestType, err := src.GetManifest(ctx, instanceInfo.instanceDigest)
|
||||
unparsedInstance := image.UnparsedInstance(src, instanceInfo.instanceDigest)
|
||||
manifestBytes, manifestType, err := unparsedInstance.Manifest(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading manifest from %q, instance %q: %w", transports.ImageName(ref), instanceInfo.instanceDigest, err)
|
||||
}
|
||||
|
@ -625,7 +626,7 @@ func (l *list) Add(ctx context.Context, sys *types.SystemContext, ref types.Imag
|
|||
hasPlatformConfig := instanceInfo.ArtifactType == "" && slices.Contains(knownConfigTypes, instanceInfo.ConfigInfo.MediaType)
|
||||
needToParsePlatformConfig := (instanceInfo.OS == "" || instanceInfo.Architecture == "")
|
||||
if hasPlatformConfig && needToParsePlatformConfig {
|
||||
img, err := image.FromUnparsedImage(ctx, sys, image.UnparsedInstance(src, instanceInfo.instanceDigest))
|
||||
img, err := image.FromUnparsedImage(ctx, sys, unparsedInstance)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading configuration blob from %q: %w", transports.ImageName(ref), err)
|
||||
}
|
||||
|
@ -712,12 +713,12 @@ func (l *list) AddArtifact(ctx context.Context, sys *types.SystemContext, option
|
|||
// reason.
|
||||
var subject *v1.Descriptor
|
||||
if options.SubjectReference != nil {
|
||||
subjectReference, err := options.SubjectReference.NewImageSource(ctx, sys)
|
||||
subjectSource, err := options.SubjectReference.NewImageSource(ctx, sys)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("setting up to read manifest and configuration from subject %q: %w", transports.ImageName(options.SubjectReference), err)
|
||||
}
|
||||
defer subjectReference.Close()
|
||||
subjectManifestBytes, subjectManifestType, err := subjectReference.GetManifest(ctx, nil)
|
||||
defer subjectSource.Close()
|
||||
subjectManifestBytes, subjectManifestType, err := image.UnparsedInstance(subjectSource, nil).Manifest(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("reading manifest from subject %q: %w", transports.ImageName(options.SubjectReference), err)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func NormalizeName(name string) (reference.Named, error) {
|
|||
|
||||
// Enforce "localhost" if needed.
|
||||
registry := reference.Domain(named)
|
||||
if !(strings.ContainsAny(registry, ".:") || registry == "localhost") {
|
||||
if !strings.ContainsAny(registry, ".:") && registry != "localhost" {
|
||||
name = toLocalImageName(ref.String())
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
ociTransport "github.com/containers/image/v5/oci/layout"
|
||||
"github.com/containers/image/v5/pkg/shortnames"
|
||||
storageTransport "github.com/containers/image/v5/storage"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/transports/alltransports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/storage"
|
||||
|
@ -52,6 +51,10 @@ type PullOptions struct {
|
|||
// The error is storage.ErrImageUnknown iff the pull policy is set to "never"
|
||||
// and no local image has been found. This allows for an easier integration
|
||||
// into some users of this package (e.g., Buildah).
|
||||
//
|
||||
// Pull returns a slice of the pulled images.
|
||||
//
|
||||
// WARNING: the Digest field of the returned image might not be a value relevant to the user issuing the pull.
|
||||
func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullPolicy, options *PullOptions) (_ []*Image, pullError error) {
|
||||
logrus.Debugf("Pulling image %s (policy: %s)", name, pullPolicy)
|
||||
if r.eventChannel != nil {
|
||||
|
@ -156,7 +159,7 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
|
|||
options.Variant = r.systemContext.VariantChoice
|
||||
}
|
||||
|
||||
var pulledImages []string
|
||||
var pulledImages []*Image
|
||||
|
||||
// Dispatch the copy operation.
|
||||
switch ref.Transport().Name() {
|
||||
|
@ -166,24 +169,18 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
|
|||
|
||||
// DOCKER ARCHIVE
|
||||
case dockerArchiveTransport.Transport.Name():
|
||||
pulledImages, err = r.copyFromDockerArchive(ctx, ref, &options.CopyOptions)
|
||||
pulledImages, _, err = r.copyFromDockerArchive(ctx, ref, &options.CopyOptions)
|
||||
|
||||
// ALL OTHER TRANSPORTS
|
||||
default:
|
||||
pulledImages, err = r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
||||
pulledImages, _, err = r.copyFromDefault(ctx, ref, &options.CopyOptions)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localImages := []*Image{}
|
||||
for _, iName := range pulledImages {
|
||||
image, _, err := r.LookupImage(iName, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("locating pulled image %q name in containers storage: %w", iName, err)
|
||||
}
|
||||
|
||||
for _, image := range pulledImages {
|
||||
// Note that we can ignore the 2nd return value here. Some
|
||||
// images may ship with "wrong" platform, but we already warn
|
||||
// about it. Throwing an error is not (yet) the plan.
|
||||
|
@ -206,11 +203,9 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
|
|||
// Note that we use the input name here to preserve the transport data.
|
||||
r.writeEvent(&Event{ID: image.ID(), Name: name, Time: time.Now(), Type: EventTypeImagePull})
|
||||
}
|
||||
|
||||
localImages = append(localImages, image)
|
||||
}
|
||||
|
||||
return localImages, pullError
|
||||
return pulledImages, pullError
|
||||
}
|
||||
|
||||
// nameFromAnnotations returns a reference string to be used as an image name,
|
||||
|
@ -229,10 +224,10 @@ func nameFromAnnotations(annotations map[string]string) string {
|
|||
|
||||
// copyFromDefault is the default copier for a number of transports. Other
|
||||
// transports require some specific dancing, sometimes Yoga.
|
||||
func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
|
||||
c, err := r.newCopier(options, nil)
|
||||
func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]*Image, []string, error) {
|
||||
c, err := r.newCopier(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
|
@ -243,7 +238,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
// Normalize to docker.io if needed (see containers/podman/issues/10998).
|
||||
named, err := reference.ParseNormalizedNamed(strings.TrimLeft(ref.StringWithinTransport(), ":/"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
imageName = named.String()
|
||||
storageName = imageName
|
||||
|
@ -252,7 +247,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
// Normalize to docker.io if needed (see containers/podman/issues/10998).
|
||||
named, err := reference.ParseNormalizedNamed(ref.StringWithinTransport())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
imageName = named.String()
|
||||
storageName = imageName
|
||||
|
@ -264,7 +259,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
// the path to a directory as the name.
|
||||
storageName, err = getImageID(ctx, ref, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
imageName = "sha256:" + storageName[1:]
|
||||
} else { // If the OCI-reference includes an image reference, use it
|
||||
|
@ -275,7 +270,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
case ociArchiveTransport.Transport.Name():
|
||||
manifestDescriptor, err := ociArchiveTransport.LoadManifestDescriptorWithContext(r.SystemContext(), ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
storageName = nameFromAnnotations(manifestDescriptor.Annotations)
|
||||
switch len(storageName) {
|
||||
|
@ -283,13 +278,13 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
// If there's no reference name in the annotations, compute an ID.
|
||||
storageName, err = getImageID(ctx, ref, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
imageName = "sha256:" + storageName[1:]
|
||||
default:
|
||||
named, err := NormalizeName(storageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
imageName = named.String()
|
||||
storageName = imageName
|
||||
|
@ -299,7 +294,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
storageName = ref.StringWithinTransport()
|
||||
named := ref.DockerReference()
|
||||
if named == nil {
|
||||
return nil, fmt.Errorf("could not get an image name for storage reference %q", ref)
|
||||
return nil, nil, fmt.Errorf("could not get an image name for storage reference %q", ref)
|
||||
}
|
||||
imageName = named.String()
|
||||
|
||||
|
@ -309,7 +304,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
// instead of looking at the StringWithinTransport().
|
||||
storageName, err = getImageID(ctx, ref, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
imageName = "sha256:" + storageName[1:]
|
||||
}
|
||||
|
@ -317,11 +312,14 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
|
|||
// Create a storage reference.
|
||||
destRef, err := storageTransport.Transport.ParseStoreReference(r.store, storageName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %q: %w", storageName, err)
|
||||
return nil, nil, fmt.Errorf("parsing %q: %w", storageName, err)
|
||||
}
|
||||
|
||||
_, err = c.Copy(ctx, ref, destRef)
|
||||
return []string{imageName}, err
|
||||
image, err := c.copyToStorage(ctx, ref, destRef)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to perform copy: %w", err)
|
||||
}
|
||||
resolvedImage := r.storageToImage(image, nil)
|
||||
return []*Image{resolvedImage}, []string{imageName}, err
|
||||
}
|
||||
|
||||
// storageReferencesFromArchiveReader returns a slice of image references inside the
|
||||
|
@ -368,12 +366,12 @@ func (r *Runtime) storageReferencesReferencesFromArchiveReader(ctx context.Conte
|
|||
}
|
||||
|
||||
// copyFromDockerArchive copies one image from the specified reference.
|
||||
func (r *Runtime) copyFromDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) {
|
||||
func (r *Runtime) copyFromDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]*Image, []string, error) {
|
||||
// There may be more than one image inside the docker archive, so we
|
||||
// need a quick glimpse inside.
|
||||
reader, readerRef, err := dockerArchiveTransport.NewReaderForReference(&r.systemContext, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err := reader.Close(); err != nil {
|
||||
|
@ -385,35 +383,38 @@ func (r *Runtime) copyFromDockerArchive(ctx context.Context, ref types.ImageRefe
|
|||
}
|
||||
|
||||
// copyFromDockerArchiveReaderReference copies the specified readerRef from reader.
|
||||
func (r *Runtime) copyFromDockerArchiveReaderReference(ctx context.Context, reader *dockerArchiveTransport.Reader, readerRef types.ImageReference, options *CopyOptions) ([]string, error) {
|
||||
c, err := r.newCopier(options, nil)
|
||||
func (r *Runtime) copyFromDockerArchiveReaderReference(ctx context.Context, reader *dockerArchiveTransport.Reader, readerRef types.ImageReference, options *CopyOptions) ([]*Image, []string, error) {
|
||||
c, err := r.newCopier(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
// Get a slice of storage references we can copy.
|
||||
references, destNames, err := r.storageReferencesReferencesFromArchiveReader(ctx, readerRef, reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
images := []*Image{}
|
||||
// Now copy all of the images. Use readerRef for performance.
|
||||
for _, destRef := range references {
|
||||
if _, err := c.Copy(ctx, readerRef, destRef); err != nil {
|
||||
return nil, err
|
||||
image, err := c.copyToStorage(ctx, readerRef, destRef)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resolvedImage := r.storageToImage(image, nil)
|
||||
images = append(images, resolvedImage)
|
||||
}
|
||||
|
||||
return destNames, nil
|
||||
return images, destNames, nil
|
||||
}
|
||||
|
||||
// copyFromRegistry pulls the specified, possibly unqualified, name from a
|
||||
// registry. On successful pull it returns the ID of the image in local
|
||||
// storage.
|
||||
// registry. On successful pull it returns slice of the pulled images.
|
||||
//
|
||||
// If options.All is set, all tags from the specified registry will be pulled.
|
||||
func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference, inputName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) {
|
||||
func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference, inputName string, pullPolicy config.PullPolicy, options *PullOptions) ([]*Image, error) {
|
||||
// Sanity check.
|
||||
if err := pullPolicy.Validate(); err != nil {
|
||||
return nil, err
|
||||
|
@ -424,7 +425,7 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []string{pulled}, nil
|
||||
return []*Image{pulled}, nil
|
||||
}
|
||||
|
||||
// Copy all tags
|
||||
|
@ -434,7 +435,7 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pulledIDs := []string{}
|
||||
pulledImages := []*Image{}
|
||||
for _, tag := range tags {
|
||||
select { // Let's be gentle with Podman remote.
|
||||
case <-ctx.Done():
|
||||
|
@ -450,19 +451,18 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pulledIDs = append(pulledIDs, pulled)
|
||||
pulledImages = append(pulledImages, pulled)
|
||||
}
|
||||
|
||||
return pulledIDs, nil
|
||||
return pulledImages, nil
|
||||
}
|
||||
|
||||
// copySingleImageFromRegistry pulls the specified, possibly unqualified, name
|
||||
// from a registry. On successful pull it returns the ID of the image in local
|
||||
// storage (or, FIXME, a name/ID? that could be resolved in local storage)
|
||||
func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy config.PullPolicy, options *PullOptions) (string, error) { //nolint:gocyclo
|
||||
// from a registry. On successful pull it returns the Image from the local storage.
|
||||
func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy config.PullPolicy, options *PullOptions) (*Image, error) { //nolint:gocyclo
|
||||
// Sanity check.
|
||||
if err := pullPolicy.Validate(); err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -487,14 +487,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
if options.OS != runtime.GOOS {
|
||||
lookupImageOptions.OS = options.OS
|
||||
}
|
||||
// FIXME: We sometimes return resolvedImageName from this function.
|
||||
// The function documentation says this returns an image ID, resolvedImageName is frequently not an image ID.
|
||||
//
|
||||
// Ultimately Runtime.Pull looks up the returned name... again, possibly finding some other match
|
||||
// than we did.
|
||||
//
|
||||
// This should be restructured so that the image we found here is returned to the caller of Pull
|
||||
// directly, without another image -> name -> image round-trip and possible inconsistency.
|
||||
|
||||
localImage, resolvedImageName, err = r.LookupImage(imageName, lookupImageOptions)
|
||||
if err != nil && !errors.Is(err, storage.ErrImageUnknown) {
|
||||
logrus.Errorf("Looking up %s in local storage: %v", imageName, err)
|
||||
|
@ -525,23 +518,23 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
if pullPolicy == config.PullPolicyNever {
|
||||
if localImage != nil {
|
||||
logrus.Debugf("Pull policy %q and %s resolved to local image %s", pullPolicy, imageName, resolvedImageName)
|
||||
return resolvedImageName, nil
|
||||
return localImage, nil
|
||||
}
|
||||
logrus.Debugf("Pull policy %q but no local image has been found for %s", pullPolicy, imageName)
|
||||
return "", fmt.Errorf("%s: %w", imageName, storage.ErrImageUnknown)
|
||||
return nil, fmt.Errorf("%s: %w", imageName, storage.ErrImageUnknown)
|
||||
}
|
||||
|
||||
if pullPolicy == config.PullPolicyMissing && localImage != nil {
|
||||
return resolvedImageName, nil
|
||||
return localImage, nil
|
||||
}
|
||||
|
||||
// If we looked up the image by ID, we cannot really pull from anywhere.
|
||||
if localImage != nil && strings.HasPrefix(localImage.ID(), imageName) {
|
||||
switch pullPolicy {
|
||||
case config.PullPolicyAlways:
|
||||
return "", fmt.Errorf("pull policy is always but image has been referred to by ID (%s)", imageName)
|
||||
return nil, fmt.Errorf("pull policy is always but image has been referred to by ID (%s)", imageName)
|
||||
default:
|
||||
return resolvedImageName, nil
|
||||
return localImage, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -566,9 +559,9 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
resolved, err := shortnames.Resolve(sys, imageName)
|
||||
if err != nil {
|
||||
if localImage != nil && pullPolicy == config.PullPolicyNewer {
|
||||
return resolvedImageName, nil
|
||||
return localImage, nil
|
||||
}
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NOTE: Below we print the description from the short-name resolution.
|
||||
|
@ -598,10 +591,9 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
if socketPath, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
|
||||
options.extendTimeoutSocket = socketPath
|
||||
}
|
||||
var resolvedReference types.ImageReference
|
||||
c, err := r.newCopier(&options.CopyOptions, &resolvedReference)
|
||||
c, err := r.newCopier(&options.CopyOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
|
@ -611,7 +603,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
logrus.Debugf("Attempting to pull candidate %s for %s", candidateString, imageName)
|
||||
srcRef, err := registryTransport.NewReference(candidate.Value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pullPolicy == config.PullPolicyNewer && localImage != nil {
|
||||
|
@ -629,18 +621,19 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
|
||||
destRef, err := storageTransport.Transport.ParseStoreReference(r.store, candidate.Value.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := writeDesc(); err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if options.Writer != nil {
|
||||
if _, err := io.WriteString(options.Writer, fmt.Sprintf("Trying to pull %s...\n", candidateString)); err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if _, err := c.Copy(ctx, srcRef, destRef); err != nil {
|
||||
image, err := c.copyToStorage(ctx, srcRef, destRef)
|
||||
if err != nil {
|
||||
logrus.Debugf("Error pulling candidate %s: %v", candidateString, err)
|
||||
pullErrors = append(pullErrors, err)
|
||||
continue
|
||||
|
@ -651,25 +644,18 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str
|
|||
// read-only which can cause issues.
|
||||
logrus.Errorf("Error recording short-name alias %q: %v", candidateString, err)
|
||||
}
|
||||
|
||||
logrus.Debugf("Pulled candidate %s successfully", candidateString)
|
||||
if resolvedReference == nil { // resolvedReference should always be set for storageTransport destinations
|
||||
return "", fmt.Errorf("internal error: After pulling %s, resolvedReference is nil", candidateString)
|
||||
}
|
||||
_, image, err := storageTransport.ResolveReference(resolvedReference)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("resolving an already-resolved reference %q to the pulled image: %w", transports.ImageName(resolvedReference), err)
|
||||
}
|
||||
return image.ID, nil
|
||||
resolvedImage := r.storageToImage(image, nil)
|
||||
return resolvedImage, err
|
||||
}
|
||||
|
||||
if localImage != nil && pullPolicy == config.PullPolicyNewer {
|
||||
return resolvedImageName, nil
|
||||
return localImage, nil
|
||||
}
|
||||
|
||||
if len(pullErrors) == 0 {
|
||||
return "", fmt.Errorf("internal error: no image pulled (pull policy %s)", pullPolicy)
|
||||
return nil, fmt.Errorf("internal error: no image pulled (pull policy %s)", pullPolicy)
|
||||
}
|
||||
|
||||
return "", resolved.FormatPullErrors(pullErrors)
|
||||
return nil, resolved.FormatPullErrors(pullErrors)
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ func (r *Runtime) Push(ctx context.Context, source, destination string, options
|
|||
}
|
||||
}
|
||||
|
||||
c, err := r.newCopier(&options.CopyOptions, nil)
|
||||
c, err := r.newCopier(&options.CopyOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -634,7 +634,7 @@ func (r *Runtime) ListImages(ctx context.Context, options *ListImagesOptions) ([
|
|||
|
||||
var tree *layerTree
|
||||
if needsLayerTree {
|
||||
tree, err = r.newLayerTreeFromData(images, snapshot.Layers)
|
||||
tree, err = r.newLayerTreeFromData(images, snapshot.Layers, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ func (r *Runtime) saveSingleImage(ctx context.Context, name, format, path string
|
|||
return err
|
||||
}
|
||||
|
||||
c, err := r.newCopier(&options.CopyOptions, nil)
|
||||
c, err := r.newCopier(&options.CopyOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ func (r *Runtime) saveDockerArchive(ctx context.Context, names []string, path st
|
|||
copyOpts := options.CopyOptions
|
||||
copyOpts.dockerArchiveAdditionalTags = local.tags
|
||||
|
||||
c, err := r.newCopier(©Opts, nil)
|
||||
c, err := r.newCopier(©Opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry stri
|
|||
paramsArr := []SearchResult{}
|
||||
for i := range limit {
|
||||
// Check whether query matches filters
|
||||
if !(filterMatchesAutomatedFilter(&options.Filter, results[i]) && filterMatchesOfficialFilter(&options.Filter, results[i]) && filterMatchesStarFilter(&options.Filter, results[i])) {
|
||||
if !filterMatchesAutomatedFilter(&options.Filter, results[i]) || !filterMatchesOfficialFilter(&options.Filter, results[i]) || !filterMatchesStarFilter(&options.Filter, results[i]) {
|
||||
continue
|
||||
}
|
||||
official := ""
|
||||
|
|
|
@ -24,10 +24,15 @@ var (
|
|||
// NameRegex is a regular expression to validate names.
|
||||
// This must NOT be changed.
|
||||
NameRegex = regexp.Delayed("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
|
||||
// RegexError is thrown in presence of an invalid name.
|
||||
RegexError = fmt.Errorf("names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: %w", ErrInvalidArg) // nolint:revive // This lint is new and we do not want to break the API.
|
||||
// ErrInvalidName is thrown in presence of an invalid name.
|
||||
ErrInvalidName = fmt.Errorf("names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: %w", ErrInvalidArg)
|
||||
// Deprecated: use [ErrInvalidName] instead.
|
||||
RegexError = ErrInvalidName
|
||||
|
||||
// NotHexRegex is a regular expression to check if a string is
|
||||
// a hexadecimal string.
|
||||
NotHexRegex = regexp.Delayed(`[^0-9a-fA-F]`)
|
||||
|
||||
// MaxInterfaceNameLength is the maximum length of a network interface name
|
||||
MaxInterfaceNameLength = 15
|
||||
)
|
||||
|
|
|
@ -24,7 +24,7 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) {
|
|||
# Allow certain signals from OCI runtimes (podman, runc and crun)
|
||||
signal (receive) peer={/usr/bin/,/usr/sbin/,}runc,
|
||||
signal (receive) peer={/usr/bin/,/usr/sbin/,}crun*,
|
||||
signal (receive) set=(int, quit, kill, term) peer={/usr/bin/,/usr/sbin/,}podman,
|
||||
signal (receive) peer={/usr/bin/,/usr/sbin/,}podman,
|
||||
{{end}}
|
||||
|
||||
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
|
||||
|
|
|
@ -11,10 +11,9 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
)
|
||||
|
||||
type linuxBlkioHandler struct {
|
||||
|
@ -26,7 +25,7 @@ func getBlkioHandler() *linuxBlkioHandler {
|
|||
}
|
||||
|
||||
// Apply set the specified constraints
|
||||
func (c *linuxBlkioHandler) Apply(ctr *CgroupControl, res *configs.Resources) error {
|
||||
func (c *linuxBlkioHandler) Apply(ctr *CgroupControl, res *cgroups.Resources) error {
|
||||
if ctr.cgroup2 {
|
||||
man, err := fs2.NewManager(ctr.config, filepath.Join(cgroupRoot, ctr.config.Path))
|
||||
if err != nil {
|
||||
|
|
|
@ -8,9 +8,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -21,11 +23,9 @@ import (
|
|||
"github.com/containers/storage/pkg/unshare"
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
|
@ -44,7 +44,7 @@ var (
|
|||
// CgroupControl controls a cgroup hierarchy
|
||||
type CgroupControl struct {
|
||||
cgroup2 bool
|
||||
config *configs.Cgroup
|
||||
config *cgroups.Cgroup
|
||||
systemd bool
|
||||
// List of additional cgroup subsystems joined that
|
||||
// do not have a custom handler.
|
||||
|
@ -58,7 +58,7 @@ type controller struct {
|
|||
|
||||
type controllerHandler interface {
|
||||
Create(*CgroupControl) (bool, error)
|
||||
Apply(*CgroupControl, *configs.Resources) error
|
||||
Apply(*CgroupControl, *cgroups.Resources) error
|
||||
Destroy(*CgroupControl) error
|
||||
Stat(*CgroupControl, *cgroups.Stats) error
|
||||
}
|
||||
|
@ -297,14 +297,14 @@ func readFileByKeyAsUint64(path, key string) (uint64, error) {
|
|||
}
|
||||
|
||||
// New creates a new cgroup control
|
||||
func New(path string, resources *configs.Resources) (*CgroupControl, error) {
|
||||
func New(path string, resources *cgroups.Resources) (*CgroupControl, error) {
|
||||
cgroup2, err := IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
control := &CgroupControl{
|
||||
cgroup2: cgroup2,
|
||||
config: &configs.Cgroup{
|
||||
config: &cgroups.Cgroup{
|
||||
Path: path,
|
||||
Resources: resources,
|
||||
},
|
||||
|
@ -326,7 +326,7 @@ func New(path string, resources *configs.Resources) (*CgroupControl, error) {
|
|||
}
|
||||
|
||||
// NewSystemd creates a new cgroup control
|
||||
func NewSystemd(path string, resources *configs.Resources) (*CgroupControl, error) {
|
||||
func NewSystemd(path string, resources *cgroups.Resources) (*CgroupControl, error) {
|
||||
cgroup2, err := IsCgroup2UnifiedMode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -334,7 +334,7 @@ func NewSystemd(path string, resources *configs.Resources) (*CgroupControl, erro
|
|||
control := &CgroupControl{
|
||||
cgroup2: cgroup2,
|
||||
systemd: true,
|
||||
config: &configs.Cgroup{
|
||||
config: &cgroups.Cgroup{
|
||||
Path: path,
|
||||
Resources: resources,
|
||||
Rootless: unshare.IsRootless(),
|
||||
|
@ -353,7 +353,7 @@ func Load(path string) (*CgroupControl, error) {
|
|||
control := &CgroupControl{
|
||||
cgroup2: cgroup2,
|
||||
systemd: false,
|
||||
config: &configs.Cgroup{
|
||||
config: &cgroups.Cgroup{
|
||||
Path: path,
|
||||
},
|
||||
}
|
||||
|
@ -485,7 +485,7 @@ func (c *CgroupControl) DeleteByPath(path string) error {
|
|||
}
|
||||
|
||||
// Update updates the cgroups
|
||||
func (c *CgroupControl) Update(resources *configs.Resources) error {
|
||||
func (c *CgroupControl) Update(resources *cgroups.Resources) error {
|
||||
for _, h := range handlers {
|
||||
if err := h.Apply(c, resources); err != nil {
|
||||
return err
|
||||
|
@ -503,7 +503,7 @@ func (c *CgroupControl) AddPid(pid int) error {
|
|||
return fs2.CreateCgroupPath(path, c.config)
|
||||
}
|
||||
|
||||
names := maps.Keys(handlers)
|
||||
names := slices.Collect(maps.Keys(handlers))
|
||||
|
||||
for _, c := range c.additionalControllers {
|
||||
if !c.symlink {
|
||||
|
@ -533,7 +533,6 @@ func (c *CgroupControl) Stat() (*cgroups.Stats, error) {
|
|||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Warningf("Failed to retrieve cgroup stats: %v", err)
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
|
@ -843,11 +842,16 @@ func UserOwnsCurrentSystemdCgroup() (bool, error) {
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
s := st.Sys()
|
||||
if s == nil {
|
||||
return false, fmt.Errorf("stat cgroup path %s", cgroupPath)
|
||||
return false, fmt.Errorf("stat cgroup path is nil %s", cgroupPath)
|
||||
}
|
||||
|
||||
//nolint:errcheck // This cast should never fail, if it does we get a interface
|
||||
// conversion panic and a stack trace on how we ended up here which is more
|
||||
// valuable than returning a human friendly error test as we don't know how it
|
||||
// happened.
|
||||
if int(s.(*syscall.Stat_t).Uid) != uid {
|
||||
return false, nil
|
||||
}
|
||||
|
|
|
@ -8,10 +8,9 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
)
|
||||
|
||||
type linuxCPUHandler struct {
|
||||
|
@ -23,7 +22,7 @@ func getCPUHandler() *linuxCPUHandler {
|
|||
}
|
||||
|
||||
// Apply set the specified constraints
|
||||
func (c *linuxCPUHandler) Apply(ctr *CgroupControl, res *configs.Resources) error {
|
||||
func (c *linuxCPUHandler) Apply(ctr *CgroupControl, res *cgroups.Resources) error {
|
||||
if ctr.cgroup2 {
|
||||
man, err := fs2.NewManager(ctr.config, filepath.Join(cgroupRoot, ctr.config.Path))
|
||||
if err != nil {
|
||||
|
|
|
@ -5,10 +5,9 @@ package cgroups
|
|||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
)
|
||||
|
||||
type linuxCpusetHandler struct {
|
||||
|
@ -20,7 +19,7 @@ func getCpusetHandler() *linuxCpusetHandler {
|
|||
}
|
||||
|
||||
// Apply set the specified constraints
|
||||
func (c *linuxCpusetHandler) Apply(ctr *CgroupControl, res *configs.Resources) error {
|
||||
func (c *linuxCpusetHandler) Apply(ctr *CgroupControl, res *cgroups.Resources) error {
|
||||
if ctr.cgroup2 {
|
||||
man, err := fs2.NewManager(ctr.config, filepath.Join(cgroupRoot, ctr.config.Path))
|
||||
if err != nil {
|
||||
|
|
|
@ -7,10 +7,9 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
)
|
||||
|
||||
type linuxMemHandler struct {
|
||||
|
@ -22,7 +21,7 @@ func getMemoryHandler() *linuxMemHandler {
|
|||
}
|
||||
|
||||
// Apply set the specified constraints
|
||||
func (c *linuxMemHandler) Apply(ctr *CgroupControl, res *configs.Resources) error {
|
||||
func (c *linuxMemHandler) Apply(ctr *CgroupControl, res *cgroups.Resources) error {
|
||||
if ctr.cgroup2 {
|
||||
man, err := fs2.NewManager(ctr.config, filepath.Join(cgroupRoot, ctr.config.Path))
|
||||
if err != nil {
|
||||
|
|
|
@ -5,10 +5,9 @@ package cgroups
|
|||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/opencontainers/cgroups/fs"
|
||||
"github.com/opencontainers/cgroups/fs2"
|
||||
)
|
||||
|
||||
type linuxPidHandler struct {
|
||||
|
@ -20,7 +19,7 @@ func getPidsHandler() *linuxPidHandler {
|
|||
}
|
||||
|
||||
// Apply set the specified constraints
|
||||
func (c *linuxPidHandler) Apply(ctr *CgroupControl, res *configs.Resources) error {
|
||||
func (c *linuxPidHandler) Apply(ctr *CgroupControl, res *cgroups.Resources) error {
|
||||
if ctr.cgroup2 {
|
||||
man, err := fs2.NewManager(ctr.config, filepath.Join(cgroupRoot, ctr.config.Path))
|
||||
if err != nil {
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
)
|
||||
|
||||
type BlkioDev struct {
|
||||
|
@ -22,7 +22,7 @@ type BlkioDev struct {
|
|||
Bytes uint64
|
||||
}
|
||||
|
||||
func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Conn) error {
|
||||
func systemdCreate(resources *cgroups.Resources, path string, c *systemdDbus.Conn) error {
|
||||
slice, name := filepath.Split(path)
|
||||
slice = strings.TrimSuffix(slice, "/")
|
||||
|
||||
|
@ -150,7 +150,7 @@ func systemdDestroyConn(path string, c *systemdDbus.Conn) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[string]string, map[string][]byte, map[string]int64, map[string][]BlkioDev, error) {
|
||||
func resourcesToProps(res *cgroups.Resources, v2 bool) (map[string]uint64, map[string]string, map[string][]byte, map[string]int64, map[string][]BlkioDev, error) {
|
||||
bMap := make(map[string][]byte)
|
||||
// this array is not used but will be once more resource limits are added
|
||||
sMap := make(map[string]string)
|
||||
|
|
|
@ -14,8 +14,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/cgroups"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
@ -122,7 +121,7 @@ func BlkioFiles(cgroupPath string) (wtFile, wtDevFile string) {
|
|||
}
|
||||
|
||||
// SetBlkioThrottle sets the throttle limits for the cgroup
|
||||
func SetBlkioThrottle(res *configs.Resources, cgroupPath string) error {
|
||||
func SetBlkioThrottle(res *cgroups.Resources, cgroupPath string) error {
|
||||
for _, td := range res.BlkioThrottleReadBpsDevice {
|
||||
if err := WriteFile(cgroupPath, "blkio.throttle.read_bps_device", fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate)); err != nil {
|
||||
return err
|
||||
|
@ -222,7 +221,7 @@ func MoveUnderCgroup(cgroup, subtree string, processes []uint32) error {
|
|||
}
|
||||
|
||||
// root cgroup, skip it
|
||||
if parts[2] == "/" && !(unifiedMode && parts[1] == "") {
|
||||
if parts[2] == "/" && (!unifiedMode || parts[1] != "") {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -262,7 +261,7 @@ func MoveUnderCgroup(cgroup, subtree string, processes []uint32) error {
|
|||
|
||||
if len(processes) > 0 {
|
||||
for _, pid := range processes {
|
||||
if _, err := f.WriteString(fmt.Sprintf("%d\n", pid)); err != nil {
|
||||
if _, err := fmt.Fprintf(f, "%d\n", pid); err != nil {
|
||||
logrus.Debugf("Cannot move process %d to cgroup %q: %v", pid, newCgroup, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
"github.com/containers/common/internal/attributedstring"
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/pkg/capabilities"
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
"github.com/containers/storage/pkg/homedir"
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
|
@ -979,24 +978,6 @@ func (c *Config) GetDefaultEnvEx(envHost, httpProxy bool) []string {
|
|||
return append(env, c.Containers.Env.Get()...)
|
||||
}
|
||||
|
||||
// Capabilities returns the capabilities parses the Add and Drop capability
|
||||
// list from the default capabilities for the container
|
||||
func (c *Config) Capabilities(user string, addCapabilities, dropCapabilities []string) ([]string, error) {
|
||||
userNotRoot := func(user string) bool {
|
||||
if user == "" || user == "root" || user == "0" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
defaultCapabilities := c.Containers.DefaultCapabilities.Get()
|
||||
if userNotRoot(user) {
|
||||
defaultCapabilities = []string{}
|
||||
}
|
||||
|
||||
return capabilities.MergeCapabilities(defaultCapabilities, addCapabilities, dropCapabilities)
|
||||
}
|
||||
|
||||
// Device parses device mapping string to a src, dest & permissions string
|
||||
// Valid values for device looklike:
|
||||
//
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/containers/common/pkg/capabilities"
|
||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
|
@ -26,3 +27,21 @@ var defaultHelperBinariesDir = []string{
|
|||
"/usr/libexec/podman",
|
||||
"/usr/lib/podman",
|
||||
}
|
||||
|
||||
// Capabilities returns the capabilities parses the Add and Drop capability
|
||||
// list from the default capabilities for the container
|
||||
func (c *Config) Capabilities(user string, addCapabilities, dropCapabilities []string) ([]string, error) {
|
||||
userNotRoot := func(user string) bool {
|
||||
if user == "" || user == "root" || user == "0" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
defaultCapabilities := c.Containers.DefaultCapabilities.Get()
|
||||
if userNotRoot(user) {
|
||||
defaultCapabilities = []string{}
|
||||
}
|
||||
|
||||
return capabilities.MergeCapabilities(defaultCapabilities, addCapabilities, dropCapabilities)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
|
@ -97,8 +97,9 @@ func (c *ContainersConfig) validateTZ() error {
|
|||
}
|
||||
|
||||
func (c *ContainersConfig) validateUmask() error {
|
||||
validUmask := regexp.MustCompile(`^[0-7]{1,4}$`)
|
||||
if !validUmask.MatchString(c.Umask) {
|
||||
// Valid values are 0 to 7777 octal.
|
||||
_, err := strconv.ParseUint(c.Umask, 8, 12)
|
||||
if err != nil {
|
||||
return fmt.Errorf("not a valid umask %s", c.Umask)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -5,3 +5,9 @@ package config
|
|||
func selinuxEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Capabilities returns the capabilities parses the Add and Drop capability
|
||||
// list from the default capabilities for the container
|
||||
func (c *Config) Capabilities(user string, addCapabilities, dropCapabilities []string) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -236,13 +236,12 @@ default_sysctls = [
|
|||
#
|
||||
#mounts = []
|
||||
|
||||
# Default way to to create a Network namespace for the container
|
||||
# Options are:
|
||||
# `private` Create private Network Namespace for the container.
|
||||
# `host` Share host Network Namespace with the container.
|
||||
# `none` Containers do not use the network
|
||||
# Default way to create a NET namespace for the container.
|
||||
# The option is mapped to the **--network** argument for the podman commands, it accepts the same values as that option.
|
||||
# For example it can be set to `bridge`, `host`, `none`, `pasta` and more, see the podman-create(1)
|
||||
# manual for all available options.
|
||||
#
|
||||
#netns = "private"
|
||||
#netns = ""
|
||||
|
||||
# Do not modify the `/etc/hosts` file in the container. Podman assumes control
|
||||
# over the container's `/etc/hosts` file by default; refer to the `--add-host`
|
||||
|
@ -381,14 +380,17 @@ default_sysctls = [
|
|||
#firewall_driver = ""
|
||||
|
||||
|
||||
# The network name of the default network to attach pods to.
|
||||
# The name of the default network as seen in `podman network ls`. This option only effects the network assignment when
|
||||
# the bridge network mode is selected, i.e. `--network bridge`. It is the default for rootful containers but not as
|
||||
# rootless. To change the default network mode use the **netns** option under the `[containers]` table.
|
||||
#
|
||||
# Note: This should not be changed while you have any containers using this network.
|
||||
#
|
||||
#default_network = "podman"
|
||||
|
||||
# The default subnet for the default network given in default_network.
|
||||
# If a network with that name does not exist, a new network using that name and
|
||||
# this subnet will be created.
|
||||
# Must be a valid IPv4 CIDR prefix.
|
||||
#
|
||||
# Note: This should not be changed if any containers are currently running on the default network.
|
||||
#
|
||||
#default_subnet = "10.88.0.0/16"
|
||||
|
||||
|
@ -897,7 +899,7 @@ default_sysctls = [
|
|||
# Linux:
|
||||
# qemu - Open source machine emulator and virtualizer. (Default)
|
||||
# Windows: there are currently two options:
|
||||
# wsl - Windows Subsystem for Linux (Default)
|
||||
# wsl - Windows Subsystem for Linux (Default)
|
||||
# hyperv - Windows Server Virtualization
|
||||
# Mac: there are currently two options:
|
||||
# applehv - Default Apple Hypervisor (Default)
|
||||
|
|
|
@ -182,13 +182,12 @@ default_sysctls = [
|
|||
#
|
||||
#log_tag = ""
|
||||
|
||||
# Default way to to create a Network namespace for the container
|
||||
# Options are:
|
||||
# `private` Create private Network Namespace for the container.
|
||||
# `host` Share host Network Namespace with the container.
|
||||
# `none` Containers do not use the network
|
||||
# Default way to create a NET namespace for the container.
|
||||
# The option is mapped to the **--network** argument for the podman commands, it accepts the same values as that option.
|
||||
# For example it can be set to `bridge`, `host`, `none`, `pasta` and more, see the podman-create(1)
|
||||
# manual for all available options.
|
||||
#
|
||||
#netns = "private"
|
||||
#netns = ""
|
||||
|
||||
# Create /etc/hosts for the container. By default, container engine manage
|
||||
# /etc/hosts, automatically adding the container's own IP address.
|
||||
|
@ -292,14 +291,17 @@ default_sysctls = [
|
|||
# "/usr/lib/netavark",
|
||||
#]
|
||||
|
||||
# The network name of the default network to attach pods to.
|
||||
# The name of the default network as seen in `podman network ls`. This option only effects the network assignment when
|
||||
# the bridge network mode is selected, i.e. `--network bridge`. It is the default for rootful containers but not as
|
||||
# rootless. To change the default network mode use the **netns** option under the `[containers]` table.
|
||||
#
|
||||
# Note: This should not be changed while you have any containers using this network.
|
||||
#
|
||||
#default_network = "podman"
|
||||
|
||||
# The default subnet for the default network given in default_network.
|
||||
# If a network with that name does not exist, a new network using that name and
|
||||
# this subnet will be created.
|
||||
# Must be a valid IPv4 CIDR prefix.
|
||||
#
|
||||
# Note: This should not be changed if any containers are currently running on the default network.
|
||||
#
|
||||
#default_subnet = "10.88.0.0/16"
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containers/common/internal/attributedstring"
|
||||
nettypes "github.com/containers/common/libnetwork/types"
|
||||
|
@ -36,8 +37,8 @@ const (
|
|||
defaultInitName = "catatonit"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultMaskedPaths = []string{
|
||||
func getMaskedPaths() ([]string, error) {
|
||||
maskedPaths := []string{
|
||||
"/proc/acpi",
|
||||
"/proc/kcore",
|
||||
"/proc/keys",
|
||||
|
@ -49,8 +50,34 @@ var (
|
|||
"/sys/devices/virtual/powercap",
|
||||
"/sys/firmware",
|
||||
"/sys/fs/selinux",
|
||||
"/proc/interrupts",
|
||||
}
|
||||
maskedPathsToGlob := []string{
|
||||
"/sys/devices/system/cpu/cpu*/thermal_throttle",
|
||||
}
|
||||
|
||||
for _, p := range maskedPathsToGlob {
|
||||
matches, err := filepath.Glob(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
maskedPaths = append(maskedPaths, matches...)
|
||||
}
|
||||
return maskedPaths, nil
|
||||
}
|
||||
|
||||
var DefaultMaskedPaths = sync.OnceValue(func() []string {
|
||||
maskedPaths, err := getMaskedPaths()
|
||||
// this should never happen, the only error possible
|
||||
// is ErrBadPattern and the patterns that were added must be valid
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return maskedPaths
|
||||
})
|
||||
|
||||
var (
|
||||
DefaultReadOnlyPaths = []string{
|
||||
"/proc/asound",
|
||||
"/proc/bus",
|
||||
|
@ -539,7 +566,7 @@ func (c *Config) NetNS() string {
|
|||
return c.Containers.NetNS
|
||||
}
|
||||
|
||||
func (c EngineConfig) EventsLogMaxSize() uint64 {
|
||||
func (c *EngineConfig) EventsLogMaxSize() uint64 {
|
||||
return uint64(c.EventsLogFileMaxSize)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ func DeviceFromPath(device string) ([]devices.Device, error) {
|
|||
return nil, err
|
||||
}
|
||||
if unshare.IsRootless() && src != dst {
|
||||
return nil, fmt.Errorf("Renaming device %s to %s is not supported in rootless containers", src, dst)
|
||||
return nil, fmt.Errorf("renaming device %s to %s is not supported in rootless containers", src, dst)
|
||||
}
|
||||
srcInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
|
|
|
@ -5,10 +5,12 @@ import (
|
|||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/v5/docker"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
errcodev2 "github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
@ -47,7 +49,7 @@ func IfNecessary(ctx context.Context, operation func() error, options *Options)
|
|||
logrus.Warnf("Failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, options.MaxRetry, err)
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
break
|
||||
// Do nothing.
|
||||
case <-ctx.Done():
|
||||
return err
|
||||
}
|
||||
|
@ -81,6 +83,13 @@ func IsErrorRetryable(err error) bool {
|
|||
return false
|
||||
}
|
||||
return true
|
||||
case docker.UnexpectedHTTPStatusError:
|
||||
// Retry on 502, 502 and 503 http server errors, they appear to be quite common in the field.
|
||||
// https://github.com/containers/common/issues/2299
|
||||
if e.StatusCode >= http.StatusBadGateway && e.StatusCode <= http.StatusGatewayTimeout {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
case *net.OpError:
|
||||
return IsErrorRetryable(e.Err)
|
||||
case *url.Error: // This includes errors returned by the net/http client.
|
||||
|
|
|
@ -6,12 +6,14 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -29,7 +31,6 @@ import (
|
|||
"github.com/skeema/knownhosts"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func golangConnectionCreate(options ConnectionCreateOptions) error {
|
||||
|
@ -287,7 +288,7 @@ func ValidateAndConfigure(uri *url.URL, iden string, insecureIsMachineConnection
|
|||
dedup[fp] = s
|
||||
}
|
||||
|
||||
uniq := maps.Values(dedup)
|
||||
uniq := slices.Collect(maps.Values(dedup))
|
||||
authMethods = append(authMethods, ssh.PublicKeysCallback(func() ([]ssh.Signer, error) {
|
||||
return uniq, nil
|
||||
}))
|
||||
|
|
|
@ -205,7 +205,7 @@ func (s *supplementedImageReference) NewImageSource(ctx context.Context, sys *ty
|
|||
}
|
||||
|
||||
// Read the default manifest for the image.
|
||||
manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
|
||||
manifestBytes, manifestType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading default manifest from image %q: %w", transports.ImageName(ref), err)
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ func (s *supplementedImageReference) NewImageSource(ctx context.Context, sys *ty
|
|||
}
|
||||
|
||||
// Read the instance's manifest.
|
||||
manifestBytes, manifestType, err := manifestToRead.src.GetManifest(ctx, manifestToRead.instance)
|
||||
manifestBytes, manifestType, err := image.UnparsedInstance(manifestToRead.src, manifestToRead.instance).Manifest(ctx)
|
||||
if err != nil {
|
||||
// if errors.Is(err, storage.ErrImageUnknown) || errors.Is(err, os.ErrNotExist) {
|
||||
// Trust that we either don't need it, or that it's in another reference.
|
||||
|
|
|
@ -31,8 +31,9 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
|
|||
}
|
||||
|
||||
var format string
|
||||
// if the string has a Z or a + or three dashes use parse otherwise use parseinlocation
|
||||
parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3)
|
||||
// If the string has a Z, or a +, or three dashes,
|
||||
// then use time.Parse, otherwise use time.ParseInLocation.
|
||||
parseInLocation := !strings.ContainsAny(value, "zZ+") && strings.Count(value, "-") != 3
|
||||
|
||||
switch {
|
||||
case strings.Contains(value, "."):
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
// StringInSlice determines if a string is in a string slice, returns bool.
|
||||
//
|
||||
// Deprecated: Use [golang.org/x/exp/slices.Contains] instead.
|
||||
// Deprecated: Use [slices.Contains] instead.
|
||||
func StringInSlice(s string, sl []string) bool {
|
||||
return slices.Contains(sl, s)
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue