@Override
  public Iterable<ServerInDataCenter> listNodes() {
    logger.trace("<< fetching servers..");
    datacetners = api.dataCenterApi().list();
    List<ServerInDataCenter> servers = new ArrayList<ServerInDataCenter>();
    for (DataCenter dataCenter : datacetners) {

      List<Server> serversInDataCenter =
          api.serverApi().getList(dataCenter.id(), new DepthOptions().depth(4));
      for (Server server : serversInDataCenter) {
        servers.add(new ServerInDataCenter(server, dataCenter.id()));
      }
    }
    logger.trace("<< fetching servers..");
    return servers;
  }
 @Override
 public boolean apply(NicRef input) {
   checkNotNull(input, "NicRef ");
   Nic nice = api.nicApi().get(input.dataCenterId(), input.serverId(), input.nicId());
   if (nice == null || nice.metadata() == null || nice.metadata().state() == null) {
     return false;
   }
   return nice.metadata().state().toString().equals(expectedState.toString());
 }
 @Override
 public Provisionable getImage(String id) {
   // try search images
   logger.trace("<< searching for image with id=%s", id);
   Image image = api.imageApi().getImage(id);
   if (image != null) {
     logger.trace(">> found image [%s].", image.properties().name());
     return image;
   }
   // try search snapshots
   logger.trace("<< not found from images. searching for snapshot with id=%s", id);
   Snapshot snapshot = api.snapshotApi().get(id);
   if (snapshot != null) {
     logger.trace(">> found snapshot [%s]", snapshot.properties().name());
     return snapshot;
   }
   throw new ResourceNotFoundException("No image/snapshot with id '" + id + "' was found");
 }
 @Override
 public boolean apply(VolumeRef input) {
   checkNotNull(input, "Volume REF");
   org.apache.jclouds.profitbricks.rest.domain.Volume volume =
       api.volumeApi().getVolume(input.dataCenterId(), input.volumeId());
   if (volume == null || volume.metadata() == null || volume.metadata().state() == null) {
     return false;
   }
   return volume.metadata().state().toString().equals(expectedState.toString());
 }
 @Override
 public boolean apply(String input) {
   checkNotNull(input, "snapshot id");
   return api.snapshotApi()
       .get(input)
       .metadata()
       .state()
       .toString()
       .equals(expectedState.toString());
 }
    @Override
    public boolean apply(ServerRef serverRef) {
      checkNotNull(serverRef, "serverRef");
      // give time for the operation to actually start
      Uninterruptibles.sleepUninterruptibly(10, TimeUnit.SECONDS);
      Server server = api.serverApi().getServer(serverRef.dataCenterId(), serverRef.serverId());

      if (server == null || server.properties().vmState() == null) {
        return false;
      }

      return server.properties().vmState() == expectedStatus;
    }
  @Override
  public ServerInDataCenter getNode(String id) {
    DataCenterAndId datacenterAndId = DataCenterAndId.fromSlashEncoded(id);
    logger.trace("<< searching for server with id=%s", id);

    Server server =
        api.serverApi()
            .getServer(
                datacenterAndId.getDataCenter(),
                datacenterAndId.getId(),
                new DepthOptions().depth(3));
    if (server != null) {
      logger.trace(">> found server [%s]", server.properties().name());
    }
    return server == null ? null : new ServerInDataCenter(server, datacenterAndId.getDataCenter());
  }
  @Override
  public void destroyNode(String nodeId) {
    DataCenterAndId datacenterAndId = DataCenterAndId.fromSlashEncoded(nodeId);
    ServerApi serverApi = api.serverApi();
    Server server =
        serverApi.getServer(
            datacenterAndId.getDataCenter(), datacenterAndId.getId(), new DepthOptions().depth(5));
    if (server != null) {
      for (org.apache.jclouds.profitbricks.rest.domain.Volume volume :
          server.entities().volumes().items()) {
        destroyVolume(volume.id(), datacenterAndId.getDataCenter());
      }

      try {
        destroyServer(datacenterAndId.getId(), datacenterAndId.getDataCenter());
      } catch (Exception ex) {
        logger.warn(ex, ">> failed to delete server with id=%s", datacenterAndId.getId());
      }
    }
  }
 @Override
 public boolean apply(String input) {
   checkNotNull(input, "datacenter id");
   DataCenter dataCenter = api.dataCenterApi().getDataCenter(input);
   return dataCenter.metadata().state() == expectedState;
 }
 @AfterMethod(alwaysRun = true)
 public void stop() throws IOException {
   server.shutdown();
   api.close();
 }
  protected NodeAndInitialCredentials<ServerInDataCenter> createNodeWithGroupEncodedIntoName(
      String group, String name, TemplateWithDataCenter template) {
    checkArgument(
        template.getLocation().getScope() == LocationScope.ZONE,
        "Template must use a ZONE-scoped location");
    final String dataCenterId = template.getDataCenter().id();
    Hardware hardware = template.getHardware();
    TemplateOptions options = template.getOptions();
    final String loginUser =
        isNullOrEmpty(options.getLoginUser()) ? "root" : options.getLoginUser();
    final String password =
        options.hasLoginPassword() ? options.getLoginPassword() : Passwords.generate();
    final org.jclouds.compute.domain.Image image = template.getImage();

    // provision all volumes based on hardware
    List<? extends Volume> volumes = hardware.getVolumes();
    List<String> volumeIds = Lists.newArrayListWithExpectedSize(volumes.size());

    int i = 1;
    for (final Volume volume : volumes) {
      try {
        logger.trace("<< provisioning volume '%s'", volume);
        final org.apache.jclouds.profitbricks.rest.domain.Volume.Request.CreatePayload.Builder
            request = org.apache.jclouds.profitbricks.rest.domain.Volume.Request.creatingBuilder();
        if (i == 1) {
          request.image(image.getId());
          // we don't need to pass password to the API if we're using a snapshot
          Provisionable.Type provisionableType =
              Provisionable.Type.fromValue(
                  image.getUserMetadata().get(ProvisionableToImage.KEY_PROVISIONABLE_TYPE));
          if (provisionableType == Provisionable.Type.IMAGE) {
            request.imagePassword(password);
          }
        }
        request
            .dataCenterId(dataCenterId)
            .name(format("%s-disk-%d", name, i++))
            .size(volume.getSize().intValue())
            .type(VolumeType.HDD);

        org.apache.jclouds.profitbricks.rest.domain.Volume vol =
            (org.apache.jclouds.profitbricks.rest.domain.Volume)
                provisioningManager.provision(
                    jobFactory.create(
                        dataCenterId,
                        new Supplier<Object>() {
                          @Override
                          public Object get() {
                            return api.volumeApi().createVolume(request.build());
                          }
                        }));

        volumeIds.add(vol.id());
        logger.trace(">> provisioning complete for volume. returned id='%s'", vol.id());
      } catch (Exception ex) {
        if (i - 1 == 1) // if first volume (one with image) provisioning fails; stop method
        {
          throw Throwables.propagate(ex);
        }
        logger.warn(ex, ">> failed to provision volume. skipping..");
      }
    }

    String volumeBootDeviceId = Iterables.get(volumeIds, 0); // must have atleast 1
    waitVolumeUntilAvailable.apply(VolumeRef.create(dataCenterId, volumeBootDeviceId));

    // provision server
    final Server server;
    Double cores = ComputeServiceUtils.getCores(hardware);

    Server.BootVolume bootVolume = Server.BootVolume.create(volumeBootDeviceId);

    try {
      final Server.Request.CreatePayload serverRequest =
          Server.Request.creatingBuilder()
              .dataCenterId(dataCenterId)
              .name(name)
              .bootVolume(bootVolume)
              .cores(cores.intValue())
              .ram(hardware.getRam())
              .build();

      logger.trace("<< provisioning server '%s'", serverRequest);

      server =
          (Server)
              provisioningManager.provision(
                  jobFactory.create(
                      dataCenterId,
                      new Supplier<Object>() {

                        @Override
                        public Object get() {
                          return api.serverApi().createServer(serverRequest);
                        }
                      }));
      logger.trace(">> provisioning complete for server. returned id='%s'", server.id());

    } catch (Exception ex) {
      logger.error(ex, ">> failed to provision server. rollbacking..");
      destroyVolumes(volumeIds, dataCenterId);
      throw Throwables.propagate(ex);
    }

    waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));
    waitDcUntilAvailable.apply(dataCenterId);

    // attach bootVolume to Server
    org.apache.jclouds.profitbricks.rest.domain.Volume volume =
        api.serverApi()
            .attachVolume(
                Server.Request.attachVolumeBuilder()
                    .dataCenterId(dataCenterId)
                    .serverId(server.id())
                    .volumeId(bootVolume.id())
                    .build());

    trackables.waitUntilRequestCompleted(volume);
    waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));
    waitDcUntilAvailable.apply(dataCenterId);

    // fetch an existing lan and creat if non was found
    Lan lan = null;

    List<Lan> lans = api.lanApi().list(dataCenterId);
    if (lans != null && !lans.isEmpty()) {
      lan =
          FluentIterable.from(lans)
              .firstMatch(
                  new Predicate<Lan>() {
                    @Override
                    public boolean apply(Lan input) {
                      input =
                          api.lanApi().get(dataCenterId, input.id(), new DepthOptions().depth(3));
                      return input.properties().isPublic();
                    }
                  })
              .orNull();
    }
    if (lan == null) {
      logger.warn("Could not find an existing lan Creating one....");
      lan =
          api.lanApi()
              .create(
                  Lan.Request.creatingBuilder()
                      .dataCenterId(dataCenterId)
                      .isPublic(Boolean.TRUE)
                      .name("lan " + name)
                      .build());
      trackables.waitUntilRequestCompleted(lan);
    }

    // add a NIC to the server
    int lanId = DEFAULT_LAN_ID;
    if (options.getNetworks() != null) {
      try {
        String networkId = Iterables.get(options.getNetworks(), 0);
        lanId = Integer.valueOf(networkId);
      } catch (Exception ex) {
        logger.warn(
            "no valid network id found from options. using default id='%d'", DEFAULT_LAN_ID);
      }
    }

    Nic nic =
        api.nicApi()
            .create(
                Nic.Request.creatingBuilder()
                    .dataCenterId(dataCenterId)
                    .name("jclouds" + name)
                    .dhcp(Boolean.TRUE)
                    .lan(lanId)
                    .firewallActive(Boolean.FALSE)
                    .serverId(server.id())
                    .build());

    trackables.waitUntilRequestCompleted(nic);
    waitNICUntilAvailable.apply(NicRef.create(dataCenterId, server.id(), nic.id()));
    waitDcUntilAvailable.apply(dataCenterId);
    waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));

    // connect the rest of volumes to server;delete if fails
    final int volumeCount = volumeIds.size();
    for (int j = 1; j < volumeCount; j++) { // skip first; already connected
      final String volumeId = volumeIds.get(j);
      try {
        logger.trace("<< connecting volume '%s' to server '%s'", volumeId, server.id());
        provisioningManager.provision(
            jobFactory.create(
                group,
                new Supplier<Object>() {

                  @Override
                  public Object get() {
                    return api.serverApi()
                        .attachVolume(
                            Server.Request.attachVolumeBuilder()
                                .dataCenterId(dataCenterId)
                                .serverId(server.id())
                                .volumeId(volumeId)
                                .build());
                  }
                }));

        logger.trace(">> volume connected.");
      } catch (Exception ex) {
        try {
          // delete unconnected volume
          logger.warn(ex, ">> failed to connect volume '%s'. deleting..", volumeId);
          destroyVolume(volumeId, dataCenterId);
          logger.warn(ex, ">> rolling back server..", server.id());
          destroyServer(server.id(), dataCenterId);
          throw ex;
        } catch (Exception ex1) {
          logger.error(ex, ">> failed to rollback");
        }
      }
    }
    waitDcUntilAvailable.apply(dataCenterId);
    waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));

    LoginCredentials serverCredentials =
        LoginCredentials.builder().user(loginUser).password(password).build();

    String serverInDataCenterId =
        DataCenterAndId.fromDataCenterAndId(dataCenterId, server.id()).slashEncode();
    ServerInDataCenter serverInDatacenter = getNode(serverInDataCenterId);

    return new NodeAndInitialCredentials<ServerInDataCenter>(
        serverInDatacenter, serverInDataCenterId, serverCredentials);
  }