From 71001d8e9d814ca5c232676f41a80d79fc365d9e Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Sun, 5 Jan 2020 15:50:39 -0500 Subject: [PATCH] add testing to activation --- .../java/bubble/cloud/CloudServiceDriver.java | 2 ++ .../cloud/auth/AuthenticationDriver.java | 2 ++ .../cloud/compute/ComputeServiceDriver.java | 2 ++ .../bubble/cloud/dns/DnsServiceDriver.java | 5 ++-- .../bubble/cloud/geoCode/GeoCodeResult.java | 10 +++++++ .../cloud/geoCode/GeoCodeServiceDriver.java | 10 +++++++ .../geoLocation/GeoLocateServiceDriver.java | 7 +++++ .../bubble/cloud/geoLocation/GeoLocation.java | 6 ++-- .../cloud/geoTime/GeoTimeServiceDriver.java | 13 +++++++++ .../cloud/payment/PaymentDriverBase.java | 3 -- .../cloud/payment/PaymentServiceDriver.java | 5 +++- .../delegate/DelegatedPaymentDriver.java | 10 +++---- .../cloud/storage/StorageServiceDriver.java | 15 ++++++++++ .../service/boot/ActivationService.java | 28 ++++++++++++++++++- .../pre_auth/ResourceMessages.properties | 7 +++++ bubble-web | 2 +- 16 files changed, 112 insertions(+), 15 deletions(-) diff --git a/bubble-server/src/main/java/bubble/cloud/CloudServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/CloudServiceDriver.java index e5e27bdd..5927c89d 100644 --- a/bubble-server/src/main/java/bubble/cloud/CloudServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/CloudServiceDriver.java @@ -68,4 +68,6 @@ public interface CloudServiceDriver { return json(val, resultClass); } + boolean test(); + } diff --git a/bubble-server/src/main/java/bubble/cloud/auth/AuthenticationDriver.java b/bubble-server/src/main/java/bubble/cloud/auth/AuthenticationDriver.java index 9c0006e1..80e54552 100644 --- a/bubble-server/src/main/java/bubble/cloud/auth/AuthenticationDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/auth/AuthenticationDriver.java @@ -36,6 +36,8 @@ public interface AuthenticationDriver extends CloudServiceDriver { boolean send(Account account, AccountMessage message, AccountContact contact); + @Override default boolean test () { return true; } + default Map buildContext(Account account, AccountMessage message, AccountContact contact) { return buildContext(account, message, contact, getConfiguration()); } 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 03baab7f..2175f421 100644 --- a/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/compute/ComputeServiceDriver.java @@ -19,4 +19,6 @@ public interface ComputeServiceDriver extends CloudServiceDriver, RegionalServic BubbleNode stop(BubbleNode node) throws Exception; BubbleNode status(BubbleNode node) throws Exception; + @Override default boolean test () { return true; } + } diff --git a/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java index 510c2497..2ed04401 100644 --- a/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/dns/DnsServiceDriver.java @@ -20,8 +20,7 @@ import java.util.Set; import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.cobbzilla.util.daemon.ZillaRuntime.die; -import static org.cobbzilla.util.daemon.ZillaRuntime.now; +import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.dns.DnsRecord.OPT_NS_NAME; import static org.cobbzilla.util.network.NetworkUtil.IPv4_ALL_ADDRS; import static org.cobbzilla.util.network.NetworkUtil.ipEquals; @@ -49,6 +48,8 @@ public interface DnsServiceDriver extends CloudServiceDriver { default Collection list() { return list(null); } + @Override default boolean test() { return !empty(list()); } + default Collection listNew(Long lastMod) { return list(); } static Collection dig(String host, DnsType type, String name) { return dig(host, 53, type, name); } diff --git a/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeResult.java b/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeResult.java index af13e380..93477faa 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeResult.java +++ b/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeResult.java @@ -20,4 +20,14 @@ public class GeoCodeResult { @JsonIgnore @Transient public double getLatitude () { return big(lat).doubleValue(); } @JsonIgnore @Transient public double getLongitude () { return big(lon).doubleValue(); } + public boolean valid () { + try { + Double.parseDouble(lat); + Double.parseDouble(lon); + return true; + } catch (Exception e) { + return false; + } + } + } diff --git a/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeServiceDriver.java index 7e319bbf..1ed7da0f 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeServiceDriver.java @@ -6,8 +6,18 @@ import bubble.cloud.geoLocation.GeoLocation; public interface GeoCodeServiceDriver extends CloudServiceDriver { + GeoLocation TEST_LOCATION = new GeoLocation() + .setCity("New York") + .setRegion("NY") + .setCountry("US"); + @Override default CloudServiceType getType() { return CloudServiceType.geoCode; } GeoCodeResult lookup (GeoLocation location); + @Override default boolean test () { + final GeoCodeResult result = lookup(TEST_LOCATION); + return result != null && result.valid(); + } + } diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriver.java index b0bd9021..b304507a 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriver.java @@ -3,10 +3,17 @@ package bubble.cloud.geoLocation; import bubble.cloud.CloudServiceDriver; import bubble.cloud.CloudServiceType; +import static org.cobbzilla.util.network.NetworkUtil.getExternalIp; + public interface GeoLocateServiceDriver extends CloudServiceDriver { @Override default CloudServiceType getType() { return CloudServiceType.geoLocation; } GeoLocation geolocate(String ip); + @Override default boolean test () { + final GeoLocation result = geolocate(getExternalIp()); + return result != null && result.hasCountry(); + } + } diff --git a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java index 8c9c13b7..75d976d7 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java +++ b/bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java @@ -10,13 +10,14 @@ import org.cobbzilla.util.math.Haversine; import javax.persistence.Transient; -import static org.cobbzilla.util.daemon.ZillaRuntime.big; -import static org.cobbzilla.util.daemon.ZillaRuntime.hashOf; +import static org.cobbzilla.util.daemon.ZillaRuntime.*; @NoArgsConstructor @Accessors(chain=true) public class GeoLocation { @Getter @Setter private String country; + public boolean hasCountry() { return !empty(country); } + @Getter @Setter private String region; @Getter @Setter private String city; @Getter @Setter private String lat; @@ -67,4 +68,5 @@ public class GeoLocation { return false; } } + } diff --git a/bubble-server/src/main/java/bubble/cloud/geoTime/GeoTimeServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/geoTime/GeoTimeServiceDriver.java index 1103f369..537311eb 100644 --- a/bubble-server/src/main/java/bubble/cloud/geoTime/GeoTimeServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/geoTime/GeoTimeServiceDriver.java @@ -5,8 +5,21 @@ import bubble.cloud.CloudServiceType; public interface GeoTimeServiceDriver extends CloudServiceDriver { + // New York City, Eastern Standard Time + String TEST_LONGITUDE = "-73.944"; + String TEST_LATITUDE = "40.661"; + String TEST_STANDARD_NAME = "Eastern Standard Time"; + String TEST_TIMEZONE_ID = "America/New York"; + @Override default CloudServiceType getType() { return CloudServiceType.geoTime; } GeoTimeZone getTimezone (String lat, String lon); + @Override default boolean test () { + final GeoTimeZone result = getTimezone(TEST_LATITUDE, TEST_LONGITUDE); + return result != null + && result.getStandardName().equals(TEST_STANDARD_NAME) + && result.getTimeZoneId().equals(TEST_TIMEZONE_ID); + } + } diff --git a/bubble-server/src/main/java/bubble/cloud/payment/PaymentDriverBase.java b/bubble-server/src/main/java/bubble/cloud/payment/PaymentDriverBase.java index 6be55b7b..31105cc7 100644 --- a/bubble-server/src/main/java/bubble/cloud/payment/PaymentDriverBase.java +++ b/bubble-server/src/main/java/bubble/cloud/payment/PaymentDriverBase.java @@ -1,7 +1,6 @@ package bubble.cloud.payment; import bubble.cloud.CloudServiceDriverBase; -import bubble.cloud.CloudServiceType; import bubble.dao.bill.*; import bubble.model.bill.*; import lombok.extern.slf4j.Slf4j; @@ -14,8 +13,6 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; @Slf4j public abstract class PaymentDriverBase extends CloudServiceDriverBase implements PaymentServiceDriver { - @Override public CloudServiceType getType() { return CloudServiceType.payment; } - @Autowired protected AccountPlanDAO accountPlanDAO; @Autowired protected BubblePlanDAO planDAO; @Autowired protected AccountPaymentMethodDAO paymentMethodDAO; diff --git a/bubble-server/src/main/java/bubble/cloud/payment/PaymentServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/payment/PaymentServiceDriver.java index 8b16e0dd..75f05a2c 100644 --- a/bubble-server/src/main/java/bubble/cloud/payment/PaymentServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/payment/PaymentServiceDriver.java @@ -1,12 +1,13 @@ package bubble.cloud.payment; +import bubble.cloud.CloudServiceDriver; import bubble.cloud.CloudServiceType; import bubble.model.bill.*; import bubble.notify.payment.PaymentValidationResult; import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported; -public interface PaymentServiceDriver { +public interface PaymentServiceDriver extends CloudServiceDriver { default CloudServiceType getType() { return CloudServiceType.payment; } @@ -23,4 +24,6 @@ public interface PaymentServiceDriver { boolean refund(String accountPlanUuid); + @Override default boolean test () { return true; } + } diff --git a/bubble-server/src/main/java/bubble/cloud/payment/delegate/DelegatedPaymentDriver.java b/bubble-server/src/main/java/bubble/cloud/payment/delegate/DelegatedPaymentDriver.java index 9c8d83e3..c81d0425 100644 --- a/bubble-server/src/main/java/bubble/cloud/payment/delegate/DelegatedPaymentDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/payment/delegate/DelegatedPaymentDriver.java @@ -1,13 +1,15 @@ package bubble.cloud.payment.delegate; -import bubble.cloud.CloudServiceType; import bubble.cloud.DelegatedCloudServiceDriverBase; import bubble.cloud.payment.PaymentServiceDriver; -import bubble.notify.payment.*; import bubble.dao.cloud.CloudServiceDAO; -import bubble.model.bill.*; +import bubble.model.bill.AccountPaymentMethod; +import bubble.model.bill.AccountPlan; +import bubble.model.bill.BubblePlan; +import bubble.model.bill.PaymentMethodType; import bubble.model.cloud.BubbleNode; import bubble.model.cloud.CloudService; +import bubble.notify.payment.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -22,8 +24,6 @@ public class DelegatedPaymentDriver extends DelegatedCloudServiceDriverBase impl public DelegatedPaymentDriver(CloudService cloud) { super(cloud); } - @Override public CloudServiceType getType() { return CloudServiceType.payment; } - @Override public PaymentMethodType getPaymentMethodType() { if (!cloud.delegated()) { log.warn("getPaymentMethodType: delegated driver has non-delegated cloud: "+cloud.getUuid()); diff --git a/bubble-server/src/main/java/bubble/cloud/storage/StorageServiceDriver.java b/bubble-server/src/main/java/bubble/cloud/storage/StorageServiceDriver.java index 39c3af1c..1757e9a1 100644 --- a/bubble-server/src/main/java/bubble/cloud/storage/StorageServiceDriver.java +++ b/bubble-server/src/main/java/bubble/cloud/storage/StorageServiceDriver.java @@ -16,6 +16,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import static bubble.ApiConstants.ROOT_NETWORK_UUID; import static java.util.UUID.randomUUID; import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.system.Sleep.sleep; @@ -114,6 +115,20 @@ public interface StorageServiceDriver extends CloudServiceDriver { return new String(readFully(fromNode, key)); } + @Override default boolean test () { + try { + if (!write(getTestNodeId(), getTestKey(), getTestBytes())) return false; + if (!delete(getTestNodeId(), getTestKey())) return false; + } catch (Exception e) { + return false; + } + return true; + } + + default String getTestNodeId () { return ROOT_NETWORK_UUID; } + default String getTestKey () { return "_test"; } + default byte[] getTestBytes() { return "test".getBytes(); } + boolean _write(String fromNode, String key, InputStream data, StorageMetadata metadata, String requestId) throws IOException; default boolean write(String fromNode, String key, InputStream data) { diff --git a/bubble-server/src/main/java/bubble/service/boot/ActivationService.java b/bubble-server/src/main/java/bubble/service/boot/ActivationService.java index 94b29602..03af1821 100644 --- a/bubble-server/src/main/java/bubble/service/boot/ActivationService.java +++ b/bubble-server/src/main/java/bubble/service/boot/ActivationService.java @@ -1,9 +1,11 @@ package bubble.service.boot; import bubble.ApiConstants; +import bubble.cloud.CloudServiceDriver; import bubble.cloud.CloudServiceType; import bubble.cloud.compute.ComputeNodeSizeType; import bubble.cloud.compute.local.LocalComputeDriver; +import bubble.cloud.dns.DnsServiceDriver; import bubble.cloud.storage.local.LocalStorageConfig; import bubble.cloud.storage.local.LocalStorageDriver; import bubble.dao.cloud.*; @@ -12,6 +14,9 @@ import bubble.model.account.ActivationRequest; import bubble.model.cloud.*; import bubble.server.BubbleConfiguration; import lombok.extern.slf4j.Slf4j; +import org.cobbzilla.util.dns.DnsRecordMatch; +import org.cobbzilla.util.dns.DnsType; +import org.cobbzilla.wizard.validation.SimpleViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -25,13 +30,14 @@ import static bubble.model.cloud.BubbleFootprint.DEFAULT_FOOTPRINT_OBJECT; import static bubble.model.cloud.BubbleNetwork.TAG_ALLOW_REGISTRATION; import static bubble.model.cloud.BubbleNetwork.TAG_PARENT_ACCOUNT; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.cobbzilla.util.daemon.ZillaRuntime.die; +import static org.cobbzilla.util.daemon.ZillaRuntime.*; import static org.cobbzilla.util.io.FileUtil.toStringOrDie; import static org.cobbzilla.util.io.StreamUtil.stream2string; import static org.cobbzilla.util.json.JsonUtil.json; import static org.cobbzilla.util.network.NetworkUtil.getFirstPublicIpv4; import static org.cobbzilla.util.network.NetworkUtil.getLocalhostIpv4; import static org.cobbzilla.util.system.CommandShell.execScript; +import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; @Service @Slf4j public class ActivationService { @@ -62,6 +68,14 @@ public class ActivationService { .setType(CloudServiceType.dns) .setTemplate(true) .setAccount(account.getUuid())); + final DnsServiceDriver dnsDriver = publicDns.getDnsDriver(configuration); + checkDriver(dnsDriver, "err.dns.testFailed", "err.dns.unknownError"); + final DnsRecordMatch nsMatcher = (DnsRecordMatch) new DnsRecordMatch() + .setType(DnsType.NS) + .setFqdn(request.getDomain().getName()); + if (empty(dnsDriver.list(nsMatcher))) { + throw invalidEx("err.dns.noNameServerRecordsForDomain", request.getDomain().getName()); + } final CloudService localStorage = cloudDAO.create(new CloudService() .setAccount(account.getUuid()) @@ -77,6 +91,8 @@ public class ActivationService { } else { networkStorage = cloudDAO.create(new CloudService(request.getStorage()) .setAccount(account.getUuid())); + final CloudServiceDriver storageDriver = networkStorage.getStorageDriver(configuration); + checkDriver(storageDriver, "err.storage.testFailed", "err.storage.unknownError"); } final AnsibleRole[] roles = request.hasRoles() ? request.getRoles() : json(loadDefaultRoles(), AnsibleRole[].class); @@ -148,6 +164,16 @@ public class ActivationService { return node; } + public void checkDriver(CloudServiceDriver storageDriver, String errTestFailed, String errException) { + try { + if (!storageDriver.test()) throw invalidEx(errTestFailed); + } catch (SimpleViolationException e) { + throw e; + } catch (Exception e) { + throw invalidEx(errException, shortError(e)); + } + } + public String loadDefaultRoles() { if (configuration.testMode()) { final File roleFile = new File("target/classes/"+DEFAULT_ROLES); diff --git a/bubble-server/src/main/resources/message_templates/en_US/server/pre_auth/ResourceMessages.properties b/bubble-server/src/main/resources/message_templates/en_US/server/pre_auth/ResourceMessages.properties index a330bb4c..5ee62a31 100644 --- a/bubble-server/src/main/resources/message_templates/en_US/server/pre_auth/ResourceMessages.properties +++ b/bubble-server/src/main/resources/message_templates/en_US/server/pre_auth/ResourceMessages.properties @@ -74,6 +74,13 @@ form_section_title_credentials=Credentials form_section_title_config=Configuration button_label_activate=Activate +# Activation errors +err.dns.testFailed=Error checking connection to DNS connection +err.dns.unknownError=Error checking connection to DNS service +err.dns.noNameServerRecordsForDomain=DNS server does not have any NS records for the domain +err.storage.unknownError=Error checking connection to Storage service +err.storage.testFailed=Error checking connection to Storage service + # Login/Registration form form_title_login=Login field_label_username=Username diff --git a/bubble-web b/bubble-web index fbb91b5d..f8821858 160000 --- a/bubble-web +++ b/bubble-web @@ -1 +1 @@ -Subproject commit fbb91b5da57408b03ce1c34de4e4d98da226ba13 +Subproject commit f88218582ca1203da0ca34313a2b50c5646a5a7b