Skip to content

Commit bee5a60

Browse files
committed
Support of 'scw ps --filter' (scaleway#134)
1 parent 30842e7 commit bee5a60

File tree

3 files changed

+119
-8
lines changed

3 files changed

+119
-8
lines changed

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,31 @@ List servers. By default, only running servers are displayed.
564564
Options:
565565

566566
-a, --all=false Show all servers. Only running servers are shown by default
567+
-f, --filter="" Filter output based on conditions provided
567568
-h, --help=false Print usage
568569
-l, --latest=false Show only the latest created server, include non-running ones
569570
-n=0 Show n last created servers, include non-running ones
570571
--no-trunc=false Don't truncate output
571572
-q, --quiet=false Only display numeric IDs
573+
574+
Examples:
575+
576+
$ scw ps
577+
$ scw ps -a
578+
$ scw ps -l
579+
$ scw ps -n=10
580+
$ scw ps -q
581+
$ scw ps --no-trunc
582+
$ scw ps -f state=booted
583+
$ scw ps -f state=running
584+
$ scw ps -f state=stopped
585+
$ scw ps -f ip=212.47.229.26
586+
$ scw ps -f tags=prod
587+
$ scw ps -f tags=boot=live
588+
$ scw ps -f image=docker
589+
$ scw ps -f image=alpine
590+
$ scw ps -f image=UUIDOFIMAGE
591+
$ scw ps -f "state=booted image=docker tags=prod"
572592
```
573593

574594

@@ -1112,6 +1132,7 @@ $ scw inspect myserver | jq '.[0].public_ip.address'
11121132
* Support --skip-ssh-key `scw login` ([#129](https://github.com/scaleway/scaleway-cli/issues/129))
11131133
* Now `scw login` ask your login/password, you can also pass token and organization with -o and -t ([#59](https://github.com/scaleway/scaleway-cli/issues/59))
11141134
* Support of `scw images --filter` option *(type, organization, name, public)* ([#134](https://github.com/scaleway/scaleway-cli/issues/134))
1135+
* 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))
11151136
* Syncing cache to disk after server creation when running `scw run` in a non-detached mode
11161137
* Bump to Golang 1.5
11171138
* Support --tmp-ssh-key `scw {run,create}` option ([#99](https://github.com/scaleway/scaleway-cli/issues/99))

pkg/cli/cmd_ps.go

+43-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,36 @@
44

55
package cli
66

7-
import "github.com/scaleway/scaleway-cli/pkg/commands"
7+
import (
8+
"strings"
9+
10+
"github.com/Sirupsen/logrus"
11+
"github.com/scaleway/scaleway-cli/pkg/commands"
12+
)
813

914
var cmdPs = &Command{
1015
Exec: runPs,
1116
UsageLine: "ps [OPTIONS]",
1217
Description: "List servers",
1318
Help: "List servers. By default, only running servers are displayed.",
19+
Examples: `
20+
$ scw ps
21+
$ scw ps -a
22+
$ scw ps -l
23+
$ scw ps -n=10
24+
$ scw ps -q
25+
$ scw ps --no-trunc
26+
$ scw ps -f state=booted
27+
$ scw ps -f state=running
28+
$ scw ps -f state=stopped
29+
$ scw ps -f ip=212.47.229.26
30+
$ scw ps -f tags=prod
31+
$ scw ps -f tags=boot=live
32+
$ scw ps -f image=docker
33+
$ scw ps -f image=alpine
34+
$ scw ps -f image=UUIDOFIMAGE
35+
$ scw ps -f "state=booted image=docker tags=prod"
36+
`,
1437
}
1538

1639
func init() {
@@ -20,15 +43,17 @@ func init() {
2043
cmdPs.Flag.BoolVar(&psNoTrunc, []string{"-no-trunc"}, false, "Don't truncate output")
2144
cmdPs.Flag.BoolVar(&psQ, []string{"q", "-quiet"}, false, "Only display numeric IDs")
2245
cmdPs.Flag.BoolVar(&psHelp, []string{"h", "-help"}, false, "Print usage")
46+
cmdPs.Flag.StringVar(&psFilters, []string{"f", "-filter"}, "", "Filter output based on conditions provided")
2347
}
2448

2549
// Flags
26-
var psA bool // -a flag
27-
var psL bool // -l flag
28-
var psQ bool // -q flag
29-
var psNoTrunc bool // -no-trunc flag
30-
var psN int // -n flag
31-
var psHelp bool // -h, --help flag
50+
var psA bool // -a flag
51+
var psL bool // -l flag
52+
var psQ bool // -q flag
53+
var psNoTrunc bool // -no-trunc flag
54+
var psN int // -n flag
55+
var psHelp bool // -h, --help flag
56+
var psFilters string // -f, --filter flag
3257

3358
func runPs(cmd *Command, rawArgs []string) error {
3459
if psHelp {
@@ -44,6 +69,17 @@ func runPs(cmd *Command, rawArgs []string) error {
4469
Quiet: psQ,
4570
NoTrunc: psNoTrunc,
4671
NLast: psN,
72+
Filters: make(map[string]string, 0),
73+
}
74+
if psFilters != "" {
75+
for _, filter := range strings.Split(psFilters, " ") {
76+
parts := strings.SplitN(filter, "=", 2)
77+
if _, ok := args.Filters[parts[0]]; ok {
78+
logrus.Warnf("Duplicated filter: %q", parts[0])
79+
} else {
80+
args.Filters[parts[0]] = parts[1]
81+
}
82+
}
4783
}
4884
ctx := cmd.GetContext(rawArgs)
4985
return commands.RunPs(ctx, args)

pkg/commands/ps.go

+55-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ package commands
66

77
import (
88
"fmt"
9+
"strings"
910
"text/tabwriter"
1011
"time"
1112

13+
"github.com/Sirupsen/logrus"
14+
"github.com/renstrom/fuzzysearch/fuzzy"
1215
"github.com/scaleway/scaleway-cli/vendor/github.com/docker/docker/pkg/units"
1316

1417
"github.com/scaleway/scaleway-cli/pkg/utils"
@@ -21,6 +24,7 @@ type PsArgs struct {
2124
NLast int
2225
NoTrunc bool
2326
Quiet bool
27+
Filters map[string]string
2428
}
2529

2630
// RunPs is the handler for 'scw ps'
@@ -29,18 +33,66 @@ func RunPs(ctx CommandContext, args PsArgs) error {
2933
if args.Latest {
3034
limit = 1
3135
}
32-
all := args.All || args.NLast > 0 || args.Latest
36+
37+
filterState := args.Filters["state"]
38+
39+
// FIXME: if filter state is defined, try to optimize the query
40+
all := args.All || args.NLast > 0 || args.Latest || filterState != ""
3341
servers, err := ctx.API.GetServers(all, limit)
3442
if err != nil {
3543
return fmt.Errorf("Unable to fetch servers from the Scaleway API: %v", err)
3644
}
3745

46+
for key, value := range args.Filters {
47+
switch key {
48+
case "state", "name", "tags", "image", "ip":
49+
continue
50+
default:
51+
logrus.Warnf("Unknown filter: '%s=%s'", key, value)
52+
}
53+
}
54+
3855
w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0)
3956
defer w.Flush()
4057
if !args.Quiet {
4158
fmt.Fprintf(w, "SERVER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAME\n")
4259
}
4360
for _, server := range *servers {
61+
62+
// filtering
63+
for key, value := range args.Filters {
64+
switch key {
65+
case "state":
66+
if value != server.State {
67+
goto skipServer
68+
}
69+
case "name":
70+
if fuzzy.RankMatch(strings.ToLower(value), strings.ToLower(server.Name)) == -1 {
71+
goto skipServer
72+
}
73+
case "tags":
74+
found := false
75+
for _, tag := range server.Tags {
76+
if tag == value {
77+
found = true
78+
continue
79+
}
80+
}
81+
if !found {
82+
goto skipServer
83+
}
84+
case "image":
85+
imageID := ctx.API.GetImageID(value, true)
86+
if imageID != server.Image.Identifier {
87+
goto skipServer
88+
}
89+
case "ip":
90+
if value != server.PublicAddress.IP {
91+
goto skipServer
92+
}
93+
}
94+
}
95+
4496
if args.Quiet {
4597
fmt.Fprintf(w, "%s\n", server.Identifier)
4698
} else {
@@ -52,6 +104,8 @@ func RunPs(ctx CommandContext, args PsArgs) error {
52104
port := server.PublicAddress.IP
53105
fmt.Fprintf(w, "%s\t%s\t\t%s\t%s\t%s\t%s\n", shortID, shortImage, shortCreationDate, server.State, port, shortName)
54106
}
107+
skipServer:
108+
continue
55109
}
56110
return nil
57111
}

0 commit comments

Comments
 (0)