Ejemplo n.º 1
0
func TestWaitForUpdates(t *testing.T) {
	folder := esx.RootFolder
	s := New(NewServiceInstance(esx.ServiceContent, folder))

	ts := s.NewServer()
	defer ts.Close()

	ctx := context.Background()

	c, err := govmomi.NewClient(ctx, ts.URL, true)
	if err != nil {
		t.Fatal(err)
	}

	cb := func(once bool) func([]types.PropertyChange) bool {
		return func(pc []types.PropertyChange) bool {
			if len(pc) != 1 {
				t.Fail()
			}

			c := pc[0]
			if c.Op != types.PropertyChangeOpAssign {
				t.Fail()
			}
			if c.Name != "name" {
				t.Fail()
			}
			if c.Val.(string) != folder.Name {
				t.Fail()
			}

			return once
		}
	}

	pc := property.DefaultCollector(c.Client)
	props := []string{"name"}

	err = property.Wait(ctx, pc, folder.Reference(), props, cb(true))
	if err != nil {
		t.Error(err)
	}

	// incremental updates not yet suppported
	err = property.Wait(ctx, pc, folder.Reference(), props, cb(false))
	if err == nil {
		t.Error("expected error")
	}

	// test object not found
	Map.Remove(folder.Reference())

	err = property.Wait(ctx, pc, folder.Reference(), props, cb(true))
	if err == nil {
		t.Error("expected error")
	}
}
Ejemplo n.º 2
0
func (v VirtualMachine) WaitForIP(ctx context.Context) (string, error) {
	var ip string

	p := property.DefaultCollector(v.c)
	err := property.Wait(ctx, p, v.Reference(), []string{"guest.ipAddress"}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Name != "guest.ipAddress" {
				continue
			}
			if c.Op != types.PropertyChangeOpAssign {
				continue
			}
			if c.Val == nil {
				continue
			}

			ip = c.Val.(string)
			return true
		}

		return false
	})

	if err != nil {
		return "", err
	}

	return ip, nil
}
Ejemplo n.º 3
0
Archivo: vm.go Proyecto: kjplatz/vic
// WaitForMac will wait until VM get mac for all attached nics.
// Returns map "Virtual Network Name": "nic MAC address"
func (vm VirtualMachine) WaitForMAC(ctx context.Context) (map[string]string, error) {
	devices, err := vm.Device(ctx)
	if err != nil {
		log.Errorf("Unable to get device listing for VM")
		return nil, err
	}

	nics := devices.SelectByType(&types.VirtualEthernetCard{})
	macs := make(map[string]string)
	// device name:network name
	nicMappings := make(map[string]string)
	for _, nic := range nics {
		if n, ok := nic.(types.BaseVirtualEthernetCard); ok {
			netName, err := vm.getNetworkName(ctx, n)
			if err != nil {
				log.Errorf("failed to get network name: %s", err)
				return nil, err
			}
			macs[netName] = ""

			nicMappings[devices.Name(nic)] = netName
		} else {
			log.Errorf("Failed to get network name of vNIC: %v", nic)
			return nil, err
		}
	}

	p := property.DefaultCollector(vm.Session.Vim25())

	// Wait for all NICs to have a MacAddress, which may not be generated yet.
	err = property.Wait(ctx, p, vm.Reference(), []string{"config.hardware.device"}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Op != types.PropertyChangeOpAssign {
				continue
			}

			changedDevices := c.Val.(types.ArrayOfVirtualDevice).VirtualDevice
			for _, device := range changedDevices {
				if nic, ok := device.(types.BaseVirtualEthernetCard); ok {
					mac := nic.GetVirtualEthernetCard().MacAddress
					if mac == "" {
						continue
					}
					netName := nicMappings[devices.Name(device)]
					macs[netName] = mac
				}
			}
		}
		for key, value := range macs {
			if value == "" {
				log.Debugf("Didn't get mac address for nic on %s, continue", key)
				return false
			}
		}
		return true
	})
	return macs, err
}
Ejemplo n.º 4
0
func (p *eventProcessor) run(ctx context.Context, tail bool) error {
	if len(p.tailers) == 0 {
		return nil
	}

	var err error
	var collectors []types.ManagedObjectReference
	for _, t := range p.tailers {
		collectors = append(collectors, t.collector)
	}

	if len(p.tailers) > 1 {
		// create and populate a ListView
		viewMgr := view.NewManager(p.mgr.Client())
		var listView *view.ListView
		listView, err = viewMgr.CreateListView(ctx, collectors)
		if err != nil {
			return err
		}

		count := 0
		// Retrieve the property from the objects in the ListView
		err = property.WaitForView(ctx, property.DefaultCollector(p.mgr.Client()), listView.Reference(), collectors[0], []string{latestPageProp}, func(c types.ManagedObjectReference, pc []types.PropertyChange) bool {
			if err = p.process(c, pc); err != nil {
				return false
			}

			count++
			if count == len(collectors) && !tail {
				return true
			}

			return false
		})

		return err
	}

	// only one object to follow
	err = property.Wait(ctx, property.DefaultCollector(p.mgr.Client()), collectors[0], []string{latestPageProp}, func(pc []types.PropertyChange) bool {
		if err = p.process(collectors[0], pc); err != nil {
			return false
		}

		if !tail {
			return true
		}

		return false
	})

	return err
}
Ejemplo n.º 5
0
Archivo: vm.go Proyecto: kjplatz/vic
// WaitForExtraConfig waits until key shows up with the expected value inside the ExtraConfig
func (vm *VirtualMachine) WaitForExtraConfig(ctx context.Context, waitFunc func(pc []types.PropertyChange) bool) error {
	// Get the default collector
	p := property.DefaultCollector(vm.Vim25())

	// Wait on config.extraConfig
	// https://www.vmware.com/support/developer/vc-sdk/visdk2xpubs/ReferenceGuide/vim.vm.ConfigInfo.html
	err := property.Wait(ctx, p, vm.Reference(), []string{"config.extraConfig"}, waitFunc)
	if err != nil {
		log.Errorf("Property collector error: %s", err)
		return err
	}
	return nil
}
Ejemplo n.º 6
0
// Wait waits for a task to finish with either success or failure. It does so
// by waiting for the "info" property of task managed object to change. The
// function returns when it finds the task in the "success" or "error" state.
// In the former case, the return value is nil. In the latter case the return
// value is an instance of this package's Error struct.
//
// Any error returned while waiting for property changes causes the function to
// return immediately and propagate the error.
//
// If the progress.Sinker argument is specified, any progress updates for the
// task are sent here. The completion percentage is passed through directly.
// The detail for the progress update is set to an empty string. If the task
// finishes in the error state, the error instance is passed through as well.
// Note that this error is the same error that is returned by this function.
//
func Wait(ctx context.Context, ref types.ManagedObjectReference, pc *property.Collector, s progress.Sinker) (*types.TaskInfo, error) {
	cb := &taskCallback{}

	// Include progress sink if specified
	if s != nil {
		cb.ch = s.Sink()
		defer close(cb.ch)
	}

	err := property.Wait(ctx, pc, ref, []string{"info"}, cb.fn)
	if err != nil {
		return nil, err
	}

	return cb.info, cb.err
}
Ejemplo n.º 7
0
func (o HttpNfcLease) Wait(ctx context.Context) (*types.HttpNfcLeaseInfo, error) {
	var lease mo.HttpNfcLease

	pc := property.DefaultCollector(o.c)
	err := property.Wait(ctx, pc, o.Reference(), []string{"state", "info", "error"}, func(pc []types.PropertyChange) bool {
		done := false

		for _, c := range pc {
			if c.Val == nil {
				continue
			}

			switch c.Name {
			case "error":
				val := c.Val.(types.LocalizedMethodFault)
				lease.Error = &val
				done = true
			case "info":
				val := c.Val.(types.HttpNfcLeaseInfo)
				lease.Info = &val
			case "state":
				lease.State = c.Val.(types.HttpNfcLeaseState)
				if lease.State != types.HttpNfcLeaseStateInitializing {
					done = true
				}
			}
		}

		return done
	})

	if err != nil {
		return nil, err
	}

	if lease.State == types.HttpNfcLeaseStateReady {
		return lease.Info, nil
	}

	if lease.Error != nil {
		return nil, errors.New(lease.Error.LocalizedMessage)
	}

	return nil, fmt.Errorf("unexpected nfc lease state: %s", lease.State)
}
Ejemplo n.º 8
0
// Wait for the VirtualMachine to change to the desired power state.
func (v VirtualMachine) WaitForPowerState(ctx context.Context, state types.VirtualMachinePowerState) error {
	p := property.DefaultCollector(v.c)
	err := property.Wait(ctx, p, v.Reference(), []string{PropRuntimePowerState}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Name != PropRuntimePowerState {
				continue
			}
			if c.Val == nil {
				continue
			}

			ps := c.Val.(types.VirtualMachinePowerState)
			if ps == state {
				return true
			}
		}
		return false
	})

	return err
}
Ejemplo n.º 9
0
func singleObjectEvents(ctx context.Context, m Manager, object types.ManagedObjectReference, pageSize int32, tail bool, force bool, prop []string, f func([]types.BaseEvent) error) error {
	filter := types.EventFilterSpec{
		Entity: &types.EventFilterSpecByEntity{
			Entity:    object,
			Recursion: types.EventFilterSpecRecursionOptionAll,
		},
	}

	collector, err := m.CreateCollectorForEvents(ctx, filter)
	if err != nil {
		return fmt.Errorf("[%#v] %s", object, err)
	}
	defer collector.Destroy(ctx)

	err = collector.SetPageSize(ctx, pageSize)
	if err != nil {
		return err
	}

	return property.Wait(ctx, property.DefaultCollector(m.Client()), collector.Reference(), prop, func(pc []types.PropertyChange) bool {
		for _, u := range pc {
			if u.Name != prop[0] {
				continue
			}
			if u.Val == nil {
				continue
			}
			f(u.Val.(types.ArrayOfEvent).Event)

		}
		if !tail {
			return true
		}
		return false
	})
}
Ejemplo n.º 10
0
// WaitForNetIP waits for the VM guest.net property to report an IP address for all VM NICs.
// Only consider IPv4 addresses if the v4 param is true.
// Returns a map with MAC address as the key and IP address list as the value.
func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][]string, error) {
	macs := make(map[string][]string)

	p := property.DefaultCollector(v.c)

	// Wait for all NICs to have a MacAddress, which may not be generated yet.
	err := property.Wait(ctx, p, v.Reference(), []string{"config.hardware.device"}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Op != types.PropertyChangeOpAssign {
				continue
			}

			devices := c.Val.(types.ArrayOfVirtualDevice).VirtualDevice
			for _, device := range devices {
				if nic, ok := device.(types.BaseVirtualEthernetCard); ok {
					mac := nic.GetVirtualEthernetCard().MacAddress
					if mac == "" {
						return false
					}
					macs[mac] = nil
				}
			}
		}

		return true
	})

	err = property.Wait(ctx, p, v.Reference(), []string{"guest.net"}, func(pc []types.PropertyChange) bool {
		for _, c := range pc {
			if c.Op != types.PropertyChangeOpAssign {
				continue
			}

			nics := c.Val.(types.ArrayOfGuestNicInfo).GuestNicInfo
			for _, nic := range nics {
				mac := nic.MacAddress
				if mac == "" || nic.IpConfig == nil {
					continue
				}

				for _, ip := range nic.IpConfig.IpAddress {
					if _, ok := macs[mac]; !ok {
						continue // Ignore any that don't correspond to a VM device
					}
					if v4 && net.ParseIP(ip.IpAddress).To4() == nil {
						continue // Ignore non IPv4 address
					}
					macs[mac] = append(macs[mac], ip.IpAddress)
				}
			}
		}

		for _, ips := range macs {
			if len(ips) == 0 {
				return false
			}
		}

		return true
	})

	if err != nil {
		return nil, err
	}

	return macs, nil
}
Ejemplo n.º 11
0
// Wait dispatches to property.Wait.
func (c *Client) Wait(ctx context.Context, obj types.ManagedObjectReference, ps []string, f func([]types.PropertyChange) bool) error {
	return property.Wait(ctx, c.PropertyCollector(), obj, ps, f)
}
Ejemplo n.º 12
0
func TestCreateVm(t *testing.T) {
	ctx := context.Background()

	for _, model := range []*Model{ESX(), VPX()} {
		defer model.Remove()
		err := model.Create()
		if err != nil {
			t.Fatal(err)
		}

		s := model.Service.NewServer()
		defer s.Close()

		c, err := govmomi.NewClient(ctx, s.URL, true)
		if err != nil {
			t.Fatal(err)
		}

		p := property.DefaultCollector(c.Client)

		spec := types.VirtualMachineConfigSpec{
			// Note: real ESX allows the VM to be created without a GuestId,
			// but will power on will fail.
			GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
		}

		steps := []func(){
			func() {
				spec.Name = "test"
			},
			func() {
				spec.Files = &types.VirtualMachineFileInfo{
					VmPathName: fmt.Sprintf("[LocalDS_0] %s/%s.vmx", spec.Name, spec.Name),
				}
			},
		}

		finder := find.NewFinder(c.Client, false)

		dc, err := finder.DefaultDatacenter(ctx)
		if err != nil {
			t.Fatal(err)
		}

		finder.SetDatacenter(dc)

		folders, err := dc.Folders(ctx)
		if err != nil {
			t.Fatal(err)
		}

		hosts, err := finder.HostSystemList(ctx, "*/*")
		if err != nil {
			t.Fatal(err)
		}

		nhosts := len(hosts)
		host := hosts[rand.Intn(nhosts)]
		pool, err := host.ResourcePool(ctx)
		if err != nil {
			t.Fatal(err)
		}

		if nhosts == 1 {
			// test the default path against the ESX model
			host = nil
		}

		vmFolder := folders.VmFolder
		// expecting CreateVM to fail until all steps are taken
		for _, step := range steps {
			task, cerr := vmFolder.CreateVM(ctx, spec, pool, host)
			if cerr != nil {
				t.Fatal(err)
			}

			_, cerr = task.WaitForResult(ctx, nil)
			if cerr == nil {
				t.Error("expected error")
			}

			step()
		}

		task, err := vmFolder.CreateVM(ctx, spec, pool, host)
		if err != nil {
			t.Fatal(err)
		}

		info, err := task.WaitForResult(ctx, nil)
		if err != nil {
			t.Fatal(err)
		}

		vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference))

		name, err := vm.ObjectName(ctx)
		if err != nil {
			t.Fatal(err)
		}

		if name != spec.Name {
			t.Errorf("name=%s", name)
		}

		_, err = vm.Device(ctx)
		if err != nil {
			t.Fatal(err)
		}

		recreate := func(context.Context) (*object.Task, error) {
			return vmFolder.CreateVM(ctx, spec, pool, nil)
		}

		ops := []struct {
			method func(context.Context) (*object.Task, error)
			state  types.VirtualMachinePowerState
			fail   bool
		}{
			// Powered off by default
			{nil, types.VirtualMachinePowerStatePoweredOff, false},
			// Create with same .vmx path should fail
			{recreate, "", true},
			// Off -> On  == ok
			{vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, false},
			// On  -> On  == fail
			{vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, true},
			// On  -> Off == ok
			{vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, false},
			// Off -> Off == fail
			{vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, true},
			// Off -> On  == ok
			{vm.PowerOn, types.VirtualMachinePowerStatePoweredOn, false},
			// Destroy == fail (power is On)
			{vm.Destroy, types.VirtualMachinePowerStatePoweredOn, true},
			// On  -> Off == ok
			{vm.PowerOff, types.VirtualMachinePowerStatePoweredOff, false},
			// Destroy == ok (power is Off)
			{vm.Destroy, "", false},
		}

		for i, op := range ops {
			if op.method != nil {
				task, err = op.method(ctx)
				if err != nil {
					t.Fatal(err)
				}

				err = task.Wait(ctx)
				if op.fail {
					if err == nil {
						t.Errorf("%d: expected error", i)
					}
				} else {
					if err != nil {
						t.Errorf("%d: %s", i, err)
					}
				}
			}

			if len(op.state) != 0 {
				state, err := vm.PowerState(ctx)
				if err != nil {
					t.Fatal(err)
				}

				if state != op.state {
					t.Errorf("state=%s", state)
				}

				err = property.Wait(ctx, p, vm.Reference(), []string{object.PropRuntimePowerState}, func(pc []types.PropertyChange) bool {
					for _, c := range pc {
						switch v := c.Val.(type) {
						case types.VirtualMachinePowerState:
							if v != op.state {
								t.Errorf("state=%s", v)
							}
						default:
							t.Errorf("unexpected type %T", v)
						}

					}
					return false
				})
			}
		}
	}
}