func DeleteVM(c config.Cpi, extInput bosh.MethodArguments) error {
	var cid string
	if reflect.TypeOf(extInput[0]) != reflect.TypeOf(cid) {
		return errors.New("Received unexpected type for vm cid")
	}

	cid = extInput[0].(string)
	node, err := rackhdapi.GetNodeByVMCID(c, cid)
	if err != nil {
		return err
	}
	nodeID := node.ID

	workflowName, err := workflows.PublishDeprovisionNodeWorkflow(c, cid)
	if err != nil {
		return err
	}

	err = workflows.RunDeprovisionNodeWorkflow(c, nodeID, workflowName)
	if err != nil {
		return err
	}

	err = rackhdapi.ReleaseNode(c, nodeID)
	if err != nil {
		return err
	}

	return nil
}
func TryReservationWithFilter(c config.Cpi, nodeID string, filter Filter, choose selectionFunc, reserve reservationFunc) (string, error) {
	var node rackhdapi.Node
	var err error
	for i := 0; i < c.MaxReserveNodeAttempts; i++ {
		node, err = choose(c, nodeID, filter)
		if err != nil {
			log.Error(fmt.Sprintf("retry %d: error choosing node %s", i, err))
			continue
		}

		err = reserve(c, node)
		if err != nil {
			log.Error(fmt.Sprintf("retry %d: error reserving node %s", i, err))
			if strings.HasPrefix(err.Error(), "Timed out running workflow") {
				rackhdapi.ReleaseNode(c, node.ID)
			}
			rand.Seed(time.Now().UnixNano())
			sleepTime := rand.Intn(5000)
			log.Debug(fmt.Sprintf("Sleeping for %d ms\n", sleepTime))
			time.Sleep(time.Millisecond * time.Duration(sleepTime))
			continue
		}

		break
	}

	if err != nil {
		return "", fmt.Errorf("unable to reserve node: %v", err)
	}

	return node.ID, nil
}
func DeleteDisk(c config.Cpi, extInput bosh.MethodArguments) error {
	var diskCID string

	if reflect.TypeOf(extInput[0]) != reflect.TypeOf(diskCID) {
		return errors.New("Received unexpected type for disk cid")
	}

	diskCID = extInput[0].(string)

	nodes, err := rackhdapi.GetNodes(c)
	if err != nil {
		return err
	}

	for _, node := range nodes {
		if node.PersistentDisk.DiskCID == diskCID {
			if node.PersistentDisk.IsAttached {
				return fmt.Errorf("Disk: %s is attached\n", diskCID)
			}

			container := rackhdapi.PersistentDiskSettingsContainer{
				PersistentDisk: rackhdapi.PersistentDiskSettings{},
			}
			bodyBytes, err := json.Marshal(container)
			if err != nil {
				return err
			}
			rackhdapi.PatchNode(c, node.ID, bodyBytes)

			if node.CID == "" {
				err = rackhdapi.ReleaseNode(c, node.ID)
				if err != nil {
					fmt.Errorf("error releasing node after delete disk %s: %v", diskCID, err)
				}
			}

			return nil
		}
	}

	return fmt.Errorf("Disk: %s not found\n", diskCID)
}
func DeleteVM(c config.Cpi, extInput bosh.MethodArguments) error {
	var cid string
	if reflect.TypeOf(extInput[0]) != reflect.TypeOf(cid) {
		return errors.New("Received unexpected type for vm cid")
	}

	cid = extInput[0].(string)
	node, err := rackhdapi.GetNodeByVMCID(c, cid)
	if err != nil {
		return err
	}

	if node.PersistentDisk.IsAttached {
		err = rackhdapi.MakeDiskRequest(c, node, false)
		if err != nil {
			return err
		}
	}

	workflowName, err := workflows.PublishDeprovisionNodeWorkflow(c)
	if err != nil {
		return err
	}

	err = workflows.RunDeprovisionNodeWorkflow(c, node.ID, workflowName)
	if err != nil {
		return err
	}

	if node.PersistentDisk.DiskCID == "" {
		err = rackhdapi.ReleaseNode(c, node.ID)
		if err != nil {
			return err
		}
	}

	return nil
}
func tryReservation(c config.Cpi, agentID string, diskCID string, filter filterFunc, choose selectionFunc, reserve reservationFunc) (string, error) {
	var nodeID string
	var err error
	for i := 0; i < c.MaxCreateVMAttempt; i++ {
		err = filter(c)
		if err != nil {
			log.Error(fmt.Sprintf("retry %d: error filtering nodes: %s", i, err))
			continue
		}

		nodeID, err = choose(c, diskCID)

		if err != nil {
			log.Error(fmt.Sprintf("retry %d: error choosing node %s", i, err))
			continue
		}

		err = reserve(c, agentID, nodeID)
		if err != nil {
			log.Error(fmt.Sprintf("retry %d: error reserving node %s", i, err))
			if strings.HasPrefix(err.Error(), "Timed out running workflow") {
				rackhdapi.ReleaseNode(c, nodeID)
			}
			sleepTime := rand.Intn(5000)
			log.Debug(fmt.Sprintf("Sleeping for %d ms\n", sleepTime))
			time.Sleep(time.Millisecond * time.Duration(sleepTime))
			continue
		}

		break
	}

	if err != nil {
		return "", errors.New("unable to reserve node")
	}

	return nodeID, nil
}
				Expect(err).To(MatchError("config error: netmask must be specified for manual network"))
			})
		})
	})

	Describe("unreserving a node", func() {
		It("return a node with reserved flag unset", func() {
			apiServerIP := fmt.Sprintf("%s:8080", os.Getenv("RACKHD_API_URI"))
			Expect(apiServerIP).ToNot(BeEmpty())
			c := config.Cpi{ApiServer: apiServerIP}

			nodes, err := rackhdapi.GetNodes(c)
			Expect(err).ToNot(HaveOccurred())
			targetNodeID := nodes[0].ID
			log.Info(fmt.Sprintf("targetNodeId: %s", targetNodeID))
			err = rackhdapi.ReleaseNode(c, targetNodeID)
			Expect(err).ToNot(HaveOccurred())
			nodeURL := fmt.Sprintf("http://%s/api/common/nodes/%s", c.ApiServer, targetNodeID)

			resp, err := http.Get(nodeURL)
			Expect(err).ToNot(HaveOccurred())
			Expect(resp.StatusCode).To(Equal(200))

			nodeBytes, err := ioutil.ReadAll(resp.Body)
			Expect(err).ToNot(HaveOccurred())

			var node rackhdapi.Node
			err = json.Unmarshal(nodeBytes, &node)
			Expect(err).ToNot(HaveOccurred())
			Expect(node.Status).To(Equal(rackhdapi.Available))
		})