Quellcode durchsuchen

replace all hardcoded refs to root as admin username. admin username is set during activation.

tags/v1.4.17
Jonathan Cobb vor 4 Jahren
Ursprung
Commit
96a8a8ebbf
17 geänderte Dateien mit 112 neuen und 26 gelöschten Zeilen
  1. +3
    -2
      bubble-server/src/main/java/bubble/dao/account/AccountDAO.java
  2. +1
    -1
      bubble-server/src/main/java/bubble/dao/device/DeviceDAO.java
  3. +0
    -1
      bubble-server/src/main/java/bubble/model/account/Account.java
  4. +5
    -1
      bubble-server/src/main/java/bubble/model/bill/AccountPlan.java
  5. +5
    -1
      bubble-server/src/main/java/bubble/model/boot/ActivationRequest.java
  6. +3
    -0
      bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java
  7. +8
    -1
      bubble-server/src/main/java/bubble/model/cloud/LaunchType.java
  8. +5
    -0
      bubble-server/src/main/java/bubble/resources/account/AuthResource.java
  9. +14
    -2
      bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java
  10. +2
    -2
      bubble-server/src/main/java/bubble/resources/cloud/ComputePackerResource.java
  11. +16
    -0
      bubble-server/src/main/java/bubble/service/boot/ActivationService.java
  12. +5
    -5
      bubble-server/src/main/java/bubble/service/boot/StandardSelfNodeService.java
  13. +24
    -4
      bubble-server/src/main/java/bubble/service/dbfilter/EntityIterator.java
  14. +1
    -1
      bubble-server/src/main/resources/messages
  15. +1
    -1
      bubble-web
  16. +18
    -3
      config/activation.json
  17. +1
    -1
      utils/cobbzilla-utils

+ 3
- 2
bubble-server/src/main/java/bubble/dao/account/AccountDAO.java Datei anzeigen

@@ -164,7 +164,7 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc

