Bläddra i källkod

WIP: packer image creation working for digitalocean

cobbzilla/introduce_packer
Jonathan Cobb 4 år sedan
förälder
incheckning
07fcafa516
29 ändrade filer med 350 tillägg och 100 borttagningar
  1. +1
    -0
      bubble-server/src/main/java/bubble/cloud/CloudRegion.java
  2. +6
    -4
      bubble-server/src/main/java/bubble/cloud/NoopCloud.java
  3. +2
    -1
      bubble-server/src/main/java/bubble/cloud/compute/ComputeConfig.java
  4. +5
    -0
      bubble-server/src/main/java/bubble/cloud/compute/ComputeNodeSize.java
  5. +8
    -0
      bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java
  6. +45
    -3
      bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriverBase.java
  7. +12
    -0
      bubble-server/src/main/java/bubble/cloud/compute/ListResourceParser.java
  8. +12
    -0
      bubble-server/src/main/java/bubble/cloud/compute/OsImage.java
  9. +6
    -0
      bubble-server/src/main/java/bubble/cloud/compute/PackerConfig.java
  10. +1
    -1
      bubble-server/src/main/java/bubble/cloud/compute/ResourceParser.java
  11. +6
    -4
      bubble-server/src/main/java/bubble/cloud/compute/delegate/DelegatedComputeDriver.java
  12. +25
    -0
      bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanComputeNodeSizeParser.java
  13. +13
    -22
      bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanDriver.java
  14. +31
    -0
      bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanOsImageParser.java
  15. +8
    -2
      bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanPackerImageParser.java
  16. +19
    -0
      bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanRegionParser.java
  17. +0
    -24
      bubble-server/src/main/java/bubble/cloud/compute/digitalocean/ResourceSlugParser.java
  18. +17
    -0
      bubble-server/src/main/java/bubble/cloud/compute/ec2/AmazonEC2Driver.java
  19. +1
    -0
      bubble-server/src/main/java/bubble/cloud/compute/local/LocalComputeDriver.java
  20. +5
    -6
      bubble-server/src/main/java/bubble/cloud/compute/mock/MockComputeDriver.java
  21. +26
    -0
      bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrComputeNodeSizeParser.java
  22. +18
    -19
      bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrDriver.java
  23. +19
    -0
      bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrOsImageParser.java
  24. +19
    -0
      bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrRegionParser.java
  25. +2
    -0
      bubble-server/src/main/java/bubble/model/cloud/notify/NotificationType.java
  26. +15
    -0
      bubble-server/src/main/java/bubble/notify/compute/NotificationHandler_compute_driver_get_os.java
  27. +14
    -2
      bubble-server/src/main/java/bubble/service/packer/PackerJob.java
  28. +11
    -10
      bubble-server/src/main/resources/models/defaults/cloudService.json
  29. +3
    -2
      bubble-server/src/main/resources/packer/packer-sage.json.hbs

+ 1
- 0
bubble-server/src/main/java/bubble/cloud/CloudRegion.java Visa fil

@@ -20,6 +20,7 @@ public class CloudRegion {

@Getter @Setter private String cloud;

@Getter @Setter private Long id;
@Getter @Setter private String name;
@Setter private String internalName;
public String getInternalName () { return internalName != null ? internalName : name; }


+ 6
- 4
bubble-server/src/main/java/bubble/cloud/NoopCloud.java Visa fil

@@ -6,10 +6,7 @@ package bubble.cloud;

import bubble.cloud.auth.AuthenticationDriver;
import bubble.cloud.auth.RenderedMessage;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeNodeSizeType;
import bubble.cloud.compute.ComputeServiceDriver;
import bubble.cloud.compute.PackerImage;
import bubble.cloud.compute.*;
import bubble.cloud.dns.DnsServiceDriver;
import bubble.cloud.email.EmailServiceDriver;
import bubble.cloud.email.RenderedEmail;
@@ -41,6 +38,7 @@ import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Slf4j
public class NoopCloud implements
@@ -254,6 +252,10 @@ public class NoopCloud implements
return null;
}

@Override public OsImage getOs() { return null; }

@Override public Map<String, ComputeNodeSize> getSizesMap() { return null; }

