diff --git a/bubble-server/src/main/java/bubble/cloud/NoopCloud.java b/bubble-server/src/main/java/bubble/cloud/NoopCloud.java index 2c4a4b51..06a15837 100644 --- a/bubble-server/src/main/java/bubble/cloud/NoopCloud.java +++ b/bubble-server/src/main/java/bubble/cloud/NoopCloud.java @@ -70,7 +70,6 @@ public class NoopCloud implements } @Override public List getPackerImages() { return Collections.emptyList(); } - @Override public List writePackerImages() { return Collections.emptyList(); } @Override public boolean _write(String fromNode, String key, InputStream data, StorageMetadata metadata, String requestId) throws IOException { if (log.isDebugEnabled()) log.debug("_write(fromNode=" + fromNode + ")"); diff --git a/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java index c840fe19..e9ebf106 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java @@ -34,6 +34,5 @@ public interface ComputeServiceDriver extends CloudServiceDriver, RegionalServic @Override default boolean test () { return true; } List getPackerImages(); - List writePackerImages(); } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriverBase.java b/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriverBase.java index e9878be7..4512553c 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriverBase.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriverBase.java @@ -73,11 +73,14 @@ public abstract class ComputeServiceDriverBase private List initRegions() { final ArrayList cloudRegions = new ArrayList<>(); for (CloudRegion configRegion : config.getRegions()) { - final CloudRegion region = getCloudRegions().stream().filter(s -> s.getInternalName().equals(configRegion.getInternalName())).findFirst().orElse(null); - if (region == null) { + final CloudRegion cloudRegion = getCloudRegions().stream() + .filter(s -> s.getInternalName().equalsIgnoreCase(configRegion.getInternalName())) + .findFirst() + .orElse(null); + if (cloudRegion == null) { log.warn("initRegions: config region not found: "+configRegion.getInternalName()); } else { - cloudRegions.add(configRegion); + cloudRegions.add(configRegion.setId(cloudRegion.getId())); } } return cloudRegions; diff --git a/bubble-server/src/main/java/bubble/cloud/compute/delegate/DelegatedComputeDriver.java b/bubble-server/src/main/java/bubble/cloud/compute/delegate/DelegatedComputeDriver.java index 2eb75538..42620dcd 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/delegate/DelegatedComputeDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/delegate/DelegatedComputeDriver.java @@ -76,6 +76,5 @@ public class DelegatedComputeDriver extends DelegatedCloudServiceDriverBase impl } @Override public List getPackerImages() { return notSupported("getPackerImages"); } - @Override public List writePackerImages() { return notSupported("writePackerImages"); } } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanDriver.java b/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanDriver.java index f92b725f..675217bd 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanDriver.java @@ -262,8 +262,4 @@ public class DigitalOceanDriver extends ComputeServiceDriverBase { return images == null ? Collections.emptyList() : images; } - @Override public List writePackerImages() { - return null; - } - } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanPackerImageParser.java b/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanPackerImageParser.java index a224eedc..301c7dd8 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanPackerImageParser.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanPackerImageParser.java @@ -14,9 +14,7 @@ public class DigitalOceanPackerImageParser extends ListResourceParser getPackerImages() { return notSupported("getPackerImages"); } - @Override public List writePackerImages() { return notSupported("writePackerImages"); } } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/local/LocalComputeDriver.java b/bubble-server/src/main/java/bubble/cloud/compute/local/LocalComputeDriver.java index 6b7a025b..056010c6 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/local/LocalComputeDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/local/LocalComputeDriver.java @@ -28,6 +28,5 @@ public class LocalComputeDriver extends CloudServiceDriverBase im @Override public BubbleNode status(BubbleNode node) throws Exception { return notSupported("status"); } @Override public List getPackerImages() { return notSupported("getPackerImages"); } - @Override public List writePackerImages() { return notSupported("writePackerImages"); } } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/mock/MockComputeDriver.java b/bubble-server/src/main/java/bubble/cloud/compute/mock/MockComputeDriver.java index 22271244..706292cb 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/mock/MockComputeDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/mock/MockComputeDriver.java @@ -69,6 +69,5 @@ public class MockComputeDriver extends ComputeServiceDriverBase { } @Override public List getPackerImages() { return Collections.emptyList(); } - @Override public List writePackerImages() { return Collections.emptyList(); } } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrDriver.java b/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrDriver.java index 9c42e269..2d937a4b 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrDriver.java @@ -17,7 +17,10 @@ import org.cobbzilla.util.http.HttpResponseBean; import javax.persistence.EntityNotFoundException; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; import static bubble.model.cloud.BubbleNode.TAG_INSTANCE_ID; import static bubble.model.cloud.BubbleNode.TAG_SSH_KEY_ID; @@ -45,6 +48,7 @@ public class VultrDriver extends ComputeServiceDriverBase { public static final String REGIONS_URL = VULTR_API_BASE + "regions/list"; public static final String PLANS_URL = VULTR_API_BASE + "plans/list"; public static final String OS_URL = VULTR_API_BASE + "os/list"; + public static final String SNAPSHOT_URL = VULTR_API_BASE + "snapshot/list"; public static final String VULTR_SUBID = "SUBID"; public static final String VULTR_V4_IP = "main_ip"; @@ -66,9 +70,10 @@ public class VultrDriver extends ComputeServiceDriverBase { public static final long SERVER_STOP_TIMEOUT = SECONDS.toMillis(60); public static final long SERVER_STOP_CHECK_INTERVAL = SECONDS.toMillis(5); - private static List loadCloudResources(String uri, ResourceParser> parser) { + private List loadCloudResources(String uri, ResourceParser> parser) { try { - final HttpResponseBean response = getResponse(uri); + final HttpRequestBean request = auth(new HttpRequestBean(uri)); + final HttpResponseBean response = getResponse(request); final JsonNode node = json(response.getEntityString(), JsonNode.class); final List resources = parser.newResults(); for (Iterator fields = node.fieldNames(); fields.hasNext(); ) { @@ -368,8 +373,9 @@ public class VultrDriver extends ComputeServiceDriverBase { } } - // todo - @Override public List getPackerImages() { return notSupported("getPackerImages"); } - @Override public List writePackerImages() { return notSupported("writePackerImages"); } + @Override public List getPackerImages() { + final List images = loadCloudResources(SNAPSHOT_URL, new VultrPackerImageParser(configuration.getJarSha())); + return images == null ? Collections.emptyList() : images; + } } diff --git a/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrPackerImageParser.java b/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrPackerImageParser.java new file mode 100644 index 00000000..0938a89d --- /dev/null +++ b/bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrPackerImageParser.java @@ -0,0 +1,27 @@ +package bubble.cloud.compute.vultr; + +import bubble.cloud.compute.ListResourceParser; +import bubble.cloud.compute.PackerImage; +import com.fasterxml.jackson.databind.JsonNode; + +import static bubble.service.packer.PackerJob.PACKER_IMAGE_PREFIX; +import static org.cobbzilla.util.daemon.ZillaRuntime.die; + +public class VultrPackerImageParser extends ListResourceParser { + + private String jarSha; + + public VultrPackerImageParser(String jarSha) { this.jarSha = jarSha; } + + @Override public PackerImage parse(JsonNode item) { + if (!item.has("SNAPSHOTID")) return die("parse: SNAPSHOTID not found"); + if (!item.has("OSID")) return die("parse: OSID not found"); + if (!item.has("description")) return die("parse: description not found"); + final String name = item.get("description").textValue(); + if (!name.startsWith(PACKER_IMAGE_PREFIX)) return null; + if (!name.endsWith("_"+jarSha)) return null; + return new PackerImage() + .setName(name) + .setId(item.get("SNAPSHOTID").textValue()); + } +} diff --git a/bubble-server/src/main/java/bubble/service/packer/PackerBuild.java b/bubble-server/src/main/java/bubble/service/packer/PackerBuild.java index 85de8153..66ddfa40 100644 --- a/bubble-server/src/main/java/bubble/service/packer/PackerBuild.java +++ b/bubble-server/src/main/java/bubble/service/packer/PackerBuild.java @@ -7,6 +7,8 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import lombok.Getter; import lombok.Setter; +import java.util.Arrays; + public class PackerBuild { @Getter @Setter private String name; @@ -19,11 +21,11 @@ public class PackerBuild { public PackerImage toPackerImage(String name) { final String[] parts = artifact_id.split(":"); - final String regionName = parts[0]; + final CloudRegion[] regions = (CloudRegion[]) Arrays.stream(parts[0].split(",")).map(r -> new CloudRegion().setInternalName(r)).toArray(); final String id = parts[1]; return new PackerImage() .setId(id) .setName(name) - .setRegions(new CloudRegion[]{new CloudRegion().setInternalName(regionName)}); + .setRegions(regions); } } diff --git a/bubble-server/src/main/java/bubble/service/packer/PackerJob.java b/bubble-server/src/main/java/bubble/service/packer/PackerJob.java index 8c0187d6..b5c859a7 100644 --- a/bubble-server/src/main/java/bubble/service/packer/PackerJob.java +++ b/bubble-server/src/main/java/bubble/service/packer/PackerJob.java @@ -155,7 +155,7 @@ public class PackerJob implements Callable> { // run packer, return handle to running packer log.info("running packer for "+installType+"..."); final CommandResult commandResult = CommandShell.exec(new Command(new CommandLine("packer") - .addArgument("build").addArgument("packer.json")) + .addArgument("build").addArgument("-parallel-builds=2").addArgument("packer.json")) .setDir(tempDir) .setEnv(env) .setCopyToStandard(true)); diff --git a/bubble-server/src/main/resources/models/defaults/cloudService.json b/bubble-server/src/main/resources/models/defaults/cloudService.json index e901498b..616588bb 100644 --- a/bubble-server/src/main/resources/models/defaults/cloudService.json +++ b/bubble-server/src/main/resources/models/defaults/cloudService.json @@ -185,6 +185,10 @@ "name": "Vultr - Tokyo", "internalName": "Tokyo", "location": {"city": "Tokyo", "country": "JP", "region": "Kantō", "lat": "35.689722", "lon": "139.692222"} + }, { + "name": "Vultr - Seoul", + "internalName": "Seoul", + "location": {"city": "Seoul", "country": "KR", "region": "Sudogwon", "lat": "37.566667", "lon": "126.966667"} }, { "name": "Vultr - Sydney", "internalName": "Sydney", @@ -202,13 +206,12 @@ "os": "Ubuntu 18.04 x64", "packer": { "vars": [{"name": "VULTR_API_KEY", "value": "[[credentials.apiKey]]"}], - "iterateRegions": true, "builder": { "type": "vultr", "ssh_username": "root", "api_key": "[[user `VULTR_API_KEY`]]", "os_id": "<>", - "region_id": "<>", + "region_id": "<>", "plan_id": "<>", "instance_label": "<>", "snapshot_description": "<>",