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 <bbaude@redhat.com>
This commit is contained in:
baude
2020-12-14 08:52:00 -06:00
parent 0fd31e2994
commit 8d4e19634c
28 changed files with 2525 additions and 347 deletions

View File

@ -5,7 +5,6 @@ registry.fedoraproject.org 443
mirrors.fedoraproject.org 443 mirrors.fedoraproject.org 443
dl.fedoraproject.org 443 dl.fedoraproject.org 443
ewr.edge.kernel.org 443 ewr.edge.kernel.org 443
mirror.chpc.utah.edu 443
mirror.clarkson.edu 443 mirror.clarkson.edu 443
mirror.umd.edu 443 mirror.umd.edu 443
mirror.vcu.edu 443 mirror.vcu.edu 443

View File

@ -265,8 +265,14 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
// Format is mandatory! Currently, we only support multi-image docker // Format is mandatory! Currently, we only support multi-image docker
// archives. // 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 { switch query.Format {
case define.V2s2Archive: case define.V2s2Archive, define.OCIArchive:
tmpfile, err := ioutil.TempFile("", "api.tar") tmpfile, err := ioutil.TempFile("", "api.tar")
if err != nil { if err != nil {
utils.Error(w, "unable to create tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) 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")) utils.Error(w, "unable to close tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return 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: default:
utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format)) utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format))
return return
@ -287,7 +300,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
opts := entities.ImageSaveOptions{ opts := entities.ImageSaveOptions{
Compress: query.Compress, Compress: query.Compress,
Format: query.Format, Format: query.Format,
MultiImageArchive: true, MultiImageArchive: len(query.References) > 1,
Output: output, Output: output,
RemoveSignatures: true, 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 // This is where you can override the golang default value for one of fields
} }
if err := decoder.Decode(&query, r.URL.Query()); err != nil { 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())) utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return return
@ -607,12 +619,12 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
func SearchImages(w http.ResponseWriter, r *http.Request) { func SearchImages(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder) decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct { query := struct {
Term string `json:"term"` Term string `json:"term"`
Limit int `json:"limit"` Limit int `json:"limit"`
NoTrunc bool `json:"noTrunc"` NoTrunc bool `json:"noTrunc"`
Filters []string `json:"filters"` Filters map[string][]string `json:"filters"`
TLSVerify bool `json:"tlsVerify"` TLSVerify bool `json:"tlsVerify"`
ListTags bool `json:"listTags"` ListTags bool `json:"listTags"`
}{ }{
// This is where you can override the golang default value for one of fields // This is where you can override the golang default value for one of fields
} }
@ -622,22 +634,42 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
return 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{ options := image.SearchOptions{
Limit: query.Limit, Limit: query.Limit,
NoTrunc: query.NoTrunc, NoTrunc: query.NoTrunc,
ListTags: query.ListTags, 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 { if _, found := r.URL.Query()["tlsVerify"]; found {
filter, err := image.ParseSearchFilter(query.Filters) options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
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) _, authfile, key, err := auth.GetCredentials(r)
@ -678,10 +710,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
All bool `schema:"all"` All bool `schema:"all"`
Force bool `schema:"force"` Force bool `schema:"force"`
Images []string `schema:"images"` Images []string `schema:"images"`
}{ }{}
All: false,
Force: false,
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil { if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 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} opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force}
imageEngine := abi.ImageEngine{Libpod: runtime} imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts) rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
strErrs := errorhandling.ErrorsToStrings(rmErrors) strErrs := errorhandling.ErrorsToStrings(rmErrors)
report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: strErrs} report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: strErrs}
utils.WriteResponse(w, http.StatusOK, report) utils.WriteResponse(w, http.StatusOK, report)

View File

