Skip to content

Commit

Permalink
Merge pull request #1 from EUDAT-GEF/jobs
Browse files Browse the repository at this point in the history
Jobs
  • Loading branch information
emanueldima committed May 10, 2016
2 parents dc0da30 + 1ee9b80 commit a6c14ae
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 92 deletions.
88 changes: 53 additions & 35 deletions dckr/dckr.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,16 @@ type ContainerID string

// Image is a struct for Docker images
type Image struct {
ID ImageID
Tags []string
Labels map[string]string
ID ImageID
RepoTag string
Labels map[string]string
}

// Container is a struct for Docker containers
type Container struct {
ID ContainerID
ImageName string
Status string
State docker.State
ID ContainerID
Image Image
State docker.State
}

// NewClientFirstOf returns a new docker client or an error
Expand Down Expand Up @@ -141,17 +140,41 @@ func (c Client) IsValid() bool {
return c.c != nil && c.c.Ping() == nil
}

func makeImage(img *docker.Image) Image {
repoTag := ""
if len(img.RepoTags) > 0 {
repoTag = img.RepoTags[0]
}
var labels map[string]string
if img.Config != nil {
labels = img.Config.Labels
}
return Image{
ID: ImageID(img.ID),
RepoTag: repoTag,
Labels: labels,
}
}

func makeImage2(img docker.APIImages) Image {
repoTag := ""
if len(img.RepoTags) > 0 {
repoTag = img.RepoTags[0]
}
return Image{
ID: ImageID(img.ID),
RepoTag: repoTag,
Labels: img.Labels,
}
}

// InspectImage returns the image stats
func (c Client) InspectImage(id ImageID) (Image, error) {
img, err := c.c.InspectImage(string(id))
ret := Image{ID: ImageID(img.ID)}
if err != nil {
return ret, err
return Image{}, err
}
if img.Config != nil {
ret.Labels = img.Config.Labels
}
return ret, err
return makeImage(img), err
}

// ListImages lists the docker images
Expand All @@ -162,12 +185,7 @@ func (c Client) ListImages() ([]Image, error) {
}
ret := make([]Image, 0, 0)
for _, img := range imgs {
rimg := Image{
ID: ImageID(img.ID),
Tags: img.RepoTags,
Labels: img.Labels,
}
ret = append(ret, rimg)
ret = append(ret, makeImage2(img))
}
return ret, nil
}
Expand Down Expand Up @@ -213,17 +231,18 @@ func (c *Client) BuildImage(dirpath string) (Image, error) {
}

