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
dl.fedoraproject.org 443
ewr.edge.kernel.org 443
mirror.chpc.utah.edu 443
mirror.clarkson.edu 443
mirror.umd.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
// archives.
if len(query.References) > 1 && query.Format != define.V2s2Archive {
utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("multi-image archives must use format of %s", define.V2s2Archive))
return
}
switch query.Format {
case define.V2s2Archive:
case define.V2s2Archive, define.OCIArchive:
tmpfile, err := ioutil.TempFile("", "api.tar")
if err != nil {
utils.Error(w, "unable to create tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
@ -277,6 +283,13 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "unable to close tmpfile", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
}
case define.OCIManifestDir, define.V2s2ManifestDir:
tmpdir, err := ioutil.TempDir("", "save")
if err != nil {
utils.Error(w, "unable to create tmpdir", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempdir"))
return
}
output = tmpdir
default:
utils.Error(w, "unsupported format", http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format))
return
@ -287,7 +300,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
opts := entities.ImageSaveOptions{
Compress: query.Compress,
Format: query.Format,
MultiImageArchive: true,
MultiImageArchive: len(query.References) > 1,
Output: output,
RemoveSignatures: true,
}
@ -414,7 +427,6 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
}{
// This is where you can override the golang default value for one of fields
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
@ -610,7 +622,7 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
Term string `json:"term"`
Limit int `json:"limit"`
NoTrunc bool `json:"noTrunc"`
Filters []string `json:"filters"`
Filters map[string][]string `json:"filters"`
TLSVerify bool `json:"tlsVerify"`
ListTags bool `json:"listTags"`
}{
@ -622,22 +634,42 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
return
}
filter := image.SearchFilter{}
if len(query.Filters) > 0 {
if len(query.Filters["stars"]) > 0 {
stars, err := strconv.Atoi(query.Filters["stars"][0])
if err != nil {
utils.InternalServerError(w, err)
return
}
filter.Stars = stars
}
if len(query.Filters["is-official"]) > 0 {
isOfficial, err := strconv.ParseBool(query.Filters["is-official"][0])
if err != nil {
utils.InternalServerError(w, err)
return
}
filter.IsOfficial = types.NewOptionalBool(isOfficial)
}
if len(query.Filters["is-automated"]) > 0 {
isAutomated, err := strconv.ParseBool(query.Filters["is-automated"][0])
if err != nil {
utils.InternalServerError(w, err)
return
}
filter.IsAutomated = types.NewOptionalBool(isAutomated)
}
}
options := image.SearchOptions{
Limit: query.Limit,
NoTrunc: query.NoTrunc,
ListTags: query.ListTags,
}
if _, found := r.URL.Query()["tlsVerify"]; found {
options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
Filter: filter,
}
if _, found := r.URL.Query()["filters"]; found {
filter, err := image.ParseSearchFilter(query.Filters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse filters parameter for %s", r.URL.String()))
return
}
options.Filter = *filter
if _, found := r.URL.Query()["tlsVerify"]; found {
options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
_, authfile, key, err := auth.GetCredentials(r)
@ -678,10 +710,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
All bool `schema:"all"`
Force bool `schema:"force"`
Images []string `schema:"images"`
}{
All: false,
Force: false,
}
}{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
@ -690,10 +719,8 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
}
opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force}
imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
strErrs := errorhandling.ErrorsToStrings(rmErrors)
report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: strErrs}
utils.WriteResponse(w, http.StatusOK, report)

View File

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

View File