// create an uninitialized device for the account, but only if this is a regular node network
// sage networks do not allow devices, they launch and manage other regular node networks
if (!account.isRoot() && !configuration.isSage()) {
if (!isFirstAdmin(account) && !configuration.isSage()) {
deviceDAO.ensureAllSpareDevices(account.getUuid(), configuration.getThisNetwork().getUuid());
deviceDAO.refreshVpnUsers();
}
@@ -475,7 +475,8 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc
private final Refreshable<Account> firstAdmin = new Refreshable<>("firstAdmin", FIRST_ADMIN_CACHE_MILLIS, this::findFirstAdmin);
public Account getFirstAdmin() { return firstAdmin.get(); }

public boolean isFirstAdmin(Account account) { return getFirstAdmin().getUuid().equals(account.getUuid()); }
public boolean isFirstAdmin(Account account) { return isFirstAdmin(account.getUuid()); }
public boolean isFirstAdmin(String accountUuid) { return getFirstAdmin().getUuid().equals(accountUuid); }

public Account findFirstAdmin() {
final List<Account> admins = findByField("admin", true);


+ 1
- 1
bubble-server/src/main/java/bubble/dao/device/DeviceDAO.java Datei anzeigen

@@ -81,7 +81,7 @@ public class DeviceDAO extends AccountOwnedEntityDAO<Device> {
var uninitializedDevices = findByAccountAndUninitialized(accountUuid);

if (uninitializedDevices.size() <= SPARE_DEVICES_PER_ACCOUNT_THRESHOLD
&& !configuration.getBean(AccountDAO.class).findByUuid(accountUuid).isRoot()) {
&& !configuration.getBean(AccountDAO.class).isFirstAdmin(accountUuid)) {
if (ensureAllSpareDevices(accountUuid, device.getNetwork())) refreshVpnUsers();
}



+ 0
- 1
bubble-server/src/main/java/bubble/model/account/Account.java Datei anzeigen

@@ -112,7 +112,6 @@ public class Account extends IdentifiableBaseParentEntity implements TokenPrinci

@Override @Transient public String getName() { return getEmail(); }
public Account setName(String n) { return setEmail(n); }
@Transient @JsonIgnore public boolean isRoot() { return getName().equals(ROOT_USERNAME); }

// make this updatable if we ever want accounts to be able to change parents
// there might be a lot more involved in that action though (read-only parent objects that will no longer be visible, must be copied in?)


+ 5
- 1
bubble-server/src/main/java/bubble/model/bill/AccountPlan.java Datei anzeigen

@@ -166,6 +166,9 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork {
@Transient @Getter @Setter private transient String forkHost = null;
public boolean hasForkHost () { return !empty(forkHost); }

@Transient @Getter @Setter private transient String adminEmail = null;
public boolean hasAdminEmail() { return !empty(adminEmail); }

@Transient @Getter @Setter private transient Boolean syncAccount = null;
public boolean syncAccount() { return syncAccount == null || syncAccount; }

@@ -200,7 +203,8 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork {
.setComputeSizeType(plan.getComputeSizeType())
.setStorage(storage.getUuid())
.setLaunchType(hasForkHost() && hasLaunchType() ? getLaunchType() : LaunchType.node)
.setForkHost(hasForkHost() ? getForkHost() : null);
.setForkHost(hasForkHost() ? getForkHost() : null)
.setAdminEmail(hasAdminEmail() ? getAdminEmail() : null);
}

}

+ 5
- 1
bubble-server/src/main/java/bubble/model/boot/ActivationRequest.java Datei anzeigen

@@ -23,7 +23,8 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
public class ActivationRequest {

@HasValue(message="err.email.required")
@Getter @Setter private String email;
@Getter private String email;
public ActivationRequest setEmail(String e) { this.email = empty(e) ? e : e.trim(); return this; }
public boolean hasEmail() { return !empty(email); }

public String getName() { return getEmail(); }
@@ -55,6 +56,9 @@ public class ActivationRequest {
@Getter @Setter private Boolean skipTests = false;
public boolean skipTests () { return bool(skipTests); };

@Getter @Setter private Boolean skipPacker = false;
public boolean skipPacker () { return bool(skipPacker); };

@Getter @Setter private AccountSshKey sshKey;
public boolean hasSshKey () { return sshKey != null; }



+ 3
- 0
bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java Datei anzeigen

@@ -208,6 +208,9 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu
public boolean hasForkHost () { return !empty(forkHost); }
public boolean fork() { return hasForkHost(); }

@Transient @Getter @Setter private transient String adminEmail;
public boolean hasAdminEmail () { return !empty(adminEmail); }

@ECField(index=190) @Column(length=20, updatable=false)
@Enumerated(EnumType.STRING) @Getter @Setter private LaunchType launchType = null;
public boolean hasLaunchType () { return launchType != null; }


+ 8
- 1
bubble-server/src/main/java/bubble/model/cloud/LaunchType.java Datei anzeigen

@@ -5,13 +5,20 @@
package bubble.model.cloud;

import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.AllArgsConstructor;

import static bubble.ApiConstants.enumFromString;

@AllArgsConstructor
public enum LaunchType {

node, fork_node, fork_sage;
node (false),
fork_node (true),
fork_sage (true);

@JsonCreator public static LaunchType fromString(String v) { return enumFromString(LaunchType.class, v); }

private final boolean fork;
public boolean fork () { return fork; }

}

+ 5
- 0
bubble-server/src/main/java/bubble/resources/account/AuthResource.java Datei anzeigen

@@ -166,6 +166,11 @@ public class AuthResource {
if (accountDAO.activated()) {
return invalid("err.activation.alreadyDone", "activation has already been done");
}

if (!request.hasEmail()) return invalid("err.email.required", "email is required");
if (request.getEmail().contains("{{") && request.getEmail().contains("}}")) {
request.setEmail(configuration.applyHandlebars(request.getEmail()).trim());
}
if (!request.hasEmail()) return invalid("err.email.required", "email is required");

if (!request.hasPassword()) return invalid("err.password.required", "password is required");


+ 14
- 2
bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java Datei anzeigen

@@ -41,10 +41,10 @@ import java.util.List;
import java.util.stream.Collectors;

import static bubble.ApiConstants.*;
import static bubble.model.account.Account.ROOT_EMAIL;
import static bubble.model.cloud.BubbleNetwork.validateHostname;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.string.ValidationRegexes.HOST_PATTERN;
import static org.cobbzilla.util.string.ValidationRegexes.validateRegexMatches;
import static org.cobbzilla.util.string.ValidationRegexes.*;
import static org.cobbzilla.wizard.model.NamedEntity.NAME_MAXLEN;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;

@@ -167,6 +167,18 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco
validateName(request, errors);
}
}
final String adminEmail = request.getAdminEmail();
if (request.hasLaunchType() && request.getLaunchType().fork() && caller.admin()) {
if (empty(adminEmail) && caller.getEmail().equals(ROOT_EMAIL)) {
errors.addViolation("err.adminEmail.required");
} else if (!empty(adminEmail) && !validateRegexMatches(EMAIL_PATTERN, adminEmail)) {
errors.addViolation("err.adminEmail.invalid");
}
} else {
if (!empty(adminEmail)) {
errors.addViolation("err.adminEmail.cannotSet");
}
}
} else {
if (!request.hasNickname()) {
if (!request.hasName()) request.setName(newNetworkName());


+ 2
- 2
bubble-server/src/main/java/bubble/resources/cloud/ComputePackerResource.java Datei anzeigen

@@ -28,8 +28,8 @@ public class ComputePackerResource {
@Autowired private BubbleConfiguration configuration;
@Autowired private PackerService packer;

private Account account;
private CloudService cloud;
private final Account account;
private final CloudService cloud;

public ComputePackerResource (Account account, CloudService cloud) {
this.account = account;


+ 16
- 0
bubble-server/src/main/java/bubble/service/boot/ActivationService.java Datei anzeigen

@@ -18,6 +18,7 @@ import bubble.model.boot.ActivationRequest;
import bubble.model.boot.CloudServiceConfig;
import bubble.model.cloud.*;
import bubble.server.BubbleConfiguration;
import bubble.service.packer.PackerService;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Cleanup;
import lombok.Getter;
@@ -64,6 +65,7 @@ public class ActivationService {
@Autowired private StandardSelfNodeService selfNodeService;
@Autowired private BubbleConfiguration configuration;
@Autowired private ModelSetupService modelSetupService;
@Autowired private PackerService packerService;

public BubbleNode bootstrapThisNode(Account account, ActivationRequest request) {
String ip = getFirstPublicIpv4();
@@ -228,12 +230,26 @@ public class ActivationService {
final Map<CrudOperation, Collection<Identifiable>> objects
= modelSetupService.setupModel(api, account, "manifest-defaults");
log.info("bootstrapThisNode: created default objects\n"+json(objects));

if (!request.skipPacker()) initialPacker(account);

}, "ActivationService.bootstrapThisNode.createDefaultObjects");

} else if (!request.skipPacker()) {
initialPacker(account);
}

return node;
}

private void initialPacker(Account account) {
for (CloudService cloud : cloudDAO.findByAccountAndType(account.getUuid(), CloudServiceType.compute)) {
log.info("initialPacker: creating images for compute cloud: "+cloud.getName());
packerService.writePackerImages(cloud, AnsibleInstallType.sage, null);
packerService.writePackerImages(cloud, AnsibleInstallType.node, null);
}
}

public BubbleNetwork createRootNetwork(BubbleNetwork network) {
network.setUuid(ROOT_NETWORK_UUID);
return networkDAO.create(network);


+ 5
- 5
bubble-server/src/main/java/bubble/service/boot/StandardSelfNodeService.java Datei anzeigen

@@ -15,10 +15,12 @@ import bubble.dao.cloud.BubbleNodeDAO;
import bubble.dao.cloud.BubbleNodeKeyDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.dao.device.DeviceDAO;
import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import bubble.model.bill.BubblePlan;
import bubble.model.cloud.*;
import bubble.model.cloud.BubbleNetwork;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.BubbleNodeKey;
import bubble.model.cloud.BubbleNodeState;
import bubble.model.cloud.notify.NotificationReceipt;
import bubble.model.cloud.notify.NotificationType;
import bubble.server.BubbleConfiguration;
@@ -29,7 +31,6 @@ import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.cache.Refreshable;
import org.cobbzilla.util.daemon.SimpleDaemon;
import org.cobbzilla.util.http.HttpSchemes;
import org.cobbzilla.util.http.HttpUtil;
import org.cobbzilla.util.io.FileUtil;
@@ -53,7 +54,6 @@ import static bubble.server.BubbleServer.disableRestoreMode;
import static bubble.server.BubbleServer.isRestoreMode;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.function.Predicate.not;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.io.FileUtil.toFileOrDie;
@@ -162,7 +162,7 @@ public class StandardSelfNodeService implements SelfNodeService {
background(() -> {
if (accountDAO.findAll()
.stream()
.filter(not(Account::isRoot))
.filter(a -> !accountDAO.isFirstAdmin(a))
.map(a -> deviceDAO.ensureAllSpareDevices(a.getUuid(), thisNetworkUuid))
.reduce(false, Boolean::logicalOr)
.booleanValue()) {


+ 24
- 4
bubble-server/src/main/java/bubble/service/dbfilter/EntityIterator.java Datei anzeigen

@@ -7,9 +7,7 @@ package bubble.service.dbfilter;
import bubble.cloud.CloudServiceType;
import bubble.cloud.storage.local.LocalStorageConfig;
import bubble.cloud.storage.local.LocalStorageDriver;
import bubble.model.account.Account;
import bubble.model.account.AccountSshKey;
import bubble.model.account.AccountTemplate;
import bubble.model.account.*;
import bubble.model.app.AppTemplateEntity;
import bubble.model.app.BubbleApp;
import bubble.model.bill.AccountPaymentMethod;
@@ -135,7 +133,29 @@ public abstract class EntityIterator implements Iterator<Identifiable> {
.forEach(this::add);

} else if (Account.class.isAssignableFrom(c)) {
entities.forEach(e -> add(((Account) e).setPreferredPlan(null)));
entities.forEach(e -> {
if (network.hasAdminEmail() && network.getAccount().equals(e.getUuid())) {
final Account a = (Account) e;
a.setEmail(network.getAdminEmail());
}
add(((Account) e).setPreferredPlan(null));
});

} else if (AccountPolicy.class.isAssignableFrom(c) && network.hasAdminEmail()) {
entities.forEach(e -> {
if (network.hasAdminEmail()) {
final AccountPolicy p = (AccountPolicy) e;
if (p.getAccount().equals(network.getAccount())) {
final AccountContact adminContact = new AccountContact()
.setType(CloudServiceType.email)
.setInfo(network.getAdminEmail())
.setVerified(true)
.setRemovable(false);
p.setAccountContacts(new AccountContact[]{adminContact});
}
}
add(e);
});

} else if (AccountSshKey.class.isAssignableFrom(c)) {
entities.forEach(e -> add(setInstallKey((AccountSshKey) e, network)));


+ 1
- 1
bubble-server/src/main/resources/messages

@@ -1 +1 @@
Subproject commit 6557ae47aae789ce6dc6ff1aca189787a89103bb
Subproject commit c0070a05666df680157c6740879ad5a3c98c3bba

+ 1
- 1
bubble-web

@@ -1 +1 @@
Subproject commit b7120e4099a382278c43813644f99e928c9ae828
Subproject commit 290017992084da8d799aba24409099d54c1a9305

+ 18
- 3
config/activation.json Datei anzeigen

@@ -54,9 +54,9 @@
}
},

// You must configure the an SMTP service, it is required to send emails
// SendGrid, MailGun, or any other SMTP service should work fine
"SmtpServer": {
// You must configure an email service, it is required to send emails
// Comment out the email clouds that you don't use
"SmtpEmail": {
"config": {
"tlsEnabled": true
},
@@ -68,6 +68,21 @@
}
},

"SendGridEmail": {
"config": {},
"credentials": {
"apiKey": "your_sendgrid_api_key"
}
},

"MailgunEmail": {
"config": {},
"credentials": {
"domain": "your_mailgun_domain",
"apiKey": "your_mailgun_api_key"
}
},

// Required for TOTP-based authentication. Nothing to configure, just leave this as-is
"TOTPAuthenticator": {},



+ 1
- 1
utils/cobbzilla-utils

@@ -1 +1 @@
Subproject commit d7ea904f35401302cbfb4bde5d70475d2721df07
Subproject commit d3b5e5254c2eca16290dc5746d0ab489160a8ff1

Laden…
Abbrechen
Speichern