Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vCenter push capability #1929

Merged
merged 1 commit into from May 31, 2017
Merged

vCenter push capability #1929

merged 1 commit into from May 31, 2017

Conversation

thebsdbox
Copy link
Contributor

Re-factored the run code to create the push functionality.

Signed-off-by: Dan Finneran daniel.finneran@gmail.com

- What I did
Added the capability to push Linuxkit .iso images to VMware vCenter. It uses a either a -folder=<NAME> or will take the name of the image and create that folder to host the uploaded image.

- How I did it
Modified run_vcenter.go to allow push_vcenter.go to log in to vCenter and upload images without creating a full VM.

- How to verify it
Push functionality

./bin/linuxkit push vcenter -datastore=vSphereNFS -hostname=esxi01.fnnrn.me -folder=sharedLinuxKit2  ./vcenter.iso 
Uploading LinuxKit file [./vcenter.iso]

run functionality (ensuring changes haven't broken existing functionality.

./bin/linuxkit run vcenter -datastore=vSphereNFS -network=HomeNetwork -hostname=esxi01.fnnrn.me -powerOn -persistentSize=1024 ./vcenter.iso 
Creating new LinuxKit Virtual Machine
Uploading LinuxKit file [./vcenter.iso]
Adding ISO to the Virtual Machine
Adding a persistent disk to the Virtual Machine
Adding VM Networking
Powering on LinuxKit VM

- Description for the changelog

Added the functionality to push linuxkit images to VMware vCenter.

- A picture of a cute animal (not mandatory but encouraged)

newVM.vSphereHost = flags.String("hostname", os.Getenv("VMHOST"), "The Server that will host the image")
newVM.path = flags.String("path", "", "Path to a specific image")

newVM.vmName = flags.String("folder", "", "A Folder on the datastore to push the image too")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its confusing calling it "folder" and "vmName" - maybe call both folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opted for vmFolder, as it makes sense in both use cases. With the run the vmFolder is both the name of the VM and the name of the folder that will be created to house the various VM files. With push the vmFolder is simply a folder created on a datastore that a will hold the VM iso file. Does that sound OK?

// Ensure an iso has been passed to the vCenter push Command
if strings.HasSuffix(*newVM.path, ".iso") {
// Used as a folder to hold the images that are pushed
if *newVM.vmName == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no need for this to be in this condition, it can be unconditional below.

newVM.dsName = flags.String("datastore", os.Getenv("VMDATASTORE"), "The Name of the DataStore to host the image")
newVM.networkName = flags.String("network", os.Getenv("VMNETWORK"), "The VMware vSwitch the image will use")
newVM.vSphereHost = flags.String("hostname", os.Getenv("VMHOST"), "The Server that will host the image")
newVM.path = flags.String("path", "", "Path to a specific image")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these standard environment variables or made up? They seem to be inconsistently named and I would prefer if they had a common prefix...

flags := flag.NewFlagSet("vCenter", flag.ExitOnError)
invoked := filepath.Base(os.Args[0])

newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL in the format of https://username:password@host/sdk")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the URL to the vcenter host? Id so, mention it in the help message

invoked := filepath.Base(os.Args[0])

newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL in the format of https://username:password@host/sdk")
newVM.dsName = flags.String("datastore", os.Getenv("VMDATASTORE"), "The Name of the DataStore to host the image")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Name -> name


newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL in the format of https://username:password@host/sdk")
newVM.dsName = flags.String("datastore", os.Getenv("VMDATASTORE"), "The Name of the DataStore to host the image")
newVM.networkName = flags.String("network", os.Getenv("VMNETWORK"), "The VMware vSwitch the image will use")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the name of the network the VM will be placed on or the name of a vSwitch as the help message implies?

newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL in the format of https://username:password@host/sdk")
newVM.dsName = flags.String("datastore", os.Getenv("VMDATASTORE"), "The Name of the DataStore to host the image")
newVM.networkName = flags.String("network", os.Getenv("VMNETWORK"), "The VMware vSwitch the image will use")
newVM.vSphereHost = flags.String("hostname", os.Getenv("VMHOST"), "The Server that will host the image")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Server -> server

newVM.vmFolder = flags.String("folder", "", "A Folder on the datastore to push the image too")

flags.Usage = func() {
fmt.Printf("USAGE: %s push vcenter [options] [name]\n\n", invoked)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is name optional as the brackets imply? To be consistent with the qemu runner this should probably be called path


// Ensure an iso has been passed to the vCenter push Command
if !strings.HasSuffix(*newVM.path, ".iso") {
log.Fatalln("Ensure that an \".iso\" file is used as part of the path")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rephrase: Please pass an ".iso" file as the path or somesuch.

}

if err := flags.Parse(args); err != nil {
log.Fatalln("Unable to parse args")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we include the error message? log.Fatalf("Unable to parse args: %v", err)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably standardise this across all of the backends?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, looking through the source code as we use ExitOnError and the parse does the following:

		case ExitOnError:
			os.Exit(2)

The log.fatalln(...) will never be called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that look right @justincormack / @rneugeba / @riyazdf ?

As we have this same snippet in a lot of places.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes thats probably true, but the linter will complain if we don't catch the error I guess so it doesn't really matter. Just be consistent with elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, i'll leave it as is for now.

Copy link
Contributor

@riyazdf riyazdf May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it - yeah we can probably standardize this with a custom error type (in a followup PR across backends) but this is good for now

newVM.vSphereHost = flags.String("hostname", os.Getenv("VCHOST"), "The server that will host the image")
newVM.path = flags.String("path", "", "Path to a specific image")

newVM.vmFolder = flags.String("folder", "", "A Folder on the datastore to push the image too")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we lowercase to folder?


newVM.vmName = flags.String("vmname", "", "Specify a name for virtual Machine")
newVM.vmFolder = flags.String("vmfolder", "", "Specify a name/folder for the virtual Machine to reside in")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we lowercase to machine?

newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL of VMware vCenter in the format of https://username:password@VCaddress/sdk")
newVM.dsName = flags.String("datastore", os.Getenv("VCDATASTORE"), "The name of the DataStore to host the VM")
newVM.networkName = flags.String("network", os.Getenv("VCNETWORK"), "The network label the VM will use")
newVM.vSphereHost = flags.String("hostname", os.Getenv("VCHOST"), "The server that will run the VM")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the reason for changing to VC*? Should we update the other flags like vmfolder? I'm not too familiar with vCenter so I'm not sure what makes most sense here :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The VC**** environment variables are there to make it a bit more clearer when repeatedly deploying VMs. The credentials and labels for vCenter internals will stay the same, so we can store them elsewhere (env vars in this case), the rest of the flags we can pass as usual as there is some need for uniqueness. Also @rneugeba, suggested some format for the env variables so I opted for VC.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 SGTM

// Parse URL from string
u, err := url.Parse(*newVM.vCenterURL)
if err != nil {
log.Fatalf("URL can't be parsed, ensure it is https://username:password/<address>/sdk")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be helpful to include the err message here? log.Fatalf("URL can't be parsed, ensure it is https://username:password/<address>/sdk: %v", err)

// Connect and log in to ESX or vCenter
c, err := govmomi.NewClient(ctx, u, true)
if err != nil {
log.Fatalln("Error logging into vCenter, check address and credentials")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment re: including error message: log.Fatalf("Error logging into vCenter, check address and credentials: %v", err)

// Find one and only datacenter, not sure how VMware linked mode will work
dc, err := f.DefaultDatacenter(ctx)
if err != nil {
log.Fatalln("No Datacenter instance could be found inside of vCenter")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment re: including error message for this and subsequent errors

@@ -248,7 +260,7 @@ func addVMDK(ctx context.Context, vm *object.VirtualMachine, dss *object.Datasto
log.Fatalf("Unable to find SCSI device from VM configuration\n%v", err)
}
// The default is to have all persistent disks named linuxkit.vmdk
disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s", *newVM.vmName, "linuxkit.vmdk")))
disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s", *newVM.vmFolder, "linuxkit.vmdk")))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this become configurable? Can be a separate PR, but wondering if we should open a tracking issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to begin with, but then it became apparent that uploading avmdk from workstation to server required a lot more steps (image conversion from thin to fat, meant uploading GBs of zeros etc.) As there is a 1:1 mapping inside of VMware vCenter VMs I opted to keep it simple and in the event the run requires a persistent disk they just get a new disk inside of their VM folder to use.

Happy to revisit this, it felt that uploading large existing disks or having to manipulate the disk controllers to support additional SCSI disks might be outside of what run should be doing :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah got it. Makes sense to keep it like this for now then, thank you for the explanation!

fmt.Printf("USAGE: %s run vcenter [options] [name]\n\n", invoked)
fmt.Printf("'name' specifies the full path of an image that will be ran\n")
fmt.Printf("USAGE: %s run vcenter [options] path\n\n", invoked)
fmt.Printf("'path' specifies the full path of an image that will be ran\n")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"that will be ran" reads weirdly, "to run" is better

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating, i've used "to run" below so changing it keeps the language consistent.

Copy link
Contributor

@riyazdf riyazdf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after nits, thanks @thebsdbox!

}

if err := flags.Parse(args); err != nil {
log.Fatalln("Unable to parse args")
Copy link
Contributor

@riyazdf riyazdf May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it - yeah we can probably standardize this with a custom error type (in a followup PR across backends) but this is good for now

newVM.vCenterURL = flags.String("url", os.Getenv("VCURL"), "URL of VMware vCenter in the format of https://username:password@VCaddress/sdk")
newVM.dsName = flags.String("datastore", os.Getenv("VCDATASTORE"), "The name of the DataStore to host the VM")
newVM.networkName = flags.String("network", os.Getenv("VCNETWORK"), "The network label the VM will use")
newVM.vSphereHost = flags.String("hostname", os.Getenv("VCHOST"), "The server that will run the VM")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 SGTM

// Find one and only datacenter, not sure how VMware linked mode will work
dc, err := f.DefaultDatacenter(ctx)
if err != nil {
log.Fatalln("No Datacenter instance could be found inside of vCenter %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this should be log.Fatalf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true :D fixed.

@@ -248,7 +260,7 @@ func addVMDK(ctx context.Context, vm *object.VirtualMachine, dss *object.Datasto
log.Fatalf("Unable to find SCSI device from VM configuration\n%v", err)
}
// The default is to have all persistent disks named linuxkit.vmdk
disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s", *newVM.vmName, "linuxkit.vmdk")))
disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s", *newVM.vmFolder, "linuxkit.vmdk")))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah got it. Makes sense to keep it like this for now then, thank you for the explanation!

Re-factored the `run` code to create the `push` functionality.

Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
Copy link
Contributor

@riyazdf riyazdf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on green, thanks for the quick fix!

@riyazdf riyazdf merged commit abb19f8 into linuxkit:master May 31, 2017
@thebsdbox thebsdbox deleted the push_vcenter branch June 1, 2017 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants