Use Go code to extract rootfs from system containers

- this removes the use of riddler to extract the rootfs, use code
  we were using for rootfs. riddler now just geenrates the config,
  next stage is to generate this ourselves
- change the naming of the daemons so no longer include number as we
  do not guarantee ordering as they start up simultaneously

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
Justin Cormack
2017-03-24 13:05:28 +00:00
parent cc5f42dc9d
commit 2be31831d8
4 changed files with 124 additions and 41 deletions

View File

@@ -164,23 +164,69 @@ nameserver 2001:4860:4860::8844
"etc/hostname": "moby",
}
func imageExtract(image string) ([]byte, error) {
// ImageExtract extracts the filesystem from an image and returns a tarball with the files prefixed by the given path
func ImageExtract(image, prefix string) ([]byte, error) {
out := new(bytes.Buffer)
tw := tar.NewWriter(out)
err := tarPrefix(prefix, tw)
if err != nil {
return []byte{}, err
}
err = imageTar(image, prefix, tw)
if err != nil {
return []byte{}, err
}
err = tw.Close()
if err != nil {
return []byte{}, err
}
return out.Bytes(), nil
}
// tarPrefix creates the leading directories for a path
func tarPrefix(path string, tw *tar.Writer) error {
if path == "" {
return nil
}
if path[len(path)-1] != byte('/') {
return fmt.Errorf("path does not end with /: %s", path)
}
path = path[:len(path)-1]
if path[0] == byte('/') {
return fmt.Errorf("path should be relative: %s", path)
}
mkdir := ""
for _, dir := range strings.Split(path, "/") {
mkdir = mkdir + dir
hdr := &tar.Header{
Name: mkdir,
Mode: 0755,
Typeflag: tar.TypeDir,
}
tw.WriteHeader(hdr)
mkdir = mkdir + "/"
}
return nil
}
func imageTar(image, prefix string, tw *tar.Writer) error {
if prefix != "" && prefix[len(prefix)-1] != byte('/') {
return fmt.Errorf("prefix does not end with /: %s", prefix)
}
container, err := dockerCreate(image)
if err != nil {
return []byte{}, fmt.Errorf("Failed to docker create image %s: %v", image, err)
return fmt.Errorf("Failed to docker create image %s: %v", image, err)
}
contents, err := dockerExport(container)
if err != nil {
return []byte{}, fmt.Errorf("Failed to docker export container from container %s: %v", container, err)
return fmt.Errorf("Failed to docker export container from container %s: %v", container, err)
}
err = dockerRm(container)
if err != nil {
return []byte{}, fmt.Errorf("Failed to docker rm container %s: %v", container, err)
return fmt.Errorf("Failed to docker rm container %s: %v", container, err)
}
// now we need to filter out some files from the resulting tar archive
out := new(bytes.Buffer)
tw := tar.NewWriter(out)
r := bytes.NewReader(contents)
tr := tar.NewReader(r)
@@ -191,21 +237,58 @@ func imageExtract(image string) ([]byte, error) {
break
}
if err != nil {
return []byte{}, err
return err
}
if exclude[hdr.Name] {
io.Copy(ioutil.Discard, tr)
} else if replace[hdr.Name] != "" {
hdr.Size = int64(len(replace[hdr.Name]))
contents := replace[hdr.Name]
hdr.Size = int64(len(contents))
hdr.Name = prefix + hdr.Name
tw.WriteHeader(hdr)
buf := bytes.NewBufferString(replace[hdr.Name])
buf := bytes.NewBufferString(contents)
io.Copy(tw, buf)
io.Copy(ioutil.Discard, tr)
} else {
hdr.Name = prefix + hdr.Name
tw.WriteHeader(hdr)
io.Copy(tw, tr)
}
}
err = tw.Close()
if err != nil {
return err
}
return nil
}
// ImageBundle produces an OCI bundle at the given path in a tarball, given an image and a config.json
func ImageBundle(path, image, config string) ([]byte, error) {
out := new(bytes.Buffer)
tw := tar.NewWriter(out)
err := tarPrefix(path+"/rootfs/", tw)
if err != nil {
return []byte{}, err
}
hdr := &tar.Header{
Name: path + "/" + "config.json",
Mode: 0644,
Size: int64(len(config)),
}
err = tw.WriteHeader(hdr)
if err != nil {
return []byte{}, err
}
buf := bytes.NewBufferString(config)
_, err = io.Copy(tw, buf)
if err != nil {
return []byte{}, err
}
err = imageTar(image, path+"/rootfs/", tw)
if err != nil {
return []byte{}, err
}
err = tw.Close()
if err != nil {
return []byte{}, err
}