func WaitForVirtualGuestToTargetState(softLayerClient sl.Client, virtualGuestId int, targetState string, logger boshlog.Logger) error {
	virtualGuestService, err := softLayerClient.GetSoftLayer_Virtual_Guest_Service()
	if err != nil {
		return bosherr.WrapError(err, "Creating VirtualGuestService from SoftLayer client")
	}

	getTargetStateRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			vgPowerState, err := virtualGuestService.GetPowerState(virtualGuestId)
			if err != nil {
				return false, bosherr.WrapErrorf(err, "Getting PowerState from vitrual guest %d", virtualGuestId)
			} else {
				if strings.Contains(vgPowerState.KeyName, targetState) {
					return false, nil
				}
				return true, nil
			}
		})

	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(TIMEOUT, POLLING_INTERVAL, getTargetStateRetryable, timeService, logger)
	err = timeoutRetryStrategy.Try()
	if err != nil {
		return bosherr.Errorf("Waiting for virtual guest with ID '%d' to have be in state '%s'", virtualGuestId, targetState)
	}

	return nil
}
예제 #2
0
func (p partedPartitioner) createMapperPartition(devicePath string) error {
	_, _, _, err := p.cmdRunner.RunCommand("/etc/init.d/open-iscsi", "restart")
	if err != nil {
		return bosherr.WrapError(err, "Shelling out to restart open-iscsi")
	}

	detectPartitionRetryable := boshretry.NewRetryable(func() (bool, error) {
		output, _, _, err := p.cmdRunner.RunCommand("dmsetup", "ls")
		if err != nil {
			return true, bosherr.WrapError(err, "Shelling out to dmsetup ls")
		}

		if strings.Contains(output, "No devices found") {
			return true, bosherr.Errorf("No devices found")
		}

		device := strings.TrimPrefix(devicePath, "/dev/mapper/")
		lines := strings.Split(strings.Trim(output, "\n"), "\n")
		for i := 0; i < len(lines); i++ {
			if match, _ := regexp.MatchString("-part1", lines[i]); match {
				if strings.Contains(lines[i], device) {
					p.logger.Info(p.logTag, "Succeeded in detecting partition %s", devicePath+"-part1")
					return false, nil
				}
			}
		}

		return true, bosherr.Errorf("Partition %s does not show up", devicePath+"-part1")
	})

	detectPartitionRetryStrategy := NewPartitionStrategy(detectPartitionRetryable, p.timeService, p.logger)
	return detectPartitionRetryStrategy.Try()
}
func WaitForVirtualGuestIsNotPingable(softLayerClient sl.Client, virtualGuestId int, logger boshlog.Logger) error {
	virtualGuestService, err := softLayerClient.GetSoftLayer_Virtual_Guest_Service()
	if err != nil {
		return bosherr.WrapError(err, "Creating VirtualGuestService from SoftLayer client")
	}

	checkPingableRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			state, err := virtualGuestService.IsPingable(virtualGuestId)
			if err != nil {
				return false, bosherr.WrapErrorf(err, "Checking pingable against vitrual guest %d", virtualGuestId)
			} else {
				return state, nil
			}
		})

	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(TIMEOUT, POLLING_INTERVAL, checkPingableRetryable, timeService, logger)
	err = timeoutRetryStrategy.Try()
	if err != nil {
		return bosherr.Errorf("Waiting for virtual guest with ID '%d' is not pingable", virtualGuestId)
	}

	return nil
}
func WaitForVirtualGuestToHaveNoRunningTransaction(softLayerClient sl.Client, virtualGuestId int, logger boshlog.Logger) error {

	virtualGuestService, err := softLayerClient.GetSoftLayer_Virtual_Guest_Service()
	if err != nil {
		return bosherr.WrapError(err, "Creating VirtualGuestService from SoftLayer client")
	}

	runningTransactionsRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			activeTransactions, err := virtualGuestService.GetActiveTransactions(virtualGuestId)
			if err != nil {
				return false, bosherr.WrapErrorf(err, "Getting active transaction against vitrual guest %d", virtualGuestId)
			} else {
				if len(activeTransactions) == 0 {
					return false, nil
				}
				return true, nil
			}
		})

	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(TIMEOUT, POLLING_INTERVAL, runningTransactionsRetryable, timeService, logger)
	err = timeoutRetryStrategy.Try()
	if err != nil {
		return bosherr.Errorf("Waiting for virtual guest with ID '%d' to have no active transactions", virtualGuestId)
	}
	return nil
}
func (vmInfoDB *VMInfoDB) QueryVMInfobyAgentID(retryTimeout time.Duration, retryInterval time.Duration) error {

	execStmtRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			tx, err := vmInfoDB.db.Begin()
			if err != nil {
				sqliteErr := err.(sqlite3.Error)
				if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
					return true, bosherr.WrapError(sqliteErr, "retrying...")
				} else {
					return false, bosherr.WrapError(sqliteErr, "Failed to begin DB transcation")
				}
			}

			var prepareStmt string
			if vmInfoDB.VmProperties.InUse == "t" {
				prepareStmt = "SELECT id, image_id, agent_id FROM vms WHERE in_use='t' AND agent_id=?"
			} else if vmInfoDB.VmProperties.InUse == "f" {
				prepareStmt = "SELECT id, image_id, agent_id FROM vms WHERE in_use='f' AND agent_id=?"
			} else {
				prepareStmt = "SELECT id, image_id, agent_id FROM vms WHERE agent_id==?"
			}

			sqlStmt, err := tx.Prepare(prepareStmt)
			defer sqlStmt.Close()
			if err != nil {
				sqliteErr := err.(sqlite3.Error)
				if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
					return true, bosherr.WrapError(sqliteErr, "retrying...")
				} else {
					return false, bosherr.WrapError(sqliteErr, "Failed to prepare sql statement")
				}
			}

			err = sqlStmt.QueryRow(vmInfoDB.VmProperties.AgentId).Scan(&vmInfoDB.VmProperties.Id, &vmInfoDB.VmProperties.ImageId, &vmInfoDB.VmProperties.AgentId)
			if err != nil && !strings.Contains(err.Error(), "no rows") {
				sqliteErr := err.(sqlite3.Error)
				if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
					return true, bosherr.WrapError(sqliteErr, "retrying...")
				} else {
					return false, bosherr.WrapError(sqliteErr, "Failed to query VM info from vms table")
				}

			}
			tx.Commit()
			return false, nil
		})

	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(retryTimeout, retryInterval, execStmtRetryable, timeService, vmInfoDB.logger)
	err := timeoutRetryStrategy.Try()
	if err != nil {
		return bosherr.WrapError(err, fmt.Sprintf("Failed to run QueryVMInfobyAgentID"))
	} else {
		return nil
	}

}
예제 #6
0
func (p partedPartitioner) createEachPartition(partitions []Partition, partitionStart uint64, deviceFullSizeInBytes uint64, devicePath string) error {
	//For each Parition
	alignmentInBytes := uint64(1048576)
	for index, partition := range partitions {

		//Get end point for partition
		var partitionEnd uint64

		if partition.SizeInBytes == 0 {
			// If no partitions were specified, use the whole disk space
			partitionEnd = p.roundDown(deviceFullSizeInBytes-1, alignmentInBytes)
		} else {
			partitionEnd = partitionStart + partition.SizeInBytes
			// If the partition size is greater than the remaining space on disk, truncate the partition to whatever size is left
			if partitionEnd >= deviceFullSizeInBytes {
				partitionEnd = deviceFullSizeInBytes - 1
				p.logger.Info(p.logTag, "Partition %d would be larger than remaining space. Reducing size to %dB", index, partitionEnd-partitionStart)
			}
			partitionEnd = p.roundDown(partitionEnd, alignmentInBytes) - 1
		}

		// Create and run a retryable
		partitionRetryable := boshretry.NewRetryable(func() (bool, error) {
			_, _, _, err := p.cmdRunner.RunCommand(
				"parted",
				"-s",
				devicePath,
				"unit",
				"B",
				"mkpart",
				"primary",
				fmt.Sprintf("%d", partitionStart),
				fmt.Sprintf("%d", partitionEnd),
			)
			if err != nil {
				p.logger.Error(p.logTag, "Failed with an error: %s", err)
				//TODO: double check the output here. Does it make sense?
				return true, bosherr.WrapError(err, "Creating partition using parted")
			}
			p.logger.Info(p.logTag, "Successfully created partition %d on %s", index, devicePath)
			return false, nil
		})

		partitionRetryStrategy := NewPartitionStrategy(partitionRetryable, p.timeService, p.logger)
		err := partitionRetryStrategy.Try()

		if err != nil {
			return bosherr.WrapErrorf(err, "Partitioning disk `%s'", devicePath)
		}

		//increment
		partitionStart = p.roundUp(partitionEnd+1, alignmentInBytes)
	}
	return nil
}
예제 #7
0
func (c *agentClient) sendAsyncTaskMessage(method string, arguments []interface{}) (value map[string]interface{}, err error) {
	var response TaskResponse
	err = c.agentRequest.Send(method, arguments, &response)
	if err != nil {
		return value, bosherr.WrapErrorf(err, "Sending '%s' to the agent", method)
	}

	agentTaskID, err := response.TaskID()
	if err != nil {
		return value, bosherr.WrapError(err, "Getting agent task id")
	}

	sendErrors := 0
	getTaskRetryable := boshretry.NewRetryable(func() (bool, error) {
		var response TaskResponse
		err = c.agentRequest.Send("get_task", []interface{}{agentTaskID}, &response)
		if err != nil {
			sendErrors++
			shouldRetry := sendErrors <= c.toleratedErrorCount
			err = bosherr.WrapError(err, "Sending 'get_task' to the agent")
			msg := fmt.Sprintf("Error occured sending get_task. Error retry %d of %d", sendErrors, c.toleratedErrorCount)
			c.logger.Debug(c.logTag, msg, err)
			return shouldRetry, err
		}
		sendErrors = 0

		c.logger.Debug(c.logTag, "get_task response value: %#v", response.Value)

		taskState, err := response.TaskState()
		if err != nil {
			return false, bosherr.WrapError(err, "Getting task state")
		}

		if taskState != "running" {
			var ok bool
			value, ok = response.Value.(map[string]interface{})
			if !ok {
				c.logger.Warn(c.logTag, "Unable to parse get_task response value: %#v", response.Value)
			}
			return true, nil
		}

		return true, bosherr.Errorf("Task %s is still running", method)
	})

	getTaskRetryStrategy := boshretry.NewUnlimitedRetryStrategy(c.getTaskDelay, getTaskRetryable, c.logger)
	// cannot call getTaskRetryStrategy.Try in the return statement due to gccgo
	// execution order issues: https://code.google.com/p/go/issues/detail?id=8698&thanks=8698&ts=1410376474
	err = getTaskRetryStrategy.Try()
	return value, err
}
func (cmd *ImportImageCmd) Run() error {
	vgbdtgService, err := cmd.client.GetSoftLayer_Virtual_Guest_Block_Device_Template_Group_Service()
	if err != nil {
		return errors.New(fmt.Sprintf("Could not get virtual guest block device template group service from softlayer-go service: `%s`", err.Error()))
	}

	configuration := sldatatypes.SoftLayer_Container_Virtual_Guest_Block_Device_Template_Configuration{
		Name: cmd.Name,
		Note: cmd.Note,
		OperatingSystemReferenceCode: cmd.OsRefCode,
		Uri: cmd.Uri,
	}

	vgbdtgObject, err := vgbdtgService.CreateFromExternalSource(configuration)
	if err != nil {
		return errors.New(fmt.Sprintf("Problem creating image template from external source: `%s`", err.Error()))
	}

	cmd.Id = vgbdtgObject.Id
	cmd.Uuid = vgbdtgObject.GlobalIdentifier

	if cmd.Public {
		execStmtRetryable := boshretry.NewRetryable(
			func() (bool, error) {
				id, err := vgbdtgService.CreatePublicArchiveTransaction(cmd.Id, cmd.PublicName, cmd.PublicNote, cmd.PublicNote, locations)
				if err != nil {
					return true, errors.New(fmt.Sprintf("There would be an active transaction in progress."))
				}

				cmd.Id = id
				cmd.Uuid = ""

				return false, nil
			})
		timeService := clock.NewClock()
		timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(common.TIMEOUT, common.POLLING_INTERVAL, execStmtRetryable, timeService, boshlog.NewLogger(boshlog.LevelInfo))
		err = timeoutRetryStrategy.Try()
		if err != nil {
			return errors.New(fmt.Sprintf("Problem occurred when making image template public: `%s`", err.Error()))
		} else {
			return nil
		}
	}

	return nil
}
예제 #9
0
func (p *provider) downloadRetryable(source Source) boshretry.Retryable {
	return boshretry.NewRetryable(func() (bool, error) {
		downloadedFile, err := p.fs.TempFile("tarballProvider")
		if err != nil {
			return true, bosherr.WrapError(err, "Unable to create temporary file")
		}
		defer func() {
			if err = p.fs.RemoveAll(downloadedFile.Name()); err != nil {
				p.logger.Warn(p.logTag, "Failed to remove downloaded file: %s", err.Error())
			}
		}()

		response, err := p.httpClient.Get(source.GetURL())
		if err != nil {
			return true, bosherr.WrapError(err, "Unable to download")
		}
		defer func() {
			if err = response.Body.Close(); err != nil {
				p.logger.Warn(p.logTag, "Failed to close download response body: %s", err.Error())
			}
		}()

		_, err = io.Copy(downloadedFile, response.Body)
		if err != nil {
			return true, bosherr.WrapError(err, "Saving downloaded bits to temporary file")
		}

		downloadedSha1, err := p.sha1Calculator.Calculate(downloadedFile.Name())
		if err != nil {
			return true, bosherr.WrapError(err, "Calculating sha1 for downloaded file")
		}

		if downloadedSha1 != source.GetSHA1() {
			return true, bosherr.Errorf("SHA1 of downloaded file '%s' does not match expected SHA1 '%s'", downloadedSha1, source.GetSHA1())
		}

		err = p.cache.Save(downloadedFile.Name(), source)
		if err != nil {
			return true, bosherr.WrapError(err, "Saving downloaded file in cache")
		}

		return false, nil
	})
}
func exec(db DB, sqlStmt string, retryTimeout time.Duration, retryInterval time.Duration, logger boshlog.Logger) error {

	execStmtRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			tx, err := db.Begin()
			if err != nil {
				sqliteErr := err.(sqlite3.Error)
				if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
					fmt.Println("err is " + err.Error())
					return true, bosherr.WrapError(sqliteErr, "Retrying...")
				} else {
					return false, bosherr.WrapError(sqliteErr, "Failed to begin DB transcation")
				}
			}

			_, err = tx.Exec(sqlStmt)
			if err != nil {
				sqliteErr := err.(sqlite3.Error)
				if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
					return true, bosherr.WrapError(sqliteErr, "Retrying...")
				} else {
					return false, bosherr.WrapError(sqliteErr, "Failed to execute sql statement: "+sqlStmt)
				}
			}

			tx.Commit()
			return false, nil
		})

	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(retryTimeout, retryInterval, execStmtRetryable, timeService, logger)
	err := timeoutRetryStrategy.Try()
	if err != nil {
		return bosherr.WrapError(err, fmt.Sprintf("Failed to execute the sql statment %s", sqlStmt))
	} else {
		return nil
	}

}
예제 #11
0
func (p sfdiskPartitioner) Partition(devicePath string, partitions []Partition) error {
	if p.diskMatchesPartitions(devicePath, partitions) {
		p.logger.Info(p.logTag, "%s already partitioned as expected, skipping", devicePath)
		return nil
	}

	sfdiskPartitionTypes := map[PartitionType]string{
		PartitionTypeSwap:  "S",
		PartitionTypeLinux: "L",
	}

	sfdiskInput := ""
	for index, partition := range partitions {
		sfdiskPartitionType := sfdiskPartitionTypes[partition.Type]
		partitionSize := fmt.Sprintf("%d", p.convertFromBytesToMb(partition.SizeInBytes))

		if index == len(partitions)-1 {
			partitionSize = ""
		}

		sfdiskInput = sfdiskInput + fmt.Sprintf(",%s,%s\n", partitionSize, sfdiskPartitionType)
	}

	partitionRetryable := boshretry.NewRetryable(func() (bool, error) {
		_, _, _, err := p.cmdRunner.RunCommandWithInput(sfdiskInput, "sfdisk", "-uM", devicePath)
		if err != nil {
			p.logger.Error(p.logTag, "Failed with an error: %s", err)
			return true, bosherr.WrapError(err, "Shelling out to sfdisk")
		}
		p.logger.Info(p.logTag, "Succeeded in partitioning %s with %s", devicePath, sfdiskInput)
		return false, nil
	})

	partitionRetryStrategy := NewSfdiskPartitionStrategy(partitionRetryable, p.timeService, p.logger)
	err := partitionRetryStrategy.Try()

	return err
}
예제 #12
0
func (c *agentClient) GetState() (agentclient.AgentState, error) {
	var response StateResponse

	getStateRetryable := boshretry.NewRetryable(func() (bool, error) {
		err := c.agentRequest.Send("get_state", []interface{}{}, &response)
		if err != nil {
			return true, bosherr.WrapError(err, "Sending get_state to the agent")
		}
		return false, nil
	})

	attemptRetryStrategy := boshretry.NewAttemptRetryStrategy(c.toleratedErrorCount+1, c.getTaskDelay, getStateRetryable, c.logger)
	err := attemptRetryStrategy.Try()
	if err != nil {
		return agentclient.AgentState{}, bosherr.WrapError(err, "Sending get_state to the agent")
	}

	agentState := agentclient.AgentState{
		JobState: response.Value.JobState,
	}

	return agentState, err
}
예제 #13
0
func (p sfdiskPartitioner) Partition(devicePath string, partitions []Partition) error {
	if p.diskMatchesPartitions(devicePath, partitions) {
		p.logger.Info(p.logTag, "%s already partitioned as expected, skipping", devicePath)
		return nil
	}

	sfdiskPartitionTypes := map[PartitionType]string{
		PartitionTypeSwap:  "S",
		PartitionTypeLinux: "L",
	}

	sfdiskInput := ""
	for index, partition := range partitions {
		sfdiskPartitionType := sfdiskPartitionTypes[partition.Type]
		partitionSize := fmt.Sprintf("%d", p.convertFromBytesToMb(partition.SizeInBytes))

		if index == len(partitions)-1 {
			partitionSize = ""
		}

		sfdiskInput = sfdiskInput + fmt.Sprintf(",%s,%s\n", partitionSize, sfdiskPartitionType)
	}

	partitionRetryable := boshretry.NewRetryable(func() (bool, error) {
		_, _, _, err := p.cmdRunner.RunCommandWithInput(sfdiskInput, "sfdisk", "-uM", devicePath)
		if err != nil {
			p.logger.Error(p.logTag, "Failed with an error: %s", err)
			return true, bosherr.WrapError(err, "Shelling out to sfdisk")
		}
		p.logger.Info(p.logTag, "Succeeded in partitioning %s with %s", devicePath, sfdiskInput)
		return false, nil
	})

	partitionRetryStrategy := NewPartitionStrategy(partitionRetryable, p.timeService, p.logger)
	err := partitionRetryStrategy.Try()

	if err != nil {
		return err
	}

	if strings.Contains(devicePath, "/dev/mapper/") {
		_, _, _, err = p.cmdRunner.RunCommand("/etc/init.d/open-iscsi", "restart")
		if err != nil {
			return bosherr.WrapError(err, "Shelling out to restart open-iscsi")
		}

		detectPartitionRetryable := boshretry.NewRetryable(func() (bool, error) {
			output, _, _, err := p.cmdRunner.RunCommand("dmsetup", "ls")
			if err != nil {
				return true, bosherr.WrapError(err, "Shelling out to dmsetup ls")
			}

			if strings.Contains(output, "No devices found") {
				return true, bosherr.Errorf("No devices found")
			}

			device := strings.TrimPrefix(devicePath, "/dev/mapper/")
			lines := strings.Split(strings.Trim(output, "\n"), "\n")
			for i := 0; i < len(lines); i++ {
				if match, _ := regexp.MatchString("-part1", lines[i]); match {
					if strings.Contains(lines[i], device) {
						p.logger.Info(p.logTag, "Succeeded in detecting partition %s", devicePath+"-part1")
						return false, nil
					}
				}
			}

			return true, bosherr.Errorf("Partition %s does not show up", devicePath+"-part1")
		})

		detectPartitionRetryStrategy := NewPartitionStrategy(detectPartitionRetryable, p.timeService, p.logger)
		err := detectPartitionRetryStrategy.Try()
		if err != nil {
			return err
		}
	}

	return nil
}
func (slns *softLayer_Network_Storage_Service) CreateNetworkStorage(size int, capacity int, location string, useHourlyPricing bool) (datatypes.SoftLayer_Network_Storage, error) {
	if size < 0 {
		return datatypes.SoftLayer_Network_Storage{}, errors.New("Cannot create negative sized volumes")
	}

	sizeItemPriceId, err := slns.getIscsiVolumeItemIdBasedOnSize(size)
	if err != nil {
		return datatypes.SoftLayer_Network_Storage{}, err
	}

	var iopsItemPriceId int

	if capacity == 0 {
		iopsItemPriceId, err = slns.selectMediumIopsItemPriceIdOnSize(size)
		if err != nil {
			return datatypes.SoftLayer_Network_Storage{}, err
		}

	} else {
		iopsItemPriceId, err = slns.getItemPriceIdBySizeAndIops(size, capacity)
		if err != nil {
			return datatypes.SoftLayer_Network_Storage{}, err
		}
	}

	blockStorageItemPriceId, err := slns.getBlockStorageItemPriceId()

	order := datatypes.SoftLayer_Container_Product_Order_Network_PerformanceStorage_Iscsi{
		Location:    location,
		ComplexType: "SoftLayer_Container_Product_Order_Network_PerformanceStorage_Iscsi",
		OsFormatType: datatypes.SoftLayer_Network_Storage_Iscsi_OS_Type{
			Id:      12,
			KeyName: "LINUX",
		},
		Prices: []datatypes.SoftLayer_Product_Item_Price{
			datatypes.SoftLayer_Product_Item_Price{
				Id: sizeItemPriceId,
			},
			datatypes.SoftLayer_Product_Item_Price{
				Id: iopsItemPriceId,
			},
			datatypes.SoftLayer_Product_Item_Price{
				Id: blockStorageItemPriceId,
			},
		},
		PackageId:        NETWORK_PERFORMANCE_STORAGE_PACKAGE_ID,
		Quantity:         1,
		UseHourlyPricing: useHourlyPricing,
	}

	productOrderService, err := slns.client.GetSoftLayer_Product_Order_Service()
	if err != nil {
		return datatypes.SoftLayer_Network_Storage{}, err
	}

	receipt, err := productOrderService.PlaceContainerOrderNetworkPerformanceStorageIscsi(order)
	if err != nil {
		return datatypes.SoftLayer_Network_Storage{}, err
	}

	var iscsiStorage datatypes.SoftLayer_Network_Storage
	SL_CREATE_ISCSI_VOLUME_TIMEOUT, err := strconv.Atoi(os.Getenv("SL_CREATE_ISCSI_VOLUME_TIMEOUT"))
	if err != nil || SL_CREATE_ISCSI_VOLUME_TIMEOUT == 0 {
		SL_CREATE_ISCSI_VOLUME_TIMEOUT = 600
	}
	SL_CREATE_ISCSI_VOLUME_POLLING_INTERVAL, err := strconv.Atoi(os.Getenv("SL_CREATE_ISCSI_VOLUME_POLLING_INTERVAL"))
	if err != nil || SL_CREATE_ISCSI_VOLUME_POLLING_INTERVAL == 0 {
		SL_CREATE_ISCSI_VOLUME_POLLING_INTERVAL = 10
	}

	execStmtRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			iscsiStorage, err = slns.findIscsiVolumeId(receipt.OrderId)
			if err != nil {
				return true, errors.New(fmt.Sprintf("Failed to find iSCSI volume with id `%d` due to `%s`, retrying...", receipt.OrderId, err.Error()))
			}

			return false, nil
		})
	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(time.Duration(SL_CREATE_ISCSI_VOLUME_TIMEOUT)*time.Second, time.Duration(SL_CREATE_ISCSI_VOLUME_POLLING_INTERVAL)*time.Second, execStmtRetryable, timeService, boshlog.NewLogger(boshlog.LevelInfo))
	err = timeoutRetryStrategy.Try()
	if err != nil {
		return datatypes.SoftLayer_Network_Storage{}, errors.New(fmt.Sprintf("Failed to find iSCSI volume with id `%d` after retry within `%d` seconds", receipt.OrderId, SL_CREATE_ISCSI_VOLUME_TIMEOUT))
	}

	return iscsiStorage, nil
}
func (vmInfoDB *VMInfoDB) UpdateVMInfoByID(retryTimeout time.Duration, retryInterval time.Duration) error {

	execStmtRetryable := boshretry.NewRetryable(
		func() (bool, error) {
			tx, err := vmInfoDB.db.Begin()
			if err != nil {
				sqliteErr := err.(sqlite3.Error)
				if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
					return true, bosherr.WrapError(sqliteErr, "retrying...")
				} else {
					return false, bosherr.WrapError(sqliteErr, "Failed to begin DB transcation")
				}
			}

			if vmInfoDB.VmProperties.InUse == "f" || vmInfoDB.VmProperties.InUse == "t" {
				sqlStmt := fmt.Sprintf("UPDATE vms SET in_use='%s', timestamp=CURRENT_TIMESTAMP WHERE id = %d", vmInfoDB.VmProperties.InUse, vmInfoDB.VmProperties.Id)
				_, err = tx.Exec(sqlStmt)
				if err != nil {
					sqliteErr := err.(sqlite3.Error)
					if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
						return true, bosherr.WrapError(sqliteErr, "retrying...")
					} else {
						return false, bosherr.WrapError(sqliteErr, "Failed to update in_use column in vms")
					}
				}
			}

			if vmInfoDB.VmProperties.ImageId != "" {
				sqlStmt := fmt.Sprintf("UPDATE vms SET image_id='%s' WHERE id = %d", vmInfoDB.VmProperties.ImageId, vmInfoDB.VmProperties.Id)
				_, err = tx.Exec(sqlStmt)
				if err != nil {
					sqliteErr := err.(sqlite3.Error)
					if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
						return true, bosherr.WrapError(sqliteErr, "retrying...")
					} else {
						return false, bosherr.WrapError(sqliteErr, "Failed to update in_use column in vms")
					}
				}
			}

			if vmInfoDB.VmProperties.AgentId != "" {
				sqlStmt := fmt.Sprintf("UPDATE vms SET agent_id='%s' WHERE id = %d", vmInfoDB.VmProperties.AgentId, vmInfoDB.VmProperties.Id)
				_, err = tx.Exec(sqlStmt)
				if err != nil {
					sqliteErr := err.(sqlite3.Error)
					if sqliteErr.Code == sqlite3.ErrBusy || sqliteErr.Code == sqlite3.ErrLocked {
						return true, bosherr.WrapError(sqliteErr, "retrying...")
					} else {
						return false, bosherr.WrapError(sqliteErr, "Failed to update in_use column in vms")
					}
				}
			}
			tx.Commit()
			return false, nil
		})

	timeService := clock.NewClock()
	timeoutRetryStrategy := boshretry.NewTimeoutRetryStrategy(retryTimeout, retryInterval, execStmtRetryable, timeService, vmInfoDB.logger)
	err := timeoutRetryStrategy.Try()
	if err != nil {
		return bosherr.WrapError(err, fmt.Sprintf("Failed to run UpdateVMInfoByID"))
	} else {
		return nil
	}
}