Skip to content

Commit

Permalink
Merge branch 'main' into bug/update-dep-race-condition
Browse files Browse the repository at this point in the history
  • Loading branch information
yhaliaw committed Jan 23, 2024
2 parents 04bde3b + 7e73a46 commit 200185c
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 15 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/integration_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
pull_request:

jobs:
# test option values defined at test/conftest.py are passed on via repository secret
# INTEGRATION_TEST_ARGS to operator-workflows automatically.
integration-tests-juju2:
name: Integration test with juju 2.9
uses: canonical/operator-workflows/.github/workflows/integration_test.yaml@main
Expand Down
12 changes: 12 additions & 0 deletions docs/explanation/ssh-debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SSH Debug

SSH debugging allows a user to identify and resolve issues or errors that occur through the secure
shell (SSH) connection between a client and a server.

To enhance the security of the runner and the infrastructure behind the runner, only user ssh-keys
registered on [Authorized Keys](https://github.com/tmate-io/tmate-ssh-server/pull/93) are allowed
by default on [tmate-ssh-server charm](https://charmhub.io/tmate-ssh-server/).

Authorized keys are registered via [action-tmate](https://github.com/canonical/action-tmate/)'s
`limit-access-to-actor` feature. This feature uses GitHub users's SSH key to launch an instance
of tmate session with `-a` option, which adds the user's SSH key to `~/.ssh/authorized_keys`.
53 changes: 53 additions & 0 deletions docs/how-to/debug-with-ssh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# How to debug with ssh

The charm exposes an integration `debug-ssh` interface which can be used with
[tmate-ssh-server charm](https://charmhub.io/tmate-ssh-server/) to pre-configure runners with
environment variables to be picked up by [action-tmate](https://github.com/canonical/action-tmate/)
for automatic configuration.

## Prerequisites

To enhance the security of self-hosted runners and its infrastracture, only authorized connections
can be established. Hence, action-tmate users must have
[ssh-key registered](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)
on the GitHub account.

## Deploying

Use the following command to deploy and integrate github-runner with tmate-ssh-server.

```shell
juju deploy tmate-ssh-server
juju integrate tmate-ssh-server github-runner
```

Idle runners will be flushed and restarted. Busy runners will be configured automatically on next
spawn.

## Using the action

Create a workflow that looks like the following within your workflow to enable action-tmate.

```yaml
name: SSH Debug workflow example

on: [pull_request]

jobs:
build:
runs-on: [self-hosted]
steps:
- uses: actions/checkout@v3
- name: Setup tmate session
uses: canonical/action-tmate@main
```
The output of the action looks like the following.
```
<workflow setup logs redacted>
SSH: ssh -p 10022 <user>@<ip>
or: ssh -i <path-to-private-SSH-key> -p10022 <user>@<ip>
```
Read more about [action-tmate's usage here](https://github.com/canonical/action-tmate).
11 changes: 11 additions & 0 deletions docs/reference/integrations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Integrations

### debug-ssh

_Interface_: debug-ssh
_Supported charms_: [tmate-ssh-server](https://charmhub.io/tmate-ssh-server)

Debug-ssh integration provides necessary information for runners to provide ssh reverse-proxy
applications to setup inside the runner.

Example debug-ssh integrate command: `juju integrate github-runner tmate-ssh-server`
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ requests
typing-extensions
# Newer version does not work with default OpenSSL version on jammy.
cryptography <= 38.0.4
pydantic ==1.10.13
pydantic ==1.10.14
cosl == 0.0.7
17 changes: 14 additions & 3 deletions src/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
LXD_PROFILE_YAML = LXD_PROFILE_YAML.parent / "lxd-profile.yml"
LXDBR_DNSMASQ_LEASES_FILE = Path("/var/snap/lxd/common/lxd/networks/lxdbr0/dnsmasq.leases")

APROXY_ARM_REVISION = 9
APROXY_AMD_REVISION = 8


class Snap(NamedTuple):
"""This class represents a snap installation."""
Expand Down Expand Up @@ -151,7 +154,7 @@ def create(self, config: CreateRunnerConfig):
# Wait some initial time for the instance to boot up
time.sleep(60)
self._wait_boot_up()
self._install_binaries(config.binary_path)
self._install_binaries(config.binary_path, config.arch)
self._configure_runner()

self._register_runner(
Expand Down Expand Up @@ -467,7 +470,7 @@ def _wait_boot_up(self) -> None:
logger.info("Finished booting up LXD instance for runner: %s", self.config.name)

@retry(tries=10, delay=10, max_delay=120, backoff=2, local_logger=logger)
def _install_binaries(self, runner_binary: Path) -> None:
def _install_binaries(self, runner_binary: Path, arch: ARCH) -> None:
"""Install runner binary and other binaries.
Args:
Expand All @@ -479,7 +482,15 @@ def _install_binaries(self, runner_binary: Path) -> None:
if self.instance is None:
raise RunnerError("Runner operation called prior to runner creation.")

self._snap_install([Snap(name="aproxy", channel="edge", revision=6)])
self._snap_install(
[
Snap(
name="aproxy",
channel="edge",
revision=APROXY_ARM_REVISION if arch == ARCH.ARM64 else APROXY_AMD_REVISION,
)
]
)

# The LXD instance is meant to run untrusted workload. Hardcoding the tmp directory should
# be fine.
Expand Down
40 changes: 32 additions & 8 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,35 @@

def pytest_addoption(parser: Parser):
"""Add options to pytest parser."""
parser.addoption("--path", action="store")
parser.addoption("--token", action="store")
parser.addoption("--charm-file", action="store")
parser.addoption("--token-alt", action="store")
parser.addoption("--http-proxy", action="store")
parser.addoption("--https-proxy", action="store")
parser.addoption("--no-proxy", action="store")
parser.addoption("--loop-device", action="store")
parser.addoption(
"--path",
action="store",
help="The path to repository in <org>/<repo> or <user>/<repo> format.",
)
parser.addoption("--token", action="store", help="The GitHub Personal Access Token.")
parser.addoption(
"--charm-file", action="store", help="The prebuilt github-runner-operator charm file."
)
parser.addoption(
"--token-alt", action="store", help="An alternative token to test the change of a token."
)
parser.addoption(
"--http-proxy",
action="store",
help="HTTP proxy configuration value for juju model proxy configuration.",
)
parser.addoption(
"--https-proxy",
action="store",
help="HTTPS proxy configuration value for juju model proxy configuration.",
)
parser.addoption(
"--no-proxy",
action="store",
help="No proxy configuration value for juju model proxy configuration.",
)
parser.addoption(
"--loop-device",
action="store",
help="The loop device to create shared FS for metrics logging",
)
15 changes: 12 additions & 3 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,32 @@ def charm_file(pytestconfig: pytest.Config, loop_device: Optional[str]) -> str:
def path(pytestconfig: pytest.Config) -> str:
"""Configured path setting."""
path = pytestconfig.getoption("--path")
assert path, "Please specify the --path command line option"
assert path, (
"Please specify the --path command line option with repository "
"path of <org>/<repo> or <user>/<repo> format."
)
return path


@pytest.fixture(scope="module")
def token(pytestconfig: pytest.Config) -> str:
"""Configured token setting."""
token = pytestconfig.getoption("--token")
assert token, "Please specify the --token command line option"
assert token, (
"Please specify the --token command line option with GitHub Personal Access "
"Token value."
)
return token


@pytest.fixture(scope="module")
def token_alt(pytestconfig: pytest.Config, token: str) -> str:
"""Configured token_alt setting."""
token_alt = pytestconfig.getoption("--token-alt")
assert token_alt, "Please specify the --token-alt command line option"
assert token_alt, (
"Please specify the --token-alt command line option with GitHub Personal "
"Access Token value."
)
assert token_alt != token, "Please specify a different token for --token-alt"
return token_alt

Expand Down

0 comments on commit 200185c

Please sign in to comment.