/** * Communicates with RDS for updated instance progress and checks the status. * Concludes if error or if naturally done. */ @Override public void followupCheck(int waitNum) { try { DBInstance dbInstance = rdsClient.describeInstance(instanceId); checkInstanceId(dbInstance); logFollowupStatus(waitNum, dbInstance); checkInstanceStatus(dbInstance); } catch (DBInstanceNotFoundException e) { handleInstanceNotFound(waitNum, e); } }
/** * Amazon can't find the instance. This is an allowed final state for a delete operation, otherwise is a bad error. */ private void handleInstanceNotFound(int waitNum, DBInstanceNotFoundException e) { LOGGER.debug("RDS " + getDescription() + " status after wait#" + waitNum + ": " + e.getClass().getSimpleName() + ": " + e.getMessage()); if (expectedFinalState.equals(DELETE_FINAL_STATE)) { LOGGER.info("RDS " + getDescription() + " is done"); result = new DBInstance(); //Just a stub, since result==null would be considered a progress error. } else { LOGGER.error(logContext + getDescription() + ": not found", e); } done = true; }
/** * Simulate deleting the rds instance and waiting for confirmation. */ private void testDeleteInstance(RdsInstanceStatus thirdStatus) { when(mockRdsClient.deleteInstance(instanceId)).thenReturn(fakeInstance(RdsInstanceStatus.DELETING/*status #0*/)); if (thirdStatus != null) { when(mockRdsClient.describeInstance(instanceId)) .thenReturn(fakeInstance(RdsInstanceStatus.DELETING)) //Followup waitNum#1 .thenReturn(fakeInstance(RdsInstanceStatus.DELETING)) //Followup waitNum#2 .thenReturn(fakeInstance(thirdStatus)); } else { when(mockRdsClient.describeInstance(instanceId)) .thenReturn(fakeInstance(RdsInstanceStatus.DELETING)) //Followup waitNum#1 .thenReturn(fakeInstance(RdsInstanceStatus.DELETING)) //Followup waitNum#2 .thenThrow(new DBInstanceNotFoundException("not found")); //Checker should catch it } rdsInstanceDeleteTask.deleteInstance(false); verify(mockRdsClient, times(3)).describeInstance(instanceId); }
private boolean isDatabaseAvailable(RetryContext context) { DescribeDBInstancesResult describeDBInstancesResult; try { describeDBInstancesResult = this.amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier((String) context.getAttribute(DB_INSTANCE_ATTRIBUTE_NAME))); } catch (DBInstanceNotFoundException e) { LOGGER.warn("Database Instance with name {} has been removed or is not configured correctly, no retry possible", getDbInstanceIdentifier()); //Database has been deleted while operating, hence we can not retry return false; } if (describeDBInstancesResult.getDBInstances().size() == 1) { DBInstance dbInstance = describeDBInstancesResult.getDBInstances().get(0); InstanceStatus instanceStatus = InstanceStatus.fromDatabaseStatus(dbInstance.getDBInstanceStatus()); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Status of database to be retried is {}", instanceStatus); } return instanceStatus.isRetryable(); } else { throw new IllegalStateException("Multiple databases found for same identifier, this is likely an incompatibility with the Amazon SDK"); } }
@Test public void afterPropertiesSet_noInstanceFound_reportsIllegalStateException() throws Exception { //Arrange this.expectedException.expect(IllegalStateException.class); this.expectedException.expectMessage("No database instance with id:'test'"); AmazonRDS amazonRDS = mock(AmazonRDS.class); when(amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))).thenThrow(new DBInstanceNotFoundException("foo")); AmazonRdsDataSourceFactoryBean amazonRdsDataSourceFactoryBean = new AmazonRdsDataSourceFactoryBean(amazonRDS, "test", "foo"); //Act amazonRdsDataSourceFactoryBean.afterPropertiesSet(); //Assert }
@Test public void canRetry_retryNotPossibleDueToNoDatabase_returnsFalse() throws Exception { //Arrange AmazonRDS amazonRDS = mock(AmazonRDS.class); DatabaseInstanceStatusRetryPolicy policy = new DatabaseInstanceStatusRetryPolicy(amazonRDS, "test"); when(amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))). thenThrow(new DBInstanceNotFoundException("test")); RetryContext retryContext = policy.open(new RetryContextSupport(null)); //Act policy.registerThrowable(retryContext, new TransientDataAccessResourceException("not available")); //Assert assertFalse(policy.canRetry(retryContext)); policy.close(retryContext); }
private static DBInstance getDbInstance(final AmazonRDSClient amazonRds, final String rdsInstanceId) { try { final DescribeDBInstancesRequest request = new DescribeDBInstancesRequest() .withDBInstanceIdentifier(rdsInstanceId); final DescribeDBInstancesResult response = amazonRds.describeDBInstances(request); return response.getDBInstances().get(0); } catch (DBInstanceNotFoundException e) { throw new IllegalStateException("Could not find DB instance!"); } }
@Override public void delete(RDSInstanceTemplate template, Collection<String> virtualInstanceIds) throws InterruptedException { if (virtualInstanceIds.isEmpty()) { return; } for (String virtualInstanceId : virtualInstanceIds) { LOG.info(">> Terminating {}", virtualInstanceId); DeleteDBInstanceRequest request = new DeleteDBInstanceRequest() .withDBInstanceIdentifier(virtualInstanceId); if (template.isSkipFinalSnapshot().or(false)) { request.setSkipFinalSnapshot(true); } else { String snapshotIdentifier = String.format("%s-director-final-snapshot-%d", virtualInstanceId, System.currentTimeMillis()); request.setFinalDBSnapshotIdentifier(snapshotIdentifier); } try { DBInstance deletedDbInstance = client.deleteDBInstance(request); LOG.info("<< Result {}", deletedDbInstance); } catch (DBInstanceNotFoundException e) { LOG.warn("<< Instance {} was not found, assuming already deleted", virtualInstanceId); } } }
@Override public Map<String, InstanceState> getInstanceState( RDSInstanceTemplate template, Collection<String> virtualInstanceIds) { Map<String, InstanceState> instanceStateByVirtualInstanceId = Maps.newHashMapWithExpectedSize(virtualInstanceIds.size()); // RDS does not allow batching of DB instance status requests. for (String virtualInstanceId : virtualInstanceIds) { InstanceState instanceState; try { DescribeDBInstancesResult result = client.describeDBInstances( new DescribeDBInstancesRequest() .withDBInstanceIdentifier(virtualInstanceId)); LOG.info("<< Result: {}", result); // Paging not required, should only ever be one instance returned if (result.getDBInstances().size() > 0) { DBInstance dbInstance = result.getDBInstances().get(0); RDSStatus status = RDSStatus.valueOfRDSString(dbInstance.getDBInstanceStatus()); instanceState = RDSInstanceState.fromRdsStatus(status); } else { instanceState = RDSInstanceState.fromRdsStatus(null); } } catch (DBInstanceNotFoundException e) { instanceState = RDSInstanceState.fromRdsStatus(null); } instanceStateByVirtualInstanceId.put(virtualInstanceId, instanceState); } return instanceStateByVirtualInstanceId; }
/** * Retrieves the {@link com.amazonaws.services.rds.model.DBInstance} information * * @param identifier * - the database identifier used * @return - the db instance * @throws IllegalStateException * if the db instance is not found */ protected DBInstance getDbInstance(String identifier) throws IllegalStateException { DBInstance instance; try { DescribeDBInstancesResult describeDBInstancesResult = this.amazonRds.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier(identifier)); instance = describeDBInstancesResult.getDBInstances().get(0); } catch (DBInstanceNotFoundException e) { throw new IllegalStateException(MessageFormat.format("No database instance with id:''{0}'' found. Please specify a valid db instance", identifier)); } return instance; }
/** * @inheritDoc */ @Override public void terminateInstance( String instanceName, Identity identity ) { AmazonRDS rds = ActivityUtils.createClient( AmazonRDSClient.class, identity ); try { rds.deleteDBInstance( new DeleteDBInstanceRequest( instanceName ).withSkipFinalSnapshot( true ) ); } catch ( DBInstanceNotFoundException e ) { } }
/** * @inheritDoc */ @Override public DatabaseInstance restoreSnapshot( String snapshotName, String instanceName, String subnetGroupName, Identity identity ) { AmazonRDS rds = ActivityUtils.createClient( AmazonRDSClient.class, identity ); try { DescribeDBInstancesResult results = rds.describeDBInstances( new DescribeDBInstancesRequest().withDBInstanceIdentifier( instanceName ) ); return toDatabaseInstance( results.getDBInstances().get( 0 ) ); } catch ( DBInstanceNotFoundException e ) { } DescribeDBSnapshotsResult result = rds.describeDBSnapshots( new DescribeDBSnapshotsRequest().withDBSnapshotIdentifier( snapshotName ) ); if ( result.getDBSnapshots().isEmpty() ) { throw new IllegalArgumentException( "Snapshot " + snapshotName + " is not found" ); } DBSnapshot snapshot = result.getDBSnapshots().get( 0 ); RestoreDBInstanceFromDBSnapshotRequest request = new RestoreDBInstanceFromDBSnapshotRequest( instanceName, snapshotName ); if ( snapshot.getVpcId() == null ) { request.setPubliclyAccessible( true ); } else { request.setDBSubnetGroupName( subnetGroupName ); } DBInstance ins = rds.restoreDBInstanceFromDBSnapshot( request ); DatabaseInstance desc = new DatabaseInstance(); desc.setAllocatedStorage( ins.getAllocatedStorage() ); desc.setAvailabilityZone( ins.getAvailabilityZone() ); desc.setInstanceId( ins.getDBInstanceIdentifier() ); desc.setInstanceType( ins.getDBInstanceClass() ); if ( ins.getEndpoint() != null ) { desc.setPublicHostName( ins.getEndpoint().getAddress() ); desc.setPort( ins.getEndpoint().getPort() ); } desc.setMasterUser( ins.getMasterUsername() ); return desc; }