@Override public List<CloudRegion> getRegions() {
if (log.isDebugEnabled()) log.debug("getRegions()");
return null;


+ 2
- 1
bubble-server/src/main/java/bubble/cloud/compute/ComputeConfig.java Visa fil

@@ -13,8 +13,9 @@ import org.cobbzilla.util.collection.NameAndValue;
public class ComputeConfig extends RegionalConfig {

@Getter @Setter private ComputeNodeSize[] sizes;
@Getter @Setter private NameAndValue[] config;
@Getter @Setter private String os;
@Getter @Setter private PackerConfig packer;
@Getter @Setter private NameAndValue[] config;

public CloudRegion getRegion (String name) {
for (CloudRegion r : getRegions()) {


+ 5
- 0
bubble-server/src/main/java/bubble/cloud/compute/ComputeNodeSize.java Visa fil

@@ -4,6 +4,7 @@
*/
package bubble.cloud.compute;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
@@ -12,6 +13,9 @@ import lombok.experimental.Accessors;
public class ComputeNodeSize {

@Getter @Setter private ComputeNodeSizeType type;
@JsonIgnore public String getTypeName() { return type.name(); }

@Getter @Setter private Long id;
@Getter @Setter private String name;
@Setter private String internalName;
public String getInternalName () { return internalName != null ? internalName : name; }
@@ -22,6 +26,7 @@ public class ComputeNodeSize {
@Getter @Setter private int ssdGB;
@Getter @Setter private int hddGB;
@Getter @Setter private Integer networkMbps;
@Getter @Setter private Integer transferGB;

@Setter private Integer costUnits;
public Integer getCostUnits () { return costUnits != null ? costUnits : type != null ? type.getCostUnits() : null; }


+ 8
- 0
bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java Visa fil

@@ -10,6 +10,9 @@ import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.RegionalServiceDriver;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public interface ComputeServiceDriver extends CloudServiceDriver, RegionalServiceDriver {

@@ -17,6 +20,11 @@ public interface ComputeServiceDriver extends CloudServiceDriver, RegionalServic

List<ComputeNodeSize> getSizes();
ComputeNodeSize getSize(ComputeNodeSizeType type);
OsImage getOs();

default Map<String, ComputeNodeSize> getSizesMap () {
return getSizes().stream().collect(Collectors.toMap(ComputeNodeSize::getTypeName, Function.identity()));
}

BubbleNode start(BubbleNode node) throws Exception;
BubbleNode cleanupStart(BubbleNode node) throws Exception;


+ 45
- 3
bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriverBase.java Visa fil

@@ -8,13 +8,14 @@ import bubble.cloud.CloudRegion;
import bubble.cloud.CloudServiceDriverBase;
import bubble.dao.cloud.BubbleNodeDAO;
import bubble.model.cloud.BubbleNode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.http.HttpRequestBean;
import org.cobbzilla.util.http.HttpResponseBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@@ -64,8 +65,49 @@ public abstract class ComputeServiceDriverBase

public abstract List<BubbleNode> listNodes() throws IOException;

@Override public List<CloudRegion> getRegions() { return Arrays.asList(config.getRegions()); }
@Override public List<ComputeNodeSize> getSizes() { return Arrays.asList(config.getSizes()); }
protected abstract List<CloudRegion> getCloudRegions();
protected abstract List<ComputeNodeSize> getCloudSizes();
protected abstract List<OsImage> getCloudOsImages();

@Getter(lazy=true) private final List<CloudRegion> regions = initRegions();
private List<CloudRegion> initRegions() {
final ArrayList<CloudRegion> 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) {
log.warn("initRegions: config region not found: "+configRegion.getInternalName());
} else {
cloudRegions.add(configRegion);
}
}
return cloudRegions;
}

@Getter(lazy=true) private final List<ComputeNodeSize> sizes = initSizes();
private List<ComputeNodeSize> initSizes() {
final ArrayList<ComputeNodeSize> cloudSizes = new ArrayList<>();
for (ComputeNodeSize configSize : config.getSizes()) {
final ComputeNodeSize cloudSize = getCloudSizes().stream().filter(sz -> sz.getInternalName().equals(configSize.getInternalName())).findFirst().orElse(null);
if (cloudSize == null) {
log.warn("initSizes: config region not found: "+configSize.getInternalName());
} else {
cloudSizes.add(cloudSize
.setName(configSize.getName())
.setType(configSize.getType()));
}
}
return cloudSizes;
}

@Getter(lazy=true) private final OsImage os = initOs();
private OsImage initOs() {
final OsImage os = getCloudOsImages().stream()
.filter(s -> s.getName().equals(config.getOs()))
.findFirst()
.orElse(null);
if (os == null) return die("initOs: os not found: "+config.getOs());
return os;
}

@Override public CloudRegion getRegion(String region) {
return getRegions().stream()


+ 12
- 0
bubble-server/src/main/java/bubble/cloud/compute/ListResourceParser.java Visa fil

@@ -0,0 +1,12 @@
package bubble.cloud.compute;

import bubble.cloud.compute.ResourceParser;

import java.util.ArrayList;
import java.util.List;

public abstract class ListResourceParser<E> implements ResourceParser<E, List<E>> {

@Override public List<E> newResults() { return new ArrayList<>(); }

}

+ 12
- 0
bubble-server/src/main/java/bubble/cloud/compute/OsImage.java Visa fil

@@ -0,0 +1,12 @@
package bubble.cloud.compute;

import lombok.*;
import lombok.experimental.Accessors;

@NoArgsConstructor @Accessors(chain=true)
public class OsImage {

@Getter @Setter private Long id;
@Getter @Setter private String name;

}

+ 6
- 0
bubble-server/src/main/java/bubble/cloud/compute/PackerConfig.java Visa fil

@@ -5,9 +5,15 @@ import lombok.Getter;
import lombok.Setter;
import org.cobbzilla.util.collection.NameAndValue;

import static org.cobbzilla.util.daemon.ZillaRuntime.bool;

public class PackerConfig {

@Getter @Setter private NameAndValue[] vars;

@Getter @Setter private Boolean iterateRegions;
public boolean iterateRegions() { return bool(iterateRegions); }

@Getter @Setter private JsonNode builder;

}

bubble-server/src/main/java/bubble/cloud/compute/digitalocean/ResourceParser.java → bubble-server/src/main/java/bubble/cloud/compute/ResourceParser.java Visa fil

@@ -1,4 +1,4 @@
package bubble.cloud.compute.digitalocean;
package bubble.cloud.compute;

import com.fasterxml.jackson.databind.JsonNode;


+ 6
- 4
bubble-server/src/main/java/bubble/cloud/compute/delegate/DelegatedComputeDriver.java Visa fil

@@ -6,10 +6,7 @@ package bubble.cloud.compute.delegate;

import bubble.cloud.CloudRegion;
import bubble.cloud.DelegatedCloudServiceDriverBase;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeNodeSizeType;
import bubble.cloud.compute.ComputeServiceDriver;
import bubble.cloud.compute.PackerImage;
import bubble.cloud.compute.*;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.CloudService;
import bubble.notify.compute.ComputeDriverNotification;
@@ -53,6 +50,11 @@ public class DelegatedComputeDriver extends DelegatedCloudServiceDriverBase impl
.orElse(null);
}

@Override public OsImage getOs() {
final BubbleNode delegate = getDelegateNode();
return notificationService.notifySync(delegate, compute_driver_get_os, notification());
}

@Override public BubbleNode start(BubbleNode node) throws Exception {
final BubbleNode delegate = getDelegateNode();
return notificationService.notifySync(delegate, compute_driver_start, notification(node));


+ 25
- 0
bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanComputeNodeSizeParser.java Visa fil

@@ -0,0 +1,25 @@
package bubble.cloud.compute.digitalocean;

import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ListResourceParser;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class DigitalOceanComputeNodeSizeParser extends ListResourceParser<ComputeNodeSize> {

@Override public ComputeNodeSize parse(JsonNode item) {
if (!item.has("slug")) return die("parse: slug not found");
if (!item.has("vcpus")) return die("parse: vcpus not found");
if (!item.has("memory")) return die("parse: memory not found");
if (!item.has("disk")) return die("parse: disk not found");
if (!item.has("transfer")) return die("parse: transfer not found");
return new ComputeNodeSize()
.setInternalName(item.get("slug").textValue())
.setVcpu(item.get("vcpus").intValue())
.setMemoryMB(item.get("memory").intValue())
.setSsdGB(item.get("disk").intValue())
.setTransferGB(1024 * item.get("transfer").intValue());
}

}

+ 13
- 22
bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanDriver.java Visa fil

@@ -5,9 +5,7 @@
package bubble.cloud.compute.digitalocean;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeServiceDriverBase;
import bubble.cloud.compute.PackerImage;
import bubble.cloud.compute.*;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.BubbleNodeState;
import com.fasterxml.jackson.databind.JsonNode;
@@ -47,11 +45,9 @@ public class DigitalOceanDriver extends ComputeServiceDriverBase {
public static final String TAG_PREFIX_NODE = "node_";
public static final String PACKER_IMAGES_URI = "images?private=true";

@Getter(lazy=true) private final Set<String> regionSlugs = getResourceSlugs("regions");
@Getter(lazy=true) private final Set<String> sizeSlugs = getResourceSlugs("sizes");
@Getter(lazy=true) private final Set<String> imageSlugs = getResourceSlugs("images?type=distribution");

private Set<String> getResourceSlugs(String uri) { return getResources(uri, new ResourceSlugParser(uri)); }
@Getter(lazy=true) private final List<CloudRegion> cloudRegions = getResources("regions", new DigitalOceanRegionParser());
@Getter(lazy=true) private final List<ComputeNodeSize> cloudSizes = getResources("sizes", new DigitalOceanComputeNodeSizeParser());
@Getter(lazy=true) private final List<OsImage> cloudOsImages = getResources("images?type=distribution", new DigitalOceanOsImageParser());

private <E, C extends Collection<E>> C getResources(String uri, ResourceParser<E, C> parser) {
final int qPos = uri.indexOf('?');
@@ -175,21 +171,16 @@ public class DigitalOceanDriver extends ComputeServiceDriverBase {

@Override public BubbleNode start(BubbleNode node) throws Exception {

final CloudRegion region = config.getRegion(node.getRegion());
final ComputeNodeSize size = config.getSize(node.getSize());
// todo: lookup image based on node installType
final String os = config.getConfig("os");
final CloudRegion region = getRegions().stream()
.filter(r -> r.getInternalName().equals(node.getRegion()))
.findFirst()
.orElse(null);
if (region == null) return die("start: region not found: " + node.getRegion());

if (!getRegionSlugs().contains(region.getInternalName())) {
return die("start: region not found: " + region.getInternalName());
}
if (!getSizeSlugs().contains(size.getInternalName())) {
return die("start: region not found: " + region.getInternalName());
}
if (!getImageSlugs().contains(os)) {
return die("start: region not found: " + region.getInternalName());
}
final ComputeNodeSize size = config.getSize(node.getSize());

// todo: lookup image based on node installType and region
final String os = getOs().getName();
final String sshKeyId = registerSshKey(node);

final CreateDropletRequest createRequest = new CreateDropletRequest()
@@ -267,7 +258,7 @@ public class DigitalOceanDriver extends ComputeServiceDriverBase {
}

@Override public List<PackerImage> getPackerImages() {
final List<PackerImage> images = getResources(PACKER_IMAGES_URI, new ImageParser());
final List<PackerImage> images = getResources(PACKER_IMAGES_URI, new DigitalOceanPackerImageParser(configuration.getJarSha()));
return images == null ? Collections.emptyList() : images;
}



+ 31
- 0
bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanOsImageParser.java Visa fil

@@ -0,0 +1,31 @@
package bubble.cloud.compute.digitalocean;

import bubble.cloud.compute.ListResourceParser;
import bubble.cloud.compute.OsImage;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class DigitalOceanOsImageParser extends ListResourceParser<OsImage> {

@Override public OsImage parse(JsonNode item) {
final OsImage image = new OsImage();
if (item.has("id")) {
final JsonNode id = item.get("id");
if (id.isNumber()) {
image.setId(id.numberValue().longValue());
} else {
return die("parse: id was not numeric");
}
} else {
return die("parse: id not found");
}
if (item.has("name")) {
final JsonNode name = item.get("slug");
image.setName(name.textValue());
} else {
return die("parse: name not found");
}
return image;
}
}

bubble-server/src/main/java/bubble/cloud/compute/digitalocean/ImageParser.java → bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanPackerImageParser.java Visa fil

@@ -1,6 +1,7 @@
package bubble.cloud.compute.digitalocean;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ListResourceParser;
import bubble.cloud.compute.PackerImage;
import com.fasterxml.jackson.databind.JsonNode;

@@ -9,9 +10,13 @@ import java.util.List;

import static bubble.service.packer.PackerJob.PACKER_IMAGE_PREFIX;

public class ImageParser implements ResourceParser<PackerImage, List<PackerImage>> {
public class DigitalOceanPackerImageParser extends ListResourceParser<PackerImage> {

@Override public List<PackerImage> newResults() { return new ArrayList<>(); }
private String jarSha;

public DigitalOceanPackerImageParser (String jarSha) {
this.jarSha = jarSha;
}

@Override public boolean allowEmpty() { return true; }

@@ -23,6 +28,7 @@ public class ImageParser implements ResourceParser<PackerImage, List<PackerImage
if (item.has("name")) {
name = item.get("name").textValue();
if (!name.startsWith(PACKER_IMAGE_PREFIX)) return null;
if (!name.endsWith("_"+jarSha)) return null;
image.setName(name);
}


+ 19
- 0
bubble-server/src/main/java/bubble/cloud/compute/digitalocean/DigitalOceanRegionParser.java Visa fil

@@ -0,0 +1,19 @@
package bubble.cloud.compute.digitalocean;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ListResourceParser;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class DigitalOceanRegionParser extends ListResourceParser<CloudRegion> {

@Override public CloudRegion parse(JsonNode item) {
if (!item.has("name")) return die("parse: name not found");
if (!item.has("slug")) return die("parse: slug not found");
return new CloudRegion()
.setName(item.get("name").textValue())
.setInternalName(item.get("slug").textValue());
}

}

+ 0
- 24
bubble-server/src/main/java/bubble/cloud/compute/digitalocean/ResourceSlugParser.java Visa fil

@@ -1,24 +0,0 @@
package bubble.cloud.compute.digitalocean;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;

import java.util.HashSet;
import java.util.Set;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.json.JsonUtil.json;

@AllArgsConstructor
class ResourceSlugParser implements ResourceParser<String, Set<String>> {

private final String uri;

@Override public Set<String> newResults() { return new HashSet<>(); }

@Override public String parse(JsonNode item) {
final JsonNode slug = item.get("slug");
if (slug == null) return die("getResourceSlugs("+ uri +"): no 'slug' found in item: "+json(item));
return slug.textValue();
}
}

+ 17
- 0
bubble-server/src/main/java/bubble/cloud/compute/ec2/AmazonEC2Driver.java Visa fil

@@ -4,8 +4,10 @@
*/
package bubble.cloud.compute.ec2;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeServiceDriverBase;
import bubble.cloud.compute.OsImage;
import bubble.cloud.compute.PackerImage;
import bubble.cloud.shared.aws.BubbleAwsCredentialsProvider;
import bubble.model.cloud.BubbleNode;
@@ -51,6 +53,21 @@ public class AmazonEC2Driver extends ComputeServiceDriverBase {
@Getter(lazy=true) private final AWSCredentialsProvider ec2credentials = new BubbleAwsCredentialsProvider(cloud, getCredentials());
@Getter(lazy=true) private final Map<String, AmazonEC2> ec2ClientMap = new HashMap<>();

@Override protected List<CloudRegion> getCloudRegions() {
// todo
return null;
}

@Override protected List<ComputeNodeSize> getCloudSizes() {
// todo
return null;
}

@Override protected List<OsImage> getCloudOsImages() {
// todo
return null;
}

private static final ExecutorService perRegionExecutor = fixedPool(8);

private AmazonEC2 getEC2Client(final String regionName) {


+ 1
- 0
bubble-server/src/main/java/bubble/cloud/compute/local/LocalComputeDriver.java Visa fil

@@ -17,6 +17,7 @@ public class LocalComputeDriver extends CloudServiceDriverBase<ComputeConfig> im

@Override public List<ComputeNodeSize> getSizes() { return notSupported("getSizes"); }
@Override public ComputeNodeSize getSize(ComputeNodeSizeType type) { return notSupported("getSize"); }
@Override public OsImage getOs() { return notSupported("getOs"); }

@Override public List<CloudRegion> getRegions() { return notSupported("getRegions"); }
@Override public CloudRegion getRegion(String region) { return notSupported("getRegion"); }


+ 5
- 6
bubble-server/src/main/java/bubble/cloud/compute/mock/MockComputeDriver.java Visa fil

@@ -5,10 +5,7 @@
package bubble.cloud.compute.mock;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeNodeSizeType;
import bubble.cloud.compute.ComputeServiceDriverBase;
import bubble.cloud.compute.PackerImage;
import bubble.cloud.compute.*;
import bubble.cloud.geoLocation.mock.MockGeoLocationDriver;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.BubbleNodeState;
@@ -27,15 +24,17 @@ public class MockComputeDriver extends ComputeServiceDriverBase {

private Map<String, BubbleNode> nodes = new ConcurrentHashMap<>();

@Getter private final List<CloudRegion> regions = singletonList(new CloudRegion()
@Getter private final List<CloudRegion> cloudRegions = singletonList(new CloudRegion()
.setDescription("New York City (mock)")
.setName("nyc_mock")
.setLocation(MockGeoLocationDriver.MOCK_LOCAION));

@Getter private final List<ComputeNodeSize> sizes = singletonList(new ComputeNodeSize()
@Getter private final List<ComputeNodeSize> cloudSizes = singletonList(new ComputeNodeSize()
.setName("standard")
.setType(ComputeNodeSizeType.small));

@Getter private final List<OsImage> cloudOsImages = singletonList(new OsImage().setName("dummy operating system"));

@Override protected String readSshKeyId(HttpResponseBean keyResponse) { return "dummy_ssh_key_id_"+now(); }

@Override public String registerSshKey(BubbleNode node) { return readSshKeyId(null); }


+ 26
- 0
bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrComputeNodeSizeParser.java Visa fil

@@ -0,0 +1,26 @@
package bubble.cloud.compute.vultr;

import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ListResourceParser;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class VultrComputeNodeSizeParser extends ListResourceParser<ComputeNodeSize> {

@Override public ComputeNodeSize parse(JsonNode item) {
if (!item.has("VPSPLANID")) return die("parse: VPSPLANID not found");
if (!item.has("name")) return die("parse: name not found");
if (!item.has("vcpu_count")) return die("parse: vcpu_count not found");
if (!item.has("ram")) return die("parse: ram not found");
if (!item.has("disk")) return die("parse: disk not found");
return new ComputeNodeSize()
.setId(item.get("VPSPLANID").asLong())
.setInternalName(item.get("name").textValue())
.setVcpu(item.get("vcpu_count").asInt())
.setMemoryMB(item.get("ram").asInt())
.setSsdGB(item.get("disk").asInt())
.setTransferGB(item.get("bandwidth_gb").asInt());
}

}

+ 18
- 19
bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrDriver.java Visa fil

@@ -5,9 +5,7 @@
package bubble.cloud.compute.vultr;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeServiceDriverBase;
import bubble.cloud.compute.PackerImage;
import bubble.cloud.compute.*;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.BubbleNodeState;
import com.fasterxml.jackson.databind.JsonNode;
@@ -59,28 +57,29 @@ public class VultrDriver extends ComputeServiceDriverBase {
public static final String LIST_SERVERS_URL = VULTR_API_BASE + "server/list";
public static final String POLL_SERVER_URL = LIST_SERVERS_URL + "?" + VULTR_SUBID + "=";

@Getter(lazy=true) private static final Map<String, Integer> regionMap = getResourceMap(REGIONS_URL);
@Getter(lazy=true) private static final Map<String, Integer> plansMap = getResourceMap(PLANS_URL);
@Getter(lazy=true) private static final Map<String, Integer> osMap = getResourceMap(OS_URL);
@Getter(lazy=true) private final List<CloudRegion> cloudRegions = loadCloudResources(REGIONS_URL, new VultrRegionParser());
@Getter(lazy=true) private final List<ComputeNodeSize> cloudSizes = loadCloudResources(PLANS_URL, new VultrComputeNodeSizeParser());
@Getter(lazy=true) private final List<OsImage> cloudOsImages = loadCloudResources(OS_URL, new VultrOsImageParser());

public static final long SERVER_START_POLL_INTERVAL = SECONDS.toMillis(5);
public static final long SERVER_START_TIMEOUT = MINUTES.toMillis(10);
public static final long SERVER_STOP_TIMEOUT = SECONDS.toMillis(60);
public static final long SERVER_STOP_CHECK_INTERVAL = SECONDS.toMillis(5);

private static Map<String, Integer> getResourceMap(String uri) {
private static <T> List<T> loadCloudResources(String uri, ResourceParser<T, List<T>> parser) {
try {
final HttpResponseBean response = getResponse(uri);
final JsonNode regionsNode = json(response.getEntityString(), JsonNode.class);
final Map<String, Integer> map = new HashMap<>();
for (Iterator<String> fields = regionsNode.fieldNames(); fields.hasNext(); ) {
final String regionId = fields.next();
final JsonNode region = regionsNode.get(regionId);
map.put(region.get("name").textValue(), Integer.parseInt(regionId));
final JsonNode node = json(response.getEntityString(), JsonNode.class);
final List<T> resources = parser.newResults();
for (Iterator<String> fields = node.fieldNames(); fields.hasNext(); ) {
final String id = fields.next();
final JsonNode item = node.get(id);
final T obj = parser.parse(item);
if (obj != null) resources.add(obj);
}
return map;
return resources;
} catch (Exception e) {
return die("getResourceMap("+uri+"): "+e, e);
return die("loadCloudResources("+uri+"): "+e, e);
}
}

@@ -97,14 +96,14 @@ public class VultrDriver extends ComputeServiceDriverBase {
final CloudRegion region = config.getRegion(node.getRegion());
final ComputeNodeSize size = config.getSize(node.getSize());

final Integer regionId = getRegionMap().get(region.getInternalName());
final Long regionId = getRegion(region.getInternalName()).getId();
if (regionId == null) return die("start: region not found: "+region.getInternalName());

final Integer planId = getPlansMap().get(size.getInternalName());
final Long planId = getSize(size.getType()).getId();
if (planId == null) return die("start: plan not found: "+size.getInternalName());

final Integer osId = getOsMap().get(config.getConfig("os"));
if (osId == null) return die("start: OS not found: "+config.getConfig("os"));
// todo: lookup osId based on installType and region
final Integer osId = getOs().getId().intValue();

// register ssh key, check response
final String sshKeyId = registerSshKey(node);


+ 19
- 0
bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrOsImageParser.java Visa fil

@@ -0,0 +1,19 @@
package bubble.cloud.compute.vultr;

import bubble.cloud.compute.ListResourceParser;
import bubble.cloud.compute.OsImage;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class VultrOsImageParser extends ListResourceParser<OsImage> {

@Override public OsImage parse(JsonNode item) {
if (!item.has("OSID")) return die("parse: OSID not found");
if (!item.has("name")) return die("parse: name not found");
return new OsImage()
.setId(item.get("OSID").asLong())
.setName(item.get("name").textValue());
}

}

+ 19
- 0
bubble-server/src/main/java/bubble/cloud/compute/vultr/VultrRegionParser.java Visa fil

@@ -0,0 +1,19 @@
package bubble.cloud.compute.vultr;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ListResourceParser;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public class VultrRegionParser extends ListResourceParser<CloudRegion> {

@Override public CloudRegion parse(JsonNode item) {
if (!item.has("DCID")) return die("parse: DCID not found");
if (!item.has("name")) return die("parse: name not found");
return new CloudRegion()
.setId(item.get("DCID").asLong())
.setInternalName(item.get("name").textValue());
}

}

+ 2
- 0
bubble-server/src/main/java/bubble/model/cloud/notify/NotificationType.java Visa fil

@@ -6,6 +6,7 @@ package bubble.model.cloud.notify;

import bubble.cloud.CloudRegion;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.OsImage;
import bubble.cloud.geoCode.GeoCodeResult;
import bubble.cloud.geoLocation.GeoLocation;
import bubble.cloud.geoTime.GeoTimeZone;
@@ -63,6 +64,7 @@ public enum NotificationType {
// delegated compute driver notifications
compute_driver_get_sizes (ComputeNodeSize[].class),
compute_driver_get_regions (CloudRegion[].class),
compute_driver_get_os (OsImage.class),
compute_driver_start (BubbleNode.class),
compute_driver_cleanup_start (BubbleNode.class),
compute_driver_stop (BubbleNode.class),


+ 15
- 0
bubble-server/src/main/java/bubble/notify/compute/NotificationHandler_compute_driver_get_os.java Visa fil

@@ -0,0 +1,15 @@
package bubble.notify.compute;

import bubble.cloud.compute.ComputeServiceDriver;
import bubble.cloud.compute.OsImage;
import bubble.model.cloud.notify.ReceivedNotification;

public class NotificationHandler_compute_driver_get_os extends NotificationHandler_compute_driver<OsImage> {

@Override protected OsImage handle(ReceivedNotification n,
ComputeDriverNotification notification,
ComputeServiceDriver compute) {
return compute.getOs();
}

}

+ 14
- 2
bubble-server/src/main/java/bubble/service/packer/PackerJob.java Visa fil

@@ -56,7 +56,7 @@ public class PackerJob implements Callable<List<PackerImage>> {
public static final String VARIABLES_VAR = "packerVariables";
public static final String BUILD_REGION_VAR = "buildRegion";
public static final String IMAGE_REGIONS_VAR = "imageRegions";
public static final String BUILDER_VAR = "builder";
public static final String BUILDERS_VAR = "builders";

@Autowired private BubbleConfiguration configuration;
@Autowired private GeoService geoService;
@@ -95,6 +95,8 @@ public class PackerJob implements Callable<List<PackerImage>> {
final Map<String, Object> ctx = new HashMap<>();
ctx.put("credentials", NameAndValue.toMap(cloud.getCredentials().getParams()));
ctx.put("compute", computeDriver);
ctx.put("sizes", computeDriver.getSizesMap());
ctx.put("os", computeDriver.getOs());

// determine lat/lon to find closest cloud region to perform build in
final GeoLocation here = geoService.locate(account.getUuid(), getExternalIp());
@@ -134,7 +136,17 @@ public class PackerJob implements Callable<List<PackerImage>> {

final String packerTemplatePath = PACKER_TEMPLATE.replace(INSTALL_TYPE_VAR, installType.name());
final String packerConfigTemplate = stream2string(packerTemplatePath);
ctx.put(BUILDER_VAR, generateBuilder(packerConfig, ctx));

final List<String> builderJsons = new ArrayList<>();
if (packerConfig.iterateRegions()) {
for (CloudRegion region : computeDriver.getRegions()) {
ctx.put("region", region);
builderJsons.add(generateBuilder(packerConfig, ctx));
}
} else {
builderJsons.add(generateBuilder(packerConfig, ctx));
}
ctx.put(BUILDERS_VAR, builderJsons);

// write packer file
final String packerJson = HandlebarsUtil.apply(configuration.getHandlebars(), packerConfigTemplate, ctx, '[', ']');


+ 11
- 10
bubble-server/src/main/resources/models/defaults/cloudService.json Visa fil

@@ -195,11 +195,11 @@
"location": {"city": "Amsterdam", "country": "NL", "region": "North Holland", "lat": "52.366667", "lon": "4.9"}
}],
"sizes": [
{"name": "small", "type": "small", "internalName": "1024 MB RAM,25 GB SSD,1.00 TB BW", "vcpu": 1, "memoryMB": 1024, "ssdGB": 25},
{"name": "medium", "type": "medium", "internalName": "2048 MB RAM,55 GB SSD,2.00 TB BW", "vcpu": 1, "memoryMB": 2048, "ssdGB": 55},
{"name": "large", "type": "large", "internalName": "4096 MB RAM,80 GB SSD,3.00 TB BW", "vcpu": 2, "memoryMB": 4096, "ssdGB": 80}
{"name": "small", "type": "small", "internalName": "1024 MB RAM,25 GB SSD,1.00 TB BW"},
{"name": "medium", "type": "medium", "internalName": "2048 MB RAM,55 GB SSD,2.00 TB BW"},
{"name": "large", "type": "large", "internalName": "4096 MB RAM,80 GB SSD,3.00 TB BW"}
],
"config": [{"name": "os", "value": "Ubuntu 18.04 x64"}],
"os": "Ubuntu 18.04 x64",
"packer": {
"vars": [{"name": "VULTR_API_KEY", "value": "[[credentials.apiKey]]"}],
"iterateRegions": true,
@@ -229,7 +229,8 @@
"type": "compute",
"driverClass": "bubble.cloud.compute.digitalocean.DigitalOceanDriver",
"driverConfig": {
"regions": [{
"regions": [
{
"name": "DigitalOcean - New York City 1",
"internalName": "nyc1",
"location": {"city": "New York", "country": "US", "region": "NY", "lat": "40.661", "lon": "-73.944"}
@@ -267,11 +268,11 @@
"location": {"city": "Bangalore", "country": "IN", "region": "Karnataka", "lat": "12.983333", "lon": "77.583333"}
}],
"sizes": [
{"name": "small", "type": "small", "internalName": "s-1vcpu-1gb", "vcpu": 1, "memoryMB": 1024, "ssdGB": 25},
{"name": "medium", "type": "medium", "internalName": "s-1vcpu-2gb", "vcpu": 1, "memoryMB": 2048, "ssdGB": 50},
{"name": "large", "type": "large", "internalName": "s-2vcpu-4gb", "vcpu": 2, "memoryMB": 4096, "ssdGB": 80}
{"name": "small", "type": "small", "internalName": "s-1vcpu-1gb"},
{"name": "medium", "type": "medium", "internalName": "s-1vcpu-2gb"},
{"name": "large", "type": "large", "internalName": "s-2vcpu-4gb"}
],
"config": [{"name": "os", "value": "ubuntu-18-04-x64"}],
"os": "ubuntu-18-04-x64",
"packer": {
"vars": [{"name": "DIGITALOCEAN_API_KEY", "value": "[[credentials.apiKey]]"}],
"builder": {
@@ -280,7 +281,7 @@
"api_token": "[[user `DIGITALOCEAN_API_KEY`]]",
"image": "<<os.name>>",
"region": "<<buildRegion.internalName>>",
"size": "<<sizes.small.name>>",
"size": "<<sizes.small.internalName>>",
"ipv6": true,
"snapshot_name": "<<packerImageName>>",
"snapshot_regions": ["<<<imageRegions>>>"]


+ 3
- 2
bubble-server/src/main/resources/packer/packer-sage.json.hbs Visa fil

@@ -1,10 +1,11 @@
{
"variables": {
[[#each packerVariables]]"[[name]]": "{{env `[[name]]`}}"[[#unless @last]],
[[#each packerVariables]] "[[name]]": "{{env `[[name]]`}}"[[#unless @last]],
[[/unless]][[/each]]
},
"builders": [
[[[builder]]]
[[#each builders]] [[[this]]][[#unless @last]],
[[/unless]][[/each]]
],
"provisioners": [
{


Laddar…
Avbryt
Spara