github.com/cloudfoundry-incubator/stembuild@v0.0.0-20211223202937-5b61d62226c6/commandparser/package_stemcell.go (about) 1 package commandparser 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "os" 8 "path/filepath" 9 10 "github.com/cloudfoundry-incubator/stembuild/colorlogger" 11 12 "github.com/cloudfoundry-incubator/stembuild/filesystem" 13 14 "github.com/cloudfoundry-incubator/stembuild/package_stemcell/config" 15 "github.com/google/subcommands" 16 ) 17 18 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . OSAndVersionGetter 19 type OSAndVersionGetter interface { 20 GetVersion() string 21 GetVersionWithPatchNumber(string) string 22 GetOs() string 23 } 24 25 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . PackagerFactory 26 type PackagerFactory interface { 27 Packager(sourceConfig config.SourceConfig, outputConfig config.OutputConfig, logLevel int, color bool) (Packager, error) 28 } 29 30 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Packager 31 type Packager interface { 32 Package() error 33 ValidateFreeSpaceForPackage(fs filesystem.FileSystem) error 34 ValidateSourceParameters() error 35 } 36 37 //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . PackagerMessenger 38 type PackagerMessenger interface { 39 InvalidOutputConfig(error) 40 CannotCreatePackager(error) 41 DoesNotHaveEnoughSpace(error) 42 SourceParametersAreInvalid(error) 43 PackageFailed(error) 44 } 45 46 type PackageCmd struct { 47 GlobalFlags *GlobalFlags 48 sourceConfig config.SourceConfig 49 outputConfig config.OutputConfig 50 osAndVersionGetter OSAndVersionGetter 51 packagerFactory PackagerFactory 52 packagerMessenger PackagerMessenger 53 } 54 55 func NewPackageCommand(o OSAndVersionGetter, p PackagerFactory, m PackagerMessenger) *PackageCmd { 56 return &PackageCmd{ 57 osAndVersionGetter: o, 58 packagerFactory: p, 59 packagerMessenger: m, 60 } 61 } 62 63 var patchVersion string 64 65 func (*PackageCmd) Name() string { return "package" } 66 func (*PackageCmd) Synopsis() string { 67 return "Create a BOSH Stemcell from a VMDK file or a provisioned vCenter VM" 68 } 69 func (*PackageCmd) Usage() string { 70 return fmt.Sprintf(` 71 Create a BOSH Stemcell from a VMDK file or a provisioned vCenter VM 72 73 VM on vCenter: 74 75 %[1]s package -vcenter-url <vCenter URL> -vcenter-username <vCenter username> -vcenter-password <vCenter password> -vm-inventory-path <vCenter VM inventory path> 76 77 Requirements: 78 - VM provisioned using the stembuild construct command 79 - Access to vCenter environment 80 - The [vcenter-url], [vcenter-username], [vcenter-password], and [vm-inventory-path] flags must be specified. 81 - NOTE: The 'vm' keyword must be included between the datacenter name and folder name for the vm-inventory-path (e.g: <datacenter>/vm/<vm-folder>/<vm-name>) 82 Example: 83 %[1]s package -vcenter-url vcenter.example.com -vcenter-username root -vcenter-password 'password' -vm-inventory-path '/my-datacenter/vm/my-folder/my-vm' 84 85 VMDK: 86 87 %[1]s package -vmdk <path-to-vmdk> 88 89 Requirements: 90 - The VMware 'ovftool' binary must be on your path or Fusion/Workstation 91 must be installed (both include the 'ovftool'). 92 - The [vmdk] flag must be specified. If the [output] flag is 93 not specified the stemcell will be created in the current working directory. 94 95 Example: 96 %[1]s package -vmdk my-1803-vmdk.vmdk 97 98 Will create an Windows 1803 stemcell using [vmdk] 'my-1803-vmdk.vmdk' 99 The final stemcell will be found in the current working directory. 100 101 Flags: 102 `, filepath.Base(os.Args[0])) 103 } 104 105 func (p *PackageCmd) SetFlags(f *flag.FlagSet) { 106 f.StringVar(&p.sourceConfig.Vmdk, "vmdk", "", "VMDK file to create stemcell from") 107 f.StringVar(&p.sourceConfig.VmInventoryPath, "vm-inventory-path", "", "vCenter VM inventory path. (e.g: <datacenter>/vm/<vm-folder>/<vm-name>)") 108 f.StringVar(&p.sourceConfig.Username, "vcenter-username", "", "vCenter username") 109 f.StringVar(&p.sourceConfig.Password, "vcenter-password", "", "vCenter password") 110 f.StringVar(&p.sourceConfig.URL, "vcenter-url", "", "vCenter url") 111 f.StringVar(&p.sourceConfig.CaCertFile, "vcenter-ca-certs", "", "filepath for custom ca certs") 112 113 f.StringVar(&p.outputConfig.OutputDir, "outputDir", "", "Output directory, default is the current working directory.") 114 f.StringVar(&p.outputConfig.OutputDir, "o", "", "Output directory (shorthand)") 115 f.StringVar(&patchVersion, "patch-version", "", "Number or name of the patch version for the stemcell being built (e.g: for 2019.12.3 the string would be \"3\")") 116 } 117 118 func (p *PackageCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { 119 120 logLevel := colorlogger.NONE 121 if p.GlobalFlags.Debug { 122 logLevel = colorlogger.DEBUG 123 } 124 125 p.setOSandStemcellVersions() 126 127 err := p.outputConfig.ValidateConfig() 128 if err != nil { 129 p.packagerMessenger.InvalidOutputConfig(err) 130 return subcommands.ExitFailure 131 } 132 133 packager, err := p.packagerFactory.Packager(p.sourceConfig, p.outputConfig, logLevel, p.GlobalFlags.Color) 134 if err != nil { 135 p.packagerMessenger.CannotCreatePackager(err) 136 return subcommands.ExitFailure 137 } 138 139 err = packager.ValidateFreeSpaceForPackage(&filesystem.OSFileSystem{}) 140 if err != nil { 141 p.packagerMessenger.DoesNotHaveEnoughSpace(err) 142 return subcommands.ExitFailure 143 } 144 145 err = packager.ValidateSourceParameters() 146 if err != nil { 147 p.packagerMessenger.SourceParametersAreInvalid(err) 148 return subcommands.ExitFailure 149 } 150 151 if err := packager.Package(); err != nil { 152 p.packagerMessenger.PackageFailed(err) 153 return subcommands.ExitFailure 154 } 155 156 return subcommands.ExitSuccess 157 } 158 159 func (p *PackageCmd) setOSandStemcellVersions() { 160 p.outputConfig.Os = p.osAndVersionGetter.GetOs() 161 162 if patchVersion == "" { 163 p.outputConfig.StemcellVersion = p.osAndVersionGetter.GetVersion() 164 } else { 165 p.outputConfig.StemcellVersion = p.osAndVersionGetter.GetVersionWithPatchNumber(patchVersion) 166 } 167 }