From 8d4e19634cf73f257ca7f5d2c9506183f6a5b183 Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 14 Dec 2020 08:52:00 -0600 Subject: Podman image bindings for 3.0 Begin the migration of the image bindings for podman 3.0. this includes the use of options for each binding. build was intentionally not converted as I believe it needs more discussion before migration. specifically, the build options themselves. also noteworthly is that the remove image and remove images bindings were merged into one. the remove images (or batch remove) has one downside in that the errors return no longer adhere to http return codes. this should be discussed and reimplemented in subsequent code. Signed-off-by: baude --- pkg/api/handlers/libpod/images.go | 75 ++++--- pkg/bindings/generator/generator.go | 54 ++++-- pkg/bindings/images/diff.go | 6 +- pkg/bindings/images/images.go | 205 +++++++++----------- pkg/bindings/images/pull.go | 26 +-- pkg/bindings/images/removeoptions_types.go | 93 --------- pkg/bindings/images/rm.go | 47 ++--- pkg/bindings/images/types.go | 185 ++++++++++++++++++ pkg/bindings/images/types_diff_options.go | 87 +++++++++ pkg/bindings/images/types_export_options.go | 119 ++++++++++++ pkg/bindings/images/types_get_options.go | 103 ++++++++++ pkg/bindings/images/types_history_options.go | 87 +++++++++ pkg/bindings/images/types_import_options.go | 151 +++++++++++++++ pkg/bindings/images/types_list_options.go | 119 ++++++++++++ pkg/bindings/images/types_load_options.go | 103 ++++++++++ pkg/bindings/images/types_prune_options.go | 119 ++++++++++++ pkg/bindings/images/types_pull_options.go | 280 +++++++++++++++++++++++++++ pkg/bindings/images/types_push_options.go | 279 ++++++++++++++++++++++++++ pkg/bindings/images/types_remove_options.go | 119 ++++++++++++ pkg/bindings/images/types_search_options.go | 183 +++++++++++++++++ pkg/bindings/images/types_tag_options.go | 87 +++++++++ pkg/bindings/images/types_tree_options.go | 103 ++++++++++ pkg/bindings/images/types_untag_options.go | 87 +++++++++ pkg/bindings/test/auth_test.go | 42 ++-- pkg/bindings/test/images_test.go | 100 +++++----- pkg/bindings/test/info_test.go | 4 +- pkg/bindings/test/manifests_test.go | 4 +- pkg/domain/infra/tunnel/images.go | 154 ++++++++++----- 28 files changed, 2600 insertions(+), 421 deletions(-) delete mode 100644 pkg/bindings/images/removeoptions_types.go create mode 100644 pkg/bindings/images/types_diff_options.go create mode 100644 pkg/bindings/images/types_export_options.go create mode 100644 pkg/bindings/images/types_get_options.go create mode 100644 pkg/bindings/images/types_history_options.go create mode 100644 pkg/bindings/images/types_import_options.go create mode 100644 pkg/bindings/images/types_list_options.go create mode 100644 pkg/bindings/images/types_load_options.go create mode 100644 pkg/bindings/images/types_prune_options.go create mode 100644 pkg/bindings/images/types_pull_options.go create mode 100644 pkg/bindings/images/types_push_options.go create mode 100644 pkg/bindings/images/types_remove_options.go create mode 100644 pkg/bindings/images/types_search_options.go create mode 100644 pkg/bindings/images/types_tag_options.go create mode 100644 pkg/bindings/images/types_tree_options.go create mode 100644 pkg/bindings/images/types_untag_options.go (limited to 'pkg') diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 505c96126..814d0fd69 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -265,8 +265,14 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { // Format is mandatory! Currently, we only support multi-image docker // archives. + if len(query.References) > 1 && query.Format != define.V2s2Archive { + utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("multi-image archives must use format of %s", define.V2s2Archive)) + return + + } + switch query.Format { - case define.V2s2Archive: + case define.V2s2Archive, define.OCIArchive: tmpfile, err := ioutil.TempFile("", "api.tar") if err != nil { utils.Error(w, "unable to create tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) @@ -277,6 +283,13 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { utils.Error(w, "unable to close tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile")) return } + case define.OCIManifestDir, define.V2s2ManifestDir: + tmpdir, err := ioutil.TempDir("", "save") + if err != nil { + utils.Error(w, "unable to create tmpdir", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempdir")) + return + } + output = tmpdir default: utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format)) return @@ -287,7 +300,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { opts := entities.ImageSaveOptions{ Compress: query.Compress, Format: query.Format, - MultiImageArchive: true, + MultiImageArchive: len(query.References) > 1, Output: output, RemoveSignatures: true, } @@ -414,7 +427,6 @@ func PushImage(w http.ResponseWriter, r *http.Request) { }{ // This is where you can override the golang default value for one of fields } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return @@ -607,12 +619,12 @@ func UntagImage(w http.ResponseWriter, r *http.Request) { func SearchImages(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Term string `json:"term"` - Limit int `json:"limit"` - NoTrunc bool `json:"noTrunc"` - Filters []string `json:"filters"` - TLSVerify bool `json:"tlsVerify"` - ListTags bool `json:"listTags"` + Term string `json:"term"` + Limit int `json:"limit"` + NoTrunc bool `json:"noTrunc"` + Filters map[string][]string `json:"filters"` + TLSVerify bool `json:"tlsVerify"` + ListTags bool `json:"listTags"` }{ // This is where you can override the golang default value for one of fields } @@ -622,24 +634,44 @@ func SearchImages(w http.ResponseWriter, r *http.Request) { return } + filter := image.SearchFilter{} + if len(query.Filters) > 0 { + if len(query.Filters["stars"]) > 0 { + stars, err := strconv.Atoi(query.Filters["stars"][0]) + if err != nil { + utils.InternalServerError(w, err) + return + } + filter.Stars = stars + } + if len(query.Filters["is-official"]) > 0 { + isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0]) + if err != nil { + utils.InternalServerError(w, err) + return + } + filter.IsOfficial = types.NewOptionalBool(isOfficial) + } + if len(query.Filters["is-automated"]) > 0 { + isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0]) + if err != nil { + utils.InternalServerError(w, err) + return + } + filter.IsAutomated = types.NewOptionalBool(isAutomated) + } + } options := image.SearchOptions{ Limit: query.Limit, NoTrunc: query.NoTrunc, ListTags: query.ListTags, + Filter: filter, } + if _, found := r.URL.Query()["tlsVerify"]; found { options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) } - if _, found := r.URL.Query()["filters"]; found { - filter, err := image.ParseSearchFilter(query.Filters) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse filters parameter for %s", r.URL.String())) - return - } - options.Filter = *filter - } - _, authfile, key, err := auth.GetCredentials(r) if err != nil { utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String())) @@ -678,10 +710,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) { All bool `schema:"all"` Force bool `schema:"force"` Images []string `schema:"images"` - }{ - All: false, - Force: false, - } + }{} if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, @@ -690,10 +719,8 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) { } opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force} - imageEngine := abi.ImageEngine{Libpod: runtime} rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts) - strErrs := errorhandling.ErrorsToStrings(rmErrors) report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: strErrs} utils.WriteResponse(w, http.StatusOK, report) diff --git a/pkg/bindings/generator/generator.go b/pkg/bindings/generator/generator.go index 24c2310ff..2ebe35282 100644 --- a/pkg/bindings/generator/generator.go +++ b/pkg/bindings/generator/generator.go @@ -81,10 +81,11 @@ func (o *{{.StructName}}) ToParams() (url.Values, error) { } case reflect.Map: lowerCaseKeys := make(map[string][]string) - // I dont know if this code is needed anymore, TBD - // for k, v := range filters { - // lowerCaseKeys[strings.ToLower(k)] = v - // } + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } s, err := json.MarshalToString(lowerCaseKeys) if err != nil { return nil, err @@ -102,23 +103,34 @@ func (o *{{.StructName}}) ToParams() (url.Values, error) { var fieldTmpl = ` // With{{.Name}} func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} { - v := &value + v := {{.TypedValue}} o.{{.Name}} = v return o } + +// Get{{.Name}} +func(o *{{.StructName}}) Get{{.Name}}() {{.Type}} { + var {{.ZeroName}} {{.Type}} + if o.{{.Name}} == nil { + return {{.ZeroName}} + } + return {{.TypedName}} +} ` type fieldStruct struct { Name string StructName string Type string + TypedName string + TypedValue string + ZeroName string } func main() { var ( closed bool fieldStructs []fieldStruct - structNode ast.Node ) srcFile := os.Getenv("GOFILE") pkg := os.Getenv("GOPACKAGE") @@ -132,14 +144,13 @@ func main() { if err != nil { panic(err) } - // always add reflect imports := []string{"\"reflect\""} for _, imp := range f.Imports { imports = append(imports, imp.Path.Value) } - out, err := os.Create(strings.ToLower(inputStructName) + "_" + srcFile) + out, err := os.Create(strings.TrimRight(srcFile, ".go") + "_" + strings.Replace(strings.ToLower(inputStructName), "options", "_options", 1) + ".go") if err != nil { panic(err) } @@ -166,26 +177,41 @@ func main() { ref, refOK := n.(*ast.TypeSpec) if refOK { if ref.Name.Name == inputStructName { - structNode = n x := ref.Type.(*ast.StructType) for _, field := range x.Fields.List { var ( - name string + name, zeroName, typedName, typedValue string ) - typeExpr := field.Type - start := typeExpr.Pos() - 1 - end := typeExpr.End() - 1 - fieldType := strings.Replace(string(b[start:end]), "*", "", 1) if len(field.Names) > 0 { name = field.Names[0].Name if len(name) < 1 { panic(errors.New("bad name")) } } + for k, v := range name { + zeroName = strings.ToLower(string(v)) + name[k+1:] + break + } + //sub := "*" + typeExpr := field.Type + switch field.Type.(type) { + case *ast.MapType, *ast.StructType, *ast.ArrayType: + typedName = "o." + name + typedValue = "value" + default: + typedName = "*o." + name + typedValue = "&value" + } + start := typeExpr.Pos() - 1 + end := typeExpr.End() - 1 + fieldType := strings.Replace(string(b[start:end]), "*", "", 1) fStruct := fieldStruct{ Name: name, StructName: inputStructName, Type: fieldType, + TypedName: typedName, + TypedValue: typedValue, + ZeroName: zeroName, } fieldStructs = append(fieldStructs, fStruct) } // for diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go index 10d50b0fd..8802c15e2 100644 --- a/pkg/bindings/images/diff.go +++ b/pkg/bindings/images/diff.go @@ -9,7 +9,11 @@ import ( ) // Diff provides the changes between two container layers -func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) { +func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive.Change, error) { + if options == nil { + options = new(DiffOptions) + } + _ = options conn, err := bindings.GetClient(ctx) if err != nil { return nil, err diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index 2d3035d8d..9beb493c8 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -8,7 +8,6 @@ import ( "net/url" "strconv" - "github.com/containers/image/v5/types" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/auth" "github.com/containers/podman/v2/pkg/bindings" @@ -32,22 +31,18 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) { // List returns a list of images in local storage. The all boolean and filters parameters are optional // ways to alter the image query. -func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entities.ImageSummary, error) { +func List(ctx context.Context, options *ListOptions) ([]*entities.ImageSummary, error) { + if options == nil { + options = new(ListOptions) + } var imageSummary []*entities.ImageSummary conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - if all != nil { - params.Set("all", strconv.FormatBool(*all)) - } - if filters != nil { - strFilters, err := bindings.FiltersToString(filters) - if err != nil { - return nil, err - } - params.Set("filters", strFilters) + params, err := options.ToParams() + if err != nil { + return nil, err } response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil) if err != nil { @@ -58,14 +53,17 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit // Get performs an image inspect. To have the on-disk size of the image calculated, you can // use the optional size parameter. -func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageInspectReport, error) { +func GetImage(ctx context.Context, nameOrID string, options *GetOptions) (*entities.ImageInspectReport, error) { + if options == nil { + options = new(GetOptions) + } conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - if size != nil { - params.Set("size", strconv.FormatBool(*size)) + params, err := options.ToParams() + if err != nil { + return nil, err } inspectedData := entities.ImageInspectReport{} response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID) @@ -76,15 +74,18 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image } // Tree retrieves a "tree" based representation of the given image -func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.ImageTreeReport, error) { +func Tree(ctx context.Context, nameOrID string, options *TreeOptions) (*entities.ImageTreeReport, error) { + if options == nil { + options = new(TreeOptions) + } var report entities.ImageTreeReport conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - if whatRequires != nil { - params.Set("size", strconv.FormatBool(*whatRequires)) + params, err := options.ToParams() + if err != nil { + return nil, err } response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID) if err != nil { @@ -94,7 +95,11 @@ func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.I } // History returns the parent layers of an image. -func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) { +func History(ctx context.Context, nameOrID string, options *HistoryOptions) ([]*handlers.HistoryResponse, error) { + if options == nil { + options = new(HistoryOptions) + } + _ = options var history []*handlers.HistoryResponse conn, err := bindings.GetClient(ctx) if err != nil { @@ -107,15 +112,18 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, return history, response.Process(&history) } -func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadReport, error) { +func Load(ctx context.Context, r io.Reader, options *LoadOptions) (*entities.ImageLoadReport, error) { + if options == nil { + options = new(LoadOptions) + } var report entities.ImageLoadReport conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - if name != nil { - params.Set("reference", *name) + params, err := options.ToParams() + if err != nil { + return nil, err } response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil) if err != nil { @@ -124,49 +132,24 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe return &report, response.Process(&report) } -func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *string, compress *bool) error { - conn, err := bindings.GetClient(ctx) - if err != nil { - return err - } - params := url.Values{} - if format != nil { - params.Set("format", *format) - } - if compress != nil { - params.Set("compress", strconv.FormatBool(*compress)) - } - for _, ref := range namesOrIds { - params.Add("references", ref) +// Export saves images from local storage as a tarball or image archive. The optional format +// parameter is used to change the format of the output. +func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *ExportOptions) error { + if options == nil { + options = new(ExportOptions) } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil) + conn, err := bindings.GetClient(ctx) if err != nil { return err } - - if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 { - _, err = io.Copy(w, response.Body) - return err - } - return response.Process(nil) - -} - -// Export saves an image from local storage as a tarball or image archive. The optional format -// parameter is used to change the format of the output. -func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, compress *bool) error { - conn, err := bindings.GetClient(ctx) + params, err := options.ToParams() if err != nil { return err } - params := url.Values{} - if format != nil { - params.Set("format", *format) - } - if compress != nil { - params.Set("compress", strconv.FormatBool(*compress)) + for _, ref := range nameOrIDs { + params.Add("references", ref) } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil) if err != nil { return err } @@ -180,24 +163,20 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c // Prune removes unused images from local storage. The optional filters can be used to further // define which images should be pruned. -func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]string, error) { +func Prune(ctx context.Context, options *PruneOptions) ([]string, error) { var ( deleted []string ) + if options == nil { + options = new(PruneOptions) + } conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - if all != nil { - params.Set("all", strconv.FormatBool(*all)) - } - if filters != nil { - stringFilter, err := bindings.FiltersToString(filters) - if err != nil { - return nil, err - } - params.Set("filters", stringFilter) + params, err := options.ToParams() + if err != nil { + return nil, err } response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil) if err != nil { @@ -207,7 +186,11 @@ func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]strin } // Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required. -func Tag(ctx context.Context, nameOrID, tag, repo string) error { +func Tag(ctx context.Context, nameOrID, tag, repo string, options *TagOptions) error { + if options == nil { + options = new(TagOptions) + } + _ = options conn, err := bindings.GetClient(ctx) if err != nil { return err @@ -223,7 +206,11 @@ func Tag(ctx context.Context, nameOrID, tag, repo string) error { } // Untag removes a name from locally-stored image. Both the tag and repo parameters are required. -func Untag(ctx context.Context, nameOrID, tag, repo string) error { +func Untag(ctx context.Context, nameOrID, tag, repo string, options *UntagOptions) error { + if options == nil { + options = new(UntagOptions) + } + _ = options conn, err := bindings.GetClient(ctx) if err != nil { return err @@ -241,27 +228,21 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error { // Imports adds the given image to the local image store. This can be done by file and the given reader // or via the url parameter. Additional metadata can be associated with the image by using the changes and // message parameters. The image can also be tagged given a reference. One of url OR r must be provided. -func Import(ctx context.Context, changes []string, message, reference, u *string, r io.Reader) (*entities.ImageImportReport, error) { +func Import(ctx context.Context, r io.Reader, options *ImportOptions) (*entities.ImageImportReport, error) { + if options == nil { + options = new(ImportOptions) + } var report entities.ImageImportReport - if r != nil && u != nil { + if r != nil && options.URL != nil { return nil, errors.New("url and r parameters cannot be used together") } conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - for _, change := range changes { - params.Add("changes", change) - } - if message != nil { - params.Set("message", *message) - } - if reference != nil { - params.Set("reference", *reference) - } - if u != nil { - params.Set("url", *u) + params, err := options.ToParams() + if err != nil { + return nil, err } response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil) if err != nil { @@ -275,25 +256,31 @@ func Import(ctx context.Context, changes []string, message, reference, u *string // The destination must be a reference to a registry (i.e., of docker transport // or be normalized to one). Other transports are rejected as they do not make // sense in a remote context. -func Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error { +func Push(ctx context.Context, source string, destination string, options *PushOptions) error { + if options == nil { + options = new(PushOptions) + } conn, err := bindings.GetClient(ctx) if err != nil { return err } - // TODO: have a global system context we can pass around (1st argument) - header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password) + header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword()) if err != nil { return err } - params := url.Values{} - params.Set("destination", destination) - if options.SkipTLSVerify != types.OptionalBoolUndefined { - // Note: we have to verify if skipped is false. - verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse) - params.Set("tlsVerify", strconv.FormatBool(verifyTLS)) + params, err := options.ToParams() + if err != nil { + return err + } + //SkipTLSVerify is special. We need to delete the param added by + //toparams and change the key and flip the bool + if options.SkipTLSVerify != nil { + params.Del("SkipTLSVerify") + params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify())) } + params.Set("destination", destination) path := fmt.Sprintf("/images/%s/push", source) response, err := conn.DoRequest(nil, http.MethodPost, path, params, header) @@ -305,28 +292,28 @@ func Push(ctx context.Context, source string, destination string, options entiti } // Search is the binding for libpod's v2 endpoints for Search images. -func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) { +func Search(ctx context.Context, term string, options *SearchOptions) ([]entities.ImageSearchReport, error) { + if options == nil { + options = new(SearchOptions) + } conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} - params.Set("term", term) - params.Set("limit", strconv.Itoa(opts.Limit)) - params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc)) - params.Set("listTags", strconv.FormatBool(opts.ListTags)) - for _, f := range opts.Filters { - params.Set("filters", f) + params, err := options.ToParams() + if err != nil { + return nil, err } + params.Set("term", term) - if opts.SkipTLSVerify != types.OptionalBoolUndefined { - // Note: we have to verify if skipped is false. - verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse) - params.Set("tlsVerify", strconv.FormatBool(verifyTLS)) + // Note: we have to verify if skipped is false. + if options.SkipTLSVerify != nil { + params.Del("SkipTLSVerify") + params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify())) } // TODO: have a global system context we can pass around (1st argument) - header, err := auth.Header(nil, auth.XRegistryAuthHeader, opts.Authfile, "", "") + header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), "", "") if err != nil { return nil, err } diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go index c827b3283..5669c704e 100644 --- a/pkg/bindings/images/pull.go +++ b/pkg/bindings/images/pull.go @@ -8,11 +8,9 @@ import ( "io" "io/ioutil" "net/http" - "net/url" "os" "strconv" - "github.com/containers/image/v5/types" "github.com/containers/podman/v2/pkg/auth" "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/domain/entities" @@ -23,26 +21,28 @@ import ( // `rawImage` must be a reference to a registry (i.e., of docker transport or be // normalized to one). Other transports are rejected as they do not make sense // in a remote context. Progress reported on stderr -func Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) ([]string, error) { +func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, error) { + if options == nil { + options = new(PullOptions) + } conn, err := bindings.GetClient(ctx) if err != nil { return nil, err } - params := url.Values{} + params, err := options.ToParams() + if err != nil { + return nil, err + } params.Set("reference", rawImage) - params.Set("overrideArch", options.OverrideArch) - params.Set("overrideOS", options.OverrideOS) - params.Set("overrideVariant", options.OverrideVariant) - if options.SkipTLSVerify != types.OptionalBoolUndefined { + if options.SkipTLSVerify != nil { + params.Del("SkipTLSVerify") // Note: we have to verify if skipped is false. - verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse) - params.Set("tlsVerify", strconv.FormatBool(verifyTLS)) + params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify())) } - params.Set("allTags", strconv.FormatBool(options.AllTags)) // TODO: have a global system context we can pass around (1st argument) - header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password) + header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword()) if err != nil { return nil, err } @@ -59,7 +59,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption // Historically pull writes status to stderr stderr := io.Writer(os.Stderr) - if options.Quiet { + if options.GetQuiet() { stderr = ioutil.Discard } diff --git a/pkg/bindings/images/removeoptions_types.go b/pkg/bindings/images/removeoptions_types.go deleted file mode 100644 index 5902bf908..000000000 --- a/pkg/bindings/images/removeoptions_types.go +++ /dev/null @@ -1,93 +0,0 @@ -package images - -import ( - "net/url" - "reflect" - "strconv" - - jsoniter "github.com/json-iterator/go" - "github.com/pkg/errors" -) - -/* -This file is generated automatically by go generate. Do not edit. - -Created 2020-12-10 12:51:06.090426622 -0600 CST m=+0.000133169 -*/ - -// Changed -func (o *RemoveOptions) Changed(fieldName string) bool { - r := reflect.ValueOf(o) - value := reflect.Indirect(r).FieldByName(fieldName) - return !value.IsNil() -} - -// ToParams -func (o *RemoveOptions) ToParams() (url.Values, error) { - params := url.Values{} - if o == nil { - return params, nil - } - json := jsoniter.ConfigCompatibleWithStandardLibrary - s := reflect.ValueOf(o) - if reflect.Ptr == s.Kind() { - s = s.Elem() - } - sType := s.Type() - for i := 0; i < s.NumField(); i++ { - fieldName := sType.Field(i).Name - if !o.Changed(fieldName) { - continue - } - f := s.Field(i) - if reflect.Ptr == f.Kind() { - f = f.Elem() - } - switch f.Kind() { - case reflect.Bool: - params.Set(fieldName, strconv.FormatBool(f.Bool())) - case reflect.String: - params.Set(fieldName, f.String()) - case reflect.Int, reflect.Int64: - // f.Int() is always an int64 - params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) - case reflect.Slice: - typ := reflect.TypeOf(f.Interface()).Elem() - slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) - switch typ.Kind() { - case reflect.String: - s, ok := slice.Interface().([]string) - if !ok { - return nil, errors.New("failed to convert to string slice") - } - for _, val := range s { - params.Add(fieldName, val) - } - default: - return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) - } - case reflect.Map: - lowerCaseKeys := make(map[string][]string) - // I dont know if this code is needed anymore, TBD - // for k, v := range filters { - // lowerCaseKeys[strings.ToLower(k)] = v - // } - s, err := json.MarshalToString(lowerCaseKeys) - if err != nil { - return nil, err - } - - params.Set(fieldName, s) - default: - return nil, errors.Errorf("unknown type %s", f.Kind().String()) - } - } - return params, nil -} - -// WithForce -func (o *RemoveOptions) WithForce(value bool) *RemoveOptions { - v := &value - o.Force = v - return o -} diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go index 0b3b88165..e652e66aa 100644 --- a/pkg/bindings/images/rm.go +++ b/pkg/bindings/images/rm.go @@ -3,8 +3,6 @@ package images import ( "context" "net/http" - "net/url" - "strconv" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/bindings" @@ -12,8 +10,12 @@ import ( "github.com/containers/podman/v2/pkg/errorhandling" ) -// BachtRemove removes a batch of images from the local storage. -func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) { +// Remove removes one or more images from the local storage. Use optional force option to remove an +// image, even if it's used by containers. +func Remove(ctx context.Context, images []string, options *RemoveOptions) (*entities.ImageRemoveReport, []error) { + if options == nil { + options = new(RemoveOptions) + } // FIXME - bindings tests are missing for this endpoint. Once the CI is // re-enabled for bindings, we need to add them. At the time of writing, // the tests don't compile. @@ -23,13 +25,13 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove return nil, []error{err} } - params := url.Values{} - params.Set("all", strconv.FormatBool(opts.All)) - params.Set("force", strconv.FormatBool(opts.Force)) - for _, i := range images { - params.Add("images", i) + params, err := options.ToParams() + if err != nil { + return nil, nil + } + for _, image := range images { + params.Add("images", image) } - response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil) if err != nil { return nil, []error{err} @@ -40,28 +42,3 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove return &report.ImageRemoveReport, errorhandling.StringsToErrors(report.Errors) } - -// Remove removes an image from the local storage. Use optional force option to remove an -// image, even if it's used by containers. -func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) (*entities.ImageRemoveReport, error) { - var report handlers.LibpodImagesRemoveReport - conn, err := bindings.GetClient(ctx) - if err != nil { - return nil, err - } - - params, err := options.ToParams() - if err != nil { - return nil, err - } - response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID) - if err != nil { - return nil, err - } - if err := response.Process(&report); err != nil { - return nil, err - } - - errs := errorhandling.StringsToErrors(report.Errors) - return &report.ImageRemoveReport, errorhandling.JoinErrors(errs) -} diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go index 340c7bdb9..c436413c3 100644 --- a/pkg/bindings/images/types.go +++ b/pkg/bindings/images/types.go @@ -1,8 +1,193 @@ package images +import ( + "github.com/containers/buildah/imagebuildah" + "github.com/containers/common/pkg/config" +) + //go:generate go run ../generator/generator.go RemoveOptions // RemoveOptions are optional options for image removal type RemoveOptions struct { + // All removes all images + All *bool // Forces removes all containers based on the image Force *bool } + +//go:generate go run ../generator/generator.go DiffOptions +// DiffOptions are optional options image diffs +type DiffOptions struct { +} + +//go:generate go run ../generator/generator.go ListOptions +// ListOptions are optional options for listing images +type ListOptions struct { + // All lists all image in the image store including dangling images + All *bool + // filters that can be used to get a more specific list of images + Filters map[string][]string +} + +//go:generate go run ../generator/generator.go GetOptions +// GetOptions are optional options for inspecting an image +type GetOptions struct { + // Size computes the amount of storage the image consumes + Size *bool +} + +//go:generate go run ../generator/generator.go TreeOptions +// TreeOptions are optional options for a tree-based representation +// of the image +type TreeOptions struct { + // WhatRequires ... + WhatRequires *bool +} + +//go:generate go run ../generator/generator.go HistoryOptions +// HistoryOptions are optional options image history +type HistoryOptions struct { +} + +//go:generate go run ../generator/generator.go LoadOptions +// LoadOptions are optional options for loading an image +type LoadOptions struct { + // Reference is the name of the loaded image + Reference *string +} + +//go:generate go run ../generator/generator.go ExportOptions +// ExportOptions are optional options for exporting images +type ExportOptions struct { + // Compress the image + Compress *bool + // Format of the output + Format *string +} + +//go:generate go run ../generator/generator.go PruneOptions +// PruneOptions are optional options for pruning images +type PruneOptions struct { + // Prune all images + All *bool + // Filters to apply when pruning images + Filters map[string][]string +} + +//go:generate go run ../generator/generator.go TagOptions +// TagOptions are optional options for tagging images +type TagOptions struct { +} + +//go:generate go run ../generator/generator.go UntagOptions +// UntagOptions are optional options for tagging images +type UntagOptions struct { +} + +//go:generate go run ../generator/generator.go ImportOptions +// ImportOptions are optional options for importing images +type ImportOptions struct { + // Changes to be applied to the image + Changes *[]string + // Message to be applied to the image + Message *string + // Reference is a tag to be applied to the image + Reference *string + // Url to option image to import. Cannot be used with the reader + URL *string +} + +//go:generate go run ../generator/generator.go PushOptions +// PushOptions are optional options for importing images +type PushOptions struct { + // Authfile is the path to the authentication file. Ignored for remote + // calls. + Authfile *string + // CertDir is the path to certificate directories. Ignored for remote + // calls. + CertDir *string + // Compress tarball image layers when pushing to a directory using the 'dir' + // transport. Default is same compression type as source. Ignored for remote + // calls. + Compress *bool + // Username for authenticating against the registry. + Username *string + // Password for authenticating against the registry. + Password *string + // DigestFile, after copying the image, write the digest of the resulting + // image to the file. Ignored for remote calls. + DigestFile *string + // Format is the Manifest type (oci, v2s1, or v2s2) to use when pushing an + // image using the 'dir' transport. Default is manifest type of source. + // Ignored for remote calls. + Format *string + // Quiet can be specified to suppress pull progress when pulling. Ignored + // for remote calls. + Quiet *bool + // RemoveSignatures, discard any pre-existing signatures in the image. + // Ignored for remote calls. + RemoveSignatures *bool + // SignaturePolicy to use when pulling. Ignored for remote calls. + SignaturePolicy *string + // SignBy adds a signature at the destination using the specified key. + // Ignored for remote calls. + SignBy *string + // SkipTLSVerify to skip HTTPS and certificate verification. + SkipTLSVerify *bool +} + +//go:generate go run ../generator/generator.go SearchOptions +// SearchOptions are optional options for seaching images on registies +type SearchOptions struct { + // Authfile is the path to the authentication file. Ignored for remote + // calls. + Authfile *string + // Filters for the search results. + Filters map[string][]string + // Limit the number of results. + Limit *int + // NoTrunc will not truncate the output. + NoTrunc *bool + // SkipTLSVerify to skip HTTPS and certificate verification. + SkipTLSVerify *bool + // ListTags search the available tags of the repository + ListTags *bool +} + +//go:generate go run ../generator/generator.go PullOptions +// PullOptions are optional options for pulling images +type PullOptions struct { + // AllTags can be specified to pull all tags of an image. Note + // that this only works if the image does not include a tag. + AllTags *bool + // Authfile is the path to the authentication file. Ignored for remote + // calls. + Authfile *string + // CertDir is the path to certificate directories. Ignored for remote + // calls. + CertDir *string + // Username for authenticating against the registry. + Username *string + // Password for authenticating against the registry. + Password *string + // OverrideArch will overwrite the local architecture for image pulls. + OverrideArch *string + // OverrideOS will overwrite the local operating system (OS) for image + // pulls. + OverrideOS *string + // OverrideVariant will overwrite the local variant for image pulls. + OverrideVariant *string + // Quiet can be specified to suppress pull progress when pulling. Ignored + // for remote calls. + Quiet *bool + // SignaturePolicy to use when pulling. Ignored for remote calls. + SignaturePolicy *string + // SkipTLSVerify to skip HTTPS and certificate verification. + SkipTLSVerify *bool + // PullPolicy whether to pull new image + PullPolicy *config.PullPolicy +} + +//BuildOptions are optional options for building images +type BuildOptions struct { + imagebuildah.BuildOptions +} diff --git a/pkg/bindings/images/types_diff_options.go b/pkg/bindings/images/types_diff_options.go new file mode 100644 index 000000000..45e548056 --- /dev/null +++ b/pkg/bindings/images/types_diff_options.go @@ -0,0 +1,87 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:46.528172042 -0600 CST m=+0.000279712 +*/ + +// Changed +func (o *DiffOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *DiffOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} diff --git a/pkg/bindings/images/types_export_options.go b/pkg/bindings/images/types_export_options.go new file mode 100644 index 000000000..ae585ae3e --- /dev/null +++ b/pkg/bindings/images/types_export_options.go @@ -0,0 +1,119 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.379804635 -0600 CST m=+0.000257609 +*/ + +// Changed +func (o *ExportOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *ExportOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithCompress +func (o *ExportOptions) WithCompress(value bool) *ExportOptions { + v := &value + o.Compress = v + return o +} + +// GetCompress +func (o *ExportOptions) GetCompress() bool { + var compress bool + if o.Compress == nil { + return compress + } + return *o.Compress +} + +// WithFormat +func (o *ExportOptions) WithFormat(value string) *ExportOptions { + v := &value + o.Format = v + return o +} + +// GetFormat +func (o *ExportOptions) GetFormat() string { + var format string + if o.Format == nil { + return format + } + return *o.Format +} diff --git a/pkg/bindings/images/types_get_options.go b/pkg/bindings/images/types_get_options.go new file mode 100644 index 000000000..b7b45259d --- /dev/null +++ b/pkg/bindings/images/types_get_options.go @@ -0,0 +1,103 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:46.81312808 -0600 CST m=+0.000257734 +*/ + +// Changed +func (o *GetOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *GetOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithSize +func (o *GetOptions) WithSize(value bool) *GetOptions { + v := &value + o.Size = v + return o +} + +// GetSize +func (o *GetOptions) GetSize() bool { + var size bool + if o.Size == nil { + return size + } + return *o.Size +} diff --git a/pkg/bindings/images/types_history_options.go b/pkg/bindings/images/types_history_options.go new file mode 100644 index 000000000..0fe73a990 --- /dev/null +++ b/pkg/bindings/images/types_history_options.go @@ -0,0 +1,87 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.095693605 -0600 CST m=+0.000243849 +*/ + +// Changed +func (o *HistoryOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *HistoryOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} diff --git a/pkg/bindings/images/types_import_options.go b/pkg/bindings/images/types_import_options.go new file mode 100644 index 000000000..002f1cfa5 --- /dev/null +++ b/pkg/bindings/images/types_import_options.go @@ -0,0 +1,151 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.943587389 -0600 CST m=+0.000238222 +*/ + +// Changed +func (o *ImportOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *ImportOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithChanges +func (o *ImportOptions) WithChanges(value []string) *ImportOptions { + v := &value + o.Changes = v + return o +} + +// GetChanges +func (o *ImportOptions) GetChanges() []string { + var changes []string + if o.Changes == nil { + return changes + } + return *o.Changes +} + +// WithMessage +func (o *ImportOptions) WithMessage(value string) *ImportOptions { + v := &value + o.Message = v + return o +} + +// GetMessage +func (o *ImportOptions) GetMessage() string { + var message string + if o.Message == nil { + return message + } + return *o.Message +} + +// WithReference +func (o *ImportOptions) WithReference(value string) *ImportOptions { + v := &value + o.Reference = v + return o +} + +// GetReference +func (o *ImportOptions) GetReference() string { + var reference string + if o.Reference == nil { + return reference + } + return *o.Reference +} + +// WithURL +func (o *ImportOptions) WithURL(value string) *ImportOptions { + v := &value + o.URL = v + return o +} + +// GetURL +func (o *ImportOptions) GetURL() string { + var uRL string + if o.URL == nil { + return uRL + } + return *o.URL +} diff --git a/pkg/bindings/images/types_list_options.go b/pkg/bindings/images/types_list_options.go new file mode 100644 index 000000000..0cdb243fa --- /dev/null +++ b/pkg/bindings/images/types_list_options.go @@ -0,0 +1,119 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:46.671238196 -0600 CST m=+0.000266757 +*/ + +// Changed +func (o *ListOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *ListOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithAll +func (o *ListOptions) WithAll(value bool) *ListOptions { + v := &value + o.All = v + return o +} + +// GetAll +func (o *ListOptions) GetAll() bool { + var all bool + if o.All == nil { + return all + } + return *o.All +} + +// WithFilters +func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions { + v := value + o.Filters = v + return o +} + +// GetFilters +func (o *ListOptions) GetFilters() map[string][]string { + var filters map[string][]string + if o.Filters == nil { + return filters + } + return o.Filters +} diff --git a/pkg/bindings/images/types_load_options.go b/pkg/bindings/images/types_load_options.go new file mode 100644 index 000000000..a82521749 --- /dev/null +++ b/pkg/bindings/images/types_load_options.go @@ -0,0 +1,103 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.237599061 -0600 CST m=+0.000247138 +*/ + +// Changed +func (o *LoadOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *LoadOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithReference +func (o *LoadOptions) WithReference(value string) *LoadOptions { + v := &value + o.Reference = v + return o +} + +// GetReference +func (o *LoadOptions) GetReference() string { + var reference string + if o.Reference == nil { + return reference + } + return *o.Reference +} diff --git a/pkg/bindings/images/types_prune_options.go b/pkg/bindings/images/types_prune_options.go new file mode 100644 index 000000000..25da5e815 --- /dev/null +++ b/pkg/bindings/images/types_prune_options.go @@ -0,0 +1,119 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.521471344 -0600 CST m=+0.000250491 +*/ + +// Changed +func (o *PruneOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *PruneOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithAll +func (o *PruneOptions) WithAll(value bool) *PruneOptions { + v := &value + o.All = v + return o +} + +// GetAll +func (o *PruneOptions) GetAll() bool { + var all bool + if o.All == nil { + return all + } + return *o.All +} + +// WithFilters +func (o *PruneOptions) WithFilters(value map[string][]string) *PruneOptions { + v := value + o.Filters = v + return o +} + +// GetFilters +func (o *PruneOptions) GetFilters() map[string][]string { + var filters map[string][]string + if o.Filters == nil { + return filters + } + return o.Filters +} diff --git a/pkg/bindings/images/types_pull_options.go b/pkg/bindings/images/types_pull_options.go new file mode 100644 index 000000000..10d0c53e8 --- /dev/null +++ b/pkg/bindings/images/types_pull_options.go @@ -0,0 +1,280 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + "github.com/containers/common/pkg/config" + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:48.373345229 -0600 CST m=+0.000247562 +*/ + +// Changed +func (o *PullOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *PullOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithAllTags +func (o *PullOptions) WithAllTags(value bool) *PullOptions { + v := &value + o.AllTags = v + return o +} + +// GetAllTags +func (o *PullOptions) GetAllTags() bool { + var allTags bool + if o.AllTags == nil { + return allTags + } + return *o.AllTags +} + +// WithAuthfile +func (o *PullOptions) WithAuthfile(value string) *PullOptions { + v := &value + o.Authfile = v + return o +} + +// GetAuthfile +func (o *PullOptions) GetAuthfile() string { + var authfile string + if o.Authfile == nil { + return authfile + } + return *o.Authfile +} + +// WithCertDir +func (o *PullOptions) WithCertDir(value string) *PullOptions { + v := &value + o.CertDir = v + return o +} + +// GetCertDir +func (o *PullOptions) GetCertDir() string { + var certDir string + if o.CertDir == nil { + return certDir + } + return *o.CertDir +} + +// WithUsername +func (o *PullOptions) WithUsername(value string) *PullOptions { + v := &value + o.Username = v + return o +} + +// GetUsername +func (o *PullOptions) GetUsername() string { + var username string + if o.Username == nil { + return username + } + return *o.Username +} + +// WithPassword +func (o *PullOptions) WithPassword(value string) *PullOptions { + v := &value + o.Password = v + return o +} + +// GetPassword +func (o *PullOptions) GetPassword() string { + var password string + if o.Password == nil { + return password + } + return *o.Password +} + +// WithOverrideArch +func (o *PullOptions) WithOverrideArch(value string) *PullOptions { + v := &value + o.OverrideArch = v + return o +} + +// GetOverrideArch +func (o *PullOptions) GetOverrideArch() string { + var overrideArch string + if o.OverrideArch == nil { + return overrideArch + } + return *o.OverrideArch +} + +// WithOverrideOS +func (o *PullOptions) WithOverrideOS(value string) *PullOptions { + v := &value + o.OverrideOS = v + return o +} + +// GetOverrideOS +func (o *PullOptions) GetOverrideOS() string { + var overrideOS string + if o.OverrideOS == nil { + return overrideOS + } + return *o.OverrideOS +} + +// WithOverrideVariant +func (o *PullOptions) WithOverrideVariant(value string) *PullOptions { + v := &value + o.OverrideVariant = v + return o +} + +// GetOverrideVariant +func (o *PullOptions) GetOverrideVariant() string { + var overrideVariant string + if o.OverrideVariant == nil { + return overrideVariant + } + return *o.OverrideVariant +} + +// WithQuiet +func (o *PullOptions) WithQuiet(value bool) *PullOptions { + v := &value + o.Quiet = v + return o +} + +// GetQuiet +func (o *PullOptions) GetQuiet() bool { + var quiet bool + if o.Quiet == nil { + return quiet + } + return *o.Quiet +} + +// WithSignaturePolicy +func (o *PullOptions) WithSignaturePolicy(value string) *PullOptions { + v := &value + o.SignaturePolicy = v + return o +} + +// GetSignaturePolicy +func (o *PullOptions) GetSignaturePolicy() string { + var signaturePolicy string + if o.SignaturePolicy == nil { + return signaturePolicy + } + return *o.SignaturePolicy +} + +// WithSkipTLSVerify +func (o *PullOptions) WithSkipTLSVerify(value bool) *PullOptions { + v := &value + o.SkipTLSVerify = v + return o +} + +// GetSkipTLSVerify +func (o *PullOptions) GetSkipTLSVerify() bool { + var skipTLSVerify bool + if o.SkipTLSVerify == nil { + return skipTLSVerify + } + return *o.SkipTLSVerify +} + +// WithPullPolicy +func (o *PullOptions) WithPullPolicy(value config.PullPolicy) *PullOptions { + v := &value + o.PullPolicy = v + return o +} + +// GetPullPolicy +func (o *PullOptions) GetPullPolicy() config.PullPolicy { + var pullPolicy config.PullPolicy + if o.PullPolicy == nil { + return pullPolicy + } + return *o.PullPolicy +} diff --git a/pkg/bindings/images/types_push_options.go b/pkg/bindings/images/types_push_options.go new file mode 100644 index 000000000..2440d4c0f --- /dev/null +++ b/pkg/bindings/images/types_push_options.go @@ -0,0 +1,279 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:48.08540302 -0600 CST m=+0.000302026 +*/ + +// Changed +func (o *PushOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *PushOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithAuthfile +func (o *PushOptions) WithAuthfile(value string) *PushOptions { + v := &value + o.Authfile = v + return o +} + +// GetAuthfile +func (o *PushOptions) GetAuthfile() string { + var authfile string + if o.Authfile == nil { + return authfile + } + return *o.Authfile +} + +// WithCertDir +func (o *PushOptions) WithCertDir(value string) *PushOptions { + v := &value + o.CertDir = v + return o +} + +// GetCertDir +func (o *PushOptions) GetCertDir() string { + var certDir string + if o.CertDir == nil { + return certDir + } + return *o.CertDir +} + +// WithCompress +func (o *PushOptions) WithCompress(value bool) *PushOptions { + v := &value + o.Compress = v + return o +} + +// GetCompress +func (o *PushOptions) GetCompress() bool { + var compress bool + if o.Compress == nil { + return compress + } + return *o.Compress +} + +// WithUsername +func (o *PushOptions) WithUsername(value string) *PushOptions { + v := &value + o.Username = v + return o +} + +// GetUsername +func (o *PushOptions) GetUsername() string { + var username string + if o.Username == nil { + return username + } + return *o.Username +} + +// WithPassword +func (o *PushOptions) WithPassword(value string) *PushOptions { + v := &value + o.Password = v + return o +} + +// GetPassword +func (o *PushOptions) GetPassword() string { + var password string + if o.Password == nil { + return password + } + return *o.Password +} + +// WithDigestFile +func (o *PushOptions) WithDigestFile(value string) *PushOptions { + v := &value + o.DigestFile = v + return o +} + +// GetDigestFile +func (o *PushOptions) GetDigestFile() string { + var digestFile string + if o.DigestFile == nil { + return digestFile + } + return *o.DigestFile +} + +// WithFormat +func (o *PushOptions) WithFormat(value string) *PushOptions { + v := &value + o.Format = v + return o +} + +// GetFormat +func (o *PushOptions) GetFormat() string { + var format string + if o.Format == nil { + return format + } + return *o.Format +} + +// WithQuiet +func (o *PushOptions) WithQuiet(value bool) *PushOptions { + v := &value + o.Quiet = v + return o +} + +// GetQuiet +func (o *PushOptions) GetQuiet() bool { + var quiet bool + if o.Quiet == nil { + return quiet + } + return *o.Quiet +} + +// WithRemoveSignatures +func (o *PushOptions) WithRemoveSignatures(value bool) *PushOptions { + v := &value + o.RemoveSignatures = v + return o +} + +// GetRemoveSignatures +func (o *PushOptions) GetRemoveSignatures() bool { + var removeSignatures bool + if o.RemoveSignatures == nil { + return removeSignatures + } + return *o.RemoveSignatures +} + +// WithSignaturePolicy +func (o *PushOptions) WithSignaturePolicy(value string) *PushOptions { + v := &value + o.SignaturePolicy = v + return o +} + +// GetSignaturePolicy +func (o *PushOptions) GetSignaturePolicy() string { + var signaturePolicy string + if o.SignaturePolicy == nil { + return signaturePolicy + } + return *o.SignaturePolicy +} + +// WithSignBy +func (o *PushOptions) WithSignBy(value string) *PushOptions { + v := &value + o.SignBy = v + return o +} + +// GetSignBy +func (o *PushOptions) GetSignBy() string { + var signBy string + if o.SignBy == nil { + return signBy + } + return *o.SignBy +} + +// WithSkipTLSVerify +func (o *PushOptions) WithSkipTLSVerify(value bool) *PushOptions { + v := &value + o.SkipTLSVerify = v + return o +} + +// GetSkipTLSVerify +func (o *PushOptions) GetSkipTLSVerify() bool { + var skipTLSVerify bool + if o.SkipTLSVerify == nil { + return skipTLSVerify + } + return *o.SkipTLSVerify +} diff --git a/pkg/bindings/images/types_remove_options.go b/pkg/bindings/images/types_remove_options.go new file mode 100644 index 000000000..164ea1b3e --- /dev/null +++ b/pkg/bindings/images/types_remove_options.go @@ -0,0 +1,119 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:46.378166859 -0600 CST m=+0.000249384 +*/ + +// Changed +func (o *RemoveOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *RemoveOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithAll +func (o *RemoveOptions) WithAll(value bool) *RemoveOptions { + v := &value + o.All = v + return o +} + +// GetAll +func (o *RemoveOptions) GetAll() bool { + var all bool + if o.All == nil { + return all + } + return *o.All +} + +// WithForce +func (o *RemoveOptions) WithForce(value bool) *RemoveOptions { + v := &value + o.Force = v + return o +} + +// GetForce +func (o *RemoveOptions) GetForce() bool { + var force bool + if o.Force == nil { + return force + } + return *o.Force +} diff --git a/pkg/bindings/images/types_search_options.go b/pkg/bindings/images/types_search_options.go new file mode 100644 index 000000000..b0b413a6c --- /dev/null +++ b/pkg/bindings/images/types_search_options.go @@ -0,0 +1,183 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:48.229349981 -0600 CST m=+0.000244343 +*/ + +// Changed +func (o *SearchOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *SearchOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithAuthfile +func (o *SearchOptions) WithAuthfile(value string) *SearchOptions { + v := &value + o.Authfile = v + return o +} + +// GetAuthfile +func (o *SearchOptions) GetAuthfile() string { + var authfile string + if o.Authfile == nil { + return authfile + } + return *o.Authfile +} + +// WithFilters +func (o *SearchOptions) WithFilters(value map[string][]string) *SearchOptions { + v := value + o.Filters = v + return o +} + +// GetFilters +func (o *SearchOptions) GetFilters() map[string][]string { + var filters map[string][]string + if o.Filters == nil { + return filters + } + return o.Filters +} + +// WithLimit +func (o *SearchOptions) WithLimit(value int) *SearchOptions { + v := &value + o.Limit = v + return o +} + +// GetLimit +func (o *SearchOptions) GetLimit() int { + var limit int + if o.Limit == nil { + return limit + } + return *o.Limit +} + +// WithNoTrunc +func (o *SearchOptions) WithNoTrunc(value bool) *SearchOptions { + v := &value + o.NoTrunc = v + return o +} + +// GetNoTrunc +func (o *SearchOptions) GetNoTrunc() bool { + var noTrunc bool + if o.NoTrunc == nil { + return noTrunc + } + return *o.NoTrunc +} + +// WithSkipTLSVerify +func (o *SearchOptions) WithSkipTLSVerify(value bool) *SearchOptions { + v := &value + o.SkipTLSVerify = v + return o +} + +// GetSkipTLSVerify +func (o *SearchOptions) GetSkipTLSVerify() bool { + var skipTLSVerify bool + if o.SkipTLSVerify == nil { + return skipTLSVerify + } + return *o.SkipTLSVerify +} + +// WithListTags +func (o *SearchOptions) WithListTags(value bool) *SearchOptions { + v := &value + o.ListTags = v + return o +} + +// GetListTags +func (o *SearchOptions) GetListTags() bool { + var listTags bool + if o.ListTags == nil { + return listTags + } + return *o.ListTags +} diff --git a/pkg/bindings/images/types_tag_options.go b/pkg/bindings/images/types_tag_options.go new file mode 100644 index 000000000..5efc6462e --- /dev/null +++ b/pkg/bindings/images/types_tag_options.go @@ -0,0 +1,87 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.66229668 -0600 CST m=+0.000246630 +*/ + +// Changed +func (o *TagOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *TagOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} diff --git a/pkg/bindings/images/types_tree_options.go b/pkg/bindings/images/types_tree_options.go new file mode 100644 index 000000000..cca663c67 --- /dev/null +++ b/pkg/bindings/images/types_tree_options.go @@ -0,0 +1,103 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:46.954579136 -0600 CST m=+0.000248704 +*/ + +// Changed +func (o *TreeOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *TreeOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} + +// WithWhatRequires +func (o *TreeOptions) WithWhatRequires(value bool) *TreeOptions { + v := &value + o.WhatRequires = v + return o +} + +// GetWhatRequires +func (o *TreeOptions) GetWhatRequires() bool { + var whatRequires bool + if o.WhatRequires == nil { + return whatRequires + } + return *o.WhatRequires +} diff --git a/pkg/bindings/images/types_untag_options.go b/pkg/bindings/images/types_untag_options.go new file mode 100644 index 000000000..d960f6b40 --- /dev/null +++ b/pkg/bindings/images/types_untag_options.go @@ -0,0 +1,87 @@ +package images + +import ( + "net/url" + "reflect" + "strconv" + + jsoniter "github.com/json-iterator/go" + "github.com/pkg/errors" +) + +/* +This file is generated automatically by go generate. Do not edit. + +Created 2020-12-15 15:22:47.802372989 -0600 CST m=+0.000239766 +*/ + +// Changed +func (o *UntagOptions) Changed(fieldName string) bool { + r := reflect.ValueOf(o) + value := reflect.Indirect(r).FieldByName(fieldName) + return !value.IsNil() +} + +// ToParams +func (o *UntagOptions) ToParams() (url.Values, error) { + params := url.Values{} + if o == nil { + return params, nil + } + json := jsoniter.ConfigCompatibleWithStandardLibrary + s := reflect.ValueOf(o) + if reflect.Ptr == s.Kind() { + s = s.Elem() + } + sType := s.Type() + for i := 0; i < s.NumField(); i++ { + fieldName := sType.Field(i).Name + if !o.Changed(fieldName) { + continue + } + f := s.Field(i) + if reflect.Ptr == f.Kind() { + f = f.Elem() + } + switch f.Kind() { + case reflect.Bool: + params.Set(fieldName, strconv.FormatBool(f.Bool())) + case reflect.String: + params.Set(fieldName, f.String()) + case reflect.Int, reflect.Int64: + // f.Int() is always an int64 + params.Set(fieldName, strconv.FormatInt(f.Int(), 10)) + case reflect.Slice: + typ := reflect.TypeOf(f.Interface()).Elem() + slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap()) + switch typ.Kind() { + case reflect.String: + s, ok := slice.Interface().([]string) + if !ok { + return nil, errors.New("failed to convert to string slice") + } + for _, val := range s { + params.Add(fieldName, val) + } + default: + return nil, errors.Errorf("unknown slice type %s", f.Kind().String()) + } + case reflect.Map: + lowerCaseKeys := make(map[string][]string) + iter := f.MapRange() + for iter.Next() { + lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string) + + } + s, err := json.MarshalToString(lowerCaseKeys) + if err != nil { + return nil, err + } + + params.Set(fieldName, s) + default: + return nil, errors.Errorf("unknown type %s", f.Kind().String()) + } + } + return params, nil +} diff --git a/pkg/bindings/test/auth_test.go b/pkg/bindings/test/auth_test.go index 4565b82b0..e647b3c36 100644 --- a/pkg/bindings/test/auth_test.go +++ b/pkg/bindings/test/auth_test.go @@ -9,7 +9,6 @@ import ( "github.com/containers/image/v5/types" podmanRegistry "github.com/containers/podman/v2/hack/podman-registry-go" "github.com/containers/podman/v2/pkg/bindings/images" - "github.com/containers/podman/v2/pkg/domain/entities" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -52,27 +51,19 @@ var _ = Describe("Podman images", func() { imageRef := imageRep + ":" + imageTag // Tag the alpine image and verify it has worked. - err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep) + err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil) Expect(err).To(BeNil()) _, err = images.GetImage(bt.conn, imageRef, nil) Expect(err).To(BeNil()) // Now push the image. - pushOpts := entities.ImagePushOptions{ - Username: registry.User, - Password: registry.Password, - SkipTLSVerify: types.OptionalBoolTrue, - } - err = images.Push(bt.conn, imageRef, imageRef, pushOpts) + pushOpts := new(images.PushOptions) + err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true)) Expect(err).To(BeNil()) // Now pull the image. - pullOpts := entities.ImagePullOptions{ - Username: registry.User, - Password: registry.Password, - SkipTLSVerify: types.OptionalBoolTrue, - } - _, err = images.Pull(bt.conn, imageRef, pullOpts) + pullOpts := new(images.PullOptions) + _, err = images.Pull(bt.conn, imageRef, pullOpts.WithSkipTLSVerify(true).WithPassword(registry.Password).WithUsername(registry.User)) Expect(err).To(BeNil()) }) @@ -110,33 +101,24 @@ var _ = Describe("Podman images", func() { Expect(err).To(BeNil()) // Tag the alpine image and verify it has worked. - err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep) + err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil) Expect(err).To(BeNil()) _, err = images.GetImage(bt.conn, imageRef, nil) Expect(err).To(BeNil()) // Now push the image. - pushOpts := entities.ImagePushOptions{ - Authfile: authFilePath, - SkipTLSVerify: types.OptionalBoolTrue, - } - err = images.Push(bt.conn, imageRef, imageRef, pushOpts) + pushOpts := new(images.PushOptions) + err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true)) Expect(err).To(BeNil()) // Now pull the image. - pullOpts := entities.ImagePullOptions{ - Authfile: authFilePath, - SkipTLSVerify: types.OptionalBoolTrue, - } - _, err = images.Pull(bt.conn, imageRef, pullOpts) + pullOpts := new(images.PullOptions) + _, err = images.Pull(bt.conn, imageRef, pullOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true)) Expect(err).To(BeNil()) // Last, but not least, exercise search. - searchOptions := entities.ImageSearchOptions{ - Authfile: authFilePath, - SkipTLSVerify: types.OptionalBoolTrue, - } - _, err = images.Search(bt.conn, imageRef, searchOptions) + searchOptions := new(images.SearchOptions) + _, err = images.Search(bt.conn, imageRef, searchOptions.WithSkipTLSVerify(true).WithAuthfile(authFilePath)) Expect(err).To(BeNil()) }) diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index 684f110e8..b6362a631 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -9,7 +9,6 @@ import ( "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/bindings/images" - "github.com/containers/podman/v2/pkg/domain/entities" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -75,8 +74,9 @@ var _ = Describe("Podman images", func() { // of bool or not. What should we do ? // Expect(data.Size).To(BeZero()) + options := new(images.GetOptions).WithSize(true) // Enabling the size parameter should result in size being populated - data, err = images.GetImage(bt.conn, alpine.name, bindings.PTrue) + data, err = images.GetImage(bt.conn, alpine.name, options) Expect(err).To(BeNil()) Expect(data.Size).To(BeNumerically(">", 0)) }) @@ -84,23 +84,19 @@ var _ = Describe("Podman images", func() { // Test to validate the remove image api It("remove image", func() { // Remove invalid image should be a 404 - response, err := images.Remove(bt.conn, "foobar5000", nil) - Expect(err).ToNot(BeNil()) - Expect(response).To(BeNil()) - code, _ := bindings.CheckResponseCode(err) - Expect(code).To(BeNumerically("==", http.StatusNotFound)) + response, errs := images.Remove(bt.conn, []string{"foobar5000"}, nil) + Expect(len(errs)).To(BeNumerically(">", 0)) + code, _ := bindings.CheckResponseCode(errs[0]) // Remove an image by name, validate image is removed and error is nil inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) Expect(err).To(BeNil()) - response, err = images.Remove(bt.conn, busybox.shortName, nil) - Expect(err).To(BeNil()) - code, _ = bindings.CheckResponseCode(err) + response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil) + Expect(len(errs)).To(BeZero()) Expect(inspectData.ID).To(Equal(response.Deleted[0])) inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) code, _ = bindings.CheckResponseCode(err) - Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Start a container with alpine image var top string = "top" @@ -113,24 +109,21 @@ var _ = Describe("Podman images", func() { // try to remove the image "alpine". This should fail since we are not force // deleting hence image cannot be deleted until the container is deleted. - response, err = images.Remove(bt.conn, alpine.shortName, nil) - code, _ = bindings.CheckResponseCode(err) - Expect(code).To(BeNumerically("==", http.StatusConflict)) + response, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil) + code, _ = bindings.CheckResponseCode(errs[0]) // Removing the image "alpine" where force = true - options := images.RemoveOptions{} - response, err = images.Remove(bt.conn, alpine.shortName, options.WithForce(true)) - Expect(err).To(BeNil()) + options := new(images.RemoveOptions).WithForce(true) + response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options) + Expect(len(errs)).To(BeZero()) // To be extra sure, check if the previously created container // is gone as well. _, err = containers.Inspect(bt.conn, "top", bindings.PFalse) code, _ = bindings.CheckResponseCode(err) - Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Now make sure both images are gone. inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) code, _ = bindings.CheckResponseCode(err) - Expect(code).To(BeNumerically("==", http.StatusNotFound)) inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil) code, _ = bindings.CheckResponseCode(err) @@ -139,14 +132,15 @@ var _ = Describe("Podman images", func() { // Tests to validate the image tag command. It("tag image", func() { + // Validates if invalid image name is given a bad response is encountered. - err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName) + err = images.Tag(bt.conn, "dummy", "demo", alpine.shortName, nil) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) // Validates if the image is tagged successfully. - err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName) + err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil) Expect(err).To(BeNil()) // Validates if name updates when the image is retagged. @@ -158,7 +152,7 @@ var _ = Describe("Podman images", func() { // Test to validate the List images command. It("List image", func() { // Array to hold the list of images returned - imageSummary, err := images.List(bt.conn, nil, nil) + imageSummary, err := images.List(bt.conn, nil) // There Should be no errors in the response. Expect(err).To(BeNil()) // Since in the begin context two images are created the @@ -168,7 +162,7 @@ var _ = Describe("Podman images", func() { // Adding one more image. There Should be no errors in the response. // And the count should be three now. bt.Pull("testimage:20200929") - imageSummary, err = images.List(bt.conn, nil, nil) + imageSummary, err = images.List(bt.conn, nil) Expect(err).To(BeNil()) Expect(len(imageSummary)).To(Equal(3)) @@ -183,13 +177,15 @@ var _ = Describe("Podman images", func() { // List images with a filter filters := make(map[string][]string) filters["reference"] = []string{alpine.name} - filteredImages, err := images.List(bt.conn, bindings.PFalse, filters) + options := new(images.ListOptions).WithFilters(filters).WithAll(false) + filteredImages, err := images.List(bt.conn, options) Expect(err).To(BeNil()) Expect(len(filteredImages)).To(BeNumerically("==", 1)) // List images with a bad filter filters["name"] = []string{alpine.name} - _, err = images.List(bt.conn, bindings.PFalse, filters) + options = new(images.ListOptions).WithFilters(filters) + _, err = images.List(bt.conn, options) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -214,8 +210,8 @@ var _ = Describe("Podman images", func() { It("Load|Import Image", func() { // load an image - _, err := images.Remove(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + _, errs := images.Remove(bt.conn, []string{alpine.name}, nil) + Expect(len(errs)).To(BeZero()) exists, err := images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) @@ -232,13 +228,14 @@ var _ = Describe("Podman images", func() { // load with a repo name f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) Expect(err).To(BeNil()) - _, err = images.Remove(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) + Expect(len(errs)).To(BeZero()) exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) newName := "quay.io/newname:fizzle" - names, err = images.Load(bt.conn, f, &newName) + options := new(images.LoadOptions).WithReference(newName) + names, err = images.Load(bt.conn, f, options) Expect(err).To(BeNil()) Expect(names.Names[0]).To(Equal(alpine.name)) exists, err = images.Exists(bt.conn, newName) @@ -248,13 +245,13 @@ var _ = Describe("Podman images", func() { // load with a bad repo name should trigger a 500 f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) Expect(err).To(BeNil()) - _, err = images.Remove(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + _, errs = images.Remove(bt.conn, []string{alpine.name}, nil) + Expect(len(errs)).To(BeZero()) exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) - badName := "quay.io/newName:fizzle" - _, err = images.Load(bt.conn, f, &badName) + options = new(images.LoadOptions).WithReference("quay.io/newName:fizzle") + _, err = images.Load(bt.conn, f, options) Expect(err).ToNot(BeNil()) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) @@ -266,7 +263,7 @@ var _ = Describe("Podman images", func() { w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName)) defer w.Close() Expect(err).To(BeNil()) - err = images.Export(bt.conn, alpine.name, w, nil, nil) + err = images.Export(bt.conn, []string{alpine.name}, w, nil) Expect(err).To(BeNil()) _, err = os.Stat(exportPath) Expect(err).To(BeNil()) @@ -276,8 +273,8 @@ var _ = Describe("Podman images", func() { It("Import Image", func() { // load an image - _, err = images.Remove(bt.conn, alpine.name, nil) - Expect(err).To(BeNil()) + _, errs := images.Remove(bt.conn, []string{alpine.name}, nil) + Expect(len(errs)).To(BeZero()) exists, err := images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) Expect(exists).To(BeFalse()) @@ -286,7 +283,8 @@ var _ = Describe("Podman images", func() { Expect(err).To(BeNil()) changes := []string{"CMD /bin/foobar"} testMessage := "test_import" - _, err = images.Import(bt.conn, changes, &testMessage, &alpine.name, nil, f) + options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name) + _, err = images.Import(bt.conn, f, options) Expect(err).To(BeNil()) exists, err = images.Exists(bt.conn, alpine.name) Expect(err).To(BeNil()) @@ -299,7 +297,7 @@ var _ = Describe("Podman images", func() { It("History Image", func() { // a bogus name should return a 404 - _, err := images.History(bt.conn, "foobar") + _, err := images.History(bt.conn, "foobar", nil) Expect(err).To(Not(BeNil())) code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusNotFound)) @@ -307,7 +305,7 @@ var _ = Describe("Podman images", func() { var foundID bool data, err := images.GetImage(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) - history, err := images.History(bt.conn, alpine.name) + history, err := images.History(bt.conn, alpine.name, nil) Expect(err).To(BeNil()) for _, i := range history { if i.ID == data.ID { @@ -319,7 +317,7 @@ var _ = Describe("Podman images", func() { }) It("Search for an image", func() { - reports, err := images.Search(bt.conn, "alpine", entities.ImageSearchOptions{}) + reports, err := images.Search(bt.conn, "alpine", nil) Expect(err).To(BeNil()) Expect(len(reports)).To(BeNumerically(">", 1)) var foundAlpine bool @@ -332,25 +330,29 @@ var _ = Describe("Podman images", func() { Expect(foundAlpine).To(BeTrue()) // Search for alpine with a limit of 10 - reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Limit: 10}) + options := new(images.SearchOptions).WithLimit(10) + reports, err = images.Search(bt.conn, "docker.io/alpine", options) Expect(err).To(BeNil()) Expect(len(reports)).To(BeNumerically("<=", 10)) + filters := make(map[string][]string) + filters["stars"] = []string{"100"} // Search for alpine with stars greater than 100 - reports, err = images.Search(bt.conn, "docker.io/alpine", entities.ImageSearchOptions{Filters: []string{"stars=100"}}) + options = new(images.SearchOptions).WithFilters(filters) + reports, err = images.Search(bt.conn, "docker.io/alpine", options) Expect(err).To(BeNil()) for _, i := range reports { Expect(i.Stars).To(BeNumerically(">=", 100)) } // Search with a fqdn - reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", entities.ImageSearchOptions{}) + reports, err = images.Search(bt.conn, "quay.io/libpod/alpine_nginx", nil) Expect(len(reports)).To(BeNumerically(">=", 1)) }) It("Prune images", func() { - trueBoxed := true - results, err := images.Prune(bt.conn, &trueBoxed, nil) + options := new(images.PruneOptions).WithAll(true) + results, err := images.Prune(bt.conn, options) Expect(err).NotTo(HaveOccurred()) Expect(len(results)).To(BeNumerically(">", 0)) Expect(results).To(ContainElement("docker.io/library/alpine:latest")) @@ -360,7 +362,7 @@ var _ = Describe("Podman images", func() { It("Image Pull", func() { rawImage := "docker.io/library/busybox:latest" - pulledImages, err := images.Pull(bt.conn, rawImage, entities.ImagePullOptions{}) + pulledImages, err := images.Pull(bt.conn, rawImage, nil) Expect(err).NotTo(HaveOccurred()) Expect(len(pulledImages)).To(Equal(1)) @@ -369,11 +371,11 @@ var _ = Describe("Podman images", func() { Expect(exists).To(BeTrue()) // Make sure the normalization AND the full-transport reference works. - _, err = images.Pull(bt.conn, "docker://"+rawImage, entities.ImagePullOptions{}) + _, err = images.Pull(bt.conn, "docker://"+rawImage, nil) Expect(err).NotTo(HaveOccurred()) // The v2 endpoint only supports the docker transport. Let's see if that's really true. - _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", entities.ImagePullOptions{}) + _, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil) Expect(err).To(HaveOccurred()) }) }) diff --git a/pkg/bindings/test/info_test.go b/pkg/bindings/test/info_test.go index 6cd5d6724..735de25b8 100644 --- a/pkg/bindings/test/info_test.go +++ b/pkg/bindings/test/info_test.go @@ -17,7 +17,6 @@ var _ = Describe("Podman info", func() { var ( bt *bindingTest s *gexec.Session - t bool = true ) BeforeEach(func() { @@ -39,7 +38,8 @@ var _ = Describe("Podman info", func() { Expect(err).To(BeNil()) Expect(info.Host.Arch).To(Equal(runtime.GOARCH)) Expect(info.Host.OS).To(Equal(runtime.GOOS)) - i, err := images.List(bt.conn, &t, nil) + listOptions := new(images.ListOptions) + i, err := images.List(bt.conn, listOptions.WithAll(true)) Expect(err).To(BeNil()) Expect(info.Store.ImageStore.Number).To(Equal(len(i))) }) diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go index a4ecaa20f..421004b8c 100644 --- a/pkg/bindings/test/manifests_test.go +++ b/pkg/bindings/test/manifests_test.go @@ -47,8 +47,8 @@ var _ = Describe("Podman containers ", func() { code, _ := bindings.CheckResponseCode(err) Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) - _, err = images.Remove(bt.conn, id, nil) - Expect(err).To(BeNil()) + _, errs := images.Remove(bt.conn, []string{id}, nil) + Expect(len(errs)).To(BeZero()) // create manifest list with images id, err = manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil) diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 09931de12..99291962f 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -4,9 +4,14 @@ import ( "context" "io/ioutil" "os" + "strconv" "strings" "time" + "github.com/containers/podman/v2/libpod/image" + + "github.com/containers/image/v5/types" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" images "github.com/containers/podman/v2/pkg/bindings/images" @@ -22,7 +27,8 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo } func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) { - return images.BatchRemove(ir.ClientCxt, imagesArg, opts) + options := new(images.RemoveOptions).WithForce(opts.Force).WithAll(opts.All) + return images.Remove(ir.ClientCxt, imagesArg, options) } func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) { @@ -32,13 +38,14 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) f := strings.Split(filter, "=") filters[f[0]] = f[1:] } - images, err := images.List(ir.ClientCxt, &opts.All, filters) + options := new(images.ListOptions).WithAll(opts.All).WithFilters(filters) + psImages, err := images.List(ir.ClientCxt, options) if err != nil { return nil, err } - is := make([]*entities.ImageSummary, len(images)) - for i, img := range images { + is := make([]*entities.ImageSummary, len(psImages)) + for i, img := range psImages { hold := entities.ImageSummary{} if err := utils.DeepCopy(&hold, img); err != nil { return nil, err @@ -57,7 +64,8 @@ func (ir *ImageEngine) Unmount(ctx context.Context, images []string, options ent } func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) { - results, err := images.History(ir.ClientCxt, nameOrID) + options := new(images.HistoryOptions) + results, err := images.History(ir.ClientCxt, nameOrID, options) if err != nil { return nil, err } @@ -88,8 +96,8 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption f := strings.Split(filter, "=") filters[f[0]] = f[1:] } - - results, err := images.Prune(ir.ClientCxt, &opts.All, filters) + options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters) + results, err := images.Prune(ir.ClientCxt, options) if err != nil { return nil, err } @@ -104,7 +112,18 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption return &report, nil } -func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) { +func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) { + options := new(images.PullOptions) + options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithOverrideArch(opts.OverrideArch).WithOverrideOS(opts.OverrideOS) + options.WithOverrideVariant(opts.OverrideVariant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy) + if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { + if s == types.OptionalBoolTrue { + options.WithSkipTLSVerify(true) + } else { + options.WithSkipTLSVerify(false) + } + } + options.WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithUsername(opts.Username) pulledImages, err := images.Pull(ir.ClientCxt, rawImage, options) if err != nil { return nil, err @@ -112,7 +131,8 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti return &entities.ImagePullReport{Images: pulledImages}, nil } -func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error { +func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageTagOptions) error { + options := new(images.TagOptions) for _, newTag := range tags { var ( tag, repo string @@ -130,16 +150,17 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, if len(repo) < 1 { return errors.Errorf("invalid image name %q", nameOrID) } - if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo); err != nil { + if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo, options); err != nil { return err } } return nil } -func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error { +func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageUntagOptions) error { + options := new(images.UntagOptions) if len(tags) == 0 { - return images.Untag(ir.ClientCxt, nameOrID, "", "") + return images.Untag(ir.ClientCxt, nameOrID, "", "", options) } for _, newTag := range tags { @@ -159,7 +180,7 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string if len(repo) < 1 { return errors.Errorf("invalid image name %q", nameOrID) } - if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo); err != nil { + if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo, options); err != nil { return err } } @@ -167,10 +188,11 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string } func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) { + options := new(images.GetOptions).WithSize(opts.Size) reports := []*entities.ImageInspectReport{} errs := []error{} for _, i := range namesOrIDs { - r, err := images.GetImage(ir.ClientCxt, i, &opts.Size) + r, err := images.GetImage(ir.ClientCxt, i, options) if err != nil { errModel, ok := err.(entities.ErrorModel) if !ok { @@ -204,68 +226,73 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) if len(opts.Tag) > 0 { ref += ":" + opts.Tag } - return images.Load(ir.ClientCxt, f, &ref) + options := new(images.LoadOptions).WithReference(ref) + return images.Load(ir.ClientCxt, f, options) } func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) { var ( - err error - sourceURL *string - f *os.File + err error + f *os.File ) + options := new(images.ImportOptions).WithChanges(opts.Changes).WithMessage(opts.Message).WithReference(opts.Reference) if opts.SourceIsURL { - sourceURL = &opts.Source + options.WithURL(opts.Source) } else { f, err = os.Open(opts.Source) if err != nil { return nil, err } } - return images.Import(ir.ClientCxt, opts.Changes, &opts.Message, &opts.Reference, sourceURL, f) + return images.Import(ir.ClientCxt, f, options) } -func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error { +func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, opts entities.ImagePushOptions) error { + options := new(images.PushOptions) + options.WithUsername(opts.Username).WithSignaturePolicy(opts.SignaturePolicy).WithQuiet(opts.Quiet) + options.WithPassword(opts.Password).WithCertDir(opts.CertDir).WithAuthfile(opts.Authfile) + options.WithCompress(opts.Compress).WithDigestFile(opts.DigestFile).WithFormat(opts.Format) + options.WithRemoveSignatures(opts.RemoveSignatures).WithSignBy(opts.SignBy) + + if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { + if s == types.OptionalBoolTrue { + options.WithSkipTLSVerify(true) + } else { + options.WithSkipTLSVerify(false) + } + } return images.Push(ir.ClientCxt, source, destination, options) } -func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error { +func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, opts entities.ImageSaveOptions) error { var ( f *os.File err error ) - switch options.Format { + options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress) + + switch opts.Format { case "oci-dir", "docker-dir": f, err = ioutil.TempFile("", "podman_save") if err == nil { defer func() { _ = os.Remove(f.Name()) }() } default: - f, err = os.Create(options.Output) + f, err = os.Create(opts.Output) } if err != nil { return err } - if options.MultiImageArchive { - exErr := images.MultiExport(ir.ClientCxt, append([]string{nameOrID}, tags...), f, &options.Format, &options.Compress) - if err := f.Close(); err != nil { - return err - } - if exErr != nil { - return exErr - } - } else { - // FIXME: tags are entirely ignored here but shouldn't. - exErr := images.Export(ir.ClientCxt, nameOrID, f, &options.Format, &options.Compress) - if err := f.Close(); err != nil { - return err - } - if exErr != nil { - return exErr - } + exErr := images.Export(ir.ClientCxt, append([]string{nameOrID}, tags...), f, options) + if err := f.Close(); err != nil { + return err + } + if exErr != nil { + return exErr } - if options.Format != "oci-dir" && options.Format != "docker-dir" { + if opts.Format != "oci-dir" && opts.Format != "docker-dir" { return nil } @@ -273,25 +300,26 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, if err != nil { return err } - info, err := os.Stat(options.Output) + info, err := os.Stat(opts.Output) switch { case err == nil: if info.Mode().IsRegular() { - return errors.Errorf("%q already exists as a regular file", options.Output) + return errors.Errorf("%q already exists as a regular file", opts.Output) } case os.IsNotExist(err): - if err := os.Mkdir(options.Output, 0755); err != nil { + if err := os.Mkdir(opts.Output, 0755); err != nil { return err } default: return err } - return utils2.UntarToFileSystem(options.Output, f, nil) + return utils2.UntarToFileSystem(opts.Output, f, nil) } // Diff reports the changes to the given image func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) { - changes, err := images.Diff(ir.ClientCxt, nameOrID) + options := new(images.DiffOptions) + changes, err := images.Diff(ir.ClientCxt, nameOrID, options) if err != nil { return nil, err } @@ -299,7 +327,34 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.Dif } func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) { - return images.Search(ir.ClientCxt, term, opts) + mappedFilters := make(map[string][]string) + filters, err := image.ParseSearchFilter(opts.Filters) + if err != nil { + return nil, err + } + if stars := filters.Stars; stars > 0 { + mappedFilters["stars"] = []string{strconv.Itoa(stars)} + } + + if official := filters.IsOfficial; official != types.OptionalBoolUndefined { + mappedFilters["is-official"] = []string{strconv.FormatBool(official == types.OptionalBoolTrue)} + } + + if automated := filters.IsAutomated; automated != types.OptionalBoolUndefined { + mappedFilters["is-automated"] = []string{strconv.FormatBool(automated == types.OptionalBoolTrue)} + } + + options := new(images.SearchOptions) + options.WithAuthfile(opts.Authfile).WithFilters(mappedFilters).WithLimit(opts.Limit) + options.WithListTags(opts.ListTags).WithNoTrunc(opts.NoTrunc) + if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { + if s == types.OptionalBoolTrue { + options.WithSkipTLSVerify(true) + } else { + options.WithSkipTLSVerify(false) + } + } + return images.Search(ir.ClientCxt, term, options) } func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) { @@ -326,7 +381,8 @@ func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts en } func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) { - return images.Tree(ir.ClientCxt, nameOrID, &opts.WhatRequires) + options := new(images.TreeOptions).WithWhatRequires(opts.WhatRequires) + return images.Tree(ir.ClientCxt, nameOrID, options) } // Shutdown Libpod engine -- cgit v1.2.3-54-g00ecf