github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/imagetool/addReplaceImage.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "strconv" 8 "strings" 9 10 "github.com/Cloud-Foundations/Dominator/imageserver/client" 11 "github.com/Cloud-Foundations/Dominator/lib/filesystem" 12 "github.com/Cloud-Foundations/Dominator/lib/log" 13 objectclient "github.com/Cloud-Foundations/Dominator/lib/objectserver/client" 14 "github.com/Cloud-Foundations/Dominator/lib/srpc" 15 ) 16 17 func addReplaceImageSubcommand(args []string, logger log.DebugLogger) error { 18 imageSClient, objectClient := getClients() 19 err := addReplaceImage(imageSClient, objectClient, args[0], args[1], 20 args[2:], logger) 21 if err != nil { 22 return fmt.Errorf("error adding image: \"%s\": %s", args[0], err) 23 } 24 return nil 25 } 26 27 func bulkAddReplaceImagesSubcommand(args []string, 28 logger log.DebugLogger) error { 29 imageSClient, objectClient := getClients() 30 err := bulkAddReplaceImages(imageSClient, objectClient, args, logger) 31 if err != nil { 32 return fmt.Errorf("error adding image: \"%s\": %s", args[0], err) 33 } 34 return nil 35 } 36 37 func addReplaceImage(imageSClient *srpc.Client, 38 objectClient *objectclient.ObjectClient, 39 name, baseImageName string, layerImageNames []string, 40 logger log.DebugLogger) error { 41 imageExists, err := client.CheckImage(imageSClient, name) 42 if err != nil { 43 return errors.New("error checking for image existence: " + err.Error()) 44 } 45 if imageExists { 46 return errors.New("image exists") 47 } 48 newImage, err := getTypedImage(baseImageName) 49 if err != nil { 50 return err 51 } 52 if !newImage.ExpiresAt.IsZero() { 53 fmt.Fprintf(os.Stderr, "Skipping expiring image: %s\n", baseImageName) 54 return nil 55 } 56 for _, layerImageName := range layerImageNames { 57 fs, err := buildImage(imageSClient, newImage.Filter, layerImageName, 58 logger) 59 if err != nil { 60 return err 61 } 62 if err := layerImages(newImage.FileSystem, fs); err != nil { 63 return err 64 } 65 } 66 if err := spliceComputedFiles(newImage.FileSystem); err != nil { 67 return err 68 } 69 return addImage(imageSClient, name, newImage, logger) 70 } 71 72 func bulkAddReplaceImages(imageSClient *srpc.Client, 73 objectClient *objectclient.ObjectClient, layerImageNames []string, 74 logger log.DebugLogger) error { 75 imageNames, err := client.ListImages(imageSClient) 76 if err != nil { 77 return err 78 } 79 err = bulkAddReplaceImagesSep(imageSClient, objectClient, layerImageNames, 80 imageNames, "/", logger) 81 if err != nil { 82 return err 83 } 84 return bulkAddReplaceImagesSep(imageSClient, objectClient, layerImageNames, 85 imageNames, ".", logger) 86 } 87 88 func bulkAddReplaceImagesSep(imageSClient *srpc.Client, 89 objectClient *objectclient.ObjectClient, layerImageNames []string, 90 imageNames []string, separator string, logger log.DebugLogger) error { 91 baseNames := make(map[string]uint64) 92 for _, name := range imageNames { 93 fields := strings.Split(name, separator) 94 nFields := len(fields) 95 if nFields < 2 { 96 continue 97 } 98 lastField := fields[nFields-1] 99 if version, err := strconv.ParseUint(lastField, 10, 64); err != nil { 100 continue 101 } else { 102 name := strings.Join(fields[:nFields-1], separator) 103 if oldVersion := baseNames[name]; version >= oldVersion { 104 baseNames[name] = version 105 } 106 } 107 } 108 for baseName, version := range baseNames { 109 oldName := fmt.Sprintf("%s%s%d", baseName, separator, version) 110 newName := fmt.Sprintf("%s%s%d", baseName, separator, version+1) 111 err := addReplaceImage(imageSClient, objectClient, newName, oldName, 112 layerImageNames, logger) 113 if err != nil { 114 return err 115 } 116 } 117 return nil 118 } 119 120 func layerImages(baseFS *filesystem.FileSystem, 121 layerFS *filesystem.FileSystem) error { 122 for filename, layerInum := range layerFS.FilenameToInodeTable() { 123 layerInode := layerFS.InodeTable[layerInum] 124 if _, ok := layerInode.(*filesystem.DirectoryInode); ok { 125 continue 126 } 127 baseInum, ok := baseFS.FilenameToInodeTable()[filename] 128 if !ok { 129 return errors.New(filename + " missing in base image") 130 } 131 baseInode := baseFS.InodeTable[baseInum] 132 sameType, sameMetadata, sameData := filesystem.CompareInodes(baseInode, 133 layerInode, nil) 134 if !sameType { 135 return errors.New(filename + " changed type") 136 } 137 if sameMetadata && sameData { 138 continue 139 } 140 baseFS.InodeTable[baseInum] = layerInode 141 } 142 return nil 143 }