func runNew(context *cli.Context) { args := context.Args() if len(args) < 1 { fmt.Printf("args: %v", args) log.Errorf("provide an output file name") return } outImageName := context.String("image-name") if outImageName == "" { log.Errorf("provide an image name") return } fileName := args[0] manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: types.ACIdentifier(outImageName), } aciDir, err := util.PrepareACIDir(manifest, "") if err != nil { log.Fatalf("error prepareing ACI dir %v: %v", aciDir, err) } if err := util.BuildACI(aciDir, fileName, context.Bool("overwrite"), false); err != nil { log.Fatalf("error building the final output ACI: %v", err) } log.Infof("Image %v built successfully", fileName) }
func runAdd(context *cli.Context) { s := getStore() args := context.Args() if len(args) < 2 { fmt.Println("There need to be at least two arguments.") fmt.Println(context.Command.Usage) } var dependencies types.Dependencies for _, arg := range args[:len(args)-1] { layer, err := util.ExtractLayerInfo(s, arg) if err != nil { log.Fatalf("error extracting layer info from %s: %v", s, err) } dependencies = append(dependencies, layer) } out := args[len(args)-1] outImageName := context.String("output-image-name") manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: types.ACIdentifier(outImageName), Dependencies: dependencies, } aciDir, err := util.PrepareACIDir(manifest, "") if err != nil { log.Fatalf("error prepareing ACI dir %v: %v", aciDir, err) } if err := util.BuildACI(aciDir, out, true, false); err != nil { log.Fatalf("error building the final output ACI: %v", err) } }
func runExec(context *cli.Context) { flagIn := context.String("in") flagCmd := context.String("cmd") flagOut := context.String("out") if flagIn == "" || flagCmd == "" || flagOut == "" { log.Fatalf("--in, --cmd, and --out need to be set") } flagNoOverlay := context.Bool("no-overlay") useOverlay := util.SupportsOverlay() && !flagNoOverlay s := getStore() mounts, err := getMounts(context) if err != nil { log.Fatalf("error parsing mounts: %v", err) } // Render the given image in tree store imageHash, err := renderInStore(s, flagIn) if err != nil { log.Fatalf("error rendering image in store: %s", err) } imagePath := s.GetTreeStorePath(imageHash) // Create a tmp directory tmpDir, err := ioutil.TempDir("", "acbuild-") if err != nil { log.Fatalf("error creating temporary directory: %s", err) } // Copy the manifest into the tmp directory if err := shutil.CopyFile(filepath.Join(imagePath, aci.ManifestFile), filepath.Join(tmpDir, aci.ManifestFile), true); err != nil { log.Fatalf("error copying manifest to a temporary directory: %s", err) } // Extract a ImageManifest from the manifest file manifestFile, err := os.Open(filepath.Join(tmpDir, aci.ManifestFile)) if err != nil { log.Fatalf("error opening the copied manifest file: %v", err) } manifestContent, err := ioutil.ReadAll(manifestFile) if err != nil { log.Fatalf("error reading the copied manifest file: %v", err) } im := &schema.ImageManifest{} if err := im.UnmarshalJSON(manifestContent); err != nil { log.Fatalf("error unmarshalling JSON to manifest: %v", err) } // If an output image name is not given, we grab it from the input ACI flagImageName := context.String("output-image-name") if flagImageName == "" { flagImageName = string(im.Name) } flagJail := context.Bool("jail") // If the system supports overlayfs, use it. // Otherwise, copy the entire rendered image to a working directory. storeRootfsDir := filepath.Join(imagePath, aci.RootfsDir) tmpRootfsDir := filepath.Join(tmpDir, aci.RootfsDir) if useOverlay { upperDir, err := mountOverlayfs(tmpRootfsDir, storeRootfsDir) if err != nil { log.Fatalf("error mounting overlayfs: %v", err) } // Note that defer functions are not run if the program // exits via os.Exit() and by extension log.Fatal(), which // is the behaviour that we want. defer unmountOverlayfs(tmpRootfsDir) if err := runCmdInDir(im, flagCmd, tmpRootfsDir, flagJail, mounts); err != nil { log.Fatalf("error executing command: %v", err) } // We store the delta (i.e. side effects of the executed command) into its own ACI // The name of the ACI is a hash of (command, hash of input image). This will make // implementing caching easier in the future. deltaACIName, err := util.Hash(flagCmd, imageHash) if err != nil { log.Fatalf("error hashing (%s %s): %s", flagCmd, imageHash, err) } deltaManifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: types.ACIdentifier(deltaACIName), } deltaACIDir, err := util.PrepareACIDir(deltaManifest, upperDir) if err != nil { log.Fatalf("error preparing delta ACI dir: %v", err) } // Create a temp directory for placing delta ACI deltaACITempDir, err := ioutil.TempDir("", "") if err != nil { log.Fatalf("error creating temp dir to put delta ACI: %v", err) } deltaACIPath := filepath.Join(deltaACITempDir, "delta.aci") // Build the delta ACI if err := util.BuildACI(deltaACIDir, deltaACIPath, true, false); err != nil { log.Fatalf("error building delta ACI: %v", err) } // Put the delta ACI into tree store deltaACIFile, err := os.Open(deltaACIPath) if err != nil { log.Fatalf("error opening the delta ACI file: %v", err) } deltaKey, err := s.WriteACI(deltaACIFile, false) if err != nil { log.Fatalf("error writing the delta ACI into the tree store: %v", err) } deltaKeyHash, err := types.NewHash(deltaKey) if err != nil { log.Fatalf("error creating hash from an image ID (%s): %v", deltaKeyHash, err) } // The manifest for the output ACI manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: types.ACIdentifier(flagImageName), } if context.Bool("split") { layers, err := util.ExtractLayers(s, flagIn) if err != nil { log.Fatalf("error extracting layers from %s: %v", flagIn, err) } manifest.Dependencies = append(manifest.Dependencies, layers...) manifest.Dependencies = append(manifest.Dependencies, types.Dependency{ ImageName: types.ACIdentifier(deltaACIName), ImageID: deltaKeyHash, }) } else { layer, err := util.ExtractLayerInfo(s, flagIn) if err != nil { log.Fatalf("error extracting layer info from input ACI: %v", err) } // two layers: // 1. The original ACI // 2. The delta ACI manifest.Dependencies = types.Dependencies{ layer, types.Dependency{ ImageName: types.ACIdentifier(deltaACIName), ImageID: deltaKeyHash, }, } } // The rootfs is empty aciDir, err := util.PrepareACIDir(manifest, "") if err != nil { log.Fatalf("error prepareing ACI dir %v: %v", aciDir, err) } // Build the output ACI if err := util.BuildACI(aciDir, flagOut, true, false); err != nil { log.Fatalf("error building the final output ACI: %v", err) } } else { if err := shutil.CopyTree(storeRootfsDir, tmpRootfsDir, &shutil.CopyTreeOptions{ Symlinks: true, IgnoreDanglingSymlinks: true, CopyFunction: shutil.Copy, }); err != nil { log.Fatalf("error copying rootfs to a temporary directory: %v", err) } if err := runCmdInDir(im, flagCmd, tmpRootfsDir, flagJail, mounts); err != nil { log.Fatalf("error executing command: %v", err) } err = util.BuildACI(tmpDir, flagOut, true, false) if err != nil { log.Fatalf("error building output ACI image: %v", err) } } }