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 }