@ -9,7 +9,11 @@ import (
)
// Diff provides the changes between two container layers
func Diff(ctx context.Context, nameOrID string) ([]archive.Change, error) {
func Diff(ctx context.Context, nameOrID string, options *DiffOptions) ([]archive.Change, error) {
if options == nil {
options = new(DiffOptions)
}
_ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err

View File

@ -8,7 +8,6 @@ import (
"net/url"
"strconv"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
@ -32,23 +31,19 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// List returns a list of images in local storage. The all boolean and filters parameters are optional
// ways to alter the image query.
func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entities.ImageSummary, error) {
func List(ctx context.Context, options *ListOptions) ([]*entities.ImageSummary, error) {
if options == nil {
options = new(ListOptions)
}
var imageSummary []*entities.ImageSummary
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
if all != nil {
params.Set("all", strconv.FormatBool(*all))
}
if filters != nil {
strFilters, err := bindings.FiltersToString(filters)
params, err := options.ToParams()
if err != nil {
return nil, err
}
params.Set("filters", strFilters)
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil)
if err != nil {
return imageSummary, err
@ -58,14 +53,17 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit
// Get performs an image inspect. To have the on-disk size of the image calculated, you can
// use the optional size parameter.
func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageInspectReport, error) {
func GetImage(ctx context.Context, nameOrID string, options *GetOptions) (*entities.ImageInspectReport, error) {
if options == nil {
options = new(GetOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
if size != nil {
params.Set("size", strconv.FormatBool(*size))
params, err := options.ToParams()
if err != nil {
return nil, err
}
inspectedData := entities.ImageInspectReport{}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID)
@ -76,15 +74,18 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
}
// Tree retrieves a "tree" based representation of the given image
func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.ImageTreeReport, error) {
func Tree(ctx context.Context, nameOrID string, options *TreeOptions) (*entities.ImageTreeReport, error) {
if options == nil {
options = new(TreeOptions)
}
var report entities.ImageTreeReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
if whatRequires != nil {
params.Set("size", strconv.FormatBool(*whatRequires))
params, err := options.ToParams()
if err != nil {
return nil, err
}
response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID)
if err != nil {
@ -94,7 +95,11 @@ func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.I
}
// History returns the parent layers of an image.
func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) {
func History(ctx context.Context, nameOrID string, options *HistoryOptions) ([]*handlers.HistoryResponse, error) {
if options == nil {
options = new(HistoryOptions)
}
_ = options
var history []*handlers.HistoryResponse
conn, err := bindings.GetClient(ctx)
if err != nil {
@ -107,15 +112,18 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
return history, response.Process(&history)
}
func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadReport, error) {
func Load(ctx context.Context, r io.Reader, options *LoadOptions) (*entities.ImageLoadReport, error) {
if options == nil {
options = new(LoadOptions)
}
var report entities.ImageLoadReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
if name != nil {
params.Set("reference", *name)
params, err := options.ToParams()
if err != nil {
return nil, err
}
response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil)
if err != nil {
@ -124,19 +132,21 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe
return &report, response.Process(&report)
}
func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *string, compress *bool) error {
// 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)
if err != nil {
return err
}
params := url.Values{}
if format != nil {
params.Set("format", *format)
params, err := options.ToParams()
if err != nil {
return err
}
if compress != nil {
params.Set("compress", strconv.FormatBool(*compress))
}
for _, ref := range namesOrIds {
for _, ref := range nameOrIDs {
params.Add("references", ref)
}
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
}
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 {
_, err = io.Copy(w, response.Body)
return err
@ -180,25 +163,21 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c
// Prune removes unused images from local storage. The optional filters can be used to further
// define which images should be pruned.
func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]string, error) {
func Prune(ctx context.Context, options *PruneOptions) ([]string, error) {
var (
deleted []string
)
if options == nil {
options = new(PruneOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
if all != nil {
params.Set("all", strconv.FormatBool(*all))
}
if filters != nil {
stringFilter, err := bindings.FiltersToString(filters)
params, err := options.ToParams()
if err != nil {
return nil, err
}
params.Set("filters", stringFilter)
}
response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil)
if err != nil {
return deleted, err
@ -207,7 +186,11 @@ func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]strin
}
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
func Tag(ctx context.Context, nameOrID, tag, repo string) error {
func Tag(ctx context.Context, nameOrID, tag, repo string, options *TagOptions) error {
if options == nil {
options = new(TagOptions)
}
_ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@ -223,7 +206,11 @@ func Tag(ctx context.Context, nameOrID, tag, repo string) error {
}
// Untag removes a name from locally-stored image. Both the tag and repo parameters are required.
func Untag(ctx context.Context, nameOrID, tag, repo string) error {
func Untag(ctx context.Context, nameOrID, tag, repo string, options *UntagOptions) error {
if options == nil {
options = new(UntagOptions)
}
_ = options
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
@ -241,27 +228,21 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error {
// Imports adds the given image to the local image store. This can be done by file and the given reader
// or via the url parameter. Additional metadata can be associated with the image by using the changes and
// message parameters. The image can also be tagged given a reference. One of url OR r must be provided.
func Import(ctx context.Context, changes []string, message, reference, u *string, r io.Reader) (*entities.ImageImportReport, error) {
func Import(ctx context.Context, r io.Reader, options *ImportOptions) (*entities.ImageImportReport, error) {
if options == nil {
options = new(ImportOptions)
}
var report entities.ImageImportReport
if r != nil && u != nil {
if r != nil && options.URL != nil {
return nil, errors.New("url and r parameters cannot be used together")
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
for _, change := range changes {
params.Add("changes", change)
}
if message != nil {
params.Set("message", *message)
}
if reference != nil {
params.Set("reference", *reference)
}
if u != nil {
params.Set("url", *u)
params, err := options.ToParams()
if err != nil {
return nil, err
}
response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil)
if err != nil {
@ -275,25 +256,31 @@ func Import(ctx context.Context, changes []string, message, reference, u *string
// The destination must be a reference to a registry (i.e., of docker transport
// or be normalized to one). Other transports are rejected as they do not make
// sense in a remote context.
func Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
func Push(ctx context.Context, source string, destination string, options *PushOptions) error {
if options == nil {
options = new(PushOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
// TODO: have a global system context we can pass around (1st argument)
header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return err
}
params := url.Values{}
params.Set("destination", destination)
if options.SkipTLSVerify != types.OptionalBoolUndefined {
// Note: we have to verify if skipped is false.
verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
params, err := options.ToParams()
if err != nil {
return err
}
//SkipTLSVerify is special. We need to delete the param added by
//toparams and change the key and flip the bool
if options.SkipTLSVerify != nil {
params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
params.Set("destination", destination)
path := fmt.Sprintf("/images/%s/push", source)
response, err := conn.DoRequest(nil, http.MethodPost, path, params, header)
@ -305,28 +292,28 @@ func Push(ctx context.Context, source string, destination string, options entiti
}
// Search is the binding for libpod's v2 endpoints for Search images.
func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
func Search(ctx context.Context, term string, options *SearchOptions) ([]entities.ImageSearchReport, error) {
if options == nil {
options = new(SearchOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
params.Set("term", term)
params.Set("limit", strconv.Itoa(opts.Limit))
params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc))
params.Set("listTags", strconv.FormatBool(opts.ListTags))
for _, f := range opts.Filters {
params.Set("filters", f)
params, err := options.ToParams()
if err != nil {
return nil, err
}
params.Set("term", term)
if opts.SkipTLSVerify != types.OptionalBoolUndefined {
// Note: we have to verify if skipped is false.
verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse)
params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
if options.SkipTLSVerify != nil {
params.Del("SkipTLSVerify")
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
// TODO: have a global system context we can pass around (1st argument)
header, err := auth.Header(nil, auth.XRegistryAuthHeader, opts.Authfile, "", "")
header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), "", "")
if err != nil {
return nil, err
}

View File

@ -8,11 +8,9 @@ import (
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
@ -23,26 +21,28 @@ import (
// `rawImage` must be a reference to a registry (i.e., of docker transport or be
// normalized to one). Other transports are rejected as they do not make sense
// in a remote context. Progress reported on stderr
func Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) ([]string, error) {
func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, error) {
if options == nil {
options = new(PullOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params := url.Values{}
params.Set("reference", rawImage)
params.Set("overrideArch", options.OverrideArch)
params.Set("overrideOS", options.OverrideOS)
params.Set("overrideVariant", options.OverrideVariant)
if options.SkipTLSVerify != types.OptionalBoolUndefined {
// Note: we have to verify if skipped is false.
verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
params, err := options.ToParams()
if err != nil {
return nil, err
}
params.Set("reference", rawImage)
if options.SkipTLSVerify != nil {
params.Del("SkipTLSVerify")
// Note: we have to verify if skipped is false.
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
params.Set("allTags", strconv.FormatBool(options.AllTags))
// TODO: have a global system context we can pass around (1st argument)
header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return nil, err
}
@ -59,7 +59,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
// Historically pull writes status to stderr
stderr := io.Writer(os.Stderr)
if options.Quiet {
if options.GetQuiet() {
stderr = ioutil.Discard
}

View File

@ -3,8 +3,6 @@ package images
import (
"context"
"net/http"
"net/url"
"strconv"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
@ -12,8 +10,12 @@ import (
"github.com/containers/podman/v2/pkg/errorhandling"
)
// BachtRemove removes a batch of images from the local storage.
func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
// Remove removes one or more images from the local storage. Use optional force option to remove an
// image, even if it's used by containers.
func Remove(ctx context.Context, images []string, options *RemoveOptions) (*entities.ImageRemoveReport, []error) {
if options == nil {
options = new(RemoveOptions)
}
// FIXME - bindings tests are missing for this endpoint. Once the CI is
// re-enabled for bindings, we need to add them. At the time of writing,
// the tests don't compile.
@ -23,13 +25,13 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return nil, []error{err}
}
params := url.Values{}
params.Set("all", strconv.FormatBool(opts.All))
params.Set("force", strconv.FormatBool(opts.Force))
for _, i := range images {
params.Add("images", i)
params, err := options.ToParams()
if err != nil {
return nil, nil
}
for _, image := range images {
params.Add("images", image)
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil)
if err != nil {
return nil, []error{err}
@ -40,28 +42,3 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
return &report.ImageRemoveReport, errorhandling.StringsToErrors(report.Errors)
}
// Remove removes an image from the local storage. Use optional force option to remove an
// image, even if it's used by containers.
func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) (*entities.ImageRemoveReport, error) {
var report handlers.LibpodImagesRemoveReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params, err := options.ToParams()
if err != nil {
return nil, err
}
response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID)
if err != nil {
return nil, err
}
if err := response.Process(&report); err != nil {
return nil, err
}
errs := errorhandling.StringsToErrors(report.Errors)
return &report.ImageRemoveReport, errorhandling.JoinErrors(errs)
}

View File

@ -1,8 +1,193 @@
package images
import (
"github.com/containers/buildah/imagebuildah"
"github.com/containers/common/pkg/config"
)
//go:generate go run ../generator/generator.go RemoveOptions
// RemoveOptions are optional options for image removal
type RemoveOptions struct {
// All removes all images
All *bool
// Forces removes all containers based on the image
Force *bool
}
//go:generate go run ../generator/generator.go DiffOptions
// DiffOptions are optional options image diffs
type DiffOptions struct {
}
//go:generate go run ../generator/generator.go ListOptions
// ListOptions are optional options for listing images
type ListOptions struct {
// All lists all image in the image store including dangling images
All *bool
// filters that can be used to get a more specific list of images
Filters map[string][]string
}
//go:generate go run ../generator/generator.go GetOptions
// GetOptions are optional options for inspecting an image
type GetOptions struct {
// Size computes the amount of storage the image consumes
Size *bool
}
//go:generate go run ../generator/generator.go TreeOptions
// TreeOptions are optional options for a tree-based representation
// of the image
type TreeOptions struct {
// WhatRequires ...
WhatRequires *bool
}
//go:generate go run ../generator/generator.go HistoryOptions
// HistoryOptions are optional options image history
type HistoryOptions struct {
}
//go:generate go run ../generator/generator.go LoadOptions
// LoadOptions are optional options for loading an image
type LoadOptions struct {
// Reference is the name of the loaded image
Reference *string
}
//go:generate go run ../generator/generator.go ExportOptions
// ExportOptions are optional options for exporting images
type ExportOptions struct {
// Compress the image
Compress *bool
// Format of the output
Format *string
}
//go:generate go run ../generator/generator.go PruneOptions
// PruneOptions are optional options for pruning images
type PruneOptions struct {
// Prune all images
All *bool
// Filters to apply when pruning images
Filters map[string][]string
}
//go:generate go run ../generator/generator.go TagOptions
// TagOptions are optional options for tagging images
type TagOptions struct {
}
//go:generate go run ../generator/generator.go UntagOptions
// UntagOptions are optional options for tagging images
type UntagOptions struct {
}
//go:generate go run ../generator/generator.go ImportOptions
// ImportOptions are optional options for importing images
type ImportOptions struct {
// Changes to be applied to the image
Changes *[]string
// Message to be applied to the image
Message *string
// Reference is a tag to be applied to the image
Reference *string
// Url to option image to import. Cannot be used with the reader
URL *string
}
//go:generate go run ../generator/generator.go PushOptions
// PushOptions are optional options for importing images
type PushOptions struct {
// Authfile is the path to the authentication file. Ignored for remote
// calls.
Authfile *string
// CertDir is the path to certificate directories. Ignored for remote
// calls.
CertDir *string
// Compress tarball image layers when pushing to a directory using the 'dir'
// transport. Default is same compression type as source. Ignored for remote
// calls.
Compress *bool
// Username for authenticating against the registry.
Username *string
// Password for authenticating against the registry.
Password *string
// DigestFile, after copying the image, write the digest of the resulting
// image to the file. Ignored for remote calls.
DigestFile *string
// Format is the Manifest type (oci, v2s1, or v2s2) to use when pushing an
// image using the 'dir' transport. Default is manifest type of source.
// Ignored for remote calls.
Format *string
// Quiet can be specified to suppress pull progress when pulling. Ignored
// for remote calls.
Quiet *bool
// RemoveSignatures, discard any pre-existing signatures in the image.
// Ignored for remote calls.
RemoveSignatures *bool
// SignaturePolicy to use when pulling. Ignored for remote calls.
SignaturePolicy *string
// SignBy adds a signature at the destination using the specified key.
// Ignored for remote calls.
SignBy *string
// SkipTLSVerify to skip HTTPS and certificate verification.
SkipTLSVerify *bool
}
//go:generate go run ../generator/generator.go SearchOptions
// SearchOptions are optional options for seaching images on registies
type SearchOptions struct {
// Authfile is the path to the authentication file. Ignored for remote
// calls.
Authfile *string
// Filters for the search results.
Filters map[string][]string
// Limit the number of results.
Limit *int
// NoTrunc will not truncate the output.
NoTrunc *bool
// SkipTLSVerify to skip HTTPS and certificate verification.
SkipTLSVerify *bool
// ListTags search the available tags of the repository
ListTags *bool
}
//go:generate go run ../generator/generator.go PullOptions
// PullOptions are optional options for pulling images
type PullOptions struct {
// AllTags can be specified to pull all tags of an image. Note
// that this only works if the image does not include a tag.
AllTags *bool
// Authfile is the path to the authentication file. Ignored for remote
// calls.
Authfile *string
// CertDir is the path to certificate directories. Ignored for remote
// calls.
CertDir *string
// Username for authenticating against the registry.
Username *string
// Password for authenticating against the registry.
Password *string
// OverrideArch will overwrite the local architecture for image pulls.
OverrideArch *string
// OverrideOS will overwrite the local operating system (OS) for image
// pulls.
OverrideOS *string
// OverrideVariant will overwrite the local variant for image pulls.
OverrideVariant *string
// Quiet can be specified to suppress pull progress when pulling. Ignored
// for remote calls.
Quiet *bool
// SignaturePolicy to use when pulling. Ignored for remote calls.
SignaturePolicy *string
// SkipTLSVerify to skip HTTPS and certificate verification.
SkipTLSVerify *bool
// PullPolicy whether to pull new image
PullPolicy *config.PullPolicy
}
//BuildOptions are optional options for building images
type BuildOptions struct {
imagebuildah.BuildOptions
}

View File

@ -12,18 +12,18 @@ import (
/*
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
func (o *RemoveOptions) Changed(fieldName string) bool {
func (o *DiffOptions) 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) {
func (o *DiffOptions) ToParams() (url.Values, error) {
params := url.Values{}
if o == nil {
return params, nil
@ -68,10 +68,11 @@ func (o *RemoveOptions) ToParams() (url.Values, error) {
}
case reflect.Map:
lowerCaseKeys := make(map[string][]string)
// I dont know if this code is needed anymore, TBD
// for k, v := range filters {
// lowerCaseKeys[strings.ToLower(k)] = v
// }
iter := f.MapRange()
for iter.Next() {
lowerCaseKeys[iter.Key().Interface().(string)] = iter.Value().Interface().([]string)
}
s, err := json.MarshalToString(lowerCaseKeys)
if err != nil {
return nil, err
@ -84,10 +85,3 @@ func (o *RemoveOptions) ToParams() (url.Values, error) {
}
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"
podmanRegistry "github.com/containers/podman/v2/hack/podman-registry-go"
"github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/domain/entities"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@ -52,27 +51,19 @@ var _ = Describe("Podman images", func() {
imageRef := imageRep + ":" + imageTag
// Tag the alpine image and verify it has worked.
err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil)
Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil())
// Now push the image.
pushOpts := entities.ImagePushOptions{
Username: registry.User,
Password: registry.Password,
SkipTLSVerify: types.OptionalBoolTrue,
}
err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
pushOpts := new(images.PushOptions)
err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithUsername(registry.User).WithPassword(registry.Password).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Now pull the image.
pullOpts := entities.ImagePullOptions{
Username: registry.User,
Password: registry.Password,
SkipTLSVerify: types.OptionalBoolTrue,
}
_, err = images.Pull(bt.conn, imageRef, pullOpts)
pullOpts := new(images.PullOptions)
_, err = images.Pull(bt.conn, imageRef, pullOpts.WithSkipTLSVerify(true).WithPassword(registry.Password).WithUsername(registry.User))
Expect(err).To(BeNil())
})
@ -110,33 +101,24 @@ var _ = Describe("Podman images", func() {
Expect(err).To(BeNil())
// Tag the alpine image and verify it has worked.
err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep, nil)
Expect(err).To(BeNil())
_, err = images.GetImage(bt.conn, imageRef, nil)
Expect(err).To(BeNil())
// Now push the image.
pushOpts := entities.ImagePushOptions{
Authfile: authFilePath,
SkipTLSVerify: types.OptionalBoolTrue,
}
err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
pushOpts := new(images.PushOptions)
err = images.Push(bt.conn, imageRef, imageRef, pushOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Now pull the image.
pullOpts := entities.ImagePullOptions{
Authfile: authFilePath,
SkipTLSVerify: types.OptionalBoolTrue,
}
_, err = images.Pull(bt.conn, imageRef, pullOpts)
pullOpts := new(images.PullOptions)
_, err = images.Pull(bt.conn, imageRef, pullOpts.WithAuthfile(authFilePath).WithSkipTLSVerify(true))
Expect(err).To(BeNil())
// Last, but not least, exercise search.
searchOptions := entities.ImageSearchOptions{
Authfile: authFilePath,
SkipTLSVerify: types.OptionalBoolTrue,
}
_, err = images.Search(bt.conn, imageRef, searchOptions)
searchOptions := new(images.SearchOptions)
_, err = images.Search(bt.conn, imageRef, searchOptions.WithSkipTLSVerify(true).WithAuthfile(authFilePath))
Expect(err).To(BeNil())
})

View File

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

View File

@ -17,7 +17,6 @@ var _ = Describe("Podman info", func() {
var (
bt *bindingTest
s *gexec.Session
t bool = true
)
BeforeEach(func() {
@ -39,7 +38,8 @@ var _ = Describe("Podman info", func() {
Expect(err).To(BeNil())
Expect(info.Host.Arch).To(Equal(runtime.GOARCH))
Expect(info.Host.OS).To(Equal(runtime.GOOS))
i, err := images.List(bt.conn, &t, nil)
listOptions := new(images.ListOptions)
i, err := images.List(bt.conn, listOptions.WithAll(true))
Expect(err).To(BeNil())
Expect(info.Store.ImageStore.Number).To(Equal(len(i)))
})

View File

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

View File

@ -4,9 +4,14 @@ import (
"context"
"io/ioutil"
"os"
"strconv"
"strings"
"time"
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/image/v5/types"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
images "github.com/containers/podman/v2/pkg/bindings/images"
@ -22,7 +27,8 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
}
func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
return images.BatchRemove(ir.ClientCxt, imagesArg, opts)
options := new(images.RemoveOptions).WithForce(opts.Force).WithAll(opts.All)
return images.Remove(ir.ClientCxt, imagesArg, options)
}
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
@ -32,13 +38,14 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
images, err := images.List(ir.ClientCxt, &opts.All, filters)
options := new(images.ListOptions).WithAll(opts.All).WithFilters(filters)
psImages, err := images.List(ir.ClientCxt, options)
if err != nil {
return nil, err
}
is := make([]*entities.ImageSummary, len(images))
for i, img := range images {
is := make([]*entities.ImageSummary, len(psImages))
for i, img := range psImages {
hold := entities.ImageSummary{}
if err := utils.DeepCopy(&hold, img); err != nil {
return nil, err
@ -57,7 +64,8 @@ func (ir *ImageEngine) Unmount(ctx context.Context, images []string, options ent
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
results, err := images.History(ir.ClientCxt, nameOrID)
options := new(images.HistoryOptions)
results, err := images.History(ir.ClientCxt, nameOrID, options)
if err != nil {
return nil, err
}
@ -88,8 +96,8 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
results, err := images.Prune(ir.ClientCxt, &opts.All, filters)
options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters)
results, err := images.Prune(ir.ClientCxt, options)
if err != nil {
return nil, err
}
@ -104,7 +112,18 @@ func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOption
return &report, nil
}
func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) {
func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) {
options := new(images.PullOptions)
options.WithAllTags(opts.AllTags).WithAuthfile(opts.Authfile).WithCertDir(opts.CertDir).WithOverrideArch(opts.OverrideArch).WithOverrideOS(opts.OverrideOS)
options.WithOverrideVariant(opts.OverrideVariant).WithPassword(opts.Password).WithPullPolicy(opts.PullPolicy)
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
if s == types.OptionalBoolTrue {
options.WithSkipTLSVerify(true)
} else {
options.WithSkipTLSVerify(false)
}
}
options.WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithUsername(opts.Username)
pulledImages, err := images.Pull(ir.ClientCxt, rawImage, options)
if err != nil {
return nil, err
@ -112,7 +131,8 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
return &entities.ImagePullReport{Images: pulledImages}, nil
}
func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageTagOptions) error {
options := new(images.TagOptions)
for _, newTag := range tags {
var (
tag, repo string
@ -130,16 +150,17 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string,
if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID)
}
if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo, options); err != nil {
return err
}
}
return nil
}
func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error {
func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageUntagOptions) error {
options := new(images.UntagOptions)
if len(tags) == 0 {
return images.Untag(ir.ClientCxt, nameOrID, "", "")
return images.Untag(ir.ClientCxt, nameOrID, "", "", options)
}
for _, newTag := range tags {
@ -159,7 +180,7 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
if len(repo) < 1 {
return errors.Errorf("invalid image name %q", nameOrID)
}
if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo); err != nil {
if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo, options); err != nil {
return err
}
}
@ -167,10 +188,11 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
}
func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
options := new(images.GetOptions).WithSize(opts.Size)
reports := []*entities.ImageInspectReport{}
errs := []error{}
for _, i := range namesOrIDs {
r, err := images.GetImage(ir.ClientCxt, i, &opts.Size)
r, err := images.GetImage(ir.ClientCxt, i, options)
if err != nil {
errModel, ok := err.(entities.ErrorModel)
if !ok {
@ -204,68 +226,73 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
if len(opts.Tag) > 0 {
ref += ":" + opts.Tag
}
return images.Load(ir.ClientCxt, f, &ref)
options := new(images.LoadOptions).WithReference(ref)
return images.Load(ir.ClientCxt, f, options)
}
func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) {
var (
err error
sourceURL *string
f *os.File
)
options := new(images.ImportOptions).WithChanges(opts.Changes).WithMessage(opts.Message).WithReference(opts.Reference)
if opts.SourceIsURL {
sourceURL = &opts.Source
options.WithURL(opts.Source)
} else {
f, err = os.Open(opts.Source)
if err != nil {
return nil, err
}
}
return images.Import(ir.ClientCxt, opts.Changes, &opts.Message, &opts.Reference, sourceURL, f)
return images.Import(ir.ClientCxt, f, options)
}
func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, opts entities.ImagePushOptions) error {
options := new(images.PushOptions)
options.WithUsername(opts.Username).WithSignaturePolicy(opts.SignaturePolicy).WithQuiet(opts.Quiet)
options.WithPassword(opts.Password).WithCertDir(opts.CertDir).WithAuthfile(opts.Authfile)
options.WithCompress(opts.Compress).WithDigestFile(opts.DigestFile).WithFormat(opts.Format)
options.WithRemoveSignatures(opts.RemoveSignatures).WithSignBy(opts.SignBy)
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
if s == types.OptionalBoolTrue {
options.WithSkipTLSVerify(true)
} else {
options.WithSkipTLSVerify(false)
}
}
return images.Push(ir.ClientCxt, source, destination, options)
}
func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, opts entities.ImageSaveOptions) error {
var (
f *os.File
err error
)
switch options.Format {
options := new(images.ExportOptions).WithFormat(opts.Format).WithCompress(opts.Compress)
switch opts.Format {
case "oci-dir", "docker-dir":
f, err = ioutil.TempFile("", "podman_save")
if err == nil {
defer func() { _ = os.Remove(f.Name()) }()
}
default:
f, err = os.Create(options.Output)
f, err = os.Create(opts.Output)
}
if err != nil {
return err
}
if options.MultiImageArchive {
exErr := images.MultiExport(ir.ClientCxt, append([]string{nameOrID}, tags...), f, &options.Format, &options.Compress)
exErr := images.Export(ir.ClientCxt, append([]string{nameOrID}, tags...), f, options)
if err := f.Close(); err != nil {
return err
}
if exErr != nil {
return exErr
}
} else {
// FIXME: tags are entirely ignored here but shouldn't.
exErr := images.Export(ir.ClientCxt, nameOrID, f, &options.Format, &options.Compress)
if err := f.Close(); err != nil {
return err
}
if exErr != nil {
return exErr
}
}
if options.Format != "oci-dir" && options.Format != "docker-dir" {
if opts.Format != "oci-dir" && opts.Format != "docker-dir" {
return nil
}
@ -273,25 +300,26 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string,
if err != nil {
return err
}
info, err := os.Stat(options.Output)
info, err := os.Stat(opts.Output)
switch {
case err == nil:
if info.Mode().IsRegular() {
return errors.Errorf("%q already exists as a regular file", options.Output)
return errors.Errorf("%q already exists as a regular file", opts.Output)
}
case os.IsNotExist(err):
if err := os.Mkdir(options.Output, 0755); err != nil {
if err := os.Mkdir(opts.Output, 0755); err != nil {
return err
}
default:
return err
}
return utils2.UntarToFileSystem(options.Output, f, nil)
return utils2.UntarToFileSystem(opts.Output, f, nil)
}
// Diff reports the changes to the given image
func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
changes, err := images.Diff(ir.ClientCxt, nameOrID)
options := new(images.DiffOptions)
changes, err := images.Diff(ir.ClientCxt, nameOrID, options)
if err != nil {
return nil, err
}
@ -299,7 +327,34 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.Dif
}
func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
return images.Search(ir.ClientCxt, term, opts)
mappedFilters := make(map[string][]string)
filters, err := image.ParseSearchFilter(opts.Filters)
if err != nil {
return nil, err
}
if stars := filters.Stars; stars > 0 {
mappedFilters["stars"] = []string{strconv.Itoa(stars)}
}
if official := filters.IsOfficial; official != types.OptionalBoolUndefined {
mappedFilters["is-official"] = []string{strconv.FormatBool(official == types.OptionalBoolTrue)}
}
if automated := filters.IsAutomated; automated != types.OptionalBoolUndefined {
mappedFilters["is-automated"] = []string{strconv.FormatBool(automated == types.OptionalBoolTrue)}
}
options := new(images.SearchOptions)
options.WithAuthfile(opts.Authfile).WithFilters(mappedFilters).WithLimit(opts.Limit)
options.WithListTags(opts.ListTags).WithNoTrunc(opts.NoTrunc)
if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined {
if s == types.OptionalBoolTrue {
options.WithSkipTLSVerify(true)
} else {
options.WithSkipTLSVerify(false)
}
}
return images.Search(ir.ClientCxt, term, options)
}
func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
@ -326,7 +381,8 @@ func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts en
}
func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
return images.Tree(ir.ClientCxt, nameOrID, &opts.WhatRequires)
options := new(images.TreeOptions).WithWhatRequires(opts.WhatRequires)
return images.Tree(ir.ClientCxt, nameOrID, options)
}
// Shutdown Libpod engine