diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/containers.go | 32 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images.go | 123 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 6 | ||||
-rw-r--r-- | pkg/api/handlers/compat/networks.go | 18 | ||||
-rw-r--r-- | pkg/api/handlers/compat/secrets.go | 32 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images_pull.go | 3 | ||||
-rw-r--r-- | pkg/api/server/register_archive.go | 2 | ||||
-rw-r--r-- | pkg/api/server/register_secrets.go | 4 | ||||
-rw-r--r-- | pkg/autoupdate/autoupdate.go | 1 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 6 | ||||
-rw-r--r-- | pkg/checkpoint/checkpoint_restore.go | 36 | ||||
-rw-r--r-- | pkg/checkpoint/crutils/checkpoint_restore_utils.go | 191 | ||||
-rw-r--r-- | pkg/domain/entities/secrets.go | 23 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 2 |
15 files changed, 413 insertions, 70 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 971b6aa50..d26bb50f4 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -307,6 +307,34 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error } } + portMappings, err := l.PortMappings() + if err != nil { + return nil, err + } + + ports := make([]types.Port, len(portMappings)) + for idx, portMapping := range portMappings { + ports[idx] = types.Port{ + IP: portMapping.HostIP, + PrivatePort: uint16(portMapping.ContainerPort), + PublicPort: uint16(portMapping.HostPort), + Type: portMapping.Protocol, + } + } + inspect, err := l.Inspect(false) + if err != nil { + return nil, err + } + + n, err := json.Marshal(inspect.NetworkSettings) + if err != nil { + return nil, err + } + networkSettings := types.SummaryNetworkSettings{} + if err := json.Unmarshal(n, &networkSettings); err != nil { + return nil, err + } + return &handlers.Container{Container: types.Container{ ID: l.ID(), Names: []string{fmt.Sprintf("/%s", l.Name())}, @@ -314,7 +342,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error ImageID: imageID, Command: strings.Join(l.Command(), " "), Created: l.CreatedTime().Unix(), - Ports: nil, + Ports: ports, SizeRw: sizeRW, SizeRootFs: sizeRootFs, Labels: l.Labels(), @@ -324,7 +352,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error NetworkMode string `json:",omitempty"` }{ "host"}, - NetworkSettings: nil, + NetworkSettings: &networkSettings, Mounts: nil, }, ContainerCreateConfig: types.ContainerCreateConfig{}, diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index 1a4dd939e..e5caa9ea5 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -1,6 +1,7 @@ package compat import ( + "context" "encoding/json" "fmt" "io" @@ -11,11 +12,13 @@ import ( "github.com/containers/buildah" "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/types" "github.com/containers/podman/v3/libpod" image2 "github.com/containers/podman/v3/libpod/image" "github.com/containers/podman/v3/pkg/api/handlers" "github.com/containers/podman/v3/pkg/api/handlers/utils" "github.com/containers/podman/v3/pkg/auth" + "github.com/containers/podman/v3/pkg/channel" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/util" "github.com/gorilla/schema" @@ -236,33 +239,103 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) { if sys := runtime.SystemContext(); sys != nil { registryOpts.DockerCertPath = sys.DockerCertPath } - img, err := runtime.ImageRuntime().New(r.Context(), - fromImage, - "", // signature policy - authfile, - nil, // writer - ®istryOpts, - image2.SigningOptions{}, - nil, // label - util.PullImageAlways, - ) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) - return + + stderr := channel.NewWriter(make(chan []byte)) + defer stderr.Close() + + progress := make(chan types.ProgressProperties) + + var img string + runCtx, cancel := context.WithCancel(context.Background()) + go func() { + defer cancel() + + newImage, err := runtime.ImageRuntime().New( + runCtx, + fromImage, + "", // signature policy + authfile, + nil, // writer + ®istryOpts, + image2.SigningOptions{}, + nil, // label + util.PullImageAlways, + progress) + if err != nil { + stderr.Write([]byte(err.Error() + "\n")) + } else { + img = newImage.ID() + } + }() + + flush := func() { + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } } - // Success - utils.WriteResponse(w, http.StatusOK, struct { - Status string `json:"status"` - Error string `json:"error,omitempty"` - Progress string `json:"progress"` - ProgressDetail map[string]string `json:"progressDetail"` - Id string `json:"id"` // nolint - }{ - Status: fmt.Sprintf("pulling image (%s) from %s (Download complete)", img.Tag, strings.Join(img.Names(), ", ")), - ProgressDetail: map[string]string{}, - Id: img.ID(), - }) + w.WriteHeader(http.StatusOK) + w.Header().Add("Content-Type", "application/json") + flush() + + enc := json.NewEncoder(w) + enc.SetEscapeHTML(true) + var failed bool + +loop: // break out of for/select infinite loop + for { + var report struct { + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress struct { + Current uint64 `json:"current,omitempty"` + Total int64 `json:"total,omitempty"` + } `json:"progressDetail,omitempty"` + Error string `json:"error,omitempty"` + Id string `json:"id,omitempty"` // nolint + } + + select { + case e := <-progress: + switch e.Event { + case types.ProgressEventNewArtifact: + report.Status = "Pulling fs layer" + case types.ProgressEventRead: + report.Status = "Downloading" + report.Progress.Current = e.Offset + report.Progress.Total = e.Artifact.Size + case types.ProgressEventSkipped: + report.Status = "Already exists" + case types.ProgressEventDone: + report.Status = "Download complete" + } + report.Id = e.Artifact.Digest.Encoded()[0:12] + if err := enc.Encode(report); err != nil { + stderr.Write([]byte(err.Error())) + } + flush() + case e := <-stderr.Chan(): + failed = true + report.Error = string(e) + if err := enc.Encode(report); err != nil { + logrus.Warnf("Failed to json encode error %q", err.Error()) + } + flush() + case <-runCtx.Done(): + if !failed { + report.Status = "Pull complete" + report.Id = img[0:12] + if err := enc.Encode(report); err != nil { + logrus.Warnf("Failed to json encode error %q", err.Error()) + } + flush() + } + break loop // break out of for/select infinite loop + case <-r.Context().Done(): + // Client has closed connection + break loop // break out of for/select infinite loop + } + } } func GetImage(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index d79b100e8..009fcf7e8 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -104,6 +104,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Squash bool `schema:"squash"` Tag []string `schema:"t"` Target string `schema:"target"` + Timestamp int64 `schema:"timestamp"` }{ Dockerfile: "Dockerfile", Registry: "docker.io", @@ -318,6 +319,11 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Target: query.Target, } + if _, found := r.URL.Query()["timestamp"]; found { + ts := time.Unix(query.Timestamp, 0) + buildOptions.Timestamp = &ts + } + runCtx, cancel := context.WithCancel(context.Background()) var imageID string go func() { diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 1a04b4289..28e90ac28 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -180,16 +180,18 @@ func findPluginByName(plugins []*libcni.NetworkConfig, pluginType string) ([]byt func ListNetworks(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - query := struct { - Filters map[string][]string `schema:"filters"` - }{ - // override any golang type defaults - } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { + filters, err := filtersFromRequest(r) + if err != nil { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } + filterMap := map[string][]string{} + for _, filter := range filters { + split := strings.SplitN(filter, "=", 2) + if len(split) > 1 { + filterMap[split[0]] = append(filterMap[split[0]], split[1]) + } + } config, err := runtime.GetConfig() if err != nil { utils.InternalServerError(w, err) @@ -205,7 +207,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) { reports := []*types.NetworkResource{} logrus.Debugf("netNames: %q", strings.Join(netNames, ", ")) for _, name := range netNames { - report, err := getNetworkResourceByNameOrID(name, runtime, query.Filters) + report, err := getNetworkResourceByNameOrID(name, runtime, filterMap) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/handlers/compat/secrets.go b/pkg/api/handlers/compat/secrets.go index c5ee8c324..86e3887a4 100644 --- a/pkg/api/handlers/compat/secrets.go +++ b/pkg/api/handlers/compat/secrets.go @@ -40,7 +40,21 @@ func ListSecrets(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) return } - utils.WriteResponse(w, http.StatusOK, reports) + if utils.IsLibpodRequest(r) { + utils.WriteResponse(w, http.StatusOK, reports) + return + } + // Docker compat expects a version field that increments when the secret is updated + // We currently can't update a secret, so we default the version to 1 + compatReports := make([]entities.SecretInfoReportCompat, 0, len(reports)) + for _, report := range reports { + compatRep := entities.SecretInfoReportCompat{ + SecretInfoReport: *report, + Version: entities.SecretVersion{Index: 1}, + } + compatReports = append(compatReports, compatRep) + } + utils.WriteResponse(w, http.StatusOK, compatReports) } func InspectSecret(w http.ResponseWriter, r *http.Request) { @@ -59,7 +73,21 @@ func InspectSecret(w http.ResponseWriter, r *http.Request) { utils.SecretNotFound(w, name, errs[0]) return } - utils.WriteResponse(w, http.StatusOK, reports[0]) + if len(reports) < 1 { + utils.InternalServerError(w, err) + return + } + if utils.IsLibpodRequest(r) { + utils.WriteResponse(w, http.StatusOK, reports[0]) + return + } + // Docker compat expects a version field that increments when the secret is updated + // We currently can't update a secret, so we default the version to 1 + compatReport := entities.SecretInfoReportCompat{ + SecretInfoReport: *reports[0], + Version: entities.SecretVersion{Index: 1}, + } + utils.WriteResponse(w, http.StatusOK, compatReport) } func RemoveSecret(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index c8b777be4..e2e4b53b4 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -136,7 +136,8 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { &dockerRegistryOptions, image.SigningOptions{}, nil, - util.PullImageAlways) + util.PullImageAlways, + nil) if err != nil { stderr.Write([]byte(err.Error() + "\n")) } else { diff --git a/pkg/api/server/register_archive.go b/pkg/api/server/register_archive.go index 2a5cfba0b..2ac126644 100644 --- a/pkg/api/server/register_archive.go +++ b/pkg/api/server/register_archive.go @@ -91,7 +91,7 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error { Libpod */ - // swagger:operation POST /libpod/containers/{name}/archive libpod libpodPutArchive + // swagger:operation PUT /libpod/containers/{name}/archive libpod libpodPutArchive // --- // summary: Copy files into a container // description: Copy a tar archive of files into a container diff --git a/pkg/api/server/register_secrets.go b/pkg/api/server/register_secrets.go index 1c5f5954b..531623845 100644 --- a/pkg/api/server/register_secrets.go +++ b/pkg/api/server/register_secrets.go @@ -115,7 +115,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // parameters: // responses: // '200': - // "$ref": "#/responses/SecretListResponse" + // "$ref": "#/responses/SecretListCompatResponse" // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/secrets"), s.APIHandler(compat.ListSecrets)).Methods(http.MethodGet) @@ -158,7 +158,7 @@ func (s *APIServer) registerSecretHandlers(r *mux.Router) error { // - application/json // responses: // '200': - // "$ref": "#/responses/SecretInspectResponse" + // "$ref": "#/responses/SecretInspectCompatResponse" // '404': // "$ref": "#/responses/NoSuchSecret" // '500': diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index 0cf51e5a6..53095c295 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -304,6 +304,7 @@ func updateImage(runtime *libpod.Runtime, name string, options Options) (*image. image.SigningOptions{}, nil, util.PullImageAlways, + nil, ) if err != nil { return nil, err diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 6e16461e5..27706fd2c 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -185,6 +185,12 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO if options.Squash { params.Set("squash", "1") } + + if options.Timestamp != nil { + t := *options.Timestamp + params.Set("timestamp", strconv.FormatInt(t.Unix(), 10)) + } + var ( headers map[string]string err error diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go index a608762b5..77a993128 100644 --- a/pkg/checkpoint/checkpoint_restore.go +++ b/pkg/checkpoint/checkpoint_restore.go @@ -4,15 +4,14 @@ import ( "context" "io/ioutil" "os" - "path/filepath" + metadata "github.com/checkpoint-restore/checkpointctl/lib" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/image" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/util" "github.com/containers/storage/pkg/archive" - jsoniter "github.com/json-iterator/go" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -20,21 +19,6 @@ import ( // Prefixing the checkpoint/restore related functions with 'cr' -// crImportFromJSON imports the JSON files stored in the exported -// checkpoint tarball -func crImportFromJSON(filePath string, v interface{}) error { - content, err := ioutil.ReadFile(filePath) - if err != nil { - return errors.Wrap(err, "failed to read container definition for restore") - } - json := jsoniter.ConfigCompatibleWithStandardLibrary - if err = json.Unmarshal(content, v); err != nil { - return errors.Wrapf(err, "failed to unmarshal container definition %s for restore", filePath) - } - - return nil -} - // CRImportCheckpoint it the function which imports the information // from checkpoint tarball and re-creates the container from that information func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOptions entities.RestoreOptions) ([]*libpod.Container, error) { @@ -48,13 +32,13 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt options := &archive.TarOptions{ // Here we only need the files config.dump and spec.dump ExcludePatterns: []string{ - "checkpoint", - "artifacts", - "ctr.log", - "rootfs-diff.tar", - "network.status", - "deleted.files", "volumes", + "ctr.log", + "artifacts", + metadata.RootFsDiffTar, + metadata.DeletedFilesFile, + metadata.NetworkStatusFile, + metadata.CheckpointDirectory, }, } dir, err := ioutil.TempDir("", "checkpoint") @@ -73,13 +57,13 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt // Load spec.dump from temporary directory dumpSpec := new(spec.Spec) - if err := crImportFromJSON(filepath.Join(dir, "spec.dump"), dumpSpec); err != nil { + if _, err := metadata.ReadJSONFile(dumpSpec, dir, metadata.SpecDumpFile); err != nil { return nil, err } // Load config.dump from temporary directory config := new(libpod.ContainerConfig) - if err = crImportFromJSON(filepath.Join(dir, "config.dump"), config); err != nil { + if _, err = metadata.ReadJSONFile(config, dir, metadata.ConfigDumpFile); err != nil { return nil, err } @@ -121,7 +105,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt return nil, err } - _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.Engine.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing) + _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.Engine.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing, nil) if err != nil { return nil, err } diff --git a/pkg/checkpoint/crutils/checkpoint_restore_utils.go b/pkg/checkpoint/crutils/checkpoint_restore_utils.go new file mode 100644 index 000000000..53ff55865 --- /dev/null +++ b/pkg/checkpoint/crutils/checkpoint_restore_utils.go @@ -0,0 +1,191 @@ +package crutils + +import ( + "io" + "os" + "os/exec" + "path/filepath" + + metadata "github.com/checkpoint-restore/checkpointctl/lib" + "github.com/containers/storage/pkg/archive" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/pkg/errors" +) + +// This file mainly exist to make the checkpoint/restore functions +// available for other users. One possible candidate would be CRI-O. + +// CRImportCheckpointWithoutConfig imports the checkpoint archive (input) +// into the directory destination without "config.dump" and "spec.dump" +func CRImportCheckpointWithoutConfig(destination, input string) error { + archiveFile, err := os.Open(input) + if err != nil { + return errors.Wrapf(err, "Failed to open checkpoint archive %s for import", input) + } + + defer archiveFile.Close() + options := &archive.TarOptions{ + ExcludePatterns: []string{ + // Import everything else besides the container config + metadata.ConfigDumpFile, + metadata.SpecDumpFile, + }, + } + if err = archive.Untar(archiveFile, destination, options); err != nil { + return errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", input) + } + + return nil +} + +// CRRemoveDeletedFiles loads the list of deleted files and if +// it exists deletes all files listed. +func CRRemoveDeletedFiles(id, baseDirectory, containerRootDirectory string) error { + deletedFiles, _, err := metadata.ReadContainerCheckpointDeletedFiles(baseDirectory) + if os.IsNotExist(errors.Unwrap(errors.Unwrap(err))) { + // No files to delete. Just return + return nil + } + + if err != nil { + return errors.Wrapf(err, "failed to read deleted files file") + } + + for _, deleteFile := range deletedFiles { + // Using RemoveAll as deletedFiles, which is generated from 'podman diff' + // lists completely deleted directories as a single entry: 'D /root'. + if err := os.RemoveAll(filepath.Join(containerRootDirectory, deleteFile)); err != nil { + return errors.Wrapf(err, "failed to delete files from container %s during restore", id) + } + } + + return nil +} + +// CRApplyRootFsDiffTar applies the tar archive found in baseDirectory with the +// root file system changes on top of containerRootDirectory +func CRApplyRootFsDiffTar(baseDirectory, containerRootDirectory string) error { + rootfsDiffPath := filepath.Join(baseDirectory, metadata.RootFsDiffTar) + if _, err := os.Stat(rootfsDiffPath); err != nil { + // Only do this if a rootfs-diff.tar actually exists + return nil + } + + rootfsDiffFile, err := os.Open(rootfsDiffPath) + if err != nil { + return errors.Wrap(err, "failed to open root file-system diff file") + } + defer rootfsDiffFile.Close() + + if err := archive.Untar(rootfsDiffFile, containerRootDirectory, nil); err != nil { + return errors.Wrapf(err, "failed to apply root file-system diff file %s", rootfsDiffPath) + } + + return nil +} + +// CRCreateRootFsDiffTar goes through the 'changes' and can create two files: +// * metadata.RootFsDiffTar will contain all new and changed files +// * metadata.DeletedFilesFile will contain a list of deleted files +// With these two files it is possible to restore the container file system to the same +// state it was during checkpointing. +// Changes to directories (owner, mode) are not handled. +func CRCreateRootFsDiffTar(changes *[]archive.Change, mountPoint, destination string) (includeFiles []string, err error) { + if len(*changes) == 0 { + return includeFiles, nil + } + + var rootfsIncludeFiles []string + var deletedFiles []string + + rootfsDiffPath := filepath.Join(destination, metadata.RootFsDiffTar) + + for _, file := range *changes { + if file.Kind == archive.ChangeAdd { + rootfsIncludeFiles = append(rootfsIncludeFiles, file.Path) + continue + } + if file.Kind == archive.ChangeDelete { + deletedFiles = append(deletedFiles, file.Path) + continue + } + fileName, err := os.Stat(file.Path) + if err != nil { + continue + } + if !fileName.IsDir() && file.Kind == archive.ChangeModify { + rootfsIncludeFiles = append(rootfsIncludeFiles, file.Path) + continue + } + } + + if len(rootfsIncludeFiles) > 0 { + rootfsTar, err := archive.TarWithOptions(mountPoint, &archive.TarOptions{ + Compression: archive.Uncompressed, + IncludeSourceDir: true, + IncludeFiles: rootfsIncludeFiles, + }) + if err != nil { + return includeFiles, errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath) + } + rootfsDiffFile, err := os.Create(rootfsDiffPath) + if err != nil { + return includeFiles, errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath) + } + defer rootfsDiffFile.Close() + if _, err = io.Copy(rootfsDiffFile, rootfsTar); err != nil { + return includeFiles, err + } + + includeFiles = append(includeFiles, metadata.RootFsDiffTar) + } + + if len(deletedFiles) == 0 { + return includeFiles, nil + } + + if _, err := metadata.WriteJSONFile(deletedFiles, destination, metadata.DeletedFilesFile); err != nil { + return includeFiles, nil + } + + includeFiles = append(includeFiles, metadata.DeletedFilesFile) + + return includeFiles, nil +} + +// CRCreateFileWithLabel creates an empty file and sets the corresponding ('fileLabel') +// SELinux label on the file. +// This is necessary for CRIU log files because CRIU infects the processes in +// the container with a 'parasite' and this will also try to write to the log files +// from the context of the container processes. +func CRCreateFileWithLabel(directory, fileName, fileLabel string) error { + logFileName := filepath.Join(directory, fileName) + + logFile, err := os.OpenFile(logFileName, os.O_CREATE, 0o600) + if err != nil { + return errors.Wrapf(err, "failed to create file %q", logFileName) + } + defer logFile.Close() + if err = label.SetFileLabel(logFileName, fileLabel); err != nil { + return errors.Wrapf(err, "failed to label file %q", logFileName) + } + + return nil +} + +// CRRuntimeSupportsCheckpointRestore tests if the given runtime at 'runtimePath' +// supports checkpointing. The checkpoint restore interface has no definition +// but crun implements all commands just as runc does. Whathh runc does it the +// official definition of the checkpoint/restore interface. +func CRRuntimeSupportsCheckpointRestore(runtimePath string) bool { + // Check if the runtime implements checkpointing. Currently only + // runc's and crun's checkpoint/restore implementation is supported. + cmd := exec.Command(runtimePath, "checkpoint", "--help") + if err := cmd.Start(); err != nil { + return false + } + if err := cmd.Wait(); err == nil { + return true + } + return false +} diff --git a/pkg/domain/entities/secrets.go b/pkg/domain/entities/secrets.go index 3481cbe05..8ede981da 100644 --- a/pkg/domain/entities/secrets.go +++ b/pkg/domain/entities/secrets.go @@ -42,6 +42,15 @@ type SecretInfoReport struct { Spec SecretSpec } +type SecretInfoReportCompat struct { + SecretInfoReport + Version SecretVersion +} + +type SecretVersion struct { + Index int +} + type SecretSpec struct { Name string Driver SecretDriverSpec @@ -78,6 +87,13 @@ type SwagSecretListResponse struct { Body []*SecretInfoReport } +// Secret list response +// swagger:response SecretListCompatResponse +type SwagSecretListCompatResponse struct { + // in:body + Body []*SecretInfoReportCompat +} + // Secret inspect response // swagger:response SecretInspectResponse type SwagSecretInspectResponse struct { @@ -85,6 +101,13 @@ type SwagSecretInspectResponse struct { Body SecretInfoReport } +// Secret inspect compat +// swagger:response SecretInspectCompatResponse +type SwagSecretInspectCompatResponse struct { + // in:body + Body SecretInfoReportCompat +} + // No such secret // swagger:response NoSuchSecret type SwagErrNoSuchSecret struct { diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 46d967789..562653403 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -247,7 +247,7 @@ func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options } if !options.AllTags { - newImage, err := runtime.New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, label, options.PullPolicy) + newImage, err := runtime.New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, label, options.PullPolicy, nil) if err != nil { return nil, err } @@ -280,7 +280,7 @@ func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options foundIDs := []string{} for _, tag := range tags { name := rawImage + ":" + tag - newImage, err := runtime.New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) + newImage, err := runtime.New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways, nil) if err != nil { logrus.Errorf("error pulling image %q", name) continue diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index c5e20a607..b7ca69281 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -221,7 +221,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } // This ensures the image is the image store - newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy) + newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy, nil) if err != nil { return nil, err } |