Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored routing, added more endpoints and types #8

Merged
merged 1 commit into from
Nov 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ require (
github.com/ghodss/yaml v1.0.0
github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
github.com/gorilla/mux v1.7.3
github.com/hashicorp/go-multierror v1.0.0
github.com/hpcloud/tail v1.0.0
github.com/imdario/mergo v0.3.7 // indirect
Expand Down
6 changes: 6 additions & 0 deletions pkg/serviceapi/handler_containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import (
"net/http"

"github.com/containers/libpod/libpod"
"github.com/gorilla/mux"
)

func registerContainersHandlers(r *mux.Router) error {
r.Handle(versionedPath("/containers/"), serviceHandler(containers))
return nil
}

func containers(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
http.NotFound(w, r)
}
52 changes: 48 additions & 4 deletions pkg/serviceapi/handler_images.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package serviceapi

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/containers/libpod/libpod"
"github.com/gorilla/mux"
)

func images(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
func registerImagesHandlers(r *mux.Router) error {
r.Handle(versionedPath("/images/json"), serviceHandler(getImages))
r.Handle(versionedPath("/images/{name:..*}/json"), serviceHandler(inspectImages))
return nil
}
func inspectImages(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
// /v1.24/images/(name)
contentType := r.Header.Get("Content-Type")
if contentType != "" && contentType != "application/json" {
http.Error(w,
Expand All @@ -18,24 +26,60 @@ func images(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
return
}

name := mux.Vars(r)["name"]
image, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
http.Error(w, fmt.Sprintf("Image '%s' not found", name), http.StatusNotFound)
return
}

info, err := image.Inspect(context.Background())
if err != nil {
http.Error(w, fmt.Sprintf("Failed to inspect Image '%s'", name), http.StatusInternalServerError)
return
}

inspect, err := ImageDataToImageInspect(info)
buffer, err := json.Marshal(inspect)
if err != nil {
http.Error(w,
fmt.Sprintf("Failed to convert API ImageInspect '%s' to json: %s", inspect.ID, err.Error()),
http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
io.WriteString(w, string(buffer))
}

func getImages(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
// /v1.24/images/json

images, err := runtime.ImageRuntime().GetImages()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w,
fmt.Sprintf("Failed to obtain the list of images from storage: %s", err.Error()),
http.StatusInternalServerError)
return
}

var summaries []*ImageSummary
for _, img := range images {
i, err := ImageToImageSummary(img)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w,
fmt.Sprintf("Failed to convert storage image '%s' to API image: %s", img.ID(), err.Error()),
http.StatusInternalServerError)
return
}
summaries = append(summaries, i)
}

buffer, err := json.Marshal(summaries)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w,
fmt.Sprintf("Failed to convert API images to json: %s", err.Error()),
http.StatusInternalServerError)
return
}

Expand Down
44 changes: 44 additions & 0 deletions pkg/serviceapi/handler_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package serviceapi


import (
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/containers/libpod/libpod"
"github.com/gorilla/mux"
)

func registerInfoHandlers(r *mux.Router) error {
r.Handle(versionedPath("/info"), serviceHandler(info))
return nil
}

