@@ -39,9 +39,9 @@ public abstract class ComputeServiceDriverBase | |||
@Override public void postSetup() { | |||
final String prefix = "postSetup("+getClass().getSimpleName()+"/"+cloud.getUuid()+"): "; | |||
if (configuration.isSelfSage()) { | |||
if (configuration.getThisNetwork().sage()) { | |||
if (cloud.delegated()) { | |||
log.info(prefix+"NOT starting NodeReaper for delegated driver"); | |||
log.info(prefix + "NOT starting NodeReaper for delegated driver"); | |||
} else { | |||
synchronized (reapers) { | |||
if (reapers.get(getCredentials()) == null) { | |||
@@ -10,6 +10,7 @@ import lombok.Cleanup; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.apache.commons.io.IOUtils; | |||
import org.cobbzilla.util.collection.NameAndValue; | |||
import org.cobbzilla.util.handlebars.HandlebarsUtil; | |||
import org.cobbzilla.util.http.HttpMeta; | |||
@@ -21,8 +22,7 @@ import org.cobbzilla.util.io.TempDir; | |||
import org.cobbzilla.wizard.cache.redis.RedisService; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.*; | |||
import java.util.List; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.regex.Pattern; | |||
@@ -139,9 +139,15 @@ public abstract class GeoLocateServiceDriverBase<T> extends CloudServiceDriverBa | |||
private File downloadDbFile(HttpRequestBean request, File archive) throws IOException { | |||
Exception lastEx = null; | |||
if (!archive.getParentFile().exists()) { | |||
mkdirOrDie(archive.getParentFile()); | |||
} | |||
for (int i=0; i<MAX_FILE_RETRIES; i++) { | |||
try { | |||
return HttpUtil.getResponse(request).toFile(archive); | |||
@Cleanup final InputStream in = HttpUtil.get(request.getUri(), NameAndValue.toMap(request.getHeaders())); | |||
@Cleanup final OutputStream out = new FileOutputStream(archive); | |||
IOUtils.copyLarge(in, out); | |||
return archive; | |||
} catch (Exception e) { | |||
lastEx = e; | |||
log.warn("downloadDbFile: "+shortError(e)); | |||
@@ -6,7 +6,6 @@ package bubble.dao.account; | |||
import bubble.cloud.CloudServiceDriver; | |||
import bubble.cloud.CloudServiceType; | |||
import bubble.cloud.compute.ComputeNodeSizeType; | |||
import bubble.dao.account.message.AccountMessageDAO; | |||
import bubble.dao.app.*; | |||
import bubble.dao.bill.AccountPaymentArchivedDAO; | |||
@@ -221,8 +220,8 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc | |||
final BubbleNetwork thisNetwork = selfNodeService.getThisNetwork(); | |||
if (parentEntity.delegated() | |||
&& thisNetwork != null | |||
&& thisNetwork.getInstallType() == AnsibleInstallType.node | |||
&& thisNetwork.getComputeSizeType() != ComputeNodeSizeType.local) { | |||
&& thisNetwork.node() | |||
&& thisNetwork.local()) { | |||
// on a node, sub-accounts can use the same cloud/config/credentials as their admin | |||
return accountEntity.setDelegated(parentEntity.getDelegated()) | |||
.setCredentialsJson(parentEntity.getCredentialsJson()) | |||
@@ -9,7 +9,6 @@ import bubble.dao.cloud.BubbleNetworkDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.account.AccountSshKey; | |||
import bubble.model.bill.AccountPlan; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -53,7 +52,7 @@ public class AccountSshKeyDAO extends AccountOwnedEntityDAO<AccountSshKey> { | |||
final Account owner = accountDAO.findByUuid(key.getAccount()); | |||
final BubbleNetwork thisNetwork = configuration.getThisNetwork(); | |||
if (thisNetwork == null || thisNetwork.getInstallType() == AnsibleInstallType.sage) { | |||
if (thisNetwork == null || thisNetwork.sage()) { | |||
// only allow installation of a key on a sage if the user is the first admin and has no keys | |||
final Account firstAdmin = accountDAO.getFirstAdmin(); | |||
if (owner.getUuid().equals(firstAdmin.getUuid())) { | |||
@@ -65,7 +64,7 @@ public class AccountSshKeyDAO extends AccountOwnedEntityDAO<AccountSshKey> { | |||
} else { | |||
// admin keys are always installed on a node | |||
// never install key for non-admin | |||
key.setInstallSshKey(owner.admin() && thisNetwork.getInstallType() == AnsibleInstallType.node); | |||
key.setInstallSshKey(owner.admin() && thisNetwork.node()); | |||
} | |||
final String hash = sha256_hex(key.getSshPublicKey()); | |||
@@ -46,7 +46,7 @@ public class BubbleNetworkDAO extends AccountOwnedEntityDAO<BubbleNetwork> { | |||
if (errors.hasSuggestedName()) network.setName(errors.getSuggestedName()); | |||
} | |||
if (!network.hasNickname()) network.setNickname(network.getName()); | |||
final AnsibleInstallType installType = network.hasForkHost() && configuration.isSageLauncher() | |||
final AnsibleInstallType installType = network.hasForkHost() && network.getLaunchType() == LaunchType.fork_sage && configuration.isSageLauncher() | |||
? AnsibleInstallType.sage | |||
: AnsibleInstallType.node; | |||
network.setInstallType(installType); | |||
@@ -57,7 +57,7 @@ public class RekeyReaderMain extends BaseMain<RekeyOptions> { | |||
} | |||
protected Iterator<Identifiable> getEntityProducer(BubbleConfiguration fromConfig, AtomicReference<Exception> error) { | |||
return new FullEntityIterator(fromConfig, null, error); | |||
return new FullEntityIterator(fromConfig, null, null, null, error); | |||
} | |||
} |
@@ -10,6 +10,7 @@ import bubble.model.account.HasNetwork; | |||
import bubble.model.cloud.BubbleDomain; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.CloudService; | |||
import bubble.model.cloud.LaunchType; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import lombok.Getter; | |||
import lombok.NoArgsConstructor; | |||
@@ -46,7 +47,7 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork { | |||
public static final String[] UPDATE_FIELDS = {"description", "paymentMethod", "paymentMethodObject"}; | |||
public static final String[] CREATE_FIELDS = ArrayUtil.append(UPDATE_FIELDS, | |||
"name", "forkHost", "locale", "timezone", "domain", "network", | |||
"name", "launchType", "forkHost", "locale", "timezone", "domain", "network", | |||
"sshKey", "syncAccount", "launchLock", "sendErrors", "sendMetrics", "plan", "footprint"); | |||
@SuppressWarnings("unused") | |||
@@ -159,6 +160,9 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork { | |||
@JsonIgnore @Transient @Getter @Setter private transient Account accountObject = null; | |||
public boolean hasAccountObject () { return account != null; } | |||
@Transient @Getter @Setter private transient LaunchType launchType = null; | |||
public boolean hasLaunchType () { return launchType != null; } | |||
@Transient @Getter @Setter private transient String forkHost = null; | |||
public boolean hasForkHost () { return !empty(forkHost); } | |||
@@ -195,6 +199,7 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork { | |||
.setFootprint(getFootprint()) | |||
.setComputeSizeType(plan.getComputeSizeType()) | |||
.setStorage(storage.getUuid()) | |||
.setLaunchType(hasForkHost() && hasLaunchType() ? getLaunchType() : LaunchType.node) | |||
.setForkHost(hasForkHost() ? getForkHost() : null); | |||
} | |||
@@ -136,6 +136,10 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu | |||
@ECIndex @Column(nullable=false, updatable=false, length=60) @ECField(index=70) | |||
@Enumerated(EnumType.STRING) | |||
@Getter @Setter private AnsibleInstallType installType; | |||
public boolean sage() { return installType == AnsibleInstallType.sage; } | |||
public boolean notSage() { return !sage(); } | |||
public boolean node() { return installType == AnsibleInstallType.node; } | |||
public boolean notNode() { return !node(); } | |||
@ECSearchable @ECField(index=80) | |||
@ECForeignKey(entity=AccountSshKey.class) | |||
@@ -146,6 +150,7 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu | |||
@ECSearchable @ECField(index=90) | |||
@ECIndex @Column(nullable=false, updatable=false, length=20) | |||
@Enumerated(EnumType.STRING) @Getter @Setter private ComputeNodeSizeType computeSizeType; | |||
public boolean local() { return computeSizeType == ComputeNodeSizeType.local; } | |||
@ECSearchable @ECField(index=100) | |||
@ECForeignKey(entity=BubbleFootprint.class) | |||
@@ -202,8 +207,11 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu | |||
public boolean hasForkHost () { return !empty(forkHost); } | |||
public boolean fork() { return hasForkHost(); } | |||
@ECSearchable @ECField(index=190) | |||
@Column(length=20) | |||
@ECField(index=190) @Column(length=20, updatable=false) | |||
@Enumerated(EnumType.STRING) @Getter @Setter private LaunchType launchType = null; | |||
public boolean hasLaunchType () { return launchType != null; } | |||
@ECSearchable @ECField(index=200) @Column(length=20) | |||
@Enumerated(EnumType.STRING) @Getter @Setter private BubbleNetworkState state = created; | |||
public String hostFromFqdn(String fqdn) { | |||
@@ -131,6 +131,8 @@ public class BubbleNode extends IdentifiableBase implements HasNetwork, HasBubbl | |||
@ECIndex @Column(nullable=false, updatable=false, length=60) | |||
@Enumerated(EnumType.STRING) | |||
@Getter @Setter private AnsibleInstallType installType; | |||
public boolean sage() { return installType == AnsibleInstallType.sage; } | |||
public boolean node() { return installType == AnsibleInstallType.node; } | |||
@ECSearchable @ECField(index=50) | |||
@ECForeignKey(entity=BubbleNode.class, cascade=false) | |||
@@ -0,0 +1,17 @@ | |||
/** | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||
*/ | |||
package bubble.model.cloud; | |||
import com.fasterxml.jackson.annotation.JsonCreator; | |||
import static bubble.ApiConstants.enumFromString; | |||
public enum LaunchType { | |||
node, fork_node, fork_sage; | |||
@JsonCreator public static LaunchType fromString(String v) { return enumFromString(LaunchType.class, v); } | |||
} |
@@ -8,6 +8,7 @@ import bubble.cloud.CloudAndRegion; | |||
import bubble.model.account.AccountContact; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.LaunchType; | |||
import bubble.model.cloud.NetLocation; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import lombok.Getter; | |||
@@ -51,6 +52,8 @@ public class NewNodeNotification { | |||
@Getter @Setter private Boolean fork; | |||
public boolean fork() { return fork != null && fork; } | |||
@Getter @Setter private LaunchType launchType; | |||
@Getter @Setter private String restoreKey; | |||
public boolean hasRestoreKey () { return !empty(restoreKey); } | |||
@@ -7,7 +7,6 @@ package bubble.notify; | |||
import bubble.dao.account.AccountDAO; | |||
import bubble.dao.account.AccountPolicyDAO; | |||
import bubble.dao.cloud.BubbleNodeDAO; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.notify.ReceivedNotification; | |||
import bubble.service.account.SyncAccountNotification; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -49,7 +48,7 @@ public class NotificationHandler_sync_account extends ReceivedNotificationHandle | |||
localAccount.getHashedPassword().setHashedPassword(incomingHashedPassword); | |||
// if we are a node, set skipSync so we don't get caught in an infinite loop | |||
// (the node would notify the sage, which would notify the node, ad infinitum) | |||
localAccount.setSkipSync(configuration.getThisNetwork().getInstallType() == AnsibleInstallType.node); | |||
localAccount.setSkipSync(configuration.getThisNetwork().node()); | |||
// update password, if we are a sage, this will notify all networks of password change | |||
accountDAO.update(localAccount); | |||
} | |||
@@ -63,7 +62,7 @@ public class NotificationHandler_sync_account extends ReceivedNotificationHandle | |||
} | |||
localPolicy.update(incomingPolicy); | |||
localPolicy.setAccountContactsJson(incomingPolicy.getAccountContactsJson()); | |||
localPolicy.setSkipSync(configuration.getThisNetwork().getInstallType() == AnsibleInstallType.node); | |||
localPolicy.setSkipSync(configuration.getThisNetwork().node()); | |||
accountPolicyDAO.update(localPolicy); | |||
} | |||
} | |||
@@ -432,8 +432,9 @@ public class AuthResource { | |||
final BubbleNetwork thisNetwork = configuration.getThisNetwork(); | |||
if (thisNetwork != null | |||
&& thisNetwork.syncAccount() | |||
&& thisNetwork.getInstallType() == AnsibleInstallType.node | |||
&& configuration.hasSageNode()) { | |||
&& thisNetwork.node() | |||
&& configuration.hasSageNode() | |||
&& !configuration.isSelfSage()) { | |||
// check if session is valid on sage | |||
@Cleanup final BubbleNodeClient sageClient = configuration.getSageNode().getApiQuickClient(configuration); | |||
try { | |||
@@ -143,12 +143,13 @@ public class BubbleConfiguration extends PgRestServerConfiguration | |||
return selfNode != null && selfNode.selfSage(); | |||
} | |||
@JsonIgnore @Transient public boolean isSageLauncher() { | |||
return isSelfSage() || !hasSageNode(); | |||
final BubbleNetwork thisNetwork = getThisNetwork(); | |||
return (isSelfSage() || !hasSageNode()) && thisNetwork.sage(); | |||
} | |||
@JsonIgnore @Transient public boolean isSage() { | |||
final BubbleNetwork thisNetwork = getThisNetwork(); | |||
return thisNetwork != null && thisNetwork.getInstallType() == AnsibleInstallType.sage; | |||
return thisNetwork != null && thisNetwork.sage(); | |||
} | |||
@JsonIgnore @Transient public synchronized BubbleNetwork getThisNetwork () { | |||
@@ -356,7 +357,7 @@ public class BubbleConfiguration extends PgRestServerConfiguration | |||
{TAG_ALLOW_REGISTRATION, thisNetwork == null ? null : thisNetwork.getBooleanTag(TAG_ALLOW_REGISTRATION, false)}, | |||
{TAG_NETWORK_UUID, thisNetwork == null ? null : thisNetwork.getUuid()}, | |||
{TAG_SAGE_LAUNCHER, thisNetwork == null || isSageLauncher()}, | |||
{TAG_BUBBLE_NODE, isSageLauncher() || thisNetwork == null ? null : thisNetwork.getInstallType() == AnsibleInstallType.node}, | |||
{TAG_BUBBLE_NODE, isSageLauncher() || thisNetwork == null ? null : thisNetwork.node()}, | |||
{TAG_PAYMENTS_ENABLED, cloudDAO.paymentsEnabled()}, | |||
{TAG_PROMO_CODE_POLICY, getPromoCodePolicy().name()}, | |||
{TAG_REQUIRE_SEND_METRICS, requireSendMetrics()}, | |||
@@ -7,14 +7,13 @@ package bubble.server.listener; | |||
import bubble.dao.account.AccountDAO; | |||
import bubble.dao.cloud.CloudServiceDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.CloudService; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.boot.SelfNodeService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.cloud.NetworkMonitorService; | |||
import bubble.service.device.DeviceService; | |||
import bubble.service.device.StandardFlexRouterService; | |||
import bubble.service.stream.AppDataCleaner; | |||
import bubble.service.stream.AppPrimerService; | |||
@@ -111,7 +110,7 @@ public class NodeInitializerListener extends RestServerLifecycleListenerBase<Bub | |||
// and start AppDataCleaner | |||
if (thisNode != null) { | |||
final BubbleNetwork thisNetwork = c.getThisNetwork(); | |||
if (thisNetwork != null && thisNetwork.getInstallType() == AnsibleInstallType.node) { | |||
if (thisNetwork != null && thisNetwork.node()) { | |||
c.getBean(AppPrimerService.class).primeApps(); | |||
c.getBean(StandardFlexRouterService.class).start(); | |||
c.getBean(DeviceService.class).initDeviceSecurityLevels(); | |||
@@ -4,7 +4,6 @@ | |||
*/ | |||
package bubble.service.account; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.service.boot.SelfNodeService; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -83,7 +82,7 @@ public class MitmControlService { | |||
public void checkMitmInstalled() { | |||
final BubbleNetwork thisNetwork = selfNodeService.getThisNetwork(); | |||
if (thisNetwork == null || thisNetwork.getInstallType() != AnsibleInstallType.node) { | |||
if (thisNetwork == null || thisNetwork.notNode()) { | |||
throw invalidEx("err.mitm.notInstalled"); | |||
} | |||
} | |||
@@ -148,8 +148,10 @@ public class StandardSelfNodeService implements SelfNodeService { | |||
// start hello sage and spare devices services, if we have a sage that is not ourselves | |||
if (!c.isSage()) { | |||
log.info("onStart: starting SageHelloService"); | |||
c.getBean(SageHelloService.class).start(); | |||
if (thisNode.node() && !c.isSelfSage()) { | |||
log.info("onStart: starting SageHelloService"); | |||
c.getBean(SageHelloService.class).start(); | |||
} | |||
log.info("onStart: building spare devices for all account that are not root account"); | |||
background(() -> { | |||
@@ -165,7 +167,7 @@ public class StandardSelfNodeService implements SelfNodeService { | |||
} | |||
// start RefundService if payments are enabled and this is a SageLauncher | |||
if (c.paymentsEnabled() && c.isSageLauncher()) { | |||
if (c.paymentsEnabled() && c.isSageLauncher() && thisNode.sage()) { | |||
log.info("onStart: starting BillingService and RefundService"); | |||
c.getBean(BillingService.class).start(); | |||
c.getBean(StandardRefundService.class).start(); | |||
@@ -435,7 +437,7 @@ public class StandardSelfNodeService implements SelfNodeService { | |||
@Override public BubblePlan getThisPlan() { | |||
final BubbleNetwork network = safeGetThisNetwork(); | |||
if (network == null) return null; | |||
if (network.getInstallType() != AnsibleInstallType.node) return null; | |||
if (network.notNode()) return null; | |||
final AccountPlan accountPlan = accountPlanDAO.findByNetwork(network.getUuid()); | |||
if (accountPlan == null) return null; | |||
return planDAO.findByUuid(accountPlan.getPlan()); | |||
@@ -451,8 +453,7 @@ public class StandardSelfNodeService implements SelfNodeService { | |||
return ttl < 0 ? Optional.empty() : Optional.of(now() + ttl * 1000); | |||
} | |||
@Override | |||
public void setLogFlag(final boolean logFlag, @NonNull final Optional<Integer> ttlInSeconds) { | |||
@Override public void setLogFlag(final boolean logFlag, @NonNull final Optional<Integer> ttlInSeconds) { | |||
if (logFlag) { | |||
getNodeConfig().set_plaintext(REDIS_LOG_FLAG_KEY, "true", EX, | |||
ttlInSeconds.orElse(isSelfSage() ? TTL_LOG_FLAG_SAGE : TTL_LOG_FLAG_NODE)); | |||
@@ -16,6 +16,7 @@ import bubble.model.bill.BubblePlanApp; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.LaunchType; | |||
import bubble.server.BubbleConfiguration; | |||
import bubble.service.dbfilter.DatabaseFilterService; | |||
import com.github.jknack.handlebars.Handlebars; | |||
@@ -61,6 +62,7 @@ public class AnsiblePrepService { | |||
ComputeServiceDriver computeDriver, | |||
ValidationResult errors, | |||
boolean fork, | |||
LaunchType launchType, | |||
String restoreKey) throws IOException { | |||
final BubbleConfiguration c = configuration; | |||
@@ -113,7 +115,7 @@ public class AnsiblePrepService { | |||
} | |||
// Copy database with new encryption key | |||
final String key = dbFilter.copyDatabase(fork, network, node, account, planApps, new File(bubbleFilesDir, "bubble.sql.gz")); | |||
final String key = dbFilter.copyDatabase(fork, launchType, network, node, account, planApps, new File(bubbleFilesDir, "bubble.sql.gz")); | |||
ctx.put("dbEncryptionKey", key); | |||
// if this is a fork, and current server is local, then sage will be self | |||
@@ -4,7 +4,6 @@ | |||
*/ | |||
package bubble.service.cloud; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.notify.NewNodeNotification; | |||
import bubble.server.BubbleConfiguration; | |||
@@ -80,7 +79,7 @@ public class NodeLaunchMonitor extends SimpleDaemon { | |||
if (thisNetwork == null) { | |||
die("register: thisNetwork is null"); | |||
} else if (configuration.isSageLauncher() || thisNetwork.getInstallType() == AnsibleInstallType.sage) { | |||
} else if (thisNetwork.sage()) { | |||
if (log.isInfoEnabled()) log.info("register: first registration, starting launch monitor"); | |||
start(); | |||
@@ -352,7 +352,7 @@ public class StandardNetworkService implements NetworkService { | |||
if (!setupOk) return launchFailureCanRetry(node, "newNode: error setting up, all retries failed for node: "+node.getUuid()); | |||
// wait for node to be ready | |||
if (node.getInstallType() == AnsibleInstallType.node) { | |||
if (node.node()) { | |||
final long readyStart = now(); | |||
boolean ready = false; | |||
Exception lastEx = null; | |||
@@ -479,7 +479,7 @@ public class StandardNetworkService implements NetworkService { | |||
progressMeter.write(METER_TICK_PREPARING_ROLES); | |||
final Map<String, Object> ctx = ansiblePrep.prepAnsible( | |||
automation, bubbleFilesDir, account, network, node, computeDriver, | |||
errors, nn.fork(), nn.getRestoreKey()); | |||
errors, nn.fork(), nn.getLaunchType(), nn.getRestoreKey()); | |||
if (errors.isInvalid()) { | |||
progressMeter.error(METER_ERROR_ROLE_VALIDATION_ERRORS); | |||
fatalLaunchFailure(node, new MultiViolationException(errors.getViolationBeans())); | |||
@@ -519,7 +519,7 @@ public class StandardNetworkService implements NetworkService { | |||
writeFile(bubbleFilesDir, null, SAGE_KEY_JSON, json(BubbleNodeKey.sageMask(sageKey))); | |||
// write packer keys if launching sage | |||
if (network.getInstallType() == AnsibleInstallType.sage) { | |||
if (network.sage()) { | |||
final File packerPubKeyFile = new File(bubbleFilesDir, PACKER_KEY_NAME+".pub"); | |||
copyFile(packerService.getPackerPublicKey(), packerPubKeyFile); | |||
@@ -726,6 +726,7 @@ public class StandardNetworkService implements NetworkService { | |||
final NewNodeNotification newNodeRequest = new NewNodeNotification() | |||
.setFork(network.fork()) | |||
.setLaunchType(network.getLaunchType()) | |||
.setNodeHost(network) | |||
.setNetLocation(netLocation) | |||
.setLock(lock); | |||
@@ -12,6 +12,7 @@ import bubble.model.account.Account; | |||
import bubble.model.bill.BubblePlanApp; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.BubbleNode; | |||
import bubble.model.cloud.LaunchType; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.Cleanup; | |||
import lombok.extern.slf4j.Slf4j; | |||
@@ -53,11 +54,12 @@ public class DatabaseFilterService { | |||
public static final String ENV_OLD_DB_KEY = "OLD_DB_KEY"; | |||
public static final String ENV_NEW_DB_KEY = "NEW_DB_KEY"; | |||
public static final String[] FLYWAY_DUMP_OPTIONS = {"--table=flyway_schema_history", "--data-only"}; | |||
public static final String[] FLYWAY_DUMP_OPTIONS = {"--table="+getFlywayTableName(), "--data-only"}; | |||
@Autowired private BubbleConfiguration configuration; | |||
public String copyDatabase(boolean fork, | |||
LaunchType launchType, | |||
BubbleNetwork network, | |||
BubbleNode node, | |||
Account account, | |||
@@ -112,7 +114,7 @@ public class DatabaseFilterService { | |||
@Override public RekeyOptions getOptions() { return readerOptions; } | |||
@Override protected Iterator<Identifiable> getEntityProducer(BubbleConfiguration fromConfig, AtomicReference<Exception> error) { | |||
return fork | |||
? new FullEntityIterator(configuration, network, readerError) | |||
? new FullEntityIterator(configuration, account, network, launchType, readerError) | |||
: new FilteredEntityIterator(configuration, account, network, node, planApps, readerError); | |||
} | |||
}.runInBackground("RekeyReaderMain.reader", readerError::set); | |||
@@ -4,32 +4,49 @@ | |||
*/ | |||
package bubble.service.dbfilter; | |||
import bubble.dao.device.DeviceDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.cloud.LaunchType; | |||
import bubble.server.BubbleConfiguration; | |||
import lombok.extern.slf4j.Slf4j; | |||
import java.util.concurrent.atomic.AtomicReference; | |||
import static bubble.model.device.Device.newUninitializedDevice; | |||
import static org.cobbzilla.wizard.dao.AbstractCRUDDAO.ORDER_CTIME_ASC; | |||
@Slf4j | |||
public class FullEntityIterator extends EntityIterator { | |||
private final BubbleConfiguration config; | |||
private final Account account; | |||
private final BubbleNetwork network; | |||
private final LaunchType launchType; | |||
public FullEntityIterator (BubbleConfiguration config, | |||
Account account, | |||
BubbleNetwork network, | |||
LaunchType launchType, | |||
AtomicReference<Exception> error) { | |||
super(error); | |||
this.config = config; | |||
this.network = network; | |||
this.account = account; | |||
this.launchType = launchType; | |||
} | |||
protected void iterate() { | |||
config.getEntityClasses() | |||
.forEach(c -> addEntities(true, c, config.getDaoForEntityClass(c).findAll(ORDER_CTIME_ASC), | |||
network, null, null)); | |||
if (account != null && launchType != null && launchType == LaunchType.fork_node) { | |||
// add an initial device so that algo starts properly the first time | |||
// name and totp key will be overwritten when the device is initialized for use | |||
log.info("iterate: creating a single dummy device for algo to start properly"); | |||
final var initDevice = newUninitializedDevice(network.getUuid(), account.getUuid()); | |||
add(config.getBean(DeviceDAO.class).create(initDevice)); | |||
} | |||
log.info("iterate: completed"); | |||
} | |||
@@ -9,7 +9,6 @@ import bubble.dao.app.*; | |||
import bubble.dao.device.DeviceDAO; | |||
import bubble.model.account.Account; | |||
import bubble.model.app.*; | |||
import bubble.model.cloud.AnsibleInstallType; | |||
import bubble.model.cloud.BubbleNetwork; | |||
import bubble.model.device.Device; | |||
import bubble.rule.AppRuleDriver; | |||
@@ -54,7 +53,7 @@ public class StandardAppPrimerService implements AppPrimerService { | |||
log.info("initPrimingEnabled: thisNetwork is null, not priming"); | |||
return false; | |||
} | |||
if (thisNetwork.getInstallType() != AnsibleInstallType.node) { | |||
if (thisNetwork.notNode()) { | |||
log.info("initPrimingEnabled: thisNetwork is not a node, not priming"); | |||
return false; | |||
} | |||
@@ -1 +1 @@ | |||
bubble.version=Adventure 1.2.1 | |||
bubble.version=Adventure 1.2.2 |
@@ -0,0 +1 @@ | |||
ALTER TABLE bubble_network ADD COLUMN launch_type VARCHAR(200); |
@@ -1 +1 @@ | |||
Subproject commit 61fc9667c4c66c0bcbbb8eb4d128e8ab58f50869 | |||
Subproject commit 9d1ecac6514696721effe012e9c726896c368ebe |
@@ -25,7 +25,6 @@ from bubble_config import bubble_port, debug_capture_fqdn, \ | |||
from mitmproxy import http | |||
from mitmproxy.net.http import headers as nheaders | |||
from mitmproxy.proxy.protocol.async_stream_body import AsyncStreamBody | |||
from mitmproxy.proxy.protocol.request_capture import RequestCapture | |||
bubble_log = logging.getLogger(__name__) | |||
@@ -401,7 +400,7 @@ def is_bubble_health_check(path): | |||
def is_sage_request(ip, fqdns): | |||
return (ip == bubble_sage_ip4 or ip == bubble_sage_ip6) and bubble_sage_host in fqdns | |||
return fqdns is not None and (ip == bubble_sage_ip4 or ip == bubble_sage_ip6) and bubble_sage_host in fqdns | |||
def is_not_from_vpn(client_addr): | |||
@@ -416,7 +415,7 @@ def is_flex_domain(client_addr, server_addr, fqdns): | |||
return False | |||
fqdn = fqdns[0] | |||
if fqdn == bubble_host or fqdn == bubble_host_alias or fqdn == bubble_sage_host: | |||
if fqdn == bubble_host or fqdn == bubble_host_alias or (bubble_sage_host is not None and fqdn == bubble_sage_host): | |||
if bubble_log.isEnabledFor(DEBUG): | |||
bubble_log.debug('is_flex_domain: (early) returning False for: '+fqdn) | |||
return False | |||
@@ -1 +1 @@ | |||
Subproject commit 66d46695a64ff58934560c4b35aa43a0ab32fbe2 | |||
Subproject commit 37dd89bd78949a63c68a64596b4e1c105809a577 |
@@ -1 +1 @@ | |||
Subproject commit dfafe62c7eb3413cf1210e40e551094458f4d9d0 | |||
Subproject commit fab2bdafe756fc53ff80b58171fb9000846bf0ef |