github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/domain/infra/tunnel/images.go (about) 1 package tunnel 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "strings" 8 "time" 9 10 "github.com/containers/common/pkg/config" 11 "github.com/containers/image/v5/docker/reference" 12 images "github.com/containers/podman/v2/pkg/bindings/images" 13 "github.com/containers/podman/v2/pkg/domain/entities" 14 "github.com/containers/podman/v2/pkg/domain/utils" 15 utils2 "github.com/containers/podman/v2/utils" 16 "github.com/pkg/errors" 17 ) 18 19 func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) { 20 found, err := images.Exists(ir.ClientCxt, nameOrID) 21 return &entities.BoolReport{Value: found}, err 22 } 23 24 func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) { 25 return images.BatchRemove(ir.ClientCxt, imagesArg, opts) 26 } 27 28 func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) { 29 30 filters := make(map[string][]string, len(opts.Filter)) 31 for _, filter := range opts.Filter { 32 f := strings.Split(filter, "=") 33 filters[f[0]] = f[1:] 34 } 35 images, err := images.List(ir.ClientCxt, &opts.All, filters) 36 if err != nil { 37 return nil, err 38 } 39 40 is := make([]*entities.ImageSummary, len(images)) 41 for i, img := range images { 42 hold := entities.ImageSummary{} 43 if err := utils.DeepCopy(&hold, img); err != nil { 44 return nil, err 45 } 46 is[i] = &hold 47 } 48 return is, nil 49 } 50 51 func (ir *ImageEngine) Mount(ctx context.Context, images []string, options entities.ImageMountOptions) ([]*entities.ImageMountReport, error) { 52 return nil, errors.New("mounting images is not supported for remote clients") 53 } 54 55 func (ir *ImageEngine) Unmount(ctx context.Context, images []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) { 56 return nil, errors.New("unmounting images is not supported for remote clients") 57 } 58 59 func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) { 60 results, err := images.History(ir.ClientCxt, nameOrID) 61 if err != nil { 62 return nil, err 63 } 64 65 history := entities.ImageHistoryReport{ 66 Layers: make([]entities.ImageHistoryLayer, len(results)), 67 } 68 69 for i, layer := range results { 70 // Created time comes over as an int64 so needs conversion to time.time 71 t := time.Unix(layer.Created, 0) 72 hold := entities.ImageHistoryLayer{ 73 ID: layer.ID, 74 Created: t.UTC(), 75 CreatedBy: layer.CreatedBy, 76 Tags: layer.Tags, 77 Size: layer.Size, 78 Comment: layer.Comment, 79 } 80 history.Layers[i] = hold 81 } 82 return &history, nil 83 } 84 85 func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) { 86 filters := make(map[string][]string, len(opts.Filter)) 87 for _, filter := range opts.Filter { 88 f := strings.Split(filter, "=") 89 filters[f[0]] = f[1:] 90 } 91 92 results, err := images.Prune(ir.ClientCxt, &opts.All, filters) 93 if err != nil { 94 return nil, err 95 } 96 97 report := entities.ImagePruneReport{ 98 Report: entities.Report{ 99 Id: results, 100 Err: nil, 101 }, 102 Size: 0, 103 } 104 return &report, nil 105 } 106 107 func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) (*entities.ImagePullReport, error) { 108 pulledImages, err := images.Pull(ir.ClientCxt, rawImage, options) 109 if err != nil { 110 return nil, err 111 } 112 return &entities.ImagePullReport{Images: pulledImages}, nil 113 } 114 115 func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error { 116 for _, newTag := range tags { 117 var ( 118 tag, repo string 119 ) 120 ref, err := reference.Parse(newTag) 121 if err != nil { 122 return errors.Wrapf(err, "error parsing reference %q", newTag) 123 } 124 if t, ok := ref.(reference.Tagged); ok { 125 tag = t.Tag() 126 } 127 if r, ok := ref.(reference.Named); ok { 128 repo = r.Name() 129 } 130 if len(repo) < 1 { 131 return errors.Errorf("invalid image name %q", nameOrID) 132 } 133 if err := images.Tag(ir.ClientCxt, nameOrID, tag, repo); err != nil { 134 return err 135 } 136 } 137 return nil 138 } 139 140 func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error { 141 if len(tags) == 0 { 142 return images.Untag(ir.ClientCxt, nameOrID, "", "") 143 } 144 145 for _, newTag := range tags { 146 var ( 147 tag, repo string 148 ) 149 ref, err := reference.Parse(newTag) 150 if err != nil { 151 return errors.Wrapf(err, "error parsing reference %q", newTag) 152 } 153 if t, ok := ref.(reference.Tagged); ok { 154 tag = t.Tag() 155 } 156 if r, ok := ref.(reference.Named); ok { 157 repo = r.Name() 158 } 159 if len(repo) < 1 { 160 return errors.Errorf("invalid image name %q", nameOrID) 161 } 162 if err := images.Untag(ir.ClientCxt, nameOrID, tag, repo); err != nil { 163 return err 164 } 165 } 166 return nil 167 } 168 169 func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) { 170 reports := []*entities.ImageInspectReport{} 171 errs := []error{} 172 for _, i := range namesOrIDs { 173 r, err := images.GetImage(ir.ClientCxt, i, &opts.Size) 174 if err != nil { 175 errModel, ok := err.(entities.ErrorModel) 176 if !ok { 177 return nil, nil, err 178 } 179 if errModel.ResponseCode == 404 { 180 errs = append(errs, errors.Wrapf(err, "unable to inspect %q", i)) 181 continue 182 } 183 return nil, nil, err 184 } 185 reports = append(reports, r) 186 } 187 return reports, errs, nil 188 } 189 190 func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) { 191 f, err := os.Open(opts.Input) 192 if err != nil { 193 return nil, err 194 } 195 defer f.Close() 196 fInfo, err := f.Stat() 197 if err != nil { 198 return nil, err 199 } 200 if fInfo.IsDir() { 201 return nil, errors.Errorf("remote client supports archives only but %q is a directory", opts.Input) 202 } 203 ref := opts.Name 204 if len(opts.Tag) > 0 { 205 ref += ":" + opts.Tag 206 } 207 return images.Load(ir.ClientCxt, f, &ref) 208 } 209 210 func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOptions) (*entities.ImageImportReport, error) { 211 var ( 212 err error 213 sourceURL *string 214 f *os.File 215 ) 216 if opts.SourceIsURL { 217 sourceURL = &opts.Source 218 } else { 219 f, err = os.Open(opts.Source) 220 if err != nil { 221 return nil, err 222 } 223 } 224 return images.Import(ir.ClientCxt, opts.Changes, &opts.Message, &opts.Reference, sourceURL, f) 225 } 226 227 func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error { 228 return images.Push(ir.ClientCxt, source, destination, options) 229 } 230 231 func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error { 232 var ( 233 f *os.File 234 err error 235 ) 236 switch options.Format { 237 case "oci-dir", "docker-dir": 238 f, err = ioutil.TempFile("", "podman_save") 239 if err == nil { 240 defer func() { _ = os.Remove(f.Name()) }() 241 } 242 default: 243 f, err = os.Create(options.Output) 244 } 245 if err != nil { 246 return err 247 } 248 249 if options.MultiImageArchive { 250 exErr := images.MultiExport(ir.ClientCxt, append([]string{nameOrID}, tags...), f, &options.Format, &options.Compress) 251 if err := f.Close(); err != nil { 252 return err 253 } 254 if exErr != nil { 255 return exErr 256 } 257 } else { 258 // FIXME: tags are entirely ignored here but shouldn't. 259 exErr := images.Export(ir.ClientCxt, nameOrID, f, &options.Format, &options.Compress) 260 if err := f.Close(); err != nil { 261 return err 262 } 263 if exErr != nil { 264 return exErr 265 } 266 } 267 268 if options.Format != "oci-dir" && options.Format != "docker-dir" { 269 return nil 270 } 271 272 f, err = os.Open(f.Name()) 273 if err != nil { 274 return err 275 } 276 info, err := os.Stat(options.Output) 277 switch { 278 case err == nil: 279 if info.Mode().IsRegular() { 280 return errors.Errorf("%q already exists as a regular file", options.Output) 281 } 282 case os.IsNotExist(err): 283 if err := os.Mkdir(options.Output, 0755); err != nil { 284 return err 285 } 286 default: 287 return err 288 } 289 return utils2.UntarToFileSystem(options.Output, f, nil) 290 } 291 292 // Diff reports the changes to the given image 293 func (ir *ImageEngine) Diff(ctx context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) { 294 changes, err := images.Diff(ir.ClientCxt, nameOrID) 295 if err != nil { 296 return nil, err 297 } 298 return &entities.DiffReport{Changes: changes}, nil 299 } 300 301 func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) { 302 return images.Search(ir.ClientCxt, term, opts) 303 } 304 305 func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) { 306 return config.Default() 307 } 308 309 func (ir *ImageEngine) Build(_ context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) { 310 report, err := images.Build(ir.ClientCxt, containerFiles, opts) 311 if err != nil { 312 return nil, err 313 } 314 // For remote clients, if the option for writing to a file was 315 // selected, we need to write to the *client's* filesystem. 316 if len(opts.IIDFile) > 0 { 317 f, err := os.Create(opts.IIDFile) 318 if err != nil { 319 return nil, err 320 } 321 if _, err := f.WriteString(report.ID); err != nil { 322 return nil, err 323 } 324 } 325 return report, nil 326 } 327 328 func (ir *ImageEngine) Tree(ctx context.Context, nameOrID string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) { 329 return images.Tree(ir.ClientCxt, nameOrID, &opts.WhatRequires) 330 } 331 332 // Shutdown Libpod engine 333 func (ir *ImageEngine) Shutdown(_ context.Context) { 334 } 335 336 func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entities.SignOptions) (*entities.SignReport, error) { 337 return nil, errors.New("not implemented yet") 338 }