mirror of
https://github.com/juanfont/headscale.git
synced 2025-08-17 04:27:33 +00:00
Compare commits
23 Commits
v0.19.0-be
...
v0.20.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ca125330fc | ||
![]() |
ce587d2421 | ||
![]() |
e1eb30084d | ||
![]() |
673638afe7 | ||
![]() |
da48cf64b3 | ||
![]() |
385fd93e73 | ||
![]() |
26edf24477 | ||
![]() |
83a538cc95 | ||
![]() |
cffa040474 | ||
![]() |
727d95b477 | ||
![]() |
640bb94119 | ||
![]() |
0f65918a25 | ||
![]() |
3ac2e0b253 | ||
![]() |
b322cdf251 | ||
![]() |
e128796b59 | ||
![]() |
6d669c6b9c | ||
![]() |
8dadb045cf | ||
![]() |
9f6e546522 | ||
![]() |
9714900db9 | ||
![]() |
cb25f0d650 | ||
![]() |
9c2e580ab5 | ||
![]() |
0ffff2c994 | ||
![]() |
c720af66d6 |
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -8,6 +8,10 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -35,7 +39,7 @@ jobs:
|
|||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: nix build
|
run: nix build
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
with:
|
||||||
name: headscale-linux
|
name: headscale-linux
|
||||||
|
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -3,6 +3,10 @@ name: Lint
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
golangci-lint:
|
golangci-lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestAuthKeyLogoutAndRelogin
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestAuthKeyLogoutAndRelogin$"
|
-run "^TestAuthKeyLogoutAndRelogin$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestAuthWebFlowAuthenticationPingAll
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestAuthWebFlowAuthenticationPingAll$"
|
-run "^TestAuthWebFlowAuthenticationPingAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestAuthWebFlowLogoutAndRelogin
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestAuthWebFlowLogoutAndRelogin$"
|
-run "^TestAuthWebFlowLogoutAndRelogin$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestCreateTailscale
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestCreateTailscale$"
|
-run "^TestCreateTailscale$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestEnablingRoutes
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestEnablingRoutes$"
|
-run "^TestEnablingRoutes$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
name: Integration Test v2 - TestNamespaceCommand
|
name: Integration Test v2 - TestEphemeral
|
||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,10 +41,17 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
-failfast \
|
-failfast \
|
||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestNamespaceCommand$"
|
-run "^TestEphemeral$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestHeadscale
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestHeadscale$"
|
-run "^TestHeadscale$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestOIDCAuthenticationPingAll
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestOIDCAuthenticationPingAll$"
|
-run "^TestOIDCAuthenticationPingAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
57
.github/workflows/test-integration-v2-TestOIDCExpireNodesBasedOnTokenExpiry.yaml
vendored
Normal file
57
.github/workflows/test-integration-v2-TestOIDCExpireNodesBasedOnTokenExpiry.yaml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestOIDCExpireNodesBasedOnTokenExpiry
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- uses: cachix/install-nix-action@v18
|
||||||
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
|
- name: Run general integration tests
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
run: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go test ./... \
|
||||||
|
-tags ts2019 \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestOIDCExpireNodesBasedOnTokenExpiry$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestPingAllByHostname
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestPingAllByHostname$"
|
-run "^TestPingAllByHostname$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestPingAllByIP
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestPingAllByIP$"
|
-run "^TestPingAllByIP$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestPreAuthKeyCommand
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestPreAuthKeyCommand$"
|
-run "^TestPreAuthKeyCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestPreAuthKeyCommandReusableEphemeral
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestPreAuthKeyCommandReusableEphemeral$"
|
-run "^TestPreAuthKeyCommandReusableEphemeral$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestPreAuthKeyCommandWithoutExpiry
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestPreAuthKeyCommandWithoutExpiry$"
|
-run "^TestPreAuthKeyCommandWithoutExpiry$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestResolveMagicDNS
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestResolveMagicDNS$"
|
-run "^TestResolveMagicDNS$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestSSHIsBlockedInACL
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestSSHIsBlockedInACL$"
|
-run "^TestSSHIsBlockedInACL$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
57
.github/workflows/test-integration-v2-TestSSHMultipleUsersAllToAll.yaml
vendored
Normal file
57
.github/workflows/test-integration-v2-TestSSHMultipleUsersAllToAll.yaml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestSSHMultipleUsersAllToAll
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- uses: cachix/install-nix-action@v18
|
||||||
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
|
- name: Run general integration tests
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
run: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go test ./... \
|
||||||
|
-tags ts2019 \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestSSHMultipleUsersAllToAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestSSHNoSSHConfigured
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestSSHNoSSHConfigured$"
|
-run "^TestSSHNoSSHConfigured$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
name: Integration Test v2 - TestSSHMultipleNamespacesAllToAll
|
name: Integration Test v2 - TestSSHOneUserAllToAll
|
||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,10 +41,17 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
-failfast \
|
-failfast \
|
||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestSSHMultipleNamespacesAllToAll$"
|
-run "^TestSSHOneUserAllToAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
@@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
|
||||||
|
|
||||||
name: Integration Test v2 - TestSSNamespaceOnlyIsolation
|
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
|
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
uses: tj-actions/changed-files@v34
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
*.nix
|
|
||||||
go.*
|
|
||||||
**/*.go
|
|
||||||
integration_test/
|
|
||||||
config-example.yaml
|
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
|
||||||
|
|
||||||
- name: Run general integration tests
|
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
|
||||||
run: |
|
|
||||||
nix develop --command -- docker run \
|
|
||||||
--tty --rm \
|
|
||||||
--volume ~/.cache/hs-integration-go:/go \
|
|
||||||
--name headscale-test-suite \
|
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
|
||||||
golang:1 \
|
|
||||||
go test ./... \
|
|
||||||
-tags ts2019 \
|
|
||||||
-failfast \
|
|
||||||
-timeout 120m \
|
|
||||||
-parallel 1 \
|
|
||||||
-run "^TestSSNamespaceOnlyIsolation$"
|
|
@@ -1,11 +1,14 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
name: Integration Test v2 - TestSSHOneNamespaceAllToAll
|
name: Integration Test v2 - TestSSUserOnlyIsolation
|
||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,10 +41,17 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
-failfast \
|
-failfast \
|
||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestSSHOneNamespaceAllToAll$"
|
-run "^TestSSUserOnlyIsolation$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestTaildrop
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestTaildrop$"
|
-run "^TestTaildrop$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
@@ -6,6 +5,10 @@ name: Integration Test v2 - TestTailscaleNodesJoiningHeadcale
|
|||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,6 +41,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -45,3 +49,9 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestTailscaleNodesJoiningHeadcale$"
|
-run "^TestTailscaleNodesJoiningHeadcale$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
|
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
name: Integration Test v2 - TestOIDCExpireNodes
|
name: Integration Test v2 - TestUserCommand
|
||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -26,8 +29,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -38,10 +41,17 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
-failfast \
|
-failfast \
|
||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^TestOIDCExpireNodes$"
|
-run "^TestUserCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -2,6 +2,10 @@ name: Tests
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,7 +26,8 @@ derp.yaml
|
|||||||
# Exclude Jetbrains Editors
|
# Exclude Jetbrains Editors
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
test_output/
|
test_output/
|
||||||
|
control_logs/
|
||||||
|
|
||||||
# Nix build output
|
# Nix build output
|
||||||
result
|
result
|
||||||
|
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,13 +1,24 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
## 0.19.0 (2022-11-26)
|
## 0.20.0 (2023-x-x)
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Fix wrong behaviour in exit nodes [#1159](https://github.com/juanfont/headscale/pull/1159)
|
||||||
|
- Align behaviour of `dns_config.restricted_nameservers` to tailscale [#1162](https://github.com/juanfont/headscale/pull/1162)
|
||||||
|
- Make OpenID Connect authenticated client expiry time configurable [#1191](https://github.com/juanfont/headscale/pull/1191)
|
||||||
|
- defaults to 180 days like Tailscale SaaS
|
||||||
|
- adds option to use the expiry time from the OpenID token for the node (see config-example.yaml)
|
||||||
|
|
||||||
|
## 0.19.0 (2023-01-29)
|
||||||
|
|
||||||
### BREAKING
|
### BREAKING
|
||||||
|
|
||||||
- Rename Namespace to User [#1144](https://github.com/juanfont/headscale/pull/1144)
|
- Rename Namespace to User [#1144](https://github.com/juanfont/headscale/pull/1144)
|
||||||
- **BACKUP your database before upgrading**
|
- **BACKUP your database before upgrading**
|
||||||
|
- Command line flags previously taking `--namespace` or `-n` will now require `--user` or `-u`
|
||||||
|
|
||||||
## 0.18.0 (2022-01-14)
|
## 0.18.0 (2023-01-14)
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
|
11
acls.go
11
acls.go
@@ -150,7 +150,11 @@ func (h *Headscale) UpdateACLRules() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateACLRules(machines []Machine, aclPolicy ACLPolicy, stripEmaildomain bool) ([]tailcfg.FilterRule, error) {
|
func generateACLRules(
|
||||||
|
machines []Machine,
|
||||||
|
aclPolicy ACLPolicy,
|
||||||
|
stripEmaildomain bool,
|
||||||
|
) ([]tailcfg.FilterRule, error) {
|
||||||
rules := []tailcfg.FilterRule{}
|
rules := []tailcfg.FilterRule{}
|
||||||
|
|
||||||
for index, acl := range aclPolicy.ACLs {
|
for index, acl := range aclPolicy.ACLs {
|
||||||
@@ -160,7 +164,7 @@ func generateACLRules(machines []Machine, aclPolicy ACLPolicy, stripEmaildomain
|
|||||||
|
|
||||||
srcIPs := []string{}
|
srcIPs := []string{}
|
||||||
for innerIndex, src := range acl.Sources {
|
for innerIndex, src := range acl.Sources {
|
||||||
srcs, err := generateACLPolicySrcIP(machines, aclPolicy, src, stripEmaildomain)
|
srcs, err := generateACLPolicySrc(machines, aclPolicy, src, stripEmaildomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Msgf("Error parsing ACL %d, Source %d", index, innerIndex)
|
Msgf("Error parsing ACL %d, Source %d", index, innerIndex)
|
||||||
@@ -311,7 +315,7 @@ func sshCheckAction(duration string) (*tailcfg.SSHAction, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateACLPolicySrcIP(
|
func generateACLPolicySrc(
|
||||||
machines []Machine,
|
machines []Machine,
|
||||||
aclPolicy ACLPolicy,
|
aclPolicy ACLPolicy,
|
||||||
src string,
|
src string,
|
||||||
@@ -427,6 +431,7 @@ func parseProtocol(protocol string) ([]int, bool, error) {
|
|||||||
// - a user
|
// - a user
|
||||||
// - a group
|
// - a group
|
||||||
// - a tag
|
// - a tag
|
||||||
|
// - a host
|
||||||
// and transform these in IPAddresses.
|
// and transform these in IPAddresses.
|
||||||
func expandAlias(
|
func expandAlias(
|
||||||
machines []Machine,
|
machines []Machine,
|
||||||
|
17
acls_test.go
17
acls_test.go
@@ -1041,7 +1041,7 @@ func Test_expandAlias(t *testing.T) {
|
|||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "simple host",
|
name: "simple host by ip",
|
||||||
args: args{
|
args: args{
|
||||||
alias: "10.0.0.1",
|
alias: "10.0.0.1",
|
||||||
machines: []Machine{},
|
machines: []Machine{},
|
||||||
@@ -1051,6 +1051,21 @@ func Test_expandAlias(t *testing.T) {
|
|||||||
want: []string{"10.0.0.1"},
|
want: []string{"10.0.0.1"},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "simple host by hostname alias",
|
||||||
|
args: args{
|
||||||
|
alias: "testy",
|
||||||
|
machines: []Machine{},
|
||||||
|
aclPolicy: ACLPolicy{
|
||||||
|
Hosts: Hosts{
|
||||||
|
"testy": netip.MustParsePrefix("10.0.0.132/32"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stripEmailDomain: true,
|
||||||
|
},
|
||||||
|
want: []string{"10.0.0.132/32"},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "simple CIDR",
|
name: "simple CIDR",
|
||||||
args: args{
|
args: args{
|
||||||
|
2
api.go
2
api.go
@@ -78,7 +78,7 @@ var registerWebAPITemplate = template.Must(
|
|||||||
<p>
|
<p>
|
||||||
Run the command below in the headscale server to add this machine to your network:
|
Run the command below in the headscale server to add this machine to your network:
|
||||||
</p>
|
</p>
|
||||||
<pre><code>headscale -n NAMESPACE nodes register --key {{.Key}}</code></pre>
|
<pre><code>headscale nodes register --user USERNAME --key {{.Key}}</code></pre>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`))
|
`))
|
||||||
|
@@ -7,19 +7,29 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
githubWorkflowPath = "../../.github/workflows/"
|
||||||
jobFileNameTemplate = `test-integration-v2-%s.yaml`
|
jobFileNameTemplate = `test-integration-v2-%s.yaml`
|
||||||
jobTemplate = template.Must(template.New("jobTemplate").Parse(`
|
jobTemplate = template.Must(
|
||||||
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
template.New("jobTemplate").
|
||||||
|
Parse(`# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
name: Integration Test v2 - {{.Name}}
|
name: Integration Test v2 - {{.Name}}
|
||||||
|
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: {{ "${{ github.workflow }}-$${{ github.head_ref || github.run_id }}" }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -40,8 +50,8 @@ jobs:
|
|||||||
integration_test/
|
integration_test/
|
||||||
config-example.yaml
|
config-example.yaml
|
||||||
|
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v18
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: {{ "${{ env.ACT }}" }} || steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
- name: Run general integration tests
|
- name: Run general integration tests
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
@@ -52,6 +62,7 @@ jobs:
|
|||||||
--name headscale-test-suite \
|
--name headscale-test-suite \
|
||||||
--volume $PWD:$PWD -w $PWD/integration \
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
golang:1 \
|
golang:1 \
|
||||||
go test ./... \
|
go test ./... \
|
||||||
-tags ts2019 \
|
-tags ts2019 \
|
||||||
@@ -59,43 +70,81 @@ jobs:
|
|||||||
-timeout 120m \
|
-timeout 120m \
|
||||||
-parallel 1 \
|
-parallel 1 \
|
||||||
-run "^{{.Name}}$"
|
-run "^{{.Name}}$"
|
||||||
`))
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
`),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
const workflowFilePerm = 0o600
|
const workflowFilePerm = 0o600
|
||||||
|
|
||||||
|
func removeTests() {
|
||||||
|
glob := fmt.Sprintf(jobFileNameTemplate, "*")
|
||||||
|
|
||||||
|
files, err := filepath.Glob(filepath.Join(githubWorkflowPath, glob))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to find test files")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
err := os.Remove(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to remove: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTests() []string {
|
||||||
|
rgBin, err := exec.LookPath("rg")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to find rg (ripgrep) binary")
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"--regexp", "func (Test.+)\\(.*",
|
||||||
|
"../../integration/",
|
||||||
|
"--replace", "$1",
|
||||||
|
"--sort", "path",
|
||||||
|
"--no-line-number",
|
||||||
|
"--no-filename",
|
||||||
|
"--no-heading",
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("executing: %s %s", rgBin, strings.Join(args, " "))
|
||||||
|
|
||||||
|
ripgrep := exec.Command(
|
||||||
|
rgBin,
|
||||||
|
args...,
|
||||||
|
)
|
||||||
|
|
||||||
|
result, err := ripgrep.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("out: %s", result)
|
||||||
|
log.Fatalf("failed to run ripgrep: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := strings.Split(string(result), "\n")
|
||||||
|
tests = tests[:len(tests)-1]
|
||||||
|
|
||||||
|
return tests
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
type testConfig struct {
|
type testConfig struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(kradalby): automatic fetch tests at runtime
|
tests := findTests()
|
||||||
tests := []string{
|
|
||||||
"TestAuthKeyLogoutAndRelogin",
|
removeTests()
|
||||||
"TestAuthWebFlowAuthenticationPingAll",
|
|
||||||
"TestAuthWebFlowLogoutAndRelogin",
|
|
||||||
"TestCreateTailscale",
|
|
||||||
"TestEnablingRoutes",
|
|
||||||
"TestHeadscale",
|
|
||||||
"TestUserCommand",
|
|
||||||
"TestOIDCAuthenticationPingAll",
|
|
||||||
"TestOIDCExpireNodes",
|
|
||||||
"TestPingAllByHostname",
|
|
||||||
"TestPingAllByIP",
|
|
||||||
"TestPreAuthKeyCommand",
|
|
||||||
"TestPreAuthKeyCommandReusableEphemeral",
|
|
||||||
"TestPreAuthKeyCommandWithoutExpiry",
|
|
||||||
"TestResolveMagicDNS",
|
|
||||||
"TestSSHIsBlockedInACL",
|
|
||||||
"TestSSHMultipleUsersAllToAll",
|
|
||||||
"TestSSHNoSSHConfigured",
|
|
||||||
"TestSSHOneUserAllToAll",
|
|
||||||
"TestSSUserOnlyIsolation",
|
|
||||||
"TestTaildrop",
|
|
||||||
"TestTailscaleNodesJoiningHeadcale",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
log.Printf("generating workflow for %s", test)
|
||||||
|
|
||||||
var content bytes.Buffer
|
var content bytes.Buffer
|
||||||
|
|
||||||
if err := jobTemplate.Execute(&content, testConfig{
|
if err := jobTemplate.Execute(&content, testConfig{
|
||||||
@@ -104,9 +153,9 @@ func main() {
|
|||||||
log.Fatalf("failed to render template: %s", err)
|
log.Fatalf("failed to render template: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
path := "../../.github/workflows/" + fmt.Sprintf(jobFileNameTemplate, test)
|
testPath := path.Join(githubWorkflowPath, fmt.Sprintf(jobFileNameTemplate, test))
|
||||||
|
|
||||||
err := os.WriteFile(path, content.Bytes(), workflowFilePerm)
|
err := os.WriteFile(testPath, content.Bytes(), workflowFilePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to write github job: %s", err)
|
log.Fatalf("failed to write github job: %s", err)
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,13 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("")
|
log.Fatal().Err(err).Msg("")
|
||||||
}
|
}
|
||||||
createNodeCmd.Flags().StringP("user", "n", "", "User")
|
createNodeCmd.Flags().StringP("user", "u", "", "User")
|
||||||
|
|
||||||
|
createNodeCmd.Flags().StringP("namespace", "n", "", "User")
|
||||||
|
createNodeNamespaceFlag := createNodeCmd.Flags().Lookup("namespace")
|
||||||
|
createNodeNamespaceFlag.Deprecated = deprecateNamespaceMessage
|
||||||
|
createNodeNamespaceFlag.Hidden = true
|
||||||
|
|
||||||
err = createNodeCmd.MarkFlagRequired("user")
|
err = createNodeCmd.MarkFlagRequired("user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("")
|
log.Fatal().Err(err).Msg("")
|
||||||
|
@@ -19,11 +19,23 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(nodeCmd)
|
rootCmd.AddCommand(nodeCmd)
|
||||||
listNodesCmd.Flags().StringP("user", "n", "", "Filter by user")
|
listNodesCmd.Flags().StringP("user", "u", "", "Filter by user")
|
||||||
listNodesCmd.Flags().BoolP("tags", "t", false, "Show tags")
|
listNodesCmd.Flags().BoolP("tags", "t", false, "Show tags")
|
||||||
|
|
||||||
|
listNodesCmd.Flags().StringP("namespace", "n", "", "User")
|
||||||
|
listNodesNamespaceFlag := listNodesCmd.Flags().Lookup("namespace")
|
||||||
|
listNodesNamespaceFlag.Deprecated = deprecateNamespaceMessage
|
||||||
|
listNodesNamespaceFlag.Hidden = true
|
||||||
|
|
||||||
nodeCmd.AddCommand(listNodesCmd)
|
nodeCmd.AddCommand(listNodesCmd)
|
||||||
|
|
||||||
registerNodeCmd.Flags().StringP("user", "n", "", "User")
|
registerNodeCmd.Flags().StringP("user", "u", "", "User")
|
||||||
|
|
||||||
|
registerNodeCmd.Flags().StringP("namespace", "n", "", "User")
|
||||||
|
registerNodeNamespaceFlag := registerNodeCmd.Flags().Lookup("namespace")
|
||||||
|
registerNodeNamespaceFlag.Deprecated = deprecateNamespaceMessage
|
||||||
|
registerNodeNamespaceFlag.Hidden = true
|
||||||
|
|
||||||
err := registerNodeCmd.MarkFlagRequired("user")
|
err := registerNodeCmd.MarkFlagRequired("user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf(err.Error())
|
log.Fatalf(err.Error())
|
||||||
@@ -63,7 +75,12 @@ func init() {
|
|||||||
log.Fatalf(err.Error())
|
log.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
moveNodeCmd.Flags().StringP("user", "n", "", "New user")
|
moveNodeCmd.Flags().StringP("user", "u", "", "New user")
|
||||||
|
|
||||||
|
moveNodeCmd.Flags().StringP("namespace", "n", "", "User")
|
||||||
|
moveNodeNamespaceFlag := moveNodeCmd.Flags().Lookup("namespace")
|
||||||
|
moveNodeNamespaceFlag.Deprecated = deprecateNamespaceMessage
|
||||||
|
moveNodeNamespaceFlag.Hidden = true
|
||||||
|
|
||||||
err = moveNodeCmd.MarkFlagRequired("user")
|
err = moveNodeCmd.MarkFlagRequired("user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -20,7 +20,13 @@ const (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(preauthkeysCmd)
|
rootCmd.AddCommand(preauthkeysCmd)
|
||||||
preauthkeysCmd.PersistentFlags().StringP("user", "n", "", "User")
|
preauthkeysCmd.PersistentFlags().StringP("user", "u", "", "User")
|
||||||
|
|
||||||
|
preauthkeysCmd.PersistentFlags().StringP("namespace", "n", "", "User")
|
||||||
|
pakNamespaceFlag := preauthkeysCmd.PersistentFlags().Lookup("namespace")
|
||||||
|
pakNamespaceFlag.Deprecated = deprecateNamespaceMessage
|
||||||
|
pakNamespaceFlag.Hidden = true
|
||||||
|
|
||||||
err := preauthkeysCmd.MarkPersistentFlagRequired("user")
|
err := preauthkeysCmd.MarkPersistentFlagRequired("user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("")
|
log.Fatal().Err(err).Msg("")
|
||||||
|
@@ -12,10 +12,15 @@ import (
|
|||||||
"github.com/tcnksm/go-latest"
|
"github.com/tcnksm/go-latest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
deprecateNamespaceMessage = "use --user"
|
||||||
|
)
|
||||||
|
|
||||||
var cfgFile string = ""
|
var cfgFile string = ""
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if len(os.Args) > 1 && (os.Args[1] == "version" || os.Args[1] == "mockoidc" || os.Args[1] == "completion") {
|
if len(os.Args) > 1 &&
|
||||||
|
(os.Args[1] == "version" || os.Args[1] == "mockoidc" || os.Args[1] == "completion") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,8 +3,10 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/juanfont/headscale"
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
"github.com/pterm/pterm"
|
"github.com/pterm/pterm"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -218,6 +220,19 @@ func routesToPtables(routes []*v1.Route) pterm.TableData {
|
|||||||
tableData := pterm.TableData{{"ID", "Machine", "Prefix", "Advertised", "Enabled", "Primary"}}
|
tableData := pterm.TableData{{"ID", "Machine", "Prefix", "Advertised", "Enabled", "Primary"}}
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
|
var isPrimaryStr string
|
||||||
|
prefix, err := netip.ParsePrefix(route.Prefix)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error parsing prefix %s: %s", route.Prefix, err)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if prefix == headscale.ExitRouteV4 || prefix == headscale.ExitRouteV6 {
|
||||||
|
isPrimaryStr = "-"
|
||||||
|
} else {
|
||||||
|
isPrimaryStr = strconv.FormatBool(route.IsPrimary)
|
||||||
|
}
|
||||||
|
|
||||||
tableData = append(tableData,
|
tableData = append(tableData,
|
||||||
[]string{
|
[]string{
|
||||||
strconv.FormatUint(route.Id, Base10),
|
strconv.FormatUint(route.Id, Base10),
|
||||||
@@ -225,7 +240,7 @@ func routesToPtables(routes []*v1.Route) pterm.TableData {
|
|||||||
route.Prefix,
|
route.Prefix,
|
||||||
strconv.FormatBool(route.Advertised),
|
strconv.FormatBool(route.Advertised),
|
||||||
strconv.FormatBool(route.Enabled),
|
strconv.FormatBool(route.Enabled),
|
||||||
strconv.FormatBool(route.IsPrimary),
|
isPrimaryStr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@ const (
|
|||||||
var userCmd = &cobra.Command{
|
var userCmd = &cobra.Command{
|
||||||
Use: "users",
|
Use: "users",
|
||||||
Short: "Manage the users of Headscale",
|
Short: "Manage the users of Headscale",
|
||||||
Aliases: []string{"user", "namespace", "ns"},
|
Aliases: []string{"user", "namespace", "namespaces", "ns"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var createUserCmd = &cobra.Command{
|
var createUserCmd = &cobra.Command{
|
||||||
|
@@ -282,27 +282,38 @@ unix_socket_permission: "0770"
|
|||||||
# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
|
# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
|
||||||
# # client_secret and client_secret_path are mutually exclusive.
|
# # client_secret and client_secret_path are mutually exclusive.
|
||||||
#
|
#
|
||||||
# Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
|
# # The amount of time from a node is authenticated with OpenID until it
|
||||||
# parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
|
# # expires and needs to reauthenticate.
|
||||||
|
# # Setting the value to "0" will mean no expiry.
|
||||||
|
# expiry: 180d
|
||||||
|
#
|
||||||
|
# # Use the expiry from the token received from OpenID when the user logged
|
||||||
|
# # in, this will typically lead to frequent need to reauthenticate and should
|
||||||
|
# # only been enabled if you know what you are doing.
|
||||||
|
# # Note: enabling this will cause `oidc.expiry` to be ignored.
|
||||||
|
# use_expiry_from_token: false
|
||||||
|
#
|
||||||
|
# # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
|
||||||
|
# # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
|
||||||
#
|
#
|
||||||
# scope: ["openid", "profile", "email", "custom"]
|
# scope: ["openid", "profile", "email", "custom"]
|
||||||
# extra_params:
|
# extra_params:
|
||||||
# domain_hint: example.com
|
# domain_hint: example.com
|
||||||
#
|
#
|
||||||
# List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the
|
# # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the
|
||||||
# authentication request will be rejected.
|
# # authentication request will be rejected.
|
||||||
#
|
#
|
||||||
# allowed_domains:
|
# allowed_domains:
|
||||||
# - example.com
|
# - example.com
|
||||||
# Groups from keycloak have a leading '/'
|
# # Note: Groups from keycloak have a leading '/'
|
||||||
# allowed_groups:
|
# allowed_groups:
|
||||||
# - /headscale
|
# - /headscale
|
||||||
# allowed_users:
|
# allowed_users:
|
||||||
# - alice@example.com
|
# - alice@example.com
|
||||||
#
|
#
|
||||||
# If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed.
|
# # If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed.
|
||||||
# This will transform `first-name.last-name@example.com` to the user `first-name.last-name`
|
# # This will transform `first-name.last-name@example.com` to the user `first-name.last-name`
|
||||||
# If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following
|
# # If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following
|
||||||
# user: `first-name.last-name.example.com`
|
# user: `first-name.last-name.example.com`
|
||||||
#
|
#
|
||||||
# strip_email_domain: true
|
# strip_email_domain: true
|
||||||
|
74
config.go
74
config.go
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -25,9 +26,14 @@ const (
|
|||||||
|
|
||||||
JSONLogFormat = "json"
|
JSONLogFormat = "json"
|
||||||
TextLogFormat = "text"
|
TextLogFormat = "text"
|
||||||
|
|
||||||
|
defaultOIDCExpiryTime = 180 * 24 * time.Hour // 180 Days
|
||||||
|
maxDuration time.Duration = 1<<63 - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var errOidcMutuallyExclusive = errors.New("oidc_client_secret and oidc_client_secret_path are mutually exclusive")
|
var errOidcMutuallyExclusive = errors.New(
|
||||||
|
"oidc_client_secret and oidc_client_secret_path are mutually exclusive",
|
||||||
|
)
|
||||||
|
|
||||||
// Config contains the initial Headscale configuration.
|
// Config contains the initial Headscale configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -101,6 +107,8 @@ type OIDCConfig struct {
|
|||||||
AllowedUsers []string
|
AllowedUsers []string
|
||||||
AllowedGroups []string
|
AllowedGroups []string
|
||||||
StripEmaildomain bool
|
StripEmaildomain bool
|
||||||
|
Expiry time.Duration
|
||||||
|
UseExpiryFromToken bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type DERPConfig struct {
|
type DERPConfig struct {
|
||||||
@@ -180,6 +188,8 @@ func LoadConfig(path string, isFile bool) error {
|
|||||||
viper.SetDefault("oidc.scope", []string{oidc.ScopeOpenID, "profile", "email"})
|
viper.SetDefault("oidc.scope", []string{oidc.ScopeOpenID, "profile", "email"})
|
||||||
viper.SetDefault("oidc.strip_email_domain", true)
|
viper.SetDefault("oidc.strip_email_domain", true)
|
||||||
viper.SetDefault("oidc.only_start_if_oidc_is_available", true)
|
viper.SetDefault("oidc.only_start_if_oidc_is_available", true)
|
||||||
|
viper.SetDefault("oidc.expiry", "180d")
|
||||||
|
viper.SetDefault("oidc.use_expiry_from_token", false)
|
||||||
|
|
||||||
viper.SetDefault("logtail.enabled", false)
|
viper.SetDefault("logtail.enabled", false)
|
||||||
viper.SetDefault("randomize_client_port", false)
|
viper.SetDefault("randomize_client_port", false)
|
||||||
@@ -411,34 +421,32 @@ func GetDNSConfig() (*tailcfg.DNSConfig, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if viper.IsSet("dns_config.restricted_nameservers") {
|
if viper.IsSet("dns_config.restricted_nameservers") {
|
||||||
if len(dnsConfig.Resolvers) > 0 {
|
dnsConfig.Routes = make(map[string][]*dnstype.Resolver)
|
||||||
dnsConfig.Routes = make(map[string][]*dnstype.Resolver)
|
domains := []string{}
|
||||||
restrictedDNS := viper.GetStringMapStringSlice(
|
restrictedDNS := viper.GetStringMapStringSlice(
|
||||||
"dns_config.restricted_nameservers",
|
"dns_config.restricted_nameservers",
|
||||||
|
)
|
||||||
|
for domain, restrictedNameservers := range restrictedDNS {
|
||||||
|
restrictedResolvers := make(
|
||||||
|
[]*dnstype.Resolver,
|
||||||
|
len(restrictedNameservers),
|
||||||
)
|
)
|
||||||
for domain, restrictedNameservers := range restrictedDNS {
|
for index, nameserverStr := range restrictedNameservers {
|
||||||
restrictedResolvers := make(
|
nameserver, err := netip.ParseAddr(nameserverStr)
|
||||||
[]*dnstype.Resolver,
|
if err != nil {
|
||||||
len(restrictedNameservers),
|
log.Error().
|
||||||
)
|
Str("func", "getDNSConfig").
|
||||||
for index, nameserverStr := range restrictedNameservers {
|
Err(err).
|
||||||
nameserver, err := netip.ParseAddr(nameserverStr)
|
Msgf("Could not parse restricted nameserver IP: %s", nameserverStr)
|
||||||
if err != nil {
|
}
|
||||||
log.Error().
|
restrictedResolvers[index] = &dnstype.Resolver{
|
||||||
Str("func", "getDNSConfig").
|
Addr: nameserver.String(),
|
||||||
Err(err).
|
|
||||||
Msgf("Could not parse restricted nameserver IP: %s", nameserverStr)
|
|
||||||
}
|
|
||||||
restrictedResolvers[index] = &dnstype.Resolver{
|
|
||||||
Addr: nameserver.String(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dnsConfig.Routes[domain] = restrictedResolvers
|
|
||||||
}
|
}
|
||||||
} else {
|
dnsConfig.Routes[domain] = restrictedResolvers
|
||||||
log.Warn().
|
domains = append(domains, domain)
|
||||||
Msg("Warning: dns_config.restricted_nameservers is set, but no nameservers are configured. Ignoring restricted_nameservers.")
|
|
||||||
}
|
}
|
||||||
|
dnsConfig.Domains = domains
|
||||||
}
|
}
|
||||||
|
|
||||||
if viper.IsSet("dns_config.domains") {
|
if viper.IsSet("dns_config.domains") {
|
||||||
@@ -603,6 +611,22 @@ func GetHeadscaleConfig() (*Config, error) {
|
|||||||
AllowedUsers: viper.GetStringSlice("oidc.allowed_users"),
|
AllowedUsers: viper.GetStringSlice("oidc.allowed_users"),
|
||||||
AllowedGroups: viper.GetStringSlice("oidc.allowed_groups"),
|
AllowedGroups: viper.GetStringSlice("oidc.allowed_groups"),
|
||||||
StripEmaildomain: viper.GetBool("oidc.strip_email_domain"),
|
StripEmaildomain: viper.GetBool("oidc.strip_email_domain"),
|
||||||
|
Expiry: func() time.Duration {
|
||||||
|
// if set to 0, we assume no expiry
|
||||||
|
if value := viper.GetString("oidc.expiry"); value == "0" {
|
||||||
|
return maxDuration
|
||||||
|
} else {
|
||||||
|
expiry, err := model.ParseDuration(value)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Msg("failed to parse oidc.expiry, defaulting back to 180 days")
|
||||||
|
|
||||||
|
return defaultOIDCExpiryTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Duration(expiry)
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
UseExpiryFromToken: viper.GetBool("oidc.use_expiry_from_token"),
|
||||||
},
|
},
|
||||||
|
|
||||||
LogTail: logConfig,
|
LogTail: logConfig,
|
||||||
|
3
db.go
3
db.go
@@ -48,6 +48,9 @@ func (h *Headscale) initDB() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = db.Migrator().RenameColumn(&Machine{}, "namespace_id", "user_id")
|
||||||
|
_ = db.Migrator().RenameColumn(&PreAuthKey{}, "namespace_id", "user_id")
|
||||||
|
|
||||||
_ = db.Migrator().RenameColumn(&Machine{}, "ip_address", "ip_addresses")
|
_ = db.Migrator().RenameColumn(&Machine{}, "ip_address", "ip_addresses")
|
||||||
_ = db.Migrator().RenameColumn(&Machine{}, "name", "hostname")
|
_ = db.Migrator().RenameColumn(&Machine{}, "name", "hostname")
|
||||||
|
|
||||||
|
@@ -80,4 +80,4 @@ server {
|
|||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
[Not all types of records are supported](https://github.com/tailscale/tailscale/blob/main/ipn/ipnlocal/local.go#L2891-L2909), especially no CNAME records.
|
[Not all types of records are supported](https://github.com/tailscale/tailscale/blob/6edf357b96b28ee1be659a70232c0135b2ffedfd/ipn/ipnlocal/local.go#L2989-L3007), especially no CNAME records.
|
||||||
|
@@ -112,3 +112,20 @@ The following Caddyfile is all that is necessary to use Caddy as a reverse proxy
|
|||||||
Caddy v2 will [automatically](https://caddyserver.com/docs/automatic-https) provision a certficate for your domain/subdomain, force HTTPS, and proxy websockets - no further configuration is necessary.
|
Caddy v2 will [automatically](https://caddyserver.com/docs/automatic-https) provision a certficate for your domain/subdomain, force HTTPS, and proxy websockets - no further configuration is necessary.
|
||||||
|
|
||||||
For a slightly more complex configuration which utilizes Docker containers to manage Caddy, Headscale, and Headscale-UI, [Guru Computing's guide](https://blog.gurucomputing.com.au/smart-vpns-with-headscale/) is an excellent reference.
|
For a slightly more complex configuration which utilizes Docker containers to manage Caddy, Headscale, and Headscale-UI, [Guru Computing's guide](https://blog.gurucomputing.com.au/smart-vpns-with-headscale/) is an excellent reference.
|
||||||
|
|
||||||
|
## Apache
|
||||||
|
|
||||||
|
The following minimal Apache config will proxy traffic to the Headscale instance on `<IP:PORT>`. Note that `upgrade=any` is required as a parameter for `ProxyPass` so that WebSockets traffic whose `Upgrade` header value is not equal to `WebSocket` (i. e. Tailscale Control Protocol) is forwarded correctly. See the [Apache docs](https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html) for more information on this.
|
||||||
|
|
||||||
|
```
|
||||||
|
<VirtualHost *:443>
|
||||||
|
ServerName <YOUR_SERVER_NAME>
|
||||||
|
|
||||||
|
ProxyPreserveHost On
|
||||||
|
ProxyPass / http://<IP:PORT>/ upgrade=any
|
||||||
|
|
||||||
|
SSLEngine On
|
||||||
|
SSLCertificateFile <PATH_TO_CERT>
|
||||||
|
SSLCertificateKeyFile <PATH_CERT_KEY>
|
||||||
|
</VirtualHost>
|
||||||
|
```
|
||||||
|
270
flake.nix
270
flake.nix
@@ -6,157 +6,163 @@
|
|||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs =
|
||||||
self,
|
{ self
|
||||||
nixpkgs,
|
, nixpkgs
|
||||||
flake-utils,
|
, flake-utils
|
||||||
...
|
, ...
|
||||||
}: let
|
}:
|
||||||
headscaleVersion =
|
let
|
||||||
if (self ? shortRev)
|
headscaleVersion =
|
||||||
then self.shortRev
|
if (self ? shortRev)
|
||||||
else "dev";
|
then self.shortRev
|
||||||
in
|
else "dev";
|
||||||
|
in
|
||||||
{
|
{
|
||||||
overlay = _: prev: let
|
overlay = _: prev:
|
||||||
pkgs = nixpkgs.legacyPackages.${prev.system};
|
let
|
||||||
in rec {
|
pkgs = nixpkgs.legacyPackages.${prev.system};
|
||||||
headscale = pkgs.buildGo119Module rec {
|
in
|
||||||
pname = "headscale";
|
rec {
|
||||||
version = headscaleVersion;
|
headscale = pkgs.buildGo119Module rec {
|
||||||
src = pkgs.lib.cleanSource self;
|
pname = "headscale";
|
||||||
|
version = headscaleVersion;
|
||||||
|
src = pkgs.lib.cleanSource self;
|
||||||
|
|
||||||
tags = ["ts2019"];
|
tags = [ "ts2019" ];
|
||||||
|
|
||||||
# Only run unit tests when testing a build
|
# Only run unit tests when testing a build
|
||||||
checkFlags = ["-short"];
|
checkFlags = [ "-short" ];
|
||||||
|
|
||||||
# When updating go.mod or go.sum, a new sha will need to be calculated,
|
# When updating go.mod or go.sum, a new sha will need to be calculated,
|
||||||
# update this if you have a mismatch after doing a change to thos files.
|
# update this if you have a mismatch after doing a change to thos files.
|
||||||
vendorSha256 = "sha256-SuKT+b8g6xEK15ry2IAmpS/vwDG+zJqK9nfsWpHNXuU=";
|
vendorSha256 = "sha256-8p5NFxXKaZPsW4B6NMzfi0pqfVroIahSgA0fukvB3JI=";
|
||||||
|
|
||||||
ldflags = ["-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}"];
|
ldflags = [ "-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}" ];
|
||||||
};
|
|
||||||
|
|
||||||
golines = pkgs.buildGoModule rec {
|
|
||||||
pname = "golines";
|
|
||||||
version = "0.11.0";
|
|
||||||
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "segmentio";
|
|
||||||
repo = "golines";
|
|
||||||
rev = "v${version}";
|
|
||||||
sha256 = "sha256-2K9KAg8iSubiTbujyFGN3yggrL+EDyeUCs9OOta/19A=";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "sha256-rxYuzn4ezAxaeDhxd8qdOzt+CKYIh03A9zKNdzILq18=";
|
golines = pkgs.buildGoModule rec {
|
||||||
|
pname = "golines";
|
||||||
|
version = "0.11.0";
|
||||||
|
|
||||||
nativeBuildInputs = [pkgs.installShellFiles];
|
src = pkgs.fetchFromGitHub {
|
||||||
};
|
owner = "segmentio";
|
||||||
|
repo = "golines";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-2K9KAg8iSubiTbujyFGN3yggrL+EDyeUCs9OOta/19A=";
|
||||||
|
};
|
||||||
|
|
||||||
golangci-lint = prev.golangci-lint.override {
|
vendorSha256 = "sha256-rxYuzn4ezAxaeDhxd8qdOzt+CKYIh03A9zKNdzILq18=";
|
||||||
# Override https://github.com/NixOS/nixpkgs/pull/166801 which changed this
|
|
||||||
# to buildGo118Module because it does not build on Darwin.
|
|
||||||
inherit (prev) buildGoModule;
|
|
||||||
};
|
|
||||||
|
|
||||||
protoc-gen-grpc-gateway = pkgs.buildGoModule rec {
|
nativeBuildInputs = [ pkgs.installShellFiles ];
|
||||||
pname = "grpc-gateway";
|
|
||||||
version = "2.14.0";
|
|
||||||
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "grpc-ecosystem";
|
|
||||||
repo = "grpc-gateway";
|
|
||||||
rev = "v${version}";
|
|
||||||
sha256 = "sha256-lnNdsDCpeSHtl2lC1IhUw11t3cnGF+37qSM7HDvKLls=";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
vendorSha256 = "sha256-dGdnDuRbwg8fU7uB5GaHEWa/zI3w06onqjturvooJQA=";
|
golangci-lint = prev.golangci-lint.override {
|
||||||
|
# Override https://github.com/NixOS/nixpkgs/pull/166801 which changed this
|
||||||
|
# to buildGo118Module because it does not build on Darwin.
|
||||||
|
inherit (prev) buildGoModule;
|
||||||
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [pkgs.installShellFiles];
|
protoc-gen-grpc-gateway = pkgs.buildGoModule rec {
|
||||||
|
pname = "grpc-gateway";
|
||||||
|
version = "2.14.0";
|
||||||
|
|
||||||
subPackages = ["protoc-gen-grpc-gateway" "protoc-gen-openapiv2"];
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "grpc-ecosystem";
|
||||||
|
repo = "grpc-gateway";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-lnNdsDCpeSHtl2lC1IhUw11t3cnGF+37qSM7HDvKLls=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorSha256 = "sha256-dGdnDuRbwg8fU7uB5GaHEWa/zI3w06onqjturvooJQA=";
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkgs.installShellFiles ];
|
||||||
|
|
||||||
|
subPackages = [ "protoc-gen-grpc-gateway" "protoc-gen-openapiv2" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// flake-utils.lib.eachDefaultSystem
|
// flake-utils.lib.eachDefaultSystem
|
||||||
(system: let
|
(system:
|
||||||
pkgs = import nixpkgs {
|
let
|
||||||
overlays = [self.overlay];
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
overlays = [ self.overlay ];
|
||||||
};
|
inherit system;
|
||||||
buildDeps = with pkgs; [git go_1_19 gnumake];
|
};
|
||||||
devDeps = with pkgs;
|
buildDeps = with pkgs; [ git go_1_19 gnumake ];
|
||||||
buildDeps
|
devDeps = with pkgs;
|
||||||
++ [
|
buildDeps
|
||||||
golangci-lint
|
++ [
|
||||||
golines
|
golangci-lint
|
||||||
nodePackages.prettier
|
golines
|
||||||
goreleaser
|
nodePackages.prettier
|
||||||
|
goreleaser
|
||||||
|
gotestsum
|
||||||
|
|
||||||
# Protobuf dependencies
|
# Protobuf dependencies
|
||||||
protobuf
|
protobuf
|
||||||
protoc-gen-go
|
protoc-gen-go
|
||||||
protoc-gen-go-grpc
|
protoc-gen-go-grpc
|
||||||
protoc-gen-grpc-gateway
|
protoc-gen-grpc-gateway
|
||||||
buf
|
buf
|
||||||
clang-tools # clang-format
|
clang-tools # clang-format
|
||||||
];
|
];
|
||||||
|
|
||||||
# Add entry to build a docker image with headscale
|
# Add entry to build a docker image with headscale
|
||||||
# caveat: only works on Linux
|
# caveat: only works on Linux
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# nix build .#headscale-docker
|
# nix build .#headscale-docker
|
||||||
# docker load < result
|
# docker load < result
|
||||||
headscale-docker = pkgs.dockerTools.buildLayeredImage {
|
headscale-docker = pkgs.dockerTools.buildLayeredImage {
|
||||||
name = "headscale";
|
name = "headscale";
|
||||||
tag = headscaleVersion;
|
tag = headscaleVersion;
|
||||||
contents = [pkgs.headscale];
|
contents = [ pkgs.headscale ];
|
||||||
config.Entrypoint = [(pkgs.headscale + "/bin/headscale")];
|
config.Entrypoint = [ (pkgs.headscale + "/bin/headscale") ];
|
||||||
};
|
};
|
||||||
in rec {
|
in
|
||||||
# `nix develop`
|
rec {
|
||||||
devShell = pkgs.mkShell {
|
# `nix develop`
|
||||||
buildInputs = devDeps;
|
devShell = pkgs.mkShell {
|
||||||
|
buildInputs = devDeps;
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export GOFLAGS=-tags="ts2019"
|
export GOFLAGS=-tags="ts2019"
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# `nix build`
|
|
||||||
packages = with pkgs; {
|
|
||||||
inherit headscale;
|
|
||||||
inherit headscale-docker;
|
|
||||||
};
|
|
||||||
defaultPackage = pkgs.headscale;
|
|
||||||
|
|
||||||
# `nix run`
|
|
||||||
apps.headscale = flake-utils.lib.mkApp {
|
|
||||||
drv = packages.headscale;
|
|
||||||
};
|
|
||||||
apps.default = apps.headscale;
|
|
||||||
|
|
||||||
checks = {
|
|
||||||
format =
|
|
||||||
pkgs.runCommand "check-format"
|
|
||||||
{
|
|
||||||
buildInputs = with pkgs; [
|
|
||||||
gnumake
|
|
||||||
nixpkgs-fmt
|
|
||||||
golangci-lint
|
|
||||||
nodePackages.prettier
|
|
||||||
golines
|
|
||||||
clang-tools
|
|
||||||
];
|
|
||||||
} ''
|
|
||||||
${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ${./.}
|
|
||||||
${pkgs.golangci-lint}/bin/golangci-lint run --fix --timeout 10m
|
|
||||||
${pkgs.nodePackages.prettier}/bin/prettier --write '**/**.{ts,js,md,yaml,yml,sass,css,scss,html}'
|
|
||||||
${pkgs.golines}/bin/golines --max-len=88 --base-formatter=gofumpt -w ${./.}
|
|
||||||
${pkgs.clang-tools}/bin/clang-format -style="{BasedOnStyle: Google, IndentWidth: 4, AlignConsecutiveDeclarations: true, AlignConsecutiveAssignments: true, ColumnLimit: 0}" -i ${./.}
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
# `nix build`
|
||||||
|
packages = with pkgs; {
|
||||||
|
inherit headscale;
|
||||||
|
inherit headscale-docker;
|
||||||
|
};
|
||||||
|
defaultPackage = pkgs.headscale;
|
||||||
|
|
||||||
|
# `nix run`
|
||||||
|
apps.headscale = flake-utils.lib.mkApp {
|
||||||
|
drv = packages.headscale;
|
||||||
|
};
|
||||||
|
apps.default = apps.headscale;
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
format =
|
||||||
|
pkgs.runCommand "check-format"
|
||||||
|
{
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
gnumake
|
||||||
|
nixpkgs-fmt
|
||||||
|
golangci-lint
|
||||||
|
nodePackages.prettier
|
||||||
|
golines
|
||||||
|
clang-tools
|
||||||
|
];
|
||||||
|
} ''
|
||||||
|
${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ${./.}
|
||||||
|
${pkgs.golangci-lint}/bin/golangci-lint run --fix --timeout 10m
|
||||||
|
${pkgs.nodePackages.prettier}/bin/prettier --write '**/**.{ts,js,md,yaml,yml,sass,css,scss,html}'
|
||||||
|
${pkgs.golines}/bin/golines --max-len=88 --base-formatter=gofumpt -w ${./.}
|
||||||
|
${pkgs.clang-tools}/bin/clang-format -style="{BasedOnStyle: Google, IndentWidth: 4, AlignConsecutiveDeclarations: true, AlignConsecutiveAssignments: true, ColumnLimit: 0}" -i ${./.}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@@ -7,6 +7,7 @@ require (
|
|||||||
github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029
|
github.com/ccding/go-stun/stun v0.0.0-20200514191101-4dc67bcdb029
|
||||||
github.com/cenkalti/backoff/v4 v4.2.0
|
github.com/cenkalti/backoff/v4 v4.2.0
|
||||||
github.com/coreos/go-oidc/v3 v3.4.0
|
github.com/coreos/go-oidc/v3 v3.4.0
|
||||||
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set/v2 v2.1.0
|
github.com/deckarep/golang-set/v2 v2.1.0
|
||||||
github.com/efekarakus/termcolor v1.0.1
|
github.com/efekarakus/termcolor v1.0.1
|
||||||
github.com/glebarez/sqlite v1.5.0
|
github.com/glebarez/sqlite v1.5.0
|
||||||
@@ -58,7 +59,6 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/containerd/console v1.0.3 // indirect
|
github.com/containerd/console v1.0.3 // indirect
|
||||||
github.com/containerd/continuity v0.3.0 // indirect
|
github.com/containerd/continuity v0.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/docker/cli v20.10.21+incompatible // indirect
|
github.com/docker/cli v20.10.21+incompatible // indirect
|
||||||
github.com/docker/docker v20.10.21+incompatible // indirect
|
github.com/docker/docker v20.10.21+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
|
@@ -11,6 +11,5 @@ Tests are located in files ending with `_test.go` and the framework are located
|
|||||||
|
|
||||||
## Running integration tests on GitHub Actions
|
## Running integration tests on GitHub Actions
|
||||||
|
|
||||||
Each test currently runs as a separate workflows in GitHub actions, to add new test, add
|
Each test currently runs as a separate workflows in GitHub actions, to add new test, run
|
||||||
the new test to the list in `../cmd/gh-action-integration-generator/main.go` and run
|
|
||||||
`go generate` inside `../cmd/gh-action-integration-generator/` and commit the result.
|
`go generate` inside `../cmd/gh-action-integration-generator/` and commit the result.
|
||||||
|
@@ -100,7 +100,7 @@ func TestOIDCAuthenticationPingAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOIDCExpireNodes(t *testing.T) {
|
func TestOIDCExpireNodesBasedOnTokenExpiry(t *testing.T) {
|
||||||
IntegrationSkip(t)
|
IntegrationSkip(t)
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -125,10 +125,11 @@ func TestOIDCExpireNodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
oidcMap := map[string]string{
|
oidcMap := map[string]string{
|
||||||
"HEADSCALE_OIDC_ISSUER": oidcConfig.Issuer,
|
"HEADSCALE_OIDC_ISSUER": oidcConfig.Issuer,
|
||||||
"HEADSCALE_OIDC_CLIENT_ID": oidcConfig.ClientID,
|
"HEADSCALE_OIDC_CLIENT_ID": oidcConfig.ClientID,
|
||||||
"HEADSCALE_OIDC_CLIENT_SECRET": oidcConfig.ClientSecret,
|
"HEADSCALE_OIDC_CLIENT_SECRET": oidcConfig.ClientSecret,
|
||||||
"HEADSCALE_OIDC_STRIP_EMAIL_DOMAIN": fmt.Sprintf("%t", oidcConfig.StripEmaildomain),
|
"HEADSCALE_OIDC_STRIP_EMAIL_DOMAIN": fmt.Sprintf("%t", oidcConfig.StripEmaildomain),
|
||||||
|
"HEADSCALE_OIDC_USE_EXPIRY_FROM_TOKEN": "1",
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(
|
err = scenario.CreateHeadscaleEnv(
|
||||||
@@ -278,7 +279,10 @@ func (s *AuthOIDCScenario) runMockOIDC(accessTTL time.Duration) (*headscale.OIDC
|
|||||||
log.Printf("headscale mock oidc is ready for tests at %s", hostEndpoint)
|
log.Printf("headscale mock oidc is ready for tests at %s", hostEndpoint)
|
||||||
|
|
||||||
return &headscale.OIDCConfig{
|
return &headscale.OIDCConfig{
|
||||||
Issuer: fmt.Sprintf("http://%s/oidc", net.JoinHostPort(s.mockOIDC.GetIPInNetwork(s.network), strconv.Itoa(port))),
|
Issuer: fmt.Sprintf(
|
||||||
|
"http://%s/oidc",
|
||||||
|
net.JoinHostPort(s.mockOIDC.GetIPInNetwork(s.network), strconv.Itoa(port)),
|
||||||
|
),
|
||||||
ClientID: "superclient",
|
ClientID: "superclient",
|
||||||
ClientSecret: "supersecret",
|
ClientSecret: "supersecret",
|
||||||
StripEmaildomain: true,
|
StripEmaildomain: true,
|
||||||
|
@@ -335,7 +335,7 @@ func (s *AuthWebFlowScenario) runHeadscaleRegister(userStr string, loginURL *url
|
|||||||
|
|
||||||
if headscale, err := s.Headscale(); err == nil {
|
if headscale, err := s.Headscale(); err == nil {
|
||||||
_, err = headscale.Execute(
|
_, err = headscale.Execute(
|
||||||
[]string{"headscale", "-n", userStr, "nodes", "register", "--key", key},
|
[]string{"headscale", "nodes", "register", "--user", userStr, "--key", key},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to register node: %s", err)
|
log.Printf("failed to register node: %s", err)
|
||||||
|
@@ -99,7 +99,7 @@ func TestUserCommand(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
t,
|
t,
|
||||||
[]string{"user1", "newname"},
|
[]string{"newname", "user1"},
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
type ControlServer interface {
|
type ControlServer interface {
|
||||||
Shutdown() error
|
Shutdown() error
|
||||||
|
SaveLog(string) error
|
||||||
Execute(command []string) (string, error)
|
Execute(command []string) (string, error)
|
||||||
GetHealthEndpoint() string
|
GetHealthEndpoint() string
|
||||||
GetEndpoint() string
|
GetEndpoint() string
|
||||||
|
68
integration/dockertestutil/logs.go
Normal file
68
integration/dockertestutil/logs.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package dockertestutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/ory/dockertest/v3"
|
||||||
|
"github.com/ory/dockertest/v3/docker"
|
||||||
|
)
|
||||||
|
|
||||||
|
const filePerm = 0o644
|
||||||
|
|
||||||
|
func SaveLog(
|
||||||
|
pool *dockertest.Pool,
|
||||||
|
resource *dockertest.Resource,
|
||||||
|
basePath string,
|
||||||
|
) error {
|
||||||
|
err := os.MkdirAll(basePath, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
|
||||||
|
err = pool.Client.Logs(
|
||||||
|
docker.LogsOptions{
|
||||||
|
Context: context.TODO(),
|
||||||
|
Container: resource.Container.ID,
|
||||||
|
OutputStream: &stdout,
|
||||||
|
ErrorStream: &stderr,
|
||||||
|
Tail: "all",
|
||||||
|
RawTerminal: false,
|
||||||
|
Stdout: true,
|
||||||
|
Stderr: true,
|
||||||
|
Follow: false,
|
||||||
|
Timestamps: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Saving logs for %s to %s\n", resource.Container.Name, basePath)
|
||||||
|
|
||||||
|
err = os.WriteFile(
|
||||||
|
path.Join(basePath, resource.Container.Name+".stdout.log"),
|
||||||
|
stdout.Bytes(),
|
||||||
|
filePerm,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(
|
||||||
|
path.Join(basePath, resource.Container.Name+".stderr.log"),
|
||||||
|
stderr.Bytes(),
|
||||||
|
filePerm,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@@ -248,6 +248,10 @@ func (t *HeadscaleInContainer) Shutdown() error {
|
|||||||
return t.pool.Purge(t.container)
|
return t.pool.Purge(t.container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *HeadscaleInContainer) SaveLog(path string) error {
|
||||||
|
return dockertestutil.SaveLog(t.pool, t.container, path)
|
||||||
|
}
|
||||||
|
|
||||||
func (t *HeadscaleInContainer) Execute(
|
func (t *HeadscaleInContainer) Execute(
|
||||||
command []string,
|
command []string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
|
@@ -32,7 +32,8 @@ var (
|
|||||||
tailscaleVersions2021 = []string{
|
tailscaleVersions2021 = []string{
|
||||||
"head",
|
"head",
|
||||||
"unstable",
|
"unstable",
|
||||||
"1.34.0",
|
"1.36.0",
|
||||||
|
"1.34.2",
|
||||||
"1.32.3",
|
"1.32.3",
|
||||||
"1.30.2",
|
"1.30.2",
|
||||||
}
|
}
|
||||||
@@ -125,7 +126,15 @@ func NewScenario() (*Scenario, error) {
|
|||||||
|
|
||||||
func (s *Scenario) Shutdown() error {
|
func (s *Scenario) Shutdown() error {
|
||||||
s.controlServers.Range(func(_ string, control ControlServer) bool {
|
s.controlServers.Range(func(_ string, control ControlServer) bool {
|
||||||
err := control.Shutdown()
|
err := control.SaveLog("/tmp/control")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(
|
||||||
|
"Failed to save log from control: %s",
|
||||||
|
fmt.Errorf("failed to save log from control: %w", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = control.Shutdown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf(
|
log.Printf(
|
||||||
"Failed to shut down control: %s",
|
"Failed to shut down control: %s",
|
||||||
|
@@ -37,12 +37,14 @@ logtail:
|
|||||||
enabled: false
|
enabled: false
|
||||||
metrics_listen_addr: 127.0.0.1:19090
|
metrics_listen_addr: 127.0.0.1:19090
|
||||||
oidc:
|
oidc:
|
||||||
|
expiry: 180d
|
||||||
only_start_if_oidc_is_available: true
|
only_start_if_oidc_is_available: true
|
||||||
scope:
|
scope:
|
||||||
- openid
|
- openid
|
||||||
- profile
|
- profile
|
||||||
- email
|
- email
|
||||||
strip_email_domain: true
|
strip_email_domain: true
|
||||||
|
use_expiry_from_token: false
|
||||||
private_key_path: private.key
|
private_key_path: private.key
|
||||||
noise:
|
noise:
|
||||||
private_key_path: noise_private.key
|
private_key_path: noise_private.key
|
||||||
|
@@ -36,12 +36,14 @@ logtail:
|
|||||||
enabled: false
|
enabled: false
|
||||||
metrics_listen_addr: 127.0.0.1:19090
|
metrics_listen_addr: 127.0.0.1:19090
|
||||||
oidc:
|
oidc:
|
||||||
|
expiry: 180d
|
||||||
only_start_if_oidc_is_available: true
|
only_start_if_oidc_is_available: true
|
||||||
scope:
|
scope:
|
||||||
- openid
|
- openid
|
||||||
- profile
|
- profile
|
||||||
- email
|
- email
|
||||||
strip_email_domain: true
|
strip_email_domain: true
|
||||||
|
use_expiry_from_token: false
|
||||||
private_key_path: private.key
|
private_key_path: private.key
|
||||||
noise:
|
noise:
|
||||||
private_key_path: noise_private.key
|
private_key_path: noise_private.key
|
||||||
|
@@ -37,12 +37,14 @@ logtail:
|
|||||||
enabled: false
|
enabled: false
|
||||||
metrics_listen_addr: 127.0.0.1:9090
|
metrics_listen_addr: 127.0.0.1:9090
|
||||||
oidc:
|
oidc:
|
||||||
|
expiry: 180d
|
||||||
only_start_if_oidc_is_available: true
|
only_start_if_oidc_is_available: true
|
||||||
scope:
|
scope:
|
||||||
- openid
|
- openid
|
||||||
- profile
|
- profile
|
||||||
- email
|
- email
|
||||||
strip_email_domain: true
|
strip_email_domain: true
|
||||||
|
use_expiry_from_token: false
|
||||||
private_key_path: private.key
|
private_key_path: private.key
|
||||||
noise:
|
noise:
|
||||||
private_key_path: noise_private.key
|
private_key_path: noise_private.key
|
||||||
|
@@ -352,7 +352,7 @@ func (h *Headscale) ListMachines() ([]Machine, error) {
|
|||||||
|
|
||||||
func (h *Headscale) ListMachinesByGivenName(givenName string) ([]Machine, error) {
|
func (h *Headscale) ListMachinesByGivenName(givenName string) ([]Machine, error) {
|
||||||
machines := []Machine{}
|
machines := []Machine{}
|
||||||
if err := h.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Find(&machines).Where("given_name = ?", givenName).Error; err != nil {
|
if err := h.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where("given_name = ?", givenName).Find(&machines).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1047,8 +1047,8 @@ func (h *Headscale) IsRoutesEnabled(machine *Machine, routeStr string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableRoutes enables new routes based on a list of new routes.
|
// enableRoutes enables new routes based on a list of new routes.
|
||||||
func (h *Headscale) EnableRoutes(machine *Machine, routeStrs ...string) error {
|
func (h *Headscale) enableRoutes(machine *Machine, routeStrs ...string) error {
|
||||||
newRoutes := make([]netip.Prefix, len(routeStrs))
|
newRoutes := make([]netip.Prefix, len(routeStrs))
|
||||||
for index, routeStr := range routeStrs {
|
for index, routeStr := range routeStrs {
|
||||||
route, err := netip.ParsePrefix(routeStr)
|
route, err := netip.ParsePrefix(routeStr)
|
||||||
|
24
oidc.go
24
oidc.go
@@ -27,8 +27,10 @@ const (
|
|||||||
errOIDCAllowedDomains = Error("authenticated principal does not match any allowed domain")
|
errOIDCAllowedDomains = Error("authenticated principal does not match any allowed domain")
|
||||||
errOIDCAllowedGroups = Error("authenticated principal is not in any allowed group")
|
errOIDCAllowedGroups = Error("authenticated principal is not in any allowed group")
|
||||||
errOIDCAllowedUsers = Error("authenticated principal does not match any allowed user")
|
errOIDCAllowedUsers = Error("authenticated principal does not match any allowed user")
|
||||||
errOIDCInvalidMachineState = Error("requested machine state key expired before authorisation completed")
|
errOIDCInvalidMachineState = Error(
|
||||||
errOIDCNodeKeyMissing = Error("could not get node key from cache")
|
"requested machine state key expired before authorisation completed",
|
||||||
|
)
|
||||||
|
errOIDCNodeKeyMissing = Error("could not get node key from cache")
|
||||||
)
|
)
|
||||||
|
|
||||||
type IDTokenClaims struct {
|
type IDTokenClaims struct {
|
||||||
@@ -68,6 +70,14 @@ func (h *Headscale) initOIDC() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Headscale) determineTokenExpiration(idTokenExpiration time.Time) time.Time {
|
||||||
|
if h.cfg.OIDC.UseExpiryFromToken {
|
||||||
|
return idTokenExpiration
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Now().Add(h.cfg.OIDC.Expiry)
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterOIDC redirects to the OIDC provider for authentication
|
// RegisterOIDC redirects to the OIDC provider for authentication
|
||||||
// Puts NodeKey in cache so the callback can retrieve it using the oidc state param
|
// Puts NodeKey in cache so the callback can retrieve it using the oidc state param
|
||||||
// Listens in /oidc/register/:nKey.
|
// Listens in /oidc/register/:nKey.
|
||||||
@@ -193,6 +203,7 @@ func (h *Headscale) OIDCCallback(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
idTokenExpiry := h.determineTokenExpiration(idToken.Expiry)
|
||||||
|
|
||||||
// TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc)
|
// TODO: we can use userinfo at some point to grab additional information about the user (groups membership, etc)
|
||||||
// userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token))
|
// userInfo, err := oidcProvider.UserInfo(context.Background(), oauth2.StaticTokenSource(oauth2Token))
|
||||||
@@ -218,7 +229,12 @@ func (h *Headscale) OIDCCallback(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeKey, machineExists, err := h.validateMachineForOIDCCallback(writer, state, claims, idToken.Expiry)
|
nodeKey, machineExists, err := h.validateMachineForOIDCCallback(
|
||||||
|
writer,
|
||||||
|
state,
|
||||||
|
claims,
|
||||||
|
idTokenExpiry,
|
||||||
|
)
|
||||||
if err != nil || machineExists {
|
if err != nil || machineExists {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -236,7 +252,7 @@ func (h *Headscale) OIDCCallback(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.registerMachineForOIDCCallback(writer, user, nodeKey, idToken.Expiry); err != nil {
|
if err := h.registerMachineForOIDCCallback(writer, user, nodeKey, idTokenExpiry); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,9 +3,11 @@ package headscale
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"tailscale.com/smallzstd"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
)
|
)
|
||||||
@@ -103,8 +105,7 @@ func (h *Headscale) marshalMapResponse(
|
|||||||
|
|
||||||
var respBody []byte
|
var respBody []byte
|
||||||
if compression == ZstdCompression {
|
if compression == ZstdCompression {
|
||||||
encoder, _ := zstd.NewWriter(nil)
|
respBody = zstdEncode(jsonBody)
|
||||||
respBody = encoder.EncodeAll(jsonBody, nil)
|
|
||||||
if !isNoise { // if legacy protocol
|
if !isNoise { // if legacy protocol
|
||||||
respBody = h.privateKey.SealTo(machineKey, respBody)
|
respBody = h.privateKey.SealTo(machineKey, respBody)
|
||||||
}
|
}
|
||||||
@@ -122,3 +123,28 @@ func (h *Headscale) marshalMapResponse(
|
|||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func zstdEncode(in []byte) []byte {
|
||||||
|
encoder, ok := zstdEncoderPool.Get().(*zstd.Encoder)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid type in sync pool")
|
||||||
|
}
|
||||||
|
out := encoder.EncodeAll(in, nil)
|
||||||
|
_ = encoder.Close()
|
||||||
|
zstdEncoderPool.Put(encoder)
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
var zstdEncoderPool = &sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
encoder, err := smallzstd.NewEncoder(
|
||||||
|
nil,
|
||||||
|
zstd.WithEncoderLevel(zstd.SpeedFastest))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@@ -90,7 +90,14 @@ func (h *Headscale) EnableRoute(id uint64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return h.EnableRoutes(&route.Machine, netip.Prefix(route.Prefix).String())
|
// Tailscale requires both IPv4 and IPv6 exit routes to
|
||||||
|
// be enabled at the same time, as per
|
||||||
|
// https://github.com/juanfont/headscale/issues/804#issuecomment-1399314002
|
||||||
|
if route.isExitRoute() {
|
||||||
|
return h.enableRoutes(&route.Machine, ExitRouteV4.String(), ExitRouteV6.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.enableRoutes(&route.Machine, netip.Prefix(route.Prefix).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) DisableRoute(id uint64) error {
|
func (h *Headscale) DisableRoute(id uint64) error {
|
||||||
|
@@ -46,10 +46,10 @@ func (s *Suite) TestGetRoutes(c *check.C) {
|
|||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(advertisedRoutes), check.Equals, 1)
|
c.Assert(len(advertisedRoutes), check.Equals, 1)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine, "192.168.0.0/24")
|
err = app.enableRoutes(&machine, "192.168.0.0/24")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine, "10.0.0.0/24")
|
err = app.enableRoutes(&machine, "10.0.0.0/24")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,10 +102,10 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
|
|||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(noEnabledRoutes), check.Equals, 0)
|
c.Assert(len(noEnabledRoutes), check.Equals, 0)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine, "192.168.0.0/24")
|
err = app.enableRoutes(&machine, "192.168.0.0/24")
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine, "10.0.0.0/24")
|
err = app.enableRoutes(&machine, "10.0.0.0/24")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes, err := app.GetEnabledRoutes(&machine)
|
enabledRoutes, err := app.GetEnabledRoutes(&machine)
|
||||||
@@ -113,14 +113,14 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
|
|||||||
c.Assert(len(enabledRoutes), check.Equals, 1)
|
c.Assert(len(enabledRoutes), check.Equals, 1)
|
||||||
|
|
||||||
// Adding it twice will just let it pass through
|
// Adding it twice will just let it pass through
|
||||||
err = app.EnableRoutes(&machine, "10.0.0.0/24")
|
err = app.enableRoutes(&machine, "10.0.0.0/24")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enableRoutesAfterDoubleApply, err := app.GetEnabledRoutes(&machine)
|
enableRoutesAfterDoubleApply, err := app.GetEnabledRoutes(&machine)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(enableRoutesAfterDoubleApply), check.Equals, 1)
|
c.Assert(len(enableRoutesAfterDoubleApply), check.Equals, 1)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine, "150.0.10.0/25")
|
err = app.enableRoutes(&machine, "150.0.10.0/25")
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutesWithAdditionalRoute, err := app.GetEnabledRoutes(&machine)
|
enabledRoutesWithAdditionalRoute, err := app.GetEnabledRoutes(&machine)
|
||||||
@@ -167,10 +167,10 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
|
|||||||
err = app.processMachineRoutes(&machine1)
|
err = app.processMachineRoutes(&machine1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, route.String())
|
err = app.enableRoutes(&machine1, route.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, route2.String())
|
err = app.enableRoutes(&machine1, route2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
hostInfo2 := tailcfg.Hostinfo{
|
hostInfo2 := tailcfg.Hostinfo{
|
||||||
@@ -192,7 +192,7 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
|
|||||||
err = app.processMachineRoutes(&machine2)
|
err = app.processMachineRoutes(&machine2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine2, route2.String())
|
err = app.enableRoutes(&machine2, route2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
enabledRoutes1, err := app.GetEnabledRoutes(&machine1)
|
enabledRoutes1, err := app.GetEnabledRoutes(&machine1)
|
||||||
@@ -254,10 +254,10 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
|
|||||||
err = app.processMachineRoutes(&machine1)
|
err = app.processMachineRoutes(&machine1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, prefix.String())
|
err = app.enableRoutes(&machine1, prefix.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, prefix2.String())
|
err = app.enableRoutes(&machine1, prefix2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.handlePrimarySubnetFailover()
|
err = app.handlePrimarySubnetFailover()
|
||||||
@@ -291,7 +291,7 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
|
|||||||
err = app.processMachineRoutes(&machine2)
|
err = app.processMachineRoutes(&machine2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine2, prefix2.String())
|
err = app.enableRoutes(&machine2, prefix2.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.handlePrimarySubnetFailover()
|
err = app.handlePrimarySubnetFailover()
|
||||||
@@ -339,7 +339,7 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
|
|||||||
err = app.processMachineRoutes(&machine2)
|
err = app.processMachineRoutes(&machine2)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine2, prefix.String())
|
err = app.enableRoutes(&machine2, prefix.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.handlePrimarySubnetFailover()
|
err = app.handlePrimarySubnetFailover()
|
||||||
@@ -413,18 +413,24 @@ func (s *Suite) TestAllowedIPRoutes(c *check.C) {
|
|||||||
err = app.processMachineRoutes(&machine1)
|
err = app.processMachineRoutes(&machine1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, prefix.String())
|
err = app.enableRoutes(&machine1, prefix.String())
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
// We do not enable this one on purpose to test that it is not enabled
|
// We do not enable this one on purpose to test that it is not enabled
|
||||||
// err = app.EnableRoutes(&machine1, prefix2.String())
|
// err = app.enableRoutes(&machine1, prefix2.String())
|
||||||
// c.Assert(err, check.IsNil)
|
// c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, prefixExitNodeV4.String())
|
routes, err := app.GetMachineRoutes(&machine1)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
for _, route := range routes {
|
||||||
|
if route.isExitRoute() {
|
||||||
|
err = app.EnableRoute(uint64(route.ID))
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = app.EnableRoutes(&machine1, prefixExitNodeV6.String())
|
// We only enable one exit route, so we can test that both are enabled
|
||||||
c.Assert(err, check.IsNil)
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = app.handlePrimarySubnetFailover()
|
err = app.handlePrimarySubnetFailover()
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
Reference in New Issue
Block a user