From 30842e787cdcf871c8ef8107223fe1f117021b0d Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Wed, 26 Aug 2015 11:35:31 +0200 Subject: [PATCH 1/4] Support of 'scw images --filter' (#134) --- README.md | 23 ++++- pkg/api/helpers.go | 1 + pkg/cli/cmd_images.go | 46 ++++++++-- pkg/commands/images.go | 194 ++++++++++++++++++++++++++--------------- 4 files changed, 190 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index bcbb7dd456..e5d1489af6 100644 --- a/README.md +++ b/README.md @@ -410,9 +410,29 @@ List images. Options: -a, --all=false Show all iamges + -f, --filter="" Filter output based on conditions provided -h, --help=false Print usage --no-trunc=false Don't truncate output -q, --quiet=false Only show numeric IDs + +Examples: + + $ scw images + $ scw images -a + $ scw images -q + $ scw images --no-trunc + $ scw images -f organization=me + $ scw images -f organization=official-distribs + $ scw images -f organization=official-apps + $ scw images -f organization=UUIDOFORGANIZATION + $ scw images -f name=ubuntu + $ scw images -f type=image + $ scw images -f type=bootscript + $ scw images -f type=snapshot + $ scw images -f type=volume + $ scw images -f public=true + $ scw images -f public=false + $ scw images -f "organization=me type=volume" -q ``` @@ -1091,10 +1111,11 @@ $ scw inspect myserver | jq '.[0].public_ip.address' * `scw -D login` displays a fake password * Support --skip-ssh-key `scw login` ([#129](https://github.com/scaleway/scaleway-cli/issues/129)) * 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)) +* Support of `scw images --filter` option *(type, organization, name, public)* ([#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)) -* Support -f `scw run --rm` option ([#117](https://github.com/scaleway/scaleway-cli/issues/117)) +* Support of `scw run --rm` option ([#117](https://github.com/scaleway/scaleway-cli/issues/117)) * Support of `--gateway=login@host` ([#110](https://github.com/scaleway/scaleway-cli/issues/110)) * Upload local ssh key to scaleway account on `scw login` ([#100](https://github.com/scaleway/scaleway-cli/issues/100)) * Add a 'running indicator' for `scw run`, can be disabled with the new flag `--quiet` diff --git a/pkg/api/helpers.go b/pkg/api/helpers.go index 8a015e89c6..59c56e86be 100644 --- a/pkg/api/helpers.go +++ b/pkg/api/helpers.go @@ -37,6 +37,7 @@ type ScalewayImageInterface struct { VirtualSize float64 Public bool Type string + Organization string } // ResolveGateway tries to resolve a server public ip address, else returns the input string, i.e. IPv4, hostname diff --git a/pkg/cli/cmd_images.go b/pkg/cli/cmd_images.go index 8a3647307b..d8c1179736 100644 --- a/pkg/cli/cmd_images.go +++ b/pkg/cli/cmd_images.go @@ -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 cmdImages = &Command{ Exec: runImages, UsageLine: "images [OPTIONS]", Description: "List images", Help: "List images.", + Examples: ` + $ scw images + $ scw images -a + $ scw images -q + $ scw images --no-trunc + $ scw images -f organization=me + $ scw images -f organization=official-distribs + $ scw images -f organization=official-apps + $ scw images -f organization=UUIDOFORGANIZATION + $ scw images -f name=ubuntu + $ scw images -f type=image + $ scw images -f type=bootscript + $ scw images -f type=snapshot + $ scw images -f type=volume + $ scw images -f public=true + $ scw images -f public=false + $ scw images -f "organization=me type=volume" -q +`, } func init() { @@ -18,13 +41,15 @@ func init() { cmdImages.Flag.BoolVar(&imagesNoTrunc, []string{"-no-trunc"}, false, "Don't truncate output") cmdImages.Flag.BoolVar(&imagesQ, []string{"q", "-quiet"}, false, "Only show numeric IDs") cmdImages.Flag.BoolVar(&imagesHelp, []string{"h", "-help"}, false, "Print usage") + cmdImages.Flag.StringVar(&imagesFilters, []string{"f", "-filter"}, "", "Filter output based on conditions provided") } // Flags -var imagesA bool // -a flag -var imagesQ bool // -q flag -var imagesNoTrunc bool // -no-trunc flag -var imagesHelp bool // -h, --help flag +var imagesA bool // -a flag +var imagesQ bool // -q flag +var imagesNoTrunc bool // -no-trunc flag +var imagesHelp bool // -h, --help flag +var imagesFilters string // -f, --filters func runImages(cmd *Command, rawArgs []string) error { if imagesHelp { @@ -38,6 +63,17 @@ func runImages(cmd *Command, rawArgs []string) error { All: imagesA, Quiet: imagesQ, NoTrunc: imagesNoTrunc, + Filters: make(map[string]string, 0), + } + if imagesFilters != "" { + for _, filter := range strings.Split(imagesFilters, " ") { + 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.RunImages(ctx, args) diff --git a/pkg/commands/images.go b/pkg/commands/images.go index 2be42e7858..0b36162fc4 100644 --- a/pkg/commands/images.go +++ b/pkg/commands/images.go @@ -7,10 +7,12 @@ package commands import ( "fmt" "sort" + "strings" "sync" "text/tabwriter" "time" + "github.com/renstrom/fuzzysearch/fuzzy" "github.com/scaleway/scaleway-cli/pkg/api" "github.com/scaleway/scaleway-cli/pkg/utils" "github.com/scaleway/scaleway-cli/vendor/github.com/Sirupsen/logrus" @@ -22,6 +24,7 @@ type ImagesArgs struct { All bool NoTrunc bool Quiet bool + Filters map[string]string } // RunImages is the handler for 'scw images' @@ -30,98 +33,111 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { chEntries := make(chan api.ScalewayImageInterface) var entries = []api.ScalewayImageInterface{} - // FIXME: remove log.Fatalf in routines + filterType := args.Filters["type"] - wg.Add(1) - go func() { - defer wg.Done() - images, err := ctx.API.GetImages() - if err != nil { - 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 { - logrus.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), - } - } - }() + // FIXME: remove log.Fatalf in routines - if args.All { + if filterType == "" || filterType == "image" { wg.Add(1) go func() { defer wg.Done() - snapshots, err := ctx.API.GetSnapshots() + images, err := ctx.API.GetImages() if err != nil { - logrus.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) + logrus.Fatalf("unable to fetch images from the Scaleway API: %v", err) } - for _, val := range *snapshots { + for _, val := range *images { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ - Type: "snapshot", + Type: "image", CreationDate: creationDate, Identifier: val.Identifier, Name: val.Name, - Tag: "", - VirtualSize: float64(val.Size), - Public: false, + Public: val.Public, + Tag: "latest", + VirtualSize: float64(val.RootVolume.Size), + Organization: val.Organization, } } }() + } - wg.Add(1) - go func() { - defer wg.Done() - bootscripts, err := ctx.API.GetBootscripts() - if err != nil { - logrus.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, + if args.All || filterType != "" { + if filterType == "" || filterType == "snapshot" { + wg.Add(1) + go func() { + defer wg.Done() + snapshots, err := ctx.API.GetSnapshots() + if err != nil { + 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 { + logrus.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, + Organization: val.Organization, + } + } + }() + } - wg.Add(1) - go func() { - defer wg.Done() - volumes, err := ctx.API.GetVolumes() - if err != nil { - 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 filterType == "" || filterType == "bootscript" { + wg.Add(1) + go func() { + defer wg.Done() + bootscripts, err := ctx.API.GetBootscripts() if err != nil { - logrus.Fatalf("unable to parse creation date from the Scaleway API: %v", err) + logrus.Fatalf("unable to fetch bootscripts 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, + for _, val := range *bootscripts { + chEntries <- api.ScalewayImageInterface{ + Type: "bootscript", + Identifier: val.Identifier, + Name: val.Title, + Tag: "", + Public: false, + } } - } - }() + }() + } + + if filterType == "" || filterType == "volume" { + wg.Add(1) + go func() { + defer wg.Done() + volumes, err := ctx.API.GetVolumes() + if err != nil { + 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 { + logrus.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, + Organization: val.Organization, + } + } + }() + } } go func() { @@ -144,6 +160,15 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { } } + for key, value := range args.Filters { + switch key { + case "organization", "type", "name", "public": + 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 { @@ -151,6 +176,36 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { } sort.Sort(api.ByCreationDate(entries)) for _, image := range entries { + + for key, value := range args.Filters { + switch key { + case "type": + if value != image.Type { + goto skipimage + } + case "organization": + switch value { + case "me": + value = ctx.API.Organization + case "official-distribs": + value = "a283af0b-d13e-42e1-a43f-855ffbf281ab" + case "official-apps": + value = "c3884e19-7a3e-4b69-9db8-50e7f902aafc" + } + if image.Organization != value { + goto skipimage + } + case "name": + if fuzzy.RankMatch(strings.ToLower(value), strings.ToLower(image.Name)) == -1 { + goto skipimage + } + case "public": + if (value == "true" && !image.Public) || (value == "false" && image.Public) { + goto skipimage + } + } + } + if args.Quiet { fmt.Fprintf(ctx.Stdout, "%s\n", image.Identifier) } else { @@ -174,6 +229,9 @@ func RunImages(ctx CommandContext, args ImagesArgs) error { } fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", shortName, tag, shortID, creationDate, virtualSize) } + + skipimage: + continue } return nil } From bee5a60da4be97a176ed1f5cf23bbaadff6828a7 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Wed, 26 Aug 2015 12:08:11 +0200 Subject: [PATCH 2/4] Support of 'scw ps --filter' (#134) --- README.md | 21 +++++++++++++++++ pkg/cli/cmd_ps.go | 50 +++++++++++++++++++++++++++++++++++------ pkg/commands/ps.go | 56 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e5d1489af6..f902ab3f88 100644 --- a/README.md +++ b/README.md @@ -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" ``` @@ -1112,6 +1132,7 @@ $ scw inspect myserver | jq '.[0].public_ip.address' * Support --skip-ssh-key `scw login` ([#129](https://github.com/scaleway/scaleway-cli/issues/129)) * 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)) * 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)) diff --git a/pkg/cli/cmd_ps.go b/pkg/cli/cmd_ps.go index c094ec7237..1209817593 100644 --- a/pkg/cli/cmd_ps.go +++ b/pkg/cli/cmd_ps.go @@ -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() { @@ -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 { @@ -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) diff --git a/pkg/commands/ps.go b/pkg/commands/ps.go index e316d30387..3b249fe68e 100644 --- a/pkg/commands/ps.go +++ b/pkg/commands/ps.go @@ -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" @@ -21,6 +24,7 @@ type PsArgs struct { NLast int NoTrunc bool Quiet bool + Filters map[string]string } // RunPs is the handler for 'scw ps' @@ -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 { @@ -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 } From caf00c4e45c3ac20f5e35d3a7498259089245f84 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Wed, 26 Aug 2015 12:34:29 +0200 Subject: [PATCH 3/4] party -c -t -d=vendor --- pkg/cli/cmd_images.go | 2 +- pkg/cli/cmd_ps.go | 2 +- pkg/commands/images.go | 2 +- pkg/commands/ps.go | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/cli/cmd_images.go b/pkg/cli/cmd_images.go index d8c1179736..bcd9227cb8 100644 --- a/pkg/cli/cmd_images.go +++ b/pkg/cli/cmd_images.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 cmdImages = &Command{ diff --git a/pkg/cli/cmd_ps.go b/pkg/cli/cmd_ps.go index 1209817593..fbc1495fae 100644 --- a/pkg/cli/cmd_ps.go +++ b/pkg/cli/cmd_ps.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 cmdPs = &Command{ diff --git a/pkg/commands/images.go b/pkg/commands/images.go index 0b36162fc4..85e29a8f65 100644 --- a/pkg/commands/images.go +++ b/pkg/commands/images.go @@ -12,11 +12,11 @@ import ( "text/tabwriter" "time" - "github.com/renstrom/fuzzysearch/fuzzy" "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" + "github.com/scaleway/scaleway-cli/vendor/github.com/renstrom/fuzzysearch/fuzzy" ) // ImagesArgs are flags for the `RunImages` function diff --git a/pkg/commands/ps.go b/pkg/commands/ps.go index 3b249fe68e..399c79fca9 100644 --- a/pkg/commands/ps.go +++ b/pkg/commands/ps.go @@ -10,9 +10,9 @@ import ( "text/tabwriter" "time" - "github.com/Sirupsen/logrus" - "github.com/renstrom/fuzzysearch/fuzzy" + "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/vendor/github.com/renstrom/fuzzysearch/fuzzy" "github.com/scaleway/scaleway-cli/pkg/utils" ) From 672c1932434c59d1a8cae48f91864698e652b953 Mon Sep 17 00:00:00 2001 From: Manfred Touron Date: Wed, 26 Aug 2015 15:55:39 +0200 Subject: [PATCH 4/4] Fixed 'index out of range' panic --- pkg/cli/cmd_images.go | 4 ++++ pkg/cli/cmd_ps.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/pkg/cli/cmd_images.go b/pkg/cli/cmd_images.go index bcd9227cb8..a92feb8ef9 100644 --- a/pkg/cli/cmd_images.go +++ b/pkg/cli/cmd_images.go @@ -68,6 +68,10 @@ func runImages(cmd *Command, rawArgs []string) error { if imagesFilters != "" { for _, filter := range strings.Split(imagesFilters, " ") { parts := strings.SplitN(filter, "=", 2) + if len(parts) != 2 { + logrus.Warnf("Invalid filter '%s', should be in the form 'key=value'", filter) + continue + } if _, ok := args.Filters[parts[0]]; ok { logrus.Warnf("Duplicated filter: %q", parts[0]) } else { diff --git a/pkg/cli/cmd_ps.go b/pkg/cli/cmd_ps.go index fbc1495fae..76eff2ad72 100644 --- a/pkg/cli/cmd_ps.go +++ b/pkg/cli/cmd_ps.go @@ -74,6 +74,10 @@ func runPs(cmd *Command, rawArgs []string) error { if psFilters != "" { for _, filter := range strings.Split(psFilters, " ") { parts := strings.SplitN(filter, "=", 2) + if len(parts) != 2 { + logrus.Warnf("Invalid filter '%s', should be in the form 'key=value'", filter) + continue + } if _, ok := args.Filters[parts[0]]; ok { logrus.Warnf("Duplicated filter: %q", parts[0]) } else {