diff options
Diffstat (limited to 'pkg/api')
-rw-r--r-- | pkg/api/handlers/compat/containers.go | 39 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_stop.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images.go | 123 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 56 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_push.go | 121 | ||||
-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/compat/version.go | 9 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/copy.go | 12 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images.go | 1 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images_pull.go | 3 | ||||
-rw-r--r-- | pkg/api/handlers/utils/handler.go | 45 | ||||
-rw-r--r-- | pkg/api/handlers/utils/handler_test.go | 5 | ||||
-rw-r--r-- | pkg/api/server/handler_api.go | 7 | ||||
-rw-r--r-- | pkg/api/server/register_archive.go | 2 | ||||
-rw-r--r-- | pkg/api/server/register_pods.go | 1 | ||||
-rw-r--r-- | pkg/api/server/register_secrets.go | 4 |
17 files changed, 352 insertions, 130 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 971b6aa50..d3277b815 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -76,7 +76,12 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { return } if len(report) > 0 && report[0].Err != nil { - utils.InternalServerError(w, report[0].Err) + err = report[0].Err + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.ContainerNotFound(w, name, err) + return + } + utils.InternalServerError(w, err) return } @@ -307,6 +312,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 +347,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 +357,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/containers_stop.go b/pkg/api/handlers/compat/containers_stop.go index 0526865b9..3ae223693 100644 --- a/pkg/api/handlers/compat/containers_stop.go +++ b/pkg/api/handlers/compat/containers_stop.go @@ -39,11 +39,11 @@ func StopContainer(w http.ResponseWriter, r *http.Request) { Ignore: query.Ignore, } if utils.IsLibpodRequest(r) { - if query.LibpodTimeout > 0 { + if _, found := r.URL.Query()["timeout"]; found { options.Timeout = &query.LibpodTimeout } } else { - if query.DockerTimeout > 0 { + if _, found := r.URL.Query()["t"]; found { options.Timeout = &query.DockerTimeout } } 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 2c70352e0..7751b91a7 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -77,6 +77,9 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Devices string `schema:"devices"` Dockerfile string `schema:"dockerfile"` DropCapabilities string `schema:"dropcaps"` + DNSServers string `schema:"dnsservers"` + DNSOptions string `schema:"dnsoptions"` + DNSSearch string `schema:"dnssearch"` Excludes string `schema:"excludes"` ForceRm bool `schema:"forcerm"` From string `schema:"from"` @@ -104,6 +107,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", @@ -159,6 +163,36 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { devices = m } + var dnsservers = []string{} + if _, found := r.URL.Query()["dnsservers"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.DNSServers), &m); err != nil { + utils.BadRequest(w, "dnsservers", query.DNSServers, err) + return + } + dnsservers = m + } + + var dnsoptions = []string{} + if _, found := r.URL.Query()["dnsoptions"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.DNSOptions), &m); err != nil { + utils.BadRequest(w, "dnsoptions", query.DNSOptions, err) + return + } + dnsoptions = m + } + + var dnssearch = []string{} + if _, found := r.URL.Query()["dnssearch"]; found { + var m = []string{} + if err := json.Unmarshal([]byte(query.DNSSearch), &m); err != nil { + utils.BadRequest(w, "dnssearches", query.DNSSearch, err) + return + } + dnssearch = m + } + var output string if len(query.Tag) > 0 { output = query.Tag[0] @@ -221,9 +255,17 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { // convert label formats var labels = []string{} if _, found := r.URL.Query()["labels"]; found { - if err := json.Unmarshal([]byte(query.Labels), &labels); err != nil { - utils.BadRequest(w, "labels", query.Labels, err) - return + makeLabels := make(map[string]string) + err := json.Unmarshal([]byte(query.Labels), &makeLabels) + if err == nil { + for k, v := range makeLabels { + labels = append(labels, k+"="+v) + } + } else { + if err := json.Unmarshal([]byte(query.Labels), &labels); err != nil { + utils.BadRequest(w, "labels", query.Labels, err) + return + } } } jobs := 1 @@ -276,6 +318,9 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { CPUQuota: query.CpuQuota, CPUShares: query.CpuShares, CPUSetCPUs: query.CpuSetCpus, + DNSServers: dnsservers, + DNSOptions: dnsoptions, + DNSSearch: dnssearch, HTTPProxy: query.HTTPProxy, Memory: query.Memory, MemorySwap: query.MemSwap, @@ -318,6 +363,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/images_push.go b/pkg/api/handlers/compat/images_push.go index 4f613338f..db02af445 100644 --- a/pkg/api/handlers/compat/images_push.go +++ b/pkg/api/handlers/compat/images_push.go @@ -1,6 +1,8 @@ package compat import ( + "context" + "encoding/json" "fmt" "io/ioutil" "net/http" @@ -10,11 +12,14 @@ import ( "github.com/containers/podman/v3/libpod" "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/domain/infra/abi" "github.com/containers/storage" + "github.com/docker/docker/pkg/jsonmessage" "github.com/gorilla/schema" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // PushImage is the handler for the compat http endpoint for pushing images. @@ -82,6 +87,8 @@ func PushImage(w http.ResponseWriter, r *http.Request) { Password: password, Username: username, DigestFile: digestFile.Name(), + Quiet: true, + Progress: make(chan types.ProgressProperties), } if _, found := r.URL.Query()["tlsVerify"]; found { options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) @@ -94,31 +101,103 @@ func PushImage(w http.ResponseWriter, r *http.Request) { destination = imageName } - if err := imageEngine.Push(r.Context(), imageName, destination, options); err != nil { - if errors.Cause(err) != storage.ErrImageUnknown { - utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName)) - return + errorWriter := channel.NewWriter(make(chan []byte)) + defer errorWriter.Close() + + statusWriter := channel.NewWriter(make(chan []byte)) + defer statusWriter.Close() + + runCtx, cancel := context.WithCancel(context.Background()) + var failed bool + + go func() { + defer cancel() + + statusWriter.Write([]byte(fmt.Sprintf("The push refers to repository [%s]", imageName))) + + err := imageEngine.Push(runCtx, imageName, destination, options) + if err != nil { + if errors.Cause(err) != storage.ErrImageUnknown { + errorWriter.Write([]byte("An image does not exist locally with the tag: " + imageName)) + } else { + errorWriter.Write([]byte(err.Error())) + } } + }() - utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "error pushing image %q", imageName)) - return + flush := func() { + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } } - digestBytes, err := ioutil.ReadAll(digestFile) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to read digest tmp file")) - return - } + w.WriteHeader(http.StatusOK) + w.Header().Add("Content-Type", "application/json") + flush() - tag := query.Tag - if tag == "" { - tag = "latest" - } - respData := struct { - Status string `json:"status"` - }{ - Status: fmt.Sprintf("%s: digest: %s size: null", tag, string(digestBytes)), - } + enc := json.NewEncoder(w) + enc.SetEscapeHTML(true) + +loop: // break out of for/select infinite loop + for { + var report jsonmessage.JSONMessage - utils.WriteJSON(w, http.StatusOK, &respData) + select { + case e := <-options.Progress: + switch e.Event { + case types.ProgressEventNewArtifact: + report.Status = "Preparing" + case types.ProgressEventRead: + report.Status = "Pushing" + report.Progress = &jsonmessage.JSONProgress{ + Current: int64(e.Offset), + Total: e.Artifact.Size, + } + case types.ProgressEventSkipped: + report.Status = "Layer already exists" + case types.ProgressEventDone: + report.Status = "Pushed" + } + report.ID = e.Artifact.Digest.Encoded()[0:12] + if err := enc.Encode(report); err != nil { + errorWriter.Write([]byte(err.Error())) + } + flush() + case e := <-statusWriter.Chan(): + report.Status = string(e) + if err := enc.Encode(report); err != nil { + errorWriter.Write([]byte(err.Error())) + } + flush() + case e := <-errorWriter.Chan(): + failed = true + report.Error = &jsonmessage.JSONError{ + Message: string(e), + } + report.ErrorMessage = 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 { + digestBytes, err := ioutil.ReadAll(digestFile) + if err == nil { + tag := query.Tag + if tag == "" { + tag = "latest" + } + report.Status = fmt.Sprintf("%s: digest: %s", tag, string(digestBytes)) + 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 + } + } } 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/compat/version.go b/pkg/api/handlers/compat/version.go index d90a892c1..fae147440 100644 --- a/pkg/api/handlers/compat/version.go +++ b/pkg/api/handlers/compat/version.go @@ -10,6 +10,7 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/api/handlers/utils" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/version" docker "github.com/docker/docker/api/types" "github.com/pkg/errors" ) @@ -35,20 +36,20 @@ func VersionHandler(w http.ResponseWriter, r *http.Request) { Name: "Podman Engine", Version: versionInfo.Version, Details: map[string]string{ - "APIVersion": utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String(), + "APIVersion": version.APIVersion[version.Libpod][version.CurrentAPI].String(), "Arch": goRuntime.GOARCH, "BuildTime": time.Unix(versionInfo.Built, 0).Format(time.RFC3339), "Experimental": "true", "GitCommit": versionInfo.GitCommit, "GoVersion": versionInfo.GoVersion, "KernelVersion": infoData.Host.Kernel, - "MinAPIVersion": utils.APIVersion[utils.LibpodTree][utils.MinimalAPIVersion].String(), + "MinAPIVersion": version.APIVersion[version.Libpod][version.MinimalAPI].String(), "Os": goRuntime.GOOS, }, }} - apiVersion := utils.APIVersion[utils.CompatTree][utils.CurrentAPIVersion] - minVersion := utils.APIVersion[utils.CompatTree][utils.MinimalAPIVersion] + apiVersion := version.APIVersion[version.Compat][version.CurrentAPI] + minVersion := version.APIVersion[version.Compat][version.MinimalAPI] utils.WriteResponse(w, http.StatusOK, entities.ComponentVersion{ Version: docker.Version{ diff --git a/pkg/api/handlers/libpod/copy.go b/pkg/api/handlers/libpod/copy.go deleted file mode 100644 index 4b345bacc..000000000 --- a/pkg/api/handlers/libpod/copy.go +++ /dev/null @@ -1,12 +0,0 @@ -package libpod - -import ( - "net/http" - - "github.com/containers/podman/v3/pkg/api/handlers/utils" - "github.com/pkg/errors" -) - -func Archive(w http.ResponseWriter, r *http.Request) { - utils.Error(w, "not implemented", http.StatusNotImplemented, errors.New("not implemented")) -} diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 1a2483784..83fe23621 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -451,6 +451,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) { Password: password, Format: query.Format, All: query.All, + Quiet: true, } if _, found := r.URL.Query()["tlsVerify"]; found { options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) 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/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go index b3c674788..7625f9546 100644 --- a/pkg/api/handlers/utils/handler.go +++ b/pkg/api/handlers/utils/handler.go @@ -10,49 +10,14 @@ import ( "unsafe" "github.com/blang/semver" + "github.com/containers/podman/v3/version" "github.com/gorilla/mux" jsoniter "github.com/json-iterator/go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) -type ( - // VersionTree determines which API endpoint tree for version - VersionTree int - // VersionLevel determines which API level, current or something from the past - VersionLevel int -) - -const ( - // LibpodTree supports Libpod endpoints - LibpodTree = VersionTree(iota) - // CompatTree supports Libpod endpoints - CompatTree - - // CurrentAPIVersion announces what is the current API level - CurrentAPIVersion = VersionLevel(iota) - // MinimalAPIVersion announces what is the oldest API level supported - MinimalAPIVersion -) - var ( - // See https://docs.docker.com/engine/api/v1.40/ - // libpod compat handlers are expected to honor docker API versions - - // APIVersion provides the current and minimal API versions for compat and libpod endpoint trees - // Note: GET|HEAD /_ping is never versioned and provides the API-Version and Libpod-API-Version headers to allow - // clients to shop for the Version they wish to support - APIVersion = map[VersionTree]map[VersionLevel]semver.Version{ - LibpodTree: { - CurrentAPIVersion: semver.MustParse("3.0.0"), - MinimalAPIVersion: semver.MustParse("3.0.0"), - }, - CompatTree: { - CurrentAPIVersion: semver.MustParse("1.40.0"), - MinimalAPIVersion: semver.MustParse("1.24.0"), - }, - } - // ErrVersionNotGiven returned when version not given by client ErrVersionNotGiven = errors.New("version not given in URL path") // ErrVersionNotSupported returned when given version is too old @@ -98,14 +63,14 @@ func SupportedVersion(r *http.Request, condition string) (semver.Version, error) // SupportedVersionWithDefaults validates that the version provided by client valid is supported by server // minimal API version <= client path version <= maximum API version focused on the endpoint tree from URL func SupportedVersionWithDefaults(r *http.Request) (semver.Version, error) { - tree := CompatTree + tree := version.Compat if IsLibpodRequest(r) { - tree = LibpodTree + tree = version.Libpod } return SupportedVersion(r, - fmt.Sprintf(">=%s <=%s", APIVersion[tree][MinimalAPIVersion].String(), - APIVersion[tree][CurrentAPIVersion].String())) + fmt.Sprintf(">=%s <=%s", version.APIVersion[tree][version.MinimalAPI].String(), + version.APIVersion[tree][version.CurrentAPI].String())) } // WriteResponse encodes the given value as JSON or string and renders it for http client diff --git a/pkg/api/handlers/utils/handler_test.go b/pkg/api/handlers/utils/handler_test.go index d9fd22b80..18a1d2678 100644 --- a/pkg/api/handlers/utils/handler_test.go +++ b/pkg/api/handlers/utils/handler_test.go @@ -7,17 +7,18 @@ import ( "net/http/httptest" "testing" + "github.com/containers/podman/v3/version" "github.com/gorilla/mux" ) func TestSupportedVersion(t *testing.T) { req, err := http.NewRequest("GET", - fmt.Sprintf("/v%s/libpod/testing/versions", APIVersion[LibpodTree][CurrentAPIVersion]), + fmt.Sprintf("/v%s/libpod/testing/versions", version.APIVersion[version.Libpod][version.CurrentAPI]), nil) if err != nil { t.Fatal(err) } - req = mux.SetURLVars(req, map[string]string{"version": APIVersion[LibpodTree][CurrentAPIVersion].String()}) + req = mux.SetURLVars(req, map[string]string{"version": version.APIVersion[version.Libpod][version.CurrentAPI].String()}) rr := httptest.NewRecorder() handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go index e7bf94fc6..28b8706a8 100644 --- a/pkg/api/server/handler_api.go +++ b/pkg/api/server/handler_api.go @@ -8,6 +8,7 @@ import ( "github.com/containers/podman/v3/pkg/api/handlers/utils" "github.com/containers/podman/v3/pkg/auth" + "github.com/containers/podman/v3/version" "github.com/google/uuid" "github.com/sirupsen/logrus" ) @@ -55,10 +56,10 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc { c = context.WithValue(c, "idletracker", s.idleTracker) // nolint r = r.WithContext(c) - cv := utils.APIVersion[utils.CompatTree][utils.CurrentAPIVersion] + cv := version.APIVersion[version.Compat][version.CurrentAPI] w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor)) - lv := utils.APIVersion[utils.LibpodTree][utils.CurrentAPIVersion].String() + lv := version.APIVersion[version.Libpod][version.CurrentAPI].String() w.Header().Set("Libpod-API-Version", lv) w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")") @@ -72,5 +73,5 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc { // VersionedPath prepends the version parsing code // any handler may override this default when registering URL(s) func VersionedPath(p string) string { - return "/v{version:[0-9][0-9.]*}" + p + return "/v{version:[0-9][0-9A-Za-z.-]*}" + p } 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_pods.go b/pkg/api/server/register_pods.go index 949bf80e2..c66cc48ff 100644 --- a/pkg/api/server/register_pods.go +++ b/pkg/api/server/register_pods.go @@ -36,7 +36,6 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // name: create // description: attributes for creating a pod // schema: - // type: object // $ref: "#/definitions/PodSpecGenerator" // responses: // 200: 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': |