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 }