Skip to content

Commit

Permalink
Support of 'scw ps --filter' (scaleway#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Aug 26, 2015
1 parent a266afb commit 370c193
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 9 deletions.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,11 +564,31 @@ List servers. By default, only running servers are displayed.
Options:

-a, --all=false Show all servers. Only running servers are shown by default
-f, --filter="" Filter output based on conditions provided
-h, --help=false Print usage
-l, --latest=false Show only the latest created server, include non-running ones
-n=0 Show n last created servers, include non-running ones
--no-trunc=false Don't truncate output
-q, --quiet=false Only display numeric IDs

Examples:

$ scw ps
$ scw ps -a
$ scw ps -l
$ scw ps -n=10
$ scw ps -q
$ scw ps --no-trunc
$ scw ps -f state=booted
$ scw ps -f state=running
$ scw ps -f state=stopped
$ scw ps -f ip=212.47.229.26
$ scw ps -f tags=prod
$ scw ps -f tags=boot=live
$ scw ps -f image=docker
$ scw ps -f image=alpine
$ scw ps -f image=UUIDOFIMAGE
$ scw ps -f "state=booted image=docker tags=prod"
```


Expand Down Expand Up @@ -1108,7 +1128,7 @@ $ scw inspect myserver | jq '.[0].public_ip.address'

#### Features

* Support of `scw images --filter` option *(type, organization, name, public)* ([#134](https://github.com/scaleway/scaleway-cli/issues/134))
* Support of `scw {ps,images} --filter` option *(images: type,organization,name,public; ps:state,ip,tags,image)* ([#134](https://github.com/scaleway/scaleway-cli/issues/134))
* Syncing cache to disk after server creation when running `scw run` in a non-detached mode
* Bump to Golang 1.5
* Support --tmp-ssh-key `scw {run,create}` option ([#99](https://github.com/scaleway/scaleway-cli/issues/99))
Expand Down
50 changes: 43 additions & 7 deletions pkg/cli/cmd_ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,36 @@

package cli

import "github.com/scaleway/scaleway-cli/pkg/commands"
import (
"strings"

"github.com/Sirupsen/logrus"
"github.com/scaleway/scaleway-cli/pkg/commands"
)

var cmdPs = &Command{
Exec: runPs,
UsageLine: "ps [OPTIONS]",
Description: "List servers",
Help: "List servers. By default, only running servers are displayed.",
Examples: `
$ scw ps
$ scw ps -a
$ scw ps -l
$ scw ps -n=10
$ scw ps -q
$ scw ps --no-trunc
$ scw ps -f state=booted
$ scw ps -f state=running
$ scw ps -f state=stopped
$ scw ps -f ip=212.47.229.26
$ scw ps -f tags=prod
$ scw ps -f tags=boot=live
$ scw ps -f image=docker
$ scw ps -f image=alpine
$ scw ps -f image=UUIDOFIMAGE
$ scw ps -f "state=booted image=docker tags=prod"
`,
}

func init() {
Expand All @@ -20,15 +43,17 @@ func init() {
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")
cmdPs.Flag.StringVar(&psFilters, []string{"f", "-filter"}, "", "Filter output based on conditions provided")
}

// 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
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
var psFilters string // -f, --filter flag

func runPs(cmd *Command, rawArgs []string) error {
if psHelp {
Expand All @@ -44,6 +69,17 @@ func runPs(cmd *Command, rawArgs []string) error {
Quiet: psQ,
NoTrunc: psNoTrunc,
NLast: psN,
Filters: make(map[string]string, 0),
}
if psFilters != "" {
for _, filter := range strings.Split(psFilters, " ") {
parts := strings.SplitN(filter, "=", 2)
if _, ok := args.Filters[parts[0]]; ok {
logrus.Warnf("Duplicated filter: %q", parts[0])
} else {
args.Filters[parts[0]] = parts[1]
}
}
}
ctx := cmd.GetContext(rawArgs)
return commands.RunPs(ctx, args)
Expand Down
56 changes: 55 additions & 1 deletion pkg/commands/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ package commands

import (
"fmt"
"strings"
"text/tabwriter"
"time"

"github.com/Sirupsen/logrus"
"github.com/renstrom/fuzzysearch/fuzzy"
"github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units"

"github.com/scaleway/scaleway-cli/pkg/utils"
Expand All @@ -21,6 +24,7 @@ type PsArgs struct {
NLast int
NoTrunc bool
Quiet bool
Filters map[string]string
}

// RunPs is the handler for 'scw ps'
Expand All @@ -29,18 +33,66 @@ func RunPs(ctx CommandContext, args PsArgs) error {
if args.Latest {
limit = 1
}
all := args.All || args.NLast > 0 || args.Latest

filterState := args.Filters["state"]

// FIXME: if filter state is defined, try to optimize the query
all := args.All || args.NLast > 0 || args.Latest || filterState != ""
servers, err := ctx.API.GetServers(all, limit)
if err != nil {
return fmt.Errorf("Unable to fetch servers from the Scaleway API: %v", err)
}

for key, value := range args.Filters {
switch key {
case "state", "name", "tags", "image", "ip":
continue
default:
logrus.Warnf("Unknown filter: '%s=%s'", key, value)
}
}

w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0)
defer w.Flush()
if !args.Quiet {
fmt.Fprintf(w, "SERVER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAME\n")
}
for _, server := range *servers {

// filtering
for key, value := range args.Filters {
switch key {
case "state":
if value != server.State {
goto skipServer
}
case "name":
if fuzzy.RankMatch(strings.ToLower(value), strings.ToLower(server.Name)) == -1 {
goto skipServer
}
case "tags":
found := false
for _, tag := range server.Tags {
if tag == value {
found = true
continue
}
}
if !found {
goto skipServer
}
case "image":
imageID := ctx.API.GetImageID(value, true)
if imageID != server.Image.Identifier {
goto skipServer
}
case "ip":
if value != server.PublicAddress.IP {
goto skipServer
}
}
}

if args.Quiet {
fmt.Fprintf(w, "%s\n", server.Identifier)
} else {
Expand All @@ -52,6 +104,8 @@ func RunPs(ctx CommandContext, args PsArgs) error {
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)
}
skipServer:
continue
}
return nil
}

0 comments on commit 370c193

Please sign in to comment.