@ -81,10 +81,11 @@ func (o *{{.StructName}}) ToParams() (url.Values, error) {
} }
case reflect.Map: case reflect.Map:
lowerCaseKeys := make(map[string][]string) lowerCaseKeys := make(map[string][]string)
// I dont know if this code is needed anymore, TBD iter := f.MapRange()
// for k, v := range filters { for iter.Next() {
// lowerCaseKeys[strings.ToLower(k)] = v lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
// }
}
s, err := json.MarshalToString(lowerCaseKeys) s, err := json.MarshalToString(lowerCaseKeys)
if err != nil { if err != nil {
return nil, err return nil, err
@ -102,23 +103,34 @@ func (o *{{.StructName}}) ToParams() (url.Values, error) {
var fieldTmpl = ` var fieldTmpl = `
// With{{.Name}} // With{{.Name}}
func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} { func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} {
v := &value v := {{.TypedValue}}
o.{{.Name}} = v o.{{.Name}} = v
return o return o
} }
// Get{{.Name}}
func(o *{{.StructName}}) Get{{.Name}}() {{.Type}} {
var {{.ZeroName}} {{.Type}}
if o.{{.Name}} == nil {
return {{.ZeroName}}
}
return {{.TypedName}}
}
` `
type fieldStruct struct { type fieldStruct struct {
Name string Name string
StructName string StructName string
Type string Type string
TypedName string
TypedValue string
ZeroName string
} }
func main() { func main() {
var ( var (
closed bool closed bool
fieldStructs []fieldStruct fieldStructs []fieldStruct
structNode ast.Node
) )
srcFile := os.Getenv("GOFILE") srcFile := os.Getenv("GOFILE")
pkg := os.Getenv("GOPACKAGE") pkg := os.Getenv("GOPACKAGE")
@ -132,14 +144,13 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
// always add reflect // always add reflect
imports := []string{"\"reflect\""} imports := []string{"\"reflect\""}
for _, imp := range f.Imports { for _, imp := range f.Imports {
imports = append(imports, imp.Path.Value) 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 { if err != nil {
panic(err) panic(err)
} }
@ -166,26 +177,41 @@ func main() {
ref, refOK := n.(*ast.TypeSpec) ref, refOK := n.(*ast.TypeSpec)
if refOK { if refOK {
if ref.Name.Name == inputStructName { if ref.Name.Name == inputStructName {
structNode = n
x := ref.Type.(*ast.StructType) x := ref.Type.(*ast.StructType)
for _, field := range x.Fields.List { for _, field := range x.Fields.List {
var ( 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 { if len(field.Names) > 0 {
name = field.Names[0].Name name = field.Names[0].Name
if len(name) < 1 { if len(name) < 1 {
panic(errors.New("bad name")) 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{ fStruct := fieldStruct{
Name: name, Name: name,
StructName: inputStructName, StructName: inputStructName,
Type: fieldType, Type: fieldType,
TypedName: typedName,
TypedValue: typedValue,
ZeroName: zeroName,
} }
fieldStructs = append(fieldStructs, fStruct) fieldStructs = append(fieldStructs, fStruct)
} // for } // for

View File

@ -9,7 +9,11 @@ import (
) )
// Diff provides the changes between two container layers // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -8,7 +8,6 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/auth" "github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings" "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 // List returns a list of images in local storage. The all boolean and filters parameters are optional
// ways to alter the image query. // 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 var imageSummary []*entities.ImageSummary
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
if all != nil { if err != nil {
params.Set("all", strconv.FormatBool(*all)) return nil, err
}
if filters != nil {
strFilters, err := bindings.FiltersToString(filters)
if err != nil {
return nil, err
}
params.Set("filters", strFilters)
} }
response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil) response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil)
if err != 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 // Get performs an image inspect. To have the on-disk size of the image calculated, you can
// use the optional size parameter. // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
if size != nil { if err != nil {
params.Set("size", strconv.FormatBool(*size)) return nil, err
} }
inspectedData := entities.ImageInspectReport{} inspectedData := entities.ImageInspectReport{}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID) 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 // 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 var report entities.ImageTreeReport
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
if whatRequires != nil { if err != nil {
params.Set("size", strconv.FormatBool(*whatRequires)) return nil, err
} }
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID) response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID)
if err != nil { 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. // 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 var history []*handlers.HistoryResponse
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
@ -107,15 +112,18 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
return history, response.Process(&history) 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 var report entities.ImageLoadReport
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
if name != nil { if err != nil {
params.Set("reference", *name) return nil, err
} }
response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil) response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil)
if err != nil { if err != nil {
@ -124,19 +132,21 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe
return &report, response.Process(&report) return &report, response.Process(&report)
} }
func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *string, compress *bool) error { // 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)
}
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
params := url.Values{} params, err := options.ToParams()
if format != nil { if err != nil {
params.Set("format", *format) return err
} }
if compress != nil { for _, ref := range nameOrIDs {
params.Set("compress", strconv.FormatBool(*compress))
}
for _, ref := range namesOrIds {
params.Add("references", ref) params.Add("references", ref)
} }
response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil) response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil)
@ -144,33 +154,6 @@ func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *
return err 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)
if err != nil {
return err
}
params := url.Values{}
if format != nil {
params.Set("format", *format)
}
if compress != nil {
params.Set("compress", strconv.FormatBool(*compress))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID)
if err != nil {
return err
}
if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 { if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 {
_, err = io.Copy(w, response.Body) _, err = io.Copy(w, response.Body)
return err 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 // Prune removes unused images from local storage. The optional filters can be used to further
// define which images should be pruned. // 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 ( var (
deleted []string deleted []string
) )
if options == nil {
options = new(PruneOptions)
}
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
if all != nil { if err != nil {
params.Set("all", strconv.FormatBool(*all)) return nil, err
}
if filters != nil {
stringFilter, err := bindings.FiltersToString(filters)
if err != nil {
return nil, err
}
params.Set("filters", stringFilter)
} }
response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil) response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil)
if err != 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. // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err 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. // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err 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 // 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 // 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. // 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 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") return nil, errors.New("url and r parameters cannot be used together")
} }
conn, err := bindings.GetClient(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
for _, change := range changes { if err != nil {
params.Add("changes", change) return nil, err
}
if message != nil {
params.Set("message", *message)
}
if reference != nil {
params.Set("reference", *reference)
}
if u != nil {
params.Set("url", *u)
} }
response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil) response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil)
if err != 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 // 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 // or be normalized to one). Other transports are rejected as they do not make
// sense in a remote context. // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
// TODO: have a global system context we can pass around (1st argument) // 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 { if err != nil {
return err return err
} }
params := url.Values{} params, err := options.ToParams()
params.Set("destination", destination) if err != nil {
if options.SkipTLSVerify != types.OptionalBoolUndefined { return err
// Note: we have to verify if skipped is false.
verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
} }
//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) path := fmt.Sprintf("/images/%s/push", source)
response, err := conn.DoRequest(nil, http.MethodPost, path, params, header) 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. // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
params.Set("term", term) if err != nil {
params.Set("limit", strconv.Itoa(opts.Limit)) return nil, err
params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc))
params.Set("listTags", strconv.FormatBool(opts.ListTags))
for _, f := range opts.Filters {
params.Set("filters", f)
} }
params.Set("term", term)
if opts.SkipTLSVerify != types.OptionalBoolUndefined { // Note: we have to verify if skipped is false.
// Note: we have to verify if skipped is false. if options.SkipTLSVerify != nil {
verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse) params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(verifyTLS)) params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
} }
// TODO: have a global system context we can pass around (1st argument) // 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -8,11 +8,9 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"os" "os"
"strconv" "strconv"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/auth" "github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities" "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 // `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 // normalized to one). Other transports are rejected as they do not make sense
// in a remote context. Progress reported on stderr // 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) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
params := url.Values{} params, err := options.ToParams()
params.Set("reference", rawImage) if err != nil {
params.Set("overrideArch", options.OverrideArch) return nil, err
params.Set("overrideOS", options.OverrideOS) }
params.Set("overrideVariant", options.OverrideVariant) params.Set("reference", rawImage)
if options.SkipTLSVerify != types.OptionalBoolUndefined { if options.SkipTLSVerify != nil {
// Note: we have to verify if skipped is false. params.Del("SkipTLSVerify")
verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse) // Note: we have to verify if skipped is false.
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) // 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 { if err != nil {
return nil, err return nil, err
} }
@ -59,7 +59,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
// Historically pull writes status to stderr // Historically pull writes status to stderr
stderr := io.Writer(os.Stderr) stderr := io.Writer(os.Stderr)
if options.Quiet { if options.GetQuiet() {
stderr = ioutil.Discard stderr = ioutil.Discard
} }

