github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/imagetool/addImagesub.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  
     9  	"github.com/Cloud-Foundations/Dominator/imageserver/client"
    10  	"github.com/Cloud-Foundations/Dominator/lib/constants"
    11  	"github.com/Cloud-Foundations/Dominator/lib/filesystem"
    12  	"github.com/Cloud-Foundations/Dominator/lib/filter"
    13  	"github.com/Cloud-Foundations/Dominator/lib/hash"
    14  	"github.com/Cloud-Foundations/Dominator/lib/image"
    15  	"github.com/Cloud-Foundations/Dominator/lib/log"
    16  	objectclient "github.com/Cloud-Foundations/Dominator/lib/objectserver/client"
    17  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    18  	subclient "github.com/Cloud-Foundations/Dominator/sub/client"
    19  )
    20  
    21  func addImagesubSubcommand(args []string, logger log.DebugLogger) error {
    22  	imageSClient, objectClient := getClients()
    23  	err := addImagesub(imageSClient, objectClient, args[0], args[1], args[2],
    24  		args[3])
    25  	if err != nil {
    26  		return fmt.Errorf("Error adding image: \"%s\"\t%s", args[0], err)
    27  	}
    28  	return nil
    29  }
    30  
    31  func addImagesub(imageSClient *srpc.Client,
    32  	objectClient *objectclient.ObjectClient,
    33  	name, subName, filterFilename, triggersFilename string) error {
    34  	imageExists, err := client.CheckImage(imageSClient, name)
    35  	if err != nil {
    36  		return errors.New("error checking for image existence: " + err.Error())
    37  	}
    38  	if imageExists {
    39  		return errors.New("image exists")
    40  	}
    41  	newImage := new(image.Image)
    42  	if err := loadImageFiles(newImage, objectClient, filterFilename,
    43  		triggersFilename); err != nil {
    44  		return err
    45  	}
    46  	fs, err := pollImage(subName)
    47  	if err != nil {
    48  		return err
    49  	}
    50  	if fs, err = applyDeleteFilter(fs); err != nil {
    51  		return err
    52  	}
    53  	fs = fs.Filter(newImage.Filter)
    54  	if err := spliceComputedFiles(fs); err != nil {
    55  		return err
    56  	}
    57  	if err := copyMissingObjects(fs, imageSClient, objectClient,
    58  		subName); err != nil {
    59  		return err
    60  	}
    61  	newImage.FileSystem = fs
    62  	return addImage(imageSClient, name, newImage)
    63  }
    64  
    65  func applyDeleteFilter(fs *filesystem.FileSystem) (
    66  	*filesystem.FileSystem, error) {
    67  	if *deleteFilter == "" {
    68  		return fs, nil
    69  	}
    70  	filter, err := filter.Load(*deleteFilter)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	return fs.Filter(filter), nil
    75  }
    76  
    77  func copyMissingObjects(fs *filesystem.FileSystem, imageSClient *srpc.Client,
    78  	objectClient *objectclient.ObjectClient, subName string) error {
    79  	// Check to see which objects are in the objectserver.
    80  	hashes := make([]hash.Hash, 0, fs.NumRegularInodes)
    81  	for hash := range fs.HashToInodesTable() {
    82  		hashes = append(hashes, hash)
    83  	}
    84  	objectSizes, err := objectClient.CheckObjects(hashes)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	missingHashes := make(map[hash.Hash]struct{})
    89  	for index, size := range objectSizes {
    90  		if size < 1 {
    91  			missingHashes[hashes[index]] = struct{}{}
    92  		}
    93  	}
    94  	if len(missingHashes) < 1 {
    95  		return nil
    96  	}
    97  	// Get missing objects from sub.
    98  	filesForMissingObjects := make([]string, 0, len(missingHashes))
    99  	hashToFilename := make(map[hash.Hash]string)
   100  	for hashVal := range missingHashes {
   101  		if inums, ok := fs.HashToInodesTable()[hashVal]; !ok {
   102  			return fmt.Errorf("no inode for object: %x", hashVal)
   103  		} else if files, ok := fs.InodeToFilenamesTable()[inums[0]]; !ok {
   104  			return fmt.Errorf("no file for inode: %d", inums[0])
   105  		} else {
   106  			filesForMissingObjects = append(filesForMissingObjects, files[0])
   107  			hashToFilename[hashVal] = files[0]
   108  		}
   109  	}
   110  	objAdderQueue, err := objectclient.NewObjectAdderQueue(imageSClient)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	subClient, err := srpc.DialHTTP("tcp",
   115  		fmt.Sprintf("%s:%d", subName, constants.SubPortNumber), 0)
   116  	if err != nil {
   117  		return fmt.Errorf("error dialing %s", err)
   118  	}
   119  	defer subClient.Close()
   120  	err = subclient.GetFiles(subClient, filesForMissingObjects,
   121  		func(reader io.Reader, size uint64) error {
   122  			hashVal, err := objAdderQueue.Add(reader, size)
   123  			if err != nil {
   124  				return err
   125  			}
   126  			delete(missingHashes, hashVal)
   127  			return nil
   128  		})
   129  	if err != nil {
   130  		return err
   131  	}
   132  	if len(missingHashes) > 0 {
   133  		for hashVal := range missingHashes {
   134  			fmt.Fprintf(os.Stderr, "Contents for file changed: %s\n",
   135  				hashToFilename[hashVal])
   136  		}
   137  		return errors.New("one or more files on the sub changed")
   138  	}
   139  	return objAdderQueue.Close()
   140  }