4 changed files with 197 additions and 37 deletions
@ -0,0 +1,178 @@
|
||||
package cmd |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
|
||||
"archive/tar" |
||||
"bytes" |
||||
"compress/gzip" |
||||
"encoding/json" |
||||
"io" |
||||
"os" |
||||
"time" |
||||
|
||||
"github.com/appc/spec/aci" |
||||
"github.com/appc/spec/schema" |
||||
"github.com/appc/spec/schema/types" |
||||
"github.com/spf13/cobra" |
||||
) |
||||
|
||||
var ( |
||||
importTarFilePath string |
||||
importTarManifest string |
||||
importTarImage string |
||||
importTarName string |
||||
) |
||||
|
||||
// createCmd represents the create command
|
||||
var importTarCmd = &cobra.Command{ |
||||
Use: "import-tar", |
||||
Short: "Import a OS Tarball", |
||||
Long: `Imports an OS Tarball as an Image. The only rule for the tarball is, |
||||
that it contains a folders rootfs folder and the root of the OS under that. |
||||
This command will then create an empty imageManifest or add the one specified by the -m command. |
||||
It can also grab a manifest from an existing image with -i. |
||||
This command is mostly a workaround for the golang Tar writer failing. |
||||
`, |
||||
Run: importTarCmdrun, |
||||
Args: cobra.MinimumNArgs(1), |
||||
} |
||||
|
||||
func init() { |
||||
RootCmd.AddCommand(importTarCmd) |
||||
importTarCmd.Flags().StringVarP(&importTarFilePath, "file", "f", "", "the file to import") |
||||
importTarCmd.Flags().StringVarP(&importTarManifest, "manifest", "m", "", "the manifest to use for the new image") |
||||
importTarCmd.Flags().StringVarP(&importTarImage, "image", "i", "", "The Image to use as the source") |
||||
importTarCmd.Flags().StringVarP(&importTarName, "name", "n", "", "name for the new image") |
||||
} |
||||
|
||||
func importTarCmdrun(cmd *cobra.Command, args []string) { |
||||
var manifest schema.ImageManifest |
||||
if importTarFilePath != "" { |
||||
f, err := os.Open(importTarFilePath) |
||||
defer f.Close() |
||||
if err != nil { |
||||
fmt.Printf("can not open manifest: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
if err = json.NewDecoder(f).Decode(&manifest); err != nil { |
||||
fmt.Printf("not proper manifest: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
} else if importTarName != "" { |
||||
manifest = *schema.BlankImageManifest() |
||||
manifest.Name = types.ACIdentifier(importTarName) |
||||
} else if importTarImage != "" { |
||||
f, err := os.Open(importTarImage) |
||||
if err != nil { |
||||
fmt.Printf("can not open image: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
gr, err := gzip.NewReader(f) |
||||
if err != nil { |
||||
gr = nil |
||||
} |
||||
defer gr.Close() |
||||
var tr *tar.Reader |
||||
if gr != nil { |
||||
tr = tar.NewReader(gr) |
||||
} else { |
||||
tr = tar.NewReader(f) |
||||
} |
||||
for { |
||||
hdr, err := tr.Next() |
||||
if err == io.EOF { |
||||
break |
||||
} |
||||
if err != nil { |
||||
fmt.Printf("could not read entry %s: %s\n", hdr.Name, err) |
||||
break |
||||
} |
||||
if hdr.Name == aci.ManifestFile { |
||||
err = json.NewDecoder(tr).Decode(&manifest) |
||||
if err != nil { |
||||
fmt.Printf("could not decode manifest from image: %s\n", err) |
||||
break |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
fmt.Printf("Either an original Image a manifest or a Name is required\n") |
||||
os.Exit(1) |
||||
} |
||||
if manifest.Name == "" { |
||||
os.Exit(1) |
||||
} |
||||
tarName := args[0] |
||||
aciName := tarName[:strings.Index(tarName, ".")] + ".aci" |
||||
|
||||
var tw *tar.Writer |
||||
var tr *tar.Reader |
||||
aciFH, err := os.OpenFile(aciName, os.O_CREATE|os.O_RDWR, os.ModePerm) |
||||
if err != nil { |
||||
fmt.Printf("can not create new image file: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
tarFH, err := os.OpenFile(tarName, os.O_RDONLY, os.ModePerm) |
||||
if err != nil { |
||||
fmt.Printf("can not open tar to import: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
if strings.Contains(tarName, ".gz") { |
||||
gr, err := gzip.NewReader(tarFH) |
||||
if err != nil { |
||||
fmt.Printf("can not open tgz for reading: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
defer gr.Close() |
||||
tr = tar.NewReader(gr) |
||||
} else { |
||||
tr = tar.NewReader(tarFH) |
||||
} |
||||
tw = tar.NewWriter(gzip.NewWriter(aciFH)) |
||||
defer tw.Close() |
||||
out, err := manifest.MarshalJSON() |
||||
buff := bytes.NewBuffer(out) |
||||
if err != nil { |
||||
fmt.Printf("could not create manifest JSON: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
now := time.Now() |
||||
hdr := tar.Header{ |
||||
Name: aci.ManifestFile, |
||||
Mode: 0644, |
||||
Uid: 0, |
||||
Gid: 0, |
||||
Size: int64(buff.Len()), |
||||
ModTime: now, |
||||
Typeflag: tar.TypeReg, |
||||
Uname: "root", |
||||
Gname: "root", |
||||
ChangeTime: now, |
||||
} |
||||
err = tw.WriteHeader(&hdr) |
||||
if err != nil { |
||||
fmt.Printf("can not write header: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
_, err = tw.Write(buff.Bytes()) |
||||
if err != nil { |
||||
fmt.Printf("could not write content od manifest: %s\n", err) |
||||
os.Exit(1) |
||||
} |
||||
for { |
||||
hdr, err := tr.Next() |
||||
if err == io.EOF { |
||||
break |
||||
} |
||||
if err != nil { |
||||
fmt.Printf("could not read entry %s: %s\n", hdr.Name, err) |
||||
break |
||||
} |
||||
tw.WriteHeader(hdr) |
||||
if _, err := io.Copy(tw, tr); err != nil { |
||||
fmt.Printf("could not copy %s\n", err) |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue