github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/imagetool/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/Cloud-Foundations/Dominator/lib/constants" 10 "github.com/Cloud-Foundations/Dominator/lib/filesystem" 11 "github.com/Cloud-Foundations/Dominator/lib/filter" 12 "github.com/Cloud-Foundations/Dominator/lib/flags/commands" 13 "github.com/Cloud-Foundations/Dominator/lib/flags/loadflags" 14 "github.com/Cloud-Foundations/Dominator/lib/flagutil" 15 "github.com/Cloud-Foundations/Dominator/lib/log" 16 "github.com/Cloud-Foundations/Dominator/lib/log/cmdlogger" 17 "github.com/Cloud-Foundations/Dominator/lib/mbr" 18 objectclient "github.com/Cloud-Foundations/Dominator/lib/objectserver/client" 19 "github.com/Cloud-Foundations/Dominator/lib/srpc" 20 "github.com/Cloud-Foundations/Dominator/lib/srpc/setupclient" 21 ) 22 23 var ( 24 allocateBlocks = flag.Bool("allocateBlocks", false, 25 "If true, allocate blocks when making raw image") 26 buildLog = flag.String("buildLog", "", 27 "Filename or URL containing build log") 28 compress = flag.Bool("compress", false, "If true, compress tar output") 29 computedFiles = flag.String("computedFiles", "", 30 "Name of file containing computed files list") 31 computedFilesRoot = flag.String("computedFilesRoot", "", 32 "Name of directory tree containing computed files to replace on unpack") 33 copyMtimesFrom = flag.String("copyMtimesFrom", "", 34 "Name of image to copy mtimes for otherwise unchanged files/devices") 35 debug = flag.Bool("debug", false, 36 "If true, show debugging output") 37 deleteFilter = flag.String("deleteFilter", "", 38 "Name of delete filter file for addi, adds and diff subcommands") 39 expiresIn = flag.Duration("expiresIn", 0, 40 "How long before the image expires (auto deletes). Default: never") 41 filterFile = flag.String("filterFile", "", 42 "Filter file to apply when adding images") 43 fleetManagerHostname = flag.String("fleetManagerHostname", "", 44 "Hostname of Fleet Manager (to find VM to scan)") 45 fleetManagerPortNum = flag.Uint("fleetManagerPortNum", 46 constants.FleetManagerPortNumber, "Port number of Fleet Manager") 47 hypervisorHostname = flag.String("hypervisorHostname", "", 48 "Hostname of hypervisor (for VM to scan)") 49 hypervisorPortNum = flag.Uint("hypervisorPortNum", 50 constants.HypervisorPortNumber, "Port number of hypervisor") 51 ignoreExpiring = flag.Bool("ignoreExpiring", false, 52 "If true, ignore expiring images when finding images") 53 imageServerHostname = flag.String("imageServerHostname", "localhost", 54 "Hostname of image server") 55 imageServerPortNum = flag.Uint("imageServerPortNum", 56 constants.ImageServerPortNumber, 57 "Port number of image server") 58 makeBootable = flag.Bool("makeBootable", true, 59 "If true, make raw image bootable by installing GRUB") 60 minFreeBytes = flag.Uint64("minFreeBytes", 4<<20, 61 "minimum number of free bytes in raw image") 62 releaseNotes = flag.String("releaseNotes", "", 63 "Filename or URL containing release notes") 64 requiredPaths = flagutil.StringToRuneMap(constants.RequiredPaths) 65 roundupPower = flag.Uint64("roundupPower", 24, 66 "power of 2 to round up raw image size") 67 scanExcludeList flagutil.StringList = constants.ScanExcludeList 68 skipFields = flag.String("skipFields", "", 69 "Fields to skip when showing or diffing images") 70 tableType mbr.TableType = mbr.TABLE_TYPE_MSDOS 71 timeout = flag.Duration("timeout", 0, 72 "Timeout for get subcommand") 73 74 logger log.DebugLogger 75 minimumExpiration = 15 * time.Minute 76 77 diffArgs = ` tool left right 78 left & right are image sources. Format: 79 type:name where type is one of: 80 d: name of directory tree to scan 81 f: name of file containing a FileSystem 82 i: name of an image on the imageserver 83 l: name of file containing an Image 84 s: name of sub to poll 85 v: hostname/IP of SmallStack VM to scan` 86 ) 87 88 func init() { 89 flag.Var(&requiredPaths, "requiredPaths", 90 "Comma separated list of required path:type entries") 91 flag.Var(&scanExcludeList, "scanExcludeList", 92 "Comma separated list of patterns to exclude from scanning") 93 flag.Var(&tableType, "tableType", "partition table type for make-raw-image") 94 } 95 96 func printUsage() { 97 w := flag.CommandLine.Output() 98 fmt.Fprintln(w, 99 "Usage: imagetool [flags...] add|check|delete|list [args...]") 100 fmt.Fprintln(w, "Common flags:") 101 flag.PrintDefaults() 102 fmt.Fprintln(w, "Commands:") 103 commands.PrintCommands(w, subcommands) 104 fmt.Fprintln(w, "Fields:") 105 fmt.Fprintln(w, " m: mode") 106 fmt.Fprintln(w, " l: number of hardlinks") 107 fmt.Fprintln(w, " u: UID") 108 fmt.Fprintln(w, " g: GID") 109 fmt.Fprintln(w, " s: size/Rdev") 110 fmt.Fprintln(w, " t: time of last modification") 111 fmt.Fprintln(w, " n: name") 112 fmt.Fprintln(w, " d: data (hash or symlink target)") 113 } 114 115 var subcommands = []commands.Command{ 116 {"add", " name imagefile filterfile triggerfile", 4, 4, 117 addImagefileSubcommand}, 118 {"addi", " name imagename filterfile triggerfile", 4, 4, 119 addImageimageSubcommand}, 120 {"addrep", "name baseimage layerimage...", 3, -1, 121 addReplaceImageSubcommand}, 122 {"adds", " name subname filterfile triggerfile", 4, 4, 123 addImagesubSubcommand}, 124 {"bulk-addrep", "layerimage...", 1, -1, bulkAddReplaceImagesSubcommand}, 125 {"change-image-expiration", "name", 1, 1, changeImageExpirationSubcommand}, 126 {"check", " name", 1, 1, checkImageSubcommand}, 127 {"check-directory", "dirname", 1, 1, checkDirectorySubcommand}, 128 {"chown", " dirname ownerGroup", 2, 2, chownDirectorySubcommand}, 129 {"copy", " name oldimagename", 2, 2, copyImageSubcommand}, 130 {"copy-filtered-files", "name srcdir destdir", 3, 3, 131 copyFilteredFilesSubcommand}, 132 {"delete", "name", 1, 1, deleteImageSubcommand}, 133 {"delunrefobj", "percentage bytes", 2, 2, 134 deleteUnreferencedObjectsSubcommand}, 135 {"diff", diffArgs, 3, 3, diffSubcommand}, 136 {"estimate-usage", " name", 1, 1, estimateImageUsageSubcommand}, 137 {"find-latest-image", " directory", 1, 1, findLatestImageSubcommand}, 138 {"get", " name directory", 2, 2, getImageSubcommand}, 139 {"get-archive-data", " name outfile", 2, 2, 140 getImageArchiveDataSubcommand}, 141 {"get-file-in-image", " name imageFile [outfile]", 2, 3, 142 getFileInImageSubcommand}, 143 {"get-image-expiration", "name", 1, 1, getImageExpirationSubcommand}, 144 {"list", "", 0, 0, listImagesSubcommand}, 145 {"listdirs", "", 0, 0, listDirectoriesSubcommand}, 146 {"listunrefobj", "", 0, 0, listUnreferencedObjectsSubcommand}, 147 {"make-raw-image", " name rawfile", 2, 2, makeRawImageSubcommand}, 148 {"match-triggers", " name triggers-file", 2, 2, 149 matchTriggersSubcommand}, 150 {"merge-filters", " filter-file...", 1, -1, mergeFiltersSubcommand}, 151 {"merge-triggers", " triggers-file...", 1, -1, 152 mergeTriggersSubcommand}, 153 {"mkdir", " name", 1, 1, makeDirectorySubcommand}, 154 {"patch-directory", " name directory", 2, 2, patchDirectorySubcommand}, 155 {"scan-filtered-files", " name directory", 2, 2, 156 scanFilteredFilesSubcommand}, 157 {"show", " name", 1, 1, showImageSubcommand}, 158 {"show-filter", " name", 1, 1, showImageFilterSubcommand}, 159 {"showunrefobj", "", 0, 0, showUnreferencedObjectsSubcommand}, 160 {"tar", " name [file]", 1, 2, tarImageSubcommand}, 161 {"test-download-speed", " name", 1, 1, testDownloadSpeedSubcommand}, 162 } 163 164 var imageSrpcClient *srpc.Client 165 var theObjectClient *objectclient.ObjectClient 166 167 var listSelector filesystem.ListSelector 168 169 func getClients() (*srpc.Client, *objectclient.ObjectClient) { 170 if imageSrpcClient == nil { 171 var err error 172 clientName := fmt.Sprintf("%s:%d", 173 *imageServerHostname, *imageServerPortNum) 174 imageSrpcClient, err = srpc.DialHTTP("tcp", clientName, 0) 175 if err != nil { 176 fmt.Fprintf(os.Stderr, "Error dialing: %s: %s\n", clientName, err) 177 os.Exit(1) 178 } 179 theObjectClient = objectclient.NewObjectClient(clientName) 180 } 181 return imageSrpcClient, theObjectClient 182 } 183 184 func makeListSelector(arg string) filesystem.ListSelector { 185 var mask filesystem.ListSelector = filesystem.ListSelectAll 186 for _, char := range arg { 187 switch char { 188 case 'm': 189 mask |= filesystem.ListSelectSkipMode 190 case 'l': 191 mask |= filesystem.ListSelectSkipNumLinks 192 case 'u': 193 mask |= filesystem.ListSelectSkipUid 194 case 'g': 195 mask |= filesystem.ListSelectSkipGid 196 case 's': 197 mask |= filesystem.ListSelectSkipSizeDevnum 198 case 't': 199 mask |= filesystem.ListSelectSkipMtime 200 case 'n': 201 mask |= filesystem.ListSelectSkipName 202 case 'd': 203 mask |= filesystem.ListSelectSkipData 204 } 205 } 206 return mask 207 } 208 209 var listFilter *filter.Filter 210 211 func doMain() int { 212 if err := loadflags.LoadForCli("imagetool"); err != nil { 213 fmt.Fprintln(os.Stderr, err) 214 return 1 215 } 216 flag.Usage = printUsage 217 flag.Parse() 218 if flag.NArg() < 1 { 219 printUsage() 220 return 2 221 } 222 logger = cmdlogger.New() 223 if *expiresIn > 0 && *expiresIn < minimumExpiration { 224 fmt.Fprintf(os.Stderr, "Minimum expiration: %s\n", minimumExpiration) 225 return 2 226 } 227 listSelector = makeListSelector(*skipFields) 228 var err error 229 if *filterFile != "" { 230 listFilter, err = filter.Load(*filterFile) 231 if err != nil { 232 fmt.Fprintln(os.Stderr, err) 233 return 2 234 } 235 } 236 if err := setupclient.SetupTls(true); err != nil { 237 fmt.Fprintln(os.Stderr, err) 238 return 1 239 } 240 return commands.RunCommands(subcommands, printUsage, logger) 241 } 242 243 func main() { 244 os.Exit(doMain()) 245 }