@@ -278,6 +278,7 @@ public class ApiConstants { | |||||
public static String getReferer(ContainerRequest ctx) { return ctx.getHeaderString(REFERER); } | public static String getReferer(ContainerRequest ctx) { return ctx.getHeaderString(REFERER); } | ||||
public static final String DETECT_LOCALE = "detect"; | public static final String DETECT_LOCALE = "detect"; | ||||
public static final String DETECT_TIMEZONE = "detect"; | |||||
public static List<String> getLocales(ContainerRequest ctx, String defaultLocale) { | public static List<String> getLocales(ContainerRequest ctx, String defaultLocale) { | ||||
final List<String> locales = new ArrayList<>(); | final List<String> locales = new ArrayList<>(); | ||||
@@ -21,6 +21,7 @@ import java.util.List; | |||||
import static org.cobbzilla.util.daemon.ZillaRuntime.now; | import static org.cobbzilla.util.daemon.ZillaRuntime.now; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | ||||
import static org.hibernate.criterion.Restrictions.*; | |||||
@Repository @Slf4j | @Repository @Slf4j | ||||
public class AccountPaymentMethodDAO extends AccountOwnedEntityDAO<AccountPaymentMethod> { | public class AccountPaymentMethodDAO extends AccountOwnedEntityDAO<AccountPaymentMethod> { | ||||
@@ -42,6 +43,14 @@ public class AccountPaymentMethodDAO extends AccountOwnedEntityDAO<AccountPaymen | |||||
return findByFields("account", account, "paymentMethodType", PaymentMethodType.promotional_credit, "deleted", null); | return findByFields("account", account, "paymentMethodType", PaymentMethodType.promotional_credit, "deleted", null); | ||||
} | } | ||||
public List<AccountPaymentMethod> findByAccountAndNotPromoAndNotDeleted(String account) { | |||||
return list(criteria().add(and( | |||||
eq("account", account), | |||||
ne("paymentMethodType", PaymentMethodType.promotional_credit), | |||||
isNull("deleted") | |||||
))); | |||||
} | |||||
public List<AccountPaymentMethod> findByAccountAndCloud(String accountUuid, String cloud) { | public List<AccountPaymentMethod> findByAccountAndCloud(String accountUuid, String cloud) { | ||||
return findByFields("account", accountUuid, "cloud", cloud); | return findByFields("account", accountUuid, "cloud", cloud); | ||||
} | } | ||||
@@ -163,16 +163,16 @@ public class AccountPlan extends IdentifiableBase implements HasNetwork { | |||||
public boolean hasForkHost () { return !empty(forkHost); } | public boolean hasForkHost () { return !empty(forkHost); } | ||||
@Transient @Getter @Setter private transient Boolean syncPassword = null; | @Transient @Getter @Setter private transient Boolean syncPassword = null; | ||||
public boolean syncPassword () { return bool(syncPassword); } | |||||
public boolean syncPassword () { return syncPassword == null || syncPassword; } | |||||
@Transient @Getter @Setter private Boolean launchLock; | @Transient @Getter @Setter private Boolean launchLock; | ||||
public boolean launchLock() { return bool(launchLock); } | public boolean launchLock() { return bool(launchLock); } | ||||
@Transient @Getter @Setter private transient Boolean sendErrors = null; | @Transient @Getter @Setter private transient Boolean sendErrors = null; | ||||
public boolean sendErrors () { return bool(sendErrors); } | |||||
public boolean sendErrors () { return sendErrors == null || sendErrors; } | |||||
@Transient @Getter @Setter private transient Boolean sendMetrics = null; | @Transient @Getter @Setter private transient Boolean sendMetrics = null; | ||||
public boolean sendMetrics () { return bool(sendMetrics); } | |||||
public boolean sendMetrics () { return sendMetrics == null || sendMetrics; } | |||||
public BubbleNetwork bubbleNetwork(Account account, | public BubbleNetwork bubbleNetwork(Account account, | ||||
BubbleDomain domain, | BubbleDomain domain, | ||||
@@ -151,13 +151,14 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
if (!canCreate(req, ctx, caller, request)) return invalid("err.cannotCreate", "Create entity not allowed", request.getName()); | if (!canCreate(req, ctx, caller, request)) return invalid("err.cannotCreate", "Create entity not allowed", request.getName()); | ||||
final E toCreate = setReferences(ctx, caller, instantiate(getEntityClass(), request).setAccount(getAccountUuid(ctx))); | |||||
final E toCreate = setReferences(ctx, req, caller, instantiate(getEntityClass(), request).setAccount(getAccountUuid(ctx))); | |||||
return ok(daoCreate(toCreate)); | return ok(daoCreate(toCreate)); | ||||
} | } | ||||
protected Object daoCreate(E toCreate) { return getDao().create(toCreate); } | protected Object daoCreate(E toCreate) { return getDao().create(toCreate); } | ||||
protected E setReferences(ContainerRequest ctx, Account caller, E e) { return e; } | protected E setReferences(ContainerRequest ctx, Account caller, E e) { return e; } | ||||
protected E setReferences(ContainerRequest ctx, Request req, Account caller, E e) { return setReferences(ctx, caller, e); } | |||||
@POST @Path("/{id}") | @POST @Path("/{id}") | ||||
public Response update(@Context ContainerRequest ctx, | public Response update(@Context ContainerRequest ctx, | ||||
@@ -6,9 +6,11 @@ package bubble.resources.bill; | |||||
import bubble.dao.bill.AccountPaymentMethodDAO; | import bubble.dao.bill.AccountPaymentMethodDAO; | ||||
import bubble.dao.bill.AccountPlanDAO; | import bubble.dao.bill.AccountPlanDAO; | ||||
import bubble.dao.bill.BubblePlanDAO; | |||||
import bubble.model.account.Account; | import bubble.model.account.Account; | ||||
import bubble.model.bill.AccountPaymentMethod; | import bubble.model.bill.AccountPaymentMethod; | ||||
import bubble.model.bill.AccountPlan; | import bubble.model.bill.AccountPlan; | ||||
import bubble.model.bill.BubblePlan; | |||||
import bubble.resources.account.AccountOwnedResource; | import bubble.resources.account.AccountOwnedResource; | ||||
import bubble.server.BubbleConfiguration; | import bubble.server.BubbleConfiguration; | ||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
@@ -33,6 +35,7 @@ public class AccountPaymentMethodsResource extends AccountOwnedResource<AccountP | |||||
public static final String PARAM_ALL = "all"; | public static final String PARAM_ALL = "all"; | ||||
@Autowired private BubblePlanDAO planDAO; | |||||
@Autowired private AccountPlanDAO accountPlanDAO; | @Autowired private AccountPlanDAO accountPlanDAO; | ||||
@Autowired private BubbleConfiguration configuration; | @Autowired private BubbleConfiguration configuration; | ||||
@@ -78,7 +81,9 @@ public class AccountPaymentMethodsResource extends AccountOwnedResource<AccountP | |||||
@Override protected Object daoCreate(AccountPaymentMethod apm) { | @Override protected Object daoCreate(AccountPaymentMethod apm) { | ||||
if (apm.hasPreferredPlan()) { | if (apm.hasPreferredPlan()) { | ||||
final Account account = accountDAO.findByUuid(apm.getAccount()); | final Account account = accountDAO.findByUuid(apm.getAccount()); | ||||
accountDAO.update(account.setPreferredPlan(apm.getPreferredPlan())); | |||||
final BubblePlan plan = planDAO.findById(apm.getPreferredPlan()); | |||||
if (plan == null) throw invalidEx("err.plan.notFound", "plan not found: "+apm.getPreferredPlan()); | |||||
accountDAO.update(account.setPreferredPlan(plan.getUuid())); | |||||
} | } | ||||
return super.daoCreate(apm); | return super.daoCreate(apm); | ||||
} | } | ||||
@@ -101,11 +101,18 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||||
return super.canDelete(ctx, caller, found); | return super.canDelete(ctx, caller, found); | ||||
} | } | ||||
@Override protected AccountPlan setReferences(ContainerRequest ctx, Account caller, AccountPlan request) { | |||||
@Override protected AccountPlan setReferences(ContainerRequest ctx, Request req, Account caller, AccountPlan request) { | |||||
// ensure we have latest account settings (preferredPlan/etc) | |||||
caller = accountDAO.findByUuid(caller.getUuid()); | |||||
final ValidationResult errors = new ValidationResult(); | final ValidationResult errors = new ValidationResult(); | ||||
if (!request.hasTimezone()) errors.addViolation("err.timezone.required"); | |||||
if (!request.hasLocale()) errors.addViolation("err.locale.required"); | |||||
if (!request.hasTimezone() || request.getTimezone().equals(DETECT_TIMEZONE)) { | |||||
request.setTimezone(geoService.getTimeZone(caller, getRemoteHost(req)).getStandardName()); | |||||
} | |||||
if (!request.hasLocale() || request.getLocale().equals(DETECT_LOCALE)) { | |||||
request.setLocale(geoService.getFirstLocale(account, getRemoteHost(req), normalizeLangHeader(req))); | |||||
} | |||||
request.setAccount(caller.getUuid()); | request.setAccount(caller.getUuid()); | ||||
if (request.hasSshKey()) { | if (request.hasSshKey()) { | ||||
@@ -115,17 +122,25 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||||
} else { | } else { | ||||
request.setSshKey(sshKey.getUuid()); | request.setSshKey(sshKey.getUuid()); | ||||
} | } | ||||
} else if (configuration.isSageLauncher()) { | |||||
final List<AccountSshKey> sshKeys = sshKeyDAO.findByAccount(caller.getUuid()); | |||||
if (empty(sshKeys)) { | |||||
request.setSshKey(null); | |||||
} else { | |||||
request.setSshKey(sshKeys.get(0).getUuid()); | |||||
} | |||||
} else { | } else { | ||||
request.setSshKey(null); // if it's an empty string, make it null (see simple_network test) | request.setSshKey(null); // if it's an empty string, make it null (see simple_network test) | ||||
} | } | ||||
final BubbleDomain domain = domainDAO.findByAccountAndId(caller.getUuid(), request.getDomain()); | |||||
BubbleDomain domain = domainDAO.findByAccountAndId(caller.getUuid(), request.getDomain()); | |||||
if (domain == null) { | if (domain == null) { | ||||
log.info("setReferences: domain not found: "+request.getDomain()+" for caller: "+caller.getUuid()); | |||||
errors.addViolation("err.domain.required"); | |||||
final List<BubbleDomain> domains = domainDAO.findByAccount(caller.getUuid()); | |||||
if (empty(domains)) return die("setReferences: no domains found for account: "+caller.getUuid()); | |||||
domain = domains.get(0); | |||||
request.setDomain(domain.getUuid()); | |||||
} else { | } else { | ||||
request.setDomain(domain.getUuid()); | request.setDomain(domain.getUuid()); | ||||
final BubbleNetwork existingNetwork = networkDAO.findByNameAndDomainName(request.getName(), domain.getName()); | final BubbleNetwork existingNetwork = networkDAO.findByNameAndDomainName(request.getName(), domain.getName()); | ||||
if (existingNetwork != null) errors.addViolation("err.name.networkNameAlreadyExists"); | if (existingNetwork != null) errors.addViolation("err.name.networkNameAlreadyExists"); | ||||
} | } | ||||
@@ -138,7 +153,15 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||||
if (!validateRegexMatches(HOST_PATTERN, forkHost)) { | if (!validateRegexMatches(HOST_PATTERN, forkHost)) { | ||||
errors.addViolation("err.forkHost.invalid"); | errors.addViolation("err.forkHost.invalid"); | ||||
} else if (domain != null && !forkHost.endsWith("."+domain.getName())) { | } else if (domain != null && !forkHost.endsWith("."+domain.getName())) { | ||||
errors.addViolation("err.forkHost.domainMismatch"); | |||||
final BubbleDomain foundDomain = domainDAO.findByAccount(caller.getUuid()).stream() | |||||
.filter(d -> forkHost.equals("." + d.getName())) | |||||
.findFirst().orElse(null); | |||||
if (foundDomain == null) { | |||||
errors.addViolation("err.forkHost.domain.notFound"); | |||||
} else { | |||||
request.setDomain(foundDomain.getUuid()); | |||||
} | |||||
} else if (domain != null) { | } else if (domain != null) { | ||||
request.setName(domain.networkFromFqdn(forkHost, errors)); | request.setName(domain.networkFromFqdn(forkHost, errors)); | ||||
validateName(request, errors); | validateName(request, errors); | ||||
@@ -146,11 +169,8 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||||
} | } | ||||
} else { | } else { | ||||
if (!request.hasNickname()) { | if (!request.hasNickname()) { | ||||
if (request.hasName()) { | |||||
request.setNickname(request.getName()); | |||||
} else { | |||||
errors.addViolation("err.name.required"); | |||||
} | |||||
if (!request.hasName()) request.setName(newNetworkName()); | |||||
request.setNickname(request.getName()); | |||||
} | } | ||||
if (request.hasNickname() && request.getNickname().length() > NAME_MAXLEN) { | if (request.hasNickname() && request.getNickname().length() > NAME_MAXLEN) { | ||||
errors.addViolation("err.name.tooLong"); | errors.addViolation("err.name.tooLong"); | ||||
@@ -160,9 +180,14 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||||
} | } | ||||
log.info("setReferences: after calling validateName, request.name="+request.getName()); | log.info("setReferences: after calling validateName, request.name="+request.getName()); | ||||
final BubblePlan plan = planDAO.findByAccountOrParentAndId(caller, request.getPlan()); | |||||
BubblePlan plan = planDAO.findByAccountOrParentAndId(caller, request.getPlan()); | |||||
if (plan == null) { | if (plan == null) { | ||||
errors.addViolation("err.plan.required"); | |||||
plan = planDAO.findByUuid(caller.getPreferredPlan()); | |||||
if (plan == null) { | |||||
errors.addViolation("err.plan.required"); | |||||
} else { | |||||
request.setPlan(plan.getUuid()); | |||||
} | |||||
} else { | } else { | ||||
request.setPlan(plan.getUuid()); | request.setPlan(plan.getUuid()); | ||||
} | } | ||||
@@ -189,22 +214,26 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco | |||||
AccountPaymentMethod paymentMethod = null; | AccountPaymentMethod paymentMethod = null; | ||||
if (configuration.paymentsEnabled()) { | if (configuration.paymentsEnabled()) { | ||||
if (!request.hasPaymentMethodObject()) { | if (!request.hasPaymentMethodObject()) { | ||||
errors.addViolation("err.paymentMethod.required"); | |||||
} else { | |||||
if (request.getPaymentMethodObject().hasUuid()) { | |||||
paymentMethod = paymentMethodDAO.findByUuid(request.getPaymentMethodObject().getUuid()); | |||||
if (paymentMethod == null) errors.addViolation("err.purchase.paymentMethodNotFound"); | |||||
final List<AccountPaymentMethod> paymentMethods = paymentMethodDAO.findByAccountAndNotPromoAndNotDeleted(caller.getUuid()); | |||||
if (empty(paymentMethods)) { | |||||
errors.addViolation("err.paymentMethod.required"); | |||||
} else { | } else { | ||||
paymentMethod = request.getPaymentMethodObject(); | |||||
request.setPaymentMethodObject(paymentMethods.get(0)); | |||||
} | } | ||||
if (paymentMethod != null && plan != null) { | |||||
if (paymentMethod.hasPromotion() || paymentMethod.getPaymentMethodType() == PaymentMethodType.promotional_credit) { | |||||
// cannot pay with a promo credit, must supply another payment method. | |||||
// promos will be applied at purchase, and may result in no charge to this payment method | |||||
errors.addViolation("err.purchase.paymentMethodNotFound"); | |||||
} else { | |||||
paymentMethod.setAccount(caller.getUuid()).validate(errors, configuration); | |||||
} | |||||
} | |||||
if (request.getPaymentMethodObject().hasUuid()) { | |||||
paymentMethod = paymentMethodDAO.findByUuid(request.getPaymentMethodObject().getUuid()); | |||||
if (paymentMethod == null) errors.addViolation("err.purchase.paymentMethodNotFound"); | |||||
} else { | |||||
paymentMethod = request.getPaymentMethodObject(); | |||||
} | |||||
if (paymentMethod != null && plan != null) { | |||||
if (paymentMethod.hasPromotion() || paymentMethod.getPaymentMethodType() == PaymentMethodType.promotional_credit) { | |||||
// cannot pay with a promo credit, must supply another payment method. | |||||
// promos will be applied at purchase, and may result in no charge to this payment method | |||||
errors.addViolation("err.purchase.paymentMethodNotFound"); | |||||
} else { | |||||
paymentMethod.setAccount(caller.getUuid()).validate(errors, configuration); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -7,6 +7,7 @@ package bubble.service.cloud; | |||||
import bubble.model.cloud.BubbleNetwork; | import bubble.model.cloud.BubbleNetwork; | ||||
import bubble.model.cloud.BubbleNode; | import bubble.model.cloud.BubbleNode; | ||||
import bubble.notify.NewNodeNotification; | import bubble.notify.NewNodeNotification; | ||||
import bubble.server.BubbleConfiguration; | |||||
import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
@@ -25,6 +26,7 @@ public class NodeLauncher implements Runnable { | |||||
private final AtomicReference<String> lock; | private final AtomicReference<String> lock; | ||||
private final StandardNetworkService networkService; | private final StandardNetworkService networkService; | ||||
private final NodeLaunchMonitor launchMonitor; | private final NodeLaunchMonitor launchMonitor; | ||||
private final BubbleConfiguration configuration; | |||||
@Override public void run() { | @Override public void run() { | ||||
final String networkUuid = newNodeRequest.getNetwork(); | final String networkUuid = newNodeRequest.getNetwork(); | ||||
@@ -98,7 +100,7 @@ public class NodeLauncher implements Runnable { | |||||
die("NodeLauncher.run: unknown launch exception (type="+launchException.getType()+"): "+shortError(launchException), launchException); | die("NodeLauncher.run: unknown launch exception (type="+launchException.getType()+"): "+shortError(launchException), launchException); | ||||
} | } | ||||
} else { | } else { | ||||
die("NodeLauncher.run: fatal launch exception: " + shortError(exception), exception); | |||||
if (!configuration.testMode()) die("NodeLauncher.run: fatal launch exception: " + shortError(exception), exception); | |||||
} | } | ||||
} | } | ||||
if (node != null && node.isRunning()) { | if (node != null && node.isRunning()) { | ||||
@@ -817,7 +817,7 @@ public class StandardNetworkService implements NetworkService { | |||||
public void backgroundNewNode(NewNodeNotification newNodeRequest, final String existingLock) { | public void backgroundNewNode(NewNodeNotification newNodeRequest, final String existingLock) { | ||||
final AtomicReference<String> lock = new AtomicReference<>(existingLock); | final AtomicReference<String> lock = new AtomicReference<>(existingLock); | ||||
daemon(new NodeLauncher(newNodeRequest, lock, this, launchMonitor)); | |||||
daemon(new NodeLauncher(newNodeRequest, lock, this, launchMonitor, configuration)); | |||||
} | } | ||||
public boolean stopNetwork(final BubbleNetwork network) { | public boolean stopNetwork(final BubbleNetwork network) { | ||||
@@ -1 +1 @@ | |||||
Subproject commit 35f36a84d84cb1f73dd8cc1f18e044657675b7f9 | |||||
Subproject commit 7ddb8f71fc43a5b5ce1056944e1f1876ee586f14 |
@@ -67,6 +67,12 @@ public abstract class ActivatedBubbleModelTestBase extends BubbleModelTestBase { | |||||
super.beforeStart(server); | super.beforeStart(server); | ||||
} | } | ||||
public void mockNetwork(RestServer<BubbleConfiguration> server) { | |||||
final BubbleConfiguration configuration = server.getConfiguration(); | |||||
configuration.setSpringContextPath("classpath:/spring-mock-network.xml"); | |||||
configuration.getStaticAssets().setLocalOverride(null); | |||||
} | |||||
public String getDefaultDomain() { return "example.com"; } | public String getDefaultDomain() { return "example.com"; } | ||||
@Override protected String[] getSqlPostScripts() { return hasExistingDb ? null : super.getSqlPostScripts(); } | @Override protected String[] getSqlPostScripts() { return hasExistingDb ? null : super.getSqlPostScripts(); } | ||||
@@ -15,9 +15,7 @@ public class PaymentTestBase extends ActivatedBubbleModelTestBase { | |||||
@Override protected String getManifest() { return "manifest-test"; } | @Override protected String getManifest() { return "manifest-test"; } | ||||
@Override public void beforeStart(RestServer<BubbleConfiguration> server) { | @Override public void beforeStart(RestServer<BubbleConfiguration> server) { | ||||
final BubbleConfiguration configuration = server.getConfiguration(); | |||||
configuration.setSpringContextPath("classpath:/spring-mock-network.xml"); | |||||
configuration.getStaticAssets().setLocalOverride(null); | |||||
mockNetwork(server); | |||||
super.beforeStart(server); | super.beforeStart(server); | ||||
} | } | ||||
@@ -12,5 +12,6 @@ public class NetworkTest extends NetworkTestBase { | |||||
@Test public void testRegions () throws Exception { modelTest("network/network_regions"); } | @Test public void testRegions () throws Exception { modelTest("network/network_regions"); } | ||||
@Test public void testGetNetworkKeys () throws Exception { modelTest("network/network_keys"); } | @Test public void testGetNetworkKeys () throws Exception { modelTest("network/network_keys"); } | ||||
@Test public void testMinimalLaunch () throws Exception { modelTest("network/minimal_launch"); } | |||||
} | } |
@@ -4,10 +4,17 @@ | |||||
*/ | */ | ||||
package bubble.test.system; | package bubble.test.system; | ||||
import bubble.server.BubbleConfiguration; | |||||
import bubble.test.ActivatedBubbleModelTestBase; | import bubble.test.ActivatedBubbleModelTestBase; | ||||
import org.cobbzilla.wizard.server.RestServer; | |||||
public class NetworkTestBase extends ActivatedBubbleModelTestBase { | public class NetworkTestBase extends ActivatedBubbleModelTestBase { | ||||
@Override protected String getManifest() { return "manifest-network"; } | @Override protected String getManifest() { return "manifest-network"; } | ||||
@Override public void beforeStart(RestServer<BubbleConfiguration> server) { | |||||
mockNetwork(server); | |||||
super.beforeStart(server); | |||||
} | |||||
} | } |
@@ -0,0 +1,69 @@ | |||||
[ | |||||
{ | |||||
"comment": "create another account and login", | |||||
"include": "new_account", | |||||
"params": { | |||||
"email": "min_launch@example.com", | |||||
"verifyEmail": true | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "list plans", | |||||
"request": { "uri": "plans" }, | |||||
"response": { | |||||
"store": "plans", | |||||
"check": [ | |||||
{"condition": "json.length > 0"} | |||||
] | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "add a payment method and preferred plan", | |||||
"before": "stripe_tokenize_card", | |||||
"request": { | |||||
"uri": "me/paymentMethods", | |||||
"method": "put", | |||||
"entity": { | |||||
"paymentMethodType": "credit", | |||||
"paymentInfo": "{{stripeToken}}", | |||||
"preferredPlan": "{{plans.[0].name}}" | |||||
} | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "add account plan", | |||||
"request": { | |||||
"uri": "me/plans", | |||||
"method": "put", | |||||
"entity": {} | |||||
}, | |||||
"response": { "store": "plan" } | |||||
}, | |||||
{ | |||||
"comment": "start the network. sets up the first node, which does the rest", | |||||
"request": { | |||||
"uri": "me/networks/{{ plan.name }}/actions/start", | |||||
"method": "post" | |||||
}, | |||||
"response": { | |||||
"store": "<<networkVar>>" | |||||
} | |||||
}, | |||||
{ | |||||
"comment": "list networks, verify new network is starting", | |||||
"before": "sleep 10s", | |||||
"request": { "uri": "me/networks" }, | |||||
"response": { | |||||
"check": [ | |||||
{"condition": "json.length === 1"}, | |||||
{"condition": "json[0].getName() === '{{plan.name}}'"}, | |||||
{"condition": "json[0].getState().name() === 'starting'"} | |||||
] | |||||
} | |||||
} | |||||
] |