diff --git a/app/server.py b/app/server.py index 060b144..90775a2 100644 --- a/app/server.py +++ b/app/server.py @@ -1,9 +1,9 @@ import configparser import json import os -import re import sys from os.path import join, dirname, expanduser +from functools import reduce import ansible_runner import yaml @@ -55,12 +55,27 @@ task_program = '' class Status: RUNNING = 'running' - ERROR = 'error' - CANCELLED = 'cancelled' - DONE = 'done' + ERROR = 'failed' + TIMEOUT = 'timeout' + CANCELLED = 'canceled' + DONE = 'successful' NEW = None +def by_path(data: dict, path: str): + def get(obj, attr): + if type(obj) is dict: + return obj.get(attr, None) + elif type(obj) is list: + try: + return obj[int(attr)] + except ValueError: + return None + else: + return None + + return reduce(get, path.split('.'), data) + class Playbook: def __init__(self): @@ -69,28 +84,40 @@ class Playbook: self.events = [] self.config_vars = {} self._runner = None + + def parse(self, event: dict): + data = {} + if by_path(event, 'event_data.task') == 'Set subjectAltName as a fact': + ansible_ssh_host = by_path(event, 'event_data.res.ansible_facts.IP_subject_alt_name') + if ansible_ssh_host: + data['ansible_ssh_host'] = ansible_ssh_host + + if by_path(event, 'event_data.play') == 'Configure the server and install required software': + local_service_ip = by_path(event, 'event_data.res.ansible_facts.ansible_lo.ipv4_secondaries.0.address') + ipv6 = by_path(event, 'event_data.res.ansible_facts.ansible_lo.ipv6.0.address') + p12_export_password = by_path(event, 'event_data.res.ansible_facts.p12_export_password') + if local_service_ip: + data['local_service_ip'] = local_service_ip + if ipv6: + data['ipv6'] = ipv6 + if p12_export_password: + data['p12_export_password'] = p12_export_password + + if by_path(event, 'event_data.play') == 'Provision the server': + host_name = by_path(event, 'event_data.res.add_host.host_name') + if host_name: + data['host_name'] = host_name + + return data if data else None def event_handler(self, data: dict) -> None: - if data['event'] == 'runner_on_ok': - # Looking for '-passout pass:"{{ CA_password }}"' - if 'Build the CA pair' in data['event_data']['task']: - m = re.match(r'-passout pass:\"(?P.*)\"', data['event_data']['cmd']) - if m: - self.config_vars['CA_password'] = m.group('password') + if self.parse(data): + self.config_vars.update(self.parse(data)) - # Looking for '-passout pass:"{{ p12_export_password }}"' - if "Build the client's p12" in data['event_data']['task']: - m = re.match(r'-passout pass:\"(?P.*)\"', data['event_data']['cmd']) - if m: - self.config_vars['p12_export_password'] = m.group('password') + self.events.append(data) - # Looking for 'DNS = {{ wireguard_dns_servers }}' - if "Generate QR codes" in data['event_data']['task']: - self.config_vars['host'] = data['event_data']['host'] - m = re.match(r'DNS = (?P.*)\n\n', data['event_data']['cmd']) - if m: - self.config_vars['local_service_ip'] = m.group('dns') - self.events.append(data) + def status_handler(self, status_data: dict, *args, **kwargs) -> None: + self.status = status_data.get('status') def cancel_handler(self) -> bool: if self.want_cancel: @@ -103,11 +130,14 @@ class Playbook: def run(self, extra_vars: dict) -> None: self.want_cancel = False self.status = Status.RUNNING - _, runner = ansible_runner.run_async(private_data_dir='.', - playbook='main.yml', - extravars=extra_vars, - cancel_callback=self.cancel_handler, - event_handler=self.event_handler) + _, runner = ansible_runner.run_async( + private_data_dir='.', + playbook='main.yml', + extravars=extra_vars, + status_handler=self.status_handler, + cancel_callback=self.cancel_handler, + event_handler=self.event_handler + ) self._runner = runner @@ -282,12 +312,14 @@ async def check_vultr_config(request): try: open(os.environ['VULTR_API_CONFIG'], 'r').read() response['has_secret'] = True + response['saved_to'] = os.environ.get('VULTR_API_CONFIG') except IOError: pass try: default_path = expanduser(join('~', '.vultr.ini')) open(default_path, 'r').read() response['has_secret'] = True + response['saved_to'] = default_path except IOError: pass return web.json_response(response) diff --git a/app/static/index.html b/app/static/index.html index ee73afd..2ca9e61 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -71,10 +71,10 @@

