in profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/ProfitBricksComputeServiceAdapter.java [152:372]
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 pubKey = options.getPublicKey();
final String password = options.hasLoginPassword() ? options.getLoginPassword() : passwordGenerator.generate();
final org.jclouds.compute.domain.Image image = template.getImage();
final int[] inboundPorts = template.getOptions().getInboundPorts();
// 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) {
if (pubKey != null) {
request.sshKeys(new HashSet<String>(Arrays.asList(pubKey)));
} else {
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(inboundPorts.length > 0)
.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()));
Map<Integer, Integer> portsRange = getPortRangesFromList(inboundPorts);
for (Map.Entry<Integer, Integer> range : portsRange.entrySet()) {
FirewallRule rule = api.firewallApi().create(
FirewallRule.Request.creatingBuilder()
.dataCenterId(dataCenterId)
.serverId(server.id())
.nicId(nic.id())
.name(server.properties().name() + " jclouds-firewall")
.protocol(FirewallRule.Protocol.TCP)
.portRangeStart(range.getKey())
.portRangeEnd(range.getValue())
.build()
);
trackables.waitUntilRequestCompleted(rule);
}
//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)
.privateKey(pubKey)
.password(password)
.build();
String serverInDataCenterId = DataCenterAndId.fromDataCenterAndId(dataCenterId, server.id()).slashEncode();
ServerInDataCenter serverInDatacenter = getNode(serverInDataCenterId);
return new NodeAndInitialCredentials<ServerInDataCenter>(serverInDatacenter, serverInDataCenterId, serverCredentials);
}