Преглед на файлове

Sync account plans if sync is set for account

pull/52/head
Kristijan Mitrovic преди 4 години
родител
ревизия
c22a049281
променени са 7 файла, в които са добавени 152 реда и са изтрити 44 реда
  1. +23
    -1
      bubble-server/src/main/java/bubble/dao/bill/AccountPlanDAO.java
  2. +3
    -0
      bubble-server/src/main/java/bubble/model/bill/AccountPlan.java
  3. +68
    -26
      bubble-server/src/main/java/bubble/notify/NotificationHandler_sync_account.java
  4. +25
    -12
      bubble-server/src/main/java/bubble/service/account/StandardSyncAccountService.java
  5. +18
    -3
      bubble-server/src/main/java/bubble/service/account/SyncAccountNotification.java
  6. +5
    -1
      bubble-server/src/main/java/bubble/service/account/SyncAccountService.java
  7. +10
    -1
      bubble-server/src/main/java/bubble/service_dbfilter/DbFilterSyncAccountService.java

+ 23
- 1
bubble-server/src/main/java/bubble/dao/bill/AccountPlanDAO.java Целия файл

@@ -9,6 +9,7 @@ import bubble.dao.account.AccountDAO;
import bubble.dao.account.AccountOwnedEntityDAO;
import bubble.dao.cloud.BubbleNetworkDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import bubble.model.bill.Bill;
import bubble.model.bill.BubblePlan;
@@ -18,8 +19,10 @@ import bubble.model.cloud.CloudService;
import bubble.model.cloud.HostnameValidationResult;
import bubble.notify.payment.PaymentValidationResult;
import bubble.server.BubbleConfiguration;
import bubble.service.account.SyncAccountService;
import bubble.service.bill.RefundService;
import bubble.service.cloud.NetworkService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@@ -166,9 +169,20 @@ public class AccountPlanDAO extends AccountOwnedEntityDAO<AccountPlan> {
paymentDriver.purchase(accountPlanUuid, paymentMethodUuid, billUuid);
});
}

final var account = accountDAO.findByUuid(accountPlan.getAccount());
configuration.getBean(SyncAccountService.class).syncPlan(account, accountPlan);

return super.postCreate(accountPlan, context);
}

@Override public AccountPlan postUpdate(@NonNull final AccountPlan accountPlan, @NonNull final Object context) {
final var account = accountDAO.findByUuid(accountPlan.getAccount());
configuration.getBean(SyncAccountService.class).syncPlan(account, accountPlan);

return super.postUpdate(accountPlan, context);
}

@Override public void delete(String uuid) {
final AccountPlan accountPlan = findByUuid(uuid);
if (accountPlan == null) return;
@@ -193,6 +207,14 @@ public class AccountPlanDAO extends AccountOwnedEntityDAO<AccountPlan> {
}
}

@Override public void forceDelete(String uuid) { super.delete(uuid); }
@Override public void forceDelete(String uuid) {
final AccountPlan accountPlan = findByUuid(uuid);
final Account account = accountDAO.findByUuid(accountPlan.getAccount());

super.delete(uuid);

configuration.getBean(SyncAccountService.class).syncForceDeletedPlan(account, accountPlan.getName());
}
public void forceDeleteWithoutSync(String uuid) { super.delete(uuid); }

}

+ 3
- 0
bubble-server/src/main/java/bubble/model/bill/AccountPlan.java Целия файл