View File

@ -3,8 +3,6 @@ package images
import ( import (
"context" "context"
"net/http" "net/http"
"net/url"
"strconv"
"github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings"
@ -12,8 +10,12 @@ import (
"github.com/containers/podman/v2/pkg/errorhandling" "github.com/containers/podman/v2/pkg/errorhandling"
) )
// BachtRemove removes a batch of images from the local storage. // Remove removes one or more images from the local storage. Use optional force option to remove an
func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) { // 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 // 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, // re-enabled for bindings, we need to add them. At the time of writing,
// the tests don't compile. // the tests don't compile.
@ -23,13 +25,13 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return nil, []error{err} return nil, []error{err}
} }
params := url.Values{} params, err := options.ToParams()
params.Set("all", strconv.FormatBool(opts.All)) if err != nil {
params.Set("force", strconv.FormatBool(opts.Force)) return nil, nil
for _, i := range images { }
params.Add("images", i) for _, image := range images {
params.Add("images", image)
} }
response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil) response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil)
if err != nil { if err != nil {
return nil, []error{err} 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) 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)
}

View File

@ -1,8 +1,193 @@
package images package images
import (
"github.com/containers/buildah/imagebuildah"
"github.com/containers/common/pkg/config"
)
//go:generate go run ../generator/generator.go RemoveOptions //go:generate go run ../generator/generator.go RemoveOptions
// RemoveOptions are optional options for image removal // RemoveOptions are optional options for image removal
type RemoveOptions struct { type RemoveOptions struct {
// All removes all images
All *bool
// Forces removes all containers based on the image // Forces removes all containers based on the image
Force *bool 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
}

View File

@ -12,18 +12,18 @@ import (
/* /*
This file is generated automatically by go generate. Do not edit. This file is generated automatically by go generate. Do not edit.
Created 2020-12-10 12:51:06.090426622 -0600 CST m=+0.000133169 Created 2020-12-15 15:22:46.528172042 -0600 CST m=+0.000279712
*/ */
// Changed // Changed
func (o *RemoveOptions) Changed(fieldName string) bool { func (o *DiffOptions) Changed(fieldName string) bool {
r := reflect.ValueOf(o) r := reflect.ValueOf(o)
value := reflect.Indirect(r).FieldByName(fieldName) value := reflect.Indirect(r).FieldByName(fieldName)
return !value.IsNil() return !value.IsNil()
} }
// ToParams // ToParams
func (o *RemoveOptions) ToParams() (url.Values, error) { func (o *DiffOptions) ToParams() (url.Values, error) {
params := url.Values{} params := url.Values{}
if o == nil { if o == nil {
return params, nil return params, nil
@ -68,10 +68,11 @@ func (o *RemoveOptions) ToParams() (url.Values, error) {
} }
case reflect.Map: case reflect.Map:
lowerCaseKeys := make(map[string][]string) lowerCaseKeys := make(map[string][]string)
// I dont know if this code is needed anymore, TBD iter := f.MapRange()
// for k, v := range filters { for iter.Next() {
// lowerCaseKeys[strings.ToLower(k)] = v lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
// }
}
s, err := json.MarshalToString(lowerCaseKeys) s, err := json.MarshalToString(lowerCaseKeys)
if err != nil { if err != nil {
return nil, err return nil, err
@ -84,10 +85,3 @@ func (o *RemoveOptions) ToParams() (url.Values, error) {
} }
return params, nil return params, nil
} }
// WithForce
func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
v := &value
o.Force = v
return o
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -9,7 +9,6 @@ import (
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
podmanRegistry "github.com/containers/podman/v2/hack/podman-registry-go" podmanRegistry "github.com/containers/podman/v2/hack/podman-registry-go"
"github.com/containers/podman/v2/pkg/bindings/images" "github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/domain/entities"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
@ -52,27 +51,19 @@ var _ = Describe("Podman images", func() {
imageRef := imageRep + ":" + imageTag imageRef := imageRep + ":" + imageTag
// Tag the alpine image and verify it has worked. // 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()) Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil) _, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Now push the image. // Now push the image.
pushOpts := entities.ImagePushOptions{ pushOpts := new(images.PushOptions)
Username: registry.User, err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true))
Password: registry.Password,
SkipTLSVerify: types.OptionalBoolTrue,
}
err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Now pull the image. // Now pull the image.
pullOpts := entities.ImagePullOptions{ pullOpts := new(images.PullOptions)
Username: registry.User, _, err = images.Pull(bt.conn, imageRef, pullOpts.WithSkipTLSVerify(true).WithPassword(registry.Password).WithUsername(registry.User))
Password: registry.Password,
SkipTLSVerify: types.OptionalBoolTrue,
}
_, err = images.Pull(bt.conn, imageRef, pullOpts)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
}) })
@ -110,33 +101,24 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Tag the alpine image and verify it has worked. // 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()) Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil) _, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Now push the image. // Now push the image.
pushOpts := entities.ImagePushOptions{ pushOpts := new(images.PushOptions)
Authfile: authFilePath, err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
SkipTLSVerify: types.OptionalBoolTrue,
}
err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Now pull the image. // Now pull the image.
pullOpts := entities.ImagePullOptions{ pullOpts := new(images.PullOptions)
Authfile: authFilePath, _, err = images.Pull(bt.conn, imageRef, pullOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
SkipTLSVerify: types.OptionalBoolTrue,
}
_, err = images.Pull(bt.conn, imageRef, pullOpts)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Last, but not least, exercise search. // Last, but not least, exercise search.
searchOptions := entities.ImageSearchOptions{ searchOptions := new(images.SearchOptions)
Authfile: authFilePath, _, err = images.Search(bt.conn, imageRef, searchOptions.WithSkipTLSVerify(true).WithAuthfile(authFilePath))
SkipTLSVerify: types.OptionalBoolTrue,
}
_, err = images.Search(bt.conn, imageRef, searchOptions)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
}) })

