diff options
author | Jhon Honce <jhonce@redhat.com> | 2020-03-09 14:18:44 +0100 |
---|---|---|
committer | Jhon Honce <jhonce@redhat.com> | 2020-03-10 08:03:41 -0700 |
commit | 31112e4b087612f7d63e83d770263b8b9fa4f206 (patch) | |
tree | e27af2df4e9c2c24f6a245e245ccc96d5fe1706b /pkg/api/handlers/generic | |
parent | 684813fb3effbd7a483e44233ed395eb49c7fded (diff) | |
download | podman-31112e4b087612f7d63e83d770263b8b9fa4f206.tar.gz podman-31112e4b087612f7d63e83d770263b8b9fa4f206.tar.bz2 podman-31112e4b087612f7d63e83d770263b8b9fa4f206.zip |
Refactor handler packages
To help with packaging, the handlers in pkg/api/handlers are now found
in pkg/api/handler/compat.
Signed-off-by: Jhon Honce <jhonce@redhat.com>
Diffstat (limited to 'pkg/api/handlers/generic')
-rw-r--r-- | pkg/api/handlers/generic/containers.go | 295 | ||||
-rw-r--r-- | pkg/api/handlers/generic/containers_create.go | 216 | ||||
-rw-r--r-- | pkg/api/handlers/generic/containers_stats.go | 211 | ||||
-rw-r--r-- | pkg/api/handlers/generic/images.go | 362 | ||||
-rw-r--r-- | pkg/api/handlers/generic/info.go | 196 | ||||
-rw-r--r-- | pkg/api/handlers/generic/swagger.go | 27 | ||||
-rw-r--r-- | pkg/api/handlers/generic/system.go | 18 | ||||
-rw-r--r-- | pkg/api/handlers/generic/types.go | 55 |
8 files changed, 0 insertions, 1380 deletions
diff --git a/pkg/api/handlers/generic/containers.go b/pkg/api/handlers/generic/containers.go deleted file mode 100644 index b8460702c..000000000 --- a/pkg/api/handlers/generic/containers.go +++ /dev/null @@ -1,295 +0,0 @@ -package generic - -import ( - "encoding/binary" - "fmt" - "net/http" - "strconv" - "strings" - "sync" - "time" - - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/logs" - "github.com/containers/libpod/pkg/api/handlers" - "github.com/containers/libpod/pkg/api/handlers/utils" - "github.com/containers/libpod/pkg/util" - "github.com/gorilla/schema" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" -) - -func RemoveContainer(w http.ResponseWriter, r *http.Request) { - decoder := r.Context().Value("decoder").(*schema.Decoder) - query := struct { - Force bool `schema:"force"` - Vols bool `schema:"v"` - Link bool `schema:"link"` - }{ - // override any golang type defaults - } - - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) - return - } - if query.Link { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - utils.ErrLinkNotSupport) - return - } - utils.RemoveContainer(w, r, query.Force, query.Vols) -} - -func ListContainers(w http.ResponseWriter, r *http.Request) { - var ( - containers []*libpod.Container - err error - ) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - query := struct { - All bool `schema:"all"` - Limit int `schema:"limit"` - Size bool `schema:"size"` - Filters map[string][]string `schema:"filters"` - }{ - // override any golang type defaults - } - - 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 - } - if query.All { - containers, err = runtime.GetAllContainers() - } else { - containers, err = runtime.GetRunningContainers() - } - if err != nil { - utils.InternalServerError(w, err) - return - } - if _, found := r.URL.Query()["limit"]; found { - last := query.Limit - if len(containers) > last { - containers = containers[len(containers)-last:] - } - } - // TODO filters still need to be applied - infoData, err := runtime.Info() - if err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain system info")) - return - } - - var list = make([]*handlers.Container, len(containers)) - for i, ctnr := range containers { - api, err := handlers.LibpodToContainer(ctnr, infoData, query.Size) - if err != nil { - utils.InternalServerError(w, err) - return - } - list[i] = api - } - utils.WriteResponse(w, http.StatusOK, list) -} - -func GetContainer(w http.ResponseWriter, r *http.Request) { - runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - query := struct { - Size bool `schema:"size"` - }{ - // override any golang type defaults - } - - 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 - } - - name := utils.GetName(r) - ctnr, err := runtime.LookupContainer(name) - if err != nil { - utils.ContainerNotFound(w, name, err) - return - } - api, err := handlers.LibpodToContainerJSON(ctnr, query.Size) - if err != nil { - utils.InternalServerError(w, err) - return - } - utils.WriteResponse(w, http.StatusOK, api) -} - -func KillContainer(w http.ResponseWriter, r *http.Request) { - // /{version}/containers/(name)/kill - con, err := utils.KillContainer(w, r) - if err != nil { - return - } - // the kill behavior for docker differs from podman in that they appear to wait - // for the Container to croak so the exit code is accurate immediately after the - // kill is sent. libpod does not. but we can add a wait here only for the docker - // side of things and mimic that behavior - if _, err = con.Wait(); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to wait for Container %s", con.ID())) - return - } - // Success - utils.WriteResponse(w, http.StatusNoContent, "") -} - -func WaitContainer(w http.ResponseWriter, r *http.Request) { - var msg string - // /{version}/containers/(name)/wait - exitCode, err := utils.WaitContainer(w, r) - if err != nil { - return - } - utils.WriteResponse(w, http.StatusOK, handlers.ContainerWaitOKBody{ - StatusCode: int(exitCode), - Error: struct { - Message string - }{ - Message: msg, - }, - }) -} - -func LogsFromContainer(w http.ResponseWriter, r *http.Request) { - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - Follow bool `schema:"follow"` - Stdout bool `schema:"stdout"` - Stderr bool `schema:"stderr"` - Since string `schema:"since"` - Until string `schema:"until"` - Timestamps bool `schema:"timestamps"` - Tail string `schema:"tail"` - }{ - Tail: "all", - } - 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 - } - - if !(query.Stdout || query.Stderr) { - msg := fmt.Sprintf("%s: you must choose at least one stream", http.StatusText(http.StatusBadRequest)) - utils.Error(w, msg, http.StatusBadRequest, errors.Errorf("%s for %s", msg, r.URL.String())) - return - } - - name := utils.GetName(r) - ctnr, err := runtime.LookupContainer(name) - if err != nil { - utils.ContainerNotFound(w, name, err) - return - } - - var tail int64 = -1 - if query.Tail != "all" { - tail, err = strconv.ParseInt(query.Tail, 0, 64) - if err != nil { - utils.BadRequest(w, "tail", query.Tail, err) - return - } - } - - var since time.Time - if _, found := r.URL.Query()["since"]; found { - since, err = util.ParseInputTime(query.Since) - if err != nil { - utils.BadRequest(w, "since", query.Since, err) - return - } - } - - var until time.Time - if _, found := r.URL.Query()["until"]; found { - since, err = util.ParseInputTime(query.Until) - if err != nil { - utils.BadRequest(w, "until", query.Until, err) - return - } - } - - options := &logs.LogOptions{ - Details: true, - Follow: query.Follow, - Since: since, - Tail: tail, - Timestamps: query.Timestamps, - } - - var wg sync.WaitGroup - options.WaitGroup = &wg - - logChannel := make(chan *logs.LogLine, tail+1) - if err := runtime.Log([]*libpod.Container{ctnr}, options, logChannel); err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain logs for Container '%s'", name)) - return - } - go func() { - wg.Wait() - close(logChannel) - }() - - w.WriteHeader(http.StatusOK) - var builder strings.Builder - for ok := true; ok; ok = query.Follow { - for line := range logChannel { - if _, found := r.URL.Query()["until"]; found { - if line.Time.After(until) { - break - } - } - - // Reset variables we're ready to loop again - builder.Reset() - header := [8]byte{} - - switch line.Device { - case "stdout": - if !query.Stdout { - continue - } - header[0] = 1 - case "stderr": - if !query.Stderr { - continue - } - header[0] = 2 - default: - // Logging and moving on is the best we can do here. We may have already sent - // a Status and Content-Type to client therefore we can no longer report an error. - log.Infof("unknown Device type '%s' in log file from Container %s", line.Device, ctnr.ID()) - continue - } - - if query.Timestamps { - builder.WriteString(line.Time.Format(time.RFC3339)) - builder.WriteRune(' ') - } - builder.WriteString(line.Msg) - - // Build header and output entry - binary.BigEndian.PutUint32(header[4:], uint32(len(header)+builder.Len())) - if _, err := w.Write(header[:]); err != nil { - log.Errorf("unable to write log output header: %q", err) - } - if _, err := fmt.Fprint(w, builder.String()); err != nil { - log.Errorf("unable to write builder string: %q", err) - } - - if flusher, ok := w.(http.Flusher); ok { - flusher.Flush() - } - } - } -} diff --git a/pkg/api/handlers/generic/containers_create.go b/pkg/api/handlers/generic/containers_create.go deleted file mode 100644 index 7e542752f..000000000 --- a/pkg/api/handlers/generic/containers_create.go +++ /dev/null @@ -1,216 +0,0 @@ -package generic - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/define" - image2 "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/api/handlers" - "github.com/containers/libpod/pkg/api/handlers/utils" - "github.com/containers/libpod/pkg/namespaces" - "github.com/containers/libpod/pkg/signal" - createconfig "github.com/containers/libpod/pkg/spec" - "github.com/containers/storage" - "github.com/gorilla/schema" - "github.com/pkg/errors" - "golang.org/x/sys/unix" -) - -func CreateContainer(w http.ResponseWriter, r *http.Request) { - runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - input := handlers.CreateContainerConfig{} - query := struct { - Name string `schema:"name"` - }{ - // override any golang type defaults - } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, - errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) - return - } - if err := json.NewDecoder(r.Body).Decode(&input); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) - return - } - if len(input.HostConfig.Links) > 0 { - utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter")) - } - newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()")) - return - } - cc, err := makeCreateConfig(input, newImage) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "makeCreatConfig()")) - return - } - cc.Name = query.Name - utils.CreateContainer(r.Context(), w, runtime, &cc) -} - -func makeCreateConfig(input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) { - var ( - err error - init bool - tmpfs []string - volumes []string - ) - env := make(map[string]string) - stopSignal := unix.SIGTERM - if len(input.StopSignal) > 0 { - stopSignal, err = signal.ParseSignal(input.StopSignal) - if err != nil { - return createconfig.CreateConfig{}, err - } - } - - workDir := "/" - if len(input.WorkingDir) > 0 { - workDir = input.WorkingDir - } - - stopTimeout := uint(define.CtrRemoveTimeout) - if input.StopTimeout != nil { - stopTimeout = uint(*input.StopTimeout) - } - c := createconfig.CgroupConfig{ - Cgroups: "", // podman - Cgroupns: "", // podman - CgroupParent: "", // podman - CgroupMode: "", // podman - } - security := createconfig.SecurityConfig{ - CapAdd: input.HostConfig.CapAdd, - CapDrop: input.HostConfig.CapDrop, - LabelOpts: nil, // podman - NoNewPrivs: false, // podman - ApparmorProfile: "", // podman - SeccompProfilePath: "", - SecurityOpts: input.HostConfig.SecurityOpt, - Privileged: input.HostConfig.Privileged, - ReadOnlyRootfs: input.HostConfig.ReadonlyRootfs, - ReadOnlyTmpfs: false, // podman-only - Sysctl: input.HostConfig.Sysctls, - } - - network := createconfig.NetworkConfig{ - DNSOpt: input.HostConfig.DNSOptions, - DNSSearch: input.HostConfig.DNSSearch, - DNSServers: input.HostConfig.DNS, - ExposedPorts: input.ExposedPorts, - HTTPProxy: false, // podman - IP6Address: "", - IPAddress: "", - LinkLocalIP: nil, // docker-only - MacAddress: input.MacAddress, - // NetMode: nil, - Network: input.HostConfig.NetworkMode.NetworkName(), - NetworkAlias: nil, // docker-only now - PortBindings: input.HostConfig.PortBindings, - Publish: nil, // podmanseccompPath - PublishAll: input.HostConfig.PublishAllPorts, - } - - uts := createconfig.UtsConfig{ - UtsMode: namespaces.UTSMode(input.HostConfig.UTSMode), - NoHosts: false, //podman - HostAdd: input.HostConfig.ExtraHosts, - Hostname: input.Hostname, - } - - z := createconfig.UserConfig{ - GroupAdd: input.HostConfig.GroupAdd, - IDMappings: &storage.IDMappingOptions{}, // podman //TODO <--- fix this, - UsernsMode: namespaces.UsernsMode(input.HostConfig.UsernsMode), - User: input.User, - } - pidConfig := createconfig.PidConfig{PidMode: namespaces.PidMode(input.HostConfig.PidMode)} - for k := range input.Volumes { - volumes = append(volumes, k) - } - - // Docker is more flexible about its input where podman throws - // away incorrectly formatted variables so we cannot reuse the - // parsing of the env input - // [Foo Other=one Blank=] - for _, e := range input.Env { - splitEnv := strings.Split(e, "=") - switch len(splitEnv) { - case 0: - continue - case 1: - env[splitEnv[0]] = "" - default: - env[splitEnv[0]] = strings.Join(splitEnv[1:], "=") - } - } - - // format the tmpfs mounts into a []string from map - for k, v := range input.HostConfig.Tmpfs { - tmpfs = append(tmpfs, fmt.Sprintf("%s:%s", k, v)) - } - - if input.HostConfig.Init != nil && *input.HostConfig.Init { - init = true - } - - m := createconfig.CreateConfig{ - Annotations: nil, // podman - Args: nil, - Cgroup: c, - CidFile: "", - ConmonPidFile: "", // podman - Command: input.Cmd, - UserCommand: input.Cmd, // podman - Detach: false, // - // Devices: input.HostConfig.Devices, - Entrypoint: input.Entrypoint, - Env: env, - HealthCheck: nil, // - Init: init, - InitPath: "", // tbd - Image: input.Image, - ImageID: newImage.ID(), - BuiltinImgVolumes: nil, // podman - ImageVolumeType: "", // podman - Interactive: false, - // IpcMode: input.HostConfig.IpcMode, - Labels: input.Labels, - LogDriver: input.HostConfig.LogConfig.Type, // is this correct - // LogDriverOpt: input.HostConfig.LogConfig.Config, - Name: input.Name, - Network: network, - Pod: "", // podman - PodmanPath: "", // podman - Quiet: false, // front-end only - Resources: createconfig.CreateResourceConfig{}, - RestartPolicy: input.HostConfig.RestartPolicy.Name, - Rm: input.HostConfig.AutoRemove, - StopSignal: stopSignal, - StopTimeout: stopTimeout, - Systemd: false, // podman - Tmpfs: tmpfs, - User: z, - Uts: uts, - Tty: input.Tty, - Mounts: nil, // we populate - // MountsFlag: input.HostConfig.Mounts, - NamedVolumes: nil, // we populate - Volumes: volumes, - VolumesFrom: input.HostConfig.VolumesFrom, - WorkDir: workDir, - Rootfs: "", // podman - Security: security, - Syslog: false, // podman - - Pid: pidConfig, - } - return m, nil -} diff --git a/pkg/api/handlers/generic/containers_stats.go b/pkg/api/handlers/generic/containers_stats.go deleted file mode 100644 index 977979741..000000000 --- a/pkg/api/handlers/generic/containers_stats.go +++ /dev/null @@ -1,211 +0,0 @@ -package generic - -import ( - "encoding/json" - "net/http" - "time" - - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/define" - "github.com/containers/libpod/pkg/api/handlers/utils" - "github.com/containers/libpod/pkg/cgroups" - docker "github.com/docker/docker/api/types" - "github.com/gorilla/schema" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -const DefaultStatsPeriod = 5 * time.Second - -func StatsContainer(w http.ResponseWriter, r *http.Request) { - runtime := r.Context().Value("runtime").(*libpod.Runtime) - decoder := r.Context().Value("decoder").(*schema.Decoder) - - query := struct { - Stream bool `schema:"stream"` - }{ - Stream: true, - } - 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 - } - - name := utils.GetName(r) - ctnr, err := runtime.LookupContainer(name) - if err != nil { - utils.ContainerNotFound(w, name, err) - return - } - - // If the container isn't running, then let's not bother and return - // immediately. - state, err := ctnr.State() - if err != nil { - utils.InternalServerError(w, err) - return - } - if state != define.ContainerStateRunning && !query.Stream { - utils.InternalServerError(w, define.ErrCtrStateInvalid) - return - } - - stats, err := ctnr.GetContainerStats(&libpod.ContainerStats{}) - if err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain Container %s stats", name)) - return - } - - var preRead time.Time - var preCPUStats CPUStats - if query.Stream { - preRead = time.Now() - systemUsage, _ := cgroups.GetSystemCPUUsage() - preCPUStats = CPUStats{ - CPUUsage: docker.CPUUsage{ - TotalUsage: stats.CPUNano, - PercpuUsage: stats.PerCPU, - UsageInKernelmode: stats.CPUSystemNano, - UsageInUsermode: stats.CPUNano - stats.CPUSystemNano, - }, - CPU: stats.CPU, - SystemUsage: systemUsage, - OnlineCPUs: 0, - ThrottlingData: docker.ThrottlingData{}, - } - } - - for ok := true; ok; ok = query.Stream { - // Container stats - stats, err := ctnr.GetContainerStats(stats) - if err != nil { - utils.InternalServerError(w, err) - return - } - inspect, err := ctnr.Inspect(false) - if err != nil { - utils.InternalServerError(w, err) - return - } - // Cgroup stats - cgroupPath, err := ctnr.CGroupPath() - if err != nil { - utils.InternalServerError(w, err) - return - } - cgroup, err := cgroups.Load(cgroupPath) - if err != nil { - utils.InternalServerError(w, err) - return - } - cgroupStat, err := cgroup.Stat() - if err != nil { - utils.InternalServerError(w, err) - return - } - - // FIXME: network inspection does not yet work entirely - net := make(map[string]docker.NetworkStats) - networkName := inspect.NetworkSettings.EndpointID - if networkName == "" { - networkName = "network" - } - net[networkName] = docker.NetworkStats{ - RxBytes: stats.NetInput, - RxPackets: 0, - RxErrors: 0, - RxDropped: 0, - TxBytes: stats.NetOutput, - TxPackets: 0, - TxErrors: 0, - TxDropped: 0, - EndpointID: inspect.NetworkSettings.EndpointID, - InstanceID: "", - } - - systemUsage, _ := cgroups.GetSystemCPUUsage() - s := StatsJSON{ - Stats: Stats{ - Read: time.Now(), - PreRead: preRead, - PidsStats: docker.PidsStats{ - Current: cgroupStat.Pids.Current, - Limit: 0, - }, - BlkioStats: docker.BlkioStats{ - IoServiceBytesRecursive: toBlkioStatEntry(cgroupStat.Blkio.IoServiceBytesRecursive), - IoServicedRecursive: nil, - IoQueuedRecursive: nil, - IoServiceTimeRecursive: nil, - IoWaitTimeRecursive: nil, - IoMergedRecursive: nil, - IoTimeRecursive: nil, - SectorsRecursive: nil, - }, - CPUStats: CPUStats{ - CPUUsage: docker.CPUUsage{ - TotalUsage: cgroupStat.CPU.Usage.Total, - PercpuUsage: cgroupStat.CPU.Usage.PerCPU, - UsageInKernelmode: cgroupStat.CPU.Usage.Kernel, - UsageInUsermode: cgroupStat.CPU.Usage.Total - cgroupStat.CPU.Usage.Kernel, - }, - CPU: stats.CPU, - SystemUsage: systemUsage, - OnlineCPUs: uint32(len(cgroupStat.CPU.Usage.PerCPU)), - ThrottlingData: docker.ThrottlingData{ - Periods: 0, - ThrottledPeriods: 0, - ThrottledTime: 0, - }, - }, - PreCPUStats: preCPUStats, - MemoryStats: docker.MemoryStats{ - Usage: cgroupStat.Memory.Usage.Usage, - MaxUsage: cgroupStat.Memory.Usage.Limit, - Stats: nil, - Failcnt: 0, - Limit: cgroupStat.Memory.Usage.Limit, - Commit: 0, - CommitPeak: 0, - PrivateWorkingSet: 0, - }, - }, - Name: stats.Name, - ID: stats.ContainerID, - Networks: net, - } - - utils.WriteJSON(w, http.StatusOK, s) - if flusher, ok := w.(http.Flusher); ok { - flusher.Flush() - } - - preRead = s.Read - bits, err := json.Marshal(s.CPUStats) - if err != nil { - logrus.Errorf("Unable to marshal cpu stats: %q", err) - } - if err := json.Unmarshal(bits, &preCPUStats); err != nil { - logrus.Errorf("Unable to unmarshal previous stats: %q", err) - } - - // Only sleep when we're streaming. - if query.Stream { - time.Sleep(DefaultStatsPeriod) - } - } -} - -func toBlkioStatEntry(entries []cgroups.BlkIOEntry) []docker.BlkioStatEntry { - results := make([]docker.BlkioStatEntry, len(entries)) - for i, e := range entries { - bits, err := json.Marshal(e) - if err != nil { - logrus.Errorf("unable to marshal blkio stats: %q", err) - } - if err := json.Unmarshal(bits, &results[i]); err != nil { - logrus.Errorf("unable to unmarshal blkio stats: %q", err) - } - } - return results -} diff --git a/pkg/api/handlers/generic/images.go b/pkg/api/handlers/generic/images.go deleted file mode 100644 index 078896834..000000000 --- a/pkg/api/handlers/generic/images.go +++ /dev/null @@ -1,362 +0,0 @@ -package generic - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "strings" - - "github.com/containers/buildah" - "github.com/containers/image/v5/manifest" - "github.com/containers/libpod/libpod" - image2 "github.com/containers/libpod/libpod/image" - "github.com/containers/libpod/pkg/api/handlers" - "github.com/containers/libpod/pkg/api/handlers/utils" - "github.com/containers/libpod/pkg/util" - "github.com/docker/docker/api/types" - "github.com/gorilla/schema" - "github.com/pkg/errors" -) - -func ExportImage(w http.ResponseWriter, r *http.Request) { - // 200 ok - // 500 server - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - name := utils.GetName(r) - newImage, err := runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - utils.ImageNotFound(w, name, errors.Wrapf(err, "Failed to find image %s", name)) - return - } - tmpfile, err := ioutil.TempFile("", "api.tar") - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) - return - } - if err := tmpfile.Close(); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile")) - return - } - if err := newImage.Save(r.Context(), name, "docker-archive", tmpfile.Name(), []string{}, false, false); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to save image")) - return - } - rdr, err := os.Open(tmpfile.Name()) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile")) - return - } - defer rdr.Close() - defer os.Remove(tmpfile.Name()) - utils.WriteResponse(w, http.StatusOK, rdr) -} - -func PruneImages(w http.ResponseWriter, r *http.Request) { - var ( - filters []string - ) - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - Filters map[string][]string `schema:"filters"` - }{ - // 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 - } - - idr := []types.ImageDeleteResponseItem{} - for k, v := range query.Filters { - for _, val := range v { - filters = append(filters, fmt.Sprintf("%s=%s", k, val)) - } - } - pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), false, filters) - if err != nil { - utils.InternalServerError(w, err) - return - } - for _, p := range pruneCids { - idr = append(idr, types.ImageDeleteResponseItem{ - Deleted: p, - }) - } - - //FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden - ipr := types.ImagesPruneReport{ - ImagesDeleted: idr, - SpaceReclaimed: 1, // TODO we cannot supply this right now - } - utils.WriteResponse(w, http.StatusOK, handlers.ImagesPruneReport{ImagesPruneReport: ipr}) -} - -func CommitContainer(w http.ResponseWriter, r *http.Request) { - var ( - destImage string - ) - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - Author string `schema:"author"` - Changes string `schema:"changes"` - Comment string `schema:"comment"` - Container string `schema:"container"` - //fromSrc string # fromSrc is currently unused - Pause bool `schema:"pause"` - Repo string `schema:"repo"` - Tag string `schema:"tag"` - }{ - // 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 - } - rtc, err := runtime.GetConfig() - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) - return - } - sc := image2.GetSystemContext(rtc.SignaturePolicyPath, "", false) - tag := "latest" - options := libpod.ContainerCommitOptions{ - Pause: true, - } - options.CommitOptions = buildah.CommitOptions{ - SignaturePolicyPath: rtc.SignaturePolicyPath, - ReportWriter: os.Stderr, - SystemContext: sc, - PreferredManifestType: manifest.DockerV2Schema2MediaType, - } - - input := handlers.CreateContainerConfig{} - if err := json.NewDecoder(r.Body).Decode(&input); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) - return - } - - if len(query.Tag) > 0 { - tag = query.Tag - } - options.Message = query.Comment - options.Author = query.Author - options.Pause = query.Pause - options.Changes = strings.Fields(query.Changes) - ctr, err := runtime.LookupContainer(query.Container) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusNotFound, err) - return - } - - // I know mitr hates this ... but doing for now - if len(query.Repo) > 1 { - destImage = fmt.Sprintf("%s:%s", query.Repo, tag) - } - - commitImage, err := ctr.Commit(r.Context(), destImage, options) - if err != nil && !strings.Contains(err.Error(), "is not running") { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure")) - return - } - utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: commitImage.ID()}) // nolint -} - -func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) { - // 200 no error - // 404 repo does not exist or no read access - // 500 internal - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - FromSrc string `schema:"fromSrc"` - Changes []string `schema:"changes"` - }{ - // 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 - } - // fromSrc – Source to import. The value may be a URL from which the image can be retrieved or - to read the image from the request body. This parameter may only be used when importing an image. - source := query.FromSrc - if source == "-" { - f, err := ioutil.TempFile("", "api_load.tar") - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile")) - return - } - source = f.Name() - if err := handlers.SaveFromBody(f, r); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file")) - } - } - iid, err := runtime.Import(r.Context(), source, "", query.Changes, "", false) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to import tarball")) - return - } - tmpfile, err := ioutil.TempFile("", "fromsrc.tar") - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) - return - } - if err := tmpfile.Close(); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile")) - return - } - // Success - utils.WriteResponse(w, http.StatusOK, struct { - Status string `json:"status"` - Progress string `json:"progress"` - ProgressDetail map[string]string `json:"progressDetail"` - Id string `json:"id"` - }{ - Status: iid, - ProgressDetail: map[string]string{}, - Id: iid, - }) - -} - -func CreateImageFromImage(w http.ResponseWriter, r *http.Request) { - // 200 no error - // 404 repo does not exist or no read access - // 500 internal - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - FromImage string `schema:"fromImage"` - Tag string `schema:"tag"` - }{ - // 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 - } - - /* - fromImage – Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed. - repo – Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image. - tag – Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled. - */ - fromImage := query.FromImage - if len(query.Tag) >= 1 { - fromImage = fmt.Sprintf("%s:%s", fromImage, query.Tag) - } - - // TODO - // We are eating the output right now because we haven't talked about how to deal with multiple responses yet - img, err := runtime.ImageRuntime().New(r.Context(), fromImage, "", "", nil, &image2.DockerRegistryOptions{}, image2.SigningOptions{}, nil, util.PullImageMissing) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) - return - } - - // Success - utils.WriteResponse(w, http.StatusOK, struct { - Status string `json:"status"` - Error string `json:"error"` - Progress string `json:"progress"` - ProgressDetail map[string]string `json:"progressDetail"` - Id string `json:"id"` - }{ - Status: fmt.Sprintf("pulling image (%s) from %s", img.Tag, strings.Join(img.Names(), ", ")), - ProgressDetail: map[string]string{}, - Id: img.ID(), - }) -} - -func GetImage(w http.ResponseWriter, r *http.Request) { - // 200 no error - // 404 no such - // 500 internal - name := utils.GetName(r) - newImage, err := handlers.GetImage(r, name) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "Failed to find image %s", name)) - return - } - inspect, err := handlers.ImageDataToImageInspect(r.Context(), newImage) - if err != nil { - utils.Error(w, "Server error", http.StatusInternalServerError, errors.Wrapf(err, "Failed to convert ImageData to ImageInspect '%s'", inspect.ID)) - return - } - utils.WriteResponse(w, http.StatusOK, inspect) -} - -func GetImages(w http.ResponseWriter, r *http.Request) { - images, err := utils.GetImages(w, r) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images")) - return - } - var summaries = make([]*handlers.ImageSummary, len(images)) - for j, img := range images { - is, err := handlers.ImageToImageSummary(img) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed transform image summaries")) - return - } - summaries[j] = is - } - utils.WriteResponse(w, http.StatusOK, summaries) -} - -func LoadImages(w http.ResponseWriter, r *http.Request) { - // TODO this is basically wrong - decoder := r.Context().Value("decoder").(*schema.Decoder) - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - query := struct { - Changes map[string]string `json:"changes"` - Message string `json:"message"` - Quiet bool `json:"quiet"` - }{ - // 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 - } - - var ( - err error - writer io.Writer - ) - f, err := ioutil.TempFile("", "api_load.tar") - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile")) - return - } - if err := handlers.SaveFromBody(f, r); err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file")) - return - } - id, err := runtime.LoadImage(r.Context(), "", f.Name(), writer, "") - //id, err := runtime.Import(r.Context()) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image")) - return - } - utils.WriteResponse(w, http.StatusOK, struct { - Stream string `json:"stream"` - }{ - Stream: fmt.Sprintf("Loaded image: %s\n", id), - }) -} diff --git a/pkg/api/handlers/generic/info.go b/pkg/api/handlers/generic/info.go deleted file mode 100644 index c9e79233d..000000000 --- a/pkg/api/handlers/generic/info.go +++ /dev/null @@ -1,196 +0,0 @@ -package generic - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - goRuntime "runtime" - "strings" - "time" - - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/libpod/config" - "github.com/containers/libpod/libpod/define" - "github.com/containers/libpod/pkg/api/handlers" - "github.com/containers/libpod/pkg/api/handlers/utils" - "github.com/containers/libpod/pkg/rootless" - "github.com/containers/libpod/pkg/sysinfo" - docker "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/swarm" - "github.com/google/uuid" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" -) - -func GetInfo(w http.ResponseWriter, r *http.Request) { - // 200 ok - // 500 internal - runtime := r.Context().Value("runtime").(*libpod.Runtime) - - infoData, err := runtime.Info() - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "Failed to obtain system memory info")) - return - } - hostInfo := infoData[0].Data - storeInfo := infoData[1].Data - - configInfo, err := runtime.GetConfig() - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "Failed to obtain runtime config")) - return - } - versionInfo, err := define.GetVersion() - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "Failed to obtain podman versions")) - return - } - stateInfo := getContainersState(runtime) - sysInfo := sysinfo.New(true) - - // FIXME: Need to expose if runtime supports Checkpoint'ing - // liveRestoreEnabled := criu.CheckForCriu() && configInfo.RuntimeSupportsCheckpoint() - - info := &handlers.Info{Info: docker.Info{ - Architecture: goRuntime.GOARCH, - BridgeNfIP6tables: !sysInfo.BridgeNFCallIP6TablesDisabled, - BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled, - CPUCfsPeriod: sysInfo.CPUCfsPeriod, - CPUCfsQuota: sysInfo.CPUCfsQuota, - CPUSet: sysInfo.Cpuset, - CPUShares: sysInfo.CPUShares, - CgroupDriver: configInfo.CgroupManager, - ClusterAdvertise: "", - ClusterStore: "", - ContainerdCommit: docker.Commit{}, - Containers: storeInfo["ContainerStore"].(map[string]interface{})["number"].(int), - ContainersPaused: stateInfo[define.ContainerStatePaused], - ContainersRunning: stateInfo[define.ContainerStateRunning], - ContainersStopped: stateInfo[define.ContainerStateStopped] + stateInfo[define.ContainerStateExited], - Debug: log.IsLevelEnabled(log.DebugLevel), - DefaultRuntime: configInfo.OCIRuntime, - DockerRootDir: storeInfo["GraphRoot"].(string), - Driver: storeInfo["GraphDriverName"].(string), - DriverStatus: getGraphStatus(storeInfo), - ExperimentalBuild: true, - GenericResources: nil, - HTTPProxy: getEnv("http_proxy"), - HTTPSProxy: getEnv("https_proxy"), - ID: uuid.New().String(), - IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled, - Images: storeInfo["ImageStore"].(map[string]interface{})["number"].(int), - IndexServerAddress: "", - InitBinary: "", - InitCommit: docker.Commit{}, - Isolation: "", - KernelMemory: sysInfo.KernelMemory, - KernelMemoryTCP: false, - KernelVersion: hostInfo["kernel"].(string), - Labels: nil, - LiveRestoreEnabled: false, - LoggingDriver: "", - MemTotal: hostInfo["MemTotal"].(int64), - MemoryLimit: sysInfo.MemoryLimit, - NCPU: goRuntime.NumCPU(), - NEventsListener: 0, - NFd: getFdCount(), - NGoroutines: goRuntime.NumGoroutine(), - Name: hostInfo["hostname"].(string), - NoProxy: getEnv("no_proxy"), - OSType: goRuntime.GOOS, - OSVersion: hostInfo["Distribution"].(map[string]interface{})["version"].(string), - OomKillDisable: sysInfo.OomKillDisable, - OperatingSystem: hostInfo["Distribution"].(map[string]interface{})["distribution"].(string), - PidsLimit: sysInfo.PidsLimit, - Plugins: docker.PluginsInfo{}, - ProductLicense: "Apache-2.0", - RegistryConfig: nil, - RuncCommit: docker.Commit{}, - Runtimes: getRuntimes(configInfo), - SecurityOptions: getSecOpts(sysInfo), - ServerVersion: versionInfo.Version, - SwapLimit: sysInfo.SwapLimit, - Swarm: swarm.Info{ - LocalNodeState: swarm.LocalNodeStateInactive, - }, - SystemStatus: nil, - SystemTime: time.Now().Format(time.RFC3339Nano), - Warnings: []string{}, - }, - BuildahVersion: hostInfo["BuildahVersion"].(string), - CPURealtimePeriod: sysInfo.CPURealtimePeriod, - CPURealtimeRuntime: sysInfo.CPURealtimeRuntime, - CgroupVersion: hostInfo["CgroupVersion"].(string), - Rootless: rootless.IsRootless(), - SwapFree: hostInfo["SwapFree"].(int64), - SwapTotal: hostInfo["SwapTotal"].(int64), - Uptime: hostInfo["uptime"].(string), - } - utils.WriteResponse(w, http.StatusOK, info) -} - -func getGraphStatus(storeInfo map[string]interface{}) [][2]string { - var graphStatus [][2]string - for k, v := range storeInfo["GraphStatus"].(map[string]string) { - graphStatus = append(graphStatus, [2]string{k, v}) - } - return graphStatus -} - -func getSecOpts(sysInfo *sysinfo.SysInfo) []string { - var secOpts []string - if sysInfo.AppArmor { - secOpts = append(secOpts, "name=apparmor") - } - if sysInfo.Seccomp { - // FIXME: get profile name... - secOpts = append(secOpts, fmt.Sprintf("name=seccomp,profile=%s", "default")) - } - return secOpts -} - -func getRuntimes(configInfo *config.Config) map[string]docker.Runtime { - var runtimes = map[string]docker.Runtime{} - for name, paths := range configInfo.OCIRuntimes { - runtimes[name] = docker.Runtime{ - Path: paths[0], - Args: nil, - } - } - return runtimes -} - -func getFdCount() (count int) { - count = -1 - if entries, err := ioutil.ReadDir("/proc/self/fd"); err == nil { - count = len(entries) - } - return -} - -// Just ignoring Container errors here... -func getContainersState(r *libpod.Runtime) map[define.ContainerStatus]int { - var states = map[define.ContainerStatus]int{} - ctnrs, err := r.GetAllContainers() - if err == nil { - for _, ctnr := range ctnrs { - state, err := ctnr.State() - if err != nil { - continue - } - states[state] += 1 - } - } - return states -} - -func getEnv(value string) string { - if v, exists := os.LookupEnv(strings.ToUpper(value)); exists { - return v - } - if v, exists := os.LookupEnv(strings.ToLower(value)); exists { - return v - } - return "" -} diff --git a/pkg/api/handlers/generic/swagger.go b/pkg/api/handlers/generic/swagger.go deleted file mode 100644 index c9c9610bb..000000000 --- a/pkg/api/handlers/generic/swagger.go +++ /dev/null @@ -1,27 +0,0 @@ -package generic - -import ( - "github.com/containers/libpod/pkg/api/handlers/utils" -) - -// Create container -// swagger:response ContainerCreateResponse -type swagCtrCreateResponse struct { - // in:body - Body struct { - utils.ContainerCreateResponse - } -} - -// Wait container -// swagger:response ContainerWaitResponse -type swagCtrWaitResponse struct { - // in:body - Body struct { - // container exit code - StatusCode int - Error struct { - Message string - } - } -} diff --git a/pkg/api/handlers/generic/system.go b/pkg/api/handlers/generic/system.go deleted file mode 100644 index edf1f8522..000000000 --- a/pkg/api/handlers/generic/system.go +++ /dev/null @@ -1,18 +0,0 @@ -package generic - -import ( - "net/http" - - "github.com/containers/libpod/pkg/api/handlers" - "github.com/containers/libpod/pkg/api/handlers/utils" - docker "github.com/docker/docker/api/types" -) - -func GetDiskUsage(w http.ResponseWriter, r *http.Request) { - utils.WriteResponse(w, http.StatusOK, handlers.DiskUsage{DiskUsage: docker.DiskUsage{ - LayersSize: 0, - Images: nil, - Containers: nil, - Volumes: nil, - }}) -} diff --git a/pkg/api/handlers/generic/types.go b/pkg/api/handlers/generic/types.go deleted file mode 100644 index f068ac011..000000000 --- a/pkg/api/handlers/generic/types.go +++ /dev/null @@ -1,55 +0,0 @@ -package generic - -import ( - "time" - - docker "github.com/docker/docker/api/types" -) - -// CPUStats aggregates and wraps all CPU related info of container -type CPUStats struct { - // CPU Usage. Linux and Windows. - CPUUsage docker.CPUUsage `json:"cpu_usage"` - - // System Usage. Linux only. - SystemUsage uint64 `json:"system_cpu_usage,omitempty"` - - // Online CPUs. Linux only. - OnlineCPUs uint32 `json:"online_cpus,omitempty"` - - // Usage of CPU in %. Linux only. - CPU float64 `json:"cpu"` - - // Throttling Data. Linux only. - ThrottlingData docker.ThrottlingData `json:"throttling_data,omitempty"` -} - -// Stats is Ultimate struct aggregating all types of stats of one container -type Stats struct { - // Common stats - Read time.Time `json:"read"` - PreRead time.Time `json:"preread"` - - // Linux specific stats, not populated on Windows. - PidsStats docker.PidsStats `json:"pids_stats,omitempty"` - BlkioStats docker.BlkioStats `json:"blkio_stats,omitempty"` - - // Windows specific stats, not populated on Linux. - NumProcs uint32 `json:"num_procs"` - StorageStats docker.StorageStats `json:"storage_stats,omitempty"` - - // Shared stats - CPUStats CPUStats `json:"cpu_stats,omitempty"` - PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" - MemoryStats docker.MemoryStats `json:"memory_stats,omitempty"` -} - -type StatsJSON struct { - Stats - - Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - - // Networks request version >=1.21 - Networks map[string]docker.NetworkStats `json:"networks,omitempty"` -} |