diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml
index 9c39200c..8c3f51d8 100644
--- a/.github/workflows/molecule.yml
+++ b/.github/workflows/molecule.yml
@@ -4,11 +4,15 @@ name: Run Molecule Test
on:
workflow_call:
inputs:
- image:
+ scenario:
required: true
type: string
+ image:
+ required: false
+ type: string
+ default: 'ghcr.io/artis3n/docker-ubuntu2204-ansible:latest'
command:
- required: true
+ required: false
type: string
runner:
required: false
@@ -24,8 +28,8 @@ env:
ANSIBLE_FORCE_COLOR: '1'
jobs:
- run-molecule:
- name: "Run Molecule"
+ run-scenario:
+ name: "Run Molecule Scenario - ${{ inputs.image }} / ${{ inputs.scenario }}"
runs-on: ${{ inputs.runner }}
environment: E2E
@@ -48,14 +52,7 @@ jobs:
run: poetry install --no-interaction
- name: Default scenario
- run: poetry run molecule test --scenario-name default
- env:
- MOLECULE_DISTRO: "${{ inputs.image }}"
- MOLECULE_COMMAND: "${{ inputs.command }}"
- TAILSCALE_CI_KEY: "${{ secrets.tailscale_key }}"
-
- - name: Uninstall scenario
- run: poetry run molecule test --scenario-name state-absent
+ run: poetry run molecule test --scenario-name "${{ inputs.scenario }}"
env:
MOLECULE_DISTRO: "${{ inputs.image }}"
MOLECULE_COMMAND: "${{ inputs.command }}"
diff --git a/.github/workflows/pull_request_target.yml b/.github/workflows/pull_request_target.yml
index 6aea7b09..11d53aae 100644
--- a/.github/workflows/pull_request_target.yml
+++ b/.github/workflows/pull_request_target.yml
@@ -17,7 +17,7 @@ env:
jobs:
molecule:
- name: "Test Distro"
+ name: "Test Distros"
strategy:
fail-fast: false
matrix:
@@ -47,12 +47,13 @@ jobs:
with:
image: ${{ matrix.image }}
command: ${{ matrix.command }}
+ scenario: 'default'
secrets:
tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
# Systems that aren't working with cgroups v2 on ubuntu 22.04, but works on ubuntu 20.04
molecule-legacy:
- name: "Test Legacy Distro"
+ name: "Test Legacy Distros"
strategy:
fail-fast: false
matrix:
@@ -74,119 +75,58 @@ jobs:
with:
image: ${{ matrix.image }}
command: ${{ matrix.command }}
+ scenario: 'default'
runner: ubuntu-20.04
secrets:
tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
- molecule-skip-auth:
- name: "Test Skip Authentication"
- runs-on: ubuntu-22.04
- environment: E2E
-
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
-
- - name: Install dependency manager
- run: pipx install poetry
-
- - name: Set up Python 3.x
- id: setup-python
- uses: actions/setup-python@v5.0.0
- with:
- python-version-file: pyproject.toml
- cache: 'poetry'
-
- - name: Install packages
- run: poetry install --no-interaction
+ molecule-state-absent:
+ name: "Run Molecule Scenario: state-absent"
+ uses: ./.github/workflows/molecule.yml
+ with:
+ scenario: 'state-absent'
+ secrets:
+ tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
- - name: Molecule - Skip Authentication
- run: poetry run molecule test --scenario-name skip-authentication
+ molecule-skip-auth:
+ name: "Run Molecule Scenario: skip-authentication"
+ uses: ./.github/workflows/molecule.yml
+ with:
+ scenario: 'skip-authentication'
+ secrets:
+ tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
molecule-args:
- name: "Test Up Args"
- runs-on: ubuntu-22.04
- environment: E2E
-
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
-
- - name: Install dependency manager
- run: pipx install poetry
-
- - name: Set up Python 3.x
- id: setup-python
- uses: actions/setup-python@v5.0.0
- with:
- python-version-file: pyproject.toml
- cache: 'poetry'
-
- - name: Install packages
- run: poetry install --no-interaction
-
- - name: Molecule - Custom Arguments Validation
- run: poetry run molecule test --scenario-name args
- env:
- TAILSCALE_CI_KEY: "${{ secrets.TAILSCALE_CI_KEY }}"
+ name: "Run Molecule Scenario: args"
+ uses: ./.github/workflows/molecule.yml
+ with:
+ scenario: 'args'
+ secrets:
+ tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
molecule-state-present:
- name: "Test State Idempotency"
- runs-on: ubuntu-22.04
- environment: E2E
-
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
-
- - name: Install dependency manager
- run: pipx install poetry
-
- - name: Set up Python 3.x
- id: setup-python
- uses: actions/setup-python@v5.0.0
- with:
- python-version-file: pyproject.toml
- cache: 'poetry'
-
- - name: Install packages
- run: poetry install --no-interaction
-
- - name: Molecule - State Present
- run: poetry run molecule test --scenario-name state-present
- env:
- TAILSCALE_CI_KEY: "${{ secrets.TAILSCALE_CI_KEY }}"
-
- molecule-state-oauth:
- name: "Test OAuth key support"
- runs-on: ubuntu-22.04
- environment: E2E
-
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
-
- - name: Install dependency manager
- run: pipx install poetry
-
- - name: Set up Python 3.x
- id: setup-python
- uses: actions/setup-python@v5.0.0
- with:
- python-version-file: pyproject.toml
- cache: 'poetry'
+ name: "Run Molecule Scenario: state-idempotency"
+ uses: ./.github/workflows/molecule.yml
+ with:
+ scenario: 'state-idempotency'
+ secrets:
+ tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
- - name: Install packages
- run: poetry install --no-interaction
+ molecule-oauth:
+ name: "Run Molecule Scenario: oauth"
+ uses: ./.github/workflows/molecule.yml
+ with:
+ scenario: 'oauth'
+ secrets:
+ tailscale_key: ${{ secrets.TAILSCALE_OAUTH_CLIENT_SECRET }}
- - name: Molecule - State Present
- run: poetry run molecule test --scenario-name oauth
- env:
- TAILSCALE_OAUTH_CLIENT_SECRET: "${{ secrets.TAILSCALE_OAUTH_CLIENT_SECRET }}"
+ molecule-strategy-free:
+ name: "Run Molecule Scenario: strategy-free"
+ uses: ./.github/workflows/molecule.yml
+ with:
+ scenario: 'strategy-free'
+ secrets:
+ tailscale_key: ${{ secrets.TAILSCALE_CI_KEY }}
molecule-headscale:
name: "Test Headscale Compatibility"
@@ -199,6 +139,7 @@ jobs:
- default
- state-absent
- idempotent-up
+ - strategy-free
steps:
- uses: actions/checkout@v4
diff --git a/Makefile b/Makefile
index 748dbfc1..4323ca9e 100644
--- a/Makefile
+++ b/Makefile
@@ -76,6 +76,14 @@ else
poetry run molecule test --scenario-name oauth
endif
+.PHONY: test-strategy-free
+test-strategy-free:
+ifndef TAILSCALE_CI_KEY
+ $(error TAILSCALE_CI_KEY is not set)
+else
+ poetry run molecule test --scenario-name strategy-free
+endif
+
.PHONY: test-headscale
test-headscale:
USE_HEADSCALE=true poetry run molecule test --scenario-name default
diff --git a/README.md b/README.md
index af4a516a..f84f4c46 100644
--- a/README.md
+++ b/README.md
@@ -36,9 +36,12 @@ See the [CI worfklow](https://github.com/artis3n/ansible-role-tailscale/blob/mai
# State Tracking
-This role will create an `artis3n-tailscale` directory in the target's [`XDG_STATE_HOME`](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) directory, or `$HOME/.local/state` if the variable is not present, in order to maintain a concept of state from the configuration of the arguments passed to `tailscale up`.
+This role will create an `artis3n-tailscale` directory in the target's [`XDG_STATE_HOME`](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) directory,
+or `$HOME/.local/state` if the variable is not present,
+in order to maintain a concept of state from the configuration of the arguments passed to `tailscale up`.
This allows the role to idempotently update a Tailscale node's configuration when needed.
-Deleting this directory will lead to this role re-configuring Tailscale when it is not needed, but will not otherwise break anything.
+Deleting this directory will lead to this role re-configuring Tailscale when it is not needed,
+but will not otherwise break anything.
However, it is recommended that you let this Ansible role manage this directory and its contents.
Note that:
@@ -47,7 +50,8 @@ Note that:
>
> ...
>
-> In Tailscale v1.8 or later, if you forget to specify a flag you added before, the CLI will warn you and provide a copyable command that includes all existing flags.
+> In Tailscale v1.8 or later, if you forget to specify a flag you added before,
+> the CLI will warn you and provide a copyable command that includes all existing flags.
@@ -55,7 +59,8 @@ Note that:
-This role will bubble up any stderr messages from the Tailscale binary to resolve any end-user configuration errors with `tailscale up` arguments.
+This role will bubble up any stderr messages from the Tailscale binary
+to resolve any end-user configuration errors with `tailscale up` arguments.
The `--authkey=` value will be redacted unless [`insecurely_log_authkey`](#insecurely_log_authkey) is set to `true`.
![logged stderr](docs/images/printed_stderr.png)
@@ -67,7 +72,8 @@ The `--authkey=` value will be redacted unless [`insecurely_log_authkey`](#insec
One of `tailscale_authkey` or `tailscale_up_skip` must be present.
In most cases you will use `tailscale_authkey`.
-If you are uninstalling Tailscale (`state: absent`), neither `tailscale_authkey` nor `tailscale_up_skip` is required.
+If you are uninstalling Tailscale (`state: absent`),
+neither `tailscale_authkey` nor `tailscale_up_skip` is required.
If you are authenticating with an OAuth key, you must also set `tailscale_tags` (see below).
@@ -83,9 +89,14 @@ A Node Authorization key can be generated under your Tailscale account. The role
- OAuth key (`tskey-client-XXX-YYYY`)
> [!IMPORTANT]
-> Using an OAuth key requires additionally setting the following variables: `tailscale_tags` (must be provided), `tailscale_oauth_ephemeral` (defaults to `true`) and `tailscale_oauth_preauthorized` (defaults to `false`).
+> Using an OAuth key requires additionally setting the following variables:
+> `tailscale_tags` (must be provided),
+> `tailscale_oauth_ephemeral` (defaults to `true`),
+> and `tailscale_oauth_preauthorized` (defaults to `false`).
-Note that auth keys expire up to a maximum of 90 days after they are generated. OAuth secrets do not expire unless revoked, and the generated OAuth access token expires after 1 hour.
+Note that auth keys expire up to a maximum of 90 days after they are generated.
+OAuth secrets do not expire unless revoked,
+and the generated OAuth access token expires after 1 hour.
For more information, see Tailscale's [OAuth clients](https://tailscale.com/kb/1215/oauth-clients) page, especially [Generating long-lived auth keys](https://tailscale.com/kb/1215/oauth-clients#generating-long-lived-auth-keys).
@@ -117,7 +128,8 @@ Skip [manual device approval](https://tailscale.com/kb/1099/device-approval), if
**Default**: `[]`
-Apply supplied tags to the Tailscale nodes configured by this role (via the `--advertise-tags` flag to `tailscale up`).
+Apply supplied tags to the Tailscale nodes configured by this role
+(via the `--advertise-tags` flag to `tailscale up`).
For more information, see [What are tags?](https://tailscale.com/kb/1068/acl-tags?q=acl%20tag#what-are-acl-tags)
> [!NOTE]
@@ -135,7 +147,8 @@ For example, `tailscale_args: ['worker']` translates to `--advertise-tags=tag:wo
**Default**: `false`
Whether to install and configure Tailscale as a service but skip running `tailscale up`.
-Helpful when packaging up a Tailscale installation into a build process such as AMI creation when the server should not yet authenticate to your Tailscale network.
+Helpful when packaging up a Tailscale installation into a build process, such as AMI creation,
+when the server should not yet authenticate to your Tailscale network.
## Optional
@@ -143,12 +156,16 @@ Helpful when packaging up a Tailscale installation into a build process such as
**Default**: `false`
-If set to `true`, the "Bring Tailscale Up" command will include the raw value of the Tailscale authkey when logging any errors encountered during `tailscale up`.
-By default, the authkey is not logged in successful task completions and is redacted in the `stderr` output by this role if an error occurs.
+If set to `true`, the "Bring Tailscale Up" command will include the raw value of the Tailscale authkey
+when logging any errors encountered during `tailscale up`.
+By default, the authkey is not logged in successful task completions
+and is redacted in the `stderr` output by this role if an error occurs.
![redacted authkey](docs/images/redacted_authkey.png)
-If you are encountering an error bringing Tailscale up and want the "Bring Tailscale Up" task to _not_ redact the value of the authkey, set this variable to `true`.
+If you are encountering an error bringing Tailscale up
+and want the "Bring Tailscale Up" task to _not_ redact the value of the authkey,
+set this variable to `true`.
Regardless, if the authkey is invalid, the role will relay Tailscale's error message on that fact:
@@ -175,9 +192,12 @@ Whether to use the Tailscale stable or unstable track.
Whether to install or uninstall Tailscale.
If defined, `state` must be either `latest`, `present`, or `absent`.
-This role uses `latest` by default to help ensure your software remains up-to-date and incorporates the latest security and product features.
-For users who desire more control over configuration drift, `present` will not update Tailscale if it is already installed.
-Changes to [`tailscale_args`](#tailscale_args) will be applied under both `latest` and `present`; this parameter only impacts the version of Tailscale installed to the target system.
+This role uses `latest` by default to help ensure your software remains up-to-date
+and incorporates the latest security and product features.
+For users who desire more control over configuration drift,
+`present` will not update Tailscale if it is already installed.
+Changes to [`tailscale_args`](#tailscale_args) will be applied under both `latest` and `present`;
+this parameter only impacts the version of Tailscale installed to the target system.
If set to `absent`, this role will de-register the Tailscale node (if already authenticated)
and clean up or disable all Tailscale artifacts added to the system.
@@ -188,7 +208,8 @@ Note that neither `tailscale_authkey` nor `tailscale_up_skip` is required if `st
Pass any additional command-line arguments to `tailscale up`.
-Note that the [command][ansible.builtin.command] module is used, which does not support subshell expressions (`$()`) or bash operations like `;` and `&`.
+Note that the [command][ansible.builtin.command] module is used,
+which does not support subshell expressions (`$()`) or bash operations like `;` and `&`.
Only `tailscale up` arguments can be passed in.
> [!CAUTION]
@@ -201,7 +222,9 @@ Only `tailscale up` arguments can be passed in.
> **Do not use this for `--timeout`.**
> Use the `tailscale_up_timeout` variable instead.
-Any stdout/stderr output from the `tailscale` binary will be printed. Since the tasks move quickly in this section, a 5 second pause is introduced to grant more time for users to realize a message was printed.
+Any stdout/stderr output from the `tailscale` binary will be printed.
+Since the tasks move quickly in this section, a 5 second pause is introduced
+to grant more time for users to realize a message was printed.
![printed stdout](docs/images/printed_stdout.png)
@@ -334,14 +357,21 @@ Ari Kalfus ([@artis3n](https://www.artis3nal.com/))
This GitHub repository uses a dedicated "test" Tailscale account to authenticate Tailscale during CI runs.
Each Docker container creates a new authorized machine in that test account.
-The machines are authorized with [ephemeral auth keys][] and are automatically cleaned up within 30 minutes-48 hours.
+The machines are authorized with [ephemeral auth keys][]
+and are automatically cleaned up within 30 minutes-48 hours.
This value is stored in a [GitHub Action secret][] with the name `TAILSCALE_CI_KEY`.
To test OAuth authkey compatibility, a Tailscale OAuth client secret is stored as `TAILSCALE_OAUTH_CLIENT_SECRET`.
-To test this role locally, store the Tailscale ephemeral auth key in a `TAILSCALE_CI_KEY` env var and, if running the `oauth` Molecule scenario, add an OAuth client secret in a `TAILSCALE_OAUTH_CLIENT_SECRET` env var.
-If you are a Collaborator on this repository, you can open a GitHub CodeSpace and these secrets will be pre-populated for you into the environment.
-
-Alternatively for Molecule testing, you can use a [Headscale][] container that is spun up as part of the create/prepare steps. To do this, set a `USE_HEADSCALE` env variable. For example:
+To test this role locally, store the Tailscale ephemeral auth key in a `TAILSCALE_CI_KEY` env var
+and, if running the `oauth` Molecule scenario,
+add an OAuth client secret in a `TAILSCALE_OAUTH_CLIENT_SECRET` env var.
+If you are a Collaborator on this repository,
+you can open a GitHub CodeSpace and these secrets will be pre-populated for you into the environment.
+
+Alternatively for Molecule testing,
+you can use a [Headscale][] container that is spun up as part of the create/prepare steps.
+To do this, set a `USE_HEADSCALE` env variable.
+For example:
```bash
USE_HEADSCALE=true molecule test
diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml
index 5ae2d73c..eae142a6 100644
--- a/molecule/default/prepare.yml
+++ b/molecule/default/prepare.yml
@@ -18,8 +18,18 @@
name: headscale
register: headscale_info
+ - name: Fetch Headscale network info
+ community.docker.docker_network_info:
+ name: headscale
+ register: headscale_network
+
+ - name: Get instance names
+ ansible.builtin.set_fact:
+ instance_names: "{{ headscale_network.network.Containers | dict2items | selectattr('value.Name', 'match', '^instance') | map(attribute='value.Name') | list }}"
+
- name: Set hosts override for Headscale
- delegate_to: instance
+ delegate_to: "{{ item }}"
+ loop: "{{ instance_names }}"
ansible.builtin.lineinfile:
path: /etc/hosts
line: "{{ headscale_info.container.NetworkSettings.Networks.headscale.IPAddress }} headscale"
diff --git a/molecule/oauth/converge.yml b/molecule/oauth/converge.yml
index f1f87be6..ba253400 100644
--- a/molecule/oauth/converge.yml
+++ b/molecule/oauth/converge.yml
@@ -3,7 +3,7 @@
hosts: instance
tasks:
- name: Init tailscale credentials variables
- ansible.builtin.include_tasks: init_tailscale_vars.yml
+ ansible.builtin.include_tasks: ../default/init_tailscale_vars.yml
- name: "Include artis3n.tailscale"
ansible.builtin.include_role:
diff --git a/molecule/oauth/init_tailscale_vars.yml b/molecule/oauth/init_tailscale_vars.yml
deleted file mode 100644
index 498bd4bd..00000000
--- a/molecule/oauth/init_tailscale_vars.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- name: Use tailscale service
- ansible.builtin.set_fact:
- tailscale_authkey: "{{ lookup('ansible.builtin.env', 'TAILSCALE_OAUTH_CLIENT_SECRET') }}"
- when: not lookup('ansible.builtin.env', 'USE_HEADSCALE', default=false)
-
-- name: Fetch headscale preauth key
- delegate_to: localhost
- changed_when: false
- community.docker.docker_container_exec:
- container: headscale
- command: headscale preauthkeys list -u test -o json
- register: preauth_list
- when: lookup('ansible.builtin.env', 'USE_HEADSCALE', default=false)
-
-- name: Use headscale service
- vars:
- combined_args: "{{ tailscale_args|default('') }} --login-server=http://headscale:8080"
- ansible.builtin.set_fact:
- tailscale_authkey: "{{ (preauth_list.stdout|from_json)[0].key }}"
- tailscale_args: "{{ combined_args }}"
- when: lookup('ansible.builtin.env', 'USE_HEADSCALE', default=false)
diff --git a/molecule/oauth/molecule.yml b/molecule/oauth/molecule.yml
index 9d505403..ecf10e3a 100644
--- a/molecule/oauth/molecule.yml
+++ b/molecule/oauth/molecule.yml
@@ -29,6 +29,8 @@ platforms:
- "${MOLECULE_PROJECT_DIRECTORY}/molecule/default/headscale.config.yaml:/etc/headscale/config.yaml"
provisioner:
name: ansible
+ playbooks:
+ prepare: ../default/prepare.yml
verifier:
name: ansible
scenario:
diff --git a/molecule/oauth/prepare.yml b/molecule/oauth/prepare.yml
deleted file mode 100644
index 5ae2d73c..00000000
--- a/molecule/oauth/prepare.yml
+++ /dev/null
@@ -1,26 +0,0 @@
----
-- name: Prepare
- hosts: localhost
- gather_facts: false
- tasks:
- - name: Create Headscale user
- community.docker.docker_container_exec:
- container: headscale
- command: headscale users create test
-
- - name: Create preauth key
- community.docker.docker_container_exec:
- container: headscale
- command: headscale preauthkeys create -u test --reusable
-
- - name: Fetch Headscale container info
- community.docker.docker_container_info:
- name: headscale
- register: headscale_info
-
- - name: Set hosts override for Headscale
- delegate_to: instance
- ansible.builtin.lineinfile:
- path: /etc/hosts
- line: "{{ headscale_info.container.NetworkSettings.Networks.headscale.IPAddress }} headscale"
- unsafe_writes: true # Hosts file in the docker container can't be written to atomically
diff --git a/molecule/state-present/cleanup.yml b/molecule/state-idempotency/cleanup.yml
similarity index 100%
rename from molecule/state-present/cleanup.yml
rename to molecule/state-idempotency/cleanup.yml
diff --git a/molecule/state-present/converge.yml b/molecule/state-idempotency/converge.yml
similarity index 100%
rename from molecule/state-present/converge.yml
rename to molecule/state-idempotency/converge.yml
diff --git a/molecule/state-present/molecule.yml b/molecule/state-idempotency/molecule.yml
similarity index 97%
rename from molecule/state-present/molecule.yml
rename to molecule/state-idempotency/molecule.yml
index f322b738..3ae982cf 100644
--- a/molecule/state-present/molecule.yml
+++ b/molecule/state-idempotency/molecule.yml
@@ -34,7 +34,7 @@ provisioner:
verifier:
name: ansible
scenario:
- name: state-present
+ name: state-idempotency
test_sequence:
- dependency
- destroy
diff --git a/molecule/state-present/verify.yml b/molecule/state-idempotency/verify.yml
similarity index 100%
rename from molecule/state-present/verify.yml
rename to molecule/state-idempotency/verify.yml
diff --git a/molecule/strategy-free/cleanup.yml b/molecule/strategy-free/cleanup.yml
new file mode 100644
index 00000000..b650329e
--- /dev/null
+++ b/molecule/strategy-free/cleanup.yml
@@ -0,0 +1,8 @@
+---
+- name: Cleanup
+ hosts: instances
+ tasks:
+ - name: De-register Tailscale node
+ become: true
+ ansible.builtin.command: tailscale logout
+ changed_when: false
diff --git a/molecule/strategy-free/converge.yml b/molecule/strategy-free/converge.yml
new file mode 100644
index 00000000..5809eb0e
--- /dev/null
+++ b/molecule/strategy-free/converge.yml
@@ -0,0 +1,13 @@
+---
+- name: Converge
+ hosts: instances
+ strategy: free
+ tasks:
+ - name: Init tailscale credentials variables
+ ansible.builtin.include_tasks: ../default/init_tailscale_vars.yml
+
+ - name: "Include artis3n.tailscale"
+ ansible.builtin.include_role:
+ name: artis3n.tailscale
+ vars:
+ verbose: true
diff --git a/molecule/strategy-free/molecule.yml b/molecule/strategy-free/molecule.yml
new file mode 100644
index 00000000..726e1d43
--- /dev/null
+++ b/molecule/strategy-free/molecule.yml
@@ -0,0 +1,80 @@
+---
+dependency:
+ name: galaxy
+ options:
+ requirements-file: requirements.yml
+driver:
+ name: docker
+platforms:
+ - name: instance-1
+ groups:
+ - instances
+ image: ${MOLECULE_DISTRO:-geerlingguy/docker-ubuntu2204-ansible:latest}
+ command: ${MOLECULE_COMMAND:-/usr/sbin/init}
+ volumes:
+ - /sys/fs/cgroup:/sys/fs/cgroup:rw
+ docker_networks:
+ - name: headscale
+ networks:
+ - name: bridge
+ - name: headscale
+ cgroupns_mode: host
+ privileged: true
+ pre_build_image: true
+ - name: instance-2
+ groups:
+ - instances
+ image: 'ghcr.io/artis3n/docker-amazonlinux2023-ansible:latest'
+ command: ${MOLECULE_COMMAND:-/usr/sbin/init}
+ volumes:
+ - /sys/fs/cgroup:/sys/fs/cgroup:rw
+ docker_networks:
+ - name: headscale
+ networks:
+ - name: bridge
+ - name: headscale
+ cgroupns_mode: host
+ privileged: true
+ pre_build_image: true
+ - name: instance-3
+ groups:
+ - instances
+ image: 'cisagov/docker-debian12-ansible:latest'
+ command: ${MOLECULE_COMMAND:-/usr/sbin/init}
+ volumes:
+ - /sys/fs/cgroup:/sys/fs/cgroup:rw
+ docker_networks:
+ - name: headscale
+ networks:
+ - name: bridge
+ - name: headscale
+ cgroupns_mode: host
+ privileged: true
+ pre_build_image: true
+ - name: headscale
+ image: ${HEADSCALE_IMAGE:-headscale/headscale:latest}
+ command: headscale serve
+ pre_build_image: true
+ networks:
+ - name: headscale
+ volumes:
+ - "${MOLECULE_PROJECT_DIRECTORY}/molecule/default/headscale.config.yaml:/etc/headscale/config.yaml"
+provisioner:
+ name: ansible
+ playbooks:
+ prepare: ../default/prepare.yml
+verifier:
+ name: ansible
+scenario:
+ name: strategy-free
+ test_sequence:
+ - dependency
+ - destroy
+ - syntax
+ - create
+ - prepare
+ - converge
+ - idempotence
+ - verify
+ - cleanup
+ - destroy
diff --git a/molecule/strategy-free/verify.yml b/molecule/strategy-free/verify.yml
new file mode 100644
index 00000000..4fb07b8d
--- /dev/null
+++ b/molecule/strategy-free/verify.yml
@@ -0,0 +1,15 @@
+---
+- name: Verify
+ hosts: instances
+ tasks:
+ - name: Get Tailscale status
+ become: true
+ ansible.builtin.command: tailscale status
+ changed_when: false
+ register: tailscale_status
+
+ - name: Assertions
+ ansible.builtin.assert:
+ that:
+ - "'Logged out.' not in tailscale_status.stdout"
+ - "'not logged in' not in tailscale_status.stdout"
diff --git a/tasks/install.yml b/tasks/install.yml
index 2a081358..86dbd773 100644
--- a/tasks/install.yml
+++ b/tasks/install.yml
@@ -154,8 +154,8 @@
register: nonsensitive_stdout
- name: Install | Pausing to highlight stdout message above
- ansible.builtin.pause:
- seconds: 5
+ ansible.builtin.wait_for:
+ timeout: 5
when: nonsensitive_stdout is not skipped
- name: Install | Clear State Upon Error