func info(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
infoData, err := runtime.Info()
if err != nil {
http.Error(w,
fmt.Sprintf("Failed to obtain the system information: %s", err.Error()),
http.StatusInternalServerError)
return
}
info, err := InfoDataToInfo(infoData)
if err != nil {
http.Error(w,
fmt.Sprintf("Failed to convert system information to API information: %s", err.Error()),
http.StatusInternalServerError)
return
}

buffer, err := json.Marshal(info)
if err != nil {
http.Error(w,
fmt.Sprintf("Failed to convert API images to json: %s", err.Error()),
http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
io.WriteString(w, string(buffer))
}
17 changes: 17 additions & 0 deletions pkg/serviceapi/handler_pods.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package serviceapi

import (
"net/http"

"github.com/containers/libpod/libpod"
"github.com/gorilla/mux"
)

func registerPodsHandlers(r *mux.Router) error {
r.Handle(versionedPath("/pods/"), serviceHandler(pods))
return nil
}

func pods(w http.ResponseWriter, r *http.Request, runtime *libpod.Runtime) {
http.NotFound(w, r)
}
21 changes: 16 additions & 5 deletions pkg/serviceapi/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ import (
"time"

"github.com/containers/libpod/libpod"
"github.com/gorilla/mux"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"

"github.com/coreos/go-systemd/activation"
)

const ApiVersion = "v1.24"

type HttpServer struct {
http.Server
router *mux.Router
done chan struct{}
listener net.Listener
}
Expand All @@ -39,7 +43,13 @@ func NewServer(runtime *libpod.Runtime) (*HttpServer, error) {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

server := HttpServer{http.Server{}, done, listeners[0]}
router := mux.NewRouter()
registerImagesHandlers(router)
registerContainersHandlers(router)
registerPodsHandlers(router)
registerInfoHandlers(router)

server := HttpServer{http.Server{}, router, done, listeners[0]}
go func() {
<-quit
log.Debugf("HttpServer is shutting down")
Expand All @@ -52,14 +62,11 @@ func NewServer(runtime *libpod.Runtime) (*HttpServer, error) {
close(done)
}()

// TODO: build this into a map...
http.Handle("/v1.24/images/json", serviceHandler(images))
http.Handle("/v1.24/containers/json", serviceHandler(containers))
return &server, nil
}

func (s *HttpServer) Serve() error {
err := http.Serve(s.listener, nil)
err := http.Serve(s.listener, s.router)
if err != nil {
return errors.Wrap(err, "Failed to start HttpServer")
}
Expand All @@ -75,3 +82,7 @@ func (s *HttpServer) Shutdown(ctx context.Context) error {
func (s *HttpServer) Close() error {
return s.Server.Close()
}

func versionedPath(p string) string {
return "/" + ApiVersion + p
}
126 changes: 124 additions & 2 deletions pkg/serviceapi/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,38 @@ package serviceapi

import (
"context"
goRuntime "runtime"
"time"

podman "github.com/containers/libpod/libpod/image"
podmanDefine "github.com/containers/libpod/libpod/define"
podmanImage "github.com/containers/libpod/libpod/image"
podmanInspect "github.com/containers/libpod/pkg/inspect"
"github.com/containers/storage/pkg/system"
docker "github.com/docker/docker/api/types"
dockerContainer "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/swarm"
"github.com/pkg/errors"
)

type ImageInspect struct {
docker.ImageInspect
}

type ContainerConfig struct {
dockerContainer.Config
}

type ImageSummary struct {
docker.ImageSummary
}

func ImageToImageSummary(p *podman.Image) (*ImageSummary, error) {
type Info struct {
docker.Info
BuildahVersion string
Rootless bool
}

func ImageToImageSummary(p *podmanImage.Image) (*ImageSummary, error) {
containers, err := p.Containers()
if err != nil {
return nil, errors.Wrapf(err, "Failed to obtain Containers for image %s", p.ID())
Expand All @@ -29,6 +50,7 @@ func ImageToImageSummary(p *podman.Image) (*ImageSummary, error) {
return nil, errors.Wrapf(err, "Failed to obtain RepoTags for image %s", p.ID())
}

// FIXME: GetParent() panics
// parent, err := p.GetParent(context.TODO())
// if err != nil {
// return nil, errors.Wrapf(err, "Failed to obtain ParentID for image %s", p.ID())
Expand Down Expand Up @@ -56,3 +78,103 @@ func ImageToImageSummary(p *podman.Image) (*ImageSummary, error) {
VirtualSize: int64(*size),
}}, nil
}

func ImageDataToImageInspect(p *podmanInspect.ImageData) (*ImageInspect, error) {
return &ImageInspect{docker.ImageInspect{
Architecture: p.Architecture,
Author: p.Author,
Comment: p.Comment,
Config: &dockerContainer.Config{},
Container: "",
ContainerConfig: nil,
Created: p.Created.Format(time.RFC3339Nano),
DockerVersion: "",
GraphDriver: docker.GraphDriverData{},
ID: p.ID,
Metadata: docker.ImageMetadata{},
Os: p.Os,
OsVersion: p.Version,
Parent: p.Parent,
RepoDigests: p.RepoDigests,
RepoTags: p.RepoTags,
RootFS: docker.RootFS{},
Size: p.Size,
Variant: "",
VirtualSize: p.VirtualSize,
}}, nil
}

func InfoDataToInfo(p []podmanDefine.InfoData) (*Info, error) {
memInfo, err := system.ReadMemInfo()
if err != nil {
return nil, errors.Wrap(err, "Failed to obtain system memory info")
}

return &Info{Info: docker.Info{
Architecture: goRuntime.GOARCH,
BridgeNfIP6tables: false,
BridgeNfIptables: false,
CPUCfsPeriod: false,
CPUCfsQuota: false,
CPUSet: false,
CPUShares: false,
CgroupDriver: "",
ClusterAdvertise: "",
ClusterStore: "",
ContainerdCommit: docker.Commit{},
Containers: 0,
ContainersPaused: 0,
ContainersRunning: 0,
ContainersStopped: 0,
Debug: false,
DefaultRuntime: "",
DockerRootDir: "",
Driver: "",
DriverStatus: nil,
ExperimentalBuild: false,
GenericResources: nil,
HTTPProxy: "",
HTTPSProxy: "",
ID: "podman",
IPv4Forwarding: false,
Images: 0,
IndexServerAddress: "",
InitBinary: "",
InitCommit: docker.Commit{},
Isolation: "",
KernelMemory: false,
KernelMemoryTCP: false,
KernelVersion: "",
Labels: nil,
LiveRestoreEnabled: false,
LoggingDriver: "",
MemTotal: memInfo.MemTotal,
MemoryLimit: false,
NCPU: goRuntime.NumCPU(),
NEventsListener: 0,
NFd: 0,
NGoroutines: 0,
Name: "",
NoProxy: "",
OSType: "",
OSVersion: "",
OomKillDisable: false,
OperatingSystem: goRuntime.GOOS,
PidsLimit: false,
Plugins: docker.PluginsInfo{},
ProductLicense: "",
RegistryConfig: nil,
RuncCommit: docker.Commit{},
Runtimes: nil,
SecurityOptions: nil,
ServerVersion: "",
SwapLimit: false,
Swarm: swarm.Info{},
SystemStatus: nil,
SystemTime: time.Now().Format(time.RFC3339Nano),
Warnings: nil,
},
Rootless: false,
BuildahVersion: "",
}, nil
}