diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2019-02-20 18:44:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-20 18:44:40 +0100 |
commit | 148d46766f8b037e5774798cd92240d91d6f6f4e (patch) | |
tree | ca696a4d574dc2a278a18b2283864a9c8a865e87 /cmd | |
parent | 11a1c23ab341d6d4726a2ba6dca522642dda9034 (diff) | |
parent | 6ae4401bd1c7988b84c6e1f715ca85ad74ee4048 (diff) | |
download | podman-148d46766f8b037e5774798cd92240d91d6f6f4e.tar.gz podman-148d46766f8b037e5774798cd92240d91d6f6f4e.tar.bz2 podman-148d46766f8b037e5774798cd92240d91d6f6f4e.zip |
Merge pull request #2360 from vrothberg/parallel-search
podman-search: run in parallel
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman/search.go | 234 | ||||
-rw-r--r-- | cmd/podman/varlink/io.podman.varlink | 8 |
2 files changed, 22 insertions, 220 deletions
diff --git a/cmd/podman/search.go b/cmd/podman/search.go index c8b64039a..f63131c84 100644 --- a/cmd/podman/search.go +++ b/cmd/podman/search.go @@ -1,19 +1,13 @@ package main import ( - "context" - "reflect" - "strconv" "strings" - "github.com/containers/image/docker" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/formats" - "github.com/containers/libpod/libpod/common" - sysreg "github.com/containers/libpod/pkg/registries" + "github.com/containers/libpod/libpod/image" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -54,30 +48,6 @@ func init() { flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") } -type searchParams struct { - Index string - Name string - Description string - Stars int - Official string - Automated string -} - -type searchOpts struct { - filter []string - limit int - noTrunc bool - format string - authfile string - insecureSkipTLSVerify types.OptionalBool -} - -type searchFilterParams struct { - stars int - isAutomated *bool - isOfficial *bool -} - func searchCmd(c *cliconfig.SearchValues) error { args := c.InputArgs if len(args) > 1 { @@ -88,37 +58,29 @@ func searchCmd(c *cliconfig.SearchValues) error { } term := args[0] - // Check if search term has a registry in it - registry, err := sysreg.GetRegistry(term) + filter, err := image.ParseSearchFilter(c.Filter) if err != nil { - return errors.Wrapf(err, "error getting registry from %q", term) - } - if registry != "" { - term = term[len(registry)+1:] + return err } - format := genSearchFormat(c.Format) - opts := searchOpts{ - format: format, - noTrunc: c.NoTrunc, - limit: c.Limit, - filter: c.Filter, - authfile: getAuthFile(c.Authfile), + searchOptions := image.SearchOptions{ + NoTrunc: c.NoTrunc, + Limit: c.Limit, + Filter: *filter, + Authfile: getAuthFile(c.Authfile), } if c.Flag("tls-verify").Changed { - opts.insecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) - } - registries, err := getRegistries(registry) - if err != nil { - return err + searchOptions.InsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) } - filter, err := parseSearchFilter(&opts) + results, err := image.SearchImages(term, searchOptions) if err != nil { return err } - - return generateSearchOutput(term, registries, opts, *filter) + format := genSearchFormat(c.Format) + out := formats.StdoutTemplateArray{Output: searchToGeneric(results), Template: format, Fields: results[0].HeaderMap()} + formats.Writer(out).Out() + return nil } func genSearchFormat(format string) string { @@ -130,175 +92,9 @@ func genSearchFormat(format string) string { return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t" } -func searchToGeneric(params []searchParams) (genericParams []interface{}) { +func searchToGeneric(params []image.SearchResult) (genericParams []interface{}) { for _, v := range params { genericParams = append(genericParams, interface{}(v)) } return genericParams } - -func (s *searchParams) headerMap() map[string]string { - v := reflect.Indirect(reflect.ValueOf(s)) - values := make(map[string]string, v.NumField()) - - for i := 0; i < v.NumField(); i++ { - key := v.Type().Field(i).Name - value := key - values[key] = strings.ToUpper(splitCamelCase(value)) - } - return values -} - -// getRegistries returns the list of registries to search, depending on an optional registry specification -func getRegistries(registry string) ([]string, error) { - var registries []string - if registry != "" { - registries = append(registries, registry) - } else { - var err error - registries, err = sysreg.GetRegistries() - if err != nil { - return nil, errors.Wrapf(err, "error getting registries to search") - } - } - return registries, nil -} - -func getSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) ([]searchParams, error) { - // Max number of queries by default is 25 - limit := maxQueries - if opts.limit != 0 { - limit = opts.limit - } - - sc := common.GetSystemContext("", opts.authfile, false) - sc.DockerInsecureSkipTLSVerify = opts.insecureSkipTLSVerify - sc.SystemRegistriesConfPath = sysreg.SystemRegistriesConfPath() // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place. - var paramsArr []searchParams - for _, reg := range registries { - results, err := docker.SearchRegistry(context.TODO(), sc, reg, term, limit) - if err != nil { - logrus.Errorf("error searching registry %q: %v", reg, err) - continue - } - index := reg - arr := strings.Split(reg, ".") - if len(arr) > 2 { - index = strings.Join(arr[len(arr)-2:], ".") - } - - // limit is the number of results to output - // if the total number of results is less than the limit, output all - // if the limit has been set by the user, output those number of queries - limit := maxQueries - if len(results) < limit { - limit = len(results) - } - if opts.limit != 0 && opts.limit < len(results) { - limit = opts.limit - } - - for i := 0; i < limit; i++ { - if len(opts.filter) > 0 { - // Check whether query matches filters - if !(matchesAutomatedFilter(filter, results[i]) && matchesOfficialFilter(filter, results[i]) && matchesStarFilter(filter, results[i])) { - continue - } - } - official := "" - if results[i].IsOfficial { - official = "[OK]" - } - automated := "" - if results[i].IsAutomated { - automated = "[OK]" - } - description := strings.Replace(results[i].Description, "\n", " ", -1) - if len(description) > 44 && !opts.noTrunc { - description = description[:descriptionTruncLength] + "..." - } - name := reg + "/" + results[i].Name - if index == "docker.io" && !strings.Contains(results[i].Name, "/") { - name = index + "/library/" + results[i].Name - } - params := searchParams{ - Index: index, - Name: name, - Description: description, - Official: official, - Automated: automated, - Stars: results[i].StarCount, - } - paramsArr = append(paramsArr, params) - } - } - return paramsArr, nil -} - -func generateSearchOutput(term string, registries []string, opts searchOpts, filter searchFilterParams) error { - searchOutput, err := getSearchOutput(term, registries, opts, filter) - if err != nil { - return err - } - if len(searchOutput) == 0 { - return nil - } - out := formats.StdoutTemplateArray{Output: searchToGeneric(searchOutput), Template: opts.format, Fields: searchOutput[0].headerMap()} - return formats.Writer(out).Out() -} - -func parseSearchFilter(opts *searchOpts) (*searchFilterParams, error) { - filterParams := &searchFilterParams{} - ptrTrue := true - ptrFalse := false - for _, filter := range opts.filter { - arr := strings.Split(filter, "=") - switch arr[0] { - case "stars": - if len(arr) < 2 { - return nil, errors.Errorf("invalid `stars` filter %q, should be stars=<value>", filter) - } - stars, err := strconv.Atoi(arr[1]) - if err != nil { - return nil, errors.Wrapf(err, "incorrect value type for stars filter") - } - filterParams.stars = stars - break - case "is-automated": - if len(arr) == 2 && arr[1] == "false" { - filterParams.isAutomated = &ptrFalse - } else { - filterParams.isAutomated = &ptrTrue - } - break - case "is-official": - if len(arr) == 2 && arr[1] == "false" { - filterParams.isOfficial = &ptrFalse - } else { - filterParams.isOfficial = &ptrTrue - } - break - default: - return nil, errors.Errorf("invalid filter type %q", filter) - } - } - return filterParams, nil -} - -func matchesStarFilter(filter searchFilterParams, result docker.SearchResult) bool { - return result.StarCount >= filter.stars -} - -func matchesAutomatedFilter(filter searchFilterParams, result docker.SearchResult) bool { - if filter.isAutomated != nil { - return result.IsAutomated == *filter.isAutomated - } - return true -} - -func matchesOfficialFilter(filter searchFilterParams, result docker.SearchResult) bool { - if filter.isOfficial != nil { - return result.IsOfficial == *filter.isOfficial - } - return true -} diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 20c8a0de5..c53a5454a 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -72,6 +72,12 @@ type ImageSearchResult ( star_count: int ) +type ImageSearchFilter ( + is_official: ?bool, + is_automated: ?bool, + star_count: int +) + type Container ( id: string, image: string, @@ -681,7 +687,7 @@ method RemoveImage(name: string, force: bool) -> (image: string) # SearchImages searches available registries for images that contain the # contents of "query" in their name. If "limit" is given, limits the amount of # search results per registry. -method SearchImages(query: string, limit: ?int, tlsVerify: ?bool) -> (results: []ImageSearchResult) +method SearchImages(query: string, limit: ?int, tlsVerify: ?bool, filter: ImageSearchFilter) -> (results: []ImageSearchResult) # DeleteUnusedImages deletes any images not associated with a container. The IDs of the deleted images are returned # in a string array. |