diff options
Diffstat (limited to 'pkg')
24 files changed, 188 insertions, 374 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index aa12afc82..0f91a4362 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -73,7 +73,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - if report[0].Err != nil { + if len(report) > 0 && report[0].Err != nil { utils.InternalServerError(w, report[0].Err) return } diff --git a/pkg/api/handlers/compat/images_search.go b/pkg/api/handlers/compat/images_search.go index 6808cdad5..885112b31 100644 --- a/pkg/api/handlers/compat/images_search.go +++ b/pkg/api/handlers/compat/images_search.go @@ -1,25 +1,30 @@ package compat import ( + "fmt" "net/http" - "strconv" "github.com/containers/image/v5/types" - "github.com/containers/podman/v2/libpod/image" + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/auth" - "github.com/docker/docker/api/types/registry" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/infra/abi" "github.com/gorilla/schema" "github.com/pkg/errors" ) func SearchImages(w http.ResponseWriter, r *http.Request) { + runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { Term string `json:"term"` Limit int `json:"limit"` + NoTrunc bool `json:"noTrunc"` Filters map[string][]string `json:"filters"` TLSVerify bool `json:"tlsVerify"` + ListTags bool `json:"listTags"` }{ // This is where you can override the golang default value for one of fields } @@ -29,67 +34,40 @@ func SearchImages(w http.ResponseWriter, r *http.Request) { return } - filter := image.SearchFilter{} - if len(query.Filters) > 0 { - if len(query.Filters["stars"]) > 0 { - stars, err := strconv.Atoi(query.Filters["stars"][0]) - if err != nil { - utils.InternalServerError(w, err) - return - } - filter.Stars = stars - } - if len(query.Filters["is-official"]) > 0 { - isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0]) - if err != nil { - utils.InternalServerError(w, err) - return - } - filter.IsOfficial = types.NewOptionalBool(isOfficial) - } - if len(query.Filters["is-automated"]) > 0 { - isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0]) - if err != nil { - utils.InternalServerError(w, err) - return - } - filter.IsAutomated = types.NewOptionalBool(isAutomated) - } - } - options := image.SearchOptions{ - Filter: filter, - Limit: query.Limit, - } - - if _, found := r.URL.Query()["tlsVerify"]; found { - options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) - } - _, authfile, key, err := auth.GetCredentials(r) if err != nil { utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String())) return } defer auth.RemoveAuthfile(authfile) - options.Authfile = authfile - results, err := image.SearchImages(query.Term, options) + filters := []string{} + for key, val := range query.Filters { + filters = append(filters, fmt.Sprintf("%s=%s", key, val[0])) + } + + options := entities.ImageSearchOptions{ + Authfile: authfile, + Limit: query.Limit, + NoTrunc: query.NoTrunc, + ListTags: query.ListTags, + Filters: filters, + } + if _, found := r.URL.Query()["tlsVerify"]; found { + options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) + } + ir := abi.ImageEngine{Libpod: runtime} + reports, err := ir.Search(r.Context(), query.Term, options) if err != nil { - utils.BadRequest(w, "term", query.Term, err) + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) return } - - compatResults := make([]registry.SearchResult, 0, len(results)) - for _, result := range results { - compatResult := registry.SearchResult{ - Name: result.Name, - Description: result.Description, - StarCount: result.Stars, - IsAutomated: result.Automated == "[OK]", - IsOfficial: result.Official == "[OK]", + if !utils.IsLibpodRequest(r) { + if len(reports) == 0 { + utils.ImageNotFound(w, query.Term, define.ErrNoSuchImage) + return } - compatResults = append(compatResults, compatResult) } - utils.WriteResponse(w, http.StatusOK, compatResults) + utils.WriteResponse(w, http.StatusOK, reports) } diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index 6b07b1cc5..a0cb1d49e 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -12,7 +12,6 @@ import ( "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/infra/abi" - "github.com/containers/podman/v2/pkg/ps" "github.com/gorilla/schema" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -63,6 +62,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { All bool `schema:"all"` + External bool `schema:"external"` Filters map[string][]string `schema:"filters"` Last int `schema:"last"` // alias for limit Limit int `schema:"limit"` @@ -90,17 +90,22 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { } runtime := r.Context().Value("runtime").(*libpod.Runtime) + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} opts := entities.ContainerListOptions{ All: query.All, + External: query.External, Filters: query.Filters, Last: limit, - Size: query.Size, - Sort: "", Namespace: query.Namespace, - Pod: true, - Sync: query.Sync, + // Always return Pod, should not be part of the API. + // https://github.com/containers/podman/pull/7223 + Pod: true, + Size: query.Size, + Sync: query.Sync, } - pss, err := ps.GetContainerLists(runtime, opts) + pss, err := containerEngine.ContainerList(r.Context(), opts) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 97cd5a65e..3b531652f 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -589,92 +589,6 @@ func UntagImage(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusCreated, "") } -func SearchImages(w http.ResponseWriter, r *http.Request) { - decoder := r.Context().Value("decoder").(*schema.Decoder) - query := struct { - Term string `json:"term"` - Limit int `json:"limit"` - NoTrunc bool `json:"noTrunc"` - Filters map[string][]string `json:"filters"` - TLSVerify bool `json:"tlsVerify"` - ListTags bool `json:"listTags"` - }{ - // This is where you can override the golang default value for one of fields - } - - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) - return - } - - filter := image.SearchFilter{} - if len(query.Filters) > 0 { - if len(query.Filters["stars"]) > 0 { - stars, err := strconv.Atoi(query.Filters["stars"][0]) - if err != nil { - utils.InternalServerError(w, err) - return - } - filter.Stars = stars - } - if len(query.Filters["is-official"]) > 0 { - isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0]) - if err != nil { - utils.InternalServerError(w, err) - return - } - filter.IsOfficial = types.NewOptionalBool(isOfficial) - } - if len(query.Filters["is-automated"]) > 0 { - isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0]) - if err != nil { - utils.InternalServerError(w, err) - return - } - filter.IsAutomated = types.NewOptionalBool(isAutomated) - } - } - options := image.SearchOptions{ - Limit: query.Limit, - NoTrunc: query.NoTrunc, - ListTags: query.ListTags, - Filter: filter, - } - - if _, found := r.URL.Query()["tlsVerify"]; found { - options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) - } - - _, authfile, key, err := auth.GetCredentials(r) - if err != nil { - utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String())) - return - } - defer auth.RemoveAuthfile(authfile) - options.Authfile = authfile - - searchResults, err := image.SearchImages(query.Term, options) - if err != nil { - utils.BadRequest(w, "term", query.Term, err) - return - } - // Convert from image.SearchResults to entities.ImageSearchReport. We don't - // want to leak any low-level packages into the remote client, which - // requires converting. - reports := make([]entities.ImageSearchReport, len(searchResults)) - for i := range searchResults { - reports[i].Index = searchResults[i].Index - reports[i].Name = searchResults[i].Name - reports[i].Description = searchResults[i].Description - reports[i].Stars = searchResults[i].Stars - reports[i].Official = searchResults[i].Official - reports[i].Automated = searchResults[i].Automated - reports[i].Tag = searchResults[i].Tag - } - - utils.WriteResponse(w, http.StatusOK, reports) -} - // ImagesBatchRemove is the endpoint for batch image removal. func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index bacba006d..efb15b14d 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -30,12 +30,12 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Reference string `schema:"reference"` - OverrideOS string `schema:"overrideOS"` - OverrideArch string `schema:"overrideArch"` - OverrideVariant string `schema:"overrideVariant"` - TLSVerify bool `schema:"tlsVerify"` - AllTags bool `schema:"allTags"` + Reference string `schema:"reference"` + OS string `schema:"OS"` + Arch string `schema:"Arch"` + Variant string `schema:"Variant"` + TLSVerify bool `schema:"tlsVerify"` + AllTags bool `schema:"allTags"` }{ TLSVerify: true, } @@ -83,9 +83,9 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { // Setup the registry options dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: authConf, - OSChoice: query.OverrideOS, - ArchitectureChoice: query.OverrideArch, - VariantChoice: query.OverrideVariant, + OSChoice: query.OS, + ArchitectureChoice: query.Arch, + VariantChoice: query.Variant, } if _, found := r.URL.Query()["tlsVerify"]; found { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) diff --git a/pkg/api/handlers/swagger/swagger.go b/pkg/api/handlers/swagger/swagger.go index 22670d795..32f041dd3 100644 --- a/pkg/api/handlers/swagger/swagger.go +++ b/pkg/api/handlers/swagger/swagger.go @@ -1,7 +1,6 @@ package swagger import ( - "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/pkg/api/handlers" @@ -166,7 +165,7 @@ type swagInspectPodResponse struct { type swagInspectVolumeResponse struct { // in:body Body struct { - libpod.InspectVolumeData + define.InspectVolumeData } } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index 74a04b2e6..e30747800 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -48,6 +48,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // default: false // description: Return all containers. By default, only running containers are shown // - in: query + // name: external + // type: boolean + // default: false + // description: Return containers in storage not controlled by Podman + // - in: query // name: limit // description: Return this number of most recently created containers, including non-running ones. // type: integer diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 8d0c0800b..d76f811e9 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -837,13 +837,16 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // name: url // description: Load image from the specified URL // type: string - // - in: formData + // - in: body // name: upload - // type: file // required: true // description: tarball for imported image + // schema: + // type: "string" // produces: // - application/json + // consumes: + // - application/x-tar // responses: // 200: // $ref: "#/responses/DocsLibpodImagesImportResponse" @@ -930,15 +933,15 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // description: "username:password for the registry" // type: string // - in: query - // name: overrideArch + // name: Arch // description: Pull image for the specified architecture. // type: string // - in: query - // name: overrideOS + // name: OS // description: Pull image for the specified operating system. // type: string // - in: query - // name: overrideVariant + // name: Variant // description: Pull image for the specified variant. // type: string // - in: query @@ -1019,7 +1022,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // $ref: "#/responses/DocsSearchResponse" // 500: // $ref: '#/responses/InternalError' - r.Handle(VersionedPath("/libpod/images/search"), s.APIHandler(libpod.SearchImages)).Methods(http.MethodGet) + r.Handle(VersionedPath("/libpod/images/search"), s.APIHandler(compat.SearchImages)).Methods(http.MethodGet) // swagger:operation GET /libpod/images/{name:.*}/get libpod libpodExportImage // --- // tags: diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go index 046f6561c..d612041f6 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -179,15 +179,15 @@ func setupSystemd() { func (s *APIServer) Serve() error { setupSystemd() - // Start the shutdown signal handler. - if err := shutdown.Start(); err != nil { - return err - } if err := shutdown.Register("server", func(sig os.Signal) error { return s.Shutdown() }); err != nil { return err } + // Start the shutdown signal handler. + if err := shutdown.Start(); err != nil { + return err + } errChan := make(chan error, 1) diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index 24604fa83..3fb1ab733 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -106,6 +106,7 @@ type MountedContainerPathsOptions struct{} // ListOptions are optional options for listing containers type ListOptions struct { All *bool + External *bool Filters map[string][]string Last *int Namespace *bool diff --git a/pkg/bindings/containers/types_list_options.go b/pkg/bindings/containers/types_list_options.go index 43326fa59..c363dcd32 100644 --- a/pkg/bindings/containers/types_list_options.go +++ b/pkg/bindings/containers/types_list_options.go @@ -103,6 +103,22 @@ func (o *ListOptions) GetAll() bool { return *o.All } +// WithExternal +func (o *ListOptions) WithExternal(value bool) *ListOptions { + v := &value + o.External = v + return o +} + +// GetExternal +func (o *ListOptions) GetExternal() bool { + var external bool + if o.External == nil { + return external + } + return *o.External +} + // WithFilters func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions { v := value diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index f216dd073..0248f2fa6 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -171,13 +171,13 @@ type PullOptions struct { Username *string // Password for authenticating against the registry. Password *string - // OverrideArch will overwrite the local architecture for image pulls. - OverrideArch *string - // OverrideOS will overwrite the local operating system (OS) for image + // Arch will overwrite the local architecture for image pulls. + Arch *string + // OS will overwrite the local operating system (OS) for image // pulls. - OverrideOS *string - // OverrideVariant will overwrite the local variant for image pulls. - OverrideVariant *string + OS *string + // Variant will overwrite the local variant for image pulls. + Variant *string // Quiet can be specified to suppress pull progress when pulling. Ignored // for remote calls. Quiet *bool diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go index 5163a6341..2bdf2b66e 100644 --- a/pkg/bindings/images/types_pull_options.go +++ b/pkg/bindings/images/types_pull_options.go @@ -168,52 +168,52 @@ func (o *PullOptions) GetPassword() string { return *o.Password } -// WithOverrideArch -func (o *PullOptions) WithOverrideArch(value string) *PullOptions { +// WithArch +func (o *PullOptions) WithArch(value string) *PullOptions { v := &value - o.OverrideArch = v + o.Arch = v return o } -// GetOverrideArch -func (o *PullOptions) GetOverrideArch() string { - var overrideArch string - if o.OverrideArch == nil { - return overrideArch +// GetArch +func (o *PullOptions) GetArch() string { + var arch string + if o.Arch == nil { + return arch } - return *o.OverrideArch + return *o.Arch } -// WithOverrideOS -func (o *PullOptions) WithOverrideOS(value string) *PullOptions { +// WithOS +func (o *PullOptions) WithOS(value string) *PullOptions { v := &value - o.OverrideOS = v + o.OS = v return o } -// GetOverrideOS -func (o *PullOptions) GetOverrideOS() string { - var overrideOS string - if o.OverrideOS == nil { - return overrideOS +// GetOS +func (o *PullOptions) GetOS() string { + var oS string + if o.OS == nil { + return oS } - return *o.OverrideOS + return *o.OS } -// WithOverrideVariant -func (o *PullOptions) WithOverrideVariant(value string) *PullOptions { +// WithVariant +func (o *PullOptions) WithVariant(value string) *PullOptions { v := &value - o.OverrideVariant = v + o.Variant = v return o } -// GetOverrideVariant -func (o *PullOptions) GetOverrideVariant() string { - var overrideVariant string - if o.OverrideVariant == nil { - return overrideVariant +// GetVariant +func (o *PullOptions) GetVariant() string { + var variant string + if o.Variant == nil { + return variant } - return *o.OverrideVariant + return *o.Variant } // WithQuiet diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 4c1bd6a7d..2c32f792f 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -297,8 +297,8 @@ type ContainerListOptions struct { Pod bool Quiet bool Size bool + External bool Sort string - Storage bool Sync bool Watch uint } diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 78a7d8aa7..ef40d5490 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -133,13 +133,13 @@ type ImagePullOptions struct { Username string // Password for authenticating against the registry. Password string - // OverrideArch will overwrite the local architecture for image pulls. - OverrideArch string - // OverrideOS will overwrite the local operating system (OS) for image + // Arch will overwrite the local architecture for image pulls. + Arch string + // OS will overwrite the local operating system (OS) for image // pulls. - OverrideOS string - // OverrideVariant will overwrite the local variant for image pulls. - OverrideVariant string + OS string + // Variant will overwrite the local variant for image pulls. + Variant string // Quiet can be specified to suppress pull progress when pulling. Ignored // for remote calls. Quiet bool diff --git a/pkg/domain/infra/abi/archive.go b/pkg/domain/infra/abi/archive.go index 809813756..c64dfb02a 100644 --- a/pkg/domain/infra/abi/archive.go +++ b/pkg/domain/infra/abi/archive.go @@ -26,13 +26,18 @@ func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrI return nil, err } + containerMountPoint, err := container.Mount() + if err != nil { + return nil, err + } + unmount := func() { if err := container.Unmount(false); err != nil { logrus.Errorf("Error unmounting container: %v", err) } } - _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerPath) + _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerMountPoint, containerPath) if err != nil { unmount() return nil, err @@ -71,6 +76,11 @@ func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID return nil, err } + containerMountPoint, err := container.Mount() + if err != nil { + return nil, err + } + unmount := func() { if err := container.Unmount(false); err != nil { logrus.Errorf("Error unmounting container: %v", err) @@ -83,7 +93,7 @@ func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID containerPath = "/." } - _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerPath) + _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerMountPoint, containerPath) if err != nil { unmount() return nil, err diff --git a/pkg/domain/infra/abi/containers_stat.go b/pkg/domain/infra/abi/containers_stat.go index 931e77026..f3d0799a0 100644 --- a/pkg/domain/infra/abi/containers_stat.go +++ b/pkg/domain/infra/abi/containers_stat.go @@ -10,18 +10,11 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/pkg/copy" "github.com/containers/podman/v2/pkg/domain/entities" - securejoin "github.com/cyphar/filepath-securejoin" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -func (ic *ContainerEngine) containerStat(container *libpod.Container, containerPath string) (*entities.ContainerStatReport, string, string, error) { - containerMountPoint, err := container.Mount() - if err != nil { - return nil, "", "", err - } - +func (ic *ContainerEngine) containerStat(container *libpod.Container, containerMountPoint string, containerPath string) (*entities.ContainerStatReport, string, string, error) { // Make sure that "/" copies the *contents* of the mount point and not // the directory. if containerPath == "/" { @@ -30,7 +23,7 @@ func (ic *ContainerEngine) containerStat(container *libpod.Container, containerP // Now resolve the container's path. It may hit a volume, it may hit a // bind mount, it may be relative. - resolvedRoot, resolvedContainerPath, err := resolveContainerPaths(container, containerMountPoint, containerPath) + resolvedRoot, resolvedContainerPath, err := container.ResolvePath(context.Background(), containerMountPoint, containerPath) if err != nil { return nil, "", "", err } @@ -94,138 +87,21 @@ func (ic *ContainerEngine) ContainerStat(ctx context.Context, nameOrID string, c return nil, err } + containerMountPoint, err := container.Mount() + if err != nil { + return nil, err + } + defer func() { if err := container.Unmount(false); err != nil { logrus.Errorf("Error unmounting container: %v", err) } }() - statReport, _, _, err := ic.containerStat(container, containerPath) + statReport, _, _, err := ic.containerStat(container, containerMountPoint, containerPath) return statReport, err } -// resolveContainerPaths resolves the container's mount point and the container -// path as specified by the user. Both may resolve to paths outside of the -// container's mount point when the container path hits a volume or bind mount. -// -// NOTE: We must take volumes and bind mounts into account as, regrettably, we -// can copy to/from stopped containers. In that case, the volumes and bind -// mounts are not present. For running containers, the runtime (e.g., runc or -// crun) takes care of these mounts. For stopped ones, we need to do quite -// some dance, as done below. -func resolveContainerPaths(container *libpod.Container, mountPoint string, containerPath string) (string, string, error) { - // Let's first make sure we have a path relative to the mount point. - pathRelativeToContainerMountPoint := containerPath - if !filepath.IsAbs(containerPath) { - // If the containerPath is not absolute, it's relative to the - // container's working dir. To be extra careful, let's first - // join the working dir with "/", and the add the containerPath - // to it. - pathRelativeToContainerMountPoint = filepath.Join(filepath.Join("/", container.WorkingDir()), containerPath) - } - resolvedPathOnTheContainerMountPoint := filepath.Join(mountPoint, pathRelativeToContainerMountPoint) - pathRelativeToContainerMountPoint = strings.TrimPrefix(pathRelativeToContainerMountPoint, mountPoint) - pathRelativeToContainerMountPoint = filepath.Join("/", pathRelativeToContainerMountPoint) - - // Now we have an "absolute container Path" but not yet resolved on the - // host (e.g., "/foo/bar/file.txt"). As mentioned above, we need to - // check if "/foo/bar/file.txt" is on a volume or bind mount. To do - // that, we need to walk *down* the paths to the root. Assuming - // volume-1 is mounted to "/foo" and volume-2 is mounted to "/foo/bar", - // we must select "/foo/bar". Once selected, we need to rebase the - // remainder (i.e, "/file.txt") on the volume's mount point on the - // host. Same applies to bind mounts. - - searchPath := pathRelativeToContainerMountPoint - for { - volume, err := findVolume(container, searchPath) - if err != nil { - return "", "", err - } - if volume != nil { - logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath) - - // TODO: We really need to force the volume to mount - // before doing this, but that API is not exposed - // externally right now and doing so is beyond the scope - // of this commit. - mountPoint, err := volume.MountPoint() - if err != nil { - return "", "", err - } - if mountPoint == "" { - return "", "", errors.Errorf("volume %s is not mounted, cannot copy into it", volume.Name()) - } - - // We found a matching volume for searchPath. We now - // need to first find the relative path of our input - // path to the searchPath, and then join it with the - // volume's mount point. - pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath) - absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(mountPoint, pathRelativeToVolume) - if err != nil { - return "", "", err - } - return mountPoint, absolutePathOnTheVolumeMount, nil - } - - if mount := findBindMount(container, searchPath); mount != nil { - logrus.Debugf("Container path %q resolved to bind mount %q:%q on path %q", containerPath, mount.Source, mount.Destination, searchPath) - // We found a matching bind mount for searchPath. We - // now need to first find the relative path of our - // input path to the searchPath, and then join it with - // the source of the bind mount. - pathRelativeToBindMount := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath) - absolutePathOnTheBindMount, err := securejoin.SecureJoin(mount.Source, pathRelativeToBindMount) - if err != nil { - return "", "", err - } - return mount.Source, absolutePathOnTheBindMount, nil - - } - - if searchPath == "/" { - // Cannot go beyond "/", so we're done. - break - } - - // Walk *down* the path (e.g., "/foo/bar/x" -> "/foo/bar"). - searchPath = filepath.Dir(searchPath) - } - - // No volume, no bind mount but just a normal path on the container. - return mountPoint, resolvedPathOnTheContainerMountPoint, nil -} - -// findVolume checks if the specified container path matches a volume inside -// the container. It returns a matching volume or nil. -func findVolume(c *libpod.Container, containerPath string) (*libpod.Volume, error) { - runtime := c.Runtime() - cleanedContainerPath := filepath.Clean(containerPath) - for _, vol := range c.Config().NamedVolumes { - if cleanedContainerPath == filepath.Clean(vol.Dest) { - return runtime.GetVolume(vol.Name) - } - } - return nil, nil -} - -// findBindMount checks if the specified container path matches a bind mount -// inside the container. It returns a matching mount or nil. -func findBindMount(c *libpod.Container, containerPath string) *specs.Mount { - cleanedPath := filepath.Clean(containerPath) - for _, m := range c.Config().Spec.Mounts { - if m.Type != "bind" { - continue - } - if cleanedPath == filepath.Clean(m.Destination) { - mount := m - return &mount - } - } - return nil -} - // secureStat extracts file info for path in a chroot'ed environment in root. func secureStat(root string, path string) (*buildahCopiah.StatForItem, error) { var glob string diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 1288ab09b..8ca93e770 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -241,9 +241,9 @@ func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: registryCreds, DockerCertPath: options.CertDir, - OSChoice: options.OverrideOS, - ArchitectureChoice: options.OverrideArch, - VariantChoice: options.OverrideVariant, + OSChoice: options.OS, + ArchitectureChoice: options.Arch, + VariantChoice: options.Variant, DockerInsecureSkipTLSVerify: options.SkipTLSVerify, } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 524b29553..0c61714c3 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -173,19 +173,32 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st } func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) { - ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds) - if err != nil { - return nil, err - } // TODO there is no endpoint for container eviction. Need to discuss - reports := make([]*entities.RmReport, 0, len(ctrs)) - options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes) - for _, c := range ctrs { + options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes).WithIgnore(opts.Ignore) + + if opts.All { + ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds) + if err != nil { + return nil, err + } + reports := make([]*entities.RmReport, 0, len(ctrs)) + for _, c := range ctrs { + reports = append(reports, &entities.RmReport{ + Id: c.ID, + Err: containers.Remove(ic.ClientCtx, c.ID, options), + }) + } + return reports, nil + } + + reports := make([]*entities.RmReport, 0, len(namesOrIds)) + for _, name := range namesOrIds { reports = append(reports, &entities.RmReport{ - Id: c.ID, - Err: containers.Remove(ic.ClientCtx, c.ID, options), + Id: name, + Err: containers.Remove(ic.ClientCtx, name, options), }) } + return reports, nil } @@ -601,7 +614,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri func (ic *ContainerEngine) ContainerList(ctx context.Context, opts entities.ContainerListOptions) ([]entities.ListContainer, error) { options := new(containers.ListOptions).WithFilters(opts.Filters).WithAll(opts.All).WithLast(opts.Last) - options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync) + options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync).WithExternal(opts.External) return containers.List(ic.ClientCtx, options) } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 2d686b2aa..0de756756 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -106,8 +106,8 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) { options := new(images.PullOptions) - options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithOverrideArch(opts.OverrideArch).WithOverrideOS(opts.OverrideOS) - options.WithOverrideVariant(opts.OverrideVariant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy) + options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithArch(opts.Arch).WithOS(opts.OS) + options.WithVariant(opts.Variant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { if s == types.OptionalBoolTrue { options.WithSkipTLSVerify(true) diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go index dc577890a..42f9e1d39 100644 --- a/pkg/ps/ps.go +++ b/pkg/ps/ps.go @@ -69,7 +69,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp pss = append(pss, listCon) } - if options.All && options.Storage { + if options.All && options.External { externCons, err := runtime.StorageContainers() if err != nil { return nil, err diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index cc3f7928c..31d317bf8 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -203,20 +203,6 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } s.Annotations = annotations - // workdir - if s.WorkDir == "" { - if newImage != nil { - workingDir, err := newImage.WorkingDir(ctx) - if err != nil { - return nil, err - } - s.WorkDir = workingDir - } - } - if s.WorkDir == "" { - s.WorkDir = "/" - } - if len(s.SeccompProfilePath) < 1 { p, err := libpod.DefaultSeccompPath() if err != nil { diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 4f36744ca..1bc050b00 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -272,10 +272,18 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if s.Entrypoint != nil { options = append(options, libpod.WithEntrypoint(s.Entrypoint)) } - // If the user did not set an workdir but the image did, ensure it is - // created. + // If the user did not specify a workdir on the CLI, let's extract it + // from the image. if s.WorkDir == "" && img != nil { options = append(options, libpod.WithCreateWorkingDir()) + wd, err := img.WorkingDir(ctx) + if err != nil { + return nil, err + } + s.WorkDir = wd + } + if s.WorkDir == "" { + s.WorkDir = "/" } if s.StopSignal != nil { options = append(options, libpod.WithStopSignal(*s.StopSignal)) diff --git a/pkg/terminal/console_windows.go b/pkg/terminal/console_windows.go index c7691857c..08e66cb3a 100644 --- a/pkg/terminal/console_windows.go +++ b/pkg/terminal/console_windows.go @@ -30,7 +30,7 @@ func setConsoleMode(handle windows.Handle, flags uint32) error { if err := windows.SetConsoleMode(handle, mode|flags); err != nil { // In similar code, it is not considered an error if we cannot set the // console mode. Following same line of thinking here. - logrus.WithError(err).Error("Failed to set console mode for cli") + logrus.WithError(err).Debug("Failed to set console mode for cli") } return nil |