/** * Test helper - makes describe result with one or more named instances. */ private DescribeInstanceHealthResult makeDescribeInstanceHealthResult(String... instanceIds) { DescribeInstanceHealthResult result = new DescribeInstanceHealthResult(); if (ArrayUtils.isNotEmpty(instanceIds)) { List<InstanceState> instanceStates = new ArrayList<InstanceState>(); for (String instanceId : instanceIds) { InstanceState instanceState = new InstanceState(); instanceState.setInstanceId(instanceId); instanceStates.add(instanceState); } result.setInstanceStates(instanceStates); } return result; }
@GET @NoAuth @Path("/{elbName}/instances") public List<InstanceState> getInstancesByElb(@PathParam("elbName") String elbName) { if (config.isPresent()) { try { DescribeInstanceHealthRequest request = new DescribeInstanceHealthRequest(elbName); DescribeInstanceHealthResult result = elbClient.describeInstanceHealth(request); return result.getInstanceStates(); } catch (AmazonClientException exn) { throw new BaragonWebException(String.format("AWS Client Error %s", exn)); } } else { throw new BaragonWebException("ElbSync and related actions are not currently enabled"); } }
/** * Initial check calls elbClient to describe instance health, same as the followup checks, because the initial * registration call does not return any health info. */ @Override public void initialCheck() { InstanceState instanceState = elbClient.describeInstanceHealth(elbName, ec2InstanceId); checkInstanceState(instanceState); LOGGER.debug(logContext + "Initial ELB instance health: " + instanceState.getState()); }
@Override public void followupCheck(int waitNum) { InstanceState instanceState = elbClient.describeInstanceHealth(elbName, ec2InstanceId); checkInstanceState(instanceState); LOGGER.debug(logContext + "ELB instance health after wait#" + waitNum + ": " + instanceState.getState()); }
/** * Sanity checks the instance state, and checks for done-ness. */ private void checkInstanceState(InstanceState instanceState) { if (!StringUtils.equals(ec2InstanceId, instanceState.getInstanceId())) { throw new IllegalStateException(logContext + "We requested health of ec2 instance id '" + ec2InstanceId + "' but ELB replied with id '" + instanceState.getInstanceId() + "'"); } if (ElbInstanceState.IN_SERVICE.equalsString(instanceState.getState())) { LOGGER.info("ELB '" + elbName + "' says ec2 instance id '" + ec2InstanceId + "' is now in service"); done = true; result = instanceState; } }
/** * Simply logs the timeout and returns null. */ @Override public InstanceState timeout() { LOGGER.error("ELB Instance Health failed to reach state '" + ElbInstanceState.IN_SERVICE + "' prior to timeout"); return null; }
/** * Checks the instance health of the ec2 instance in the given ELB. */ public InstanceState describeInstanceHealth(String elbName, String ec2InstanceId) { LOGGER.debug("describeInstanceHealth(elbName: " + elbName + ", ec2InstanceId: " + ec2InstanceId + ")"); assertNonBlankArgs(elbName, ec2InstanceId); StopWatch stopWatch = new StopWatch(); try { stopWatch.start(); DescribeInstanceHealthRequest request = new DescribeInstanceHealthRequest(); request.setLoadBalancerName(elbName); request.setInstances(Arrays.asList(new Instance(ec2InstanceId))); DescribeInstanceHealthResult result = awsElbClient.describeInstanceHealth(request); if (result == null || CollectionUtils.isEmpty(result.getInstanceStates())) { throw new RuntimeException("ELB '" + elbName + "' didn't match instance id '" + ec2InstanceId + "'"); } else if (result.getInstanceStates().size() > 1) { LOGGER.warn("Expected 1 instance state for instance id '" + ec2InstanceId + "' in elb '" + elbName + "', found " + result.getInstanceStates().size()); } return result.getInstanceStates().get(0); } finally { stopWatch.stop(); LOGGER.debug("describeInstanceHealth time elapsed " + stopWatch); } }
private InstanceState makeInstanceState(String instanceId, ElbInstanceState elbInstanceState) { InstanceState instanceState = new InstanceState(); instanceState.setInstanceId(instanceId); instanceState.setState(elbInstanceState.toString()); return instanceState; }
public List<InstanceState> describeInstanceHealth(String elbName, List<String> instanceIds) { logger.info("describe elb instance health, instanceIds={}", instanceIds); List<com.amazonaws.services.elasticloadbalancing.model.Instance> instances = instanceIds.stream() .map(com.amazonaws.services.elasticloadbalancing.model.Instance::new) .collect(Collectors.toList()); DescribeInstanceHealthResult result = elb.describeInstanceHealth(new DescribeInstanceHealthRequest(elbName) .withInstances(instances)); return result.getInstanceStates(); }
public void attachInstances(String elbName, List<String> instanceIds, boolean waitUntilInService) throws InterruptedException { logger.info("attach instances to elb, elb={}, instances={}", elbName, instanceIds); String expectedState = waitUntilInService ? "InService" : "Service"; // if not waitUntilInService, state can be InService or OutOfService List<Instance> instances = instanceIds.stream().map(Instance::new).collect(Collectors.toList()); elb.registerInstancesWithLoadBalancer(new RegisterInstancesWithLoadBalancerRequest() .withLoadBalancerName(elbName) .withInstances(instances)); int attempts = 0; while (true) { attempts++; Threads.sleepRoughly(Duration.ofSeconds(15)); List<InstanceState> states = describeInstanceHealth(elbName, instanceIds); for (InstanceState state : states) { logger.info("instance elb state {} => {}", state.getInstanceId(), state.getState()); } boolean allAttached = states.stream().allMatch(state -> state.getState().contains(expectedState)); if (allAttached) { logger.info("all instances are attached to elb"); break; } else if (attempts >= 30) { throw new Error("failed to wait all instances to be attached to elb, please check aws console for more details"); } else { logger.info("continue to wait, not all new instances are attached"); } } }
private void waitUntilInstanceAttachedToELB(List<String> newInstanceIds) throws InterruptedException { if (resource.elb != null) { int attempts = 0; while (true) { attempts++; Threads.sleepRoughly(Duration.ofSeconds(15)); List<InstanceState> states = AWS.elb.describeInstanceHealth(resource.elb.remoteELB.getLoadBalancerName(), newInstanceIds); for (InstanceState state : states) { logger.info("ELB instance state {} => {}", state.getInstanceId(), state.getState()); } boolean allInService = states.stream().allMatch(state -> "InService".equalsIgnoreCase(state.getState())); if (allInService) { logger.info("all new instances of ELB are in service"); break; } else if (attempts >= 30) { // roughly wait 30*15=450 seconds, where ASG health check grace period is 300 seconds logger.warn("failed to wait all instances to be attached to ELB, it could be instance failed health check after grace period, ASG probably already created new instances to replace, please check AWS console for more details"); break; } else { logger.info("continue to wait, not all new instances are in service"); } } } }
public boolean isInstanceHealthy(String instanceId, String elbName) { DescribeInstanceHealthRequest describeRequest = new DescribeInstanceHealthRequest(elbName); DescribeInstanceHealthResult result = elbClient.describeInstanceHealth(describeRequest); boolean instanceIsHealthy = false; for (InstanceState instanceState : result.getInstanceStates()) { if (instanceState.getState().equals("InService")) { if (instanceState.getInstanceId().equals(instanceId)) { instanceIsHealthy = true; } } } return instanceIsHealthy; }
private boolean isLastHealthyInstance(DeregisterInstancesFromLoadBalancerRequest request) throws AmazonClientException { DescribeInstanceHealthRequest describeRequest = new DescribeInstanceHealthRequest(request.getLoadBalancerName()); DescribeInstanceHealthResult result = elbClient.describeInstanceHealth(describeRequest); boolean instanceIsHealthy = false; int healthyCount = 0; for (InstanceState instanceState : result.getInstanceStates()) { if (instanceState.getState().equals("InService")) { healthyCount++; if (instanceState.getInstanceId().equals(request.getInstances().get(0).getInstanceId())) { //Will only ever be one instance per request instanceIsHealthy = true; } } } return (instanceIsHealthy && healthyCount == 1); }
@Override public InstanceState getResult() { return result; }
private void setupMock(InstanceState fakeInstanceState) { when(mockElbClient.describeInstanceHealth(ELB_NAME, EC2_INSTANCE_ID)).thenReturn(fakeInstanceState); }