github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/bindings/images/images.go (about)

     1  package images
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"net/url"
     9  	"strconv"
    10  
    11  	"github.com/containers/image/v5/types"
    12  	"github.com/containers/podman/v2/pkg/api/handlers"
    13  	"github.com/containers/podman/v2/pkg/auth"
    14  	"github.com/containers/podman/v2/pkg/bindings"
    15  	"github.com/containers/podman/v2/pkg/domain/entities"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // Exists a lightweight way to determine if an image exists in local storage.  It returns a
    20  // boolean response.
    21  func Exists(ctx context.Context, nameOrID string) (bool, error) {
    22  	conn, err := bindings.GetClient(ctx)
    23  	if err != nil {
    24  		return false, err
    25  	}
    26  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/exists", nil, nil, nameOrID)
    27  	if err != nil {
    28  		return false, err
    29  	}
    30  	return response.IsSuccess(), nil
    31  }
    32  
    33  // List returns a list of images in local storage.  The all boolean and filters parameters are optional
    34  // ways to alter the image query.
    35  func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entities.ImageSummary, error) {
    36  	var imageSummary []*entities.ImageSummary
    37  	conn, err := bindings.GetClient(ctx)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	params := url.Values{}
    42  	if all != nil {
    43  		params.Set("all", strconv.FormatBool(*all))
    44  	}
    45  	if filters != nil {
    46  		strFilters, err := bindings.FiltersToString(filters)
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  		params.Set("filters", strFilters)
    51  	}
    52  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil)
    53  	if err != nil {
    54  		return imageSummary, err
    55  	}
    56  	return imageSummary, response.Process(&imageSummary)
    57  }
    58  
    59  // Get performs an image inspect.  To have the on-disk size of the image calculated, you can
    60  // use the optional size parameter.
    61  func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.ImageInspectReport, error) {
    62  	conn, err := bindings.GetClient(ctx)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	params := url.Values{}
    67  	if size != nil {
    68  		params.Set("size", strconv.FormatBool(*size))
    69  	}
    70  	inspectedData := entities.ImageInspectReport{}
    71  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID)
    72  	if err != nil {
    73  		return &inspectedData, err
    74  	}
    75  	return &inspectedData, response.Process(&inspectedData)
    76  }
    77  
    78  // Tree retrieves a "tree" based representation of the given image
    79  func Tree(ctx context.Context, nameOrID string, whatRequires *bool) (*entities.ImageTreeReport, error) {
    80  	var report entities.ImageTreeReport
    81  	conn, err := bindings.GetClient(ctx)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	params := url.Values{}
    86  	if whatRequires != nil {
    87  		params.Set("size", strconv.FormatBool(*whatRequires))
    88  	}
    89  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrID)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	return &report, response.Process(&report)
    94  }
    95  
    96  // History returns the parent layers of an image.
    97  func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) {
    98  	var history []*handlers.HistoryResponse
    99  	conn, err := bindings.GetClient(ctx)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/history", nil, nil, nameOrID)
   104  	if err != nil {
   105  		return history, err
   106  	}
   107  	return history, response.Process(&history)
   108  }
   109  
   110  func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadReport, error) {
   111  	var report entities.ImageLoadReport
   112  	conn, err := bindings.GetClient(ctx)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	params := url.Values{}
   117  	if name != nil {
   118  		params.Set("reference", *name)
   119  	}
   120  	response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	return &report, response.Process(&report)
   125  }
   126  
   127  func MultiExport(ctx context.Context, namesOrIds []string, w io.Writer, format *string, compress *bool) error {
   128  	conn, err := bindings.GetClient(ctx)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	params := url.Values{}
   133  	if format != nil {
   134  		params.Set("format", *format)
   135  	}
   136  	if compress != nil {
   137  		params.Set("compress", strconv.FormatBool(*compress))
   138  	}
   139  	for _, ref := range namesOrIds {
   140  		params.Add("references", ref)
   141  	}
   142  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/export", params, nil)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 {
   148  		_, err = io.Copy(w, response.Body)
   149  		return err
   150  	}
   151  	return response.Process(nil)
   152  
   153  }
   154  
   155  // Export saves an image from local storage as a tarball or image archive.  The optional format
   156  // parameter is used to change the format of the output.
   157  func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, compress *bool) error {
   158  	conn, err := bindings.GetClient(ctx)
   159  	if err != nil {
   160  		return err
   161  	}
   162  	params := url.Values{}
   163  	if format != nil {
   164  		params.Set("format", *format)
   165  	}
   166  	if compress != nil {
   167  		params.Set("compress", strconv.FormatBool(*compress))
   168  	}
   169  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID)
   170  	if err != nil {
   171  		return err
   172  	}
   173  
   174  	if response.StatusCode/100 == 2 || response.StatusCode/100 == 3 {
   175  		_, err = io.Copy(w, response.Body)
   176  		return err
   177  	}
   178  	return response.Process(nil)
   179  }
   180  
   181  // Prune removes unused images from local storage.  The optional filters can be used to further
   182  // define which images should be pruned.
   183  func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]string, error) {
   184  	var (
   185  		deleted []string
   186  	)
   187  	conn, err := bindings.GetClient(ctx)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	params := url.Values{}
   192  	if all != nil {
   193  		params.Set("all", strconv.FormatBool(*all))
   194  	}
   195  	if filters != nil {
   196  		stringFilter, err := bindings.FiltersToString(filters)
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		params.Set("filters", stringFilter)
   201  	}
   202  	response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil)
   203  	if err != nil {
   204  		return deleted, err
   205  	}
   206  	return deleted, response.Process(&deleted)
   207  }
   208  
   209  // Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
   210  func Tag(ctx context.Context, nameOrID, tag, repo string) error {
   211  	conn, err := bindings.GetClient(ctx)
   212  	if err != nil {
   213  		return err
   214  	}
   215  	params := url.Values{}
   216  	params.Set("tag", tag)
   217  	params.Set("repo", repo)
   218  	response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/tag", params, nil, nameOrID)
   219  	if err != nil {
   220  		return err
   221  	}
   222  	return response.Process(nil)
   223  }
   224  
   225  // Untag removes a name from locally-stored image. Both the tag and repo parameters are required.
   226  func Untag(ctx context.Context, nameOrID, tag, repo string) error {
   227  	conn, err := bindings.GetClient(ctx)
   228  	if err != nil {
   229  		return err
   230  	}
   231  	params := url.Values{}
   232  	params.Set("tag", tag)
   233  	params.Set("repo", repo)
   234  	response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/untag", params, nil, nameOrID)
   235  	if err != nil {
   236  		return err
   237  	}
   238  	return response.Process(nil)
   239  }
   240  
   241  // Imports adds the given image to the local image store.  This can be done by file and the given reader
   242  // or via the url parameter.  Additional metadata can be associated with the image by using the changes and
   243  // message parameters.  The image can also be tagged given a reference. One of url OR r must be provided.
   244  func Import(ctx context.Context, changes []string, message, reference, u *string, r io.Reader) (*entities.ImageImportReport, error) {
   245  	var report entities.ImageImportReport
   246  	if r != nil && u != nil {
   247  		return nil, errors.New("url and r parameters cannot be used together")
   248  	}
   249  	conn, err := bindings.GetClient(ctx)
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  	params := url.Values{}
   254  	for _, change := range changes {
   255  		params.Add("changes", change)
   256  	}
   257  	if message != nil {
   258  		params.Set("message", *message)
   259  	}
   260  	if reference != nil {
   261  		params.Set("reference", *reference)
   262  	}
   263  	if u != nil {
   264  		params.Set("url", *u)
   265  	}
   266  	response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  	return &report, response.Process(&report)
   271  }
   272  
   273  // Push is the binding for libpod's v2 endpoints for push images.  Note that
   274  // `source` must be a referring to an image in the remote's container storage.
   275  // The destination must be a reference to a registry (i.e., of docker transport
   276  // or be normalized to one).  Other transports are rejected as they do not make
   277  // sense in a remote context.
   278  func Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
   279  	conn, err := bindings.GetClient(ctx)
   280  	if err != nil {
   281  		return err
   282  	}
   283  
   284  	// TODO: have a global system context we can pass around (1st argument)
   285  	header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
   286  	if err != nil {
   287  		return err
   288  	}
   289  
   290  	params := url.Values{}
   291  	params.Set("destination", destination)
   292  	if options.SkipTLSVerify != types.OptionalBoolUndefined {
   293  		// Note: we have to verify if skipped is false.
   294  		verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
   295  		params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
   296  	}
   297  
   298  	path := fmt.Sprintf("/images/%s/push", source)
   299  	response, err := conn.DoRequest(nil, http.MethodPost, path, params, header)
   300  	if err != nil {
   301  		return err
   302  	}
   303  
   304  	return response.Process(err)
   305  }
   306  
   307  // Search is the binding for libpod's v2 endpoints for Search images.
   308  func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) {
   309  	conn, err := bindings.GetClient(ctx)
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  	params := url.Values{}
   314  	params.Set("term", term)
   315  	params.Set("limit", strconv.Itoa(opts.Limit))
   316  	params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc))
   317  	params.Set("listTags", strconv.FormatBool(opts.ListTags))
   318  	for _, f := range opts.Filters {
   319  		params.Set("filters", f)
   320  	}
   321  
   322  	if opts.SkipTLSVerify != types.OptionalBoolUndefined {
   323  		// Note: we have to verify if skipped is false.
   324  		verifyTLS := bool(opts.SkipTLSVerify == types.OptionalBoolFalse)
   325  		params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
   326  	}
   327  
   328  	// TODO: have a global system context we can pass around (1st argument)
   329  	header, err := auth.Header(nil, auth.XRegistryAuthHeader, opts.Authfile, "", "")
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  
   334  	response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params, header)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	results := []entities.ImageSearchReport{}
   340  	if err := response.Process(&results); err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	return results, nil
   345  }