public void testAllocateWithPoolNameWhenResponseIs2xx() throws Exception {
    HttpRequest createFloatingIP =
        HttpRequest.builder()
            .method("POST")
            .endpoint(
                "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
            .addHeader("Accept", "application/json")
            .addHeader("X-Auth-Token", authToken)
            .payload(payloadFromStringWithContentType("{\"pool\":\"myPool\"}", "application/json"))
            .build();

    HttpResponse createFloatingIPResponse =
        HttpResponse.builder()
            .statusCode(200)
            .payload(payloadFromResource("/floatingip_details.json"))
            .build();

    NovaApi apiWhenFloatingIPsExist =
        requestsSendResponses(
            keystoneAuthWithUsernameAndPasswordAndTenantName,
            responseWithKeystoneAccess,
            extensionsOfNovaRequest,
            extensionsOfNovaResponse,
            createFloatingIP,
            createFloatingIPResponse);

    assertEquals(
        apiWhenFloatingIPsExist
            .getFloatingIPExtensionForZone("az-1.region-a.geo-1")
            .get()
            .allocateFromPool("myPool")
            .toString(),
        new ParseFloatingIPTest().expected().toString());
  }
  @Test
  public void testApplyWithIllegalStateException() throws UnknownHostException {
    final NovaApi api = createMock(NovaApi.class);
    KeyPairApi keyApi = createMock(KeyPairApi.class);
    @SuppressWarnings("unchecked")
    final Supplier<String> uniqueIdSupplier = createMock(Supplier.class);

    KeyPair pair = createMock(KeyPair.class);

    expect(api.getKeyPairExtensionForZone("zone")).andReturn(Optional.of(keyApi)).atLeastOnce();

    expect(uniqueIdSupplier.get()).andReturn("1");
    expect(keyApi.createKeyPair("group-1")).andThrow(new IllegalStateException());
    expect(uniqueIdSupplier.get()).andReturn("2");
    expect(keyApi.createKeyPair("group-2")).andReturn(pair);

    replay(api, keyApi, uniqueIdSupplier);

    CreateUniqueKeyPair parser =
        Guice.createInjector(
                new AbstractModule() {

                  @Override
                  protected void configure() {
                    bind(new TypeLiteral<Supplier<String>>() {}).toInstance(uniqueIdSupplier);
                    bind(NovaApi.class).toInstance(api);
                  }
                })
            .getInstance(CreateUniqueKeyPair.class);

    assertEquals(parser.load(ZoneAndName.fromZoneAndName("zone", "group")), pair);

    verify(api, keyApi, uniqueIdSupplier);
  }
  public void testAllocateWhenResponseIs404() throws Exception {
    HttpRequest createFloatingIP =
        HttpRequest.builder()
            .method("POST")
            .endpoint(
                "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
            .addHeader("Accept", "application/json")
            .addHeader("X-Auth-Token", authToken)
            .payload(payloadFromStringWithContentType("{}", "application/json"))
            .build();

    HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(404).build();

    NovaApi apiWhenNoServersExist =
        requestsSendResponses(
            keystoneAuthWithUsernameAndPasswordAndTenantName,
            responseWithKeystoneAccess,
            extensionsOfNovaRequest,
            extensionsOfNovaResponse,
            createFloatingIP,
            createFloatingIPResponse);

    assertNull(
        apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().create());
  }
  public void testListFloatingIPsWhenResponseIs404() throws Exception {
    HttpRequest list =
        HttpRequest.builder()
            .method("GET")
            .endpoint(
                "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
            .addHeader("Accept", "application/json")
            .addHeader("X-Auth-Token", authToken)
            .build();

    HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();

    NovaApi apiWhenNoServersExist =
        requestsSendResponses(
            keystoneAuthWithUsernameAndPasswordAndTenantName,
            responseWithKeystoneAccess,
            extensionsOfNovaRequest,
            extensionsOfNovaResponse,
            list,
            listResponse);

    assertTrue(
        apiWhenNoServersExist
            .getFloatingIPExtensionForZone("az-1.region-a.geo-1")
            .get()
            .list()
            .isEmpty());
  }
  @Override
  public void releaseAddress(String ip) {

    ComputeServiceContext context = iaasProvider.getComputeService().getContext();
    String region = ComputeServiceBuilderUtil.extractRegion(iaasProvider);

    NovaApi novaApi = context.unwrapApi(NovaApi.class);
    FloatingIPApi floatingIPApi = novaApi.getFloatingIPExtensionForZone(region).get();

    for (FloatingIP floatingIP : floatingIPApi.list()) {
      if (floatingIP.getIp().equals(ip)) {
        floatingIPApi.delete(floatingIP.getId());
        break;
      }
    }
  }
  public void testWhenNamespaceNotInExtensionsListFloatingIpNotPresent() throws Exception {

    NovaApi apiWhenExtensionNotInList =
        requestsSendResponses(
            keystoneAuthWithUsernameAndPasswordAndTenantName,
            responseWithKeystoneAccess,
            extensionsOfNovaRequest,
            unmatchedExtensionsOfNovaResponse);

    assertEquals(
        apiWhenExtensionNotInList.getConfiguredZones(),
        ImmutableSet.of("az-1.region-a.geo-1", "az-2.region-a.geo-1", "az-3.region-a.geo-1"));

    assertFalse(
        apiWhenExtensionNotInList.getFloatingIPExtensionForZone("az-1.region-a.geo-1").isPresent());
  }
  /** Delete the public key in the cloud and the local private key. */
  private void deleteKeyPair(KeyPair keyPair) {
    System.out.format("  Delete Key Pair%n");

    KeyPairApi keyPairApi = novaApi.getKeyPairExtensionForZone(ZONE).get();
    keyPairApi.delete(keyPair.getName());

    if (keyPairFile.delete()) {
      System.out.format("    Deleted %s%n", keyPairFile.getAbsolutePath());
    } else {
      System.err.format("    Could not delete %s%n", keyPairFile.getAbsolutePath());
    }
  }
  /**
   * Create a public key in the cloud and write the private key file to the local working directory.
   */
  private KeyPair createKeyPair() throws IOException {
    System.out.format("  Create Key Pair%n");

    KeyPairApi keyPairApi = novaApi.getKeyPairExtensionForZone(ZONE).get();
    KeyPair keyPair = keyPairApi.create(NAME);

    Files.write(keyPair.getPrivateKey(), keyPairFile, UTF_8);

    System.out.format("    Wrote %s%n", keyPairFile.getAbsolutePath());

    return keyPair;
  }
  /**
   * Detect that the OpenStack Key Pair Extension is installed on the Rackspace Cloud.
   *
   * <p>This method is not necessary and is here for demonstration purposes only.
   */
  private void detectKeyPairExtension() {
    Optional<? extends KeyPairApi> keyPairApiExtension = novaApi.getKeyPairExtensionForZone(ZONE);

    if (keyPairApiExtension.isPresent()) {
      System.out.format("  Key Pair Extension Present%n");

      KeyPairApi keyPairApi = keyPairApiExtension.get();

      for (KeyPair keyPair : keyPairApi.list()) {
        System.out.format("    %s%n", keyPair.getName());
      }
    }
  }
  public void testListFloatingIPsWhenResponseIs2xx() throws Exception {
    HttpRequest list =
        HttpRequest.builder()
            .method("GET")
            .endpoint(
                "https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
            .addHeader("Accept", "application/json")
            .addHeader("X-Auth-Token", authToken)
            .build();

    HttpResponse listResponse =
        HttpResponse.builder()
            .statusCode(200)
            .payload(payloadFromResource("/floatingip_list.json"))
            .build();

    NovaApi apiWhenFloatingIPsExist =
        requestsSendResponses(
            keystoneAuthWithUsernameAndPasswordAndTenantName,
            responseWithKeystoneAccess,
            extensionsOfNovaRequest,
            extensionsOfNovaResponse,
            list,
            listResponse);

    assertEquals(
        apiWhenFloatingIPsExist.getConfiguredZones(),
        ImmutableSet.of("az-1.region-a.geo-1", "az-2.region-a.geo-1", "az-3.region-a.geo-1"));

    assertEquals(
        apiWhenFloatingIPsExist
            .getFloatingIPExtensionForZone("az-1.region-a.geo-1")
            .get()
            .list()
            .toString(),
        new ParseFloatingIPListTest().expected().toString());
  }
  @Override
  public List<String> associateAddresses(NodeMetadata node) {

    ComputeServiceContext context = iaasProvider.getComputeService().getContext();
    String region = ComputeServiceBuilderUtil.extractRegion(iaasProvider);

    if (StringUtils.isEmpty(region)) {
      throw new RuntimeException(
          "Could not find region in iaas provider: " + iaasProvider.getName());
    }

    NovaApi novaApi = context.unwrapApi(NovaApi.class);
    FloatingIPApi floatingIPApi = novaApi.getFloatingIPExtensionForZone(region).get();

    String ip = null;
    // first try to find an unassigned IP.
    FluentIterable<FloatingIP> floatingIPs = floatingIPApi.list();
    ArrayList<FloatingIP> unassignedIps =
        Lists.newArrayList(
            Iterables.filter(
                floatingIPs,
                new Predicate<FloatingIP>() {
                  @Override
                  public boolean apply(FloatingIP floatingIP) {
                    return floatingIP.getInstanceId() == null;
                  }
                }));

    if (!unassignedIps.isEmpty()) {
      // try to prevent multiple parallel launches from choosing the same ip.
      Collections.shuffle(unassignedIps);
      ip = Iterables.getLast(unassignedIps).getIp();
    }

    // if no unassigned IP is available, we'll try to allocate an IP.
    if (StringUtils.isEmpty(ip)) {
      String floatingIpPool =
          iaasProvider.getProperty(CloudControllerConstants.DEFAULT_FLOATING_IP_POOL);
      FloatingIP allocatedFloatingIP;
      if (StringUtils.isEmpty(floatingIpPool)) {
        allocatedFloatingIP = floatingIPApi.create();
      } else {
        log.debug(
            String.format(
                "Trying to allocate a floating IP address from IP pool %s", floatingIpPool));
        allocatedFloatingIP = floatingIPApi.allocateFromPool(floatingIpPool);
      }
      if (allocatedFloatingIP == null) {
        String msg =
            String.format(
                "Floating IP API did not return a floating IP address from IP pool %s",
                floatingIpPool);
        log.error(msg);
        throw new CloudControllerException(msg);
      }
      ip = allocatedFloatingIP.getIp();
    }

    // wait till the fixed IP address gets assigned - this is needed before
    // we associate a public IP
    log.info(
        String.format(
            "Waiting for private IP addresses get allocated: [node-id] %s", node.getId()));
    while (node.getPrivateAddresses() == null) {
      CloudControllerUtil.sleep(1000);
    }
    log.info(String.format("Private IP addresses allocated: %s", node.getPrivateAddresses()));

    if ((node.getPublicAddresses() != null) && (node.getPublicAddresses().iterator().hasNext())) {
      log.info(
          "Public IP address "
              + node.getPublicAddresses().iterator().next()
              + " is already allocated to the instance: [node-id]  "
              + node.getId());
      return null;
    }

    int retries = 0;
    int retryCount = Integer.getInteger("stratos.public.ip.association.retry.count", 5);
    while ((retries < retryCount) && (!associateIp(floatingIPApi, ip, node.getProviderId()))) {
      // wait for 5s
      CloudControllerUtil.sleep(5000);
      retries++;
    }

    log.info(
        String.format(
            "Successfully associated an IP address: [node-id] %s [ip] %s", node.getId(), ip));

    List<String> allocatedIPAddresses = new ArrayList<String>();
    allocatedIPAddresses.add(ip);
    return allocatedIPAddresses;
  }