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 SetVMMetadata(c config.Cpi, extInput bosh.MethodArguments) error {

	var cid string
	if reflect.TypeOf(extInput[0]) != reflect.TypeOf(cid) {
		return fmt.Errorf("Cannot set VM metadata: received unexpected value for vm cid: %s", cid)
	}
	cid = extInput[0].(string)

	metadata, err := json.Marshal(extInput[1])
	if err != nil {
		return fmt.Errorf("Cannot set VM metadata: metadata is not valid JSON")
	} else {
		for _, v := range extInput[1].(map[string]interface{}) {
			switch v.(type) {
			case string, int:
			default:
				fmt.Println("Cannot set VM metadata: metadata must be a hash with string or integer values")
			}
		}
	}

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

	return rackhdapi.SetNodeMetadata(c, nodeID, string(metadata))
}
func CreateDisk(c config.Cpi, extInput bosh.MethodArguments) (string, error) {
	diskSizeInMB, vmCID, err := parseCreateDiskInput(extInput)
	if err != nil {
		return "", err
	}

	filter := Filter{
		data:   diskSizeInMB,
		method: FilterBasedOnSizeMethod,
	}
	var diskCID string
	var node rackhdapi.Node
	if vmCID != "" {
		node, err = rackhdapi.GetNodeByVMCID(c, vmCID)
		if err != nil {
			return "", err
		}

		if node.PersistentDisk.DiskCID != "" {
			return "", fmt.Errorf("error creating disk: VM %s already has a persistent disk", vmCID)
		}

		valid, err := filter.Run(c, node)
		if !valid || err != nil {
			return "", fmt.Errorf("error creating disk: %v", err)
		}

		if node.PersistentDisk.PregeneratedDiskCID == "" {
			return "", fmt.Errorf("error creating disk: can not find pregenerated disk cid for VM %s", vmCID)
		}
		diskCID = node.PersistentDisk.PregeneratedDiskCID

	} else {
		node.ID, err = TryReservationWithFilter(c, "", filter, SelectNodeFromRackHD, ReserveNodeFromRackHD)
		if err != nil {
			return "", err
		}
		diskCID = fmt.Sprintf("%s-%s", node.ID, c.RequestID)
	}

	container := rackhdapi.PersistentDiskSettingsContainer{
		PersistentDisk: rackhdapi.PersistentDiskSettings{
			DiskCID:    diskCID,
			Location:   fmt.Sprintf("/dev/%s", rackhdapi.PersistentDiskLocation),
			IsAttached: false,
		},
	}

	bodyBytes, err := json.Marshal(container)
	if err != nil {
		return "", fmt.Errorf("error marshalling persistent disk information for VM %s", vmCID)
	}

	err = rackhdapi.PatchNode(c, node.ID, bodyBytes)
	if err != nil {
		return "", err
	}

	return container.PersistentDisk.DiskCID, nil
}
func CreateDisk(c config.Cpi, extInput bosh.MethodArguments) (string, error) {
	diskSizeInMB, vmCID, err := parseCreateDiskInput(extInput)
	if err != nil {
		return "", err
	}

	var node rackhdapi.Node
	if vmCID != "" {
		node, err = rackhdapi.GetNodeByVMCID(c, vmCID)
		if err != nil {
			return "", err
		}

		if node.PersistentDisk.DiskCID != "" {
			return "", fmt.Errorf("error creating disk: VM %s already has a persistent disk", vmCID)
		}
	} else {
		nodeID, err := SelectNodeFromRackHD(c, "")
		if err != nil {
			return "", err
		}
		node.ID = nodeID
	}

	catalog, err := rackhdapi.GetNodeCatalog(c, node.ID)
	if err != nil {
		return "", fmt.Errorf("error getting catalog of VM: %s", vmCID)
	}

	availableSpaceInKB, err := strconv.Atoi(catalog.Data.BlockDevices[rackhdapi.PersistentDiskLocation].Size)
	if err != nil {
		return "", fmt.Errorf("error creating disk for VM %s: disk not found", vmCID)
	}

	if availableSpaceInKB < diskSizeInMB*1024 {
		return "", fmt.Errorf("error creating disk with size %vMB for VM %s: insufficient available disk space", diskSizeInMB, vmCID)
	}

	container := rackhdapi.PersistentDiskSettingsContainer{
		PersistentDisk: rackhdapi.PersistentDiskSettings{
			DiskCID:    node.ID,
			Location:   fmt.Sprintf("/dev/%s", rackhdapi.PersistentDiskLocation),
			IsAttached: false,
		},
	}

	bodyBytes, err := json.Marshal(container)
	if err != nil {
		return "", fmt.Errorf("error marshalling persistent disk information for VM %s", vmCID)
	}

	err = rackhdapi.PatchNode(c, node.ID, bodyBytes)
	if err != nil {
		return "", err
	}

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

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

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

	vmCID = extInput[0].(string)
	diskCID = extInput[1].(string)

	node, err := rackhdapi.GetNodeByVMCID(c, vmCID)
	if err != nil {
		return fmt.Errorf("VM: %s not found\n", vmCID)
	}

	if node.PersistentDisk.DiskCID == "" {
		return fmt.Errorf("Disk: %s not found on VM: %s", diskCID, vmCID)
	}

	if node.PersistentDisk.DiskCID != diskCID {
		if node.PersistentDisk.IsAttached {
			return fmt.Errorf("Node %s has persistent disk %s attached. Cannot attach additional disk %s.", vmCID, node.PersistentDisk.DiskCID, diskCID)
		} else {
			return fmt.Errorf("Node %s has persistent disk %s, but detached. Cannot attach disk %s.", vmCID, node.PersistentDisk.DiskCID, diskCID)
		}
	}

	if node.CID != vmCID {
		return fmt.Errorf("Disk: %s does not belong to VM: %s\n", diskCID, vmCID)
	}

	if !node.PersistentDisk.IsAttached {
		container := rackhdapi.PersistentDiskSettingsContainer{
			PersistentDisk: node.PersistentDisk,
		}
		container.PersistentDisk.IsAttached = true

		bodyBytes, err := json.Marshal(container)
		if err != nil {
			return err
		}

		err = rackhdapi.PatchNode(c, node.ID, bodyBytes)
		if err != nil {
			return err
		}
	}

	return nil
}
func GetDisks(c config.Cpi, extInput bosh.MethodArguments) ([]string, error) {
	var vmCID string

	if reflect.TypeOf(extInput[0]) != reflect.TypeOf(vmCID) {
		return nil, errors.New("Received unexpected type for vm cid")
	}

	vmCID = extInput[0].(string)

	node, err := rackhdapi.GetNodeByVMCID(c, vmCID)
	if err != nil {
		return nil, err
	}

	if node.PersistentDisk.DiskCID != "" {
		result := make([]string, 1)
		result[0] = node.PersistentDisk.DiskCID
		return result, nil
	} else {
		return make([]string, 0), nil
	}
}
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
}
		})
	})

	Describe("Getting a single node by CID", func() {
		It("returns expected node's fields", func() {
			expectedNodes := helpers.LoadNodes("../spec_assets/dummy_all_nodes_are_vms.json")
			expectedNodesData, err := json.Marshal(expectedNodes)
			Expect(err).ToNot(HaveOccurred())
			server.AppendHandlers(
				ghttp.CombineHandlers(
					ghttp.VerifyRequest("GET", "/api/common/nodes"),
					ghttp.RespondWith(http.StatusOK, expectedNodesData),
				),
			)

			node, err := rackhdapi.GetNodeByVMCID(cpiConfig, "vm-5678")

			Expect(err).ToNot(HaveOccurred())
			Expect(node).To(Equal(expectedNodes[0]))
		})
	})

	Describe("Getting a single node by disk CID", func() {
		It("returns node with the disk specified", func() {
			expectedNodes := helpers.LoadNodes("../spec_assets/dummy_create_vm_with_disk_response.json")
			expectedNodesData, err := json.Marshal(expectedNodes)
			Expect(err).ToNot(HaveOccurred())
			server.AppendHandlers(
				ghttp.CombineHandlers(
					ghttp.VerifyRequest("GET", "/api/common/nodes"),
					ghttp.RespondWith(http.StatusOK, expectedNodesData),