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 }
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 } }
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 }
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 }
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 } }
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 }
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 }
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 } }