View File

@ -9,7 +9,6 @@ import (
"github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/images" "github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/domain/entities"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec" "github.com/onsi/gomega/gexec"
@ -75,8 +74,9 @@ var _ = Describe("Podman images", func() {
// of bool or not. What should we do ? // of bool or not. What should we do ?
// Expect(data.Size).To(BeZero()) // Expect(data.Size).To(BeZero())
options := new(images.GetOptions).WithSize(true)
// Enabling the size parameter should result in size being populated // 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(err).To(BeNil())
Expect(data.Size).To(BeNumerically(">", 0)) Expect(data.Size).To(BeNumerically(">", 0))
}) })
@ -84,23 +84,19 @@ var _ = Describe("Podman images", func() {
// Test to validate the remove image api // Test to validate the remove image api
It("remove image", func() { It("remove image", func() {
// Remove invalid image should be a 404 // Remove invalid image should be a 404
response, err := images.Remove(bt.conn, "foobar5000", nil) response, errs := images.Remove(bt.conn, []string{"foobar5000"}, nil)
Expect(err).ToNot(BeNil()) Expect(len(errs)).To(BeNumerically(">", 0))
Expect(response).To(BeNil()) code, _ := bindings.CheckResponseCode(errs[0])
code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Remove an image by name, validate image is removed and error is nil // Remove an image by name, validate image is removed and error is nil
inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil) inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
response, err = images.Remove(bt.conn, busybox.shortName, nil) response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
code, _ = bindings.CheckResponseCode(err)
Expect(inspectData.ID).To(Equal(response.Deleted[0])) Expect(inspectData.ID).To(Equal(response.Deleted[0]))
inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil)
code, _ = bindings.CheckResponseCode(err) code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Start a container with alpine image // Start a container with alpine image
var top string = "top" 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 // 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. // deleting hence image cannot be deleted until the container is deleted.
response, err = images.Remove(bt.conn, alpine.shortName, nil) response, errs = images.Remove(bt.conn, []string{alpine.shortName}, nil)
code, _ = bindings.CheckResponseCode(err) code, _ = bindings.CheckResponseCode(errs[0])
Expect(code).To(BeNumerically("==", http.StatusConflict))
// Removing the image "alpine" where force = true // Removing the image "alpine" where force = true
options := images.RemoveOptions{} options := new(images.RemoveOptions).WithForce(true)
response, err = images.Remove(bt.conn, alpine.shortName, options.WithForce(true)) response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
// To be extra sure, check if the previously created container // To be extra sure, check if the previously created container
// is gone as well. // is gone as well.
_, err = containers.Inspect(bt.conn, "top", bindings.PFalse) _, err = containers.Inspect(bt.conn, "top", bindings.PFalse)
code, _ = bindings.CheckResponseCode(err) code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Now make sure both images are gone. // Now make sure both images are gone.
inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil) inspectData, err = images.GetImage(bt.conn, busybox.shortName, nil)
code, _ = bindings.CheckResponseCode(err) code, _ = bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound))
inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil) inspectData, err = images.GetImage(bt.conn, alpine.shortName, nil)
code, _ = bindings.CheckResponseCode(err) code, _ = bindings.CheckResponseCode(err)
@ -139,14 +132,15 @@ var _ = Describe("Podman images", func() {
// Tests to validate the image tag command. // Tests to validate the image tag command.
It("tag image", func() { It("tag image", func() {
// Validates if invalid image name is given a bad response is encountered. // 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()) Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err) code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound)) Expect(code).To(BeNumerically("==", http.StatusNotFound))
// Validates if the image is tagged successfully. // 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()) Expect(err).To(BeNil())
// Validates if name updates when the image is retagged. // 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. // Test to validate the List images command.
It("List image", func() { It("List image", func() {
// Array to hold the list of images returned // 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. // There Should be no errors in the response.
Expect(err).To(BeNil()) Expect(err).To(BeNil())
// Since in the begin context two images are created the // 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. // Adding one more image. There Should be no errors in the response.
// And the count should be three now. // And the count should be three now.
bt.Pull("testimage:20200929") bt.Pull("testimage:20200929")
imageSummary, err = images.List(bt.conn, nil, nil) imageSummary, err = images.List(bt.conn, nil)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(len(imageSummary)).To(Equal(3)) Expect(len(imageSummary)).To(Equal(3))
@ -183,13 +177,15 @@ var _ = Describe("Podman images", func() {
// List images with a filter // List images with a filter
filters := make(map[string][]string) filters := make(map[string][]string)
filters["reference"] = []string{alpine.name} 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(err).To(BeNil())
Expect(len(filteredImages)).To(BeNumerically("==", 1)) Expect(len(filteredImages)).To(BeNumerically("==", 1))
// List images with a bad filter // List images with a bad filter
filters["name"] = []string{alpine.name} 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()) Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err) code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@ -214,8 +210,8 @@ var _ = Describe("Podman images", func() {
It("Load|Import Image", func() { It("Load|Import Image", func() {
// load an image // load an image
_, err := images.Remove(bt.conn, alpine.name, nil) _, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name) exists, err := images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(exists).To(BeFalse()) Expect(exists).To(BeFalse())
@ -232,13 +228,14 @@ var _ = Describe("Podman images", func() {
// load with a repo name // load with a repo name
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = images.Remove(bt.conn, alpine.name, nil) _, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name) exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(exists).To(BeFalse()) Expect(exists).To(BeFalse())
newName := "quay.io/newname:fizzle" 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(err).To(BeNil())
Expect(names.Names[0]).To(Equal(alpine.name)) Expect(names.Names[0]).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, newName) 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 // load with a bad repo name should trigger a 500
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName)) f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
Expect(err).To(BeNil()) Expect(err).To(BeNil())
_, err = images.Remove(bt.conn, alpine.name, nil) _, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name) exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(exists).To(BeFalse()) Expect(exists).To(BeFalse())
badName := "quay.io/newName:fizzle" options = new(images.LoadOptions).WithReference("quay.io/newName:fizzle")
_, err = images.Load(bt.conn, f, &badName) _, err = images.Load(bt.conn, f, options)
Expect(err).ToNot(BeNil()) Expect(err).ToNot(BeNil())
code, _ := bindings.CheckResponseCode(err) code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) 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)) w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName))
defer w.Close() defer w.Close()
Expect(err).To(BeNil()) 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()) Expect(err).To(BeNil())
_, err = os.Stat(exportPath) _, err = os.Stat(exportPath)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -276,8 +273,8 @@ var _ = Describe("Podman images", func() {
It("Import Image", func() { It("Import Image", func() {
// load an image // load an image
_, err = images.Remove(bt.conn, alpine.name, nil) _, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name) exists, err := images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(exists).To(BeFalse()) Expect(exists).To(BeFalse())
@ -286,7 +283,8 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
changes := []string{"CMD /bin/foobar"} changes := []string{"CMD /bin/foobar"}
testMessage := "test_import" 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()) Expect(err).To(BeNil())
exists, err = images.Exists(bt.conn, alpine.name) exists, err = images.Exists(bt.conn, alpine.name)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -299,7 +297,7 @@ var _ = Describe("Podman images", func() {
It("History Image", func() { It("History Image", func() {
// a bogus name should return a 404 // 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())) Expect(err).To(Not(BeNil()))
code, _ := bindings.CheckResponseCode(err) code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusNotFound)) Expect(code).To(BeNumerically("==", http.StatusNotFound))
@ -307,7 +305,7 @@ var _ = Describe("Podman images", func() {
var foundID bool var foundID bool
data, err := images.GetImage(bt.conn, alpine.name, nil) data, err := images.GetImage(bt.conn, alpine.name, nil)
Expect(err).To(BeNil()) 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()) Expect(err).To(BeNil())
for _, i := range history { for _, i := range history {
if i.ID == data.ID { if i.ID == data.ID {
@ -319,7 +317,7 @@ var _ = Describe("Podman images", func() {
}) })
It("Search for an image", 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(err).To(BeNil())
Expect(len(reports)).To(BeNumerically(">", 1)) Expect(len(reports)).To(BeNumerically(">", 1))
var foundAlpine bool var foundAlpine bool
@ -332,25 +330,29 @@ var _ = Describe("Podman images", func() {
Expect(foundAlpine).To(BeTrue()) Expect(foundAlpine).To(BeTrue())
// Search for alpine with a limit of 10 // 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(err).To(BeNil())
Expect(len(reports)).To(BeNumerically("<=", 10)) Expect(len(reports)).To(BeNumerically("<=", 10))
filters := make(map[string][]string)
filters["stars"] = []string{"100"}
// Search for alpine with stars greater than 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()) Expect(err).To(BeNil())
for _, i := range reports { for _, i := range reports {
Expect(i.Stars).To(BeNumerically(">=", 100)) Expect(i.Stars).To(BeNumerically(">=", 100))
} }
// Search with a fqdn // 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)) Expect(len(reports)).To(BeNumerically(">=", 1))
}) })
It("Prune images", func() { It("Prune images", func() {
trueBoxed := true options := new(images.PruneOptions).WithAll(true)
results, err := images.Prune(bt.conn, &trueBoxed, nil) results, err := images.Prune(bt.conn, options)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(BeNumerically(">", 0)) Expect(len(results)).To(BeNumerically(">", 0))
Expect(results).To(ContainElement("docker.io/library/alpine:latest")) Expect(results).To(ContainElement("docker.io/library/alpine:latest"))
@ -360,7 +362,7 @@ var _ = Describe("Podman images", func() {
It("Image Pull", func() { It("Image Pull", func() {
rawImage := "docker.io/library/busybox:latest" 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(err).NotTo(HaveOccurred())
Expect(len(pulledImages)).To(Equal(1)) Expect(len(pulledImages)).To(Equal(1))
@ -369,11 +371,11 @@ var _ = Describe("Podman images", func() {
Expect(exists).To(BeTrue()) Expect(exists).To(BeTrue())
// Make sure the normalization AND the full-transport reference works. // 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()) Expect(err).NotTo(HaveOccurred())
// The v2 endpoint only supports the docker transport. Let's see if that's really true. // 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()) Expect(err).To(HaveOccurred())
}) })
}) })

View File

@ -17,7 +17,6 @@ var _ = Describe("Podman info", func() {
var ( var (
bt *bindingTest bt *bindingTest
s *gexec.Session s *gexec.Session
t bool = true
) )
BeforeEach(func() { BeforeEach(func() {
@ -39,7 +38,8 @@ var _ = Describe("Podman info", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(info.Host.Arch).To(Equal(runtime.GOARCH)) Expect(info.Host.Arch).To(Equal(runtime.GOARCH))
Expect(info.Host.OS).To(Equal(runtime.GOOS)) 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(err).To(BeNil())
Expect(info.Store.ImageStore.Number).To(Equal(len(i))) Expect(info.Store.ImageStore.Number).To(Equal(len(i)))
}) })

View File

@ -47,8 +47,8 @@ var _ = Describe("Podman containers ", func() {
code, _ := bindings.CheckResponseCode(err) code, _ := bindings.CheckResponseCode(err)
Expect(code).To(BeNumerically("==", http.StatusInternalServerError)) Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
_, err = images.Remove(bt.conn, id, nil) _, errs := images.Remove(bt.conn, []string{id}, nil)
Expect(err).To(BeNil()) Expect(len(errs)).To(BeZero())
// create manifest list with images // create manifest list with images
id, err = manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil) id, err = manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{alpine.name}, nil)

View File

@ -4,9 +4,14 @@ import (
"context" "context"
"io/ioutil" "io/ioutil"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/image/v5/types"
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/docker/reference"
images "github.com/containers/podman/v2/pkg/bindings/images" 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) { 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) { 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, "=") f := strings.Split(filter, "=")
filters[f[0]] = f[1:] 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 { if err != nil {
return nil, err return nil, err
} }
is := make([]*entities.ImageSummary, len(images)) is := make([]*entities.ImageSummary, len(psImages))
for i, img := range images { for i, img := range psImages {
hold := entities.ImageSummary{} hold := entities.ImageSummary{}
if err := utils.DeepCopy(&hold, img); err != nil { if err := utils.DeepCopy(&hold, img); err != nil {
return nil, err 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) { 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 { if err != nil {
return nil, err return nil, err
} }
@ -88,8 +96,8 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
f := strings.Split(filter, "=") f := strings.Split(filter, "=")
filters[f[0]] = f[1:] filters[f[0]] = f[1:]
} }
options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters)
results, err := images.Prune(ir.ClientCxt, &opts.All, filters) results, err := images.Prune(ir.ClientCxt, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -104,7 +112,18 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
return &report, nil 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) pulledImages, err := images.Pull(ir.ClientCxt, rawImage, options)
if err != nil { if err != nil {
return nil, err return nil, err
@ -112,7 +131,8 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
return &entities.ImagePullReport{Images: pulledImages}, nil 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 { for _, newTag := range tags {
var ( var (
tag, repo string tag, repo string
@ -130,16 +150,17 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
if len(repo) < 1 { if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID) 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 err
} }
} }
return nil 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 { if len(tags) == 0 {
return images.Untag(ir.ClientCxt, nameOrID, "", "") return images.Untag(ir.ClientCxt, nameOrID, "", "", options)
} }
for _, newTag := range tags { for _, newTag := range tags {
@ -159,7 +180,7 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
if len(repo) < 1 { if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID) 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 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) { 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{} reports := []*entities.ImageInspectReport{}
errs := []error{} errs := []error{}
for _, i := range namesOrIDs { for _, i := range namesOrIDs {
r, err := images.GetImage(ir.ClientCxt, i, &opts.Size) r, err := images.GetImage(ir.ClientCxt, i, options)
if err != nil { if err != nil {
errModel, ok := err.(entities.ErrorModel) errModel, ok := err.(entities.ErrorModel)
if !ok { if !ok {
@ -204,68 +226,73 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
if len(opts.Tag) > 0 { if len(opts.Tag) > 0 {
ref += ":" + opts.Tag 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) { func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) {
var ( var (
err error err error
sourceURL *string f *os.File
f *os.File
) )
options := new(images.ImportOptions).WithChanges(opts.Changes).WithMessage(opts.Message).WithReference(opts.Reference)
if opts.SourceIsURL { if opts.SourceIsURL {
sourceURL = &opts.Source options.WithURL(opts.Source)
} else { } else {
f, err = os.Open(opts.Source) f, err = os.Open(opts.Source)
if err != nil { if err != nil {
return nil, err 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) 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 ( var (
f *os.File f *os.File
err error err error
) )
switch options.Format { options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress)
switch opts.Format {
case "oci-dir", "docker-dir": case "oci-dir", "docker-dir":
f, err = ioutil.TempFile("", "podman_save") f, err = ioutil.TempFile("", "podman_save")
if err == nil { if err == nil {
defer func() { _ = os.Remove(f.Name()) }() defer func() { _ = os.Remove(f.Name()) }()
} }
default: default:
f, err = os.Create(options.Output) f, err = os.Create(opts.Output)
} }
if err != nil { if err != nil {
return err return err
} }
if options.MultiImageArchive { exErr := images.Export(ir.ClientCxt, append([]string{nameOrID}, tags...), f, options)
exErr := images.MultiExport(ir.ClientCxt, append([]string{nameOrID}, tags...), f, &options.Format, &options.Compress) if err := f.Close(); err != nil {
if err := f.Close(); err != nil { return err
return err }
} if exErr != nil {
if exErr != nil { return exErr
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
}
} }
if options.Format != "oci-dir" && options.Format != "docker-dir" { if opts.Format != "oci-dir" && opts.Format != "docker-dir" {
return nil return nil
} }
@ -273,25 +300,26 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string,
if err != nil { if err != nil {
return err return err
} }
info, err := os.Stat(options.Output) info, err := os.Stat(opts.Output)
switch { switch {
case err == nil: case err == nil:
if info.Mode().IsRegular() { 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): case os.IsNotExist(err):
if err := os.Mkdir(options.Output, 0755); err != nil { if err := os.Mkdir(opts.Output, 0755); err != nil {
return err return err
} }
default: default:
return err return err
} }
return utils2.UntarToFileSystem(options.Output, f, nil) return utils2.UntarToFileSystem(opts.Output, f, nil)
} }
// Diff reports the changes to the given image // Diff reports the changes to the given image
func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) { 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 { if err != nil {
return nil, err 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) { 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) { 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) { 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 // Shutdown Libpod engine