@Override
 public Instance update(Instance existingEntity, Instance requestedEntity) {
   LOG.debug(
       String.format(
           "update(Existing Instance - %s,Requested Instance - %s)",
           existingEntity, requestedEntity));
   InstanceStateTransition transition = new InstanceStateTransition();
   Instance entityToReturn = null;
   if (existingEntity != null) {
     transition.setPreviousState(existingEntity.getState());
     // we set this here in case we can't write the state want.
     // this way the user doesn't get back a null. :D.
     transition.setNextState(existingEntity.getState());
     instanceStatusMap.put(existingEntity.getInstanceId(), transition);
     if (existingEntity.getNodeId() != null
         && existingEntity.getState() != InstanceState.SHUTTING_DOWN
         && existingEntity.getState() != InstanceState.TERMINATED) {
       existingEntity.setState(InstanceState.SHUTTING_DOWN);
       entityToReturn = existingEntity;
     } else if (existingEntity.getState() != InstanceState.TERMINATED) {
       LOG.info(
           String.format(
               "Instance %s is provisionally being terminated before an Instance Manager has claimed it by stamping a node id onto it",
               existingEntity.getInstanceId()));
       existingEntity.setState(InstanceState.TERMINATED);
       entityToReturn = existingEntity;
     }
   } else {
     LOG.warn(String.format("Expected non-null instance"));
   }
   return entityToReturn;
 }
  @Override
  public void handleResult(Instance result) {
    LOG.debug(String.format("handleResult(PiEntity - %s)", result));
    if (result != null) {
      if (result.getNodeId() != null) {
        LOG.debug(
            String.format(
                "Sending termination message for inst %s to node %s",
                result.getInstanceId(), result.getNodeId()));
        PId instanceRecordId = piIdBuilder.getNodeIdFromNodeId(result.getNodeId());
        MessageContext instanceMessageContext = messageContextFactory.newMessageContext();
        instanceMessageContext.routePiMessageToApplication(
            instanceRecordId,
            EntityMethod.DELETE,
            result,
            InstanceManagerApplication.APPLICATION_NAME);
      } else {
        LOG.debug(
            String.format(
                "Null node id detected, not sending termination message for %s to instance manager",
                result.getInstanceId()));
      }

      int instanceGlobalAvzCode =
          piIdBuilder.getGlobalAvailabilityZoneCodeFromEc2Id(result.getInstanceId());
      PId securityGroupId =
          piIdBuilder
              .getPId(SecurityGroup.getUrl(result.getUserId(), result.getSecurityGroupName()))
              .forGlobalAvailablityZoneCode(instanceGlobalAvzCode);
      LOG.debug(
          String.format(
              "Sending termination message for inst %s to network app node %s for sec group %s:%s",
              result.getInstanceId(),
              result.getUserId(),
              securityGroupId.toStringFull(),
              result.getSecurityGroupName()));
      MessageContext securityGroupMessageContext = messageContextFactory.newMessageContext();
      securityGroupMessageContext.routePiMessageToApplication(
          securityGroupId, EntityMethod.DELETE, result, NetworkManagerApplication.APPLICATION_NAME);
      InstanceStateTransition transition = instanceStatusMap.get(result.getInstanceId());
      if (transition != null) {
        transition.setNextState(result.getState());
      }
    } else {
      LOG.warn("Expected a non-null instance record");
    }
  }
 private Instance setupInstanceWithReservationId(
     String instanceId, String reservationId, String userId) {
   Instance instance = mock(Instance.class);
   when(instance.getInstanceId()).thenReturn(instanceId);
   when(instance.getReservationId()).thenReturn(reservationId);
   when(instance.getUserId()).thenReturn(userId);
   when(instance.getLastHeartbeatTimestamp()).thenReturn(System.currentTimeMillis());
   return instance;
 }
  @Before
  public void setup() {
    when(piIdBuilder.getPIdForEc2AvailabilityZone(uri)).thenReturn(instancePId);
    when(piIdBuilder.getGlobalAvailabilityZoneCodeFromEc2Id(instanceId)).thenReturn(globalAvzCode);
    when(piIdBuilder.getPId(SecurityGroup.getUrl(userId, securityGroupName)))
        .thenReturn(securityGroupPId);
    when(piIdBuilder.getPiQueuePId(PiQueue.INSTANCE_NETWORK_MANAGER_TEARDOWN))
        .thenReturn(instanceNetworkManagerTeardownQueueId);
    when(securityGroupPId.forGlobalAvailablityZoneCode(globalAvzCode)).thenReturn(securityGroupPId);

    when(instanceNetworkManagerTeardownQueueId.forLocalScope(
            PiQueue.TERMINATE_INSTANCE.getNodeScope()))
        .thenReturn(instanceNetworkManagerTeardownQueueId);
    when(messageContextFactory.newMessageContext()).thenReturn(messageContext);
    when(dhtClientFactory.createReader()).thenReturn(dhtReader);

    when(resultInstance.getInstanceId()).thenReturn(instanceId);
    when(resultInstance.getNodeId()).thenReturn(instanceNodeId);
    when(resultInstance.getUserId()).thenReturn(userId);
    when(resultInstance.getSecurityGroupName()).thenReturn(securityGroupName);
  }
  public ReservationInstances runInstances(final Reservation reservation) {
    LOG.debug(String.format("runInstances(%s)", reservation));

    String securityGroupUrl =
        SecurityGroup.getUrl(reservation.getUserId(), reservation.getSecurityGroupName());
    PId securityGroupId = getPiIdBuilder().getPId(securityGroupUrl).forLocalRegion();
    SecurityGroup securityGroup =
        (SecurityGroup) getDhtClientFactory().createBlockingReader().get(securityGroupId);

    validateReservation(reservation, securityGroup);

    reservation.setReservationId(getIdFactory().createNewReservationId());

    AvailabilityZone availabilityZone;
    if (StringUtils.isNotEmpty(reservation.getAvailabilityZone())) {
      try {
        availabilityZone = getAvailabilityZoneByName(reservation.getAvailabilityZone());
      } catch (AvailabilityZoneNotFoundException e) {
        throw new IllegalArgumentException(
            String.format("Unknown availability zone: %s", reservation.getAvailabilityZone()));
      }
    } else {
      availabilityZone = getLocalAvailabilityZone();
      reservation.setAvailabilityZone(availabilityZone.getAvailabilityZoneName());
    }

    // setup return object
    ReservationInstances reservationInstances = new ReservationInstances();
    reservationInstances.setReservation(reservation);

    for (int i = 0; i < reservation.getMaxCount(); i++) {
      String instanceId =
          getIdFactory().createNewInstanceId(availabilityZone.getGlobalAvailabilityZoneCode());
      // create instance
      Instance instance = new Instance(reservation);
      instance.setInstanceType(reservation.getInstanceType());
      instance.setUserId(reservation.getUserId());
      instance.setInstanceId(instanceId);
      instance.setState(InstanceState.PENDING);
      instance.setLaunchTime(System.currentTimeMillis());
      instance.setAvailabilityZoneCode(availabilityZone.getAvailabilityZoneCodeWithinRegion());
      instance.setRegionCode(availabilityZone.getRegionCode());
      LOG.info(String.format("Requesting new %s", instance));
      reservationInstances.getInstances().add(instance);

      // create instance in dht
      PId instanceDhtId =
          getPiIdBuilder().getPIdForEc2AvailabilityZone(Instance.getUrl(instanceId));
      BlockingDhtWriter blockingDhtWriter = getDhtClientFactory().createBlockingWriter();
      AddNewInstanceResolver addNewInstanceResolver = new AddNewInstanceResolver();
      blockingDhtWriter.update(instanceDhtId, instance, addNewInstanceResolver);

      reservation.addInstanceId(instance.getInstanceId());
    }

    getUserService()
        .addInstancesToUser(
            reservation.getUserId(), reservation.getInstanceIds(), reservation.getInstanceType());

    // write security group to DHT
    getDhtClientFactory()
        .createBlockingWriter()
        .update(
            securityGroupId,
            null,
            new AddInstanceToSecurityGroupResolver(reservation.getInstanceIds()));

    // add to task processing queue
    PId runInstanceQueueId =
        getPiIdBuilder()
            .getPId(PiQueue.RUN_INSTANCE.getUrl())
            .forGlobalAvailablityZoneCode(availabilityZone.getGlobalAvailabilityZoneCode());
    for (String instanceId : reservation.getInstanceIds()) {
      getTaskProcessingQueueHelper()
          .addUrlToQueue(runInstanceQueueId, Instance.getUrl(instanceId), instanceTaskQueueRetries);
    }

    // anycast message
    PubSubMessageContext pubSubMessageContext =
        getApiApplicationManager()
            .newPubSubMessageContextFromGlobalAvzCode(
                PiTopics.RUN_INSTANCE, availabilityZone.getGlobalAvailabilityZoneCode());
    pubSubMessageContext.randomAnycast(EntityMethod.CREATE, reservation);

    return reservationInstances;
  }