From 526f27ac4d22e96742958464ce390e2aa99cec56 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 12:46:42 +0200 Subject: [PATCH 01/36] Reorganized project structure (#80) --- .gitignore | 3 ++- Makefile | 14 +++++++------- README.md | 6 +++--- main.go => cmd/scw/main.go | 8 ++++---- {api => pkg/api}/README.md | 0 {api => pkg/api}/api.go | 0 {api => pkg/api}/cache.go | 0 {api => pkg/api}/helpers.go | 2 +- {api => pkg/api}/types.go | 0 {commands => pkg/commands}/attach.go | 4 ++-- {commands => pkg/commands}/commands.go | 2 +- {commands => pkg/commands}/commit.go | 2 +- {commands => pkg/commands}/cp.go | 6 +++--- {commands => pkg/commands}/create.go | 4 ++-- {commands => pkg/commands}/events.go | 2 +- {commands => pkg/commands}/exec.go | 6 +++--- {commands => pkg/commands}/help.go | 2 +- {commands => pkg/commands}/history.go | 4 ++-- {commands => pkg/commands}/images.go | 6 +++--- {commands => pkg/commands}/info.go | 4 ++-- {commands => pkg/commands}/inspect.go | 4 ++-- {commands => pkg/commands}/kill.go | 6 +++--- {commands => pkg/commands}/login.go | 6 +++--- {commands => pkg/commands}/logout.go | 4 ++-- {commands => pkg/commands}/logs.go | 6 +++--- {commands => pkg/commands}/port.go | 6 +++--- {commands => pkg/commands}/ps.go | 4 ++-- {commands => pkg/commands}/rename.go | 4 ++-- {commands => pkg/commands}/restart.go | 2 +- {commands => pkg/commands}/rm.go | 2 +- {commands => pkg/commands}/rmi.go | 2 +- {commands => pkg/commands}/run.go | 6 +++--- {commands => pkg/commands}/search.go | 6 +++--- {commands => pkg/commands}/start.go | 4 ++-- {commands => pkg/commands}/stop.go | 4 ++-- {commands => pkg/commands}/tag.go | 2 +- {commands => pkg/commands}/top.go | 6 +++--- {commands => pkg/commands}/types/command.go | 2 +- {commands => pkg/commands}/version.go | 5 ++--- {commands => pkg/commands}/wait.go | 4 ++-- {commands => pkg/commands}/x_completion.go | 4 ++-- {commands => pkg/commands}/x_flushcache.go | 2 +- {commands => pkg/commands}/x_patch.go | 4 ++-- {scwversion => pkg/scwversion}/placeholder.go | 0 {scwversion => pkg/scwversion}/version.tpl | 0 {utils => pkg/utils}/quiet.go | 0 {utils => pkg/utils}/utils.go | 0 {utils => pkg/utils}/utils_test.go | 0 48 files changed, 85 insertions(+), 85 deletions(-) rename main.go => cmd/scw/main.go (95%) rename {api => pkg/api}/README.md (100%) rename {api => pkg/api}/api.go (100%) rename {api => pkg/api}/cache.go (100%) rename {api => pkg/api}/helpers.go (99%) rename {api => pkg/api}/types.go (100%) rename {commands => pkg/commands}/attach.go (91%) rename {commands => pkg/commands}/commands.go (91%) rename {commands => pkg/commands}/commit.go (96%) rename {commands => pkg/commands}/cp.go (98%) rename {commands => pkg/commands}/create.go (94%) rename {commands => pkg/commands}/events.go (96%) rename {commands => pkg/commands}/exec.go (94%) rename {commands => pkg/commands}/help.go (97%) rename {commands => pkg/commands}/history.go (94%) rename {commands => pkg/commands}/images.go (97%) rename {commands => pkg/commands}/info.go (94%) rename {commands => pkg/commands}/inspect.go (97%) rename {commands => pkg/commands}/kill.go (92%) rename {commands => pkg/commands}/login.go (95%) rename {commands => pkg/commands}/logout.go (90%) rename {commands => pkg/commands}/logs.go (91%) rename {commands => pkg/commands}/port.go (92%) rename {commands => pkg/commands}/ps.go (95%) rename {commands => pkg/commands}/rename.go (90%) rename {commands => pkg/commands}/restart.go (95%) rename {commands => pkg/commands}/rm.go (95%) rename {commands => pkg/commands}/rmi.go (95%) rename {commands => pkg/commands}/run.go (96%) rename {commands => pkg/commands}/search.go (93%) rename {commands => pkg/commands}/start.go (94%) rename {commands => pkg/commands}/stop.go (95%) rename {commands => pkg/commands}/tag.go (94%) rename {commands => pkg/commands}/top.go (92%) rename {commands => pkg/commands}/types/command.go (98%) rename {commands => pkg/commands}/version.go (89%) rename {commands => pkg/commands}/wait.go (91%) rename {commands => pkg/commands}/x_completion.go (96%) rename {commands => pkg/commands}/x_flushcache.go (93%) rename {commands => pkg/commands}/x_patch.go (96%) rename {scwversion => pkg/scwversion}/placeholder.go (100%) rename {scwversion => pkg/scwversion}/version.tpl (100%) rename {utils => pkg/utils}/quiet.go (100%) rename {utils => pkg/utils}/utils.go (100%) rename {utils => pkg/utils}/utils_test.go (100%) diff --git a/.gitignore b/.gitignore index f744bddefd..bea63b5237 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # builds /scaleway-cli /scw -scwversion/version.go +pkg/scwversion/version.go dist/ # junk @@ -9,4 +9,5 @@ dist/ *# .#* profile.cov +profile.out .vendor diff --git a/Makefile b/Makefile index 9659b7065e..c2e33934ce 100644 --- a/Makefile +++ b/Makefile @@ -23,8 +23,8 @@ FPM_ARGS ?= \ NAME = scw -SRC = . -PACKAGES = api commands utils +SRC = cmd/scw +PACKAGES = pkg/api pkg/commands pkg/utils REV = $(shell git rev-parse HEAD || echo "nogit") TAG = $(shell git describe --tags --always || echo "nogit") BUILDER = scaleway-cli-builder @@ -43,7 +43,7 @@ COVER_LIST = $(foreach int, $(PACKAGES), $(int)_cover) all: build -build: scwversion/version.go $(BUILD_LIST) +build: pkg/scwversion/version.go $(BUILD_LIST) clean: $(CLEAN_LIST) install: $(INSTALL_LIST) test: $(TEST_LIST) @@ -59,8 +59,8 @@ cover: touch $@ -scwversion/version.go: .git - @sed 's/\(.*GITCOMMIT.* = \).*/\1"$(REV)"/;s/\(.*VERSION.* = \).*/\1"$(TAG)"/' scwversion/version.tpl > $@.tmp +pkg/scwversion/version.go: .git + @sed 's/\(.*GITCOMMIT.* = \).*/\1"$(REV)"/;s/\(.*VERSION.* = \).*/\1"$(TAG)"/' pkg/scwversion/version.tpl > $@.tmp @if [ "$$(diff $@.tmp $@ 2>&1)" != "" ]; then mv $@.tmp $@; fi @rm -f $@.tmp @@ -72,7 +72,7 @@ $(CLEAN_LIST): %_clean: $(GOCLEAN) ./$* $(INSTALL_LIST): %_install: $(GOINSTALL) ./$* -$(IREF_LIST): %_iref: scwversion/version.go +$(IREF_LIST): %_iref: pkg/scwversion/version.go $(GOTEST) -i ./$* $(TEST_LIST): %_test: $(GOTEST) ./$* @@ -83,7 +83,7 @@ $(FMT_LIST): %_fmt: $(GOFMT) ./$* -cross: scwversion/version.go +cross: pkg/scwversion/version.go docker build -t $(BUILDER) . @docker rm scaleway-cli-builer 2>/dev/null || true mkdir -p dist diff --git a/README.md b/README.md index 0b5fbc9255..965332aa5b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ chmod +x /usr/local/bin/scw To install Scaleway CLI master git, run the following command: ```bash -go get github.com/scaleway/scaleway-cli +go get github.com/scaleway/scaleway-cli/... ``` ### Requirements @@ -106,7 +106,7 @@ $ docker run -it --rm --volume=$HOME/.scwrc:/.scwrc scaleway/cli ps 2. Ensure you have `$GOPATH` and `$PATH` well configured, something like: * `export GOPATH=$HOME/go` * `export PATH=$PATH:$GOPATH/bin` -3. Install the project: `go get github.com/scaleway/scaleway-cli` +3. Install the project: `go get github.com/scaleway/scaleway-cli/...` 4. Run: `scaleway-cli` ## Usage @@ -1230,7 +1230,7 @@ Feel free to contribute :smiley::beers: 2. Ensure you have `$GOPATH` and `$PATH` well configured, something like: * `export GOPATH=$HOME/go` * `export PATH=$PATH:$GOPATH/bin` -3. Fetch the project: `go get -d github.com/scaleway/scaleway-cli` +3. Fetch the project: `go get -d github.com/scaleway/scaleway-cli/...` 4. Go to scaleway-cli directory: `cd $GOPATH/src/github.com/scaleway/scaleway-cli` 5. Hack: `emacs` 6. Build: `make` diff --git a/main.go b/cmd/scw/main.go similarity index 95% rename from main.go rename to cmd/scw/main.go index 82f205f9e0..2154acbfd0 100644 --- a/main.go +++ b/cmd/scw/main.go @@ -14,10 +14,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" flag "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/mflag" - "github.com/scaleway/scaleway-cli/api" - cmds "github.com/scaleway/scaleway-cli/commands" - "github.com/scaleway/scaleway-cli/scwversion" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + cmds "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/pkg/scwversion" + "github.com/scaleway/scaleway-cli/pkg/utils" ) // CommandListOpts holds a list of parameters diff --git a/api/README.md b/pkg/api/README.md similarity index 100% rename from api/README.md rename to pkg/api/README.md diff --git a/api/api.go b/pkg/api/api.go similarity index 100% rename from api/api.go rename to pkg/api/api.go diff --git a/api/cache.go b/pkg/api/cache.go similarity index 100% rename from api/cache.go rename to pkg/api/cache.go diff --git a/api/helpers.go b/pkg/api/helpers.go similarity index 99% rename from api/helpers.go rename to pkg/api/helpers.go index 35f4084f79..55ed9e5875 100644 --- a/api/helpers.go +++ b/pkg/api/helpers.go @@ -12,7 +12,7 @@ import ( "sync" "time" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/utils" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/namesgenerator" "github.com/scaleway/scaleway-cli/vendor/github.com/dustin/go-humanize" diff --git a/api/types.go b/pkg/api/types.go similarity index 100% rename from api/types.go rename to pkg/api/types.go diff --git a/commands/attach.go b/pkg/commands/attach.go similarity index 91% rename from commands/attach.go rename to pkg/commands/attach.go index 9253e20d2f..2a63fea8b4 100644 --- a/commands/attach.go +++ b/pkg/commands/attach.go @@ -7,8 +7,8 @@ package commands import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdAttach = &types.Command{ diff --git a/commands/commands.go b/pkg/commands/commands.go similarity index 91% rename from commands/commands.go rename to pkg/commands/commands.go index 0951c0db9a..314ff2f6c5 100644 --- a/commands/commands.go +++ b/pkg/commands/commands.go @@ -7,7 +7,7 @@ // Package commands contains CLI commands package commands -import types "github.com/scaleway/scaleway-cli/commands/types" +import types "github.com/scaleway/scaleway-cli/pkg/commands/types" // Commands is the list of enabled CLI commands var Commands = []*types.Command{ diff --git a/commands/commit.go b/pkg/commands/commit.go similarity index 96% rename from commands/commit.go rename to pkg/commands/commit.go index 68c833410c..09ca79d009 100644 --- a/commands/commit.go +++ b/pkg/commands/commit.go @@ -9,7 +9,7 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdCommit = &types.Command{ diff --git a/commands/cp.go b/pkg/commands/cp.go similarity index 98% rename from commands/cp.go rename to pkg/commands/cp.go index 9657461706..9839eaf431 100644 --- a/commands/cp.go +++ b/pkg/commands/cp.go @@ -15,9 +15,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/archive" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdCp = &types.Command{ diff --git a/commands/create.go b/pkg/commands/create.go similarity index 94% rename from commands/create.go rename to pkg/commands/create.go index 561ca28b84..10ac40afaf 100644 --- a/commands/create.go +++ b/pkg/commands/create.go @@ -9,8 +9,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdCreate = &types.Command{ diff --git a/commands/events.go b/pkg/commands/events.go similarity index 96% rename from commands/events.go rename to pkg/commands/events.go index c2c6dba598..15002b1e76 100644 --- a/commands/events.go +++ b/pkg/commands/events.go @@ -11,7 +11,7 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdEvents = &types.Command{ diff --git a/commands/exec.go b/pkg/commands/exec.go similarity index 94% rename from commands/exec.go rename to pkg/commands/exec.go index 2852c5ff36..cdd3d3847c 100644 --- a/commands/exec.go +++ b/pkg/commands/exec.go @@ -10,9 +10,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdExec = &types.Command{ diff --git a/commands/help.go b/pkg/commands/help.go similarity index 97% rename from commands/help.go rename to pkg/commands/help.go index 0ba0e42aa2..7d568c7a9b 100644 --- a/commands/help.go +++ b/pkg/commands/help.go @@ -9,7 +9,7 @@ import ( "os" "text/template" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) // CmdHelp is the 'scw help' command diff --git a/commands/history.go b/pkg/commands/history.go similarity index 94% rename from commands/history.go rename to pkg/commands/history.go index d6ec4bd7f1..a5511294e4 100644 --- a/commands/history.go +++ b/pkg/commands/history.go @@ -13,8 +13,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - types "github.com/scaleway/scaleway-cli/commands/types" - utils "github.com/scaleway/scaleway-cli/utils" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + utils "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdHistory = &types.Command{ diff --git a/commands/images.go b/pkg/commands/images.go similarity index 97% rename from commands/images.go rename to pkg/commands/images.go index fe5374a7d1..ec2f0fc47c 100644 --- a/commands/images.go +++ b/pkg/commands/images.go @@ -15,9 +15,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdImages = &types.Command{ diff --git a/commands/info.go b/pkg/commands/info.go similarity index 94% rename from commands/info.go rename to pkg/commands/info.go index 0af769f35f..a910d7efc0 100644 --- a/commands/info.go +++ b/pkg/commands/info.go @@ -11,8 +11,8 @@ import ( "github.com/scaleway/scaleway-cli/vendor/github.com/kardianos/osext" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdInfo = &types.Command{ diff --git a/commands/inspect.go b/pkg/commands/inspect.go similarity index 97% rename from commands/inspect.go rename to pkg/commands/inspect.go index 971af1e98f..aeb126e1c2 100644 --- a/commands/inspect.go +++ b/pkg/commands/inspect.go @@ -13,8 +13,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/skratchdot/open-golang/open" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdInspect = &types.Command{ diff --git a/commands/kill.go b/pkg/commands/kill.go similarity index 92% rename from commands/kill.go rename to pkg/commands/kill.go index 7ee6b9c8a0..5cf1340293 100644 --- a/commands/kill.go +++ b/pkg/commands/kill.go @@ -11,9 +11,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdKill = &types.Command{ diff --git a/commands/login.go b/pkg/commands/login.go similarity index 95% rename from commands/login.go rename to pkg/commands/login.go index b51c3e902a..befc477208 100644 --- a/commands/login.go +++ b/pkg/commands/login.go @@ -14,9 +14,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/golang.org/x/crypto/ssh/terminal" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdLogin = &types.Command{ diff --git a/commands/logout.go b/pkg/commands/logout.go similarity index 90% rename from commands/logout.go rename to pkg/commands/logout.go index 9428546e81..eef367de34 100644 --- a/commands/logout.go +++ b/pkg/commands/logout.go @@ -9,8 +9,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdLogout = &types.Command{ diff --git a/commands/logs.go b/pkg/commands/logs.go similarity index 91% rename from commands/logs.go rename to pkg/commands/logs.go index 780ee8f997..47ff441700 100644 --- a/commands/logs.go +++ b/pkg/commands/logs.go @@ -9,9 +9,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdLogs = &types.Command{ diff --git a/commands/port.go b/pkg/commands/port.go similarity index 92% rename from commands/port.go rename to pkg/commands/port.go index 78a31d9011..7f9af3e2ba 100644 --- a/commands/port.go +++ b/pkg/commands/port.go @@ -9,9 +9,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdPort = &types.Command{ diff --git a/commands/ps.go b/pkg/commands/ps.go similarity index 95% rename from commands/ps.go rename to pkg/commands/ps.go index 7eecdbd11b..29bb2667e8 100644 --- a/commands/ps.go +++ b/pkg/commands/ps.go @@ -13,8 +13,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdPs = &types.Command{ diff --git a/commands/rename.go b/pkg/commands/rename.go similarity index 90% rename from commands/rename.go rename to pkg/commands/rename.go index b1f8e787a6..86797d080a 100644 --- a/commands/rename.go +++ b/pkg/commands/rename.go @@ -7,8 +7,8 @@ package commands import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdRename = &types.Command{ diff --git a/commands/restart.go b/pkg/commands/restart.go similarity index 95% rename from commands/restart.go rename to pkg/commands/restart.go index a13b17ef55..ffa1729d5b 100644 --- a/commands/restart.go +++ b/pkg/commands/restart.go @@ -10,7 +10,7 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdRestart = &types.Command{ diff --git a/commands/rm.go b/pkg/commands/rm.go similarity index 95% rename from commands/rm.go rename to pkg/commands/rm.go index f2c59f986f..595da8f1ad 100644 --- a/commands/rm.go +++ b/pkg/commands/rm.go @@ -10,7 +10,7 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdRm = &types.Command{ diff --git a/commands/rmi.go b/pkg/commands/rmi.go similarity index 95% rename from commands/rmi.go rename to pkg/commands/rmi.go index f804a721f9..dd1eb4968c 100644 --- a/commands/rmi.go +++ b/pkg/commands/rmi.go @@ -10,7 +10,7 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdRmi = &types.Command{ diff --git a/commands/run.go b/pkg/commands/run.go similarity index 96% rename from commands/run.go rename to pkg/commands/run.go index 3306929036..23190dacac 100644 --- a/commands/run.go +++ b/pkg/commands/run.go @@ -10,9 +10,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - api "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + api "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdRun = &types.Command{ diff --git a/commands/search.go b/pkg/commands/search.go similarity index 93% rename from commands/search.go rename to pkg/commands/search.go index 6716c7c839..3c0e871c0f 100644 --- a/commands/search.go +++ b/pkg/commands/search.go @@ -11,9 +11,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdSearch = &types.Command{ diff --git a/commands/start.go b/pkg/commands/start.go similarity index 94% rename from commands/start.go rename to pkg/commands/start.go index bc780188b5..44d81a4079 100644 --- a/commands/start.go +++ b/pkg/commands/start.go @@ -11,8 +11,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdStart = &types.Command{ diff --git a/commands/stop.go b/pkg/commands/stop.go similarity index 95% rename from commands/stop.go rename to pkg/commands/stop.go index 4546ce656f..8a1f31bf4d 100644 --- a/commands/stop.go +++ b/pkg/commands/stop.go @@ -11,8 +11,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdStop = &types.Command{ diff --git a/commands/tag.go b/pkg/commands/tag.go similarity index 94% rename from commands/tag.go rename to pkg/commands/tag.go index f54287b148..ad96bd75cd 100644 --- a/commands/tag.go +++ b/pkg/commands/tag.go @@ -9,7 +9,7 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdTag = &types.Command{ diff --git a/commands/top.go b/pkg/commands/top.go similarity index 92% rename from commands/top.go rename to pkg/commands/top.go index 0b28cd4c87..ae27d63f7b 100644 --- a/commands/top.go +++ b/pkg/commands/top.go @@ -12,9 +12,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" - "github.com/scaleway/scaleway-cli/utils" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdTop = &types.Command{ diff --git a/commands/types/command.go b/pkg/commands/types/command.go similarity index 98% rename from commands/types/command.go rename to pkg/commands/types/command.go index 364313e58e..145fb4c2b0 100644 --- a/commands/types/command.go +++ b/pkg/commands/types/command.go @@ -15,7 +15,7 @@ import ( flag "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/mflag" - "github.com/scaleway/scaleway-cli/api" + "github.com/scaleway/scaleway-cli/pkg/api" ) // Command is a Scaleway command diff --git a/commands/version.go b/pkg/commands/version.go similarity index 89% rename from commands/version.go rename to pkg/commands/version.go index 7449ce02b3..1b7d6488d7 100644 --- a/commands/version.go +++ b/pkg/commands/version.go @@ -8,9 +8,8 @@ import ( "fmt" "runtime" - "github.com/scaleway/scaleway-cli/scwversion" - - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/scwversion" ) var cmdVersion = &types.Command{ diff --git a/commands/wait.go b/pkg/commands/wait.go similarity index 91% rename from commands/wait.go rename to pkg/commands/wait.go index 5c60e4b106..a41335d5c8 100644 --- a/commands/wait.go +++ b/pkg/commands/wait.go @@ -9,8 +9,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdWait = &types.Command{ diff --git a/commands/x_completion.go b/pkg/commands/x_completion.go similarity index 96% rename from commands/x_completion.go rename to pkg/commands/x_completion.go index 3b7519ea8f..d376eb4274 100644 --- a/commands/x_completion.go +++ b/pkg/commands/x_completion.go @@ -10,8 +10,8 @@ import ( "sort" "strings" - types "github.com/scaleway/scaleway-cli/commands/types" - utils "github.com/scaleway/scaleway-cli/utils" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" + utils "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdCompletion = &types.Command{ diff --git a/commands/x_flushcache.go b/pkg/commands/x_flushcache.go similarity index 93% rename from commands/x_flushcache.go rename to pkg/commands/x_flushcache.go index 531212efee..5eae6a9a26 100644 --- a/commands/x_flushcache.go +++ b/pkg/commands/x_flushcache.go @@ -8,7 +8,7 @@ import ( "fmt" "log" - types "github.com/scaleway/scaleway-cli/commands/types" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdFlushCache = &types.Command{ diff --git a/commands/x_patch.go b/pkg/commands/x_patch.go similarity index 96% rename from commands/x_patch.go rename to pkg/commands/x_patch.go index fffd4506f1..6fc7bad94f 100644 --- a/commands/x_patch.go +++ b/pkg/commands/x_patch.go @@ -10,8 +10,8 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - api "github.com/scaleway/scaleway-cli/api" - types "github.com/scaleway/scaleway-cli/commands/types" + api "github.com/scaleway/scaleway-cli/pkg/api" + types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) var cmdPatch = &types.Command{ diff --git a/scwversion/placeholder.go b/pkg/scwversion/placeholder.go similarity index 100% rename from scwversion/placeholder.go rename to pkg/scwversion/placeholder.go diff --git a/scwversion/version.tpl b/pkg/scwversion/version.tpl similarity index 100% rename from scwversion/version.tpl rename to pkg/scwversion/version.tpl diff --git a/utils/quiet.go b/pkg/utils/quiet.go similarity index 100% rename from utils/quiet.go rename to pkg/utils/quiet.go diff --git a/utils/utils.go b/pkg/utils/utils.go similarity index 100% rename from utils/utils.go rename to pkg/utils/utils.go diff --git a/utils/utils_test.go b/pkg/utils/utils_test.go similarity index 100% rename from utils/utils_test.go rename to pkg/utils/utils_test.go From e07a1fb197d2522b8c327de90c60c3a2948384b8 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 14:54:31 +0200 Subject: [PATCH 02/36] Refactored ps command (#80) --- pkg/commands/ps.go | 54 ++++++++++++++++++++++++++--------- pkg/commands/types/command.go | 23 +++++++++++++++ 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/pkg/commands/ps.go b/pkg/commands/ps.go index 29bb2667e8..e3be773eaa 100644 --- a/pkg/commands/ps.go +++ b/pkg/commands/ps.go @@ -6,7 +6,6 @@ package commands import ( "fmt" - "os" "text/tabwriter" "time" @@ -18,7 +17,7 @@ import ( ) var cmdPs = &types.Command{ - Exec: runPs, + Exec: cmdExecPs, UsageLine: "ps [OPTIONS]", Description: "List servers", Help: "List servers. By default, only running servers are displayed.", @@ -41,39 +40,66 @@ var psNoTrunc bool // -no-trunc flag var psN int // -n flag var psHelp bool // -h, --help flag -func runPs(cmd *types.Command, args []string) { +// PsArgs are flags for the `RunPs` function +type PsArgs struct { + All bool + Latest bool + NLast int + NoTrunc bool + Quiet bool +} + +func cmdExecPs(cmd *types.Command, rawArgs []string) { if psHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } - limit := psN - if psL { + args := PsArgs{ + All: psA, + Latest: psL, + Quiet: psQ, + NoTrunc: psNoTrunc, + NLast: psN, + } + ctx := cmd.GetContext(rawArgs) + err := RunPs(ctx, args) + if err != nil { + log.Fatalf("Cannot exec 'ps': %v", err) + } +} + +// RunPs is the handler for 'scw ps' +func RunPs(ctx types.CommandContext, args PsArgs) error { + limit := args.NLast + if args.Latest { limit = 1 } - servers, err := cmd.API.GetServers(psA || psN > 0 || psL, limit) + all := args.All || args.NLast > 0 || args.Latest + servers, err := ctx.API.GetServers(all, limit) if err != nil { - log.Fatalf("Unable to fetch servers from the Scaleway API: %v", err) + return fmt.Errorf("Unable to fetch servers from the Scaleway API: %v", err) } - w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) + w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0) defer w.Flush() - if !psQ { + if !args.Quiet { fmt.Fprintf(w, "SERVER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAME\n") } for _, server := range *servers { - if psQ { + if args.Quiet { fmt.Fprintf(w, "%s\n", server.Identifier) } else { - shortID := utils.TruncIf(server.Identifier, 8, !psNoTrunc) - shortImage := utils.TruncIf(utils.Wordify(server.Image.Name), 25, !psNoTrunc) - shortName := utils.TruncIf(utils.Wordify(server.Name), 25, !psNoTrunc) + shortID := utils.TruncIf(server.Identifier, 8, !args.NoTrunc) + shortImage := utils.TruncIf(utils.Wordify(server.Image.Name), 25, !args.NoTrunc) + shortName := utils.TruncIf(utils.Wordify(server.Name), 25, !args.NoTrunc) creationTime, _ := time.Parse("2006-01-02T15:04:05.000000+00:00", server.CreationDate) shortCreationDate := units.HumanDuration(time.Now().UTC().Sub(creationTime)) port := server.PublicAddress.IP fmt.Fprintf(w, "%s\t%s\t\t%s\t%s\t%s\t%s\n", shortID, shortImage, shortCreationDate, server.State, port, shortName) } } + return nil } diff --git a/pkg/commands/types/command.go b/pkg/commands/types/command.go index 145fb4c2b0..152afee71f 100644 --- a/pkg/commands/types/command.go +++ b/pkg/commands/types/command.go @@ -8,6 +8,7 @@ package types import ( "bytes" "fmt" + "io" "log" "os" "strings" @@ -45,6 +46,28 @@ type Command struct { API *api.ScalewayAPI } +// CommandContext is passed to all commands and contains streams, environment, api and arguments +type CommandContext struct { + Stdin io.Reader + Stdout io.Writer + Stderr io.Writer + Env []string + RawArgs []string + API *api.ScalewayAPI +} + +// GetContext returns a standard context, with real stdin, stdout, stderr, a configured API and raw arguments +func (c *Command) GetContext(rawArgs []string) CommandContext { + return CommandContext{ + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + Env: os.Environ(), + RawArgs: rawArgs, + API: c.API, + } +} + // Name returns the command's name func (c *Command) Name() string { name := c.UsageLine From 95165d09bbd84a2493652563819d9a610bafeb49 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 15:06:59 +0200 Subject: [PATCH 03/36] Refactored 'exec' command (#80) --- pkg/commands/exec.go | 77 +++++++++++++++++++++++++---------- pkg/commands/types/command.go | 6 +++ 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/pkg/commands/exec.go b/pkg/commands/exec.go index cdd3d3847c..ce981fbecc 100644 --- a/pkg/commands/exec.go +++ b/pkg/commands/exec.go @@ -5,18 +5,18 @@ package commands import ( - "os" + "fmt" "time" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdExec = &types.Command{ - Exec: runExec, + Exec: cmdExecExec, UsageLine: "exec [OPTIONS] SERVER [COMMAND] [ARGS...]", Description: "Run a command on a running server", Help: "Run a command on a running server.", @@ -47,57 +47,92 @@ var execTimeout float64 // -T flag var execHelp bool // -h, --help flag var execGateway string // -g, --gateway flag -func runExec(cmd *types.Command, args []string) { +// ExecArgs are flags for the `RunExec` function +type ExecArgs struct { + Timeout float64 + Wait bool + Gateway string + Server string + Command []string +} + +func cmdExecExec(cmd *types.Command, rawArgs []string) { if execHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) + args := ExecArgs{ + Timeout: execTimeout, + Wait: execW, + Gateway: execGateway, + Server: rawArgs[0], + Command: rawArgs[1:], + } + ctx := cmd.GetContext(rawArgs) + err := RunExec(ctx, args) + if err != nil { + log.Fatalf("Cannot exec 'exec': %v", err) + } +} + +// RunExec is the handler for 'scw exec' +func RunExec(ctx types.CommandContext, args ExecArgs) error { + serverID := ctx.API.GetServerID(args.Server) // Resolve gateway - if execGateway == "" { - execGateway = os.Getenv("SCW_GATEWAY") + if args.Gateway == "" { + args.Gateway = ctx.Getenv("SCW_GATEWAY") } var gateway string var err error - if execGateway == serverID || execGateway == args[0] { + if args.Gateway == serverID || args.Gateway == args.Server { + log.Debugf("The server and the gateway are the same host, using direct access to the server") gateway = "" } else { - gateway, err = api.ResolveGateway(cmd.API, execGateway) + gateway, err = api.ResolveGateway(ctx.API, args.Gateway) if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", execGateway, err) + return fmt.Errorf("Cannot resolve Gateway '%s': %v", args.Gateway, err) + } + if gateway != "" { + log.Debugf("The server will be accessed using the gateway '%s' as a SSH relay", gateway) } } var server *api.ScalewayServer - if execW { + if args.Wait { // --wait - server, err = api.WaitForServerReady(cmd.API, serverID, gateway) + log.Debugf("Waiting for server to be ready") + server, err = api.WaitForServerReady(ctx.API, serverID, gateway) if err != nil { - log.Fatalf("Failed to wait for server to be ready, %v", err) + return fmt.Errorf("Failed to wait for server to be ready, %v", err) } } else { // no --wait - server, err = cmd.API.GetServer(serverID) + log.Debugf("scw won't wait for the server to be ready, if it is not, the command will fail") + server, err = ctx.API.GetServer(serverID) if err != nil { - log.Fatalf("Failed to get server information for %s: %v", serverID, err) + return fmt.Errorf("Failed to get server information for %s: %v", serverID, err) } } - if execTimeout > 0 { + // --timeout + if args.Timeout > 0 { + log.Debugf("Setting up a global timeout of %d seconds", args.Timeout) + // FIXME: avoid use of log.Fatalf here go func() { - time.Sleep(time.Duration(execTimeout*1000) * time.Millisecond) + time.Sleep(time.Duration(args.Timeout*1000) * time.Millisecond) log.Fatalf("Operation timed out") }() } - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args[1:], !execW, gateway) + err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, !args.Wait, gateway) if err != nil { - log.Fatalf("%v", err) - os.Exit(1) + return fmt.Errorf("Failed to run the command: %v", err) } + log.Debugf("Command successfuly executed") + return nil } diff --git a/pkg/commands/types/command.go b/pkg/commands/types/command.go index 152afee71f..3b2d8b07b5 100644 --- a/pkg/commands/types/command.go +++ b/pkg/commands/types/command.go @@ -56,6 +56,12 @@ type CommandContext struct { API *api.ScalewayAPI } +// Getenv returns the equivalent of os.Getenv for the CommandContext.Env +func (c *CommandContext) Getenv(key string) string { + // FIXME: parse c.Env instead + return os.Getenv(key) +} + // GetContext returns a standard context, with real stdin, stdout, stderr, a configured API and raw arguments func (c *Command) GetContext(rawArgs []string) CommandContext { return CommandContext{ From fea23f5af8d60f29b5c2e759f9d0fdb5eb45f7ad Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 15:31:56 +0200 Subject: [PATCH 04/36] Refactored 'commit' command (#80) --- pkg/commands/commit.go | 46 +++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/pkg/commands/commit.go b/pkg/commands/commit.go index 09ca79d009..57c9e096b2 100644 --- a/pkg/commands/commit.go +++ b/pkg/commands/commit.go @@ -13,7 +13,7 @@ import ( ) var cmdCommit = &types.Command{ - Exec: runCommit, + Exec: cmdExecCommit, UsageLine: "commit [OPTIONS] SERVER [NAME]", Description: "Create a new snapshot from a server's volume", Help: "Create a new snapshot from a server's volume.", @@ -32,29 +32,55 @@ func init() { var commitVolume int // -v, --volume flag var commitHelp bool // -h, --help flag -func runCommit(cmd *types.Command, args []string) { +// CommitArgs are flags for the `RunCommit` function +type CommitArgs struct { + Volume int + Server string + Name string +} + +func cmdExecCommit(cmd *types.Command, rawArgs []string) { if commitHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - server, err := cmd.API.GetServer(serverID) + args := CommitArgs{ + Volume: commitVolume, + Server: rawArgs[0], + Name: "", + } + if len(rawArgs) > 1 { + args.Name = rawArgs[1] + } + + ctx := cmd.GetContext(rawArgs) + err := RunCommit(ctx, args) + if err != nil { + log.Fatalf("Cannot execute 'commit': %v", err) + } +} + +// RunCommit is the handler for 'scw commit' +func RunCommit(ctx types.CommandContext, args CommitArgs) error { + serverID := ctx.API.GetServerID(args.Server) + server, err := ctx.API.GetServer(serverID) if err != nil { - log.Fatalf("Cannot fetch server: %v", err) + return fmt.Errorf("Cannot fetch server: %v", err) } var volume = server.Volumes[fmt.Sprintf("%d", commitVolume)] var name string - if len(args) > 1 { - name = args[1] + if args.Name != "" { + name = args.Name } else { name = volume.Name + "-snapshot" } - snapshot, err := cmd.API.PostSnapshot(volume.Identifier, name) + snapshot, err := ctx.API.PostSnapshot(volume.Identifier, name) if err != nil { - log.Fatalf("Cannot create snapshot: %v", err) + return fmt.Errorf("Cannot create snapshot: %v", err) } fmt.Println(snapshot) + return nil } From 712735ae02c107bc60d90cc4bc5c679e69803903 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 15:48:55 +0200 Subject: [PATCH 05/36] Refactored 'attach' command (#80) --- pkg/commands/attach.go | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/pkg/commands/attach.go b/pkg/commands/attach.go index 2a63fea8b4..ff25879fb1 100644 --- a/pkg/commands/attach.go +++ b/pkg/commands/attach.go @@ -5,14 +5,14 @@ package commands import ( - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "log" types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) var cmdAttach = &types.Command{ - Exec: runAttach, + Exec: cmdExecAttach, UsageLine: "attach [OPTIONS] SERVER", Description: "Attach to a server serial console", Help: "Attach to a running server serial console.", @@ -32,18 +32,34 @@ func init() { var attachHelp bool // -h, --help flag var attachNoStdin bool // --no-stdin flag -func runAttach(cmd *types.Command, args []string) { +// AttachArgs are flags for the `RunAttach` function +type AttachArgs struct { + NoStdin bool + Server string +} + +func cmdExecAttach(cmd *types.Command, rawArgs []string) { if attachHelp { cmd.PrintUsage() } - if len(args) != 1 { + if len(rawArgs) != 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - - err := utils.AttachToSerial(serverID, cmd.API.Token, !attachNoStdin) + args := AttachArgs{ + NoStdin: attachNoStdin, + Server: rawArgs[0], + } + ctx := cmd.GetContext(rawArgs) + err := RunAttach(ctx, args) if err != nil { - log.Fatalf("%v", err) + log.Fatalf("Cannot execute 'attach': %v", err) } } + +// RunAttach is the handler for 'scw attach' +func RunAttach(ctx types.CommandContext, args AttachArgs) error { + serverID := ctx.API.GetServerID(args.Server) + + return utils.AttachToSerial(serverID, ctx.API.Token, !args.NoStdin) +} From 7bc8e27ebf6b6a841bd6736743770e60d62d9b70 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 15:52:01 +0200 Subject: [PATCH 06/36] Refactored 'events' command (#80) --- pkg/commands/events.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/pkg/commands/events.go b/pkg/commands/events.go index 15002b1e76..f7ec2169f9 100644 --- a/pkg/commands/events.go +++ b/pkg/commands/events.go @@ -15,7 +15,7 @@ import ( ) var cmdEvents = &types.Command{ - Exec: runEvents, + Exec: cmdExecEvents, UsageLine: "events [OPTIONS]", Description: "Get real time events from the API", Help: "Get real time events from the API.", @@ -28,34 +28,47 @@ func init() { // Flags var eventsHelp bool // -h, --help flag -func runEvents(cmd *types.Command, args []string) { +type EventsArgs struct{} + +func cmdExecEvents(cmd *types.Command, rawArgs []string) { if eventsHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } - events, err := cmd.API.GetTasks() + args := EventsArgs{} + ctx := cmd.GetContext(rawArgs) + err := RunEvents(ctx, args) + if err != nil { + log.Fatalf("Cannot execute 'events': %v", err) + } +} + +// RunEvents is the handler for 'scw events' +func RunEvents(ctx types.CommandContext, args EventsArgs) error { + events, err := ctx.API.GetTasks() if err != nil { - log.Fatalf("unable to fetch tasks from the Scaleway API: %v", err) + return fmt.Errorf("unable to fetch tasks from the Scaleway API: %v", err) } for _, event := range *events { startedAt, err := time.Parse("2006-01-02T15:04:05.000000+00:00", event.StartDate) if err != nil { - log.Fatalf("unable to parse started date from the Scaleway API: %v", err) + return fmt.Errorf("unable to parse started date from the Scaleway API: %v", err) } terminatedAt := "" if event.TerminationDate != "" { terminatedAtTime, err := time.Parse("2006-01-02T15:04:05.000000+00:00", event.TerminationDate) if err != nil { - log.Fatalf("unable to parse terminated date from the Scaleway API: %v", err) + return fmt.Errorf("unable to parse terminated date from the Scaleway API: %v", err) } terminatedAt = units.HumanDuration(time.Now().UTC().Sub(terminatedAtTime)) } fmt.Printf("%s %s: %s (%s %d) %s\n", startedAt, event.HrefFrom, event.Description, event.Status, event.Progress, terminatedAt) } + return nil } From 889c9c01765db63ba177e724d13fd0e1e43e09a7 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 16:04:36 +0200 Subject: [PATCH 07/36] Refactored 'login' command (#80) --- pkg/commands/login.go | 46 +++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/pkg/commands/login.go b/pkg/commands/login.go index befc477208..06f7684961 100644 --- a/pkg/commands/login.go +++ b/pkg/commands/login.go @@ -20,7 +20,7 @@ import ( ) var cmdLogin = &types.Command{ - Exec: runLogin, + Exec: cmdExecLogin, UsageLine: "login [OPTIONS]", Description: "Log in to Scaleway API", Help: `Generates a configuration file in '/home/$USER/.scwrc' @@ -32,6 +32,7 @@ You can get your credentials on https://cloud.scaleway.com/#/credentials } func promptUser(prompt string, output *string, echo bool) { + // FIXME: should use stdin/stdout from command context fmt.Fprintf(os.Stdout, prompt) os.Stdout.Sync() @@ -59,50 +60,69 @@ var organization string // -o flag var token string // -t flag var loginHelp bool // -h, --help flag -func runLogin(cmd *types.Command, args []string) { +type LoginArgs struct { + Organization string + Token string +} + +func cmdExecLogin(cmd *types.Command, rawArgs []string) { if loginHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } + args := LoginArgs{ + Organization: organization, + Token: token, + } + ctx := cmd.GetContext(rawArgs) + err := RunLogin(ctx, args) + if err != nil { + log.Fatalf("Cannot execute 'login': %v", err) + } +} + +// RunLogin is the handler for 'scw login' +func RunLogin(ctx types.CommandContext, args LoginArgs) error { if len(organization) == 0 { fmt.Println("You can get your credentials on https://cloud.scaleway.com/#/credentials") - promptUser("Organization (access key): ", &organization, true) + promptUser("Organization (access key): ", &args.Organization, true) } - if len(token) == 0 { - promptUser("Token: ", &token, false) + if args.Token == "" { + promptUser("Token: ", &args.Token, false) } cfg := &api.Config{ APIEndPoint: "https://account.scaleway.com/", - Organization: strings.Trim(organization, "\n"), - Token: strings.Trim(token, "\n"), + Organization: strings.Trim(args.Organization, "\n"), + Token: strings.Trim(args.Token, "\n"), } api, err := api.NewScalewayAPI(cfg.APIEndPoint, cfg.Organization, cfg.Token) if err != nil { - log.Fatalf("Unable to create ScalewayAPI: %s", err) + return fmt.Errorf("Unable to create ScalewayAPI: %s", err) } err = api.CheckCredentials() if err != nil { - log.Fatalf("Unable to contact ScalewayAPI: %s", err) + return fmt.Errorf("Unable to contact ScalewayAPI: %s", err) } scwrcPath, err := utils.GetConfigFilePath() if err != nil { - log.Fatalf("Unable to get scwrc config file path: %s", err) + return fmt.Errorf("Unable to get scwrc config file path: %s", err) } scwrc, err := os.OpenFile(scwrcPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600) if err != nil { - log.Fatalf("Unable to create scwrc config file: %s", err) + return fmt.Errorf("Unable to create scwrc config file: %s", err) } defer scwrc.Close() encoder := json.NewEncoder(scwrc) cfg.APIEndPoint = "https://api.scaleway.com/" err = encoder.Encode(cfg) if err != nil { - log.Fatalf("Unable to encode scw config file: %s", err) + return fmt.Errorf("Unable to encode scw config file: %s", err) } + return nil } From d3b55c1cf6f22345fd224a5c2dbd6a78e0ad6405 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:04:56 +0200 Subject: [PATCH 08/36] Splitted out code between cli and commands (#80) --- Makefile | 2 +- cmd/scw/main.go | 2 +- pkg/cli/attach.go | 50 +++++++++++++++ pkg/{commands/types => cli}/command.go | 27 ++------ pkg/{commands => cli}/commands.go | 6 +- pkg/cli/commit.go | 55 ++++++++++++++++ pkg/{commands => cli}/cp.go | 7 +-- pkg/{commands => cli}/create.go | 7 +-- pkg/cli/events.go | 40 ++++++++++++ pkg/cli/exec.go | 64 +++++++++++++++++++ pkg/{commands => cli}/help.go | 11 ++-- pkg/{commands => cli}/history.go | 7 +-- pkg/{commands => cli}/images.go | 7 +-- pkg/{commands => cli}/info.go | 7 +-- pkg/{commands => cli}/inspect.go | 7 +-- pkg/{commands => cli}/kill.go | 7 +-- pkg/cli/login.go | 52 +++++++++++++++ pkg/{commands => cli}/logout.go | 7 +-- pkg/{commands => cli}/logs.go | 7 +-- pkg/{commands => cli}/port.go | 7 +-- pkg/cli/ps.go | 56 +++++++++++++++++ pkg/{commands => cli}/rename.go | 7 +-- pkg/{commands => cli}/restart.go | 8 +-- pkg/{commands => cli}/rm.go | 8 +-- pkg/{commands => cli}/rmi.go | 8 +-- pkg/{commands => cli}/run.go | 7 +-- pkg/{commands => cli}/search.go | 7 +-- pkg/{commands => cli}/start.go | 7 +-- pkg/{commands => cli}/stop.go | 7 +-- pkg/{commands => cli}/tag.go | 8 +-- pkg/{commands => cli}/top.go | 7 +-- pkg/{commands => cli}/version.go | 7 +-- pkg/{commands => cli}/wait.go | 7 +-- pkg/{commands => cli}/x_completion.go | 11 ++-- pkg/{commands => cli}/x_flushcache.go | 11 ++-- pkg/{commands => cli}/x_patch.go | 7 +-- pkg/commands/attach.go | 49 +-------------- pkg/commands/command.go | 29 +++++++++ pkg/commands/commit.go | 52 +-------------- pkg/commands/events.go | 35 +---------- pkg/commands/exec.go | 57 +---------------- pkg/commands/login.go | 87 +++++++------------------- pkg/commands/ps.go | 50 +-------------- 43 files changed, 468 insertions(+), 443 deletions(-) create mode 100644 pkg/cli/attach.go rename pkg/{commands/types => cli}/command.go (83%) rename pkg/{commands => cli}/commands.go (84%) create mode 100644 pkg/cli/commit.go rename pkg/{commands => cli}/cp.go (97%) rename pkg/{commands => cli}/create.go (91%) create mode 100644 pkg/cli/events.go create mode 100644 pkg/cli/exec.go rename pkg/{commands => cli}/help.go (88%) rename pkg/{commands => cli}/history.go (92%) rename pkg/{commands => cli}/images.go (96%) rename pkg/{commands => cli}/info.go (91%) rename pkg/{commands => cli}/inspect.go (96%) rename pkg/{commands => cli}/kill.go (91%) create mode 100644 pkg/cli/login.go rename pkg/{commands => cli}/logout.go (85%) rename pkg/{commands => cli}/logs.go (91%) rename pkg/{commands => cli}/port.go (91%) create mode 100644 pkg/cli/ps.go rename pkg/{commands => cli}/rename.go (85%) rename pkg/{commands => cli}/restart.go (86%) rename pkg/{commands => cli}/rm.go (87%) rename pkg/{commands => cli}/rmi.go (87%) rename pkg/{commands => cli}/run.go (96%) rename pkg/{commands => cli}/search.go (93%) rename pkg/{commands => cli}/start.go (91%) rename pkg/{commands => cli}/stop.go (93%) rename pkg/{commands => cli}/tag.go (85%) rename pkg/{commands => cli}/top.go (91%) rename pkg/{commands => cli}/version.go (84%) rename pkg/{commands => cli}/wait.go (86%) rename pkg/{commands => cli}/x_completion.go (92%) rename pkg/{commands => cli}/x_flushcache.go (75%) rename pkg/{commands => cli}/x_patch.go (94%) create mode 100644 pkg/commands/command.go diff --git a/Makefile b/Makefile index c2e33934ce..c8c90dba1f 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ FPM_ARGS ?= \ NAME = scw SRC = cmd/scw -PACKAGES = pkg/api pkg/commands pkg/utils +PACKAGES = pkg/api pkg/commands pkg/utils pkg/cli REV = $(shell git rev-parse HEAD || echo "nogit") TAG = $(shell git describe --tags --always || echo "nogit") BUILDER = scaleway-cli-builder diff --git a/cmd/scw/main.go b/cmd/scw/main.go index 2154acbfd0..85c8b566b2 100644 --- a/cmd/scw/main.go +++ b/cmd/scw/main.go @@ -15,7 +15,7 @@ import ( flag "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/mflag" "github.com/scaleway/scaleway-cli/pkg/api" - cmds "github.com/scaleway/scaleway-cli/pkg/commands" + cmds "github.com/scaleway/scaleway-cli/pkg/cli" "github.com/scaleway/scaleway-cli/pkg/scwversion" "github.com/scaleway/scaleway-cli/pkg/utils" ) diff --git a/pkg/cli/attach.go b/pkg/cli/attach.go new file mode 100644 index 0000000000..2901622d11 --- /dev/null +++ b/pkg/cli/attach.go @@ -0,0 +1,50 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package cli + +import ( + "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" +) + +var cmdAttach = &Command{ + Exec: cmdExecAttach, + UsageLine: "attach [OPTIONS] SERVER", + Description: "Attach to a server serial console", + Help: "Attach to a running server serial console.", + Examples: ` + $ scw attach my-running-server + $ scw attach $(scw start my-stopped-server) + $ scw attach $(scw start $(scw create ubuntu-vivid)) +`, +} + +func init() { + cmdAttach.Flag.BoolVar(&attachHelp, []string{"h", "-help"}, false, "Print usage") + cmdAttach.Flag.BoolVar(&attachNoStdin, []string{"-no-stdin"}, false, "Do not attach stdin") +} + +// Flags +var attachHelp bool // -h, --help flag +var attachNoStdin bool // --no-stdin flag + +func cmdExecAttach(cmd *Command, rawArgs []string) { + if attachHelp { + cmd.PrintUsage() + } + if len(rawArgs) != 1 { + cmd.PrintShortUsage() + } + + args := commands.AttachArgs{ + NoStdin: attachNoStdin, + Server: rawArgs[0], + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunAttach(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'attach': %v", err) + } +} diff --git a/pkg/commands/types/command.go b/pkg/cli/command.go similarity index 83% rename from pkg/commands/types/command.go rename to pkg/cli/command.go index 3b2d8b07b5..97b4959520 100644 --- a/pkg/commands/types/command.go +++ b/pkg/cli/command.go @@ -2,13 +2,12 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -// Golang structs for scw commands -package types +package cli +// Command is a Scaleway command import ( "bytes" "fmt" - "io" "log" "os" "strings" @@ -17,9 +16,9 @@ import ( flag "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/mflag" "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/commands" ) -// Command is a Scaleway command type Command struct { // Exec executes the command Exec func(cmd *Command, args []string) @@ -46,25 +45,9 @@ type Command struct { API *api.ScalewayAPI } -// CommandContext is passed to all commands and contains streams, environment, api and arguments -type CommandContext struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer - Env []string - RawArgs []string - API *api.ScalewayAPI -} - -// Getenv returns the equivalent of os.Getenv for the CommandContext.Env -func (c *CommandContext) Getenv(key string) string { - // FIXME: parse c.Env instead - return os.Getenv(key) -} - // GetContext returns a standard context, with real stdin, stdout, stderr, a configured API and raw arguments -func (c *Command) GetContext(rawArgs []string) CommandContext { - return CommandContext{ +func (c *Command) GetContext(rawArgs []string) commands.CommandContext { + return commands.CommandContext{ Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, diff --git a/pkg/commands/commands.go b/pkg/cli/commands.go similarity index 84% rename from pkg/commands/commands.go rename to pkg/cli/commands.go index 314ff2f6c5..502321e41f 100644 --- a/pkg/commands/commands.go +++ b/pkg/cli/commands.go @@ -5,12 +5,10 @@ // Docker-style commands to manage BareMetal servers // Package commands contains CLI commands -package commands - -import types "github.com/scaleway/scaleway-cli/pkg/commands/types" +package cli // Commands is the list of enabled CLI commands -var Commands = []*types.Command{ +var Commands = []*Command{ CmdHelp, cmdAttach, diff --git a/pkg/cli/commit.go b/pkg/cli/commit.go new file mode 100644 index 0000000000..16d036e326 --- /dev/null +++ b/pkg/cli/commit.go @@ -0,0 +1,55 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package cli + +import ( + "log" + + "github.com/scaleway/scaleway-cli/pkg/commands" +) + +var cmdCommit = &Command{ + Exec: cmdExecCommit, + UsageLine: "commit [OPTIONS] SERVER [NAME]", + Description: "Create a new snapshot from a server's volume", + Help: "Create a new snapshot from a server's volume.", + Examples: ` + $ scw commit my-stopped-server + $ scw commit -v 1 my-stopped-server +`, +} + +func init() { + cmdCommit.Flag.IntVar(&commitVolume, []string{"v", "-volume"}, 0, "Volume slot") + cmdCommit.Flag.BoolVar(&commitHelp, []string{"h", "-help"}, false, "Print usage") +} + +// Flags +var commitVolume int // -v, --volume flag +var commitHelp bool // -h, --help flag + +func cmdExecCommit(cmd *Command, rawArgs []string) { + if commitHelp { + cmd.PrintUsage() + } + if len(rawArgs) < 1 { + cmd.PrintShortUsage() + } + + args := commands.CommitArgs{ + Volume: commitVolume, + Server: rawArgs[0], + Name: "", + } + if len(rawArgs) > 1 { + args.Name = rawArgs[1] + } + + ctx := cmd.GetContext(rawArgs) + err := commands.RunCommit(ctx, args) + if err != nil { + log.Fatalf("Cannot execute 'commit': %v", err) + } +} diff --git a/pkg/commands/cp.go b/pkg/cli/cp.go similarity index 97% rename from pkg/commands/cp.go rename to pkg/cli/cp.go index 9839eaf431..fd8fdc170d 100644 --- a/pkg/commands/cp.go +++ b/pkg/cli/cp.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -16,11 +16,10 @@ import ( "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/archive" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdCp = &types.Command{ +var cmdCp = &Command{ Exec: runCp, UsageLine: "cp [OPTIONS] SERVER:PATH|HOSTPATH|- SERVER:PATH|HOSTPATH|-", Description: "Copy files/folders from a PATH on the server to a HOSTDIR on the host", @@ -230,7 +229,7 @@ func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destin return err } -func runCp(cmd *types.Command, args []string) { +func runCp(cmd *Command, args []string) { if cpHelp { cmd.PrintUsage() } diff --git a/pkg/commands/create.go b/pkg/cli/create.go similarity index 91% rename from pkg/commands/create.go rename to pkg/cli/create.go index 10ac40afaf..450de31f9e 100644 --- a/pkg/commands/create.go +++ b/pkg/cli/create.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -10,10 +10,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdCreate = &types.Command{ +var cmdCreate = &Command{ Exec: runCreate, UsageLine: "create [OPTIONS] IMAGE", Description: "Create a new server but do not start it", @@ -42,7 +41,7 @@ var createEnv string // -e, --env flag var createVolume string // -v, --volume flag var createHelp bool // -h, --help flag -func runCreate(cmd *types.Command, args []string) { +func runCreate(cmd *Command, args []string) { if createHelp { cmd.PrintUsage() } diff --git a/pkg/cli/events.go b/pkg/cli/events.go new file mode 100644 index 0000000000..ab68e7e447 --- /dev/null +++ b/pkg/cli/events.go @@ -0,0 +1,40 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package cli + +import ( + "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" +) + +var cmdEvents = &Command{ + Exec: cmdExecEvents, + UsageLine: "events [OPTIONS]", + Description: "Get real time events from the API", + Help: "Get real time events from the API.", +} + +func init() { + cmdEvents.Flag.BoolVar(&eventsHelp, []string{"h", "-help"}, false, "Print usage") +} + +// Flags +var eventsHelp bool // -h, --help flag + +func cmdExecEvents(cmd *Command, rawArgs []string) { + if eventsHelp { + cmd.PrintUsage() + } + if len(rawArgs) != 0 { + cmd.PrintShortUsage() + } + + args := commands.EventsArgs{} + ctx := cmd.GetContext(rawArgs) + err := commands.RunEvents(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'events': %v", err) + } +} diff --git a/pkg/cli/exec.go b/pkg/cli/exec.go new file mode 100644 index 0000000000..334a10ed3a --- /dev/null +++ b/pkg/cli/exec.go @@ -0,0 +1,64 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package cli + +import ( + "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" +) + +var cmdExec = &Command{ + Exec: cmdExecExec, + UsageLine: "exec [OPTIONS] SERVER [COMMAND] [ARGS...]", + Description: "Run a command on a running server", + Help: "Run a command on a running server.", + Examples: ` + $ scw exec myserver + $ scw exec myserver bash + $ scw exec --gateway=myotherserver myserver bash + $ scw exec myserver 'tmux a -t joe || tmux new -s joe || bash' + $ exec_secure=1 scw exec myserver bash + $ scw exec -w $(scw start $(scw create ubuntu-trusty)) bash + $ scw exec $(scw start -w $(scw create ubuntu-trusty)) bash + $ scw exec myserver tmux new -d sleep 10 + $ scw exec myserver ls -la | grep password + $ cat local-file | scw exec myserver 'cat > remote/path' +`, +} + +func init() { + cmdExec.Flag.BoolVar(&execHelp, []string{"h", "-help"}, false, "Print usage") + cmdExec.Flag.Float64Var(&execTimeout, []string{"T", "-timeout"}, 0, "Set timeout values to seconds") + cmdExec.Flag.BoolVar(&execW, []string{"w", "-wait"}, false, "Wait for SSH to be ready") + cmdExec.Flag.StringVar(&execGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") +} + +// Flags +var execW bool // -w, --wait flag +var execTimeout float64 // -T flag +var execHelp bool // -h, --help flag +var execGateway string // -g, --gateway flag + +func cmdExecExec(cmd *Command, rawArgs []string) { + if execHelp { + cmd.PrintUsage() + } + if len(rawArgs) < 1 { + cmd.PrintShortUsage() + } + + args := commands.ExecArgs{ + Timeout: execTimeout, + Wait: execW, + Gateway: execGateway, + Server: rawArgs[0], + Command: rawArgs[1:], + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunExec(ctx, args) + if err != nil { + logrus.Fatalf("Cannot exec 'exec': %v", err) + } +} diff --git a/pkg/commands/help.go b/pkg/cli/help.go similarity index 88% rename from pkg/commands/help.go rename to pkg/cli/help.go index 7d568c7a9b..fa787f04bf 100644 --- a/pkg/commands/help.go +++ b/pkg/cli/help.go @@ -2,18 +2,17 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( - "log" "os" "text/template" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/Sirupsen/logrus" ) // CmdHelp is the 'scw help' command -var CmdHelp = &types.Command{ +var CmdHelp = &Command{ Exec: nil, UsageLine: "help [COMMAND]", Description: "help of the scw command line", @@ -54,7 +53,7 @@ Commands: Run 'scw COMMAND --help' for more information on a command. ` -func runHelp(cmd *types.Command, args []string) { +func runHelp(cmd *Command, args []string) { if waitHelp { cmd.PrintUsage() } @@ -69,7 +68,7 @@ func runHelp(cmd *types.Command, args []string) { command.PrintUsage() } } - log.Fatalf("Unknown help topic `%s`. Run 'scw help'.", name) + logrus.Fatalf("Unknown help topic `%s`. Run 'scw help'.", name) } else { t := template.New("top") template.Must(t.Parse(helpTemplate)) diff --git a/pkg/commands/history.go b/pkg/cli/history.go similarity index 92% rename from pkg/commands/history.go rename to pkg/cli/history.go index a5511294e4..8fbd8272f4 100644 --- a/pkg/commands/history.go +++ b/pkg/cli/history.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -13,11 +13,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" utils "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdHistory = &types.Command{ +var cmdHistory = &Command{ Exec: runHistory, UsageLine: "history [OPTIONS] IMAGE", Description: "Show the history of an image", @@ -35,7 +34,7 @@ var historyNoTrunc bool // --no-trunc flag var historyQuiet bool // -q, --quiet flag var historyHelp bool // -h, --help flag -func runHistory(cmd *types.Command, args []string) { +func runHistory(cmd *Command, args []string) { if historyHelp { cmd.PrintUsage() } diff --git a/pkg/commands/images.go b/pkg/cli/images.go similarity index 96% rename from pkg/commands/images.go rename to pkg/cli/images.go index ec2f0fc47c..23743861b7 100644 --- a/pkg/commands/images.go +++ b/pkg/cli/images.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -16,11 +16,10 @@ import ( "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdImages = &types.Command{ +var cmdImages = &Command{ Exec: runImages, UsageLine: "images [OPTIONS]", Description: "List images", @@ -40,7 +39,7 @@ var imagesQ bool // -q flag var imagesNoTrunc bool // -no-trunc flag var imagesHelp bool // -h, --help flag -func runImages(cmd *types.Command, args []string) { +func runImages(cmd *Command, args []string) { if imagesHelp { cmd.PrintUsage() } diff --git a/pkg/commands/info.go b/pkg/cli/info.go similarity index 91% rename from pkg/commands/info.go rename to pkg/cli/info.go index a910d7efc0..da2bc11496 100644 --- a/pkg/commands/info.go +++ b/pkg/cli/info.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -11,11 +11,10 @@ import ( "github.com/scaleway/scaleway-cli/vendor/github.com/kardianos/osext" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdInfo = &types.Command{ +var cmdInfo = &Command{ Exec: runInfo, UsageLine: "info [OPTIONS]", Description: "Display system-wide information", @@ -29,7 +28,7 @@ func init() { // Flags var infoHelp bool // -h, --help flag -func runInfo(cmd *types.Command, args []string) { +func runInfo(cmd *Command, args []string) { if infoHelp { cmd.PrintUsage() } diff --git a/pkg/commands/inspect.go b/pkg/cli/inspect.go similarity index 96% rename from pkg/commands/inspect.go rename to pkg/cli/inspect.go index aeb126e1c2..89c890fffb 100644 --- a/pkg/commands/inspect.go +++ b/pkg/cli/inspect.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "encoding/json" @@ -14,10 +14,9 @@ import ( "github.com/scaleway/scaleway-cli/vendor/github.com/skratchdot/open-golang/open" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdInspect = &types.Command{ +var cmdInspect = &Command{ Exec: runInspect, UsageLine: "inspect [OPTIONS] IDENTIFIER [IDENTIFIER...]", Description: "Return low-level information on a server, image, snapshot, volume or bootscript", @@ -52,7 +51,7 @@ var inspectFormat string // -f, --format flag var inspectBrowser bool // -b, --browser flag var inspectHelp bool // -h, --help flag -func runInspect(cmd *types.Command, args []string) { +func runInspect(cmd *Command, args []string) { if inspectHelp { cmd.PrintUsage() } diff --git a/pkg/commands/kill.go b/pkg/cli/kill.go similarity index 91% rename from pkg/commands/kill.go rename to pkg/cli/kill.go index 5cf1340293..1a4addcc12 100644 --- a/pkg/commands/kill.go +++ b/pkg/cli/kill.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "os" @@ -12,11 +12,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdKill = &types.Command{ +var cmdKill = &Command{ Exec: runKill, UsageLine: "kill [OPTIONS] SERVER", Description: "Kill a running server", @@ -33,7 +32,7 @@ func init() { var killHelp bool // -h, --help flag var killGateway string // -g, --gateway flag -func runKill(cmd *types.Command, args []string) { +func runKill(cmd *Command, args []string) { if killHelp { cmd.PrintUsage() } diff --git a/pkg/cli/login.go b/pkg/cli/login.go new file mode 100644 index 0000000000..8cbe1bd6e2 --- /dev/null +++ b/pkg/cli/login.go @@ -0,0 +1,52 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package cli + +import ( + "github.com/scaleway/scaleway-cli/pkg/commands" + log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +var cmdLogin = &Command{ + Exec: cmdExecLogin, + UsageLine: "login [OPTIONS]", + Description: "Log in to Scaleway API", + Help: `Generates a configuration file in '/home/$USER/.scwrc' +containing credentials used to interact with the Scaleway API. This +configuration file is automatically used by the 'scw' commands. + +You can get your credentials on https://cloud.scaleway.com/#/credentials +`, +} + +func init() { + cmdLogin.Flag.StringVar(&organization, []string{"o", "-organization"}, "", "Organization") + cmdLogin.Flag.StringVar(&token, []string{"t", "-token"}, "", "Token") + cmdLogin.Flag.BoolVar(&loginHelp, []string{"h", "-help"}, false, "Print usage") +} + +// FLags +var organization string // -o flag +var token string // -t flag +var loginHelp bool // -h, --help flag + +func cmdExecLogin(cmd *Command, rawArgs []string) { + if loginHelp { + cmd.PrintUsage() + } + if len(rawArgs) != 0 { + cmd.PrintShortUsage() + } + + args := commands.LoginArgs{ + Organization: organization, + Token: token, + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunLogin(ctx, args) + if err != nil { + log.Fatalf("Cannot execute 'login': %v", err) + } +} diff --git a/pkg/commands/logout.go b/pkg/cli/logout.go similarity index 85% rename from pkg/commands/logout.go rename to pkg/cli/logout.go index eef367de34..eb1bfd8283 100644 --- a/pkg/commands/logout.go +++ b/pkg/cli/logout.go @@ -2,18 +2,17 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "os" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdLogout = &types.Command{ +var cmdLogout = &Command{ Exec: runLogout, UsageLine: "logout [OPTIONS]", Description: "Log out from the Scaleway API", @@ -27,7 +26,7 @@ func init() { // FLags var logoutHelp bool // -h, --help flag -func runLogout(cmd *types.Command, args []string) { +func runLogout(cmd *Command, args []string) { if logoutHelp { cmd.PrintUsage() } diff --git a/pkg/commands/logs.go b/pkg/cli/logs.go similarity index 91% rename from pkg/commands/logs.go rename to pkg/cli/logs.go index 47ff441700..96fd758709 100644 --- a/pkg/commands/logs.go +++ b/pkg/cli/logs.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "os" @@ -10,11 +10,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdLogs = &types.Command{ +var cmdLogs = &Command{ Exec: runLogs, UsageLine: "logs [OPTIONS] SERVER", Description: "Fetch the logs of a server", @@ -30,7 +29,7 @@ func init() { var logsHelp bool // -h, --help flag var logsGateway string // -g, --gateway flag -func runLogs(cmd *types.Command, args []string) { +func runLogs(cmd *Command, args []string) { if logsHelp { cmd.PrintUsage() } diff --git a/pkg/commands/port.go b/pkg/cli/port.go similarity index 91% rename from pkg/commands/port.go rename to pkg/cli/port.go index 7f9af3e2ba..085322bafd 100644 --- a/pkg/commands/port.go +++ b/pkg/cli/port.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "os" @@ -10,11 +10,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdPort = &types.Command{ +var cmdPort = &Command{ Exec: runPort, UsageLine: "port [OPTIONS] SERVER [PRIVATE_PORT[/PROTO]]", Description: "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT", @@ -30,7 +29,7 @@ func init() { var portHelp bool // -h, --help flag var portGateway string // -g, --gateway flag -func runPort(cmd *types.Command, args []string) { +func runPort(cmd *Command, args []string) { if portHelp { cmd.PrintUsage() } diff --git a/pkg/cli/ps.go b/pkg/cli/ps.go new file mode 100644 index 0000000000..93cebdf76b --- /dev/null +++ b/pkg/cli/ps.go @@ -0,0 +1,56 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package cli + +import ( + "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" +) + +var cmdPs = &Command{ + Exec: cmdExecPs, + UsageLine: "ps [OPTIONS]", + Description: "List servers", + Help: "List servers. By default, only running servers are displayed.", +} + +func init() { + cmdPs.Flag.BoolVar(&psA, []string{"a", "-all"}, false, "Show all servers. Only running servers are shown by default") + cmdPs.Flag.BoolVar(&psL, []string{"l", "-latest"}, false, "Show only the latest created server, include non-running ones") + cmdPs.Flag.IntVar(&psN, []string{"n"}, 0, "Show n last created servers, include non-running ones") + cmdPs.Flag.BoolVar(&psNoTrunc, []string{"-no-trunc"}, false, "Don't truncate output") + cmdPs.Flag.BoolVar(&psQ, []string{"q", "-quiet"}, false, "Only display numeric IDs") + cmdPs.Flag.BoolVar(&psHelp, []string{"h", "-help"}, false, "Print usage") +} + +// Flags +var psA bool // -a flag +var psL bool // -l flag +var psQ bool // -q flag +var psNoTrunc bool // -no-trunc flag +var psN int // -n flag +var psHelp bool // -h, --help flag + +func cmdExecPs(cmd *Command, rawArgs []string) { + if psHelp { + cmd.PrintUsage() + } + if len(rawArgs) != 0 { + cmd.PrintShortUsage() + } + + args := commands.PsArgs{ + All: psA, + Latest: psL, + Quiet: psQ, + NoTrunc: psNoTrunc, + NLast: psN, + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunPs(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'ps': %v", err) + } +} diff --git a/pkg/commands/rename.go b/pkg/cli/rename.go similarity index 85% rename from pkg/commands/rename.go rename to pkg/cli/rename.go index 86797d080a..dd7ca298b1 100644 --- a/pkg/commands/rename.go +++ b/pkg/cli/rename.go @@ -2,16 +2,15 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdRename = &types.Command{ +var cmdRename = &Command{ Exec: runRename, UsageLine: "rename [OPTIONS] SERVER NEW_NAME", Description: "Rename a server", @@ -25,7 +24,7 @@ func init() { // Flags var renameHelp bool // -h, --help flag -func runRename(cmd *types.Command, args []string) { +func runRename(cmd *Command, args []string) { if renameHelp { cmd.PrintUsage() } diff --git a/pkg/commands/restart.go b/pkg/cli/restart.go similarity index 86% rename from pkg/commands/restart.go rename to pkg/cli/restart.go index ffa1729d5b..ce168eba8d 100644 --- a/pkg/commands/restart.go +++ b/pkg/cli/restart.go @@ -2,18 +2,16 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" "os" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdRestart = &types.Command{ +var cmdRestart = &Command{ Exec: runRestart, UsageLine: "restart [OPTIONS] SERVER [SERVER...]", Description: "Restart a running server", @@ -27,7 +25,7 @@ func init() { // Flags var restartHelp bool // -h, --help flag -func runRestart(cmd *types.Command, args []string) { +func runRestart(cmd *Command, args []string) { if restartHelp { cmd.PrintUsage() } diff --git a/pkg/commands/rm.go b/pkg/cli/rm.go similarity index 87% rename from pkg/commands/rm.go rename to pkg/cli/rm.go index 595da8f1ad..54ca53b924 100644 --- a/pkg/commands/rm.go +++ b/pkg/cli/rm.go @@ -2,18 +2,16 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" "os" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdRm = &types.Command{ +var cmdRm = &Command{ Exec: runRm, UsageLine: "rm [OPTIONS] SERVER [SERVER...]", Description: "Remove one or more servers", @@ -32,7 +30,7 @@ func init() { // Flags var rmHelp bool // -h, --help flag -func runRm(cmd *types.Command, args []string) { +func runRm(cmd *Command, args []string) { if rmHelp { cmd.PrintUsage() } diff --git a/pkg/commands/rmi.go b/pkg/cli/rmi.go similarity index 87% rename from pkg/commands/rmi.go rename to pkg/cli/rmi.go index dd1eb4968c..6471539da7 100644 --- a/pkg/commands/rmi.go +++ b/pkg/cli/rmi.go @@ -2,18 +2,16 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" "os" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdRmi = &types.Command{ +var cmdRmi = &Command{ Exec: runRmi, UsageLine: "rmi [OPTIONS] IMAGE [IMAGE...]", Description: "Remove one or more images", @@ -31,7 +29,7 @@ func init() { // Flags var rmiHelp bool // -h, --help flag -func runRmi(cmd *types.Command, args []string) { +func runRmi(cmd *Command, args []string) { if rmiHelp { cmd.PrintUsage() } diff --git a/pkg/commands/run.go b/pkg/cli/run.go similarity index 96% rename from pkg/commands/run.go rename to pkg/cli/run.go index 23190dacac..e5ba118798 100644 --- a/pkg/commands/run.go +++ b/pkg/cli/run.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -11,11 +11,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" api "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdRun = &types.Command{ +var cmdRun = &Command{ Exec: runRun, UsageLine: "run [OPTIONS] IMAGE [COMMAND] [ARG...]", Description: "Run a command in a new server", @@ -53,7 +52,7 @@ var runAttachFlag bool // -a, --attach flag var runDetachFlag bool // -d, --detach flag var runGateway string // -g, --gateway flag -func runRun(cmd *types.Command, args []string) { +func runRun(cmd *Command, args []string) { if runHelpFlag { cmd.PrintUsage() } diff --git a/pkg/commands/search.go b/pkg/cli/search.go similarity index 93% rename from pkg/commands/search.go rename to pkg/cli/search.go index 3c0e871c0f..97eb621716 100644 --- a/pkg/commands/search.go +++ b/pkg/cli/search.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -12,11 +12,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdSearch = &types.Command{ +var cmdSearch = &Command{ Exec: runSearch, UsageLine: "search [OPTIONS] TERM", Description: "Search the Scaleway Hub for images", @@ -32,7 +31,7 @@ func init() { var searchNoTrunc bool // --no-trunc flag var searchHelp bool // -h, --help flag -func runSearch(cmd *types.Command, args []string) { +func runSearch(cmd *Command, args []string) { if searchHelp { cmd.PrintUsage() } diff --git a/pkg/commands/start.go b/pkg/cli/start.go similarity index 91% rename from pkg/commands/start.go rename to pkg/cli/start.go index 44d81a4079..b07c37e1c2 100644 --- a/pkg/commands/start.go +++ b/pkg/cli/start.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -12,10 +12,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdStart = &types.Command{ +var cmdStart = &Command{ Exec: runStart, UsageLine: "start [OPTIONS] SERVER [SERVER...]", Description: "Start a stopped server", @@ -33,7 +32,7 @@ var startW bool // -w flag var startTimeout float64 // -T flag var startHelp bool // -h, --help flag -func runStart(cmd *types.Command, args []string) { +func runStart(cmd *Command, args []string) { if startHelp { cmd.PrintUsage() } diff --git a/pkg/commands/stop.go b/pkg/cli/stop.go similarity index 93% rename from pkg/commands/stop.go rename to pkg/cli/stop.go index 8a1f31bf4d..a75cfa97f6 100644 --- a/pkg/commands/stop.go +++ b/pkg/cli/stop.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -12,10 +12,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdStop = &types.Command{ +var cmdStop = &Command{ Exec: runStop, UsageLine: "stop [OPTIONS] SERVER [SERVER...]", Description: "Stop a running server", @@ -42,7 +41,7 @@ var stopHelp bool // -h, --help flag var stopW bool // -w, --wait flat // FIXME: parallelize stop when stopping multiple servers -func runStop(cmd *types.Command, args []string) { +func runStop(cmd *Command, args []string) { if stopHelp { cmd.PrintUsage() } diff --git a/pkg/commands/tag.go b/pkg/cli/tag.go similarity index 85% rename from pkg/commands/tag.go rename to pkg/cli/tag.go index ad96bd75cd..8b730d9e4b 100644 --- a/pkg/commands/tag.go +++ b/pkg/cli/tag.go @@ -2,17 +2,15 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdTag = &types.Command{ +var cmdTag = &Command{ Exec: runTag, UsageLine: "tag [OPTIONS] SNAPSHOT NAME", Description: "Tag a snapshot into an image", @@ -26,7 +24,7 @@ func init() { // Flags var tagHelp bool // -h, --help flag -func runTag(cmd *types.Command, args []string) { +func runTag(cmd *Command, args []string) { if tagHelp { cmd.PrintUsage() } diff --git a/pkg/commands/top.go b/pkg/cli/top.go similarity index 91% rename from pkg/commands/top.go rename to pkg/cli/top.go index ae27d63f7b..bc3c8832db 100644 --- a/pkg/commands/top.go +++ b/pkg/cli/top.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -13,11 +13,10 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdTop = &types.Command{ +var cmdTop = &Command{ Exec: runTop, UsageLine: "top [OPTIONS] SERVER", // FIXME: add ps options Description: "Lookup the running processes of a server", @@ -33,7 +32,7 @@ func init() { var topHelp bool // -h, --help flag var topGateway string // -g, --gateway flag -func runTop(cmd *types.Command, args []string) { +func runTop(cmd *Command, args []string) { if topHelp { cmd.PrintUsage() } diff --git a/pkg/commands/version.go b/pkg/cli/version.go similarity index 84% rename from pkg/commands/version.go rename to pkg/cli/version.go index 1b7d6488d7..fbcbcef09b 100644 --- a/pkg/commands/version.go +++ b/pkg/cli/version.go @@ -2,17 +2,16 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" "runtime" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/scwversion" ) -var cmdVersion = &types.Command{ +var cmdVersion = &Command{ Exec: runVersion, UsageLine: "version [OPTIONS]", Description: "Show the version information", @@ -26,7 +25,7 @@ func init() { // Flags var versionHelp bool // -h, --help flag -func runVersion(cmd *types.Command, args []string) { +func runVersion(cmd *Command, args []string) { if versionHelp { cmd.PrintUsage() } diff --git a/pkg/commands/wait.go b/pkg/cli/wait.go similarity index 86% rename from pkg/commands/wait.go rename to pkg/cli/wait.go index a41335d5c8..54b3a9724b 100644 --- a/pkg/commands/wait.go +++ b/pkg/cli/wait.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "os" @@ -10,10 +10,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdWait = &types.Command{ +var cmdWait = &Command{ Exec: runWait, UsageLine: "wait [OPTIONS] SERVER [SERVER...]", Description: "Block until a server stops", @@ -27,7 +26,7 @@ func init() { // Flags var waitHelp bool // -h, --help flag -func runWait(cmd *types.Command, args []string) { +func runWait(cmd *Command, args []string) { if waitHelp { cmd.PrintUsage() } diff --git a/pkg/commands/x_completion.go b/pkg/cli/x_completion.go similarity index 92% rename from pkg/commands/x_completion.go rename to pkg/cli/x_completion.go index d376eb4274..13351a9e25 100644 --- a/pkg/commands/x_completion.go +++ b/pkg/cli/x_completion.go @@ -2,19 +2,18 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" - "log" "sort" "strings" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/Sirupsen/logrus" utils "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdCompletion = &types.Command{ +var cmdCompletion = &Command{ Exec: runCompletion, UsageLine: "_completion [OPTIONS] CATEGORY", Description: "Completion helper", @@ -52,7 +51,7 @@ func wordifyName(name string, kind string) string { return ret } -func runCompletion(cmd *types.Command, args []string) { +func runCompletion(cmd *Command, args []string) { if completionHelp { cmd.PrintUsage() } @@ -106,7 +105,7 @@ func runCompletion(cmd *types.Command, args []string) { elements = append(elements, wordifyName(name, "bootscript")) } default: - log.Fatalf("Unhandled category of completion: %s", category) + logrus.Fatalf("Unhandled category of completion: %s", category) } sort.Strings(elements) diff --git a/pkg/commands/x_flushcache.go b/pkg/cli/x_flushcache.go similarity index 75% rename from pkg/commands/x_flushcache.go rename to pkg/cli/x_flushcache.go index 5eae6a9a26..ed12bacf8b 100644 --- a/pkg/commands/x_flushcache.go +++ b/pkg/cli/x_flushcache.go @@ -2,16 +2,15 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" - "log" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" + "github.com/Sirupsen/logrus" ) -var cmdFlushCache = &types.Command{ +var cmdFlushCache = &Command{ Exec: runFlushCache, UsageLine: "_flush-cache [OPTIONS]", Description: "", @@ -26,7 +25,7 @@ func init() { // Flags var flushCacheHelp bool // -h, --help flag -func runFlushCache(cmd *types.Command, args []string) { +func runFlushCache(cmd *Command, args []string) { if flushCacheHelp { cmd.PrintUsage() } @@ -36,7 +35,7 @@ func runFlushCache(cmd *types.Command, args []string) { err := cmd.API.Cache.Flush() if err != nil { - log.Fatal("Failed to flush the cache") + logrus.Fatal("Failed to flush the cache") } fmt.Println("Cache flushed") diff --git a/pkg/commands/x_patch.go b/pkg/cli/x_patch.go similarity index 94% rename from pkg/commands/x_patch.go rename to pkg/cli/x_patch.go index 6fc7bad94f..670c315438 100644 --- a/pkg/commands/x_patch.go +++ b/pkg/cli/x_patch.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE.md file. -package commands +package cli import ( "fmt" @@ -11,10 +11,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" api "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdPatch = &types.Command{ +var cmdPatch = &Command{ Exec: runPatch, UsageLine: "_patch [OPTIONS] IDENTIFIER FIELD=VALUE", Description: "", @@ -33,7 +32,7 @@ func init() { // Flags var patchHelp bool // -h, --help flag -func runPatch(cmd *types.Command, args []string) { +func runPatch(cmd *Command, args []string) { if patchHelp { cmd.PrintUsage() } diff --git a/pkg/commands/attach.go b/pkg/commands/attach.go index ff25879fb1..b3804bebea 100644 --- a/pkg/commands/attach.go +++ b/pkg/commands/attach.go @@ -4,33 +4,7 @@ package commands -import ( - "log" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" - "github.com/scaleway/scaleway-cli/pkg/utils" -) - -var cmdAttach = &types.Command{ - Exec: cmdExecAttach, - UsageLine: "attach [OPTIONS] SERVER", - Description: "Attach to a server serial console", - Help: "Attach to a running server serial console.", - Examples: ` - $ scw attach my-running-server - $ scw attach $(scw start my-stopped-server) - $ scw attach $(scw start $(scw create ubuntu-vivid)) -`, -} - -func init() { - cmdAttach.Flag.BoolVar(&attachHelp, []string{"h", "-help"}, false, "Print usage") - cmdAttach.Flag.BoolVar(&attachNoStdin, []string{"-no-stdin"}, false, "Do not attach stdin") -} - -// Flags -var attachHelp bool // -h, --help flag -var attachNoStdin bool // --no-stdin flag +import "github.com/scaleway/scaleway-cli/pkg/utils" // AttachArgs are flags for the `RunAttach` function type AttachArgs struct { @@ -38,27 +12,8 @@ type AttachArgs struct { Server string } -func cmdExecAttach(cmd *types.Command, rawArgs []string) { - if attachHelp { - cmd.PrintUsage() - } - if len(rawArgs) != 1 { - cmd.PrintShortUsage() - } - - args := AttachArgs{ - NoStdin: attachNoStdin, - Server: rawArgs[0], - } - ctx := cmd.GetContext(rawArgs) - err := RunAttach(ctx, args) - if err != nil { - log.Fatalf("Cannot execute 'attach': %v", err) - } -} - // RunAttach is the handler for 'scw attach' -func RunAttach(ctx types.CommandContext, args AttachArgs) error { +func RunAttach(ctx CommandContext, args AttachArgs) error { serverID := ctx.API.GetServerID(args.Server) return utils.AttachToSerial(serverID, ctx.API.Token, !args.NoStdin) diff --git a/pkg/commands/command.go b/pkg/commands/command.go new file mode 100644 index 0000000000..18b92d2b7c --- /dev/null +++ b/pkg/commands/command.go @@ -0,0 +1,29 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +// Golang structs for scw commands +package commands + +import ( + "io" + "os" + + "github.com/scaleway/scaleway-cli/pkg/api" +) + +// CommandContext is passed to all commands and contains streams, environment, api and arguments +type CommandContext struct { + Stdin io.Reader + Stdout io.Writer + Stderr io.Writer + Env []string + RawArgs []string + API *api.ScalewayAPI +} + +// Getenv returns the equivalent of os.Getenv for the CommandContext.Env +func (c *CommandContext) Getenv(key string) string { + // FIXME: parse c.Env instead + return os.Getenv(key) +} diff --git a/pkg/commands/commit.go b/pkg/commands/commit.go index 57c9e096b2..6db8ff1720 100644 --- a/pkg/commands/commit.go +++ b/pkg/commands/commit.go @@ -6,32 +6,8 @@ package commands import ( "fmt" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdCommit = &types.Command{ - Exec: cmdExecCommit, - UsageLine: "commit [OPTIONS] SERVER [NAME]", - Description: "Create a new snapshot from a server's volume", - Help: "Create a new snapshot from a server's volume.", - Examples: ` - $ scw commit my-stopped-server - $ scw commit -v 1 my-stopped-server -`, -} - -func init() { - cmdCommit.Flag.IntVar(&commitVolume, []string{"v", "-volume"}, 0, "Volume slot") - cmdCommit.Flag.BoolVar(&commitHelp, []string{"h", "-help"}, false, "Print usage") -} - -// Flags -var commitVolume int // -v, --volume flag -var commitHelp bool // -h, --help flag - // CommitArgs are flags for the `RunCommit` function type CommitArgs struct { Volume int @@ -39,38 +15,14 @@ type CommitArgs struct { Name string } -func cmdExecCommit(cmd *types.Command, rawArgs []string) { - if commitHelp { - cmd.PrintUsage() - } - if len(rawArgs) < 1 { - cmd.PrintShortUsage() - } - - args := CommitArgs{ - Volume: commitVolume, - Server: rawArgs[0], - Name: "", - } - if len(rawArgs) > 1 { - args.Name = rawArgs[1] - } - - ctx := cmd.GetContext(rawArgs) - err := RunCommit(ctx, args) - if err != nil { - log.Fatalf("Cannot execute 'commit': %v", err) - } -} - // RunCommit is the handler for 'scw commit' -func RunCommit(ctx types.CommandContext, args CommitArgs) error { +func RunCommit(ctx CommandContext, args CommitArgs) error { serverID := ctx.API.GetServerID(args.Server) server, err := ctx.API.GetServer(serverID) if err != nil { return fmt.Errorf("Cannot fetch server: %v", err) } - var volume = server.Volumes[fmt.Sprintf("%d", commitVolume)] + var volume = server.Volumes[fmt.Sprintf("%d", args.Volume)] var name string if args.Name != "" { name = args.Name diff --git a/pkg/commands/events.go b/pkg/commands/events.go index f7ec2169f9..63f9998f62 100644 --- a/pkg/commands/events.go +++ b/pkg/commands/events.go @@ -8,46 +8,13 @@ import ( "fmt" "time" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - - types "github.com/scaleway/scaleway-cli/pkg/commands/types" ) -var cmdEvents = &types.Command{ - Exec: cmdExecEvents, - UsageLine: "events [OPTIONS]", - Description: "Get real time events from the API", - Help: "Get real time events from the API.", -} - -func init() { - cmdEvents.Flag.BoolVar(&eventsHelp, []string{"h", "-help"}, false, "Print usage") -} - -// Flags -var eventsHelp bool // -h, --help flag - type EventsArgs struct{} -func cmdExecEvents(cmd *types.Command, rawArgs []string) { - if eventsHelp { - cmd.PrintUsage() - } - if len(rawArgs) != 0 { - cmd.PrintShortUsage() - } - - args := EventsArgs{} - ctx := cmd.GetContext(rawArgs) - err := RunEvents(ctx, args) - if err != nil { - log.Fatalf("Cannot execute 'events': %v", err) - } -} - // RunEvents is the handler for 'scw events' -func RunEvents(ctx types.CommandContext, args EventsArgs) error { +func RunEvents(ctx CommandContext, args EventsArgs) error { events, err := ctx.API.GetTasks() if err != nil { return fmt.Errorf("unable to fetch tasks from the Scaleway API: %v", err) diff --git a/pkg/commands/exec.go b/pkg/commands/exec.go index ce981fbecc..e4753a88cd 100644 --- a/pkg/commands/exec.go +++ b/pkg/commands/exec.go @@ -11,42 +11,9 @@ import ( log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdExec = &types.Command{ - Exec: cmdExecExec, - UsageLine: "exec [OPTIONS] SERVER [COMMAND] [ARGS...]", - Description: "Run a command on a running server", - Help: "Run a command on a running server.", - Examples: ` - $ scw exec myserver - $ scw exec myserver bash - $ scw exec --gateway=myotherserver myserver bash - $ scw exec myserver 'tmux a -t joe || tmux new -s joe || bash' - $ exec_secure=1 scw exec myserver bash - $ scw exec -w $(scw start $(scw create ubuntu-trusty)) bash - $ scw exec $(scw start -w $(scw create ubuntu-trusty)) bash - $ scw exec myserver tmux new -d sleep 10 - $ scw exec myserver ls -la | grep password - $ cat local-file | scw exec myserver 'cat > remote/path' -`, -} - -func init() { - cmdExec.Flag.BoolVar(&execHelp, []string{"h", "-help"}, false, "Print usage") - cmdExec.Flag.Float64Var(&execTimeout, []string{"T", "-timeout"}, 0, "Set timeout values to seconds") - cmdExec.Flag.BoolVar(&execW, []string{"w", "-wait"}, false, "Wait for SSH to be ready") - cmdExec.Flag.StringVar(&execGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway") -} - -// Flags -var execW bool // -w, --wait flag -var execTimeout float64 // -T flag -var execHelp bool // -h, --help flag -var execGateway string // -g, --gateway flag - // ExecArgs are flags for the `RunExec` function type ExecArgs struct { Timeout float64 @@ -56,30 +23,8 @@ type ExecArgs struct { Command []string } -func cmdExecExec(cmd *types.Command, rawArgs []string) { - if execHelp { - cmd.PrintUsage() - } - if len(rawArgs) < 1 { - cmd.PrintShortUsage() - } - - args := ExecArgs{ - Timeout: execTimeout, - Wait: execW, - Gateway: execGateway, - Server: rawArgs[0], - Command: rawArgs[1:], - } - ctx := cmd.GetContext(rawArgs) - err := RunExec(ctx, args) - if err != nil { - log.Fatalf("Cannot exec 'exec': %v", err) - } -} - // RunExec is the handler for 'scw exec' -func RunExec(ctx types.CommandContext, args ExecArgs) error { +func RunExec(ctx CommandContext, args ExecArgs) error { serverID := ctx.API.GetServerID(args.Server) // Resolve gateway diff --git a/pkg/commands/login.go b/pkg/commands/login.go index 06f7684961..900206c93e 100644 --- a/pkg/commands/login.go +++ b/pkg/commands/login.go @@ -8,85 +8,24 @@ import ( "bufio" "encoding/json" "fmt" + "log" "os" "strings" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/vendor/golang.org/x/crypto/ssh/terminal" + "golang.org/x/crypto/ssh/terminal" "github.com/scaleway/scaleway-cli/pkg/api" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdLogin = &types.Command{ - Exec: cmdExecLogin, - UsageLine: "login [OPTIONS]", - Description: "Log in to Scaleway API", - Help: `Generates a configuration file in '/home/$USER/.scwrc' -containing credentials used to interact with the Scaleway API. This -configuration file is automatically used by the 'scw' commands. - -You can get your credentials on https://cloud.scaleway.com/#/credentials -`, -} - -func promptUser(prompt string, output *string, echo bool) { - // FIXME: should use stdin/stdout from command context - fmt.Fprintf(os.Stdout, prompt) - os.Stdout.Sync() - - if !echo { - b, err := terminal.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - log.Fatalf("Unable to prompt for password: %s", err) - } - *output = string(b) - fmt.Fprintf(os.Stdout, "\n") - } else { - reader := bufio.NewReader(os.Stdin) - *output, _ = reader.ReadString('\n') - } -} - -func init() { - cmdLogin.Flag.StringVar(&organization, []string{"o", "-organization"}, "", "Organization") - cmdLogin.Flag.StringVar(&token, []string{"t", "-token"}, "", "Token") - cmdLogin.Flag.BoolVar(&loginHelp, []string{"h", "-help"}, false, "Print usage") -} - -// FLags -var organization string // -o flag -var token string // -t flag -var loginHelp bool // -h, --help flag - type LoginArgs struct { Organization string Token string } -func cmdExecLogin(cmd *types.Command, rawArgs []string) { - if loginHelp { - cmd.PrintUsage() - } - if len(rawArgs) != 0 { - cmd.PrintShortUsage() - } - - args := LoginArgs{ - Organization: organization, - Token: token, - } - ctx := cmd.GetContext(rawArgs) - err := RunLogin(ctx, args) - if err != nil { - log.Fatalf("Cannot execute 'login': %v", err) - } -} - // RunLogin is the handler for 'scw login' -func RunLogin(ctx types.CommandContext, args LoginArgs) error { - if len(organization) == 0 { +func RunLogin(ctx CommandContext, args LoginArgs) error { + if args.Organization == "" { fmt.Println("You can get your credentials on https://cloud.scaleway.com/#/credentials") promptUser("Organization (access key): ", &args.Organization, true) } @@ -126,3 +65,21 @@ func RunLogin(ctx types.CommandContext, args LoginArgs) error { } return nil } + +func promptUser(prompt string, output *string, echo bool) { + // FIXME: should use stdin/stdout from command context + fmt.Fprintf(os.Stdout, prompt) + os.Stdout.Sync() + + if !echo { + b, err := terminal.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + log.Fatalf("Unable to prompt for password: %s", err) + } + *output = string(b) + fmt.Fprintf(os.Stdout, "\n") + } else { + reader := bufio.NewReader(os.Stdin) + *output, _ = reader.ReadString('\n') + } +} diff --git a/pkg/commands/ps.go b/pkg/commands/ps.go index e3be773eaa..e316d30387 100644 --- a/pkg/commands/ps.go +++ b/pkg/commands/ps.go @@ -9,37 +9,11 @@ import ( "text/tabwriter" "time" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - types "github.com/scaleway/scaleway-cli/pkg/commands/types" "github.com/scaleway/scaleway-cli/pkg/utils" ) -var cmdPs = &types.Command{ - Exec: cmdExecPs, - UsageLine: "ps [OPTIONS]", - Description: "List servers", - Help: "List servers. By default, only running servers are displayed.", -} - -func init() { - cmdPs.Flag.BoolVar(&psA, []string{"a", "-all"}, false, "Show all servers. Only running servers are shown by default") - cmdPs.Flag.BoolVar(&psL, []string{"l", "-latest"}, false, "Show only the latest created server, include non-running ones") - cmdPs.Flag.IntVar(&psN, []string{"n"}, 0, "Show n last created servers, include non-running ones") - cmdPs.Flag.BoolVar(&psNoTrunc, []string{"-no-trunc"}, false, "Don't truncate output") - cmdPs.Flag.BoolVar(&psQ, []string{"q", "-quiet"}, false, "Only display numeric IDs") - cmdPs.Flag.BoolVar(&psHelp, []string{"h", "-help"}, false, "Print usage") -} - -// Flags -var psA bool // -a flag -var psL bool // -l flag -var psQ bool // -q flag -var psNoTrunc bool // -no-trunc flag -var psN int // -n flag -var psHelp bool // -h, --help flag - // PsArgs are flags for the `RunPs` function type PsArgs struct { All bool @@ -49,30 +23,8 @@ type PsArgs struct { Quiet bool } -func cmdExecPs(cmd *types.Command, rawArgs []string) { - if psHelp { - cmd.PrintUsage() - } - if len(rawArgs) != 0 { - cmd.PrintShortUsage() - } - - args := PsArgs{ - All: psA, - Latest: psL, - Quiet: psQ, - NoTrunc: psNoTrunc, - NLast: psN, - } - ctx := cmd.GetContext(rawArgs) - err := RunPs(ctx, args) - if err != nil { - log.Fatalf("Cannot exec 'ps': %v", err) - } -} - // RunPs is the handler for 'scw ps' -func RunPs(ctx types.CommandContext, args PsArgs) error { +func RunPs(ctx CommandContext, args PsArgs) error { limit := args.NLast if args.Latest { limit = 1 From add74e684f5aed284dc6d304c810cc7c5ab00fe2 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:24:47 +0200 Subject: [PATCH 09/36] Refactored 'cp' command (#80) --- pkg/cli/cp.go | 213 +++---------------------------------------- pkg/commands/cp.go | 222 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+), 202 deletions(-) create mode 100644 pkg/commands/cp.go diff --git a/pkg/cli/cp.go b/pkg/cli/cp.go index fd8fdc170d..f51db23c12 100644 --- a/pkg/cli/cp.go +++ b/pkg/cli/cp.go @@ -5,18 +5,8 @@ package cli import ( - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "strings" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/archive" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdCp = &Command{ @@ -50,204 +40,23 @@ func init() { var cpHelp bool // -h, --help flag var cpGateway string // -g, --gateway flag -// TarFromSource creates a stream buffer with the tarballed content of the user source -func TarFromSource(apiClient *api.ScalewayAPI, source string) (*io.ReadCloser, error) { - var tarOutputStream io.ReadCloser - - // source is a server address + path (scp-like uri) - if strings.Index(source, ":") > -1 { - log.Debugf("Creating a tarball remotely and streaming it using SSH") - serverParts := strings.Split(source, ":") - if len(serverParts) != 2 { - return nil, fmt.Errorf("invalid source uri, see 'scw cp -h' for usage") - } - - serverID := apiClient.GetServerID(serverParts[0]) - - server, err := apiClient.GetServer(serverID) - if err != nil { - return nil, err - } - - dir, base := utils.PathToTARPathparts(serverParts[1]) - log.Debugf("Equivalent to 'scp root@%s:%s/%s ...'", server.PublicAddress.IP, dir, base) - - // remoteCommand is executed on the remote server - // it streams a tarball raw content - remoteCommand := []string{"tar"} - remoteCommand = append(remoteCommand, "-C", dir) - if os.Getenv("DEBUG") == "1" { - remoteCommand = append(remoteCommand, "-v") - } - remoteCommand = append(remoteCommand, "-cf", "-") - remoteCommand = append(remoteCommand, base) - - // Resolve gateway - if cpGateway == "" { - cpGateway = os.Getenv("SCW_GATEWAY") - } - var gateway string - if cpGateway == serverID || cpGateway == serverParts[0] { - gateway = "" - } else { - gateway, err = api.ResolveGateway(apiClient, cpGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", cpGateway, err) - } - } - - // execCmd contains the ssh connection + the remoteCommand - execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, nil, remoteCommand, gateway)) - log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) - spawnSrc := exec.Command("ssh", execCmd...) - - tarOutputStream, err = spawnSrc.StdoutPipe() - if err != nil { - return nil, err - } - - tarErrorStream, err := spawnSrc.StderrPipe() - if err != nil { - return nil, err - } - defer tarErrorStream.Close() - io.Copy(os.Stderr, tarErrorStream) - - err = spawnSrc.Start() - if err != nil { - return nil, err - } - defer spawnSrc.Wait() - - return &tarOutputStream, nil - } - - // source is stdin - if source == "-" { - log.Debugf("Streaming tarball from stdin") - tarOutputStream = os.Stdin - return &tarOutputStream, nil - } - - // source is a path on localhost - log.Debugf("Taring local path %s", source) - path, err := filepath.Abs(source) - if err != nil { - return nil, err - } - path, err = filepath.EvalSymlinks(path) - if err != nil { - return nil, err - } - log.Debugf("Real local path is %s", path) - - dir, base := utils.PathToTARPathparts(path) - - tarOutputStream, err = archive.TarWithOptions(dir, &archive.TarOptions{ - Compression: archive.Uncompressed, - IncludeFiles: []string{base}, - }) - if err != nil { - return nil, err - } - return &tarOutputStream, nil -} - -// UntarToDest writes to user destination the streamed tarball in input -func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destination string) error { - // destination is a server address + path (scp-like uri) - if strings.Index(destination, ":") > -1 { - log.Debugf("Streaming using ssh and untaring remotely") - serverParts := strings.Split(destination, ":") - if len(serverParts) != 2 { - return fmt.Errorf("invalid destination uri, see 'scw cp -h' for usage") - } - - serverID := apiClient.GetServerID(serverParts[0]) - - server, err := apiClient.GetServer(serverID) - if err != nil { - return err - } - - // remoteCommand is executed on the remote server - // it streams a tarball raw content - remoteCommand := []string{"tar"} - remoteCommand = append(remoteCommand, "-C", serverParts[1]) - if os.Getenv("DEBUG") == "1" { - remoteCommand = append(remoteCommand, "-v") - } - remoteCommand = append(remoteCommand, "-xf", "-") - - // Resolve gateway - if cpGateway == "" { - cpGateway = os.Getenv("SCW_GATEWAY") - } - var gateway string - if cpGateway == serverID || cpGateway == serverParts[0] { - gateway = "" - } else { - gateway, err = api.ResolveGateway(apiClient, cpGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", cpGateway, err) - } - } - - // execCmd contains the ssh connection + the remoteCommand - execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, nil, remoteCommand, gateway)) - log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) - spawnDst := exec.Command("ssh", execCmd...) - - untarInputStream, err := spawnDst.StdinPipe() - if err != nil { - return err - } - defer untarInputStream.Close() - - // spawnDst.Stderr = os.Stderr - // spawnDst.Stdout = os.Stdout - - err = spawnDst.Start() - if err != nil { - return err - } - - _, err = io.Copy(untarInputStream, *sourceStream) - return err - } - - // destination is stdout - if destination == "-" { // stdout - log.Debugf("Writing sourceStream(%v) to os.Stdout(%v)", sourceStream, os.Stdout) - _, err := io.Copy(os.Stdout, *sourceStream) - return err - } - - // destination is a path on localhost - log.Debugf("Untaring to local path: %s", destination) - err := archive.Untar(*sourceStream, destination, &archive.TarOptions{NoLchown: true}) - return err -} - -func runCp(cmd *Command, args []string) { +func runCp(cmd *Command, rawArgs []string) { if cpHelp { cmd.PrintUsage() } - if len(args) != 2 { + if len(rawArgs) != 2 { cmd.PrintShortUsage() } - if strings.Count(args[0], ":") > 1 || strings.Count(args[1], ":") > 1 { - log.Fatalf("usage: scw %s", cmd.UsageLine) + args := commands.CpArgs{ + Gateway: cpGateway, + Source: rawArgs[0], + Destination: rawArgs[1], } - - sourceStream, err := TarFromSource(cmd.API, args[0]) + ctx := cmd.GetContext(rawArgs) + err := commands.RunCp(ctx, args) if err != nil { - log.Fatalf("Cannot tar from source '%s': %v", args[0], err) + logrus.Fatalf("Cannot execute 'cp': %v", err) } - err = UntarToDest(cmd.API, sourceStream, args[1]) - if err != nil { - log.Fatalf("Cannot untar to destination '%s': %v", args[1], err) - } } diff --git a/pkg/commands/cp.go b/pkg/commands/cp.go new file mode 100644 index 0000000000..5b0f9b6e14 --- /dev/null +++ b/pkg/commands/cp.go @@ -0,0 +1,222 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/archive" +) + +type CpArgs struct { + Gateway string + Source string + Destination string +} + +// RunCp is the handler for 'scw cp' +func RunCp(ctx CommandContext, args CpArgs) error { + if strings.Count(args.Source, ":") > 1 || strings.Count(args.Destination, ":") > 1 { + return fmt.Errorf("bad usage, see 'scw help cp'.") + } + + sourceStream, err := TarFromSource(ctx.API, args.Source, args.Gateway) + if err != nil { + return fmt.Errorf("cannot tar from source '%s': %v", args.Source, err) + } + + err = UntarToDest(ctx.API, sourceStream, args.Destination, args.Gateway) + if err != nil { + return fmt.Errorf("cannot untar to destination '%s': %v", args.Destination, err) + } + return nil +} + +// TarFromSource creates a stream buffer with the tarballed content of the user source +func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (*io.ReadCloser, error) { + var tarOutputStream io.ReadCloser + + // source is a server address + path (scp-like uri) + if strings.Index(source, ":") > -1 { + logrus.Debugf("Creating a tarball remotely and streaming it using SSH") + serverParts := strings.Split(source, ":") + if len(serverParts) != 2 { + return nil, fmt.Errorf("invalid source uri, see 'scw cp -h' for usage") + } + + serverID := apiClient.GetServerID(serverParts[0]) + + server, err := apiClient.GetServer(serverID) + if err != nil { + return nil, err + } + + dir, base := utils.PathToTARPathparts(serverParts[1]) + logrus.Debugf("Equivalent to 'scp root@%s:%s/%s ...'", server.PublicAddress.IP, dir, base) + + // remoteCommand is executed on the remote server + // it streams a tarball raw content + remoteCommand := []string{"tar"} + remoteCommand = append(remoteCommand, "-C", dir) + if os.Getenv("DEBUG") == "1" { + remoteCommand = append(remoteCommand, "-v") + } + remoteCommand = append(remoteCommand, "-cf", "-") + remoteCommand = append(remoteCommand, base) + + // Resolve gateway + if gateway == "" { + gateway = os.Getenv("SCW_GATEWAY") + } + var gateway string + if gateway == serverID || gateway == serverParts[0] { + gateway = "" + } else { + gateway, err = api.ResolveGateway(apiClient, gateway) + if err != nil { + return nil, fmt.Errorf("cannot resolve Gateway '%s': %v", gateway, err) + } + } + + // execCmd contains the ssh connection + the remoteCommand + execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, nil, remoteCommand, gateway)) + logrus.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) + spawnSrc := exec.Command("ssh", execCmd...) + + tarOutputStream, err = spawnSrc.StdoutPipe() + if err != nil { + return nil, err + } + + tarErrorStream, err := spawnSrc.StderrPipe() + if err != nil { + return nil, err + } + defer tarErrorStream.Close() + io.Copy(os.Stderr, tarErrorStream) + + err = spawnSrc.Start() + if err != nil { + return nil, err + } + defer spawnSrc.Wait() + + return &tarOutputStream, nil + } + + // source is stdin + if source == "-" { + logrus.Debugf("Streaming tarball from stdin") + tarOutputStream = os.Stdin + return &tarOutputStream, nil + } + + // source is a path on localhost + logrus.Debugf("Taring local path %s", source) + path, err := filepath.Abs(source) + if err != nil { + return nil, err + } + path, err = filepath.EvalSymlinks(path) + if err != nil { + return nil, err + } + logrus.Debugf("Real local path is %s", path) + + dir, base := utils.PathToTARPathparts(path) + + tarOutputStream, err = archive.TarWithOptions(dir, &archive.TarOptions{ + Compression: archive.Uncompressed, + IncludeFiles: []string{base}, + }) + if err != nil { + return nil, err + } + return &tarOutputStream, nil +} + +// UntarToDest writes to user destination the streamed tarball in input +func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destination string, gateway string) error { + // destination is a server address + path (scp-like uri) + if strings.Index(destination, ":") > -1 { + logrus.Debugf("Streaming using ssh and untaring remotely") + serverParts := strings.Split(destination, ":") + if len(serverParts) != 2 { + return fmt.Errorf("invalid destination uri, see 'scw cp -h' for usage") + } + + serverID := apiClient.GetServerID(serverParts[0]) + + server, err := apiClient.GetServer(serverID) + if err != nil { + return err + } + + // remoteCommand is executed on the remote server + // it streams a tarball raw content + remoteCommand := []string{"tar"} + remoteCommand = append(remoteCommand, "-C", serverParts[1]) + if os.Getenv("DEBUG") == "1" { + remoteCommand = append(remoteCommand, "-v") + } + remoteCommand = append(remoteCommand, "-xf", "-") + + // Resolve gateway + if gateway == "" { + gateway = os.Getenv("SCW_GATEWAY") + } + var gateway string + if gateway == serverID || gateway == serverParts[0] { + gateway = "" + } else { + gateway, err = api.ResolveGateway(apiClient, gateway) + if err != nil { + return fmt.Errorf("cannot resolve Gateway '%s': %v", gateway, err) + } + } + + // execCmd contains the ssh connection + the remoteCommand + execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, false, nil, remoteCommand, gateway)) + logrus.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) + spawnDst := exec.Command("ssh", execCmd...) + + untarInputStream, err := spawnDst.StdinPipe() + if err != nil { + return err + } + defer untarInputStream.Close() + + // spawnDst.Stderr = os.Stderr + // spawnDst.Stdout = os.Stdout + + err = spawnDst.Start() + if err != nil { + return err + } + + _, err = io.Copy(untarInputStream, *sourceStream) + return err + } + + // destination is stdout + if destination == "-" { // stdout + logrus.Debugf("Writing sourceStream(%v) to os.Stdout(%v)", sourceStream, os.Stdout) + _, err := io.Copy(os.Stdout, *sourceStream) + return err + } + + // destination is a path on localhost + logrus.Debugf("Untaring to local path: %s", destination) + err := archive.Untar(*sourceStream, destination, &archive.TarOptions{NoLchown: true}) + return err +} From 7aa7feb78b96b96200d67adede0c324e45e85d0a Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:35:12 +0200 Subject: [PATCH 10/36] Refactored 'create' command (#80) --- pkg/cli/create.go | 26 +++++++++++++++----------- pkg/commands/create.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 pkg/commands/create.go diff --git a/pkg/cli/create.go b/pkg/cli/create.go index 450de31f9e..276cfeecaa 100644 --- a/pkg/cli/create.go +++ b/pkg/cli/create.go @@ -5,11 +5,10 @@ package cli import ( - "fmt" + "strings" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdCreate = &Command{ @@ -41,19 +40,24 @@ var createEnv string // -e, --env flag var createVolume string // -v, --volume flag var createHelp bool // -h, --help flag -func runCreate(cmd *Command, args []string) { +func runCreate(cmd *Command, rawArgs []string) { if createHelp { cmd.PrintUsage() } - if len(args) != 1 { + if len(rawArgs) != 1 { cmd.PrintShortUsage() } - serverID, err := api.CreateServer(cmd.API, args[0], createName, createBootscript, createEnv, createVolume, true) - + args := commands.CreateArgs{ + Name: createName, + Bootscript: createBootscript, + Tags: strings.Split(createEnv, " "), + Volumes: strings.Split(createVolume, " "), + Image: rawArgs[0], + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunCreate(ctx, args) if err != nil { - log.Fatalf("Failed to create server: %v", err) + logrus.Fatalf("Cannot execute 'create': %v", err) } - - fmt.Println(serverID) } diff --git a/pkg/commands/create.go b/pkg/commands/create.go new file mode 100644 index 0000000000..ee0d3ba50f --- /dev/null +++ b/pkg/commands/create.go @@ -0,0 +1,34 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "strings" + + "github.com/scaleway/scaleway-cli/pkg/api" +) + +type CreateArgs struct { + Name string + Bootscript string + Tags []string + Volumes []string + Image string +} + +// RunCreate is the handler for 'scw create' +func RunCreate(ctx CommandContext, args CreateArgs) error { + env := strings.Join(args.Tags, " ") + volume := strings.Join(args.Volumes, " ") + serverID, err := api.CreateServer(ctx.API, args.Image, args.Name, args.Bootscript, env, volume, true) + if err != nil { + return err + } + + fmt.Fprintln(ctx.Stdout, serverID) + + return nil +} From 2e40afc054b22530d2f4dd62b61afaf4578bf1df Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:39:34 +0200 Subject: [PATCH 11/36] Refactored 'help' command (#80) --- pkg/commands/help.go | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 pkg/commands/help.go diff --git a/pkg/commands/help.go b/pkg/commands/help.go new file mode 100644 index 0000000000..36fd33d90e --- /dev/null +++ b/pkg/commands/help.go @@ -0,0 +1,7 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +// nothing here From 2f80f5e0d1ce66ebdddee5106d31cdf7cdda6430 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:43:24 +0200 Subject: [PATCH 12/36] Refactored 'history' command (#80) --- pkg/cli/history.go | 46 +++++++++-------------------------- pkg/commands/history.go | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 pkg/commands/history.go diff --git a/pkg/cli/history.go b/pkg/cli/history.go index 8fbd8272f4..d6a865725e 100644 --- a/pkg/cli/history.go +++ b/pkg/cli/history.go @@ -5,15 +5,8 @@ package cli import ( - "fmt" - "os" - "text/tabwriter" - "time" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - - utils "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdHistory = &Command{ @@ -34,39 +27,22 @@ var historyNoTrunc bool // --no-trunc flag var historyQuiet bool // -q, --quiet flag var historyHelp bool // -h, --help flag -func runHistory(cmd *Command, args []string) { +func runHistory(cmd *Command, rawArgs []string) { if historyHelp { cmd.PrintUsage() } - if len(args) != 1 { + if len(rawArgs) != 1 { cmd.PrintShortUsage() } - imageID := cmd.API.GetImageID(args[0], true) - image, err := cmd.API.GetImage(imageID) - if err != nil { - log.Fatalf("Cannot get image %s: %v", imageID, err) - } - - if imagesQ { - fmt.Println(imageID) - return + args := commands.HistoryArgs{ + Quiet: historyQuiet, + NoTrunc: historyNoTrunc, + Image: rawArgs[0], } - - w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "IMAGE\tCREATED\tCREATED BY\tSIZE\n") - - identifier := utils.TruncIf(image.Identifier, 8, !historyNoTrunc) - - creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", image.CreationDate) + ctx := cmd.GetContext(rawArgs) + err := commands.RunHistory(ctx, args) if err != nil { - log.Fatalf("Unable to parse creation date from the Scaleway API: %v", err) + logrus.Fatalf("Cannot execute 'history': %v", err) } - creationDateStr := units.HumanDuration(time.Now().UTC().Sub(creationDate)) - - volumeName := utils.TruncIf(image.RootVolume.Name, 25, !historyNoTrunc) - size := units.HumanSize(float64(image.RootVolume.Size)) - - fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", identifier, creationDateStr, volumeName, size) } diff --git a/pkg/commands/history.go b/pkg/commands/history.go new file mode 100644 index 0000000000..ed09de4a3f --- /dev/null +++ b/pkg/commands/history.go @@ -0,0 +1,53 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "text/tabwriter" + "time" + + "github.com/docker/docker/pkg/units" + "github.com/scaleway/scaleway-cli/pkg/utils" +) + +// HistoryArgs are flags for the `RunHistory` function +type HistoryArgs struct { + NoTrunc bool + Quiet bool + Image string +} + +// RunHistory is the handler for 'scw history' +func RunHistory(ctx CommandContext, args HistoryArgs) error { + imageID := ctx.API.GetImageID(args.Image, true) + image, err := ctx.API.GetImage(imageID) + if err != nil { + return fmt.Errorf("cannot get image %s: %v", imageID, err) + } + + if args.Quiet { + fmt.Fprintln(ctx.Stdout, imageID) + return nil + } + + w := tabwriter.NewWriter(ctx.Stdout, 10, 1, 3, ' ', 0) + defer w.Flush() + fmt.Fprintf(w, "IMAGE\tCREATED\tCREATED BY\tSIZE\n") + + identifier := utils.TruncIf(image.Identifier, 8, !args.NoTrunc) + + creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", image.CreationDate) + if err != nil { + return fmt.Errorf("unable to parse creation date from the Scaleway API: %v", err) + } + creationDateStr := units.HumanDuration(time.Now().UTC().Sub(creationDate)) + + volumeName := utils.TruncIf(image.RootVolume.Name, 25, !args.NoTrunc) + size := units.HumanSize(float64(image.RootVolume.Size)) + + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", identifier, creationDateStr, volumeName, size) + return nil +} From d7c2b282fc4f4c14a8cc5a91b6dd6611ac36a139 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:49:15 +0200 Subject: [PATCH 13/36] Refactored 'images' command (#80) --- pkg/cli/images.go | 171 +++------------------------------------ pkg/commands/images.go | 177 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 159 deletions(-) create mode 100644 pkg/commands/images.go diff --git a/pkg/cli/images.go b/pkg/cli/images.go index 23743861b7..f26b1bf3b6 100644 --- a/pkg/cli/images.go +++ b/pkg/cli/images.go @@ -5,18 +5,8 @@ package cli import ( - "fmt" - "os" - "sort" - "sync" - "text/tabwriter" - "time" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdImages = &Command{ @@ -39,159 +29,22 @@ var imagesQ bool // -q flag var imagesNoTrunc bool // -no-trunc flag var imagesHelp bool // -h, --help flag -func runImages(cmd *Command, args []string) { +func runImages(cmd *Command, rawArgs []string) { if imagesHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } - wg := sync.WaitGroup{} - chEntries := make(chan api.ScalewayImageInterface) - var entries = []api.ScalewayImageInterface{} - - wg.Add(1) - go func() { - defer wg.Done() - images, err := cmd.API.GetImages() - if err != nil { - log.Fatalf("unable to fetch images from the Scaleway API: %v", err) - } - for _, val := range *images { - creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) - if err != nil { - log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) - } - chEntries <- api.ScalewayImageInterface{ - Type: "image", - CreationDate: creationDate, - Identifier: val.Identifier, - Name: val.Name, - Public: val.Public, - Tag: "latest", - VirtualSize: float64(val.RootVolume.Size), - } - } - }() - - if imagesA { - wg.Add(1) - go func() { - defer wg.Done() - snapshots, err := cmd.API.GetSnapshots() - if err != nil { - log.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) - } - for _, val := range *snapshots { - creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) - if err != nil { - log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) - } - chEntries <- api.ScalewayImageInterface{ - Type: "snapshot", - CreationDate: creationDate, - Identifier: val.Identifier, - Name: val.Name, - Tag: "", - VirtualSize: float64(val.Size), - Public: false, - } - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - bootscripts, err := cmd.API.GetBootscripts() - if err != nil { - log.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err) - } - for _, val := range *bootscripts { - chEntries <- api.ScalewayImageInterface{ - Type: "bootscript", - Identifier: val.Identifier, - Name: val.Title, - Tag: "", - Public: false, - } - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - volumes, err := cmd.API.GetVolumes() - if err != nil { - log.Fatalf("unable to fetch volumes from the Scaleway API: %v", err) - } - for _, val := range *volumes { - creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) - if err != nil { - log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) - } - chEntries <- api.ScalewayImageInterface{ - Type: "volume", - CreationDate: creationDate, - Identifier: val.Identifier, - Name: val.Name, - Tag: "", - VirtualSize: float64(val.Size), - Public: false, - } - } - }() - } - - go func() { - wg.Wait() - close(chEntries) - }() - - done := false - for { - select { - case entry, ok := <-chEntries: - if !ok { - done = true - break - } - entries = append(entries, entry) - } - if done { - break - } - } - - w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) - defer w.Flush() - if !imagesQ { - fmt.Fprintf(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE\n") + args := commands.ImagesArgs{ + All: imagesA, + Quiet: imagesQ, + NoTrunc: imagesNoTrunc, } - sort.Sort(api.ByCreationDate(entries)) - for _, image := range entries { - if imagesQ { - fmt.Fprintf(w, "%s\n", image.Identifier) - } else { - tag := image.Tag - shortID := utils.TruncIf(image.Identifier, 8, !imagesNoTrunc) - name := utils.Wordify(image.Name) - if !image.Public && image.Type == "image" { - name = "user/" + name - } - shortName := utils.TruncIf(name, 25, !imagesNoTrunc) - var creationDate, virtualSize string - if image.CreationDate.IsZero() { - creationDate = "n/a" - } else { - creationDate = units.HumanDuration(time.Now().UTC().Sub(image.CreationDate)) - } - if image.VirtualSize == 0 { - virtualSize = "n/a" - } else { - virtualSize = units.HumanSize(image.VirtualSize) - } - fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", shortName, tag, shortID, creationDate, virtualSize) - } + ctx := cmd.GetContext(rawArgs) + err := commands.RunImages(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'images': %v", err) } } diff --git a/pkg/commands/images.go b/pkg/commands/images.go new file mode 100644 index 0000000000..c23302894c --- /dev/null +++ b/pkg/commands/images.go @@ -0,0 +1,177 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "log" + "sort" + "sync" + "text/tabwriter" + "time" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" +) + +// ImagesArgs are flags for the `RunImages` function +type ImagesArgs struct { + All bool + NoTrunc bool + Quiet bool +} + +// RunImages is the handler for 'scw images' +func RunImages(ctx CommandContext, args ImagesArgs) error { + wg := sync.WaitGroup{} + chEntries := make(chan api.ScalewayImageInterface) + var entries = []api.ScalewayImageInterface{} + + wg.Add(1) + go func() { + defer wg.Done() + images, err := ctx.API.GetImages() + if err != nil { + log.Fatalf("unable to fetch images from the Scaleway API: %v", err) + } + for _, val := range *images { + creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) + if err != nil { + log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + } + chEntries <- api.ScalewayImageInterface{ + Type: "image", + CreationDate: creationDate, + Identifier: val.Identifier, + Name: val.Name, + Public: val.Public, + Tag: "latest", + VirtualSize: float64(val.RootVolume.Size), + } + } + }() + + if args.All { + wg.Add(1) + go func() { + defer wg.Done() + snapshots, err := ctx.API.GetSnapshots() + if err != nil { + log.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) + } + for _, val := range *snapshots { + creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) + if err != nil { + log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + } + chEntries <- api.ScalewayImageInterface{ + Type: "snapshot", + CreationDate: creationDate, + Identifier: val.Identifier, + Name: val.Name, + Tag: "", + VirtualSize: float64(val.Size), + Public: false, + } + } + }() + + wg.Add(1) + go func() { + defer wg.Done() + bootscripts, err := ctx.API.GetBootscripts() + if err != nil { + log.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err) + } + for _, val := range *bootscripts { + chEntries <- api.ScalewayImageInterface{ + Type: "bootscript", + Identifier: val.Identifier, + Name: val.Title, + Tag: "", + Public: false, + } + } + }() + + wg.Add(1) + go func() { + defer wg.Done() + volumes, err := ctx.API.GetVolumes() + if err != nil { + log.Fatalf("unable to fetch volumes from the Scaleway API: %v", err) + } + for _, val := range *volumes { + creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) + if err != nil { + log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + } + chEntries <- api.ScalewayImageInterface{ + Type: "volume", + CreationDate: creationDate, + Identifier: val.Identifier, + Name: val.Name, + Tag: "", + VirtualSize: float64(val.Size), + Public: false, + } + } + }() + } + + go func() { + wg.Wait() + close(chEntries) + }() + + done := false + for { + select { + case entry, ok := <-chEntries: + if !ok { + done = true + break + } + entries = append(entries, entry) + } + if done { + break + } + } + + w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0) + defer w.Flush() + if !args.Quiet { + fmt.Fprintf(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE\n") + } + sort.Sort(api.ByCreationDate(entries)) + for _, image := range entries { + if args.Quiet { + fmt.Fprintf(ctx.Stdout, "%s\n", image.Identifier) + } else { + tag := image.Tag + shortID := utils.TruncIf(image.Identifier, 8, !args.NoTrunc) + name := utils.Wordify(image.Name) + if !image.Public && image.Type == "image" { + name = "user/" + name + } + shortName := utils.TruncIf(name, 25, !args.NoTrunc) + var creationDate, virtualSize string + if image.CreationDate.IsZero() { + creationDate = "n/a" + } else { + creationDate = units.HumanDuration(time.Now().UTC().Sub(image.CreationDate)) + } + if image.VirtualSize == 0 { + virtualSize = "n/a" + } else { + virtualSize = units.HumanSize(image.VirtualSize) + } + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", shortName, tag, shortID, creationDate, virtualSize) + } + } + return nil +} From 864ee31273ef03065bf03756af24917841961218 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:57:35 +0200 Subject: [PATCH 14/36] Refactored 'info' command (#80) --- pkg/cli/info.go | 41 ++++++++++------------------------------ pkg/commands/info.go | 45 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 pkg/commands/info.go diff --git a/pkg/cli/info.go b/pkg/cli/info.go index da2bc11496..74b9e207ee 100644 --- a/pkg/cli/info.go +++ b/pkg/cli/info.go @@ -5,13 +5,8 @@ package cli import ( - "fmt" - "os" - "runtime" - - "github.com/scaleway/scaleway-cli/vendor/github.com/kardianos/osext" - - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdInfo = &Command{ @@ -28,34 +23,18 @@ func init() { // Flags var infoHelp bool // -h, --help flag -func runInfo(cmd *Command, args []string) { +func runInfo(cmd *Command, rawArgs []string) { if infoHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } - // FIXME: fmt.Printf("Servers: %s\n", "quantity") - // FIXME: fmt.Printf("Images: %s\n", "quantity") - fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "") - - fmt.Printf("Organization: %s\n", cmd.API.Organization) - // FIXME: add partially-masked token - fmt.Printf("API Endpoint: %s\n", os.Getenv("scaleway_api_endpoint")) - configPath, _ := utils.GetConfigFilePath() - fmt.Printf("RC file: %s\n", configPath) - fmt.Printf("User: %s\n", os.Getenv("USER")) - fmt.Printf("CPUs: %d\n", runtime.NumCPU()) - hostname, _ := os.Hostname() - fmt.Printf("Hostname: %s\n", hostname) - cliPath, _ := osext.Executable() - fmt.Printf("CLI Path: %s\n", cliPath) - - fmt.Printf("Cache: %s\n", cmd.API.Cache.Path) - fmt.Printf(" Servers: %d\n", cmd.API.Cache.GetNbServers()) - fmt.Printf(" Images: %d\n", cmd.API.Cache.GetNbImages()) - fmt.Printf(" Snapshots: %d\n", cmd.API.Cache.GetNbSnapshots()) - fmt.Printf(" Volumes: %d\n", cmd.API.Cache.GetNbVolumes()) - fmt.Printf(" Bootscripts: %d\n", cmd.API.Cache.GetNbBootscripts()) + args := commands.InfoArgs{} + ctx := cmd.GetContext(rawArgs) + err := commands.RunInfo(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'info': %v", err) + } } diff --git a/pkg/commands/info.go b/pkg/commands/info.go new file mode 100644 index 0000000000..8dc3139cf8 --- /dev/null +++ b/pkg/commands/info.go @@ -0,0 +1,45 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "os" + "runtime" + + "github.com/scaleway/scaleway-cli/vendor/github.com/kardianos/osext" + + "github.com/scaleway/scaleway-cli/pkg/utils" +) + +// InfoArgs are flags for the `RunInfo` function +type InfoArgs struct{} + +// RunInfo is the handler for 'scw info' +func RunInfo(ctx CommandContext, args InfoArgs) error { + // FIXME: fmt.Fprintf(ctx.Stdout, "Servers: %s\n", "quantity") + // FIXME: fmt.Fprintf(ctx.Stdout, "Images: %s\n", "quantity") + fmt.Fprintf(ctx.Stdout, "Debug mode (client): %v\n", ctx.Getenv("DEBUG") != "") + + fmt.Fprintf(ctx.Stdout, "Organization: %s\n", ctx.API.Organization) + // FIXME: add partially-masked token + fmt.Fprintf(ctx.Stdout, "API Endpoint: %s\n", ctx.Getenv("scaleway_api_endpoint")) + configPath, _ := utils.GetConfigFilePath() + fmt.Fprintf(ctx.Stdout, "RC file: %s\n", configPath) + fmt.Fprintf(ctx.Stdout, "User: %s\n", ctx.Getenv("USER")) + fmt.Fprintf(ctx.Stdout, "CPUs: %d\n", runtime.NumCPU()) + hostname, _ := os.Hostname() + fmt.Fprintf(ctx.Stdout, "Hostname: %s\n", hostname) + cliPath, _ := osext.Executable() + fmt.Fprintf(ctx.Stdout, "CLI Path: %s\n", cliPath) + + fmt.Fprintf(ctx.Stdout, "Cache: %s\n", ctx.API.Cache.Path) + fmt.Fprintf(ctx.Stdout, " Servers: %d\n", ctx.API.Cache.GetNbServers()) + fmt.Fprintf(ctx.Stdout, " Images: %d\n", ctx.API.Cache.GetNbImages()) + fmt.Fprintf(ctx.Stdout, " Snapshots: %d\n", ctx.API.Cache.GetNbSnapshots()) + fmt.Fprintf(ctx.Stdout, " Volumes: %d\n", ctx.API.Cache.GetNbVolumes()) + fmt.Fprintf(ctx.Stdout, " Bootscripts: %d\n", ctx.API.Cache.GetNbBootscripts()) + return nil +} From c3fa4e153652d553d815b2d89b6a4174df61cc82 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 18:13:08 +0200 Subject: [PATCH 15/36] Refactored 'inspect' command (#80) --- pkg/cli/inspect.go | 104 +++++-------------------------------- pkg/commands/inspect.go | 112 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 92 deletions(-) create mode 100644 pkg/commands/inspect.go diff --git a/pkg/cli/inspect.go b/pkg/cli/inspect.go index 89c890fffb..0c5cba302e 100644 --- a/pkg/cli/inspect.go +++ b/pkg/cli/inspect.go @@ -5,15 +5,9 @@ package cli import ( - "encoding/json" - "fmt" - "os" - "text/template" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/vendor/github.com/skratchdot/open-golang/open" - - "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdInspect = &Command{ @@ -51,96 +45,22 @@ var inspectFormat string // -f, --format flag var inspectBrowser bool // -b, --browser flag var inspectHelp bool // -h, --help flag -func runInspect(cmd *Command, args []string) { +func runInspect(cmd *Command, rawArgs []string) { if inspectHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - nbInspected := 0 - ci := make(chan api.ScalewayResolvedIdentifier) - cj := make(chan api.InspectIdentifierResult) - go api.ResolveIdentifiers(cmd.API, args, ci) - go api.InspectIdentifiers(cmd.API, ci, cj) - - if inspectBrowser { - // --browser will open links in the browser - for { - data, isOpen := <-cj - if !isOpen { - break - } - - switch data.Type { - case api.IdentifierServer: - err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/servers/%s", data.Object.(*api.ScalewayServer).Identifier)) - if err != nil { - log.Fatalf("Cannot open browser: %v", err) - } - nbInspected++ - case api.IdentifierImage: - err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/images/%s", data.Object.(*api.ScalewayImage).Identifier)) - if err != nil { - log.Fatalf("Cannot open browser: %v", err) - } - nbInspected++ - case api.IdentifierVolume: - err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/volumes/%s", data.Object.(*api.ScalewayVolume).Identifier)) - if err != nil { - log.Fatalf("Cannot open browser: %v", err) - } - nbInspected++ - case api.IdentifierSnapshot: - log.Errorf("Cannot use '--browser' option for snapshots") - case api.IdentifierBootscript: - log.Errorf("Cannot use '--browser' option for bootscripts") - } - } - - } else { - // without --browser option, inspect will print object info to the terminal - res := "[" - for { - data, isOpen := <-cj - if !isOpen { - break - } - if inspectFormat == "" { - dataB, err := json.MarshalIndent(data.Object, "", " ") - if err == nil { - if nbInspected != 0 { - res += ",\n" - } - res += string(dataB) - nbInspected++ - } - } else { - tmpl, err := template.New("").Funcs(api.FuncMap).Parse(inspectFormat) - if err != nil { - log.Fatalf("Format parsing error: %v", err) - } - - err = tmpl.Execute(os.Stdout, data.Object) - if err != nil { - log.Fatalf("Format execution error: %v", err) - } - fmt.Fprint(os.Stdout, "\n") - nbInspected++ - } - } - res += "]" - - if inspectFormat == "" { - if os.Getenv("SCW_SENSITIVE") != "1" { - res = cmd.API.HideAPICredentials(res) - } - fmt.Println(res) - } + args := commands.InspectArgs{ + Format: inspectFormat, + Browser: inspectBrowser, + Identifiers: rawArgs, } - - if len(args) != nbInspected { - os.Exit(1) + ctx := cmd.GetContext(rawArgs) + err := commands.RunInspect(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'inspect': %v", err) } } diff --git a/pkg/commands/inspect.go b/pkg/commands/inspect.go new file mode 100644 index 0000000000..ce335d8060 --- /dev/null +++ b/pkg/commands/inspect.go @@ -0,0 +1,112 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "encoding/json" + "fmt" + "os" + "text/template" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/vendor/github.com/skratchdot/open-golang/open" +) + +// InspectArgs are flags for the `RunInspect` function +type InspectArgs struct { + Format string + Browser bool + Identifiers []string +} + +// RunInspect is the handler for 'scw inspect' +func RunInspect(ctx CommandContext, args InspectArgs) error { + nbInspected := 0 + ci := make(chan api.ScalewayResolvedIdentifier) + cj := make(chan api.InspectIdentifierResult) + go api.ResolveIdentifiers(ctx.API, args.Identifiers, ci) + go api.InspectIdentifiers(ctx.API, ci, cj) + + if args.Browser { + // --browser will open links in the browser + for { + data, isOpen := <-cj + if !isOpen { + break + } + + switch data.Type { + case api.IdentifierServer: + err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/servers/%s", data.Object.(*api.ScalewayServer).Identifier)) + if err != nil { + return fmt.Errorf("cannot open browser: %v", err) + } + nbInspected++ + case api.IdentifierImage: + err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/images/%s", data.Object.(*api.ScalewayImage).Identifier)) + if err != nil { + return fmt.Errorf("cannot open browser: %v", err) + } + nbInspected++ + case api.IdentifierVolume: + err := open.Start(fmt.Sprintf("https://cloud.scaleway.com/#/volumes/%s", data.Object.(*api.ScalewayVolume).Identifier)) + if err != nil { + return fmt.Errorf("cannot open browser: %v", err) + } + nbInspected++ + case api.IdentifierSnapshot: + logrus.Errorf("Cannot use '--browser' option for snapshots") + case api.IdentifierBootscript: + logrus.Errorf("Cannot use '--browser' option for bootscripts") + } + } + + } else { + // without --browser option, inspect will print object info to the terminal + res := "[" + for { + data, isOpen := <-cj + if !isOpen { + break + } + if args.Format == "" { + dataB, err := json.MarshalIndent(data.Object, "", " ") + if err == nil { + if nbInspected != 0 { + res += ",\n" + } + res += string(dataB) + nbInspected++ + } + } else { + tmpl, err := template.New("").Funcs(api.FuncMap).Parse(args.Format) + if err != nil { + return fmt.Errorf("format parsing error: %v", err) + } + + err = tmpl.Execute(ctx.Stdout, data.Object) + if err != nil { + return fmt.Errorf("format execution error: %v", err) + } + fmt.Fprint(ctx.Stdout, "\n") + nbInspected++ + } + } + res += "]" + + if args.Format == "" { + if os.Getenv("SCW_SENSITIVE") != "1" { + res = ctx.API.HideAPICredentials(res) + } + fmt.Fprintln(ctx.Stdout, res) + } + } + + if len(args.Identifiers) != nbInspected { + os.Exit(1) + } + return nil +} From bc6d79444fa9601b54c333ea9682981d494b8ab9 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 18:26:11 +0200 Subject: [PATCH 16/36] Refactored 'kill' command (#80) --- pkg/cli/kill.go | 49 ++++++++----------------------------- pkg/commands/kill.go | 57 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 pkg/commands/kill.go diff --git a/pkg/cli/kill.go b/pkg/cli/kill.go index 1a4addcc12..b1536314ba 100644 --- a/pkg/cli/kill.go +++ b/pkg/cli/kill.go @@ -5,14 +5,9 @@ package cli import ( - "os" - "os/exec" - "strings" + "github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdKill = &Command{ @@ -32,45 +27,21 @@ func init() { var killHelp bool // -h, --help flag var killGateway string // -g, --gateway flag -func runKill(cmd *Command, args []string) { +func runKill(cmd *Command, rawArgs []string) { if killHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - command := "halt" - server, err := cmd.API.GetServer(serverID) - if err != nil { - log.Fatalf("Failed to get server information for %s: %v", serverID, err) - } - - // Resolve gateway - if killGateway == "" { - killGateway = os.Getenv("SCW_GATEWAY") + args := commands.KillArgs{ + Gateway: killGateway, + Server: rawArgs[0], } - var gateway string - if killGateway == serverID || killGateway == args[0] { - gateway = "" - } else { - gateway, err = api.ResolveGateway(cmd.API, killGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", killGateway, err) - } - } - - execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, nil, []string{command}, gateway)) - - log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) - - spawn := exec.Command("ssh", execCmd...) - spawn.Stdout = os.Stdout - spawn.Stdin = os.Stdin - spawn.Stderr = os.Stderr - err = spawn.Run() + ctx := cmd.GetContext(rawArgs) + err := commands.RunKill(ctx, args) if err != nil { - log.Fatal(err) + logrus.Fatalf("Cannot execute 'kill': %v", err) } } diff --git a/pkg/commands/kill.go b/pkg/commands/kill.go new file mode 100644 index 0000000000..3ab5a634bd --- /dev/null +++ b/pkg/commands/kill.go @@ -0,0 +1,57 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "os" + "os/exec" + "strings" + + "github.com/docker/machine/log" + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" +) + +// KillArgs are flags for the `RunKill` function +type KillArgs struct { + Gateway string + Server string +} + +// RunKill is the handler for 'scw kill' +func RunKill(ctx CommandContext, args KillArgs) error { + serverID := ctx.API.GetServerID(args.Server) + command := "halt" + server, err := ctx.API.GetServer(serverID) + if err != nil { + return fmt.Errorf("failed to get server information for %s: %v", serverID, err) + } + + // Resolve gateway + if args.Gateway == "" { + args.Gateway = ctx.Getenv("SCW_GATEWAY") + } + var gateway string + if args.Gateway == serverID || args.Gateway == args.Server { + gateway = "" + } else { + gateway, err = api.ResolveGateway(ctx.API, args.Gateway) + if err != nil { + return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) + } + } + + execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, nil, []string{command}, gateway)) + + log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) + + spawn := exec.Command("ssh", execCmd...) + spawn.Stdout = os.Stdout + spawn.Stdin = os.Stdin + spawn.Stderr = os.Stderr + + return spawn.Run() +} From 91617d12b3388bd78ec9265d85dbfed169f66414 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 17:25:15 +0200 Subject: [PATCH 17/36] party -c -d=vendor --- pkg/cli/attach.go | 2 +- pkg/cli/create.go | 2 +- pkg/cli/events.go | 2 +- pkg/cli/exec.go | 2 +- pkg/cli/help.go | 2 +- pkg/cli/history.go | 2 +- pkg/cli/kill.go | 2 +- pkg/cli/ps.go | 2 +- pkg/cli/x_completion.go | 2 +- pkg/cli/x_flushcache.go | 2 +- pkg/commands/history.go | 2 +- pkg/commands/kill.go | 4 ++-- pkg/commands/login.go | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/cli/attach.go b/pkg/cli/attach.go index 2901622d11..fc47dff5f2 100644 --- a/pkg/cli/attach.go +++ b/pkg/cli/attach.go @@ -5,8 +5,8 @@ package cli import ( - "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdAttach = &Command{ diff --git a/pkg/cli/create.go b/pkg/cli/create.go index 276cfeecaa..4806637efe 100644 --- a/pkg/cli/create.go +++ b/pkg/cli/create.go @@ -7,8 +7,8 @@ package cli import ( "strings" - "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdCreate = &Command{ diff --git a/pkg/cli/events.go b/pkg/cli/events.go index ab68e7e447..79b54a6959 100644 --- a/pkg/cli/events.go +++ b/pkg/cli/events.go @@ -5,8 +5,8 @@ package cli import ( - "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdEvents = &Command{ diff --git a/pkg/cli/exec.go b/pkg/cli/exec.go index 334a10ed3a..76eeaae79c 100644 --- a/pkg/cli/exec.go +++ b/pkg/cli/exec.go @@ -5,8 +5,8 @@ package cli import ( - "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdExec = &Command{ diff --git a/pkg/cli/help.go b/pkg/cli/help.go index fa787f04bf..a1c1e18f3f 100644 --- a/pkg/cli/help.go +++ b/pkg/cli/help.go @@ -8,7 +8,7 @@ import ( "os" "text/template" - "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) // CmdHelp is the 'scw help' command diff --git a/pkg/cli/history.go b/pkg/cli/history.go index d6a865725e..3f0e808720 100644 --- a/pkg/cli/history.go +++ b/pkg/cli/history.go @@ -5,8 +5,8 @@ package cli import ( - "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdHistory = &Command{ diff --git a/pkg/cli/kill.go b/pkg/cli/kill.go index b1536314ba..a5d181e465 100644 --- a/pkg/cli/kill.go +++ b/pkg/cli/kill.go @@ -5,7 +5,7 @@ package cli import ( - "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" ) diff --git a/pkg/cli/ps.go b/pkg/cli/ps.go index 93cebdf76b..91066164fe 100644 --- a/pkg/cli/ps.go +++ b/pkg/cli/ps.go @@ -5,8 +5,8 @@ package cli import ( - "github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdPs = &Command{ diff --git a/pkg/cli/x_completion.go b/pkg/cli/x_completion.go index 13351a9e25..7133e26112 100644 --- a/pkg/cli/x_completion.go +++ b/pkg/cli/x_completion.go @@ -9,8 +9,8 @@ import ( "sort" "strings" - "github.com/Sirupsen/logrus" utils "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdCompletion = &Command{ diff --git a/pkg/cli/x_flushcache.go b/pkg/cli/x_flushcache.go index ed12bacf8b..87a280377b 100644 --- a/pkg/cli/x_flushcache.go +++ b/pkg/cli/x_flushcache.go @@ -7,7 +7,7 @@ package cli import ( "fmt" - "github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdFlushCache = &Command{ diff --git a/pkg/commands/history.go b/pkg/commands/history.go index ed09de4a3f..34f97295d4 100644 --- a/pkg/commands/history.go +++ b/pkg/commands/history.go @@ -9,8 +9,8 @@ import ( "text/tabwriter" "time" - "github.com/docker/docker/pkg/units" "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" ) // HistoryArgs are flags for the `RunHistory` function diff --git a/pkg/commands/kill.go b/pkg/commands/kill.go index 3ab5a634bd..bb3d945345 100644 --- a/pkg/commands/kill.go +++ b/pkg/commands/kill.go @@ -10,9 +10,9 @@ import ( "os/exec" "strings" - "github.com/docker/machine/log" "github.com/scaleway/scaleway-cli/pkg/api" "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) // KillArgs are flags for the `RunKill` function @@ -46,7 +46,7 @@ func RunKill(ctx CommandContext, args KillArgs) error { execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, nil, []string{command}, gateway)) - log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) + logrus.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) spawn := exec.Command("ssh", execCmd...) spawn.Stdout = os.Stdout diff --git a/pkg/commands/login.go b/pkg/commands/login.go index 900206c93e..a2c1968ab4 100644 --- a/pkg/commands/login.go +++ b/pkg/commands/login.go @@ -12,7 +12,7 @@ import ( "os" "strings" - "golang.org/x/crypto/ssh/terminal" + "github.com/scaleway/scaleway-cli/vendor/golang.org/x/crypto/ssh/terminal" "github.com/scaleway/scaleway-cli/pkg/api" "github.com/scaleway/scaleway-cli/pkg/utils" From 9ea9db35dbed3ba52fedf9858e7e252b53a21be1 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 18:37:14 +0200 Subject: [PATCH 18/36] Refactored 'logout' command (#80) --- pkg/cli/logout.go | 24 ++++++++---------------- pkg/commands/logout.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 pkg/commands/logout.go diff --git a/pkg/cli/logout.go b/pkg/cli/logout.go index eb1bfd8283..e8d0160a7a 100644 --- a/pkg/cli/logout.go +++ b/pkg/cli/logout.go @@ -5,11 +5,8 @@ package cli import ( - "os" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdLogout = &Command{ @@ -26,23 +23,18 @@ func init() { // FLags var logoutHelp bool // -h, --help flag -func runLogout(cmd *Command, args []string) { +func runLogout(cmd *Command, rawArgs []string) { if logoutHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } - scwrcPath, err := utils.GetConfigFilePath() + args := commands.LogoutArgs{} + ctx := cmd.GetContext(rawArgs) + err := commands.RunLogout(ctx, args) if err != nil { - log.Fatalf("Unable to get scwrc config file path: %v", err) - } - - if _, err = os.Stat(scwrcPath); err == nil { - err = os.Remove(scwrcPath) - if err != nil { - log.Fatalf("Unable to remove scwrc config file: %v", err) - } + logrus.Fatalf("Cannot execute 'logout': %v", err) } } diff --git a/pkg/commands/logout.go b/pkg/commands/logout.go new file mode 100644 index 0000000000..da4e3ab159 --- /dev/null +++ b/pkg/commands/logout.go @@ -0,0 +1,32 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "os" + + "github.com/scaleway/scaleway-cli/pkg/utils" +) + +// LogoutArgs are flags for the `RunLogout` function +type LogoutArgs struct{} + +// RunLogout is the handler for 'scw logout' +func RunLogout(ctx CommandContext, args LogoutArgs) error { + // FIXME: ask if we need to remove the local ssh key on the account + scwrcPath, err := utils.GetConfigFilePath() + if err != nil { + return fmt.Errorf("unable to get scwrc config file path: %v", err) + } + + if _, err = os.Stat(scwrcPath); err == nil { + err = os.Remove(scwrcPath) + if err != nil { + return fmt.Errorf("unable to remove scwrc config file: %v", err) + } + } + return nil +} From 9c75b4bc816dc3de6c805a3d47a1f7f078a71550 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 22:42:41 +0200 Subject: [PATCH 19/36] Refactored 'logs' command (#80) --- pkg/cli/logs.go | 41 +++++++++--------------------------- pkg/commands/logs.go | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 pkg/commands/logs.go diff --git a/pkg/cli/logs.go b/pkg/cli/logs.go index 96fd758709..a89091c10b 100644 --- a/pkg/cli/logs.go +++ b/pkg/cli/logs.go @@ -5,12 +5,9 @@ package cli import ( - "os" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdLogs = &Command{ @@ -29,39 +26,21 @@ func init() { var logsHelp bool // -h, --help flag var logsGateway string // -g, --gateway flag -func runLogs(cmd *Command, args []string) { +func runLogs(cmd *Command, rawArgs []string) { if logsHelp { cmd.PrintUsage() } - if len(args) != 1 { + if len(rawArgs) != 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - server, err := cmd.API.GetServer(serverID) - if err != nil { - log.Fatalf("Failed to get server information for %s: %v", serverID, err) + args := commands.LogsArgs{ + Gateway: logsGateway, + Server: rawArgs[0], } - - // FIXME: switch to serial history when API is ready - - // Resolve gateway - if logsGateway == "" { - logsGateway = os.Getenv("SCW_GATEWAY") - } - var gateway string - if logsGateway == serverID || logsGateway == args[0] { - gateway = "" - } else { - gateway, err = api.ResolveGateway(cmd.API, logsGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", logsGateway, err) - } - } - - command := []string{"dmesg"} - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway) + ctx := cmd.GetContext(rawArgs) + err := commands.RunLogs(ctx, args) if err != nil { - log.Fatalf("Command execution failed: %v", err) + logrus.Fatalf("Cannot execute 'logs': %v", err) } } diff --git a/pkg/commands/logs.go b/pkg/commands/logs.go new file mode 100644 index 0000000000..3cbdcfe5e2 --- /dev/null +++ b/pkg/commands/logs.go @@ -0,0 +1,50 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" +) + +// LogsArgs are flags for the `RunLogs` function +type LogsArgs struct { + Gateway string + Server string +} + +// RunLogs is the handler for 'scw logs' +func RunLogs(ctx CommandContext, args LogsArgs) error { + serverID := ctx.API.GetServerID(args.Server) + server, err := ctx.API.GetServer(serverID) + if err != nil { + return fmt.Errorf("failed to get server information for %s: %v", serverID, err) + } + + // FIXME: switch to serial history when API is ready + + // Resolve gateway + if args.Gateway == "" { + args.Gateway = ctx.Getenv("SCW_GATEWAY") + } + var gateway string + if args.Gateway == serverID || args.Gateway == args.Server { + gateway = "" + } else { + gateway, err = api.ResolveGateway(ctx.API, args.Gateway) + if err != nil { + return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) + } + } + + command := []string{"dmesg"} + err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway) + if err != nil { + return fmt.Errorf("command execution failed: %v", err) + } + return nil +} From e94726cd289c694260c7595c2ab29f5ddc0b15f9 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 22:45:59 +0200 Subject: [PATCH 20/36] Refactored 'port' command (#80) --- pkg/cli/port.go | 39 +++++++++-------------------------- pkg/commands/port.go | 49 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 pkg/commands/port.go diff --git a/pkg/cli/port.go b/pkg/cli/port.go index 085322bafd..e7bf460330 100644 --- a/pkg/cli/port.go +++ b/pkg/cli/port.go @@ -5,12 +5,9 @@ package cli import ( - "os" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdPort = &Command{ @@ -29,37 +26,21 @@ func init() { var portHelp bool // -h, --help flag var portGateway string // -g, --gateway flag -func runPort(cmd *Command, args []string) { +func runPort(cmd *Command, rawArgs []string) { if portHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - server, err := cmd.API.GetServer(serverID) - if err != nil { - log.Fatalf("Failed to get server information for %s: %v", serverID, err) - } - - // Resolve gateway - if portGateway == "" { - portGateway = os.Getenv("SCW_GATEWAY") - } - var gateway string - if portGateway == serverID || portGateway == args[0] { - gateway = "" - } else { - gateway, err = api.ResolveGateway(cmd.API, portGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", portGateway, err) - } + args := commands.PortArgs{ + Gateway: portGateway, + Server: rawArgs[0], } - - command := []string{"netstat -lutn 2>/dev/null | grep LISTEN"} - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway) + ctx := cmd.GetContext(rawArgs) + err := commands.RunPort(ctx, args) if err != nil { - log.Fatalf("Command execution failed: %v", err) + logrus.Fatalf("Cannot execute 'port': %v", err) } } diff --git a/pkg/commands/port.go b/pkg/commands/port.go new file mode 100644 index 0000000000..3d4092f8e7 --- /dev/null +++ b/pkg/commands/port.go @@ -0,0 +1,49 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" +) + +// PortArgs are flags for the `RunPort` function +type PortArgs struct { + Gateway string + Server string +} + +// RunPort is the handler for 'scw port' +func RunPort(ctx CommandContext, args PortArgs) error { + serverID := ctx.API.GetServerID(args.Server) + server, err := ctx.API.GetServer(serverID) + if err != nil { + return fmt.Errorf("failed to get server information for %s: %v", serverID, err) + } + + // Resolve gateway + if args.Gateway == "" { + args.Gateway = ctx.Getenv("SCW_GATEWAY") + } + var gateway string + if args.Gateway == serverID || args.Gateway == args.Server { + gateway = "" + } else { + gateway, err = api.ResolveGateway(ctx.API, args.Gateway) + if err != nil { + return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) + } + } + + command := []string{"netstat -lutn 2>/dev/null | grep LISTEN"} + err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, command, true, gateway) + if err != nil { + return fmt.Errorf("command execution failed: %v", err) + } + + return nil +} From 0cb25093429d539d3a73662b3d57c65eaad5be6c Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Thu, 6 Aug 2015 23:56:26 +0200 Subject: [PATCH 21/36] Refactored 'rename' command (#80) --- pkg/cli/rename.go | 24 +++++++++++------------- pkg/commands/rename.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 pkg/commands/rename.go diff --git a/pkg/cli/rename.go b/pkg/cli/rename.go index dd7ca298b1..8aa6a6978e 100644 --- a/pkg/cli/rename.go +++ b/pkg/cli/rename.go @@ -5,9 +5,9 @@ package cli import ( - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdRename = &Command{ @@ -24,23 +24,21 @@ func init() { // Flags var renameHelp bool // -h, --help flag -func runRename(cmd *Command, args []string) { +func runRename(cmd *Command, rawArgs []string) { if renameHelp { cmd.PrintUsage() } - if len(args) != 2 { + if len(rawArgs) != 2 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - - var server api.ScalewayServerPatchDefinition - server.Name = &args[1] - - err := cmd.API.PatchServer(serverID, server) + args := commands.RenameArgs{ + Server: rawArgs[0], + NewName: rawArgs[1], + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunRename(ctx, args) if err != nil { - log.Fatalf("Cannot rename server: %v", err) - } else { - cmd.API.Cache.InsertServer(serverID, *server.Name) + logrus.Fatalf("Cannot execute 'rename': %v", err) } } diff --git a/pkg/commands/rename.go b/pkg/commands/rename.go new file mode 100644 index 0000000000..873b55702a --- /dev/null +++ b/pkg/commands/rename.go @@ -0,0 +1,33 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "log" + + "github.com/scaleway/scaleway-cli/pkg/api" +) + +// RenameArgs are flags for the `RunRename` function +type RenameArgs struct { + Server string + NewName string +} + +// RunRename is the handler for 'scw rename' +func RunRename(ctx CommandContext, args RenameArgs) error { + serverID := ctx.API.GetServerID(args.Server) + + var server api.ScalewayServerPatchDefinition + server.Name = &args.NewName + + err := ctx.API.PatchServer(serverID, server) + if err != nil { + log.Fatalf("Cannot rename server: %v", err) + } else { + ctx.API.Cache.InsertServer(serverID, *server.Name) + } + return nil +} From 7255efb846ffc16a8dff5ef32d7bca4323b42e29 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 00:00:37 +0200 Subject: [PATCH 22/36] Refactored 'restart' command (#80) --- pkg/cli/restart.go | 33 ++++++++++++--------------------- pkg/commands/restart.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 pkg/commands/restart.go diff --git a/pkg/cli/restart.go b/pkg/cli/restart.go index ce168eba8d..ba045b6fee 100644 --- a/pkg/cli/restart.go +++ b/pkg/cli/restart.go @@ -5,10 +5,8 @@ package cli import ( - "fmt" - "os" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdRestart = &Command{ @@ -25,28 +23,21 @@ func init() { // Flags var restartHelp bool // -h, --help flag -func runRestart(cmd *Command, args []string) { +func runRestart(cmd *Command, rawArgs []string) { if restartHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - hasError := false - for _, needle := range args { - server := cmd.API.GetServerID(needle) - err := cmd.API.PostServerAction(server, "reboot") - if err != nil { - if err.Error() != "server is being stopped or rebooted" { - log.Errorf("failed to restart server %s: %s", server, err) - hasError = true - } - } else { - fmt.Println(needle) - } - if hasError { - os.Exit(1) - } + args := commands.RestartArgs{ + Servers: rawArgs, + } + ctx := cmd.GetContext(rawArgs) + err := commands.RunRestart(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'restart': %v", err) } + } diff --git a/pkg/commands/restart.go b/pkg/commands/restart.go new file mode 100644 index 0000000000..c3b4b18cd3 --- /dev/null +++ b/pkg/commands/restart.go @@ -0,0 +1,37 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// RestartArgs are flags for the `RunRestart` function +type RestartArgs struct { + Servers []string +} + +// RunRestart is the handler for 'scw restart' +func RunRestart(ctx CommandContext, args RestartArgs) error { + hasError := false + for _, needle := range args.Servers { + server := ctx.API.GetServerID(needle) + err := ctx.API.PostServerAction(server, "reboot") + if err != nil { + if err.Error() != "server is being stopped or rebooted" { + logrus.Errorf("failed to restart server %s: %s", server, err) + hasError = true + } + } else { + fmt.Fprintln(ctx.Stdout, needle) + } + if hasError { + return fmt.Errorf("at least 1 server failed to restart") + } + } + return nil +} From 09b1e575531516a49ed0ad4853072ce065af13a4 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 00:09:08 +0200 Subject: [PATCH 23/36] Refactored 'rm' command (#80) --- pkg/cli/rm.go | 29 +++++++++++------------------ pkg/commands/rm.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 pkg/commands/rm.go diff --git a/pkg/cli/rm.go b/pkg/cli/rm.go index 54ca53b924..0a420614ce 100644 --- a/pkg/cli/rm.go +++ b/pkg/cli/rm.go @@ -5,10 +5,8 @@ package cli import ( - "fmt" - "os" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdRm = &Command{ @@ -30,26 +28,21 @@ func init() { // Flags var rmHelp bool // -h, --help flag -func runRm(cmd *Command, args []string) { +func runRm(cmd *Command, rawArgs []string) { if rmHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - hasError := false - for _, needle := range args { - server := cmd.API.GetServerID(needle) - err := cmd.API.DeleteServer(server) - if err != nil { - log.Errorf("failed to delete server %s: %s", server, err) - hasError = true - } else { - fmt.Println(needle) - } + args := commands.RmArgs{ + Servers: rawArgs, } - if hasError { - os.Exit(1) + ctx := cmd.GetContext(rawArgs) + err := commands.RunRm(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'rm': %v", err) } + } diff --git a/pkg/commands/rm.go b/pkg/commands/rm.go new file mode 100644 index 0000000000..a62a52f7af --- /dev/null +++ b/pkg/commands/rm.go @@ -0,0 +1,35 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// RmArgs are flags for the `RunRm` function +type RmArgs struct { + Servers []string +} + +// RunRm is the handler for 'scw rm' +func RunRm(ctx CommandContext, args RmArgs) error { + hasError := false + for _, needle := range args.Servers { + server := ctx.API.GetServerID(needle) + err := ctx.API.DeleteServer(server) + if err != nil { + logrus.Errorf("failed to delete server %s: %s", server, err) + hasError = true + } else { + fmt.Fprintln(ctx.Stdout, needle) + } + } + if hasError { + return fmt.Errorf("at least 1 server failed to be removed") + } + return nil +} From ca2ae82538c9a90f27778eb64862b860903f763f Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 10:44:19 +0200 Subject: [PATCH 24/36] Refactored 'top' command (#80) --- pkg/cli/top.go | 45 +++++++++------------------------------ pkg/commands/top.go | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 35 deletions(-) create mode 100644 pkg/commands/top.go diff --git a/pkg/cli/top.go b/pkg/cli/top.go index bc3c8832db..992e3c4114 100644 --- a/pkg/cli/top.go +++ b/pkg/cli/top.go @@ -5,15 +5,9 @@ package cli import ( - "fmt" - "os" - "os/exec" - "strings" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdTop = &Command{ @@ -32,40 +26,21 @@ func init() { var topHelp bool // -h, --help flag var topGateway string // -g, --gateway flag -func runTop(cmd *Command, args []string) { +func runTop(cmd *Command, rawArgs []string) { if topHelp { cmd.PrintUsage() } - if len(args) != 1 { + if len(rawArgs) != 1 { cmd.PrintShortUsage() } - serverID := cmd.API.GetServerID(args[0]) - command := "ps" - server, err := cmd.API.GetServer(serverID) - if err != nil { - log.Fatalf("Failed to get server information for %s: %v", serverID, err) - } - - // Resolve gateway - if topGateway == "" { - topGateway = os.Getenv("SCW_GATEWAY") - } - var gateway string - if topGateway == serverID || topGateway == args[0] { - gateway = "" - } else { - gateway, err = api.ResolveGateway(cmd.API, topGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", topGateway, err) - } + args := commands.TopArgs{ + Gateway: topGateway, + Server: rawArgs[0], } - - execCmd := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, nil, []string{command}, gateway) - log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) - out, err := exec.Command("ssh", execCmd...).CombinedOutput() - fmt.Printf("%s", out) + ctx := cmd.GetContext(rawArgs) + err := commands.RunTop(ctx, args) if err != nil { - log.Fatal(err) + logrus.Fatalf("Cannot execute 'top': %v", err) } } diff --git a/pkg/commands/top.go b/pkg/commands/top.go new file mode 100644 index 0000000000..7c9c9bd699 --- /dev/null +++ b/pkg/commands/top.go @@ -0,0 +1,51 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// TopArgs are flags for the `RunTop` function +type TopArgs struct { + Server string + Gateway string +} + +// RunTop is the handler for 'scw top' +func RunTop(ctx CommandContext, args TopArgs) error { + serverID := ctx.API.GetServerID(args.Server) + command := "ps" + server, err := ctx.API.GetServer(serverID) + if err != nil { + return fmt.Errorf("failed to get server information for %s: %v", serverID, err) + } + + // Resolve gateway + if args.Gateway == "" { + args.Gateway = ctx.Getenv("SCW_GATEWAY") + } + var gateway string + if args.Gateway == serverID || args.Gateway == args.Server { + gateway = "" + } else { + gateway, err = api.ResolveGateway(ctx.API, args.Gateway) + if err != nil { + return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) + } + } + + execCmd := utils.NewSSHExecCmd(server.PublicAddress.IP, server.PrivateIP, true, nil, []string{command}, gateway) + logrus.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) + out, err := exec.Command("ssh", execCmd...).CombinedOutput() + fmt.Printf("%s", out) + return err +} From 617ee4aaf07f14ffb9ab95e210f6fe2dc77131e7 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 10:55:42 +0200 Subject: [PATCH 25/36] Refactored 'rmi' command (#80) --- pkg/cli/rmi.go | 31 ++++++++++--------------------- pkg/commands/rmi.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 21 deletions(-) create mode 100644 pkg/commands/rmi.go diff --git a/pkg/cli/rmi.go b/pkg/cli/rmi.go index 6471539da7..2c7375ec92 100644 --- a/pkg/cli/rmi.go +++ b/pkg/cli/rmi.go @@ -5,10 +5,8 @@ package cli import ( - "fmt" - "os" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdRmi = &Command{ @@ -29,29 +27,20 @@ func init() { // Flags var rmiHelp bool // -h, --help flag -func runRmi(cmd *Command, args []string) { +func runRmi(cmd *Command, rawArgs []string) { if rmiHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - if len(args) == 0 { - log.Fatalf("usage: scw %s", cmd.UsageLine) - } - hasError := false - for _, needle := range args { - image := cmd.API.GetImageID(needle, true) - err := cmd.API.DeleteImage(image) - if err != nil { - log.Errorf("failed to delete image %s: %s", image, err) - hasError = true - } else { - fmt.Println(needle) - } + args := commands.RmiArgs{ + Images: rawArgs, } - if hasError { - os.Exit(1) + ctx := cmd.GetContext(rawArgs) + err := commands.RunRmi(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'rmi': %v", err) } } diff --git a/pkg/commands/rmi.go b/pkg/commands/rmi.go new file mode 100644 index 0000000000..0bd41db683 --- /dev/null +++ b/pkg/commands/rmi.go @@ -0,0 +1,35 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// RmiArgs are flags for the `RunRmi` function +type RmiArgs struct { + Images []string +} + +// RunRmi is the handler for 'scw rmi' +func RunRmi(ctx CommandContext, args RmiArgs) error { + hasError := false + for _, needle := range args.Images { + image := ctx.API.GetImageID(needle, true) + err := ctx.API.DeleteImage(image) + if err != nil { + logrus.Errorf("failed to delete image %s: %s", image, err) + hasError = true + } else { + fmt.Fprintln(ctx.Stdout, needle) + } + } + if hasError { + return fmt.Errorf("at least 1 image failed to be removed") + } + return nil +} From f11348ebaa0984a25b6a1513ba60348523f2250c Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 11:01:39 +0200 Subject: [PATCH 26/36] Refactored 'wait' command (#80) --- pkg/cli/wait.go | 28 ++++++++++------------------ pkg/commands/wait.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 pkg/commands/wait.go diff --git a/pkg/cli/wait.go b/pkg/cli/wait.go index 54b3a9724b..7086bf909d 100644 --- a/pkg/cli/wait.go +++ b/pkg/cli/wait.go @@ -5,11 +5,9 @@ package cli import ( - "os" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdWait = &Command{ @@ -26,26 +24,20 @@ func init() { // Flags var waitHelp bool // -h, --help flag -func runWait(cmd *Command, args []string) { +func runWait(cmd *Command, rawArgs []string) { if waitHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - hasError := false - for _, needle := range args { - serverIdentifier := cmd.API.GetServerID(needle) - - _, err := api.WaitForServerStopped(cmd.API, serverIdentifier) - if err != nil { - log.Errorf("failed to wait for server %s: %v", serverIdentifier, err) - hasError = true - } + args := commands.WaitArgs{ + Servers: rawArgs, } - - if hasError { - os.Exit(1) + ctx := cmd.GetContext(rawArgs) + err := commands.RunWait(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'wait': %v", err) } } diff --git a/pkg/commands/wait.go b/pkg/commands/wait.go new file mode 100644 index 0000000000..e178aecf65 --- /dev/null +++ b/pkg/commands/wait.go @@ -0,0 +1,36 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// WaitArgs are flags for the `RunWait` function +type WaitArgs struct { + Servers []string +} + +// RunWait is the handler for 'scw wait' +func RunWait(ctx CommandContext, args WaitArgs) error { + hasError := false + for _, needle := range args.Servers { + serverIdentifier := ctx.API.GetServerID(needle) + + _, err := api.WaitForServerStopped(ctx.API, serverIdentifier) + if err != nil { + logrus.Errorf("failed to wait for server %s: %v", serverIdentifier, err) + hasError = true + } + } + + if hasError { + return fmt.Errorf("at least 1 server failed to be stopped") + } + return nil +} From b1429dcb7b66f9a07c622eb3d5b673a390250506 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 11:13:00 +0200 Subject: [PATCH 27/36] Refactored 'run' command (#80) --- pkg/cli/run.go | 91 ++++++++++---------------------------- pkg/commands/run.go | 103 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 69 deletions(-) create mode 100644 pkg/commands/run.go diff --git a/pkg/cli/run.go b/pkg/cli/run.go index e5ba118798..2e1f382d05 100644 --- a/pkg/cli/run.go +++ b/pkg/cli/run.go @@ -5,13 +5,12 @@ package cli import ( - "fmt" - "os" + "strings" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - api "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdRun = &Command{ @@ -52,85 +51,39 @@ var runAttachFlag bool // -a, --attach flag var runDetachFlag bool // -d, --detach flag var runGateway string // -g, --gateway flag -func runRun(cmd *Command, args []string) { +func runRun(cmd *Command, rawArgs []string) { if runHelpFlag { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - if runAttachFlag && len(args) > 1 { + if runAttachFlag && len(rawArgs) > 1 { log.Fatalf("Conflicting options: -a and COMMAND") } if runAttachFlag && runDetachFlag { log.Fatalf("Conflicting options: -a and -d") } - if runDetachFlag && len(args) > 1 { + if runDetachFlag && len(rawArgs) > 1 { log.Fatalf("Conflicting options: -d and COMMAND") } - if runGateway == "" { - runGateway = os.Getenv("SCW_GATEWAY") + args := commands.RunArgs{ + Attach: runAttachFlag, + Bootscript: runCreateBootscript, + Command: rawArgs[1:], + Detach: runDetachFlag, + Gateway: runGateway, + Image: rawArgs[0], + Name: runCreateName, + Tags: strings.Split(runCreateEnv, " "), + Volumes: strings.Split(runCreateVolume, " "), + // FIXME: DynamicIPRequired + // FIXME: Timeout } - - // create IMAGE - log.Info("Server creation ...") - dynamicIPRequired := runGateway == "" - serverID, err := api.CreateServer(cmd.API, args[0], runCreateName, runCreateBootscript, runCreateEnv, runCreateVolume, dynamicIPRequired) + ctx := cmd.GetContext(rawArgs) + err := commands.RunRun(ctx, args) if err != nil { - log.Fatalf("Failed to create server: %v", err) - } - log.Infof("Server created: %s", serverID) - - // start SERVER - log.Info("Server start requested ...") - err = api.StartServer(cmd.API, serverID, false) - if err != nil { - log.Fatalf("Failed to start server %s: %v", serverID, err) - } - log.Info("Server is starting, this may take up to a minute ...") - - if runDetachFlag { - fmt.Println(serverID) - return - } - - if runAttachFlag { - // Attach to server serial - log.Info("Attaching to server console ...") - err = utils.AttachToSerial(serverID, cmd.API.Token, true) - if err != nil { - log.Fatalf("Cannot attach to server serial: %v", err) - } - } else { - // Resolve gateway - gateway, err := api.ResolveGateway(cmd.API, runGateway) - if err != nil { - log.Fatalf("Cannot resolve Gateway '%s': %v", runGateway, err) - } - - // waiting for server to be ready - log.Debug("Waiting for server to be ready") - // We wait for 30 seconds, which is the minimal amount of time needed by a server to boot - server, err := api.WaitForServerReady(cmd.API, serverID, gateway) - if err != nil { - log.Fatalf("Cannot get access to server %s: %v", serverID, err) - } - log.Debugf("SSH server is available: %s:22", server.PublicAddress.IP) - log.Info("Server is ready !") - - // exec -w SERVER COMMAND ARGS... - if len(args) < 2 { - log.Info("Connecting to server ...") - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway) - } else { - log.Infof("Executing command: %s ...", args[1:]) - err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args[1:], false, gateway) - } - if err != nil { - log.Infof("Command execution failed: %v", err) - os.Exit(1) - } - log.Info("Command successfuly executed") + logrus.Fatalf("Cannot execute 'run': %v", err) } } diff --git a/pkg/commands/run.go b/pkg/commands/run.go new file mode 100644 index 0000000000..dfbdfb1d78 --- /dev/null +++ b/pkg/commands/run.go @@ -0,0 +1,103 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "os" + "strings" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// RunArgs are flags for the `RunRun` function +type RunArgs struct { + Attach bool + Bootscript string + Command []string + Detach bool + Gateway string + Image string + Name string + Tags []string + Volumes []string + // DynamicIPRequired + // Timeout +} + +// RunRun is the handler for 'scw run' +func RunRun(ctx CommandContext, args RunArgs) error { + if args.Gateway == "" { + args.Gateway = ctx.Getenv("SCW_GATEWAY") + } + + env := strings.Join(args.Tags, " ") + volume := strings.Join(args.Volumes, " ") + + // create IMAGE + logrus.Info("Server creation ...") + dynamicIPRequired := args.Gateway == "" + serverID, err := api.CreateServer(ctx.API, args.Image, args.Name, args.Bootscript, env, volume, dynamicIPRequired) + if err != nil { + return fmt.Errorf("failed to create server: %v", err) + } + logrus.Infof("Server created: %s", serverID) + + // start SERVER + logrus.Info("Server start requested ...") + err = api.StartServer(ctx.API, serverID, false) + if err != nil { + return fmt.Errorf("failed to start server %s: %v", serverID, err) + } + logrus.Info("Server is starting, this may take up to a minute ...") + + if args.Detach { + fmt.Fprintln(ctx.Stdout, serverID) + return nil + } + + if args.Attach { + // Attach to server serial + logrus.Info("Attaching to server console ...") + err = utils.AttachToSerial(serverID, ctx.API.Token, true) + if err != nil { + return fmt.Errorf("cannot attach to server serial: %v", err) + } + } else { + // Resolve gateway + gateway, err := api.ResolveGateway(ctx.API, args.Gateway) + if err != nil { + return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) + } + + // waiting for server to be ready + logrus.Debug("Waiting for server to be ready") + // We wait for 30 seconds, which is the minimal amount of time needed by a server to boot + server, err := api.WaitForServerReady(ctx.API, serverID, gateway) + if err != nil { + return fmt.Errorf("cannot get access to server %s: %v", serverID, err) + } + logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP) + logrus.Info("Server is ready !") + + // exec -w SERVER COMMAND ARGS... + if len(args.Command) < 1 { + logrus.Info("Connecting to server ...") + err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway) + } else { + logrus.Infof("Executing command: %s ...", args.Command) + err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway) + } + if err != nil { + logrus.Infof("Command execution failed: %v", err) + // FIXME: create a new error type for silent exiting + os.Exit(1) + } + logrus.Info("Command successfuly executed") + } + return nil +} From cac92ab89ce11bbfe7a7b943f3f31ed550f9e8b5 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 11:24:40 +0200 Subject: [PATCH 28/36] Refactored 'tag' command (#80) --- pkg/cli/tag.go | 23 ++++++++++------------- pkg/commands/tag.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 pkg/commands/tag.go diff --git a/pkg/cli/tag.go b/pkg/cli/tag.go index 8b730d9e4b..3c655694c9 100644 --- a/pkg/cli/tag.go +++ b/pkg/cli/tag.go @@ -5,9 +5,8 @@ package cli import ( - "fmt" - - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdTag = &Command{ @@ -24,23 +23,21 @@ func init() { // Flags var tagHelp bool // -h, --help flag -func runTag(cmd *Command, args []string) { +func runTag(cmd *Command, rawArgs []string) { if tagHelp { cmd.PrintUsage() } - if len(args) != 2 { + if len(rawArgs) != 2 { cmd.PrintShortUsage() } - snapshotID := cmd.API.GetSnapshotID(args[0]) - snapshot, err := cmd.API.GetSnapshot(snapshotID) - if err != nil { - log.Fatalf("Cannot fetch snapshot: %v", err) + args := commands.TagArgs{ + Snapshot: rawArgs[0], + Name: rawArgs[1], } - - image, err := cmd.API.PostImage(snapshot.Identifier, args[1]) + ctx := cmd.GetContext(rawArgs) + err := commands.RunTag(ctx, args) if err != nil { - log.Fatalf("Cannot create image: %v", err) + logrus.Fatalf("Cannot execute 'tag': %v", err) } - fmt.Println(image) } diff --git a/pkg/commands/tag.go b/pkg/commands/tag.go new file mode 100644 index 0000000000..d381a7533a --- /dev/null +++ b/pkg/commands/tag.go @@ -0,0 +1,29 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import "fmt" + +// TagArgs are flags for the `RunTag` function +type TagArgs struct { + Snapshot string + Name string +} + +// RunTag is the handler for 'scw tag' +func RunTag(ctx CommandContext, args TagArgs) error { + snapshotID := ctx.API.GetSnapshotID(args.Snapshot) + snapshot, err := ctx.API.GetSnapshot(snapshotID) + if err != nil { + return fmt.Errorf("cannot fetch snapshot: %v", err) + } + + image, err := ctx.API.PostImage(snapshot.Identifier, args.Name) + if err != nil { + return fmt.Errorf("cannot create image: %v", err) + } + fmt.Fprintln(ctx.Stdout, image) + return nil +} From fd6ad5bfb5a8a8f5e61823cd217dc079717ff222 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 11:32:47 +0200 Subject: [PATCH 29/36] Refactored 'search' command (#80) --- pkg/cli/search.go | 75 +++++----------------------------- pkg/commands/search.go | 92 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 65 deletions(-) create mode 100644 pkg/commands/search.go diff --git a/pkg/cli/search.go b/pkg/cli/search.go index 97eb621716..af832965c6 100644 --- a/pkg/cli/search.go +++ b/pkg/cli/search.go @@ -5,14 +5,9 @@ package cli import ( - "fmt" - "os" - "text/tabwriter" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" - "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdSearch = &Command{ @@ -31,71 +26,21 @@ func init() { var searchNoTrunc bool // --no-trunc flag var searchHelp bool // -h, --help flag -func runSearch(cmd *Command, args []string) { +func runSearch(cmd *Command, rawArgs []string) { if searchHelp { cmd.PrintUsage() } - if len(args) != 1 { + if len(rawArgs) != 1 { cmd.PrintShortUsage() } - w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") - - var entries = []api.ScalewayImageInterface{} - - images, err := cmd.API.GetImages() - if err != nil { - log.Fatalf("unable to fetch images from the Scaleway API: %v", err) + args := commands.SearchArgs{ + Term: rawArgs[0], + NoTrunc: searchNoTrunc, } - for _, val := range *images { - entries = append(entries, api.ScalewayImageInterface{ - Type: "image", - Name: val.Name, - Public: val.Public, - }) - } - - snapshots, err := cmd.API.GetSnapshots() + ctx := cmd.GetContext(rawArgs) + err := commands.RunSearch(ctx, args) if err != nil { - log.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) - } - for _, val := range *snapshots { - entries = append(entries, api.ScalewayImageInterface{ - Type: "snapshot", - Name: val.Name, - Public: false, - }) - } - - for _, image := range entries { - // name field - name := utils.TruncIf(utils.Wordify(image.Name), 45, !searchNoTrunc) - - // description field - var description string - switch image.Type { - case "image": - if image.Public { - description = "public image" - } else { - description = "user image" - } - - case "snapshot": - description = "user snapshot" - } - description = utils.TruncIf(utils.Wordify(description), 45, !searchNoTrunc) - - // official field - var official string - if image.Public { - official = "[OK]" - } else { - official = "" - } - - fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\n", name, description, 0, official, "") + logrus.Fatalf("Cannot execute 'search': %v", err) } } diff --git a/pkg/commands/search.go b/pkg/commands/search.go new file mode 100644 index 0000000000..60c65bd946 --- /dev/null +++ b/pkg/commands/search.go @@ -0,0 +1,92 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "strings" + "text/tabwriter" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/renstrom/fuzzysearch/fuzzy" +) + +// SearchArgs are flags for the `RunSearch` function +type SearchArgs struct { + Term string + NoTrunc bool +} + +// RunSearch is the handler for 'scw search' +func RunSearch(ctx CommandContext, args SearchArgs) error { + // FIXME: parallelize API calls + + term := strings.ToLower(args.Term) + w := tabwriter.NewWriter(ctx.Stdout, 10, 1, 3, ' ', 0) + defer w.Flush() + fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") + + var entries = []api.ScalewayImageInterface{} + + images, err := ctx.API.GetImages() + if err != nil { + return fmt.Errorf("unable to fetch images from the Scaleway API: %v", err) + } + for _, val := range *images { + if fuzzy.Match(term, strings.ToLower(val.Name)) { + entries = append(entries, api.ScalewayImageInterface{ + Type: "image", + Name: val.Name, + Public: val.Public, + }) + } + } + + snapshots, err := ctx.API.GetSnapshots() + if err != nil { + return fmt.Errorf("unable to fetch snapshots from the Scaleway API: %v", err) + } + for _, val := range *snapshots { + if fuzzy.Match(term, strings.ToLower(val.Name)) { + entries = append(entries, api.ScalewayImageInterface{ + Type: "snapshot", + Name: val.Name, + Public: false, + }) + } + } + + for _, image := range entries { + // name field + name := utils.TruncIf(utils.Wordify(image.Name), 45, !args.NoTrunc) + + // description field + var description string + switch image.Type { + case "image": + if image.Public { + description = "public image" + } else { + description = "user image" + } + + case "snapshot": + description = "user snapshot" + } + description = utils.TruncIf(utils.Wordify(description), 45, !args.NoTrunc) + + // official field + var official string + if image.Public { + official = "[OK]" + } else { + official = "" + } + + fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\n", name, description, 0, official, "") + } + return nil +} From 46ba016a855918b8abaf3be009053ab7f2ac7ca7 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 11:38:36 +0200 Subject: [PATCH 30/36] Refactored 'start' command (#80) --- pkg/cli/start.go | 52 +++++++++----------------------------- pkg/commands/start.go | 59 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 40 deletions(-) create mode 100644 pkg/commands/start.go diff --git a/pkg/cli/start.go b/pkg/cli/start.go index b07c37e1c2..ddb536ddf6 100644 --- a/pkg/cli/start.go +++ b/pkg/cli/start.go @@ -5,13 +5,9 @@ package cli import ( - "fmt" - "os" - "time" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdStart = &Command{ @@ -32,46 +28,22 @@ var startW bool // -w flag var startTimeout float64 // -T flag var startHelp bool // -h, --help flag -func runStart(cmd *Command, args []string) { +func runStart(cmd *Command, rawArgs []string) { if startHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - hasError := false - errChan := make(chan error) - successChan := make(chan bool) - remainingItems := len(args) - - for i := range args { - needle := args[i] - go api.StartServerOnce(cmd.API, needle, startW, successChan, errChan) - } - - if startTimeout > 0 { - go func() { - time.Sleep(time.Duration(startTimeout*1000) * time.Millisecond) - log.Fatalf("Operation timed out") - }() - } - - for { - select { - case _ = <-successChan: - remainingItems-- - case err := <-errChan: - log.Errorf(fmt.Sprintf("%s", err)) - remainingItems-- - hasError = true - } - - if remainingItems == 0 { - break - } + args := commands.StartArgs{ + Servers: rawArgs, + Timeout: startTimeout, + Wait: startW, } - if hasError { - os.Exit(1) + ctx := cmd.GetContext(rawArgs) + err := commands.RunStart(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'start': %v", err) } } diff --git a/pkg/commands/start.go b/pkg/commands/start.go new file mode 100644 index 0000000000..0f37b91c25 --- /dev/null +++ b/pkg/commands/start.go @@ -0,0 +1,59 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "time" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// StartArgs are flags for the `RunStart` function +type StartArgs struct { + Servers []string + Wait bool + Timeout float64 +} + +// RunStart is the handler for 'scw start' +func RunStart(ctx CommandContext, args StartArgs) error { + hasError := false + errChan := make(chan error) + successChan := make(chan bool) + remainingItems := len(args.Servers) + + for _, needle := range args.Servers { + go api.StartServerOnce(ctx.API, needle, args.Wait, successChan, errChan) + } + + if args.Timeout > 0 { + go func() { + time.Sleep(time.Duration(args.Timeout*1000) * time.Millisecond) + // FIXME: avoid use of fatalf + logrus.Fatalf("Operation timed out") + }() + } + + for { + select { + case _ = <-successChan: + remainingItems-- + case err := <-errChan: + logrus.Errorf(fmt.Sprintf("%s", err)) + remainingItems-- + hasError = true + } + + if remainingItems == 0 { + break + } + } + if hasError { + return fmt.Errorf("at least 1 server failed to start") + } + return nil +} From 379d0ceadb0911f45ff2e0718ebb083b59ac3a2c Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 11:45:50 +0200 Subject: [PATCH 31/36] Updated CHANGELOG --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 965332aa5b..dfdad340db 100644 --- a/README.md +++ b/README.md @@ -1050,6 +1050,7 @@ $ scw inspect myserver | jq '.[0].public_ip.address' #### Fixes +* `scw search TERM` was not restricting results based on `TERM` * Bumped dependencies * Hiding more sensitive data ([#77](https://github.com/scaleway/scaleway-cli/issues/77)) * Fixed "Run in Docker" usage ([#90](https://github.com/scaleway/scaleway-cli/issues/90)) From 317448ab6f4301a0028c8fe5f04a6351ef45042b Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 12:45:28 +0200 Subject: [PATCH 32/36] Refactored 'stop' command (#80) --- pkg/cli/stop.go | 52 +++++++++----------------------------- pkg/commands/stop.go | 59 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 40 deletions(-) create mode 100644 pkg/commands/stop.go diff --git a/pkg/cli/stop.go b/pkg/cli/stop.go index a75cfa97f6..226cdc8cd5 100644 --- a/pkg/cli/stop.go +++ b/pkg/cli/stop.go @@ -5,13 +5,9 @@ package cli import ( - "fmt" - "os" - "time" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - log "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" - - "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/pkg/commands" ) var cmdStop = &Command{ @@ -40,46 +36,22 @@ var stopT bool // -t flag var stopHelp bool // -h, --help flag var stopW bool // -w, --wait flat -// FIXME: parallelize stop when stopping multiple servers -func runStop(cmd *Command, args []string) { +func runStop(cmd *Command, rawArgs []string) { if stopHelp { cmd.PrintUsage() } - if len(args) < 1 { + if len(rawArgs) < 1 { cmd.PrintShortUsage() } - hasError := false - for _, needle := range args { - serverID := cmd.API.GetServerID(needle) - action := "poweroff" - if stopT { - action = "terminate" - } - err := cmd.API.PostServerAction(serverID, action) - if err != nil { - if err.Error() != "server should be running" && err.Error() != "server is being stopped or rebooted" { - log.Warningf("failed to stop server %s: %s", serverID, err) - hasError = true - } - } else { - if stopW { - // We wait for 10 seconds which is the minimal amount of time needed for a server to stop - time.Sleep(10 * time.Second) - _, err = api.WaitForServerStopped(cmd.API, serverID) - if err != nil { - log.Errorf("failed to wait for server %s: %v", serverID, err) - hasError = true - } - } - if stopT { - cmd.API.Cache.RemoveServer(serverID) - } - fmt.Println(needle) - } + args := commands.StopArgs{ + Terminate: stopT, + Wait: stopW, + Servers: rawArgs, } - - if hasError { - os.Exit(1) + ctx := cmd.GetContext(rawArgs) + err := commands.RunStop(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'stop': %v", err) } } diff --git a/pkg/commands/stop.go b/pkg/commands/stop.go new file mode 100644 index 0000000000..1369432c4d --- /dev/null +++ b/pkg/commands/stop.go @@ -0,0 +1,59 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "time" + + "github.com/scaleway/scaleway-cli/pkg/api" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" +) + +// StopArgs are flags for the `RunStop` function +type StopArgs struct { + Terminate bool + Wait bool + Servers []string +} + +// RunStop is the handler for 'scw stop' +func RunStop(ctx CommandContext, args StopArgs) error { + // FIXME: parallelize stop when stopping multiple servers + hasError := false + for _, needle := range args.Servers { + serverID := ctx.API.GetServerID(needle) + action := "poweroff" + if args.Terminate { + action = "terminate" + } + err := ctx.API.PostServerAction(serverID, action) + if err != nil { + if err.Error() != "server should be running" && err.Error() != "server is being stopped or rebooted" { + logrus.Warningf("failed to stop server %s: %s", serverID, err) + hasError = true + } + } else { + if args.Wait { + // We wait for 10 seconds which is the minimal amount of time needed for a server to stop + time.Sleep(10 * time.Second) + _, err = api.WaitForServerStopped(ctx.API, serverID) + if err != nil { + logrus.Errorf("failed to wait for server %s: %v", serverID, err) + hasError = true + } + } + if args.Terminate { + ctx.API.Cache.RemoveServer(serverID) + } + fmt.Fprintln(ctx.Stdout, needle) + } + } + + if hasError { + return fmt.Errorf("at least 1 server failed to be stopped") + } + return nil +} From 09e76280ce0d207c42a0736a665a70f90b6e6e2e Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 12:49:43 +0200 Subject: [PATCH 33/36] Refactored 'version' command (#80) --- pkg/cli/version.go | 21 ++++++++++----------- pkg/commands/version.go | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 pkg/commands/version.go diff --git a/pkg/cli/version.go b/pkg/cli/version.go index fbcbcef09b..a521710915 100644 --- a/pkg/cli/version.go +++ b/pkg/cli/version.go @@ -5,10 +5,8 @@ package cli import ( - "fmt" - "runtime" - - "github.com/scaleway/scaleway-cli/pkg/scwversion" + "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdVersion = &Command{ @@ -25,17 +23,18 @@ func init() { // Flags var versionHelp bool // -h, --help flag -func runVersion(cmd *Command, args []string) { +func runVersion(cmd *Command, rawArgs []string) { if versionHelp { cmd.PrintUsage() } - if len(args) != 0 { + if len(rawArgs) != 0 { cmd.PrintShortUsage() } - fmt.Printf("Client version: %s\n", scwversion.VERSION) - fmt.Printf("Go version (client): %s\n", runtime.Version()) - fmt.Printf("Git commit (client): %s\n", scwversion.GITCOMMIT) - fmt.Printf("OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH) - // FIXME: API version information + args := commands.VersionArgs{} + ctx := cmd.GetContext(rawArgs) + err := commands.RunVersion(ctx, args) + if err != nil { + logrus.Fatalf("Cannot execute 'version': %v", err) + } } diff --git a/pkg/commands/version.go b/pkg/commands/version.go new file mode 100644 index 0000000000..7395a83a6f --- /dev/null +++ b/pkg/commands/version.go @@ -0,0 +1,26 @@ +// Copyright (C) 2015 Scaleway. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE.md file. + +package commands + +import ( + "fmt" + "runtime" + + "github.com/scaleway/scaleway-cli/pkg/scwversion" +) + +// VersionArgs are flags for the `RunVersion` function +type VersionArgs struct{} + +// RunVersion is the handler for 'scw version' +func RunVersion(ctx CommandContext, args VersionArgs) error { + fmt.Fprintf(ctx.Stdout, "Client version: %s\n", scwversion.VERSION) + fmt.Fprintf(ctx.Stdout, "Go version (client): %s\n", runtime.Version()) + fmt.Fprintf(ctx.Stdout, "Git commit (client): %s\n", scwversion.GITCOMMIT) + fmt.Fprintf(ctx.Stdout, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH) + // FIXME: API version information + + return nil +} From 2b45f0aee3db3e92df9b58c5b0c46395fd4046c9 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 12:50:57 +0200 Subject: [PATCH 34/36] Updated CHANGELOG --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dfdad340db..0269a5316a 100644 --- a/README.md +++ b/README.md @@ -1050,6 +1050,7 @@ $ scw inspect myserver | jq '.[0].public_ip.address' #### Fixes +* Global refactor to improve Golang library usage, allow chaining of commands and ease the writing of unit tests ([#80](https://github.com/scaleway/scaleway-cli/issues/80)) * `scw search TERM` was not restricting results based on `TERM` * Bumped dependencies * Hiding more sensitive data ([#77](https://github.com/scaleway/scaleway-cli/issues/77)) From a1f006271fa32fc66d928a327191d4209474b7b5 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 13:04:02 +0200 Subject: [PATCH 35/36] Switching to logrus --- pkg/cli/command.go | 4 ++-- pkg/cli/commit.go | 5 ++--- pkg/commands/images.go | 18 ++++++++++-------- pkg/commands/login.go | 4 ++-- pkg/commands/rename.go | 4 ++-- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pkg/cli/command.go b/pkg/cli/command.go index 97b4959520..147075dd67 100644 --- a/pkg/cli/command.go +++ b/pkg/cli/command.go @@ -8,11 +8,11 @@ package cli import ( "bytes" "fmt" - "log" "os" "strings" "text/template" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" flag "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/mflag" "github.com/scaleway/scaleway-cli/pkg/api" @@ -71,7 +71,7 @@ func (c *Command) Name() string { func (c *Command) PrintUsage() { helpMessage, err := commandHelpMessage(c) if err != nil { - log.Fatalf("%v", err) + logrus.Fatalf("%v", err) } fmt.Fprintf(os.Stderr, "%s\n", helpMessage) os.Exit(1) diff --git a/pkg/cli/commit.go b/pkg/cli/commit.go index 16d036e326..e946feaba2 100644 --- a/pkg/cli/commit.go +++ b/pkg/cli/commit.go @@ -5,9 +5,8 @@ package cli import ( - "log" - "github.com/scaleway/scaleway-cli/pkg/commands" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" ) var cmdCommit = &Command{ @@ -50,6 +49,6 @@ func cmdExecCommit(cmd *Command, rawArgs []string) { ctx := cmd.GetContext(rawArgs) err := commands.RunCommit(ctx, args) if err != nil { - log.Fatalf("Cannot execute 'commit': %v", err) + logrus.Fatalf("Cannot execute 'commit': %v", err) } } diff --git a/pkg/commands/images.go b/pkg/commands/images.go index c23302894c..2be42e7858 100644 --- a/pkg/commands/images.go +++ b/pkg/commands/images.go @@ -6,7 +6,6 @@ package commands import ( "fmt" - "log" "sort" "sync" "text/tabwriter" @@ -14,6 +13,7 @@ import ( "github.com/scaleway/scaleway-cli/pkg/api" "github.com/scaleway/scaleway-cli/pkg/utils" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units" ) @@ -30,17 +30,19 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { chEntries := make(chan api.ScalewayImageInterface) var entries = []api.ScalewayImageInterface{} + // FIXME: remove log.Fatalf in routines + wg.Add(1) go func() { defer wg.Done() images, err := ctx.API.GetImages() if err != nil { - log.Fatalf("unable to fetch images from the Scaleway API: %v", err) + logrus.Fatalf("unable to fetch images from the Scaleway API: %v", err) } for _, val := range *images { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { - log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ Type: "image", @@ -60,12 +62,12 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { defer wg.Done() snapshots, err := ctx.API.GetSnapshots() if err != nil { - log.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) + logrus.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) } for _, val := range *snapshots { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { - log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ Type: "snapshot", @@ -84,7 +86,7 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { defer wg.Done() bootscripts, err := ctx.API.GetBootscripts() if err != nil { - log.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err) + logrus.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err) } for _, val := range *bootscripts { chEntries <- api.ScalewayImageInterface{ @@ -102,12 +104,12 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { defer wg.Done() volumes, err := ctx.API.GetVolumes() if err != nil { - log.Fatalf("unable to fetch volumes from the Scaleway API: %v", err) + logrus.Fatalf("unable to fetch volumes from the Scaleway API: %v", err) } for _, val := range *volumes { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { - log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ Type: "volume", diff --git a/pkg/commands/login.go b/pkg/commands/login.go index a2c1968ab4..3a981e6c55 100644 --- a/pkg/commands/login.go +++ b/pkg/commands/login.go @@ -8,10 +8,10 @@ import ( "bufio" "encoding/json" "fmt" - "log" "os" "strings" + "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" "github.com/scaleway/scaleway-cli/vendor/golang.org/x/crypto/ssh/terminal" "github.com/scaleway/scaleway-cli/pkg/api" @@ -74,7 +74,7 @@ func promptUser(prompt string, output *string, echo bool) { if !echo { b, err := terminal.ReadPassword(int(os.Stdin.Fd())) if err != nil { - log.Fatalf("Unable to prompt for password: %s", err) + logrus.Fatalf("Unable to prompt for password: %s", err) } *output = string(b) fmt.Fprintf(os.Stdout, "\n") diff --git a/pkg/commands/rename.go b/pkg/commands/rename.go index 873b55702a..dcd54df2ae 100644 --- a/pkg/commands/rename.go +++ b/pkg/commands/rename.go @@ -5,7 +5,7 @@ package commands import ( - "log" + "fmt" "github.com/scaleway/scaleway-cli/pkg/api" ) @@ -25,7 +25,7 @@ func RunRename(ctx CommandContext, args RenameArgs) error { err := ctx.API.PatchServer(serverID, server) if err != nil { - log.Fatalf("Cannot rename server: %v", err) + return fmt.Errorf("cannot rename server: %v", err) } else { ctx.API.Cache.InsertServer(serverID, *server.Name) } From 6893505bc84063595abc02252bc473ea07ebbdb1 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Fri, 7 Aug 2015 13:14:49 +0200 Subject: [PATCH 36/36] Using streams from context, removed os.Exits --- pkg/commands/cp.go | 39 ++++++++++++++++++++------------------- pkg/commands/inspect.go | 5 ++--- pkg/commands/kill.go | 7 +++---- pkg/commands/run.go | 5 +---- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/pkg/commands/cp.go b/pkg/commands/cp.go index 5b0f9b6e14..4af6194829 100644 --- a/pkg/commands/cp.go +++ b/pkg/commands/cp.go @@ -30,12 +30,12 @@ func RunCp(ctx CommandContext, args CpArgs) error { return fmt.Errorf("bad usage, see 'scw help cp'.") } - sourceStream, err := TarFromSource(ctx.API, args.Source, args.Gateway) + sourceStream, err := TarFromSource(ctx, args.Source, args.Gateway) if err != nil { return fmt.Errorf("cannot tar from source '%s': %v", args.Source, err) } - err = UntarToDest(ctx.API, sourceStream, args.Destination, args.Gateway) + err = UntarToDest(ctx, sourceStream, args.Destination, args.Gateway) if err != nil { return fmt.Errorf("cannot untar to destination '%s': %v", args.Destination, err) } @@ -43,7 +43,7 @@ func RunCp(ctx CommandContext, args CpArgs) error { } // TarFromSource creates a stream buffer with the tarballed content of the user source -func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (*io.ReadCloser, error) { +func TarFromSource(ctx CommandContext, source string, gateway string) (*io.ReadCloser, error) { var tarOutputStream io.ReadCloser // source is a server address + path (scp-like uri) @@ -54,9 +54,9 @@ func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (* return nil, fmt.Errorf("invalid source uri, see 'scw cp -h' for usage") } - serverID := apiClient.GetServerID(serverParts[0]) + serverID := ctx.API.GetServerID(serverParts[0]) - server, err := apiClient.GetServer(serverID) + server, err := ctx.API.GetServer(serverID) if err != nil { return nil, err } @@ -68,7 +68,7 @@ func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (* // it streams a tarball raw content remoteCommand := []string{"tar"} remoteCommand = append(remoteCommand, "-C", dir) - if os.Getenv("DEBUG") == "1" { + if ctx.Getenv("DEBUG") == "1" { remoteCommand = append(remoteCommand, "-v") } remoteCommand = append(remoteCommand, "-cf", "-") @@ -76,13 +76,13 @@ func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (* // Resolve gateway if gateway == "" { - gateway = os.Getenv("SCW_GATEWAY") + gateway = ctx.Getenv("SCW_GATEWAY") } var gateway string if gateway == serverID || gateway == serverParts[0] { gateway = "" } else { - gateway, err = api.ResolveGateway(apiClient, gateway) + gateway, err = api.ResolveGateway(ctx.API, gateway) if err != nil { return nil, fmt.Errorf("cannot resolve Gateway '%s': %v", gateway, err) } @@ -103,7 +103,7 @@ func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (* return nil, err } defer tarErrorStream.Close() - io.Copy(os.Stderr, tarErrorStream) + io.Copy(ctx.Stderr, tarErrorStream) err = spawnSrc.Start() if err != nil { @@ -117,6 +117,7 @@ func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (* // source is stdin if source == "-" { logrus.Debugf("Streaming tarball from stdin") + // FIXME: should be ctx.Stdin tarOutputStream = os.Stdin return &tarOutputStream, nil } @@ -146,7 +147,7 @@ func TarFromSource(apiClient *api.ScalewayAPI, source string, gateway string) (* } // UntarToDest writes to user destination the streamed tarball in input -func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destination string, gateway string) error { +func UntarToDest(ctx CommandContext, sourceStream *io.ReadCloser, destination string, gateway string) error { // destination is a server address + path (scp-like uri) if strings.Index(destination, ":") > -1 { logrus.Debugf("Streaming using ssh and untaring remotely") @@ -155,9 +156,9 @@ func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destin return fmt.Errorf("invalid destination uri, see 'scw cp -h' for usage") } - serverID := apiClient.GetServerID(serverParts[0]) + serverID := ctx.API.GetServerID(serverParts[0]) - server, err := apiClient.GetServer(serverID) + server, err := ctx.API.GetServer(serverID) if err != nil { return err } @@ -166,20 +167,20 @@ func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destin // it streams a tarball raw content remoteCommand := []string{"tar"} remoteCommand = append(remoteCommand, "-C", serverParts[1]) - if os.Getenv("DEBUG") == "1" { + if ctx.Getenv("DEBUG") == "1" { remoteCommand = append(remoteCommand, "-v") } remoteCommand = append(remoteCommand, "-xf", "-") // Resolve gateway if gateway == "" { - gateway = os.Getenv("SCW_GATEWAY") + gateway = ctx.Getenv("SCW_GATEWAY") } var gateway string if gateway == serverID || gateway == serverParts[0] { gateway = "" } else { - gateway, err = api.ResolveGateway(apiClient, gateway) + gateway, err = api.ResolveGateway(ctx.API, gateway) if err != nil { return fmt.Errorf("cannot resolve Gateway '%s': %v", gateway, err) } @@ -196,8 +197,8 @@ func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destin } defer untarInputStream.Close() - // spawnDst.Stderr = os.Stderr - // spawnDst.Stdout = os.Stdout + // spawnDst.Stderr = ctx.Stderr + // spawnDst.Stdout = ctx.Stdout err = spawnDst.Start() if err != nil { @@ -210,8 +211,8 @@ func UntarToDest(apiClient *api.ScalewayAPI, sourceStream *io.ReadCloser, destin // destination is stdout if destination == "-" { // stdout - logrus.Debugf("Writing sourceStream(%v) to os.Stdout(%v)", sourceStream, os.Stdout) - _, err := io.Copy(os.Stdout, *sourceStream) + logrus.Debugf("Writing sourceStream(%v) to ctx.Stdout(%v)", sourceStream, ctx.Stdout) + _, err := io.Copy(ctx.Stdout, *sourceStream) return err } diff --git a/pkg/commands/inspect.go b/pkg/commands/inspect.go index ce335d8060..61a45a1eac 100644 --- a/pkg/commands/inspect.go +++ b/pkg/commands/inspect.go @@ -7,7 +7,6 @@ package commands import ( "encoding/json" "fmt" - "os" "text/template" "github.com/scaleway/scaleway-cli/pkg/api" @@ -98,7 +97,7 @@ func RunInspect(ctx CommandContext, args InspectArgs) error { res += "]" if args.Format == "" { - if os.Getenv("SCW_SENSITIVE") != "1" { + if ctx.Getenv("SCW_SENSITIVE") != "1" { res = ctx.API.HideAPICredentials(res) } fmt.Fprintln(ctx.Stdout, res) @@ -106,7 +105,7 @@ func RunInspect(ctx CommandContext, args InspectArgs) error { } if len(args.Identifiers) != nbInspected { - os.Exit(1) + return fmt.Errorf("at least 1 item failed to be inspected") } return nil } diff --git a/pkg/commands/kill.go b/pkg/commands/kill.go index bb3d945345..b8b90c3983 100644 --- a/pkg/commands/kill.go +++ b/pkg/commands/kill.go @@ -6,7 +6,6 @@ package commands import ( "fmt" - "os" "os/exec" "strings" @@ -49,9 +48,9 @@ func RunKill(ctx CommandContext, args KillArgs) error { logrus.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) spawn := exec.Command("ssh", execCmd...) - spawn.Stdout = os.Stdout - spawn.Stdin = os.Stdin - spawn.Stderr = os.Stderr + spawn.Stdout = ctx.Stdout + spawn.Stdin = ctx.Stdin + spawn.Stderr = ctx.Stderr return spawn.Run() } diff --git a/pkg/commands/run.go b/pkg/commands/run.go index dfbdfb1d78..86629a6161 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -6,7 +6,6 @@ package commands import ( "fmt" - "os" "strings" "github.com/scaleway/scaleway-cli/pkg/api" @@ -93,9 +92,7 @@ func RunRun(ctx CommandContext, args RunArgs) error { err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway) } if err != nil { - logrus.Infof("Command execution failed: %v", err) - // FIXME: create a new error type for silent exiting - os.Exit(1) + return fmt.Errorf("command execution failed: %v", err) } logrus.Info("Command successfuly executed") }