@@ -174,6 +174,9 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork {
@Transient @Getter @Setter private transient Boolean sendMetrics = null;
public boolean sendMetrics () { return sendMetrics == null || sendMetrics; }

@JsonIgnore @Transient @Getter @Setter private Boolean skipSync;
public boolean skipSync() { return bool(skipSync); }

public BubbleNetwork bubbleNetwork(Account account,
BubbleDomain domain,
BubblePlan plan,


+ 68
- 26
bubble-server/src/main/java/bubble/notify/NotificationHandler_sync_account.java Целия файл

@@ -5,12 +5,14 @@
package bubble.notify;

import bubble.dao.account.AccountDAO;
import bubble.dao.bill.AccountPlanDAO;
import bubble.dao.cloud.BubbleNodeDAO;
import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import bubble.model.cloud.AnsibleInstallType;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.notify.ReceivedNotification;
import bubble.service.account.SyncAccountNotification;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

@@ -22,34 +24,74 @@ public class NotificationHandler_sync_account extends ReceivedNotificationHandle

@Autowired private BubbleNodeDAO nodeDAO;
@Autowired private AccountDAO accountDAO;
@Autowired private AccountPlanDAO accountPlanDAO;

@Override public void handleNotification(ReceivedNotification n) {
final BubbleNode node = nodeDAO.findByUuid(n.getFromNode());
@Override
public void handleNotification(ReceivedNotification n) {
final var node = nodeDAO.findByUuid(n.getFromNode());
if (node == null) {
log.warn("sync_account: node not found: "+n.getFromNode());
log.warn("sync_account: node not found: " + n.getFromNode());
return;
}

final var notification = json(n.getPayloadJson(), SyncAccountNotification.class);

final var localAccount = accountDAO.findByUuid(notification.getAccountUuid());
if (localAccount == null) {
reportError("sync_account: localAccount not found: " + notification.getAccountUuid());
return;
}
if (!localAccount.sync()) {
log.info("sync_account: localAccount " + localAccount.getName() + " has sync disabled, no sync done");
return;
}

if (notification.getHashedPassword().isPresent()) {
syncAccountPassword(localAccount, notification.getHashedPassword().get());
}
if (notification.getAccountPlan().isPresent()) {
syncAccountPlan(localAccount.getUuid(), notification.getAccountPlan().get());
}
if (notification.getForceDeletedAccountPlanName().isPresent()) {
syncForceDelAccountPlan(localAccount.getUuid(), notification.getForceDeletedAccountPlanName().get());
}
}

private void syncAccountPassword(@NonNull final Account localAccount,
@NonNull final String incomingHashedPassword) {
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);

// update password, if we are a sage, this will notify all networks of password change
accountDAO.update(localAccount);
}

private void syncAccountPlan(@NonNull final String accountUuid, @NonNull final AccountPlan incomingPlan) {
final var localPlan = accountPlanDAO.findByAccountAndId(accountUuid, incomingPlan.getName());

if (localPlan == null) {
// create new localPlan
final var newPlan = new AccountPlan(incomingPlan);
newPlan.setSkipSync(configuration.getThisNetwork().getInstallType() == AnsibleInstallType.node);
accountPlanDAO.create(newPlan);
} else {
// update localPlan
localPlan.update(incomingPlan);
localPlan.setSkipSync(configuration.getThisNetwork().getInstallType() == AnsibleInstallType.node);
accountPlanDAO.update(localPlan);
}
}

private void syncForceDelAccountPlan(@NonNull final String accountUuid, @NonNull final String planName) {
final var localPlan = accountPlanDAO.findByAccountAndId(accountUuid, planName);

if (configuration.getThisNetwork().getInstallType() == AnsibleInstallType.node) {
accountPlanDAO.forceDeleteWithoutSync(localPlan.getUuid());
} else {
final SyncAccountNotification notification = json(n.getPayloadJson(), SyncAccountNotification.class);

final Account account = accountDAO.findByUuid(notification.getAccountUuid());
if (account == null) {
reportError("sync_account: account not found: "+notification.getAccountUuid());
return;
}
if (!account.sync()) {
log.info("sync_account: account "+account.getName()+" has sync disabled, not synchronizing");
return;
}

account.getHashedPassword().setHashedPassword(notification.getHashedPassword());

// 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)
if (configuration.getThisNetwork().getInstallType() == AnsibleInstallType.node) {
account.setSkipSync(true);
}

// update password, if we are a sage, this will notify all networks of password change
accountDAO.update(account);
accountPlanDAO.forceDelete(localPlan.getUuid());
}
}



+ 25
- 12
bubble-server/src/main/java/bubble/service/account/StandardSyncAccountService.java Целия файл

@@ -7,12 +7,14 @@ package bubble.service.account;
import bubble.dao.cloud.BubbleNetworkDAO;
import bubble.dao.cloud.BubbleNodeDAO;
import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import bubble.model.cloud.AnsibleInstallType;
import bubble.model.cloud.BubbleNetwork;
import bubble.model.cloud.BubbleNetworkState;
import bubble.model.cloud.BubbleNode;
import bubble.server.BubbleConfiguration;
import bubble.service.notify.NotificationService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -28,51 +30,62 @@ public class StandardSyncAccountService implements SyncAccountService {
@Autowired private NotificationService notificationService;
@Autowired private BubbleConfiguration configuration;

public void syncAccount(Account account) {
public void syncAccount(@NonNull final Account account) {
sync(account, new SyncAccountNotification(account));
}

public void syncPlan(@NonNull final Account account, @NonNull final AccountPlan accountPlan) {
sync(account, new SyncAccountNotification(account.getUuid(), accountPlan));
}

public void syncForceDeletedPlan(@NonNull final Account account, @NonNull final String accountPlanName) {
sync(account, new SyncAccountNotification(account.getUuid(), accountPlanName));
}

private void sync(@NonNull final Account account, @NonNull final SyncAccountNotification notification) {
final BubbleNetwork thisNetwork = configuration.getThisNetwork();
if (thisNetwork == null) {
// should never happen
log.warn("syncAccount: thisNetwork was null, sync_account is impossible");
log.warn("sync: thisNetwork was null, sync_account is impossible");
return;
}
if (!account.admin()) {
log.info("syncAccount: not syncing non-admin password");
log.info("sync: not syncing non-admin account");
return;
}
if (!account.sync()) {
log.info("syncAccount: password sync disabled for account: "+account.getName());
log.info("sync: account sync disabled for account: "+account.getName());
return;
}
final AnsibleInstallType installType = thisNetwork.getInstallType();
final SyncAccountNotification notification = new SyncAccountNotification(account);
if (installType == AnsibleInstallType.sage) {
// changing password on sage, notify all bubbles launched by user that have syncAccount == true
// changing account on sage, notify all bubbles launched by user that have syncAccount == true

for (BubbleNetwork network : networkDAO.findByAccount(account.getUuid())) {
if (network.getState() != BubbleNetworkState.running) continue;
if (!network.syncAccount()) continue;
for (BubbleNode node : nodeDAO.findByNetwork(network.getUuid())) {
if (node.getUuid().equals(configuration.getThisNode().getUuid())) {
log.info("syncAccount: not notifying self");
log.info("sync: not notifying self");
continue;
}
log.info("syncAccount: sending sync_account notification from sage to node: "+node.id());
log.info("sync: sending sync_account notification from sage to node: "+node.id());
notificationService.notify(node, sync_account, notification);
}
}

} else if (installType == AnsibleInstallType.node) {
if (!thisNetwork.syncAccount()) {
log.info("syncAccount: disabled for node, not sending sync_account notification");
log.info("sync: disabled for node, not sending sync_account notification");
return;
}
// changing password on node, notify sage, which will then notify all bubbles launched by user that have
// changing account on node, notify sage, which will then notify all bubbles launched by user that have
// syncAccount == true
log.info("syncAccount: sending sync_account notification from node to sage: "+configuration.getSageNode());
log.info("sync: sending sync_account notification from node to sage: "+configuration.getSageNode());
notificationService.notify(configuration.getSageNode(), sync_account, notification);

} else {
reportError("syncAccount("+account.getEmail()+"/"+account.getUuid()+"): invalid installType: "+installType);
reportError("sync("+account.getEmail()+"/"+account.getUuid()+"): invalid installType: "+installType);
}
}



+ 18
- 3
bubble-server/src/main/java/bubble/service/account/SyncAccountNotification.java Целия файл

@@ -5,20 +5,35 @@
package bubble.service.account;

import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.util.Optional;

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

@Getter @Setter private String accountUuid;
@Getter @Setter private String hashedPassword;
@Getter @Setter private Optional<String> hashedPassword = Optional.empty();
@Getter @Setter private Optional<AccountPlan> accountPlan = Optional.empty();
@Getter @Setter private Optional<String> forceDeletedAccountPlanName = Optional.empty();

public SyncAccountNotification(Account account) {
public SyncAccountNotification(@NonNull final Account account) {
this.accountUuid = account.getUuid();
this.hashedPassword = account.getHashedPassword().getHashedPassword();
this.hashedPassword = Optional.of(account.getHashedPassword().getHashedPassword());
}

public SyncAccountNotification(@NonNull final String accountUuid, @NonNull final AccountPlan accountPlan) {
this.accountUuid = accountUuid;
this.accountPlan = Optional.of(accountPlan);
}

public SyncAccountNotification(@NonNull final String accountUuid, @NonNull final String forceDeletedPlanUuid) {
this.accountUuid = accountUuid;
this.forceDeletedAccountPlanName = Optional.of(forceDeletedPlanUuid);
}
}

+ 5
- 1
bubble-server/src/main/java/bubble/service/account/SyncAccountService.java Целия файл

@@ -5,9 +5,13 @@
package bubble.service.account;

import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import lombok.NonNull;

public interface SyncAccountService {

void syncAccount(Account account);
void syncAccount(@NonNull final Account account);
void syncPlan(@NonNull final Account account, @NonNull final AccountPlan accountPlan);
void syncForceDeletedPlan(@NonNull final Account account, @NonNull final String accountPlanName);

}

+ 10
- 1
bubble-server/src/main/java/bubble/service_dbfilter/DbFilterSyncAccountService.java Целия файл

@@ -5,7 +5,9 @@
package bubble.service_dbfilter;

import bubble.model.account.Account;
import bubble.model.bill.AccountPlan;
import bubble.service.account.SyncAccountService;
import lombok.NonNull;
import org.springframework.stereotype.Service;

import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported;
@@ -13,6 +15,13 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported;
@Service
public class DbFilterSyncAccountService implements SyncAccountService {

@Override public void syncAccount(Account account) { notSupported("syncAccount"); }
@Override public void syncAccount(@NonNull final Account account) { notSupported("syncAccount"); }
@Override public void syncPlan(@NonNull final Account account, @NonNull final AccountPlan accountPlan) {
notSupported("syncPlan");
}

@Override public void syncForceDeletedPlan(@NonNull final Account account, @NonNull final String accountPlanName) {
notSupported("syncForceDeletedPlan");
}

}

Зареждане…
Отказ
Запис