github.com/dctrud/umoci@v0.4.3-0.20191016193643-05a1d37de015/cmd/umoci/new.go (about) 1 /* 2 * umoci: Umoci Modifies Open Containers' Images 3 * Copyright (C) 2016, 2017, 2018 SUSE LLC. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package main 19 20 import ( 21 "runtime" 22 "time" 23 24 "github.com/apex/log" 25 "github.com/openSUSE/umoci/oci/cas/dir" 26 "github.com/openSUSE/umoci/oci/casext" 27 igen "github.com/openSUSE/umoci/oci/config/generate" 28 imeta "github.com/opencontainers/image-spec/specs-go" 29 ispec "github.com/opencontainers/image-spec/specs-go/v1" 30 "github.com/pkg/errors" 31 "github.com/urfave/cli" 32 "golang.org/x/net/context" 33 ) 34 35 var newCommand = cli.Command{ 36 Name: "new", 37 Usage: "creates a blank tagged OCI image", 38 ArgsUsage: `--image <image-path>:<new-tag> 39 40 Where "<image-path>" is the path to the OCI image, and "<new-tag>" is the name 41 of the tag for the empty manifest. 42 43 Once you create a new image with umoci-new(1) you can directly use the image 44 with umoci-unpack(1), umoci-repack(1), and umoci-config(1) to modify the new 45 manifest as you see fit. This allows you to create entirely new images without 46 needing a base image to start from.`, 47 48 // new modifies an image layout. 49 Category: "image", 50 51 Action: newImage, 52 } 53 54 func newImage(ctx *cli.Context) error { 55 imagePath := ctx.App.Metadata["--image-path"].(string) 56 tagName := ctx.App.Metadata["--image-tag"].(string) 57 58 // Get a reference to the CAS. 59 engine, err := dir.Open(imagePath) 60 if err != nil { 61 return errors.Wrap(err, "open CAS") 62 } 63 engineExt := casext.NewEngine(engine) 64 defer engine.Close() 65 66 // Create a new manifest. 67 log.WithFields(log.Fields{ 68 "tag": tagName, 69 }).Debugf("creating new manifest") 70 71 // Create a new image config. 72 g := igen.New() 73 createTime := time.Now() 74 75 // Set all of the defaults we need. 76 g.SetCreated(createTime) 77 g.SetOS(runtime.GOOS) 78 g.SetArchitecture(runtime.GOARCH) 79 g.ClearHistory() 80 81 // Make sure we have no diffids. 82 g.SetRootfsType("layers") 83 g.ClearRootfsDiffIDs() 84 85 // Update config and create a new blob for it. 86 config := g.Image() 87 configDigest, configSize, err := engineExt.PutBlobJSON(context.Background(), config) 88 if err != nil { 89 return errors.Wrap(err, "put config blob") 90 } 91 92 log.WithFields(log.Fields{ 93 "digest": configDigest, 94 "size": configSize, 95 }).Debugf("umoci: added new config") 96 97 // Create a new manifest that just points to the config and has an 98 // empty layer set. FIXME: Implement ManifestList support. 99 manifest := ispec.Manifest{ 100 Versioned: imeta.Versioned{ 101 SchemaVersion: 2, // FIXME: This is hardcoded at the moment. 102 }, 103 Config: ispec.Descriptor{ 104 MediaType: ispec.MediaTypeImageConfig, 105 Digest: configDigest, 106 Size: configSize, 107 }, 108 Layers: []ispec.Descriptor{}, 109 } 110 111 manifestDigest, manifestSize, err := engineExt.PutBlobJSON(context.Background(), manifest) 112 if err != nil { 113 return errors.Wrap(err, "put manifest blob") 114 } 115 116 log.WithFields(log.Fields{ 117 "digest": manifestDigest, 118 "size": manifestSize, 119 }).Debugf("umoci: added new manifest") 120 121 // Now create a new reference, and either add it to the engine or spew it 122 // to stdout. 123 124 descriptor := ispec.Descriptor{ 125 // FIXME: Support manifest lists. 126 MediaType: ispec.MediaTypeImageManifest, 127 Digest: manifestDigest, 128 Size: manifestSize, 129 } 130 131 log.Infof("new image manifest created: %s", descriptor.Digest) 132 133 if err := engineExt.UpdateReference(context.Background(), tagName, descriptor); err != nil { 134 return errors.Wrap(err, "add new tag") 135 } 136 137 log.Infof("created new tag for image manifest: %s", tagName) 138 139 return nil 140 }