From 35798493305bf0ff1729a31d67adb28be4899e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Meireles?= Date: Wed, 2 Dec 2015 14:42:07 +0000 Subject: [PATCH 1/4] don't let cruft on the local fs after an halt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: António Meireles --- halt.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/halt.go b/halt.go index 6bd0145..1e70358 100644 --- a/halt.go +++ b/halt.go @@ -19,6 +19,7 @@ import ( "fmt" "log" "os" + "path/filepath" "time" "github.com/spf13/cobra" @@ -88,11 +89,16 @@ func (vm VMInfo) halt() (err error) { } // wait until it's _really_ dead defer func() { + leftover := filepath.Join(SessionContext.runDir, vm.UUID) + for range time.Tick(500 * time.Millisecond) { if _, ee := os.FindProcess(vm.Pid); ee == nil { break } } + if e := os.RemoveAll(leftover); e != nil { + log.Println(e.Error()) + } log.Printf("successfully halted '%s'\n", vm.Name) }() From 29b56cf168f3ca8e38a211dfe0623a0727b55121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Meireles?= Date: Wed, 2 Dec 2015 14:44:16 +0000 Subject: [PATCH 2/4] recover gracefully from crash when requesting a free port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - happens randomly, shouldn't, and this is supposed to get around it Signed-off-by: António Meireles --- helpers.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/helpers.go b/helpers.go index 6356898..763ce86 100644 --- a/helpers.go +++ b/helpers.go @@ -336,12 +336,17 @@ func (vm *VMInfo) isActive() bool { func (vm *VMInfo) metadataService() (endpoint string, err error) { var ( - free net.Listener - runOnce sync.Once + free net.Listener + runOnce sync.Once + freePort = func() (net.Listener, error) { + defer recover() + return net.Listen("tcp", "localhost:0") + } ) + // workaround OSX and/or golang weirdness... for range time.Tick(500 * time.Millisecond) { - if free, err = net.Listen("tcp", "localhost:0"); err == nil { + if free, err = freePort(); err == nil { break } } From 4799b6c7ca108b5a9406acc81bc0144e2e831637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Meireles?= Date: Wed, 2 Dec 2015 14:46:52 +0000 Subject: [PATCH 3/4] also store MacAdress in VMInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: António Meireles --- globals.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/globals.go b/globals.go index 096a759..ace0577 100644 --- a/globals.go +++ b/globals.go @@ -31,7 +31,7 @@ type ( VMInfo struct { Name, Channel, Version string Cpus, Memory int - UUID string + UUID, MacAddress string CloudConfig, CClocation, SSHkey, Extra string `json:",omitempty"` Root int Ethernet []NetworkInterface From 48a19bf47c9915832c680b8a1c05bc5fc5ef6f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Meireles?= Date: Wed, 2 Dec 2015 14:50:31 +0000 Subject: [PATCH 4/4] refactor and make more resilient UUIDs handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in particular we workaround an odd bug where with some UUIDs we aren't able to guess the MAC address. Signed-off-by: António Meireles --- run.go | 26 +++++++++++++++++--------- uuid2ip/uuid2ip.c | 40 +++++++++++++++++++++++----------------- uuid2ip/uuid2ip.go | 31 ++++++++++++------------------- uuid2ip/uuid2ip.h | 8 ++++---- 4 files changed, 56 insertions(+), 49 deletions(-) diff --git a/run.go b/run.go index c3c8146..252c9e1 100644 --- a/run.go +++ b/run.go @@ -96,8 +96,8 @@ func xhyveCommand(cmd *cobra.Command, args []string) (err error) { func bootVM(vipre *viper.Viper) (err error) { var ( - mac, rundir string - vm, c = &VMInfo{}, &exec.Cmd{} + rundir string + vm, c = &VMInfo{}, &exec.Cmd{} ) vm.PreferLocalImages = vipre.GetBool("local") @@ -170,10 +170,6 @@ func bootVM(vipre *viper.Viper) (err error) { return } - if mac, err = uuid2ip.GuestMACfromUUID(vm.UUID); err != nil { - return - } - go func() { wg.Add(1) defer func() { @@ -189,9 +185,10 @@ func bootVM(vipre *viper.Viper) (err error) { break } - for range time.Tick(100 * time.Millisecond) { + for range time.Tick(500 * time.Millisecond) { var e error - if vm.PublicIP, e = uuid2ip.GuestIPfromMAC(mac); e == nil { + if vm.PublicIP, e = + uuid2ip.GuestIPfromMAC(vm.MacAddress); e == nil { break } } @@ -415,7 +412,7 @@ func (vm *VMInfo) validateNameAndUUID(name, xxid string) (err error) { if xxid == "random" { vm.UUID = uuid.NewV4().String() } else { - if _, err := uuid.FromString(xxid); err != nil { + if _, err = uuid.FromString(xxid); err != nil { log.Printf("%s not a valid UUID as it doesn't follow RFC 4122. %s\n", xxid, " using a randomly generated one") vm.UUID = uuid.NewV4().String() @@ -423,6 +420,17 @@ func (vm *VMInfo) validateNameAndUUID(name, xxid string) (err error) { vm.UUID = xxid } } + for { + if vm.MacAddress, err = uuid2ip.GuestMACfromUUID(vm.UUID); err == nil { + break + } + if xxid != "random" { + log.Printf("unable to guess the MAC Address from the provided "+ + "UUID (%s). Using a randomly generated one one\n", xxid) + } + vm.UUID = uuid.NewV4().String() + } + if name == "" { vm.Name = vm.UUID } else { diff --git a/uuid2ip/uuid2ip.c b/uuid2ip/uuid2ip.c index 362c46d..6252a68 100644 --- a/uuid2ip/uuid2ip.c +++ b/uuid2ip/uuid2ip.c @@ -45,19 +45,18 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* originally at https://github.com/ailispaw/boot2docker-xhyve/uuid2ip and - * slightly refactored to better fit the golang bindings - * github.com/AntonioMeireles/coreos-xhyve/uuid2ip - */ - + /* originally at github.com/zchee/docker-machine-xhyve/blob/embed-xhyve/vmnet/ + * and slightly refactored to better fit the golang bindings + * github.com/TheNewNormal/coreos-xhyve/uuid2ip + */ #include #include #include "uuid2ip.h" -static int -vmnet_get_mac_address_from_uuid(char *guest_uuid_str, char *mac, char *err) { +static char* +vmnet_get_mac_address_from_uuid(char *guest_uuid_str) { /* * from vmn_create() in https://github.com/mist64/xhyve/blob/master/src/pci_virtio_vmnet.c */ @@ -65,6 +64,7 @@ vmnet_get_mac_address_from_uuid(char *guest_uuid_str, char *mac, char *err) { uuid_t uuid; __block interface_ref iface; __block vmnet_return_t iface_status; + __block char* mac = malloc(18); dispatch_semaphore_t iface_created, iface_stopped; dispatch_queue_t if_create_q, if_stop_q; uint32_t uuid_status; @@ -74,8 +74,8 @@ vmnet_get_mac_address_from_uuid(char *guest_uuid_str, char *mac, char *err) { uuid_from_string(guest_uuid_str, &uuid, &uuid_status); if (uuid_status != uuid_s_ok) { - strcpy(err, "Invalid UUID"); - return -1; + fprintf(stderr, "Invalid UUID\n"); + return NULL; } xpc_dictionary_set_uuid(interface_desc, vmnet_interface_id_key, uuid); @@ -94,7 +94,10 @@ vmnet_get_mac_address_from_uuid(char *guest_uuid_str, char *mac, char *err) { dispatch_semaphore_signal(iface_created); return; } - strcpy(mac, xpc_dictionary_get_string(interface_param, vmnet_mac_address_key)); + + //printf("%s\n", xpc_dictionary_get_string(interface_param, vmnet_mac_address_key)); + const char *macStr = xpc_dictionary_get_string(interface_param, vmnet_mac_address_key); + strcpy(mac, macStr); dispatch_semaphore_signal(iface_created); }); @@ -103,9 +106,11 @@ vmnet_get_mac_address_from_uuid(char *guest_uuid_str, char *mac, char *err) { dispatch_release(if_create_q); if (iface == NULL || iface_status != VMNET_SUCCESS) { - strcpy(err, "virtio_net: Could not create vmnet interface, " - "permission denied or no entitlement?"); - return -1; + // XXX supress noise in this cery specific case + // XXX understand some day why some random UUIDs induce this... + // fprintf(stderr, "virtio_net: Could not create vmnet interface, " + // "permission denied or no entitlement?\n"); + return NULL; } iface_status = 0; @@ -125,9 +130,10 @@ vmnet_get_mac_address_from_uuid(char *guest_uuid_str, char *mac, char *err) { dispatch_release(if_stop_q); if (iface_status != VMNET_SUCCESS) { - strcpy(err, "virtio_net: Could not stop vmnet interface, " - "permission denied or no entitlement?"); - return -1; + fprintf(stderr, "virtio_net: Could not stop vmnet interface, " + "permission denied or no entitlement?\n"); + return NULL; } - return 0; + + return mac; } diff --git a/uuid2ip/uuid2ip.go b/uuid2ip/uuid2ip.go index ee56efd..a4b9a33 100644 --- a/uuid2ip/uuid2ip.go +++ b/uuid2ip/uuid2ip.go @@ -26,9 +26,9 @@ import "C" import ( "fmt" "io/ioutil" + "net" "os" "regexp" - "runtime" "strings" "unsafe" ) @@ -36,25 +36,18 @@ import ( // GuestMACfromUUID returns the MAC address that will assembled from the given // UUID by xhyve, needs to be called before xhyve actual invocation func GuestMACfromUUID(uuid string) (mac string, err error) { - fail, uuidC := "", C.CString(uuid) - macC, failC := C.CString(mac), C.CString(fail) - var ret C.int - - runtime.LockOSThread() - defer func() { - C.free(unsafe.Pointer(uuidC)) - C.free(unsafe.Pointer(macC)) - C.free(unsafe.Pointer(failC)) - runtime.UnlockOSThread() - }() - - if ret = C.vmnet_get_mac_address_from_uuid(uuidC, - (*C.char)(unsafe.Pointer(macC)), - (*C.char)(unsafe.Pointer(failC))); ret != 0 { - return mac, fmt.Errorf(C.GoString(failC)) + var ( + hw net.HardwareAddr + uuidC = C.CString(uuid) + ) + mac = C.GoString(C.vmnet_get_mac_address_from_uuid(uuidC)) + C.free(unsafe.Pointer(uuidC)) + if mac == "" { + err = fmt.Errorf("Could not get a MAC address from %s", uuid) + } else if hw, err = net.ParseMAC(mac); err == nil { + mac = hw.String() } - mac = C.GoString(macC) - return mac, nil + return } // GuestIPfromMAC returns the IP address that would be leased to the given MAC diff --git a/uuid2ip/uuid2ip.h b/uuid2ip/uuid2ip.h index bba0287..aa9114d 100644 --- a/uuid2ip/uuid2ip.h +++ b/uuid2ip/uuid2ip.h @@ -1,3 +1,4 @@ + /*- * Copyright (c) 2002,2005 Marcel Moolenaar * Copyright (c) 2002 Hiten Mahesh Pandya @@ -26,10 +27,9 @@ * * $FreeBSD$ */ - - /* originally at https://github.com/ailispaw/boot2docker-xhyve/uuid2ip and - * slightly refactored to better fit the golang bindings - * github.com/AntonioMeireles/coreos-xhyve/uuid2ip + /* originally at github.com/zchee/docker-machine-xhyve/blob/embed-xhyve/vmnet/ + * and slightly refactored to better fit the golang bindings + * github.com/TheNewNormal/coreos-xhyve/uuid2ip */ #pragma once