@@ -0,0 +1,35 @@ | |||
#!/bin/bash | |||
# | |||
# Write a constant value to stdout. | |||
# | |||
# This will only ever write the constant value to stdout if it can successfully be read. | |||
# If the constant can be read, its value is printed with the .toString() method. | |||
# If an error occurs, nothing is written to stdout, and the error will be written to stderr. | |||
# If the value of the constant is null, nothing is printed to stdout, and "null" is printed to stderr. | |||
# | |||
# Usage: | |||
# | |||
# bconst classAndMember | |||
# | |||
# classAndMember : the full name of a Java class, followed by a dot and the constant member name | |||
# | |||
# For example: | |||
# | |||
# bconst bubble.ApiConstants.ROOT_NETWORK_UUID | |||
# | |||
# Environment variables | |||
# | |||
# BUBBLE_API : which API to use. Default is local (http://127.0.0.1:PORT, where PORT is found in .bubble.env) | |||
# BUBBLE_USER : account to use. Default is root | |||
# BUBBLE_PASS : password for account. Default is root | |||
# BUBBLE_INCLUDE : path to look for JSON include files. default value is to assume we are being run from | |||
# bubble repo, bubble-models repo, or bubble-client and use include files from minimal model. | |||
# | |||
SCRIPT="${0}" | |||
SCRIPT_DIR=$(cd $(dirname ${SCRIPT}) && pwd) | |||
. ${SCRIPT_DIR}/bubble_common | |||
CLASS_AND_MEMBER="${1:?sole param should be something like: bubble.pkg.SomeClass.SOME_CONSTANT}" | |||
shift | |||
BUBBLE_QUIET=1 exec ${SCRIPT_DIR}/bubble const "${CLASS_AND_MEMBER}" "${@}" |
@@ -57,10 +57,9 @@ if [[ ! -d ${ROLES_DIR} ]] ; then | |||
die "automation/roles dir not found: ${ROLES_DIR}" | |||
fi | |||
API_CONSTANTS="${BUBBLE_SERVER}/src/main/java/bubble/ApiConstants.java" | |||
LOCAL_NET_ID="$(cat "${API_CONSTANTS}" | grep -v '//' | grep -m 1 "String ROOT_NETWORK_UUID" | awk -F '"' '{print $2}')" | |||
LOCAL_NET_ID="$("${SCRIPT_DIR}/bconst" bubble.ApiConstants.ROOT_NETWORK_UUID 2> /dev/null)" | |||
if [[ -z "${LOCAL_NET_ID}" ]] ; then | |||
die "ROOT_NETWORK_UUID could not be read from ${API_CONSTANTS}" | |||
die "ROOT_NETWORK_UUID could not be read from ApiConstants" | |||
fi | |||
echo "lbs = ${LOCALSTORAGE_BASE_DIR}" | |||
@@ -0,0 +1,244 @@ | |||
package bubble.cloud; | |||
import bubble.cloud.auth.AuthenticationDriver; | |||
import bubble.cloud.compute.ComputeNodeSize; | |||
import bubble.cloud.compute.ComputeNodeSizeType; | |||
import bubble.cloud.compute.ComputeServiceDriver; | |||
import bubble.cloud.dns.DnsServiceDriver; | |||
import bubble.cloud.email.EmailServiceDriver; | |||
import bubble.cloud.geoCode.GeoCodeResult; | |||
import bubble.cloud.geoCode.GeoCodeServiceDriver; | |||
import bubble.cloud.geoLocation.GeoLocateServiceDriver; | |||
import bubble.cloud.geoLocation.GeoLocation; | |||
import bubble.cloud.geoTime.GeoTimeServiceDriver; | |||
import bubble.cloud.geoTime.GeoTimeZone; | |||
import bubble.cloud.payment.PaymentServiceDriver; | |||
import bubble.cloud.sms.SmsServiceDriver; | |||
import bubble.cloud.storage.StorageServiceDriver; | |||
import bubble.model.account.Account; | |||
import bubble.model.account.AccountContact; | |||
import bubble.model.account.message.AccountMessage; | |||
import bubble.model.bill.AccountPaymentMethod; | |||
import bubble.model.bill.BubblePlan; | |||
import bubble.model.bill.PaymentMethodType; | |||
import bubble.model.cloud.*; | |||
import bubble.notify.payment.PaymentValidationResult; | |||
import bubble.notify.storage.StorageListing; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.dns.DnsRecord; | |||
import org.cobbzilla.util.dns.DnsRecordMatch; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.Collection; | |||
import java.util.List; | |||
@Slf4j | |||
public class NoopCloud implements | |||
AuthenticationDriver, ComputeServiceDriver, DnsServiceDriver, EmailServiceDriver, | |||
GeoCodeServiceDriver, GeoLocateServiceDriver, GeoTimeServiceDriver, PaymentServiceDriver, | |||
SmsServiceDriver, StorageServiceDriver { | |||
public static final String NOOP_CLOUD = NoopCloud.class.getName(); | |||
@Override public boolean send(Account account, AccountMessage message, AccountContact contact) { | |||
if (log.isDebugEnabled()) log.debug("send( account="+ account + ")"); | |||
return false; | |||
} | |||
@Override public boolean test() { | |||
if (log.isDebugEnabled()) log.debug("test()"); | |||
return false; | |||
} | |||
@Override public boolean _write(String fromNode, String key, InputStream data, StorageMetadata metadata, String requestId) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("_write( fromNode="+ fromNode + ")"); | |||
return false; | |||
} | |||
@Override public boolean canWrite(String fromNode, String toNode, String key) { | |||
if (log.isDebugEnabled()) log.debug("canWrite( fromNode="+ fromNode + ")"); | |||
return false; | |||
} | |||
@Override public boolean delete(String fromNode, String uri) { | |||
if (log.isDebugEnabled()) log.debug("delete( fromNode="+ fromNode + ")"); | |||
return false; | |||
} | |||
@Override public boolean deleteNetwork(String networkUuid) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("deleteNetwork( networkUuid="+ networkUuid + ")"); | |||
return false; | |||
} | |||
@Override public boolean rekey(String fromNode, CloudService newCloud) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("rekey( fromNode="+ fromNode + ")"); | |||
return false; | |||
} | |||
@Override public StorageListing list(String fromNode, String prefix) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("list( fromNode="+ fromNode + ")"); | |||
return null; | |||
} | |||
@Override public StorageListing listNext(String fromNode, String listingId) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("listNext( fromNode="+ fromNode + ")"); | |||
return null; | |||
} | |||
@Override public void setConfig(JsonNode json, CloudService cloudService) { | |||
if (log.isDebugEnabled()) log.debug("setConfig( json="+ json + ")"); | |||
} | |||
@Override public CloudCredentials getCredentials() { | |||
if (log.isDebugEnabled()) log.debug("getCredentials()"); | |||
return null; | |||
} | |||
@Override public void setCredentials(CloudCredentials creds) { | |||
if (log.isDebugEnabled()) log.debug("setCredentials( creds="+ creds + ")"); | |||
} | |||
@Override public CloudServiceType getType() { | |||
if (log.isDebugEnabled()) log.debug("getType()"); | |||
return null; | |||
} | |||
@Override public boolean _exists(String fromNode, String key) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("_exists( fromNode="+ fromNode + ")"); | |||
return false; | |||
} | |||
@Override public StorageMetadata readMetadata(String fromNode, String key) { | |||
if (log.isDebugEnabled()) log.debug("readMetadata( fromNode="+ fromNode + ")"); | |||
return null; | |||
} | |||
@Override public InputStream _read(String fromNode, String key) throws IOException { | |||
if (log.isDebugEnabled()) log.debug("_read( fromNode="+ fromNode + ")"); | |||
return null; | |||
} | |||
@Override public PaymentMethodType getPaymentMethodType() { | |||
if (log.isDebugEnabled()) log.debug("getPaymentMethodType()"); | |||
return null; | |||
} | |||
@Override public PaymentValidationResult validate(AccountPaymentMethod paymentMethod) { | |||
if (log.isDebugEnabled()) log.debug("validate( paymentMethod="+ paymentMethod + ")"); | |||
return null; | |||
} | |||
@Override public boolean authorize(BubblePlan plan, String accountPlanUuid, String billUuid, AccountPaymentMethod paymentMethod) { | |||
if (log.isDebugEnabled()) log.debug("authorize( plan="+ plan + ")"); | |||
return false; | |||
} | |||
@Override public boolean cancelAuthorization(BubblePlan plan, String accountPlanUuid, AccountPaymentMethod paymentMethod) { | |||
if (log.isDebugEnabled()) log.debug("cancelAuthorization( plan="+ plan + ")"); | |||
return false; | |||
} | |||
@Override public boolean purchase(String accountPlanUuid, String paymentMethodUuid, String billUuid) { | |||
if (log.isDebugEnabled()) log.debug("purchase( accountPlanUuid="+ accountPlanUuid + ")"); | |||
return false; | |||
} | |||
@Override public boolean refund(String accountPlanUuid) { | |||
if (log.isDebugEnabled()) log.debug("refund( accountPlanUuid="+ accountPlanUuid + ")"); | |||
return false; | |||
} | |||
@Override public GeoTimeZone getTimezone(String lat, String lon) { | |||
if (log.isDebugEnabled()) log.debug("getTimezone( lat="+ lat + ")"); | |||
return null; | |||
} | |||
@Override public GeoLocation geolocate(String ip) { | |||
if (log.isDebugEnabled()) log.debug("geolocate( ip="+ ip + ")"); | |||
return null; | |||
} | |||
@Override public GeoCodeResult lookup(GeoLocation location) { | |||
if (log.isDebugEnabled()) log.debug("lookup( location="+ location + ")"); | |||
return null; | |||
} | |||
@Override public Collection<DnsRecord> create(BubbleDomain domain) { | |||
if (log.isDebugEnabled()) log.debug("create( domain="+ domain + ")"); | |||
return null; | |||
} | |||
@Override public Collection<DnsRecord> setNetwork(BubbleNetwork network) { | |||
if (log.isDebugEnabled()) log.debug("setNetwork( network="+ network + ")"); | |||
return null; | |||
} | |||
@Override public Collection<DnsRecord> setNode(BubbleNode node) { | |||
if (log.isDebugEnabled()) log.debug("setNode( node="+ node + ")"); | |||
return null; | |||
} | |||
@Override public Collection<DnsRecord> deleteNode(BubbleNode node) { | |||
if (log.isDebugEnabled()) log.debug("deleteNode( node="+ node + ")"); | |||
return null; | |||
} | |||
@Override public DnsRecord update(DnsRecord record) { | |||
if (log.isDebugEnabled()) log.debug("update( record="+ record + ")"); | |||
return null; | |||
} | |||
@Override public DnsRecord remove(DnsRecord record) { | |||
if (log.isDebugEnabled()) log.debug("remove( record="+ record + ")"); | |||
return null; | |||
} | |||
@Override public Collection<DnsRecord> list(DnsRecordMatch matcher) { | |||
if (log.isDebugEnabled()) log.debug("list( matcher="+ matcher + ")"); | |||
return null; | |||
} | |||
@Override public List<ComputeNodeSize> getSizes() { | |||
if (log.isDebugEnabled()) log.debug("getSizes()"); | |||
return null; | |||
} | |||
@Override public ComputeNodeSize getSize(ComputeNodeSizeType type) { | |||
if (log.isDebugEnabled()) log.debug("getSize( type="+ type + ")"); | |||
return null; | |||
} | |||
@Override public BubbleNode start(BubbleNode node) throws Exception { | |||
if (log.isDebugEnabled()) log.debug("start( node="+ node + ")"); | |||
return null; | |||
} | |||
@Override public BubbleNode cleanupStart(BubbleNode node) throws Exception { | |||
if (log.isDebugEnabled()) log.debug("cleanupStart( node="+ node + ")"); | |||
return null; | |||
} | |||
@Override public BubbleNode stop(BubbleNode node) throws Exception { | |||
if (log.isDebugEnabled()) log.debug("stop( node="+ node + ")"); | |||
return null; | |||
} | |||
@Override public BubbleNode status(BubbleNode node) throws Exception { | |||
if (log.isDebugEnabled()) log.debug("status( node="+ node + ")"); | |||
return null; | |||
} | |||
@Override public List<CloudRegion> getRegions() { | |||
if (log.isDebugEnabled()) log.debug("getRegions()"); | |||
return null; | |||
} | |||
@Override public CloudRegion getRegion(String region) { | |||
if (log.isDebugEnabled()) log.debug("getRegion( region="+ region + ")"); | |||
return null; | |||
} | |||
} |
@@ -197,6 +197,7 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc | |||
}); | |||
ready.set(true); | |||
cloudDAO.ensureNoopCloudsExist(account); | |||
copyTemplateObjects(acct, parent, roleDAO); | |||
final Map<String, RuleDriver> drivers = new HashMap<>(); | |||
@@ -8,6 +8,7 @@ import bubble.model.account.Account; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.CloudService; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.wizard.validation.ValidationResult; | |||
import org.hibernate.criterion.Order; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
@@ -16,17 +17,49 @@ import org.springframework.stereotype.Repository; | |||
import java.util.List; | |||
import static bubble.ApiConstants.ROOT_NETWORK_UUID; | |||
import static bubble.cloud.NoopCloud.NOOP_CLOUD; | |||
import static bubble.cloud.storage.local.LocalStorageDriver.LOCAL_STORAGE; | |||
import static bubble.model.cloud.CloudService.testDriver; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | |||
import static org.cobbzilla.wizard.model.Identifiable.UUID; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | |||
import static org.cobbzilla.wizard.server.RestServerBase.reportError; | |||
@Repository | |||
@Repository @Slf4j | |||
public class CloudServiceDAO extends AccountOwnedTemplateDAO<CloudService> { | |||
@Autowired private AccountDAO accountDAO; | |||
@Autowired private BubbleConfiguration configuration; | |||
public void ensureNoopCloudsExist(Account account) { | |||
for (CloudServiceType type : CloudServiceType.values()) { | |||
final CloudService noopCloud = findByAccountNoopForType(account.getUuid(), type); | |||
if (empty(noopCloud)) { | |||
try { | |||
create(new CloudService() | |||
.setAccount(account.getUuid()) | |||
.setType(type) | |||
.setName(NOOP_CLOUD) | |||
.setDescription(NOOP_CLOUD) | |||
.setPriority(Integer.MIN_VALUE) | |||
.setEnabled(true) | |||
.setTemplate(false) | |||
.setSkipTest(true) | |||
.setCredentialsJson("{}") | |||
.setDriverConfigJson("{}") | |||
.setDriverClass(NOOP_CLOUD)); | |||
} catch (Exception e) { | |||
reportError("ensureNoopCloudExists: " + shortError(e)); | |||
} | |||
} | |||
} | |||
} | |||
private CloudService findByAccountNoopForType(String accountUuid, CloudServiceType type) { | |||
final List<CloudService> found = findByAccountAndTypeAndDriverClass(accountUuid, type, NOOP_CLOUD); | |||
return found.isEmpty() ? null : found.size() == 1 ? found.get(0) : die("findByAccountNoopForType("+accountUuid+", "+type+"): "+found.size()+" results found, expected only one"); | |||
} | |||
@Override public Order getDefaultSortOrder() { return PRIORITY_ASC; } | |||
@Override public Object preCreate(CloudService cloud) { | |||
@@ -6,6 +6,7 @@ import bubble.main.http.BubbleHttpPostMain; | |||
import bubble.main.http.BubbleHttpPutMain; | |||
import bubble.server.BubbleServer; | |||
import org.cobbzilla.util.collection.MapBuilder; | |||
import org.cobbzilla.util.main.ConstMain; | |||
import org.cobbzilla.util.string.StringUtil; | |||
import org.cobbzilla.wizard.main.MainBase; | |||
import org.slf4j.bridge.SLF4JBridgeHandler; | |||
@@ -28,7 +29,8 @@ public class BubbleMain { | |||
{"handlebars", BubbleHandlebarsMain.class}, | |||
{"crypt", CryptMain.class}, | |||
{"rekey", RekeyDatabaseMain.class}, | |||
{"generate-algo-conf", GenerateAlgoConfMain.class} | |||
{"generate-algo-conf", GenerateAlgoConfMain.class}, | |||
{"const", ConstMain.class} | |||
}); | |||
public static void main(String[] args) throws Exception { | |||
@@ -61,6 +61,7 @@ import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD; | |||
}) | |||
@ECIndexes({ | |||
@ECIndex(unique=true, of={"account", "name"}), | |||
@ECIndex(unique=true, of={"account", "type", "driverClass"}, where="driver_class='bubble.cloud.NoopCloud'"), | |||
@ECIndex(of={"account", "template", "enabled"}), | |||
@ECIndex(of={"template", "enabled"}) | |||
}) | |||
@@ -1,10 +1,12 @@ | |||
package bubble.service.dbfilter; | |||
import bubble.cloud.CloudServiceType; | |||
import bubble.cloud.storage.local.LocalStorageConfig; | |||
import bubble.cloud.storage.local.LocalStorageDriver; | |||
import bubble.model.account.AccountSshKey; | |||
import bubble.model.account.AccountTemplate; | |||
import bubble.model.app.BubbleApp; | |||
import bubble.model.bill.AccountPaymentMethod; | |||
import bubble.model.bill.BubblePlanApp; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.BubbleNode; | |||
@@ -13,13 +15,12 @@ import lombok.Getter; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.wizard.model.Identifiable; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.NoSuchElementException; | |||
import java.util.*; | |||
import java.util.concurrent.BlockingQueue; | |||
import java.util.concurrent.LinkedBlockingQueue; | |||
import java.util.concurrent.atomic.AtomicReference; | |||
import static bubble.cloud.NoopCloud.NOOP_CLOUD; | |||
import static bubble.cloud.storage.local.LocalStorageDriver.LOCAL_STORAGE_STANDARD_BASE_DIR; | |||
import static bubble.service.dbfilter.EndOfEntityStream.END_OF_ENTITY_STREAM; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | |||
@@ -36,6 +37,7 @@ public abstract class EntityIterator implements Iterator<Identifiable> { | |||
@Getter private final Thread thread; | |||
@Getter private final AtomicReference<Exception> error; | |||
private List<BubbleApp> userApps; | |||
private Map<CloudServiceType, CloudService> noopClouds = new HashMap<>(); | |||
public EntityIterator(AtomicReference<Exception> error) { | |||
this.error = error; | |||
@@ -86,11 +88,41 @@ public abstract class EntityIterator implements Iterator<Identifiable> { | |||
if (CloudService.class.isAssignableFrom(c)) { | |||
entities.stream() | |||
.filter(cloud -> fullCopy || notPaymentCloud((CloudService) cloud)) | |||
.forEach(e -> add(setLocalStoragePath((CloudService) e))); | |||
.forEach(e -> { | |||
final CloudService cs = (CloudService) e; | |||
if (!fullCopy) { | |||
if (cs.getDriverClass().equals(NOOP_CLOUD)) { | |||
final CloudServiceType type = cs.getType(); | |||
if (noopClouds.containsKey(type)) { | |||
log.warn("addEntities: multiple " + NOOP_CLOUD + " drivers found for type=" + type); | |||
} else { | |||
noopClouds.put(type, cs); | |||
} | |||
} | |||
} | |||
add(setLocalStoragePath(cs)); | |||
}); | |||
} else if (AccountSshKey.class.isAssignableFrom(c)) { | |||
entities.forEach(e -> add(setInstallKey((AccountSshKey) e, network))); | |||
} else if (!fullCopy && AccountPaymentMethod.class.isAssignableFrom(c)) { | |||
// clear out payment information, set driver to noop | |||
final CloudService noopCloud = noopClouds.get(CloudServiceType.payment); | |||
if (noopCloud == null) { | |||
die("addEntities: "+NOOP_CLOUD+" for payment cloud type not found"); | |||
} else { | |||
entities.forEach(e -> { | |||
final AccountPaymentMethod apm = (AccountPaymentMethod) e; | |||
apm.setMaskedPaymentInfo("") | |||
.setPaymentInfo("") | |||
.setCloud(noopCloud.getUuid()) | |||
.setDeleted(now()) | |||
.setPromotion(null); | |||
add(apm); | |||
}); | |||
} | |||
} else if (!fullCopy && planApps != null && BubbleApp.class.isAssignableFrom(c)) { | |||
// only copy enabled apps, make them templates | |||
entities.stream().filter(app -> planAppEnabled(((BubbleApp) app).getTemplateApp(), planApps)) | |||
@@ -30,7 +30,7 @@ public class FilteredEntityIterator extends EntityIterator { | |||
private static final List<Class<? extends Identifiable>> POST_COPY_ENTITIES = Arrays.asList(new Class<?>[] { | |||
BubbleNode.class, BubbleNodeKey.class, Device.class, AccountMessage.class, | |||
ReferralCode.class, AccountPaymentMethod.class, AccountPayment.class, Bill.class, Promotion.class, | |||
ReferralCode.class, AccountPayment.class, Bill.class, Promotion.class, | |||
}); | |||
private static boolean isPostCopyEntity(Class<? extends Identifiable> clazz) { | |||
@@ -1 +1 @@ | |||
Subproject commit 77831c8f23574ebdc8476dd835f8bbfbd8404338 | |||
Subproject commit fb7fe350cd4fe0f0338d37e551a0112cfa2e7835 |