From a481e73016769a360634ca37e0257d8e3f16f376 Mon Sep 17 00:00:00 2001 From: Jonathan Calmels Date: Tue, 3 May 2016 16:50:47 -0700 Subject: [PATCH] Add /docker/cli/json RestAPI endpoint Fixes: #39 Fixes: #91 --- tools/src/nvidia-docker-plugin/remote_api.go | 2 + tools/src/nvidia-docker-plugin/remote_v1.go | 74 +++++++++++++------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/tools/src/nvidia-docker-plugin/remote_api.go b/tools/src/nvidia-docker-plugin/remote_api.go index 61dbc3c0..16e94bd7 100644 --- a/tools/src/nvidia-docker-plugin/remote_api.go +++ b/tools/src/nvidia-docker-plugin/remote_api.go @@ -16,6 +16,7 @@ type restapi interface { gpuStatus(http.ResponseWriter, *http.Request) gpuStatusJSON(http.ResponseWriter, *http.Request) dockerCLI(http.ResponseWriter, *http.Request) + dockerCLIJSON(http.ResponseWriter, *http.Request) mesosCLI(http.ResponseWriter, *http.Request) } @@ -45,6 +46,7 @@ func (a *RemoteAPI) register(apis ...restapi) { a.Handle("GET", prefix+"/gpu/status", api.gpuStatus) a.Handle("GET", prefix+"/gpu/status/json", api.gpuStatusJSON) a.Handle("GET", prefix+"/docker/cli", api.dockerCLI) + a.Handle("GET", prefix+"/docker/cli/json", api.dockerCLIJSON) a.Handle("GET", prefix+"/mesos/cli", api.mesosCLI) if i == len(apis)-1 && prefix != "" { diff --git a/tools/src/nvidia-docker-plugin/remote_v1.go b/tools/src/nvidia-docker-plugin/remote_v1.go index a0a39af8..bfcad575 100644 --- a/tools/src/nvidia-docker-plugin/remote_v1.go +++ b/tools/src/nvidia-docker-plugin/remote_v1.go @@ -68,13 +68,13 @@ func (r *remoteV10) gpuInfo(resp http.ResponseWriter, req *http.Request) { func (r *remoteV10) gpuInfoJSON(resp http.ResponseWriter, req *http.Request) { var body bytes.Buffer - writeInfoJSON(&body) + writeGPUInfoJSON(&body) resp.Header().Set("Content-Type", "application/json") _, err := body.WriteTo(resp) assert(err) } -func writeInfoJSON(wr io.Writer) { +func writeGPUInfoJSON(wr io.Writer) { var err error r := struct { @@ -131,13 +131,13 @@ func (r *remoteV10) gpuStatus(resp http.ResponseWriter, req *http.Request) { func (r *remoteV10) gpuStatusJSON(resp http.ResponseWriter, req *http.Request) { var body bytes.Buffer - writeStatusJSON(&body) + writeGPUStatusJSON(&body) resp.Header().Set("Content-Type", "application/json") _, err := body.WriteTo(resp) assert(err) } -func writeStatusJSON(wr io.Writer) { +func writeGPUStatusJSON(wr io.Writer) { status := make([]*nvidia.DeviceStatus, 0, len(Devices)) for i := range Devices { @@ -150,27 +150,57 @@ func writeStatusJSON(wr io.Writer) { } func (r *remoteV10) dockerCLI(resp http.ResponseWriter, req *http.Request) { - var body bytes.Buffer + const tpl = "--volume-driver={{.VolumeDriver}}{{range .Volumes}} --volume={{.}}{{end}}" + + "{{range .Devices}} --device={{.}}{{end}}" devs := strings.Split(req.FormValue("dev"), " ") vols := strings.Split(req.FormValue("vol"), " ") - if err := dockerCLIDevices(&body, devs); err != nil { + args, err := dockerCLIArgs(devs, vols) + if err != nil { http.Error(resp, err.Error(), http.StatusBadRequest) return } - body.WriteRune(' ') - if err := dockerCLIVolumes(&body, vols); err != nil { + t := template.Must(template.New("").Parse(tpl)) + assert(t.Execute(resp, args)) +} + +func (r *remoteV10) dockerCLIJSON(resp http.ResponseWriter, req *http.Request) { + devs := strings.Split(req.FormValue("dev"), " ") + vols := strings.Split(req.FormValue("vol"), " ") + + args, err := dockerCLIArgs(devs, vols) + if err != nil { http.Error(resp, err.Error(), http.StatusBadRequest) return } - _, err := body.WriteTo(resp) - assert(err) + resp.Header().Set("Content-Type", "application/json") + assert(json.NewEncoder(resp).Encode(args)) } -func dockerCLIDevices(wr io.Writer, ids []string) error { - var tpl = fmt.Sprintf("--device=%s --device=%s{{range .}} --device={{.}}{{end}}", nvidia.DeviceCtl, nvidia.DeviceUVM) +type dockerArgs struct { + VolumeDriver string + Volumes []string + Devices []string +} +func dockerCLIArgs(devs, vols []string) (*dockerArgs, error) { + devs, err := dockerCLIDevices(devs) + if err != nil { + return nil, err + } + vols, err = dockerCLIVolumes(vols) + if err != nil { + return nil, err + } + return &dockerArgs{ + VolumeDriver: nvidia.DockerPlugin, + Volumes: vols, + Devices: append(devs, nvidia.DeviceCtl, nvidia.DeviceUVM), + }, nil +} + +func dockerCLIDevices(ids []string) ([]string, error) { devs := make([]string, 0, len(Devices)) if len(ids) == 1 && (ids[0] == "*" || ids[0] == "") { @@ -181,24 +211,20 @@ func dockerCLIDevices(wr io.Writer, ids []string) error { for _, id := range ids { i, err := strconv.Atoi(id) if err != nil || i < 0 || i >= len(Devices) { - return fmt.Errorf("invalid device: %s", id) + return nil, fmt.Errorf("invalid device: %s", id) } devs = append(devs, Devices[i].Path) } } - t := template.Must(template.New("").Parse(tpl)) - assert(t.Execute(wr, devs)) - return nil + return devs, nil } -func dockerCLIVolumes(wr io.Writer, names []string) error { - var tpl = fmt.Sprintf("--volume-driver=%s{{range .}} --volume={{.}}{{end}}", nvidia.DockerPlugin) - +func dockerCLIVolumes(names []string) ([]string, error) { vols := make([]string, 0, len(Volumes)) drv, err := nvidia.GetDriverVersion() if err != nil { - return err + return nil, err } if len(names) == 1 && (names[0] == "*" || names[0] == "") { for _, v := range Volumes { @@ -208,14 +234,12 @@ func dockerCLIVolumes(wr io.Writer, names []string) error { for _, n := range names { v, ok := Volumes[n] if !ok { - return fmt.Errorf("invalid volume: %s", n) + return nil, fmt.Errorf("invalid volume: %s", n) } vols = append(vols, fmt.Sprintf("%s_%s:%s:ro", v.Name, drv, v.Mountpoint)) } } - t := template.Must(template.New("").Parse(tpl)) - assert(t.Execute(wr, vols)) - return nil + return vols, nil } func (r *remoteV10) mesosCLI(resp http.ResponseWriter, req *http.Request) { @@ -223,7 +247,7 @@ func (r *remoteV10) mesosCLI(resp http.ResponseWriter, req *http.Request) { // Generate Mesos attributes var b bytes.Buffer - writeInfoJSON(&b) + writeGPUInfoJSON(&b) attr := base64Encode(zlibCompress(b.Bytes())) // Generate Mesos custom resources