Merge branch 'master' into update-docs

This commit is contained in:
TC1977 2019-05-12 09:20:20 -04:00 committed by GitHub
commit 5ab17fae59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 702 additions and 173 deletions

9
docs/cloud-scaleway.md Normal file
View file

@ -0,0 +1,9 @@
### Configuration file
Algo requires an API key from your Scaleway account to create a server.
The API key is generated by going to your Scaleway credentials at [https://console.scaleway.com/account/credentials](https://console.scaleway.com/account/credentials), and then selecting "Generate new token" on the right side of the box labeled "API Tokens".
Enter this token when Algo prompts you for the `auth token`.
This information will be pass as the `algo_scaleway_token` variable when asked for in the Algo prompt.
Your organization ID is also on this page: https://console.scaleway.com/account/credentials

View file

@ -230,7 +230,6 @@ Possible options can be gathered via cli `aws lightsail get-regions`
Required variables:
- [scaleway_token](https://www.scaleway.com/docs/generate-an-api-token/)
- [scaleway_org](https://cloud.scaleway.com/#/billing)
- region
Possible regions:

View file

@ -18,7 +18,7 @@ First of all, check [this](https://github.com/trailofbits/algo#features) and ens
* [Windows: The value of parameter linuxConfiguration.ssh.publicKeys.keyData is invalid](#windows-the-value-of-parameter-linuxconfigurationsshpublickeyskeydata-is-invalid)
* [Docker: Failed to connect to the host via ssh](#docker-failed-to-connect-to-the-host-via-ssh)
* [Wireguard: Unable to find 'configs/...' in expected paths](#wireguard-unable-to-find-configs-in-expected-paths)
* [Ubuntu Error: "unable to write 'random state" when generating CA password](#ubuntu-error-unable-to-write-random-state-when-generating-ca-password")
* [Ubuntu Error: "unable to write 'random state'" when generating CA password](#ubuntu-error-unable-to-write-random-state-when-generating-ca-password)
* [Connection Problems](#connection-problems)
* [I'm blocked or get CAPTCHAs when I access certain websites](#im-blocked-or-get-captchas-when-i-access-certain-websites)
* [I want to change the list of trusted Wifi networks on my Apple device](#i-want-to-change-the-list-of-trusted-wifi-networks-on-my-apple-device)
@ -153,7 +153,9 @@ You need to reset the permissions on your `.ssh` directory. Run `chmod 700 /home
### The region you want is not available
You want to install Algo to a specific region in a cloud provider, but that region is not available in the list given by the installer. In that case, you should [file an issue](https://github.com/trailofbits/algo/issues/new). Cloud providers add new regions on a regular basis and we don't always keep up. File an issue and give us information about what region is missing and we'll add it.
Algo downloads the regions from the supported cloud providers (other than Microsoft Azure) listed in the first menu using APIs. If the region you want isn't available, the cloud provider has probably taken it offline for some reason. You should investigate further with your cloud provider.
If there's a specific region you want to install to in Microsoft Azure that isn't available, you should [file an issue](https://github.com/trailofbits/algo/issues/new), give us information about what region is missing, and we'll add it.
### AWS: SSH permission denied with an ECDSA key
@ -269,7 +271,7 @@ sudo rm -rf /etc/wireguard/*.lock
```
Then immediately re-run `./algo`.
### Ubuntu Error: "unable to write 'random state" when generating CA password
### Ubuntu Error: "unable to write 'random state'" when generating CA password
When running Algo, you received an error like this:

View file

@ -26,7 +26,7 @@
tasks:
- block:
- name: Region prompt
- name: Cloud prompt
pause:
prompt: |
What provider would you like to use?
@ -122,11 +122,11 @@
{{ _server | regex_replace('(?!\.)(\W|_)', '-') }}
algo_ondemand_cellular: >-
{% if ondemand_cellular is defined %}{{ ondemand_cellular | bool }}
{%- elif _ondemand_cellular.user_input %}{{ booleans_map[_ondemand_cellular.user_input] | default(defaults['ondemand_cellular']) }}
{%- elif _ondemand_cellular.user_input is defined %}{{ booleans_map[_ondemand_cellular.user_input] | default(defaults['ondemand_cellular']) }}
{%- else %}false{% endif %}
algo_ondemand_wifi: >-
{% if ondemand_wifi is defined %}{{ ondemand_wifi | bool }}
{%- elif _ondemand_wifi.user_input %}{{ booleans_map[_ondemand_wifi.user_input] | default(defaults['ondemand_wifi']) }}
{%- elif _ondemand_wifi.user_input is defined %}{{ booleans_map[_ondemand_wifi.user_input] | default(defaults['ondemand_wifi']) }}
{%- else %}false{% endif %}
algo_ondemand_wifi_exclude: >-
{% if ondemand_wifi_exclude is defined %}{{ ondemand_wifi_exclude | b64encode }}
@ -135,19 +135,19 @@
{%- else %}{{ '_null' | b64encode }}{% endif %}
algo_local_dns: >-
{% if local_dns is defined %}{{ local_dns | bool }}
{%- elif _local_dns.user_input %}{{ booleans_map[_local_dns.user_input] | default(defaults['local_dns']) }}
{%- elif _local_dns.user_input is defined %}{{ booleans_map[_local_dns.user_input] | default(defaults['local_dns']) }}
{%- else %}false{% endif %}
algo_ssh_tunneling: >-
{% if ssh_tunneling is defined %}{{ ssh_tunneling | bool }}
{%- elif _ssh_tunneling.user_input %}{{ booleans_map[_ssh_tunneling.user_input] | default(defaults['ssh_tunneling']) }}
{%- elif _ssh_tunneling.user_input is defined %}{{ booleans_map[_ssh_tunneling.user_input] | default(defaults['ssh_tunneling']) }}
{%- else %}false{% endif %}
algo_windows: >-
{% if windows is defined %}{{ windows | bool }}
{%- elif _windows.user_input %}{{ booleans_map[_windows.user_input] | default(defaults['windows']) }}
{%- elif _windows.user_input is defined %}{{ booleans_map[_windows.user_input] | default(defaults['windows']) }}
{%- else %}false{% endif %}
algo_store_cakey: >-
{% if store_cakey is defined %}{{ store_cakey | bool }}
{%- elif _store_cakey.user_input %}{{ booleans_map[_store_cakey.user_input] | default(defaults['store_cakey']) }}
{%- else %}false{% endif %}
{% if ipsec_enabled %}{%- if store_cakey is defined %}{{ store_cakey | bool }}
{%- elif _store_cakey.user_input is defined %}{{ booleans_map[_store_cakey.user_input] | default(defaults['store_cakey']) }}
{%- else %}false{% endif %}{% endif %}
rescue:
- include_tasks: playbooks/rescue.yml

619
library/scaleway_compute.py Normal file
View file

@ -0,0 +1,619 @@
#!/usr/bin/python
#
# Scaleway Compute management module
#
# Copyright (C) 2018 Online SAS.
# https://www.scaleway.com
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: scaleway_compute
short_description: Scaleway compute management module
version_added: "2.6"
author: Remy Leone (@sieben)
description:
- "This module manages compute instances on Scaleway."
extends_documentation_fragment: scaleway
options:
enable_ipv6:
description:
- Enable public IPv6 connectivity on the instance
default: false
type: bool
boot_type:
description:
- Boot method
default: bootscript
choices:
- bootscript
- local
image:
description:
- Image identifier used to start the instance with
required: true
name:
description:
- Name of the instance
organization:
description:
- Organization identifier
required: true
state:
description:
- Indicate desired state of the instance.
default: present
choices:
- present
- absent
- running
- restarted
- stopped
tags:
description:
- List of tags to apply to the instance (5 max)
required: false
default: []
region:
description:
- Scaleway compute zone
required: true
choices:
- ams1
- EMEA-NL-EVS
- par1
- EMEA-FR-PAR1
commercial_type:
description:
- Commercial name of the compute node
required: true
choices:
- ARM64-2GB
- ARM64-4GB
- ARM64-8GB
- ARM64-16GB
- ARM64-32GB
- ARM64-64GB
- ARM64-128GB
- C1
- C2S
- C2M
- C2L
- START1-XS
- START1-S
- START1-M
- START1-L
- X64-15GB
- X64-30GB
- X64-60GB
- X64-120GB
wait:
description:
- Wait for the instance to reach its desired state before returning.
type: bool
default: 'no'
wait_timeout:
description:
- Time to wait for the server to reach the expected state
required: false
default: 300
wait_sleep_time:
description:
- Time to wait before every attempt to check the state of the server
required: false
default: 3
'''
EXAMPLES = '''
- name: Create a server
scaleway_compute:
name: foobar
state: present
image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe
organization: 951df375-e094-4d26-97c1-ba548eeb9c42
region: ams1
commercial_type: VC1S
tags:
- test
- www
- name: Destroy it right after
scaleway_compute:
name: foobar
state: absent
image: 89ee4018-f8c3-4dc4-a6b5-bca14f985ebe
organization: 951df375-e094-4d26-97c1-ba548eeb9c42
region: ams1
commercial_type: VC1S
'''
RETURN = '''
'''
import datetime
import time
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import quote as urlquote
from ansible.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway
SCALEWAY_COMMERCIAL_TYPES = [
# Virtual ARM64 compute instance
'ARM64-2GB',
'ARM64-4GB',
'ARM64-8GB',
'ARM64-16GB',
'ARM64-32GB',
'ARM64-64GB',
'ARM64-128GB',
# Baremetal
'C1', # ARM64 (4 cores) - 2GB
'C2S', # X86-64 (4 cores) - 8GB
'C2M', # X86-64 (8 cores) - 16GB
'C2L', # x86-64 (8 cores) - 32 GB
# Virtual X86-64 compute instance
'START1-XS', # Starter X86-64 (1 core) - 1GB - 25 GB NVMe
'START1-S', # Starter X86-64 (2 cores) - 2GB - 50 GB NVMe
'START1-M', # Starter X86-64 (4 cores) - 4GB - 100 GB NVMe
'START1-L', # Starter X86-64 (8 cores) - 8GB - 200 GB NVMe
'X64-15GB',
'X64-30GB',
'X64-60GB',
'X64-120GB',
]
SCALEWAY_SERVER_STATES = (
'stopped',
'stopping',
'starting',
'running',
'locked'
)
SCALEWAY_TRANSITIONS_STATES = (
"stopping",
"starting",
"pending"
)
def fetch_state(compute_api, server):
compute_api.module.debug("fetch_state of server: %s" % server["id"])
response = compute_api.get(path="servers/%s" % server["id"])
if response.status_code == 404:
return "absent"
if not response.ok:
msg = 'Error during state fetching: (%s) %s' % (response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
try:
compute_api.module.debug("Server %s in state: %s" % (server["id"], response.json["server"]["state"]))
return response.json["server"]["state"]
except KeyError:
compute_api.module.fail_json(msg="Could not fetch state in %s" % response.json)
def wait_to_complete_state_transition(compute_api, server):
wait = compute_api.module.params["wait"]
if not wait:
return
wait_timeout = compute_api.module.params["wait_timeout"]
wait_sleep_time = compute_api.module.params["wait_sleep_time"]
start = datetime.datetime.utcnow()
end = start + datetime.timedelta(seconds=wait_timeout)
while datetime.datetime.utcnow() < end:
compute_api.module.debug("We are going to wait for the server to finish its transition")
if fetch_state(compute_api, server) not in SCALEWAY_TRANSITIONS_STATES:
compute_api.module.debug("It seems that the server is not in transition anymore.")
compute_api.module.debug("Server in state: %s" % fetch_state(compute_api, server))
break
time.sleep(wait_sleep_time)
else:
compute_api.module.fail_json(msg="Server takes too long to finish its transition")
def create_server(compute_api, server):
compute_api.module.debug("Starting a create_server")
target_server = None
response = compute_api.post(path="servers",
data={"enable_ipv6": server["enable_ipv6"],
"boot_type": server["boot_type"],
"tags": server["tags"],
"commercial_type": server["commercial_type"],
"image": server["image"],
"name": server["name"],
"organization": server["organization"]})
if not response.ok:
msg = 'Error during server creation: (%s) %s' % (response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
try:
target_server = response.json["server"]
except KeyError:
compute_api.module.fail_json(msg="Error in getting the server information from: %s" % response.json)
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
return target_server
def restart_server(compute_api, server):
return perform_action(compute_api=compute_api, server=server, action="reboot")
def stop_server(compute_api, server):
return perform_action(compute_api=compute_api, server=server, action="poweroff")
def start_server(compute_api, server):
return perform_action(compute_api=compute_api, server=server, action="poweron")
def perform_action(compute_api, server, action):
response = compute_api.post(path="servers/%s/action" % server["id"],
data={"action": action})
if not response.ok:
msg = 'Error during server %s: (%s) %s' % (action, response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
wait_to_complete_state_transition(compute_api=compute_api, server=server)
return response
def remove_server(compute_api, server):
compute_api.module.debug("Starting remove server strategy")
response = compute_api.delete(path="servers/%s" % server["id"])
if not response.ok:
msg = 'Error during server deletion: (%s) %s' % (response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
wait_to_complete_state_transition(compute_api=compute_api, server=server)
return response
def present_strategy(compute_api, wished_server):
compute_api.module.debug("Starting present strategy")
changed = False
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
if not query_results:
changed = True
if compute_api.module.check_mode:
return changed, {"status": "A server would be created."}
target_server = create_server(compute_api=compute_api, server=wished_server)
else:
target_server = query_results[0]
if server_attributes_should_be_changed(compute_api=compute_api, target_server=target_server,
wished_server=wished_server):
changed = True
if compute_api.module.check_mode:
return changed, {"status": "Server %s attributes would be changed." % target_server["id"]}
server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
return changed, target_server
def absent_strategy(compute_api, wished_server):
compute_api.module.debug("Starting absent strategy")
changed = False
target_server = None
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
if not query_results:
return changed, {"status": "Server already absent."}
else:
target_server = query_results[0]
changed = True
if compute_api.module.check_mode:
return changed, {"status": "Server %s would be made absent." % target_server["id"]}
# A server MUST be stopped to be deleted.
while not fetch_state(compute_api=compute_api, server=target_server) == "stopped":
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
response = stop_server(compute_api=compute_api, server=target_server)
if not response.ok:
err_msg = 'Error while stopping a server before removing it [{0}: {1}]'.format(response.status_code,
response.json)
compute_api.module.fail_json(msg=err_msg)
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
response = remove_server(compute_api=compute_api, server=target_server)
if not response.ok:
err_msg = 'Error while removing server [{0}: {1}]'.format(response.status_code, response.json)
compute_api.module.fail_json(msg=err_msg)
return changed, {"status": "Server %s deleted" % target_server["id"]}
def running_strategy(compute_api, wished_server):
compute_api.module.debug("Starting running strategy")
changed = False
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
if not query_results:
changed = True
if compute_api.module.check_mode:
return changed, {"status": "A server would be created before being run."}
target_server = create_server(compute_api=compute_api, server=wished_server)
else:
target_server = query_results[0]
if server_attributes_should_be_changed(compute_api=compute_api, target_server=target_server,
wished_server=wished_server):
changed = True
if compute_api.module.check_mode:
return changed, {"status": "Server %s attributes would be changed before running it." % target_server["id"]}
server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
current_state = fetch_state(compute_api=compute_api, server=target_server)
if current_state not in ("running", "starting"):
compute_api.module.debug("running_strategy: Server in state: %s" % current_state)
changed = True
if compute_api.module.check_mode:
return changed, {"status": "Server %s attributes would be changed." % target_server["id"]}
response = start_server(compute_api=compute_api, server=target_server)
if not response.ok:
msg = 'Error while running server [{0}: {1}]'.format(response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
return changed, target_server
def stop_strategy(compute_api, wished_server):
compute_api.module.debug("Starting stop strategy")
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
changed = False
if not query_results:
if compute_api.module.check_mode:
return changed, {"status": "A server would be created before being stopped."}
target_server = create_server(compute_api=compute_api, server=wished_server)
changed = True
else:
target_server = query_results[0]
compute_api.module.debug("stop_strategy: Servers are found.")
if server_attributes_should_be_changed(compute_api=compute_api, target_server=target_server,
wished_server=wished_server):
changed = True
if compute_api.module.check_mode:
return changed, {
"status": "Server %s attributes would be changed before stopping it." % target_server["id"]}
server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
current_state = fetch_state(compute_api=compute_api, server=target_server)
if current_state not in ("stopped",):
compute_api.module.debug("stop_strategy: Server in state: %s" % current_state)
changed = True
if compute_api.module.check_mode:
return changed, {"status": "Server %s would be stopped." % target_server["id"]}
response = stop_server(compute_api=compute_api, server=target_server)
compute_api.module.debug(response.json)
compute_api.module.debug(response.ok)
if not response.ok:
msg = 'Error while stopping server [{0}: {1}]'.format(response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
return changed, target_server
def restart_strategy(compute_api, wished_server):
compute_api.module.debug("Starting restart strategy")
changed = False
query_results = find(compute_api=compute_api, wished_server=wished_server, per_page=1)
if not query_results:
changed = True
if compute_api.module.check_mode:
return changed, {"status": "A server would be created before being rebooted."}
target_server = create_server(compute_api=compute_api, server=wished_server)
else:
target_server = query_results[0]
if server_attributes_should_be_changed(compute_api=compute_api,
target_server=target_server,
wished_server=wished_server):
changed = True
if compute_api.module.check_mode:
return changed, {
"status": "Server %s attributes would be changed before rebooting it." % target_server["id"]}
server_change_attributes(compute_api=compute_api, target_server=target_server, wished_server=wished_server)
changed = True
if compute_api.module.check_mode:
return changed, {"status": "Server %s would be rebooted." % target_server["id"]}
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
if fetch_state(compute_api=compute_api, server=target_server) in ("running",):
response = restart_server(compute_api=compute_api, server=target_server)
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
if not response.ok:
msg = 'Error while restarting server that was running [{0}: {1}].'.format(response.status_code,
response.json)
compute_api.module.fail_json(msg=msg)
if fetch_state(compute_api=compute_api, server=target_server) in ("stopped",):
response = restart_server(compute_api=compute_api, server=target_server)
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
if not response.ok:
msg = 'Error while restarting server that was stopped [{0}: {1}].'.format(response.status_code,
response.json)
compute_api.module.fail_json(msg=msg)
return changed, target_server
state_strategy = {
"present": present_strategy,
"restarted": restart_strategy,
"stopped": stop_strategy,
"running": running_strategy,
"absent": absent_strategy
}
def find(compute_api, wished_server, per_page=1):
compute_api.module.debug("Getting inside find")
# Only the name attribute is accepted in the Compute query API
url = 'servers?name=%s&per_page=%d' % (urlquote(wished_server["name"]), per_page)
response = compute_api.get(url)
if not response.ok:
msg = 'Error during server search: (%s) %s' % (response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
search_results = response.json["servers"]
return search_results
PATCH_MUTABLE_SERVER_ATTRIBUTES = (
"ipv6",
"tags",
"name",
"dynamic_ip_required",
)
def server_attributes_should_be_changed(compute_api, target_server, wished_server):
compute_api.module.debug("Checking if server attributes should be changed")
compute_api.module.debug("Current Server: %s" % target_server)
compute_api.module.debug("Wished Server: %s" % wished_server)
debug_dict = dict((x, (target_server[x], wished_server[x]))
for x in PATCH_MUTABLE_SERVER_ATTRIBUTES
if x in target_server and x in wished_server)
compute_api.module.debug("Debug dict %s" % debug_dict)
try:
return any([target_server[x] != wished_server[x]
for x in PATCH_MUTABLE_SERVER_ATTRIBUTES
if x in target_server and x in wished_server])
except AttributeError:
compute_api.module.fail_json(msg="Error while checking if attributes should be changed")
def server_change_attributes(compute_api, target_server, wished_server):
compute_api.module.debug("Starting patching server attributes")
patch_payload = dict((x, wished_server[x])
for x in PATCH_MUTABLE_SERVER_ATTRIBUTES
if x in wished_server and x in target_server)
response = compute_api.patch(path="servers/%s" % target_server["id"],
data=patch_payload)
if not response.ok:
msg = 'Error during server attributes patching: (%s) %s' % (response.status_code, response.json)
compute_api.module.fail_json(msg=msg)
wait_to_complete_state_transition(compute_api=compute_api, server=target_server)
return response
def core(module):
region = module.params["region"]
wished_server = {
"state": module.params["state"],
"image": module.params["image"],
"name": module.params["name"],
"commercial_type": module.params["commercial_type"],
"enable_ipv6": module.params["enable_ipv6"],
"boot_type": module.params["boot_type"],
"tags": module.params["tags"],
"organization": module.params["organization"]
}
module.params['api_url'] = SCALEWAY_LOCATION[region]["api_endpoint"]
compute_api = Scaleway(module=module)
changed, summary = state_strategy[wished_server["state"]](compute_api=compute_api, wished_server=wished_server)
module.exit_json(changed=changed, msg=summary)
def main():
argument_spec = scaleway_argument_spec()
argument_spec.update(dict(
image=dict(required=True),
name=dict(),
region=dict(required=True, choices=SCALEWAY_LOCATION.keys()),
commercial_type=dict(required=True, choices=SCALEWAY_COMMERCIAL_TYPES),
enable_ipv6=dict(default=False, type="bool"),
boot_type=dict(default="bootscript"),
state=dict(choices=state_strategy.keys(), default='present'),
tags=dict(type="list", default=[]),
organization=dict(required=True),
wait=dict(type="bool", default=False),
wait_timeout=dict(type="int", default=300),
wait_sleep_time=dict(type="int", default=3),
))
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
core(module)
if __name__ == '__main__':
main()

View file

@ -4,12 +4,14 @@
shell: >
./algo-showenv.sh \
'algo_provider "{{ algo_provider }}"' \
{% if ipsec_enabled %}
'algo_ondemand_cellular "{{ algo_ondemand_cellular }}"' \
'algo_ondemand_wifi "{{ algo_ondemand_wifi }}"' \
'algo_ondemand_wifi_exclude "{{ algo_ondemand_wifi_exclude }}"' \
'algo_windows "{{ algo_windows }}"' \
{% endif %}
'algo_local_dns "{{ algo_local_dns }}"' \
'algo_ssh_tunneling "{{ algo_ssh_tunneling }}"' \
'algo_windows "{{ algo_windows }}"' \
'wireguard_enabled "{{ wireguard_enabled }}"' \
'dns_encryption "{{ dns_encryption }}"' \
> /dev/tty

View file

@ -1,10 +0,0 @@
---
- name: Set image id as a fact
set_fact:
image_id: "{{ item.id }}"
no_log: true
when:
- cloud_providers.scaleway.image == item.name
- cloud_providers.scaleway.arch == item.arch
- server_disk_size == item.root_volume.size
with_items: "{{ outer_item['json']['images'] }}"

View file

@ -1,133 +1,46 @@
- name: Include prompts
import_tasks: prompts.yml
- name: Set disk size
set_fact:
server_disk_size: 50000000000
- name: Check server size
set_fact:
server_disk_size: 25000000000
when: cloud_providers.scaleway.size == "START1-XS"
- name: Check if server exists
uri:
url: "https://cp-{{ algo_region }}.scaleway.com/servers"
method: GET
headers:
Content-Type: 'application/json'
X-Auth-Token: "{{ algo_scaleway_token }}"
status_code: 200
register: scaleway_servers
- name: Set server id as a fact
set_fact:
server_id: "{{ item.id }}"
no_log: true
when: algo_server_name == item.name
with_items: "{{ scaleway_servers.json.servers }}"
- name: Create a server if it doesn't exist
block:
- name: Get the organization id
uri:
url: https://account.cloud.online.net/organizations
method: GET
headers:
Content-Type: 'application/json'
X-Auth-Token: "{{ algo_scaleway_token }}"
status_code: 200
register: scaleway_organizations
- name: Set organization id as a fact
set_fact:
organization_id: "{{ item.id }}"
no_log: true
when: algo_scaleway_org == item.name
with_items: "{{ scaleway_organizations.json.organizations }}"
- name: Get total count of images
uri:
url: "https://cp-{{ algo_region }}.scaleway.com/images"
method: GET
headers:
Content-Type: 'application/json'
X-Auth-Token: "{{ algo_scaleway_token }}"
status_code: 200
register: scaleway_pages
- block:
- name: Gather Scaleway organizations facts
scaleway_organization_facts:
- name: Get images
uri:
url: "https://cp-{{ algo_region }}.scaleway.com/images?per_page=100&page={{ item }}"
method: GET
headers:
Content-Type: 'application/json'
X-Auth-Token: "{{ algo_scaleway_token }}"
status_code: 200
register: scaleway_images
with_sequence: start=1 end={{ ((scaleway_pages.x_total_count|int / 100)| round )|int }}
scaleway_image_facts:
region: "{{ algo_region }}"
- name: Set image id as a fact
include_tasks: image_facts.yml
with_items: "{{ scaleway_images['results'] }}"
loop_control:
loop_var: outer_item
- name: Set cloud specific facts
set_fact:
organization_id: "{{ scaleway_organization_facts[0]['id'] }}"
images: >-
[{% for i in scaleway_image_facts -%}
{% if i.name == cloud_providers.scaleway.image and
i.arch == cloud_providers.scaleway.arch -%}
'{{ i.id }}'{% if not loop.last %},{% endif %}
{%- endif -%}
{%- endfor -%}]
- name: Create a server
uri:
url: "https://cp-{{ algo_region }}.scaleway.com/servers/"
method: POST
headers:
Content-Type: 'application/json'
X-Auth-Token: "{{ algo_scaleway_token }}"
body:
organization: "{{ organization_id }}"
name: "{{ algo_server_name }}"
image: "{{ image_id }}"
commercial_type: "{{ cloud_providers.scaleway.size }}"
enable_ipv6: true
boot_type: local
tags:
- Environment:Algo
- AUTHORIZED_KEY={{ lookup('file', SSH_keys.public)|regex_replace(' ', '_') }}
status_code: 201
body_format: json
scaleway_compute:
name: "{{ algo_server_name }}"
enable_ipv6: true
boot_type: local
state: running
image: "{{ images[0] }}"
organization: "{{ organization_id }}"
region: "{{ algo_region }}"
commercial_type: "{{ cloud_providers.scaleway.size }}"
wait: true
tags:
- Environment:Algo
- AUTHORIZED_KEY={{ lookup('file', SSH_keys.public)|regex_replace(' ', '_') }}
register: algo_instance
- name: Set server id as a fact
set_fact:
server_id: "{{ algo_instance.json.server.id }}"
when: server_id is not defined
- name: Power on the server
uri:
url: https://cp-{{ algo_region }}.scaleway.com/servers/{{ server_id }}/action
method: POST
headers:
Content-Type: application/json
X-Auth-Token: "{{ algo_scaleway_token }}"
body:
action: poweron
status_code: 202
body_format: json
ignore_errors: true
no_log: true
- name: Wait for the server to become running
uri:
url: "https://cp-{{ algo_region }}.scaleway.com/servers/{{ server_id }}"
method: GET
headers:
Content-Type: 'application/json'
X-Auth-Token: "{{ algo_scaleway_token }}"
status_code: 200
until:
- algo_instance.json.server.state is defined
- algo_instance.json.server.state == "running"
retries: 20
delay: 30
register: algo_instance
until: algo_instance.msg.public_ip
retries: 3
delay: 3
environment:
SCW_TOKEN: "{{ algo_scaleway_token }}"
- set_fact:
cloud_instance_ip: "{{ algo_instance['json']['server']['public_ip']['address'] }}"
cloud_instance_ip: "{{ algo_instance.msg.public_ip.address }}"
ansible_ssh_user: root

View file

@ -1,16 +1,12 @@
---
- pause:
prompt: |
Enter your auth token (https://www.scaleway.com/docs/generate-an-api-token/)
Enter your auth token (https://trailofbits.github.io/algo/cloud-scaleway.html)
echo: false
register: _scaleway_token
when: scaleway_token is undefined
- pause:
prompt: |
Enter your organization name (https://cloud.scaleway.com/#/billing)
register: _scaleway_org
when: scaleway_org is undefined
when:
- scaleway_token is undefined
- lookup('env','SCW_TOKEN')|length <= 0
- pause:
prompt: |
@ -26,8 +22,7 @@
- name: Set scaleway facts
set_fact:
algo_scaleway_token: "{{ scaleway_token | default(_scaleway_token.user_input) }}"
algo_scaleway_org: "{{ scaleway_org | default(_scaleway_org.user_input|default(omit)) }}"
algo_scaleway_token: "{{ scaleway_token | default(_scaleway_token.user_input) | default(lookup('env','SCW_TOKEN'), true) }}"
algo_region: >-
{% if region is defined %}{{ region }}
{%- elif _algo_region.user_input %}{{ scaleway_regions[_algo_region.user_input | int -1 ]['alias'] }}

View file

@ -13,21 +13,21 @@
{%- elif _algo_server.user_input %}{{ _algo_server.user_input }}
{%- else %}localhost{% endif %}
- pause:
prompt: |
What user should we use to login on the server? (note: passwordless login required, or ignore if you're deploying to localhost)
[root]
register: _algo_ssh_user
when:
- ssh_user is undefined
- cloud_instance_ip != "localhost"
- block:
- pause:
prompt: |
What user should we use to login on the server? (note: passwordless login required, or ignore if you're deploying to localhost)
[root]
register: _algo_ssh_user
when: ssh_user is undefined
- name: Set the facts
set_fact:
ansible_ssh_user: >-
{% if ssh_user is defined %}{{ ssh_user }}
{%- elif _algo_ssh_user.user_input %}{{ _algo_ssh_user.user_input }}
{%- else %}root{% endif %}
- name: Set the facts
set_fact:
ansible_ssh_user: >-
{% if ssh_user is defined %}{{ ssh_user }}
{%- elif _algo_ssh_user.user_input %}{{ _algo_ssh_user.user_input }}
{%- else %}root{% endif %}
when: cloud_instance_ip != "localhost"
- pause:
prompt: |

View file

@ -40,6 +40,10 @@
{%- elif _ca_password.user_input %}{{ _ca_password.user_input }}
{%- else %}omit{% endif %}
- name: Local pre-tasks
import_tasks: playbooks/cloud-pre.yml
become: false
- name: Add the server to the vpn-host group
add_host:
name: "{{ algo_server }}"
@ -61,10 +65,6 @@
tasks:
- block:
- name: Local pre-tasks
import_tasks: playbooks/cloud-pre.yml
become: false
- import_role:
name: common