// ExecuteImage takes a docker image, creates a container and executes it
func (c Client) ExecuteImage(id ImageID, name string, volumes map[string]struct{}) (ContainerID, error) {
cfg := docker.Config{
Image: string(id),
Volumes: volumes,
func (c Client) ExecuteImage(id ImageID) (ContainerID, error) {
img, err := c.c.InspectImage(string(id))
if err != nil {
return ContainerID(""), err
}
hc := docker.HostConfig{}
cco := docker.CreateContainerOptions{
Name: name,
Config: &cfg,
Name: "",
Config: img.Config,
HostConfig: &hc,
}
// fmt.Println("container options", cco)
cont, err := c.c.CreateContainer(cco)
if err != nil {
return ContainerID(""), err
Expand All @@ -242,11 +261,13 @@ func (c Client) ListContainers() ([]Container, error) {
}
ret := make([]Container, 0, 0)
for _, cont := range conts {
fmt.Println("list container: ", cont)
img, _ := c.InspectImage(ImageID(cont.Image))
ret = append(ret, Container{
ID: ContainerID(cont.ID),
ImageName: cont.Image,
Status: cont.Status,
ID: ContainerID(cont.ID),
Image: img,
State: docker.State{
Status: cont.Status,
},
})
}
return ret, nil
Expand All @@ -255,13 +276,10 @@ func (c Client) ListContainers() ([]Container, error) {
// InspectContainer returns the container details
func (c Client) InspectContainer(id ContainerID) (Container, error) {
cont, err := c.c.InspectContainer(string(id))
img, _ := c.InspectImage(ImageID(cont.Image))
ret := Container{
ID: ContainerID(cont.ID),
ImageName: cont.Image,
// Image: Image{
// ID: ImageID(cont.Image),
// Labels: cont.Labels,
// },
ID: ContainerID(cont.ID),
Image: img,
State: cont.State,
}
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"log"
"os"

"./dckr"
"./server"
"github.com/eudat-gef/gef-docker/dckr"
"github.com/eudat-gef/gef-docker/server"
)

var configFilePath = "config.json"
Expand Down
76 changes: 30 additions & 46 deletions server/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"os"
"path/filepath"

"../dckr"
"github.com/eudat-gef/gef-docker/dckr"

"github.com/pborman/uuid"
"github.com/gorilla/mux"
"github.com/pborman/uuid"
)

const (
Expand Down Expand Up @@ -107,7 +107,8 @@ func (s *Server) newBuildHandler(w http.ResponseWriter, r *http.Request) {
Response{w}.ServerError("cannot create temporary directory", err)
return
}
Response{w}.Location(buildID).Created(jmap("Location", buildID))
loc := apiRootPath + buildsAPIPath + "/" + buildID
Response{w}.Location(loc).Created(jmap("Location", loc, "buildID", buildID))
}

func (s *Server) buildHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -152,9 +153,7 @@ func (s *Server) buildHandler(w http.ResponseWriter, r *http.Request) {
Response{w}.ServerError("build docker image: ", err)
return
}
srv := extractServiceInfo(image)
srv.ID = image.ID
Response{w}.Ok(jmap("Image", image, "Service", srv))
Response{w}.Ok(jmap("Image", image, "Service", extractServiceInfo(image)))
}

func (s *Server) listServicesHandler(w http.ResponseWriter, r *http.Request) {
Expand All @@ -166,9 +165,7 @@ func (s *Server) listServicesHandler(w http.ResponseWriter, r *http.Request) {
services := make([]Service, len(images), len(images))
for i, img := range images {
// fmt.Println("list serv handler: ", img)
srv := extractServiceInfo(img)
srv.ID = img.ID
services[i] = srv
services[i] = extractServiceInfo(img)
}
Response{w}.Ok(jmap("Images", images, "Services", services))
}
Expand All @@ -181,61 +178,48 @@ func (s *Server) inspectServiceHandler(w http.ResponseWriter, r *http.Request) {
Response{w}.ServerError("inspect docker image: ", err)
return
}
srv := extractServiceInfo(image)
srv.ID = image.ID
Response{w}.Ok(jmap("Image", image, "Service", srv))
Response{w}.Ok(jmap("Image", image, "Service", extractServiceInfo(image)))
}

func (s *Server) listJobsHandler(w http.ResponseWriter, r *http.Request) {
containers, err := s.docker.ListContainers()
if err != nil {
Response{w}.ServerError("list all containers: ", err)
func (s *Server) executeServiceHandler(w http.ResponseWriter, r *http.Request) {
imageID := r.FormValue("imageID")
if imageID == "" {
vars := mux.Vars(r)
imageID = vars["imageID"]
}
if imageID == "" {
Response{w}.ServerNewError("execute docker image: imageID required")
return
}
jobs := []Job{}
for _, c := range containers {
jobs = append(jobs, Job{
ID: c.ID,
ServiceName: c.ImageName,
Status: c.Status,
})
containerID, err := s.docker.ExecuteImage(dckr.ImageID(imageID))
if err != nil {
Response{w}.ServerError("execute docker image: ", err)
return
}
Response{w}.Ok(jmap("Containers", containers, "Jobs", jobs))
loc := apiRootPath + jobsAPIPath + "/" + string(containerID)
Response{w}.Location(loc).Created(jmap("Location", loc, "jobID", containerID))
}

func (s *Server) executeServiceHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
imageID := dckr.ImageID(vars["imageID"])
image, err := s.docker.InspectImage(imageID)
func (s *Server) listJobsHandler(w http.ResponseWriter, r *http.Request) {
containers, err := s.docker.ListContainers()
if err != nil {
Response{w}.ServerError("executeServiceHandler: ", err)
Response{w}.ServerError("list all docker containers: ", err)
return
}
srv := extractServiceInfo(image)
volumes := map[string]struct{}{
"/data/GEF/datasets/set1:/mydata/input:ro": struct{}{},
"/home/vagrant/test:/mydata/output": struct{}{},
}
containerID, err := s.docker.ExecuteImage(imageID, srv.Name, volumes)
if err != nil {
Response{w}.ServerError("execute docker image: ", err)
return
var jobs []Job
for _, c := range containers {
jobs = append(jobs, makeJob(c))
}
Response{w}.Ok(jmap("ContainerID", containerID, "JobID", containerID))
Response{w}.Ok(jmap("Jobs", jobs))
}

func (s *Server) inspectJobHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
contID := dckr.ContainerID(vars["jobID"])
cont, err := s.docker.InspectContainer(contID)
if err != nil {
Response{w}.ServerError("inspect container: ", err)
Response{w}.ServerError("inspect docker container: ", err)
return
}
job := Job{
ID: cont.ID,
ServiceName: cont.ImageName,
Status: cont.Status,
}
Response{w}.Ok(jmap("Container", cont, "Job", job))
Response{w}.Ok(jmap("Job", makeJob(cont)))
}
22 changes: 13 additions & 9 deletions server/gefservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strconv"
"strings"

"../dckr"
"github.com/eudat-gef/gef-docker/dckr"
)

// GefSrvLabelPrefix is the prefix identifying GEF related labels
Expand All @@ -15,6 +15,7 @@ const GefSrvLabelPrefix = "eudat.gef.service."
type Service struct {
ID dckr.ImageID
Name string
RepoTag string
Description string
Version string
Input []IOPort
Expand All @@ -29,15 +30,22 @@ type IOPort struct {

// Job is an instance of a running service
type Job struct {
ID dckr.ContainerID
ServiceName string
Status string
dckr.Container
Service Service
}

func makeJob(container dckr.Container) Job {
r := Job{Container: container, Service: extractServiceInfo(container.Image)}
return r
}

///////////////////////////////////////////////////////////////////////////////

func extractServiceInfo(image dckr.Image) Service {
srv := Service{}
srv := Service{
ID: image.ID,
RepoTag: image.RepoTag,
}

for k, v := range image.Labels {
if !strings.HasPrefix(k, GefSrvLabelPrefix) {
Expand Down Expand Up @@ -84,10 +92,6 @@ func extractServiceInfo(image dckr.Image) Service {
srv.Output = out
}

if srv.Name == "" {
srv.Name = strings.Join(image.Tags, ", ")
}

return srv
}

Expand Down
8 changes: 8 additions & 0 deletions server/httpmisc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ func (w Response) ServerError(message string, err error) {
http.Error(w, str, 500)
}

// ServerNewError sets a 500/server error
func (w Response) ServerNewError(message string) {
str := fmt.Sprintf("API Server ERROR: %s", message)
log.Println(str)
http.Error(w, str, 500)
}

// Location sets location header
func (w Response) Location(loc string) Response {
w.Header().Set("Location", loc)
Expand Down Expand Up @@ -62,6 +69,7 @@ func setCodeAndBody(w Response, code int, body interface{}) {
w.WriteHeader(code)
w.Write(data)
// log.Println("setCodeAndBody:", code, contentType, body)
log.Println("-> ", code, contentType, len(data), "bytes")
}

func jmap(kv ...interface{}) map[string]interface{} {
Expand Down

0 comments on commit a6c14ae

Please sign in to comment.