🙂 Please be patient

-

+

😢 Set up failed

-

+

🥳 Congratulations, your Algo server is running!

@@ -82,7 +82,7 @@

-
+
- - - -
+

Now it’s time to inspect console output

Restart console process to try again

- - +
@@ -144,13 +144,13 @@ 'provider-setup': window.httpVueLoader('/static/provider-setup.vue'), 'command-preview': window.httpVueLoader('/static/command-preview.vue'), 'status-running': window.httpVueLoader('/static/status-running.vue'), - 'status-done': window.httpVueLoader('/static/status-done.vue') + 'status-successful': window.httpVueLoader('/static/status-done.vue') }, created() { fetch("/playbook") .then(r => r.json()) .catch(() => { - this.step = 'status-error'; + this.step = 'status-failed'; }) .then(data => { if (data.status && data.status !== 'cancelled'){ diff --git a/app/static/provider-vultr.vue b/app/static/provider-vultr.vue index dbec245..594659b 100644 --- a/app/static/provider-vultr.vue +++ b/app/static/provider-vultr.vue @@ -85,6 +85,7 @@ module.exports = { .then(response => { if (response.has_secret) { this.ui_token_from_env = true; + this.vultr_config = response.saved_to; this.load_regions(); } else if (response.error) { this.ui_config_error = response.error; @@ -138,10 +139,8 @@ module.exports = { }, submit() { let submit_value = { - region: this.region - } - if (!this.ui_token_from_env) { - submit_value['vultr_config'] = this.vultr_config; + region: this.region, + vultr_config: this.vultr_config } this.$emit("submit", submit_value); }, @@ -150,4 +149,4 @@ module.exports = { "region-select": window.httpVueLoader("/static/region-select.vue"), } }; - \ No newline at end of file + diff --git a/app/static/status-done.vue b/app/static/status-done.vue index fba4f9c..e0ea7b0 100644 --- a/app/static/status-done.vue +++ b/app/static/status-done.vue @@ -7,7 +7,7 @@

Local DNS resolver {{result.local_service_ip}}

The p12 and SSH keys password for new users is {{result.p12_export_password}}

The CA key password is {{result.CA_password}}

-

Shell access: ssh -F configs/{{result.ansible_ssh_host}}/ssh_config {{config.server_name}}

+

Shell access: ssh -F configs/{{result.ansible_ssh_host}}/ssh_config {{config.server_name}}

Read more on how to set up clients at the Algo home page

diff --git a/app/static/status-running.vue b/app/static/status-running.vue index c25ec19..eb8a830 100644 --- a/app/static/status-running.vue +++ b/app/static/status-running.vue @@ -8,7 +8,7 @@

Don’t close terminal!

- [{{ event.counter }}]: {{ event.stdout }} + {{ event.stdout }}
@@ -43,8 +43,12 @@ module.exports = { }) .then(data => { this.events = data.events; - if (data.status && data.status === 'done') { - this.$emit('done'); + if (data.status && data.status === 'successful') { + this.$emit('successful'); + throw new Error(); + } + if (data.status && data.status === 'failed') { + this.$emit('error'); throw new Error(); } if (!data.status || data.status === 'cancelled') {