From e6b089f9be43c84960a9a000a0b92d84eefc72e9 Mon Sep 17 00:00:00 2001 From: "Jonathan Leibiusky @xetorthio" Date: Fri, 7 Jul 2017 18:00:11 -0300 Subject: [PATCH 1/3] Allow to drag & drop file uploads to instances Upload file to relative session dir from terminal --- .profile | 1 + handlers/file_upload.go | 23 ++++++++++++++++++----- pwd/instance.go | 36 ++++++++++++++++++++++++++++++++++-- pwd/pwd.go | 3 ++- www/assets/app.js | 12 ++++++++++-- www/assets/style.css | 4 ++++ www/index.html | 5 ++++- 7 files changed, 73 insertions(+), 11 deletions(-) diff --git a/.profile b/.profile index ac9d1f9..75ea98d 100644 --- a/.profile +++ b/.profile @@ -2,3 +2,4 @@ export PS1='\e[1m\e[31m[\h] \e[32m($(docker-prompt)) \e[34m\u@$(hostname -i)\e[3 alias vi='vim' export PATH=$PATH:/root/go/bin cat /etc/motd +echo $BASHPID > /var/run/cwd diff --git a/handlers/file_upload.go b/handlers/file_upload.go index f261d9e..0420241 100644 --- a/handlers/file_upload.go +++ b/handlers/file_upload.go @@ -35,6 +35,8 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusBadRequest) return } + r := req.URL.Query().Get("relative") + for { p, err := red.NextPart() if err == io.EOF { @@ -48,12 +50,23 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) { if p.FileName() == "" { continue } - err = core.InstanceUploadFromReader(i, p.FileName(), p) - if err != nil { - log.Println(err) - rw.WriteHeader(http.StatusInternalServerError) - return + + if r != "" { + err = core.InstanceUploadToCWDFromReader(i, p.FileName(), p) + if err != nil { + log.Println(err) + rw.WriteHeader(http.StatusInternalServerError) + return + } + } else { + err = core.InstanceUploadFromReader(i, p.FileName(), "/var/run/pwd/uploads", p) + if err != nil { + log.Println(err) + rw.WriteHeader(http.StatusInternalServerError) + return + } } + log.Printf("Uploaded [%s] to [%s]\n", p.FileName(), i.Name) } rw.WriteHeader(http.StatusOK) diff --git a/pwd/instance.go b/pwd/instance.go index 5af7544..c160628 100644 --- a/pwd/instance.go +++ b/pwd/instance.go @@ -1,6 +1,7 @@ package pwd import ( + "bytes" "fmt" "io" "log" @@ -82,10 +83,41 @@ func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, url string) error return nil } -func (p *pwd) InstanceUploadFromReader(instance *types.Instance, fileName string, reader io.Reader) error { +func (p *pwd) getInstanceCWD(instance *types.Instance) (string, error) { + b := bytes.NewBufferString("") + + if c, err := p.docker.ExecAttach(instance.Name, []string{"bash", "-c", `pwdx $( 0 { + log.Println(b.String()) + return "", fmt.Errorf("Error %d trying to get CWD", c) + } else if err != nil { + return "", err + } + + cwd := strings.TrimSpace(strings.Split(b.String(), ":")[1]) + + return cwd, nil +} + +func (p *pwd) InstanceUploadToCWDFromReader(instance *types.Instance, fileName string, reader io.Reader) error { + defer observeAction("InstanceUploadToCWDFromReader", time.Now()) + + var cwd string + var err error + if cwd, err = p.getInstanceCWD(instance); err != nil { + return err + } + + if err = p.InstanceUploadFromReader(instance, fileName, cwd, reader); err != nil { + return err + } + + return nil +} + +func (p *pwd) InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error { defer observeAction("InstanceUploadFromReader", time.Now()) - copyErr := p.docker.CopyToContainer(instance.Name, "/var/run/pwd/uploads", fileName, reader) + copyErr := p.docker.CopyToContainer(instance.Name, dest, fileName, reader) if copyErr != nil { return fmt.Errorf("Error while uploading file [%s]. Error: %s\n", fileName, copyErr) diff --git a/pwd/pwd.go b/pwd/pwd.go index 1dcc8fa..2aa1e7b 100644 --- a/pwd/pwd.go +++ b/pwd/pwd.go @@ -61,7 +61,8 @@ type PWDApi interface { InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error InstanceAttachTerminal(instance *types.Instance) error InstanceUploadFromUrl(instance *types.Instance, url string) error - InstanceUploadFromReader(instance *types.Instance, filename string, reader io.Reader) error + InstanceUploadFromReader(instance *types.Instance, filename, dest string, reader io.Reader) error + InstanceUploadToCWDFromReader(instance *types.Instance, fileName string, reader io.Reader) error InstanceGet(session *types.Session, name string) *types.Instance InstanceFindByIP(ip string) *types.Instance InstanceFindByAlias(sessionPrefix, alias string) *types.Instance diff --git a/www/assets/app.js b/www/assets/app.js index 75d735b..ef34dc8 100644 --- a/www/assets/app.js +++ b/www/assets/app.js @@ -1,7 +1,7 @@ (function() { 'use strict'; - var app = angular.module('DockerPlay', ['ngMaterial']); + var app = angular.module('DockerPlay', ['ngMaterial', 'ngFileUpload']); // Automatically redirects user to a new session when bypassing captcha. // Controller keeps code/logic separate from the HTML @@ -19,7 +19,7 @@ } } - app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', 'TerminalService', 'KeyboardShortcutService', 'InstanceService', 'SessionService', function($scope, $log, $http, $location, $timeout, $mdDialog, $window, TerminalService, KeyboardShortcutService, InstanceService, SessionService) { + app.controller('PlayController', ['$scope', '$log', '$http', '$location', '$timeout', '$mdDialog', '$window', 'TerminalService', 'KeyboardShortcutService', 'InstanceService', 'SessionService', 'Upload', function($scope, $log, $http, $location, $timeout, $mdDialog, $window, TerminalService, KeyboardShortcutService, InstanceService, SessionService, Upload) { $scope.sessionId = SessionService.getCurrentSessionId(); $scope.instances = []; $scope.idx = {}; @@ -32,6 +32,14 @@ $scope.deleteInstanceBtnText = 'Delete'; $scope.isInstanceBeingDeleted = false; + $scope.uploadFiles = function (files) { + if (files && files.length) { + for (var i = 0; i < files.length; i++) { + Upload.upload({url: '/sessions/' + $scope.sessionId + '/instances/' + $scope.selectedInstance.name + '/uploads?relative=true', data: {file: files[i]}, method: 'POST'}); + } + } + } + var selectedKeyboardShortcuts = KeyboardShortcutService.getCurrentShortcuts(); angular.element($window).bind('resize', function() { diff --git a/www/assets/style.css b/www/assets/style.css index 0d429f0..9feb2d0 100644 --- a/www/assets/style.css +++ b/www/assets/style.css @@ -62,3 +62,7 @@ md-input-container .md-errors-spacer { .md-mini { min-width: 24px; } + +.dragover { + opacity: 0.5; +} diff --git a/www/index.html b/www/index.html index 7576672..0b926ed 100644 --- a/www/index.html +++ b/www/index.html @@ -72,7 +72,7 @@
- + @@ -272,6 +272,9 @@ + + + From b9f154c07cdc0222cd7dbfc7eaf28fb7ec9a9234 Mon Sep 17 00:00:00 2001 From: Marcos Lilljedahl Date: Mon, 10 Jul 2017 18:53:33 -0300 Subject: [PATCH 2/3] Unify file upload strategies --- handlers/file_upload.go | 28 +++++++++++----------------- pwd/instance.go | 35 ++++++++++++++--------------------- pwd/pwd.go | 5 ++--- pwd/session.go | 7 +++++-- www/assets/app.js | 2 +- 5 files changed, 33 insertions(+), 44 deletions(-) diff --git a/handlers/file_upload.go b/handlers/file_upload.go index 0420241..dda880b 100644 --- a/handlers/file_upload.go +++ b/handlers/file_upload.go @@ -4,6 +4,7 @@ import ( "io" "log" "net/http" + "path/filepath" "github.com/gorilla/mux" ) @@ -20,7 +21,10 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) { // has a url query parameter, ignore body if url := req.URL.Query().Get("url"); url != "" { - err := core.InstanceUploadFromUrl(i, req.URL.Query().Get("url")) + + _, fileName := filepath.Split(url) + + err := core.InstanceUploadFromUrl(i, fileName, "", req.URL.Query().Get("url")) if err != nil { log.Println(err) rw.WriteHeader(http.StatusInternalServerError) @@ -35,7 +39,7 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusBadRequest) return } - r := req.URL.Query().Get("relative") + path := req.URL.Query().Get("path") for { p, err := red.NextPart() @@ -50,21 +54,11 @@ func FileUpload(rw http.ResponseWriter, req *http.Request) { if p.FileName() == "" { continue } - - if r != "" { - err = core.InstanceUploadToCWDFromReader(i, p.FileName(), p) - if err != nil { - log.Println(err) - rw.WriteHeader(http.StatusInternalServerError) - return - } - } else { - err = core.InstanceUploadFromReader(i, p.FileName(), "/var/run/pwd/uploads", p) - if err != nil { - log.Println(err) - rw.WriteHeader(http.StatusInternalServerError) - return - } + err = core.InstanceUploadFromReader(i, p.FileName(), path, p) + if err != nil { + log.Println(err) + rw.WriteHeader(http.StatusInternalServerError) + return } log.Printf("Uploaded [%s] to [%s]\n", p.FileName(), i.Name) diff --git a/pwd/instance.go b/pwd/instance.go index c160628..4482728 100644 --- a/pwd/instance.go +++ b/pwd/instance.go @@ -60,7 +60,7 @@ func (p *pwd) InstanceAttachTerminal(instance *types.Instance) error { return nil } -func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, url string) error { +func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, fileName, dest string, url string) error { defer observeAction("InstanceUploadFromUrl", time.Now()) log.Printf("Downloading file [%s]\n", url) resp, err := http.Get(url) @@ -72,9 +72,7 @@ func (p *pwd) InstanceUploadFromUrl(instance *types.Instance, url string) error return fmt.Errorf("Could not download file [%s]. Status code: %d\n", url, resp.StatusCode) } - _, fileName := filepath.Split(url) - - copyErr := p.docker.CopyToContainer(instance.Name, "/var/run/pwd/uploads", fileName, resp.Body) + copyErr := p.docker.CopyToContainer(instance.Name, dest, fileName, resp.Body) if copyErr != nil { return fmt.Errorf("Error while downloading file [%s]. Error: %s\n", url, copyErr) @@ -98,26 +96,21 @@ func (p *pwd) getInstanceCWD(instance *types.Instance) (string, error) { return cwd, nil } -func (p *pwd) InstanceUploadToCWDFromReader(instance *types.Instance, fileName string, reader io.Reader) error { - defer observeAction("InstanceUploadToCWDFromReader", time.Now()) - - var cwd string - var err error - if cwd, err = p.getInstanceCWD(instance); err != nil { - return err - } - - if err = p.InstanceUploadFromReader(instance, fileName, cwd, reader); err != nil { - return err - } - - return nil -} - func (p *pwd) InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error { defer observeAction("InstanceUploadFromReader", time.Now()) - copyErr := p.docker.CopyToContainer(instance.Name, dest, fileName, reader) + var finalDest string + if filepath.IsAbs(dest) { + finalDest = dest + } else { + if cwd, err := p.getInstanceCWD(instance); err != nil { + return err + } else { + finalDest = fmt.Sprintf("%s/%s", cwd, dest) + } + } + + copyErr := p.docker.CopyToContainer(instance.Name, finalDest, fileName, reader) if copyErr != nil { return fmt.Errorf("Error while uploading file [%s]. Error: %s\n", fileName, copyErr) diff --git a/pwd/pwd.go b/pwd/pwd.go index 2aa1e7b..4c397fb 100644 --- a/pwd/pwd.go +++ b/pwd/pwd.go @@ -60,9 +60,8 @@ type PWDApi interface { InstanceNew(session *types.Session, conf InstanceConfig) (*types.Instance, error) InstanceResizeTerminal(instance *types.Instance, cols, rows uint) error InstanceAttachTerminal(instance *types.Instance) error - InstanceUploadFromUrl(instance *types.Instance, url string) error - InstanceUploadFromReader(instance *types.Instance, filename, dest string, reader io.Reader) error - InstanceUploadToCWDFromReader(instance *types.Instance, fileName string, reader io.Reader) error + InstanceUploadFromUrl(instance *types.Instance, fileName, dest, url string) error + InstanceUploadFromReader(instance *types.Instance, fileName, dest string, reader io.Reader) error InstanceGet(session *types.Session, name string) *types.Instance InstanceFindByIP(ip string) *types.Instance InstanceFindByAlias(sessionPrefix, alias string) *types.Instance diff --git a/pwd/session.go b/pwd/session.go index ad36812..18d5873 100644 --- a/pwd/session.go +++ b/pwd/session.go @@ -5,6 +5,7 @@ import ( "log" "math" "path" + "path/filepath" "strings" "sync" "time" @@ -152,13 +153,15 @@ func (p *pwd) SessionDeployStack(s *types.Session) error { log.Printf("Error creating instance for stack [%s]: %s\n", s.Stack, err) return err } - err = p.InstanceUploadFromUrl(i, s.Stack) + + _, fileName := filepath.Split(s.Stack) + err = p.InstanceUploadFromUrl(i, fileName, "", s.Stack) if err != nil { log.Printf("Error uploading stack file [%s]: %s\n", s.Stack, err) return err } - fileName := path.Base(s.Stack) + fileName = path.Base(s.Stack) file := fmt.Sprintf("/var/run/pwd/uploads/%s", fileName) cmd := fmt.Sprintf("docker swarm init --advertise-addr eth0 && docker-compose -f %s pull && docker stack deploy -c %s %s", file, file, s.StackName) diff --git a/www/assets/app.js b/www/assets/app.js index ef34dc8..8f67e77 100644 --- a/www/assets/app.js +++ b/www/assets/app.js @@ -35,7 +35,7 @@ $scope.uploadFiles = function (files) { if (files && files.length) { for (var i = 0; i < files.length; i++) { - Upload.upload({url: '/sessions/' + $scope.sessionId + '/instances/' + $scope.selectedInstance.name + '/uploads?relative=true', data: {file: files[i]}, method: 'POST'}); + Upload.upload({url: '/sessions/' + $scope.sessionId + '/instances/' + $scope.selectedInstance.name + '/uploads', data: {file: files[i]}, method: 'POST'}); } } } From 3e38804393263dab67fca880f1917cff00a31086 Mon Sep 17 00:00:00 2001 From: Marcos Lilljedahl Date: Mon, 10 Jul 2017 18:59:38 -0300 Subject: [PATCH 3/3] Fix path for stack files --- pwd/session.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwd/session.go b/pwd/session.go index 18d5873..fedf2f1 100644 --- a/pwd/session.go +++ b/pwd/session.go @@ -155,7 +155,7 @@ func (p *pwd) SessionDeployStack(s *types.Session) error { } _, fileName := filepath.Split(s.Stack) - err = p.InstanceUploadFromUrl(i, fileName, "", s.Stack) + err = p.InstanceUploadFromUrl(i, fileName, "/var/run/pwd/uploads", s.Stack) if err != nil { log.Printf("Error uploading stack file [%s]: %s\n", s.Stack, err) return err