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  }