diff options
40 files changed, 287 insertions, 182 deletions
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go index ddc9ce246..26db5e1a4 100644 --- a/cmd/podman/machine/list.go +++ b/cmd/podman/machine/list.go @@ -177,6 +177,7 @@ func toMachineFormat(vms []*machine.ListResponse) ([]*entities.ListReporter, err response.Port = vm.Port response.RemoteUsername = vm.RemoteUsername response.IdentityPath = vm.IdentityPath + response.Starting = vm.Starting machineResponses = append(machineResponses, response) } diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go index 8534b8efa..1cadce916 100644 --- a/cmd/podman/machine/ssh.go +++ b/cmd/podman/machine/ssh.go @@ -101,7 +101,7 @@ func remoteConnectionUsername() (string, error) { if err != nil { return "", err } - dest, _, err := cfg.ActiveDestination() + dest, _, _, err := cfg.ActiveDestination() if err != nil { return "", err } diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 9e3ff48aa..5c65be96d 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -176,7 +176,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { setupConnection := func() error { var err error - cfg.URI, cfg.Identity, err = cfg.ActiveDestination() + cfg.URI, cfg.Identity, cfg.MachineMode, err = cfg.ActiveDestination() if err != nil { return fmt.Errorf("failed to resolve active destination: %w", err) } @@ -368,10 +368,13 @@ func loggingHook() { func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { cfg := opts.Config - srv, uri, ident := resolveDestination() + srv, uri, ident, machine := resolveDestination() lFlags := cmd.Flags() + // non configurable option to help ssh dialing + opts.MachineMode = machine + sshFlagName := "ssh" lFlags.StringVar(&opts.SSHMode, sshFlagName, string(ssh.GolangMode), "define the ssh mode") _ = cmd.RegisterFlagCompletionFunc(sshFlagName, common.AutocompleteSSH) @@ -513,26 +516,26 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { } } -func resolveDestination() (string, string, string) { +func resolveDestination() (string, string, string, bool) { if uri, found := os.LookupEnv("CONTAINER_HOST"); found { var ident string if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found { ident = v } - return "", uri, ident + return "", uri, ident, false } cfg, err := config.ReadCustomConfig() if err != nil { logrus.Warning(fmt.Errorf("unable to read local containers.conf: %w", err)) - return "", registry.DefaultAPIAddress(), "" + return "", registry.DefaultAPIAddress(), "", false } - uri, ident, err := cfg.ActiveDestination() + uri, ident, machine, err := cfg.ActiveDestination() if err != nil { - return "", registry.DefaultAPIAddress(), "" + return "", registry.DefaultAPIAddress(), "", false } - return cfg.Engine.ActiveService, uri, ident + return cfg.Engine.ActiveService, uri, ident, machine } func formatError(err error) string { diff --git a/cmd/podman/system/connection/list.go b/cmd/podman/system/connection/list.go index 190a68d52..3c1a42453 100644 --- a/cmd/podman/system/connection/list.go +++ b/cmd/podman/system/connection/list.go @@ -105,8 +105,9 @@ func inspect(cmd *cobra.Command, args []string) error { r := namedDestination{ Name: k, Destination: config.Destination{ - Identity: v.Identity, - URI: v.URI, + Identity: v.Identity, + URI: v.URI, + IsMachine: v.IsMachine, }, Default: def, } diff --git a/contrib/podmanremoteimage/Containerfile b/contrib/podmanremoteimage/Containerfile new file mode 100644 index 000000000..aa24b3956 --- /dev/null +++ b/contrib/podmanremoteimage/Containerfile @@ -0,0 +1,10 @@ +FROM registry.access.redhat.com/ubi8/go-toolset:latest AS builder +WORKDIR /opt/app-root/src +COPY . . +RUN make podman-remote-static +RUN GOOS=windows make podman-remote +RUN GOOS=darwin make podman-remote + +FROM scratch +COPY --from=builder /opt/app-root/src/bin . +ENTRYPOINT ["/podman-remote-static"] diff --git a/contrib/podmanremoteimage/README.md b/contrib/podmanremoteimage/README.md new file mode 100644 index 000000000..e43df9c64 --- /dev/null +++ b/contrib/podmanremoteimage/README.md @@ -0,0 +1,25 @@ +podman-remote-images +==================== + +Overview +-------- + +This directory contains the containerfile for creating a container image which consist podman-remote binary +for each platform (win/linux/mac). + +Users can copy those binaries onto the specific platforms using following instructions + +- For Windows binary +```bash +$ podman cp $(podman create --name remote-temp quay.io/containers/podman-remote-artifacts:latest):/windows/podman.exe . && podman rm remote-temp +``` + +- For Linux binary +```bash +$ podman cp $(podman create --name remote-temp quay.io/containers/podman-remote-artifacts:latest):/podman-remote-static . && podman rm remote-temp +``` + +- For Mac binary +```bash +$ podman cp $(podman create --name remote-temp quay.io/containers/podman-remote-artifacts:latest):/darwin/podman . && podman rm remote-temp +``` diff --git a/docs/source/markdown/.gitignore b/docs/source/markdown/.gitignore index af4c5360b..57a64e1c1 100644 --- a/docs/source/markdown/.gitignore +++ b/docs/source/markdown/.gitignore @@ -1,3 +1,4 @@ +podman-attach.1.md podman-auto-update.1.md podman-build.1.md podman-container-clone.1.md diff --git a/docs/source/markdown/options/env-file.md b/docs/source/markdown/options/env-file.md new file mode 100644 index 000000000..f08dc09f0 --- /dev/null +++ b/docs/source/markdown/options/env-file.md @@ -0,0 +1,3 @@ +#### **--env-file**=*file* + +Read in a line-delimited file of environment variables. diff --git a/docs/source/markdown/options/env.md b/docs/source/markdown/options/env.md new file mode 100644 index 000000000..ace25138e --- /dev/null +++ b/docs/source/markdown/options/env.md @@ -0,0 +1,5 @@ +#### **--env**, **-e**=*env* + +Set environment variables. + +This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container. diff --git a/docs/source/markdown/options/sig-proxy.md b/docs/source/markdown/options/sig-proxy.md new file mode 100644 index 000000000..bb940aed3 --- /dev/null +++ b/docs/source/markdown/options/sig-proxy.md @@ -0,0 +1,3 @@ +#### **--sig-proxy** + +Proxy received signals to the container process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. diff --git a/docs/source/markdown/podman-attach.1.md b/docs/source/markdown/podman-attach.1.md.in index c073fccf8..427f764dc 100644 --- a/docs/source/markdown/podman-attach.1.md +++ b/docs/source/markdown/podman-attach.1.md.in @@ -28,9 +28,8 @@ The default is **false**.\ Do not attach STDIN. The default is **false**. -#### **--sig-proxy** +@@option sig-proxy -Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.\ The default is **true**. ## EXAMPLES diff --git a/docs/source/markdown/podman-create.1.md.in b/docs/source/markdown/podman-create.1.md.in index 742a32b5a..351124dc4 100644 --- a/docs/source/markdown/podman-create.1.md.in +++ b/docs/source/markdown/podman-create.1.md.in @@ -151,17 +151,13 @@ This option cannot be combined with **--network** that is set to **none** or **c @@option entrypoint -#### **--env**, **-e**=*env* - -Set environment variables - -This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container. +@@option env See [**Environment**](#environment) note below for precedence and examples. -#### **--env-file**=*file* +@@option env-file -Read in a line delimited file of environment variables. See **Environment** note below for precedence. +See [**Environment**](#environment) note below for precedence and examples. @@option env-host diff --git a/docs/source/markdown/podman-exec.1.md.in b/docs/source/markdown/podman-exec.1.md.in index 8198c319e..0479f2ee4 100644 --- a/docs/source/markdown/podman-exec.1.md.in +++ b/docs/source/markdown/podman-exec.1.md.in @@ -21,15 +21,9 @@ Start the exec session, but do not attach to it. The command will run in the bac Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*. -#### **--env**, **-e**=*env* +@@option env -Set environment variables. - -This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container. - -#### **--env-file**=*file* - -Read in a line delimited file of environment variables. +@@option env-file @@option interactive diff --git a/docs/source/markdown/podman-run.1.md.in b/docs/source/markdown/podman-run.1.md.in index 2109a0e33..95ee595d9 100644 --- a/docs/source/markdown/podman-run.1.md.in +++ b/docs/source/markdown/podman-run.1.md.in @@ -187,17 +187,13 @@ This option cannot be combined with **--network** that is set to **none** or **c @@option entrypoint -#### **--env**, **-e**=*env* - -Set environment variables. - -This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container. +@@option env See [**Environment**](#environment) note below for precedence and examples. -#### **--env-file**=*file* +@@option env-file -Read in a line delimited file of environment variables. See **Environment** note below for precedence. +See [**Environment**](#environment) note below for precedence and examples. @@option env-host @@ -439,9 +435,9 @@ Note: Labeling can be disabled for all containers by setting **label=false** in @@option shm-size -#### **--sig-proxy** +@@option sig-proxy -Sets whether the signals sent to the **podman run** command are proxied to the container process. SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is **true**. +The default is **true**. @@option stop-signal diff --git a/docs/source/markdown/podman-start.1.md.in b/docs/source/markdown/podman-start.1.md.in index 6fa41018b..a1ccc4120 100644 --- a/docs/source/markdown/podman-start.1.md.in +++ b/docs/source/markdown/podman-start.1.md.in @@ -60,9 +60,9 @@ Valid filters are listed below: Instead of providing the container name or ID, use the last created container. If you use methods other than Podman to run containers such as CRI-O, the last started container could be from either of those methods. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) -#### **--sig-proxy** +@@option sig-proxy -Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true* when attaching, *false* otherwise. +The default is **true** when attaching, **false** otherwise. ## EXAMPLE @@ -12,7 +12,7 @@ require ( github.com/containernetworking/cni v1.1.2 github.com/containernetworking/plugins v1.1.1 github.com/containers/buildah v1.27.1-0.20220921131114-d3064796af36 - github.com/containers/common v0.49.2-0.20220920205255-8062f81c5497 + github.com/containers/common v0.49.2-0.20220926195839-590004b80685 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.22.1-0.20220919112403-fe51f7ffca50 github.com/containers/ocicrypt v1.1.5 @@ -419,8 +419,9 @@ github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNG github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= github.com/containers/buildah v1.27.1-0.20220921131114-d3064796af36 h1:LTSEbPUbs0slJSJ+IH6atAjYDe0IDzA0sPgBLjT1yAo= github.com/containers/buildah v1.27.1-0.20220921131114-d3064796af36/go.mod h1:cY3pGPyMmrNp/sEDK8ESoBOf4hoNovptZSI0oyo8eQM= -github.com/containers/common v0.49.2-0.20220920205255-8062f81c5497 h1:LB9SxcAglqSAHiiHGacN1Abi0ZL9haJpQ1numVlqtxM= github.com/containers/common v0.49.2-0.20220920205255-8062f81c5497/go.mod h1:ZnhOPR/07UOkfIg5bezUpBilGjxEUdaeoUpu7gRBGc0= +github.com/containers/common v0.49.2-0.20220926195839-590004b80685 h1:rutCgIKcew85mTUO0JTnh7XDXQfaTz/qQ3HyQHb0jZE= +github.com/containers/common v0.49.2-0.20220926195839-590004b80685/go.mod h1:ZnhOPR/07UOkfIg5bezUpBilGjxEUdaeoUpu7gRBGc0= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.22.1-0.20220907162003-651744379993/go.mod h1:/Ruurd87C6Ap45t1PWNOD8+SGwiZbk79XCgs1iUTvYA= diff --git a/libpod/container_validate.go b/libpod/container_validate.go index f4611ecce..7224ec7db 100644 --- a/libpod/container_validate.go +++ b/libpod/container_validate.go @@ -3,6 +3,9 @@ package libpod import ( "fmt" + "github.com/containers/image/v5/docker" + "github.com/containers/image/v5/pkg/shortnames" + "github.com/containers/image/v5/transports/alltransports" "github.com/containers/podman/v4/libpod/define" spec "github.com/opencontainers/runtime-spec/specs-go" ) @@ -141,5 +144,35 @@ func (c *Container) validate() error { if c.config.HealthCheckOnFailureAction != define.HealthCheckOnFailureActionNone && c.config.HealthCheckConfig == nil { return fmt.Errorf("cannot set on-failure action to %s without a health check", c.config.HealthCheckOnFailureAction.String()) } + + if value, exists := c.config.Labels[define.AutoUpdateLabel]; exists { + // TODO: we cannot reference pkg/autoupdate here due to + // circular dependencies. It's worth considering moving the + // auto-update logic into the libpod package. + if value == "registry" || value == "image" { + if err := validateAutoUpdateImageReference(c.config.RawImageName); err != nil { + return err + } + } + } + + return nil +} + +// validateAutoUpdateImageReference checks if the specified imageName is a +// fully-qualified image reference to the docker transport. Such a reference +// includes a domain, name and tag (e.g., quay.io/podman/stable:latest). The +// reference may also be prefixed with "docker://" explicitly indicating that +// it's a reference to the docker transport. +func validateAutoUpdateImageReference(imageName string) error { + // Make sure the input image is a docker. + imageRef, err := alltransports.ParseImageName(imageName) + if err == nil && imageRef.Transport().Name() != docker.Transport.Name() { + return fmt.Errorf("auto updates require the docker image transport but image is of transport %q", imageRef.Transport().Name()) + } else if err != nil { + if shortnames.IsShortName(imageName) { + return fmt.Errorf("short name: auto updates require fully-qualified image reference: %q", imageName) + } + } return nil } diff --git a/libpod/define/autoupdate.go b/libpod/define/autoupdate.go new file mode 100644 index 000000000..7c278c3c5 --- /dev/null +++ b/libpod/define/autoupdate.go @@ -0,0 +1,9 @@ +package define + +// AutoUpdateLabel denotes the container/pod label key to specify auto-update +// policies in container labels. +const AutoUpdateLabel = "io.containers.autoupdate" + +// AutoUpdateAuthfileLabel denotes the container label key to specify authfile +// in container labels. +const AutoUpdateAuthfileLabel = "io.containers.autoupdate.authfile" diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 29d1398cf..078e75ed3 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -118,6 +118,11 @@ func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *netty if changeDefaultName && name == runtime.Network().DefaultNetworkName() { name = nettypes.BridgeNetworkDriver } + options := network.Options + // bridge always has isolate set in the compat API but we should not return it to not confuse callers + // https://github.com/containers/podman/issues/15580 + delete(options, nettypes.IsolateOption) + report := types.NetworkResource{ Name: name, ID: network.ID, @@ -126,7 +131,7 @@ func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *netty Internal: network.Internal, EnableIPv6: network.IPv6Enabled, Labels: network.Labels, - Options: network.Options, + Options: options, IPAM: ipam, Scope: "local", Attachable: false, diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index 9cf77d135..a0ed8ccba 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -9,8 +9,6 @@ import ( "github.com/containers/common/libimage" "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker" - "github.com/containers/image/v5/docker/reference" - "github.com/containers/image/v5/transports/alltransports" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/libpod/events" @@ -21,14 +19,6 @@ import ( "github.com/sirupsen/logrus" ) -// Label denotes the container/pod label key to specify auto-update policies in -// container labels. -const Label = "io.containers.autoupdate" - -// Label denotes the container label key to specify authfile in -// container labels. -const AuthfileLabel = "io.containers.autoupdate.authfile" - // Policy represents an auto-update policy. type Policy string @@ -102,32 +92,7 @@ func LookupPolicy(s string) (Policy, error) { return "", fmt.Errorf("invalid auto-update policy %q: valid policies are %+q", s, keys) } -// ValidateImageReference checks if the specified imageName is a fully-qualified -// image reference to the docker transport (without digest). Such a reference -// includes a domain, name and tag (e.g., quay.io/podman/stable:latest). The -// reference may also be prefixed with "docker://" explicitly indicating that -// it's a reference to the docker transport. -func ValidateImageReference(imageName string) error { - // Make sure the input image is a docker. - imageRef, err := alltransports.ParseImageName(imageName) - if err == nil && imageRef.Transport().Name() != docker.Transport.Name() { - return fmt.Errorf("auto updates require the docker image transport but image is of transport %q", imageRef.Transport().Name()) - } else if err != nil { - repo, err := reference.Parse(imageName) - if err != nil { - return fmt.Errorf("enforcing fully-qualified docker transport reference for auto updates: %w", err) - } - if _, ok := repo.(reference.NamedTagged); !ok { - return fmt.Errorf("auto updates require fully-qualified image references (no tag): %q", imageName) - } - if _, ok := repo.(reference.Digested); ok { - return fmt.Errorf("auto updates require fully-qualified image references without digest: %q", imageName) - } - } - return nil -} - -// AutoUpdate looks up containers with a specified auto-update policy and acts +/// AutoUpdate looks up containers with a specified auto-update policy and acts // accordingly. // // If the policy is set to PolicyRegistryImage, it checks if the image @@ -418,7 +383,7 @@ func (u *updater) assembleTasks(ctx context.Context) []error { // Check the container's auto-update policy which is configured // as a label. labels := ctr.Labels() - value, exists := labels[Label] + value, exists := labels[define.AutoUpdateLabel] if !exists { continue } @@ -454,7 +419,7 @@ func (u *updater) assembleTasks(ctx context.Context) []error { } t := task{ - authfile: labels[AuthfileLabel], + authfile: labels[define.AutoUpdateAuthfileLabel], auto: u, container: ctr, policy: policy, diff --git a/pkg/autoupdate/autoupdate_test.go b/pkg/autoupdate/autoupdate_test.go deleted file mode 100644 index 7a5da5bb0..000000000 --- a/pkg/autoupdate/autoupdate_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package autoupdate - -import ( - "testing" -) - -func TestValidateImageReference(t *testing.T) { - tests := []struct { - input string - valid bool - }{ - { // Fully-qualified reference - input: "quay.io/foo/bar:tag", - valid: true, - }, - { // Fully-qualified reference in transport notation - input: "docker://quay.io/foo/bar:tag", - valid: true, - }, - { // Fully-qualified reference but with digest - input: "quay.io/foo/bar@sha256:c9b1b535fdd91a9855fb7f82348177e5f019329a58c53c47272962dd60f71fc9", - valid: false, - }, - { // Reference with missing tag - input: "quay.io/foo/bar", - valid: false, - }, - { // Short name - input: "alpine", - valid: false, - }, - { // Short name with repo - input: "library/alpine", - valid: false, - }, - { // Wrong transport - input: "docker-archive:/some/path.tar", - valid: false, - }, - } - - for _, test := range tests { - err := ValidateImageReference(test.input) - if test.valid && err != nil { - t.Fatalf("parsing %q should have succeeded: %v", test.input, err) - } else if !test.valid && err == nil { - t.Fatalf("parsing %q should have failed", test.input) - } - } -} diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go index 6d7b052b7..a3677d393 100644 --- a/pkg/bindings/connection.go +++ b/pkg/bindings/connection.go @@ -59,7 +59,7 @@ func JoinURL(elements ...string) string { // NewConnection creates a new service connection without an identity func NewConnection(ctx context.Context, uri string) (context.Context, error) { - return NewConnectionWithIdentity(ctx, uri, "") + return NewConnectionWithIdentity(ctx, uri, "", false) } // NewConnectionWithIdentity takes a URI as a string and returns a context with the @@ -70,7 +70,7 @@ func NewConnection(ctx context.Context, uri string) (context.Context, error) { // For example tcp://localhost:<port> // or unix:///run/podman/podman.sock // or ssh://<user>@<host>[:port]/run/podman/podman.sock?secure=True -func NewConnectionWithIdentity(ctx context.Context, uri string, identity string) (context.Context, error) { +func NewConnectionWithIdentity(ctx context.Context, uri string, identity string, machine bool) (context.Context, error) { var ( err error ) @@ -96,10 +96,11 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, identity string) return nil, err } conn, err := ssh.Dial(&ssh.ConnectionDialOptions{ - Host: uri, - Identity: identity, - User: _url.User, - Port: port, + Host: uri, + Identity: identity, + User: _url.User, + Port: port, + InsecureIsMachineConnection: machine, }, "golang") if err != nil { return nil, err diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go index a69cf5111..d0d439a1b 100644 --- a/pkg/domain/entities/engine.go +++ b/pkg/domain/entities/engine.go @@ -54,4 +54,5 @@ type PodmanConfig struct { StorageDriver string StorageOpts []string SSHMode string + MachineMode bool } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index bd9117f72..4a83cb464 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -20,7 +20,6 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/autoupdate" "github.com/containers/podman/v4/pkg/domain/entities" v1apps "github.com/containers/podman/v4/pkg/k8s.io/api/apps/v1" v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" @@ -816,8 +815,8 @@ func (ic *ContainerEngine) getImageAndLabelInfo(ctx context.Context, cwd string, } } - setLabel(autoupdate.Label) - setLabel(autoupdate.AuthfileLabel) + setLabel(define.AutoUpdateLabel) + setLabel(define.AutoUpdateAuthfileLabel) return pulledImage, labels, nil } diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go index 7b5198d2f..94565c59e 100644 --- a/pkg/domain/infra/runtime_abi.go +++ b/pkg/domain/infra/runtime_abi.go @@ -21,7 +21,7 @@ func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine, r, err := NewLibpodRuntime(facts.FlagSet, facts) return r, err case entities.TunnelMode: - ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity) + ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity, facts.MachineMode) return &tunnel.ContainerEngine{ClientCtx: ctx}, err } return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode) @@ -35,7 +35,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error) return r, err case entities.TunnelMode: // TODO: look at me! - ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity) + ctx, err := bindings.NewConnectionWithIdentity(context.Background(), facts.URI, facts.Identity, facts.MachineMode) return &tunnel.ImageEngine{ClientCtx: ctx}, err } return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode) diff --git a/pkg/domain/infra/runtime_tunnel.go b/pkg/domain/infra/runtime_tunnel.go index 8a4de032f..48e6a6773 100644 --- a/pkg/domain/infra/runtime_tunnel.go +++ b/pkg/domain/infra/runtime_tunnel.go @@ -18,12 +18,12 @@ var ( connection *context.Context ) -func newConnection(uri string, identity string) (context.Context, error) { +func newConnection(uri string, identity string, machine bool) (context.Context, error) { connectionMutex.Lock() defer connectionMutex.Unlock() if connection == nil { - ctx, err := bindings.NewConnectionWithIdentity(context.Background(), uri, identity) + ctx, err := bindings.NewConnectionWithIdentity(context.Background(), uri, identity, machine) if err != nil { return ctx, err } @@ -37,7 +37,7 @@ func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine, case entities.ABIMode: return nil, fmt.Errorf("direct runtime not supported") case entities.TunnelMode: - ctx, err := newConnection(facts.URI, facts.Identity) + ctx, err := newConnection(facts.URI, facts.Identity, facts.MachineMode) return &tunnel.ContainerEngine{ClientCtx: ctx}, err } return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode) @@ -49,7 +49,7 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error) case entities.ABIMode: return nil, fmt.Errorf("direct image runtime not supported") case entities.TunnelMode: - ctx, err := newConnection(facts.URI, facts.Identity) + ctx, err := newConnection(facts.URI, facts.Identity, facts.MachineMode) return &tunnel.ImageEngine{ClientCtx: ctx}, err } return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode) diff --git a/pkg/machine/connection.go b/pkg/machine/connection.go index 6ff761a92..93c638cc7 100644 --- a/pkg/machine/connection.go +++ b/pkg/machine/connection.go @@ -25,7 +25,8 @@ func AddConnection(uri fmt.Stringer, name, identity string, isDefault bool) erro cfg.Engine.ActiveService = name } dst := config.Destination{ - URI: uri.String(), + URI: uri.String(), + IsMachine: true, } dst.Identity = identity if cfg.Engine.ServiceDestinations == nil { diff --git a/pkg/machine/e2e/basic_test.go b/pkg/machine/e2e/basic_test.go index fa1728770..b7a11c7d9 100644 --- a/pkg/machine/e2e/basic_test.go +++ b/pkg/machine/e2e/basic_test.go @@ -1,8 +1,6 @@ package e2e_test import ( - "os" - . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" @@ -24,10 +22,6 @@ var _ = Describe("run basic podman commands", func() { It("Basic ops", func() { // golangci-lint has trouble with actually skipping tests marked Skip // so skip it on cirrus envs and where CIRRUS_CI isn't set. - if os.Getenv("CIRRUS_CI") != "false" { - Skip("FIXME: #15347 - ssh know hosts broken - fails on PR runs and on x86_64") - } - name := randomString() i := new(initMachine) session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath).withNow()).run() diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index fab25aa35..a6907c0df 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -405,6 +405,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { WritePath: v.getIgnitionFile(), UID: v.UID, } + err = machine.NewIgnitionFile(ign) return err == nil, err } @@ -1033,7 +1034,7 @@ func (v *MachineVM) SSH(_ string, opts machine.SSHOptions) error { sshDestination := username + "@localhost" port := strconv.Itoa(v.Port) - args := []string{"-i", v.IdentityPath, "-p", port, sshDestination, "-o", "UserKnownHostsFile=/dev/null", + args := []string{"-i", v.IdentityPath, "-p", port, sshDestination, "-o", "StrictHostKeyChecking=no", "-o", "LogLevel=ERROR", "-o", "SetEnv=LC_ALL="} if len(opts.Args) > 0 { args = append(args, opts.Args...) diff --git a/test/compose/uptwice/docker-compose.yml b/test/compose/uptwice/docker-compose.yml index e06f9e554..71cc0806c 100644 --- a/test/compose/uptwice/docker-compose.yml +++ b/test/compose/uptwice/docker-compose.yml @@ -2,4 +2,5 @@ version: '3' services: app: build: . - command: sleep 10002 + command: sleep 10001 + stop_signal: SIGKILL # faster shutdown, no reason to wait 10 seconds diff --git a/test/compose/uptwice/teardown.sh b/test/compose/uptwice/teardown.sh new file mode 100644 index 000000000..115c454dc --- /dev/null +++ b/test/compose/uptwice/teardown.sh @@ -0,0 +1,3 @@ +# -*- bash -*- + +mv docker-compose.yml.bak docker-compose.yml diff --git a/test/compose/uptwice/tests.sh b/test/compose/uptwice/tests.sh index 291694d83..013b5a29a 100644 --- a/test/compose/uptwice/tests.sh +++ b/test/compose/uptwice/tests.sh @@ -1,4 +1,17 @@ # -*- bash -*- +CR=$'\r' +NL=$'\n' + +cp docker-compose.yml docker-compose.yml.bak sed -i -e 's/10001/10002/' docker-compose.yml -docker-compose up -d +output=$(docker-compose up -d 2>&1) + +# Horrible output check here but we really want to make sure that there are +# no unexpected warning/errors and the normal messages are send on stderr as +# well so we cannot check for an empty stderr. +expected="Recreating uptwice_app_1 ... ${CR}${NL}Recreating uptwice_app_1 ... done$CR" +if [ "$TEST_FLAVOR" = "compose_v2" ]; then + expected="Container uptwice-app-1 Recreate${NL}Container uptwice-app-1 Recreated${NL}Container uptwice-app-1 Starting${NL}Container uptwice-app-1 Started" +fi +is "$output" "$expected" "no error output in compose up (#15580)" diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats index 76f6b02e8..6f5113779 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -133,6 +133,26 @@ function _confirm_update() { die "Timed out waiting for $cname to update; old IID=$old_iid" } +@test "podman auto-update - validate input" { + # Fully-qualified image reference is required + run_podman create --label io.containers.autoupdate=registry $IMAGE + run_podman rm -f "$output" + + # Short name does not work + shortname="shortname:latest" + run_podman image tag $IMAGE $shortname + run_podman 125 create --label io.containers.autoupdate=registry $shortname + is "$output" "Error: short name: auto updates require fully-qualified image reference: \"$shortname\"" + + # Requires docker (or no) transport + archive=$PODMAN_TMPDIR/archive.tar + run_podman save -o $archive $IMAGE + run_podman 125 create --label io.containers.autoupdate=registry docker-archive:$archive + is "$output" ".*Error: auto updates require the docker image transport but image is of transport \"docker-archive\"" + + run_podman rmi $shortname +} + # This test can fail in dev. environment because of SELinux. # quick fix: chcon -t container_runtime_exec_t ./bin/podman @test "podman auto-update - label io.containers.autoupdate=image" { diff --git a/vendor/github.com/containers/common/libimage/platform.go b/vendor/github.com/containers/common/libimage/platform.go index 736a193f6..274b2aa06 100644 --- a/vendor/github.com/containers/common/libimage/platform.go +++ b/vendor/github.com/containers/common/libimage/platform.go @@ -63,6 +63,9 @@ func toPlatformString(os, arch, variant string) string { // * 2) a bool indicating whether architecture, os or variant were set (some callers need that to decide whether they need to throw an error) // * 3) a fatal error that occurred prior to check for matches (e.g., storage errors etc.) func (i *Image) matchesPlatform(ctx context.Context, os, arch, variant string) (error, bool, error) { + if err := i.isCorrupted(""); err != nil { + return err, false, nil + } inspectInfo, err := i.inspectInfo(ctx) if err != nil { return nil, false, fmt.Errorf("inspecting image: %w", err) diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index 858f961b6..cde7cec53 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -613,6 +613,9 @@ type Destination struct { // Identity file with ssh key, optional Identity string `toml:"identity,omitempty"` + + // isMachine describes if the remote destination is a machine. + IsMachine bool `toml:"is_machine,omitempty"` } // NewConfig creates a new Config. It starts with an empty config and, if @@ -1235,32 +1238,32 @@ func Reload() (*Config, error) { return defConfig() } -func (c *Config) ActiveDestination() (uri, identity string, err error) { +func (c *Config) ActiveDestination() (uri, identity string, machine bool, err error) { if uri, found := os.LookupEnv("CONTAINER_HOST"); found { if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found { identity = v } - return uri, identity, nil + return uri, identity, false, nil } connEnv := os.Getenv("CONTAINER_CONNECTION") switch { case connEnv != "": d, found := c.Engine.ServiceDestinations[connEnv] if !found { - return "", "", fmt.Errorf("environment variable CONTAINER_CONNECTION=%q service destination not found", connEnv) + return "", "", false, fmt.Errorf("environment variable CONTAINER_CONNECTION=%q service destination not found", connEnv) } - return d.URI, d.Identity, nil + return d.URI, d.Identity, d.IsMachine, nil case c.Engine.ActiveService != "": d, found := c.Engine.ServiceDestinations[c.Engine.ActiveService] if !found { - return "", "", fmt.Errorf("%q service destination not found", c.Engine.ActiveService) + return "", "", false, fmt.Errorf("%q service destination not found", c.Engine.ActiveService) } - return d.URI, d.Identity, nil + return d.URI, d.Identity, d.IsMachine, nil case c.Engine.RemoteURI != "": - return c.Engine.RemoteURI, c.Engine.RemoteIdentity, nil + return c.Engine.RemoteURI, c.Engine.RemoteIdentity, false, nil } - return "", "", errors.New("no service destination configured") + return "", "", false, errors.New("no service destination configured") } var ( diff --git a/vendor/github.com/containers/common/pkg/ssh/connection_golang.go b/vendor/github.com/containers/common/pkg/ssh/connection_golang.go index a5c1be89c..8ec3c45ed 100644 --- a/vendor/github.com/containers/common/pkg/ssh/connection_golang.go +++ b/vendor/github.com/containers/common/pkg/ssh/connection_golang.go @@ -3,6 +3,7 @@ package ssh import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net" @@ -70,7 +71,7 @@ func golangConnectionDial(options ConnectionDialOptions) (*ConnectionDialReport, if err != nil { return nil, err } - cfg, err := ValidateAndConfigure(uri, options.Identity) + cfg, err := ValidateAndConfigure(uri, options.Identity, options.InsecureIsMachineConnection) if err != nil { return nil, err } @@ -84,12 +85,15 @@ func golangConnectionDial(options ConnectionDialOptions) (*ConnectionDialReport, } func golangConnectionExec(options ConnectionExecOptions) (*ConnectionExecReport, error) { + if !strings.HasPrefix(options.Host, "ssh://") { + options.Host = "ssh://" + options.Host + } _, uri, err := Validate(options.User, options.Host, options.Port, options.Identity) if err != nil { return nil, err } - cfg, err := ValidateAndConfigure(uri, options.Identity) + cfg, err := ValidateAndConfigure(uri, options.Identity, false) if err != nil { return nil, err } @@ -111,11 +115,15 @@ func golangConnectionScp(options ConnectionScpOptions) (*ConnectionScpReport, er return nil, err } + // removed for parsing + if !strings.HasPrefix(host, "ssh://") { + host = "ssh://" + host + } _, uri, err := Validate(options.User, host, options.Port, options.Identity) if err != nil { return nil, err } - cfg, err := ValidateAndConfigure(uri, options.Identity) + cfg, err := ValidateAndConfigure(uri, options.Identity, false) if err != nil { return nil, err } @@ -209,7 +217,7 @@ func GetUserInfo(uri *url.URL) (*url.Userinfo, error) { // ValidateAndConfigure will take a ssh url and an identity key (rsa and the like) and ensure the information given is valid // iden iden can be blank to mean no identity key // once the function validates the information it creates and returns an ssh.ClientConfig. -func ValidateAndConfigure(uri *url.URL, iden string) (*ssh.ClientConfig, error) { +func ValidateAndConfigure(uri *url.URL, iden string, insecureIsMachineConnection bool) (*ssh.ClientConfig, error) { var signers []ssh.Signer passwd, passwdSet := uri.User.Password() if iden != "" { // iden might be blank if coming from image scp or if no validation is needed @@ -272,23 +280,61 @@ func ValidateAndConfigure(uri *url.URL, iden string) (*ssh.ClientConfig, error) if err != nil { return nil, err } - keyFilePath := filepath.Join(homedir.Get(), ".ssh", "known_hosts") - known, err := knownhosts.New(keyFilePath) - if err != nil { - return nil, fmt.Errorf("creating host key callback function for %s: %w", keyFilePath, err) + + var callback ssh.HostKeyCallback + if insecureIsMachineConnection { + callback = ssh.InsecureIgnoreHostKey() + } else { + callback = ssh.HostKeyCallback(func(host string, remote net.Addr, pubKey ssh.PublicKey) error { + keyFilePath := filepath.Join(homedir.Get(), ".ssh", "known_hosts") + known, err := knownhosts.New(keyFilePath) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + logrus.Warn("please create a known_hosts file. The next time this host is connected to, podman will add it to known_hosts") + return nil + } + return err + } + // we need to check if there is an error from reading known hosts for this public key and if there is an error, what is it, and why is it happening? + // if it is a key mismatch we want to error since we know the host using another key + // however, if it is a general error not because of a known key, we want to add our key to the known_hosts file + hErr := known(host, remote, pubKey) + var keyErr *knownhosts.KeyError + // if keyErr.Want is not empty, we are receiving a different key meaning the host is known but we are using the wrong key + as := errors.As(hErr, &keyErr) + switch { + case as && len(keyErr.Want) > 0: + logrus.Warnf("ssh host key mismatch for host %s, got key %s of type %s", host, ssh.FingerprintSHA256(pubKey), pubKey.Type()) + return keyErr + // if keyErr.Want is empty that just means we do not know this host yet, add it. + case as && len(keyErr.Want) == 0: + // write to known_hosts + err := addKnownHostsEntry(host, pubKey) + if err != nil { + if os.IsNotExist(err) { + logrus.Warn("podman will soon require a known_hosts file to function properly.") + return nil + } + return err + } + case hErr != nil: + return hErr + } + return nil + }) } cfg := &ssh.ClientConfig{ User: uri.User.Username(), Auth: authMethods, - HostKeyCallback: known, + HostKeyCallback: callback, Timeout: tick, } return cfg, nil } func getUDS(uri *url.URL, iden string) (string, error) { - cfg, err := ValidateAndConfigure(uri, iden) + cfg, err := ValidateAndConfigure(uri, iden, false) if err != nil { return "", fmt.Errorf("failed to validate: %w", err) } @@ -324,3 +370,20 @@ func getUDS(uri *url.URL, iden string) (string, error) { } return info.Host.RemoteSocket.Path, nil } + +// addKnownHostsEntry adds (host, pubKey) to user’s known_hosts. +func addKnownHostsEntry(host string, pubKey ssh.PublicKey) error { + hd := homedir.Get() + known := filepath.Join(hd, ".ssh", "known_hosts") + f, err := os.OpenFile(known, os.O_APPEND|os.O_WRONLY, 0o600) + if err != nil { + return err + } + defer f.Close() + l := knownhosts.Line([]string{host}, pubKey) + if _, err = f.WriteString("\n" + l + "\n"); err != nil { + return err + } + logrus.Infof("key %s added to %s", ssh.FingerprintSHA256(pubKey), known) + return nil +} diff --git a/vendor/github.com/containers/common/pkg/ssh/types.go b/vendor/github.com/containers/common/pkg/ssh/types.go index f22b5fba9..16512c43f 100644 --- a/vendor/github.com/containers/common/pkg/ssh/types.go +++ b/vendor/github.com/containers/common/pkg/ssh/types.go @@ -27,12 +27,13 @@ type ConnectionCreateOptions struct { } type ConnectionDialOptions struct { - Host string - Identity string - User *url.Userinfo - Port int - Auth []string - Timeout time.Duration + Host string + Identity string + User *url.Userinfo + Port int + Auth []string + Timeout time.Duration + InsecureIsMachineConnection bool } type ConnectionDialReport struct { diff --git a/vendor/github.com/containers/common/pkg/ssh/utils.go b/vendor/github.com/containers/common/pkg/ssh/utils.go index c15745015..b05105d9c 100644 --- a/vendor/github.com/containers/common/pkg/ssh/utils.go +++ b/vendor/github.com/containers/common/pkg/ssh/utils.go @@ -21,6 +21,7 @@ func Validate(user *url.Userinfo, path string, port int, identity string) (*conf if strings.Contains(path, "/run") { sock = strings.Split(path, "/run")[1] } + // url.Parse NEEDS ssh://, if this ever fails or returns some nonsense, that is why. uri, err := url.Parse(path) if err != nil { return nil, nil, err @@ -33,9 +34,9 @@ func Validate(user *url.Userinfo, path string, port int, identity string) (*conf if uri.Port() == "" { if port != 0 { - uri.Host = net.JoinHostPort(uri.Hostname(), strconv.Itoa(port)) + uri.Host = net.JoinHostPort(uri.Host, strconv.Itoa(port)) } else { - uri.Host = net.JoinHostPort(uri.Hostname(), "22") + uri.Host = net.JoinHostPort(uri.Host, "22") } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 17e889387..222b70cd3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/containers/buildah/pkg/rusage github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/util -# github.com/containers/common v0.49.2-0.20220920205255-8062f81c5497 +# github.com/containers/common v0.49.2-0.20220926195839-590004b80685 ## explicit; go 1.17 github.com/containers/common/libimage github.com/containers/common/libimage/define |
