kris/fix_backup_restore_test_cont_2
into master
4 years ago
@@ -48,18 +48,15 @@ | |||
src: supervisor_wg_monitor_connections.conf | |||
dest: /etc/supervisor/conf.d/wg_monitor_connections.conf | |||
# Don't setup algo when in restore mode, bubble_restore_monitor.sh will set it up after the CA key has been restored | |||
- name: Run algo playbook to install algo | |||
shell: /root/ansible/roles/algo/algo/install_algo.sh | |||
when: restore_key is not defined | |||
block: | |||
- name: Run install algo script including playbook | |||
shell: /root/ansible/roles/algo/algo/install_algo.sh | |||
# Don't start monitors when in restore mode, bubble_restore_monitor.sh will start it after algo is installed | |||
- name: Run algo playbook to install algo | |||
shell: bash -c "supervisorctl reload && sleep 5s && supervisorctl restart algo_refresh_users_monitor && supervisorctl restart wg_monitor_connections" | |||
when: restore_key is not defined | |||
- name: Restart algo related services | |||
shell: bash -c "supervisorctl reload && sleep 5s && supervisorctl restart algo_refresh_users_monitor && supervisorctl restart wg_monitor_connections" | |||
- name: Run algo playbook to install algo | |||
shell: bash -c "supervisorctl reload && sleep 5s && supervisorctl stop algo_refresh_users_monitor && supervisorctl stop wg_monitor_connections" | |||
when: restore_key is defined | |||
- include: algo_firewall.yml | |||
# Don't setup algo when in restore mode, bubble_restore_monitor.sh will set it up after the CA key has been restored | |||
tags: algo_related | |||
- include: algo_firewall.yml |
@@ -21,7 +21,7 @@ function die { | |||
} | |||
function log { | |||
echo "${1}" >> ${LOG} | |||
echo "$(date): ${1}" >> ${LOG} | |||
} | |||
START=$(date +%s) | |||
@@ -92,7 +92,7 @@ cp ${RESTORE_BASE}/bubble.sql.gz ${BUBBLE_HOME}/sql/ \ | |||
&& chgrp -R postgres ${BUBBLE_HOME}/sql \ | |||
&& chmod 550 ${BUBBLE_HOME}/sql \ | |||
&& chmod 440 ${BUBBLE_HOME}/sql/* || die "Error restoring bubble database archive" | |||
su - postgres bash -c "cd ${BUBBLE_HOME}/sql && full_reset_db.sh drop" || die "Error restoring database" | |||
su - postgres bash -c "cd ${BUBBLE_HOME}/sql && full_reset_db.sh drop restored_node" || die "Error restoring database" | |||
# Remove old keys | |||
log "Removing node keys" | |||
@@ -107,21 +107,27 @@ log "Flushing redis" | |||
echo "FLUSHALL" | redis-cli || die "Error flushing redis" | |||
# restore algo configs | |||
log "Restoring algo configs" | |||
CONFIGS_BACKUP=/home/bubble/.BUBBLE_ALGO_CONFIGS.tgz | |||
if [[ ! -f ${CONFIGS_BACKUP} ]] ; then | |||
log "Warning: Algo VPN configs backup not found: ${CONFIGS_BACKUP}, not installing algo" | |||
else | |||
ALGO_BASE=/root/ansible/roles/algo/algo | |||
ANSIBLE_HOME="/root" | |||
ANSIBLE_DIR="${ANSIBLE_HOME}/ansible" | |||
ID_FILE="${ANSIBLE_HOME}/.ssh/bubble_rsa" | |||
SSH_OPTIONS="--ssh-extra-args '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey -i ${ID_FILE}'" | |||
ALGO_BASE=${ANSIBLE_DIR}/roles/algo/algo | |||
if [[ ! -d ${ALGO_BASE} ]] ; then | |||
die "Error restoring Algo VPN: directory ${ALGO_BASE} not found" | |||
fi | |||
cd ${ALGO_BASE} && tar xzf ${CONFIGS_BACKUP} || die "Error restoring algo VPN configs" | |||
# install/configure algo | |||
${ALGO_BASE}/install_algo.sh || die "Error configuring or installing algo VPN" | |||
# ensure user monitor is running | |||
supervisorctl restart algo_refresh_users_monitor | |||
cd "${ANSIBLE_DIR}" && \ | |||
. ./venv/bin/activate && \ | |||
bash -c \ | |||
"ansible-playbook ${SSH_OPTIONS} --tags 'algo_related,always' --inventory ./hosts ./playbook.yml 2>&1 >> ${LOG}" \ | |||
|| die "Error running ansible in post-restore. journalctl -xe = $(journalctl -xe | tail -n 50)" | |||
fi | |||
# restart mitm proxy service | |||
@@ -135,7 +141,7 @@ supervisorctl restart bubble | |||
# verify service is running OK | |||
log "Pausing for a bit, then verifying bubble server has successfully restarted after restore" | |||
sleep 60 | |||
curl https://$(hostname):${ADMIN_PORT}/api/.bubble || log "Error restarting bubble server" | |||
curl https://$(hostname):${ADMIN_PORT}/api/.bubble || log "Error restarting bubble server - port ${ADMIN_PORT}" | |||
# remove restore markers, we are done | |||
log "Cleaning up temp files" | |||
@@ -5,6 +5,8 @@ function die { | |||
exit 1 | |||
} | |||
INSTALL_MODE=${2:-{{install_type}}} | |||
if [[ $(whoami) == "root" ]] ; then | |||
su - postgres ${0} ${@} | |||
exit $? | |||
@@ -15,5 +17,5 @@ if [[ $(whoami) != "postgres" ]] ; then | |||
fi | |||
cd ~bubble/sql \ | |||
&& init_bubble_db.sh {{ db_name }} {{ db_user }} {{ is_fork }} {{ install_type }} ${1} \ | |||
&& init_bubble_db.sh {{ db_name }} {{ db_user }} {{ is_fork }} ${INSTALL_MODE} ${1} \ | |||
|| die "error reinitializing database" |
@@ -88,13 +88,17 @@ | |||
state: link | |||
- name: Restart dnscrypt-proxy | |||
shell: service dnscrypt-proxy restart | |||
service: | |||
name: dnscrypt-proxy | |||
state: restarted | |||
tags: algo_related | |||
- name: restart supervisord | |||
service: | |||
name: supervisor | |||
enabled: yes | |||
state: restarted | |||
tags: always | |||
- import_tasks: route.yml | |||
@@ -14,7 +14,7 @@ | |||
value: 0 | |||
sysctl_set: yes | |||
- name: "Allow MITM private port" | |||
- name: Allow MITM private port | |||
iptables: | |||
chain: INPUT | |||
action: insert | |||
@@ -26,33 +26,15 @@ | |||
jump: ACCEPT | |||
comment: Accept new local TCP DNS connections on private port | |||
become: yes | |||
tags: algo_related | |||
- name: Route port 80 through mitmproxy | |||
iptables: | |||
table: nat | |||
chain: PREROUTING | |||
action: insert | |||
rule_num: 1 | |||
protocol: tcp | |||
destination_port: 80 | |||
jump: REDIRECT | |||
to_ports: "{{ mitm_port }}" | |||
- name: Route port 443 through mitmproxy | |||
iptables: | |||
table: nat | |||
chain: PREROUTING | |||
action: insert | |||
rule_num: 2 | |||
protocol: tcp | |||
destination_port: 443 | |||
jump: REDIRECT | |||
to_ports: "{{ mitm_port }}" | |||
- name: Setup for MITM and save iptables | |||
block: | |||
- name: save iptables rules | |||
shell: iptables-save > /etc/iptables/rules.v4 | |||
become: yes | |||
- name: save iptables rules | |||
shell: iptables-save > /etc/iptables/rules.v4 | |||
become: yes | |||
- name: save iptables v6 rules | |||
shell: ip6tables-save > /etc/iptables/rules.v6 | |||
become: yes | |||
- name: save iptables v6 rules | |||
shell: ip6tables-save > /etc/iptables/rules.v6 | |||
become: yes | |||
tags: always |
@@ -120,7 +120,13 @@ public class VultrDriver extends ComputeServiceDriverBase { | |||
// create server, check response | |||
final HttpResponseBean serverResponse = serverRequest.curl(); // fixme: we can do better than shelling to curl | |||
if (serverResponse.getStatus() != 200) return die("start: error creating server: " + serverResponse); | |||
final String subId = json(serverResponse.getEntityString(), JsonNode.class).get(VULTR_SUBID).textValue(); | |||
final JsonNode responseJson; | |||
try { | |||
responseJson = json(serverResponse.getEntityString(), JsonNode.class); | |||
} catch (IllegalStateException e) { | |||
return die("start: error creating server (error parsing response as JSON): " + serverResponse); | |||
} | |||
final var subId = responseJson.get(VULTR_SUBID).textValue(); | |||
node.setState(BubbleNodeState.booting); | |||
node.setTag(TAG_INSTANCE_ID, subId); | |||
@@ -20,7 +20,7 @@ import static org.cobbzilla.util.security.ShaUtil.sha256_hex; | |||
public abstract class StorageServiceDriverBase<T> extends CloudServiceDriverBase<T> implements StorageServiceDriver { | |||
private final Map<String, WriteRequest> requestMap = new ConcurrentHashMap<>(); | |||
private static final Map<String, WriteRequest> requestMap = new ConcurrentHashMap<>(); | |||
private static final Map<String, WriteRequestCleaner> cleaners = new ConcurrentHashMap<>(); | |||
@@ -66,11 +66,11 @@ public abstract class StorageServiceDriverBase<T> extends CloudServiceDriverBase | |||
} catch (IllegalStateException e) { | |||
if (e.getMessage().contains("timeout")) { | |||
if (countBytes == 0) { | |||
return die("StorageServiceDriverBase._write: error: " + e); | |||
return die("StorageServiceDriverBase._write: error (no bytes) ", e); | |||
} | |||
} | |||
} catch (Exception e) { | |||
return die("StorageServiceDriverBase._write: error: " + e); | |||
return die("StorageServiceDriverBase._write: exception ", e); | |||
} | |||
} | |||
} | |||
@@ -13,6 +13,8 @@ import bubble.model.account.message.AccountAction; | |||
import bubble.model.account.message.AccountMessageType; | |||
import bubble.model.account.message.ActionTarget; | |||
import bubble.server.BubbleConfiguration; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import lombok.NonNull; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.glassfish.jersey.server.ContainerRequest; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
@@ -20,9 +22,12 @@ import org.springframework.context.ApplicationContext; | |||
import org.springframework.stereotype.Repository; | |||
import org.springframework.stereotype.Service; | |||
import javax.annotation.Nullable; | |||
import javax.validation.Valid; | |||
import javax.ws.rs.*; | |||
import javax.ws.rs.core.Context; | |||
import javax.ws.rs.core.Response; | |||
import java.io.IOException; | |||
import java.util.*; | |||
import java.util.function.Predicate; | |||
import java.util.stream.Collectors; | |||
@@ -32,6 +37,7 @@ import static bubble.cloud.auth.RenderedMessage.filteredInbox; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.die; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | |||
import static org.cobbzilla.util.json.JsonUtil.*; | |||
import static org.cobbzilla.util.reflect.ReflectionUtil.forName; | |||
import static org.cobbzilla.util.reflect.ReflectionUtil.instantiate; | |||
import static org.cobbzilla.wizard.resources.ResourceUtil.*; | |||
@@ -117,4 +123,16 @@ public class DebugResource { | |||
} | |||
} | |||
@POST @Path("/echo") | |||
public Response echoJsonInLog(@Context ContainerRequest ctx, | |||
@Valid @NonNull final JsonNode input, | |||
@QueryParam("respondWith") @Nullable final String respondWith) throws IOException { | |||
final var output = "ECHO: \n" + toJsonOrDie(input); | |||
log.info(output); | |||
if (empty(respondWith)) return ok(); | |||
log.debug("Responding with value in path: " + respondWith); | |||
return ok(getNodeAsJava(findNode(input, respondWith), "")); | |||
} | |||
} |
@@ -146,7 +146,7 @@ public class InboundNotifyResource { | |||
? stream(APPLICATION_OCTET_STREAM, data) | |||
: notFound(storageRequest.getKey()); | |||
} catch (Exception e) { | |||
return die("readStorage: "+e); | |||
return die("readStorage: exception", e); | |||
} finally { | |||
storageStreamService.clearToken(token); | |||
} | |||
@@ -49,9 +49,14 @@ sudo pip3 install setuptools psycopg2-binary || die "Error pip3 installing setup | |||
SSH_OPTIONS="--ssh-extra-args '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey -i ${ID_FILE}'" | |||
SKIP_TAGS="" | |||
if [[ -n "{{restoreKey}}" ]] ; then | |||
SKIP_TAGS="--skip-tags algo_related" | |||
fi | |||
cd "${ANSIBLE_DIR}" && \ | |||
virtualenv -p python3 ./venv && \ | |||
. ./venv/bin/activate && \ | |||
pip3 install ansible && \ | |||
bash -c "ansible-playbook ${SSH_OPTIONS} --inventory ./hosts ./playbook.yml" \ | |||
bash -c "ansible-playbook ${SSH_OPTIONS} ${SKIP_TAGS} --inventory ./hosts ./playbook.yml" \ | |||
|| die "Error running ansible. journalctl -xe = $(journalctl -xe | tail -n 50)" |
@@ -13,7 +13,7 @@ | |||
{ "percent": 44,"messageKey":"role_bubble_jar", "pattern":"TASK \\[bubble : Install bubble jar] \\*{5,}" }, | |||
{ "percent": 48,"messageKey":"role_bubble_db", "pattern":"TASK \\[bubble : Populate database] \\*{5,}" }, | |||
{ "percent": 51,"messageKey":"role_bubble_restore", "pattern":"TASK \\[bubble : Install restore helper scripts] \\*{5,}" }, | |||
{ "percent": 52,"messageKey":"role_bubble_algo", "pattern":"TASK \\[algo : Run algo playbook to install algo] \\*{5,}" }, | |||
{ "percent": 52,"messageKey":"role_bubble_algo", "pattern":"TASK \\[algo : [\\w\\s]+] \\*{5,}" }, | |||
{ "percent": 76,"messageKey":"role_nginx", "pattern":"TASK \\[nginx : [\\w\\s]+] \\*{5,}" }, | |||
{ "percent": 81,"messageKey":"role_nginx_certbot", "pattern":"TASK \\[nginx : Init certbot] \\*{5,}" }, | |||
{ "percent": 91,"messageKey":"role_mitmproxy", "pattern":"TASK \\[mitmproxy : [\\w\\s]+] \\*{5,}" }, | |||
@@ -0,0 +1,14 @@ | |||
/** | |||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||
*/ | |||
package bubble.test; | |||
import org.junit.Test; | |||
public class DebugCallsTest extends ActivatedBubbleModelTestBase { | |||
@Override protected String getManifest() { return "manifest-empty"; } | |||
@Test public void testEcho() throws Exception { modelTest("debug_echo"); } | |||
} |
@@ -16,15 +16,12 @@ | |||
}, | |||
{ | |||
"before": "sleep 3s", | |||
"comment": "check email inbox, expect network keys request", | |||
"request": { | |||
"uri": "debug/inbox/email/<<rootEmail>>?type=request&action=password&target=network" | |||
}, | |||
"comment": "await and get network keys request in email inbox", | |||
"before": "await_url debug/inbox/email/<<rootEmail>>?type=request&action=password&target=network 3m 5s len(await_json) > 0", | |||
"request": { "uri": "debug/inbox/email/<<rootEmail>>?type=request&action=password&target=network" }, | |||
"response": { | |||
"store": "emailInbox", | |||
"check": [ | |||
{"condition": "json.length >= 1"}, | |||
{"condition": "'{{json.[0].ctx.message.messageType}}' == 'request'"}, | |||
{"condition": "'{{json.[0].ctx.message.action}}' == 'password'"}, | |||
{"condition": "'{{json.[0].ctx.message.target}}' == 'network'"} | |||
@@ -41,15 +38,12 @@ | |||
}, | |||
{ | |||
"before": "sleep 3s", | |||
"comment": "check email inbox for key request confirmation", | |||
"request": { | |||
"uri": "debug/inbox/email/<<rootEmail>>?type=confirmation&action=password&target=network" | |||
}, | |||
"comment": "await and get key request confirmation from email inbox", | |||
"before": "await_url debug/inbox/email/<<rootEmail>>?type=confirmation&action=password&target=network 3m 5s len(await_json) > 0", | |||
"request": { "uri": "debug/inbox/email/<<rootEmail>>?type=confirmation&action=password&target=network" }, | |||
"response": { | |||
"store": "emailInbox", | |||
"check": [ | |||
{"condition": "json.length >= 1"}, | |||
{"condition": "'{{json.[0].ctx.message.messageType}}' == 'confirmation'"}, | |||
{"condition": "'{{json.[0].ctx.message.action}}' == 'password'"}, | |||
{"condition": "'{{json.[0].ctx.message.target}}' == 'network'"} | |||
@@ -111,13 +111,13 @@ | |||
{ | |||
"comment": "list all payment methods", | |||
"request": { "uri": "me/paymentMethods?all=true" }, | |||
"request": { "uri": "me/paymentMethods" }, | |||
"response": { "store": "paymentMethods" } | |||
}, | |||
{ | |||
"comment": "add payment method for the user", | |||
"onlyIf": "len(paymentMethods) == 0", | |||
"onlyIf": "!match_any(paymentMethods, function(m) { return !m.hasPromotion() && m.getPaymentMethodType() != `promotional_credit`; })", | |||
"before": "stripe_tokenize_card", | |||
"request": { | |||
"uri": "me/paymentMethods", | |||
@@ -127,15 +127,15 @@ | |||
}, | |||
{ | |||
"comment": "list all payment methods again after creating one", | |||
"onlyIf": "len(paymentMethods) == 0", | |||
"request": { "uri": "me/paymentMethods?all=true" }, | |||
"response": { "store": "paymentMethods", "check": [{ "condition": "len(json) == 1" }] } | |||
"comment": "wait for the one created above and fetch all payment methods again including that one", | |||
"onlyIf": "!match_any(paymentMethods, function(m) { return !m.hasPromotion() && m.getPaymentMethodType() != `promotional_credit`; })", | |||
"before": "await_url me/paymentMethods 5m 10s match_any(await_json, function(m) { return !m.hasPromotion() && m.getPaymentMethodType() != `promotional_credit`; })", | |||
"request": { "uri": "me/paymentMethods" }, | |||
"response": { "store": "paymentMethods" } | |||
}, | |||
{ | |||
"comment": "add plan, using the first found payment method for the new bubble", | |||
"before": "sleep 24s", | |||
"request": { | |||
"uri": "me/plans", | |||
"method": "put", | |||
@@ -147,7 +147,9 @@ | |||
"plan": "<<plan>>", | |||
"footprint": "<<footprint>>", | |||
"sendMetrics": <<sendMetrics>>, | |||
"paymentMethodObject": { "uuid": "{{ paymentMethods.[0].uuid }}" } | |||
"paymentMethodObject": { | |||
"uuid": "{{ js '_find(paymentMethods, function(m) { return !m.hasPromotion() && m.getPaymentMethodType() != `promotional_credit`; }).getUuid()' }}" | |||
} | |||
} | |||
}, | |||
"response": { "store": "plan" } | |||
@@ -166,7 +168,7 @@ | |||
{ | |||
"comment": "call API of deployed node after some grace period, ensure it is running", | |||
"before": "await_url .bubble 20m:40m 20s", | |||
"before": "await_url .bubble 20m:20m 20s", | |||
"connection": { | |||
"name": "<<bubbleConnectionVar>>", | |||
"baseUri": "https://{{<<networkVar>>.host}}.<<network>>.<<domain>>:{{serverConfig.nginxPort}}/api" | |||
@@ -218,4 +220,4 @@ | |||
] | |||
} | |||
} | |||
] | |||
] |
@@ -0,0 +1,48 @@ | |||
[ | |||
{ | |||
"comment": "Simplest example of using ECHO debug call without the query param", | |||
"request": { "uri": "debug/echo", "entity": { "anything": "something" } }, | |||
"response": { "check": [{ "condition": "len(json) == 0" }] }, | |||
"after": "add_to_ctx { \"added\": \"val\", \"addedInner\": { \"inner\": \"value\", \"another\": \"variable\" }, \"addedArray\": [ \"abc\", \"def\" ] }" | |||
}, | |||
{ | |||
"comment": "Example of using ECHO debug call and echo_in_log after", | |||
"request": { | |||
"uri": "debug/echo?respondWith=inner.comment", | |||
"entity": { | |||
"inner": { "comment": "Fixed text comment" }, | |||
"non-existing": "{{notexistingvar}}" | |||
} | |||
}, | |||
"response": { | |||
"raw": true, | |||
"store": "echoedResponse", | |||
"check": [{ "condition": "response.json == 'Fixed text comment'" }] | |||
}, | |||
"after": "echo_in_log Test:\n\tnon existent value: {{somethingThatDoesntExist}}\n\tjust stored response: {{echoedResponse}}" | |||
}, | |||
{ | |||
"comment": "Another example of using ECHO debug call and echo_in_log after", | |||
"before": "add_to_ctx { \"brand\": \"new\" }", | |||
"request": { | |||
"uri": "debug/echo?respondWith=inner", | |||
"entity": { | |||
"previouslyStored": "{{echoedResponse}}", | |||
"inner": { "comment": "Another fixed text comment" } | |||
} | |||
}, | |||
"response": { | |||
"store": "echoedJson", | |||
"check": [ | |||
{ "condition": "json.get('comment') == 'Another fixed text comment'" }, | |||
{ "condition": "'{{brand}}' == 'new'" }, | |||
{ "condition": "'{{addedInner.another}}' == 'variable'" }, | |||
{ "condition": "'{{added}}' == 'val'" } | |||
] | |||
}, | |||
"after": "echo_in_log \"And now the stored value is: {{echoedJson.comment}}\"" | |||
// echo_in_log is, of course, available within `before` also | |||
} | |||
] |
@@ -1,6 +1,7 @@ | |||
[ | |||
{ | |||
"comment": "login as root on sage node", | |||
"comment": "login as root on sage node (adding username to ctx also)", | |||
"before": "add_to_ctx { \"username\": \"bubble-user\" }", | |||
"connection": { | |||
"name": "sageConnection", | |||
"baseUri": "https://{{sageFqdn}}:{{serverConfig.nginxPort}}/api" | |||
@@ -41,11 +42,11 @@ | |||
"params": { | |||
"sageFqdn": "{{sageFqdn}}", | |||
"rootPassword": "{{sageRootPass}}", | |||
"username": "bubble-user", | |||
"username": "{{username}}", | |||
"password": "password1!", | |||
"userSessionVar": "userSession", | |||
"network": "bubble-{{rand 5}}", | |||
"email": "bubble-user@example.com", | |||
"email": "{{username}}@example.com", | |||
"plan": "bubble", | |||
"networkVar": "bubbleNetwork", | |||
"bubbleConnectionVar": "bubbleConnection", | |||
@@ -61,9 +62,6 @@ | |||
"uri": "me/networks/{{bubbleNetwork.network}}/storage/write/test_file_{{bubbleNetwork.network}}.txt", | |||
"headers": { "Content-Type": "multipart/form-data" }, | |||
"entity": {"file": "data:this is a test file: {{rand 20}}"} | |||
}, | |||
"response": { | |||
"store": "fileMeta" | |||
} | |||
}, | |||
@@ -71,11 +69,11 @@ | |||
"comment": "add verified email to root account on new node", | |||
"include": "add_approved_contact", | |||
"params": { | |||
"username": "bubble-user", | |||
"username": "{{username}}", | |||
"userSession": "bubbleUserSession", | |||
"userConnection": "bubbleConnection", | |||
"contactInfo": "bubble-user@example.com", | |||
"contactLookup": "bubble-user@example.com", | |||
"contactInfo": "{{username}}@example.com", | |||
"contactLookup": "{{username}}@example.com", | |||
"authFactor": "not_required", | |||
"rootSession": "bubbleUserSession", | |||
"rootConnection": "bubbleConnection" | |||
@@ -94,9 +92,6 @@ | |||
"agreeToTerms": true, | |||
"contact": {"type": "email", "info": "user-{{rand 5}}@example.com"} | |||
} | |||
}, | |||
"response": { | |||
"store": "newUser" | |||
} | |||
}, | |||
@@ -108,28 +103,14 @@ | |||
}, | |||
{ | |||
"comment": "backup network", | |||
"request": { | |||
"uri": "me/networks/{{bubbleNetwork.network}}/backups/test_backup", | |||
"method": "put" | |||
}, | |||
"response": { | |||
"store": "backup" | |||
} | |||
"comment": "backup network for later restore", | |||
"request": { "method": "put", "uri": "me/networks/{{bubbleNetwork.network}}/backups/test_backup" } | |||
}, | |||
{ | |||
"before": "await_url me/networks/{{bubbleNetwork.network}}/backups/test_backup?status=backup_completed 5m 10s", | |||
"comment": "find completed backup", | |||
"request": { | |||
"uri": "me/networks/{{bubbleNetwork.network}}/backups/test_backup" | |||
}, | |||
"response": { | |||
"store": "backup", | |||
"check": [ | |||
{"condition": "json.getStatus().name() == 'backup_completed'"} | |||
] | |||
} | |||
"comment": "await completed backup and store in the context", | |||
"before": "await_url me/networks/{{bubbleNetwork.network}}/backups/test_backup?status=backup_completed 90s:10m 15s", | |||
"request": { "uri": "me/networks/{{bubbleNetwork.network}}/backups/test_backup?status=backup_completed" } | |||
}, | |||
{ | |||
@@ -137,7 +118,7 @@ | |||
"include": "get_network_keys", | |||
"params": { | |||
"network": "{{bubbleNetwork.network}}", | |||
"rootEmail": "bubble-user@example.com", | |||
"rootEmail": "{{username}}@example.com", | |||
"networkKeysVar": "networkKeys", | |||
"networkKeysPassword": "Passw0rd!!" | |||
} | |||
@@ -155,13 +136,9 @@ | |||
}, | |||
{ | |||
"comment": "verify network is stopped", | |||
"request": {"uri": "me/networks/{{bubbleNetwork.network}}" }, | |||
"response": { | |||
"check": [ | |||
{"condition": "json.getState().name() == 'stopped'"} | |||
] | |||
} | |||
"comment": "wait for network to stop", | |||
"before": "await_url me/networks/{{bubbleNetwork.network}} 5m 10s await_json.getState().name() == 'stopped'", | |||
"request": { "uri": "me" } | |||
}, | |||
{ | |||
@@ -179,12 +156,12 @@ | |||
}, | |||
{ | |||
"before": "await_url .bubble 40m 20s", | |||
"comment": "restore node using restoreKey", | |||
"before": "await_url .bubble 16m:20m 20s", | |||
"connection": { | |||
"name": "restoredBubbleConnection", | |||
"baseUri": "https://{{restoreNN.fqdn}}:{{serverConfig.nginxPort}}/api" | |||
}, | |||
"comment": "restore node using restoreKey", | |||
"request": { | |||
"uri": "auth/restore/{{restoreNN.restoreKey}}", | |||
"entity": { | |||
@@ -193,17 +170,16 @@ | |||
}, | |||
"method": "put" | |||
}, | |||
"after": "sleep 240s" // give the restore some time to stop the server, restore and restart | |||
"after": "await_url .bubble 9m:10m 20s" // give the restore some time to stop the server, restore and restart | |||
}, | |||
{ | |||
"before": "await_url .bubble 10m 20s", | |||
"comment": "login to restored bubble", | |||
"request": { | |||
"session": "new", | |||
"uri": "auth/login", | |||
"entity": { | |||
"name": "bubble-user", | |||
"name": "{{username}}", | |||
"password": "password1!" | |||
} | |||
}, | |||
@@ -240,15 +216,16 @@ | |||
"request": { | |||
"uri": "me/networks/{{restoreNN.network}}/actions/stop", | |||
"method": "post" | |||
} | |||
}, | |||
"after": "await_url me/networks/{{restoreNN.network}} 5m 10s await_json.getState().name() == 'stopped'" | |||
}, | |||
{ | |||
"comment": "delete restored bubble network from sage", | |||
"comment": "delete restored bubble network from sage by deleting plan which should have the same name", | |||
"request": { | |||
"uri": "me/networks/{{restoreNN.network}}", | |||
"uri": "me/plans/{{restoreNN.network}}", | |||
"method": "delete" | |||
}, | |||
"after": "verify_unreachable https://{{restoreNN.fqdn}}:{{serverConfig.nginxPort}}/api/me" | |||
} | |||
] | |||
] |