github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/state/backups/testing/file.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  import (
     7  	"archive/tar"
     8  	"bytes"
     9  	"compress/gzip"
    10  	"io"
    11  	"path"
    12  	"strings"
    13  
    14  	"github.com/juju/collections/set"
    15  	"github.com/juju/errors"
    16  
    17  	"github.com/juju/juju/state/backups"
    18  )
    19  
    20  // File represents a file during testing.
    21  type File struct {
    22  	// Name is the path to which the file will be identified in the archive.
    23  	Name string
    24  	// Content is the data that will be written to the archive for the file.
    25  	Content string
    26  	// IsDir determines if the file is a regular file or a directory.
    27  	IsDir bool
    28  }
    29  
    30  // AddToArchive adds the file to the tar archive.
    31  func (f *File) AddToArchive(archive *tar.Writer) error {
    32  	hdr := &tar.Header{
    33  		Name: f.Name,
    34  	}
    35  	if f.IsDir {
    36  		hdr.Typeflag = tar.TypeDir
    37  		hdr.Mode = 0777
    38  	} else {
    39  		hdr.Size = int64(len(f.Content))
    40  		hdr.Mode = 0666
    41  	}
    42  
    43  	if err := archive.WriteHeader(hdr); err != nil {
    44  		return errors.Trace(err)
    45  	}
    46  
    47  	if !f.IsDir {
    48  		if _, err := archive.Write([]byte(f.Content)); err != nil {
    49  			return errors.Trace(err)
    50  		}
    51  	}
    52  
    53  	return nil
    54  }
    55  
    56  // NewArchive returns a new archive file containing the files.
    57  func NewArchive(meta *backups.Metadata, files, dump []File) (*bytes.Buffer, error) {
    58  	dirs := set.NewStrings()
    59  	var sysFiles []File
    60  	for _, file := range files {
    61  		var parent string
    62  		for _, p := range strings.Split(path.Dir(file.Name), "/") {
    63  			if parent == "" {
    64  				parent = p
    65  			} else {
    66  				parent = path.Join(parent, p)
    67  			}
    68  			if !dirs.Contains(parent) {
    69  				sysFiles = append(sysFiles, File{
    70  					Name:  parent,
    71  					IsDir: true,
    72  				})
    73  				dirs.Add(parent)
    74  			}
    75  		}
    76  		if file.IsDir {
    77  			if !dirs.Contains(file.Name) {
    78  				sysFiles = append(sysFiles, file)
    79  				dirs.Add(file.Name)
    80  			}
    81  		} else {
    82  			sysFiles = append(sysFiles, file)
    83  		}
    84  	}
    85  
    86  	var rootFile bytes.Buffer
    87  	if err := writeToTar(&rootFile, sysFiles); err != nil {
    88  		return nil, errors.Trace(err)
    89  	}
    90  
    91  	topfiles := []File{{
    92  		Name:  "juju-backup",
    93  		IsDir: true,
    94  	}}
    95  
    96  	topfiles = append(topfiles, File{
    97  		Name:  "juju-backup/dump",
    98  		IsDir: true,
    99  	})
   100  	for _, dumpFile := range dump {
   101  		topfiles = append(topfiles, File{
   102  			Name:    "juju-backup/dump/" + dumpFile.Name,
   103  			Content: dumpFile.Content,
   104  			IsDir:   dumpFile.IsDir,
   105  		})
   106  	}
   107  
   108  	topfiles = append(topfiles,
   109  		File{
   110  			Name:    "juju-backup/root.tar",
   111  			Content: rootFile.String(),
   112  		},
   113  	)
   114  
   115  	if meta != nil {
   116  		metaFile, err := meta.AsJSONBuffer()
   117  		if err != nil {
   118  			return nil, errors.Trace(err)
   119  		}
   120  		topfiles = append(topfiles,
   121  			File{
   122  				Name:    "juju-backup/metadata.json",
   123  				Content: metaFile.(*bytes.Buffer).String(),
   124  			},
   125  		)
   126  	}
   127  
   128  	var arFile bytes.Buffer
   129  	compressed := gzip.NewWriter(&arFile)
   130  	defer compressed.Close()
   131  	if err := writeToTar(compressed, topfiles); err != nil {
   132  		return nil, errors.Trace(err)
   133  	}
   134  
   135  	return &arFile, nil
   136  }
   137  
   138  // NewArchiveBasic returns a new archive file with a few files provided.
   139  func NewArchiveBasic(meta *backups.Metadata) (*bytes.Buffer, error) {
   140  	files := []File{
   141  		{
   142  			Name:    "var/lib/juju/tools/1.21-alpha2.1-trusty-amd64/jujud",
   143  			Content: "<some binary data goes here>",
   144  		},
   145  		{
   146  			Name:    "var/lib/juju/system-identity",
   147  			Content: "<an ssh key goes here>",
   148  		},
   149  	}
   150  	dump := []File{
   151  		{
   152  			Name:    "juju/machines.bson",
   153  			Content: "<BSON data goes here>",
   154  		},
   155  		{
   156  			Name:    "oplog.bson",
   157  			Content: "<BSON data goes here>",
   158  		},
   159  	}
   160  
   161  	arFile, err := NewArchive(meta, files, dump)
   162  	if err != nil {
   163  		return nil, errors.Trace(err)
   164  	}
   165  	return arFile, nil
   166  }
   167  
   168  func writeToTar(archive io.Writer, files []File) error {
   169  	tarw := tar.NewWriter(archive)
   170  	defer tarw.Close()
   171  
   172  	for _, file := range files {
   173  		if err := file.AddToArchive(tarw); err != nil {
   174  			return errors.Trace(err)
   175  		}
   176  	}
   177  	return nil
   178  }