Compare commits

..

3 Commits

Author SHA1 Message Date
Juan Font f90ebb8567 Update config.go 2023-05-10 12:16:07 +02:00
Juan Font 7564c4548c Fix socket location in config.go 2023-05-10 12:16:07 +02:00
Juan Font 5f80d1b155 Revert "Revert unix_socket to default value"
This reverts commit ca54fb9f56.
2023-05-10 12:16:07 +02:00
138 changed files with 3100 additions and 1663 deletions
@@ -0,0 +1,35 @@
name: Integration Test CLI
on: [pull_request]
jobs:
integration-test-cli:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Set Swap Space
uses: pierotofy/set-swap-space@master
with:
swap-size-gb: 10
- 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 CLI integration tests
if: steps.changed-files.outputs.any_changed == 'true'
run: nix develop --command -- make test_integration_cli
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
@@ -43,7 +43,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
+1 -16
View File
@@ -2,20 +2,6 @@
## 0.23.0 (2023-XX-XX)
### BREAKING
- Code reorganisation, a lot of code has moved, please review the following PRs accordingly [#1444](https://github.com/juanfont/headscale/pull/1444)
### Changes
## 0.22.3 (2023-05-12)
### Changes
- Added missing ca-certificates in Docker image [#1463](https://github.com/juanfont/headscale/pull/1463)
## 0.22.2 (2023-05-10)
### Changes
- Add environment flags to enable pprof (profiling) [#1382](https://github.com/juanfont/headscale/pull/1382)
@@ -23,14 +9,13 @@
- Fix systemd service file location in `.deb` packages [#1391](https://github.com/juanfont/headscale/pull/1391)
- Improvements on Noise implementation [#1379](https://github.com/juanfont/headscale/pull/1379)
- Replace node filter logic, ensuring nodes with access can see eachother [#1381](https://github.com/juanfont/headscale/pull/1381)
- Disable (or delete) both exit routes at the same time [#1428](https://github.com/juanfont/headscale/pull/1428)
- Ditch distroless for Docker image, create default socket dir in `/var/run/headscale` [#1450](https://github.com/juanfont/headscale/pull/1450)
## 0.22.1 (2023-04-20)
### Changes
- Fix issue where systemd could not bind to port 80 [#1365](https://github.com/juanfont/headscale/pull/1365)
- Disable (or delete) both exit routes at the same time [#1428](https://github.com/juanfont/headscale/pull/1428)
## 0.22.0 (2023-04-20)
+1 -8
View File
@@ -14,17 +14,10 @@ RUN strip /go/bin/headscale
RUN test -e /go/bin/headscale
# Production image
FROM docker.io/debian:bullseye-slim
RUN apt-get update \
&& apt-get install -y ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
FROM gcr.io/distroless/base-debian11
COPY --from=build /go/bin/headscale /bin/headscale
ENV TZ UTC
RUN mkdir -p /var/run/headscale
EXPOSE 8080/tcp
CMD ["headscale"]
-2
View File
@@ -18,8 +18,6 @@ FROM docker.io/golang:1.20.0-bullseye
COPY --from=build /go/bin/headscale /bin/headscale
ENV TZ UTC
RUN mkdir -p /var/run/headscale
# Need to reset the entrypoint or everything will run as a busybox script
ENTRYPOINT []
EXPOSE 8080/tcp
+14 -2
View File
@@ -24,9 +24,21 @@ build:
dev: lint test build
test:
gotestsum -- $(TAGS) -short -coverprofile=coverage.out ./...
@go test $(TAGS) -short -coverprofile=coverage.out ./...
test_integration:
test_integration: test_integration_cli test_integration_derp test_integration_v2_general
test_integration_cli:
docker network rm $$(docker network ls --filter name=headscale --quiet) || true
docker network create headscale-test || true
docker run -t --rm \
--network headscale-test \
-v ~/.cache/hs-integration-go:/go \
-v $$PWD:$$PWD -w $$PWD \
-v /var/run/docker.sock:/var/run/docker.sock golang:1 \
go run gotest.tools/gotestsum@latest -- $(TAGS) -failfast -timeout 30m -count=1 -run IntegrationCLI ./...
test_integration_v2_general:
docker run \
-t --rm \
-v ~/.cache/hs-integration-go:/go \
+9
View File
@@ -80,6 +80,15 @@ and container to run Headscale.**
Please have a look at the [`documentation`](https://headscale.net/).
## Graphical Control Panels
Headscale provides an API for complete management of your Tailnet.
These are community projects not directly affiliated with the Headscale project.
| Name | Repository Link | Description | Status |
| --------------- | ---------------------------------------------------- | ------------------------------------------------------ | ------ |
| headscale-webui | [Github](https://github.com/ifargle/headscale-webui) | A simple Headscale web UI for small-scale deployments. | Alpha |
## Talks
- Fosdem 2023 (video): [Headscale: How we are using integration testing to reimplement Tailscale](https://fosdem.org/2023/schedule/event/goheadscale/)
+16 -21
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"encoding/json"
@@ -59,8 +59,8 @@ const (
var featureEnableSSH = envknob.RegisterBool("HEADSCALE_EXPERIMENTAL_FEATURE_SSH")
// LoadACLPolicyFromPath loads the ACL policy from the specify path, and generates the ACL rules.
func (h *Headscale) LoadACLPolicyFromPath(path string) error {
// LoadACLPolicy loads the ACL policy from the specify path, and generates the ACL rules.
func (h *Headscale) LoadACLPolicy(path string) error {
log.Debug().
Str("func", "LoadACLPolicy").
Str("path", path).
@@ -72,42 +72,37 @@ func (h *Headscale) LoadACLPolicyFromPath(path string) error {
}
defer policyFile.Close()
var policy ACLPolicy
policyBytes, err := io.ReadAll(policyFile)
if err != nil {
return err
}
log.Debug().
Str("path", path).
Bytes("file", policyBytes).
Msg("Loading ACLs")
switch filepath.Ext(path) {
case ".yml", ".yaml":
return h.LoadACLPolicyFromBytes(policyBytes, "yaml")
}
log.Debug().
Str("path", path).
Bytes("file", policyBytes).
Msg("Loading ACLs from YAML")
return h.LoadACLPolicyFromBytes(policyBytes, "hujson")
}
func (h *Headscale) LoadACLPolicyFromBytes(acl []byte, format string) error {
var policy ACLPolicy
switch format {
case "yaml":
err := yaml.Unmarshal(acl, &policy)
err := yaml.Unmarshal(policyBytes, &policy)
if err != nil {
return err
}
log.Trace().
Interface("policy", policy).
Msg("Loaded policy from YAML")
default:
ast, err := hujson.Parse(acl)
ast, err := hujson.Parse(policyBytes)
if err != nil {
return err
}
ast.Standardize()
acl = ast.Pack()
err = json.Unmarshal(acl, &policy)
policyBytes = ast.Pack()
err = json.Unmarshal(policyBytes, &policy)
if err != nil {
return err
}
+14 -309
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"errors"
@@ -15,26 +15,17 @@ import (
)
func (s *Suite) TestWrongPath(c *check.C) {
err := app.LoadACLPolicyFromPath("asdfg")
err := app.LoadACLPolicy("asdfg")
c.Assert(err, check.NotNil)
}
func (s *Suite) TestBrokenHuJson(c *check.C) {
acl := []byte(`
{
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/broken.hujson")
c.Assert(err, check.NotNil)
}
func (s *Suite) TestInvalidPolicyHuson(c *check.C) {
acl := []byte(`
{
"valid_json": true,
"but_a_policy_though": false
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/invalid.hujson")
c.Assert(err, check.NotNil)
c.Assert(err, check.Equals, errEmptyPolicy)
}
@@ -58,161 +49,12 @@ func (s *Suite) TestParseInvalidCIDR(c *check.C) {
}
func (s *Suite) TestRuleInvalidGeneration(c *check.C) {
acl := []byte(`
{
// Declare static groups of users beyond those in the identity service.
"groups": {
"group:example": [
"user1@example.com",
"user2@example.com",
],
},
// Declare hostname aliases to use in place of IP addresses or subnets.
"hosts": {
"example-host-1": "100.100.100.100",
"example-host-2": "100.100.101.100/24",
},
// Define who is allowed to use which tags.
"tagOwners": {
// Everyone in the montreal-admins or global-admins group are
// allowed to tag servers as montreal-webserver.
"tag:montreal-webserver": [
"group:montreal-admins",
"group:global-admins",
],
// Only a few admins are allowed to create API servers.
"tag:api-server": [
"group:global-admins",
"example-host-1",
],
},
// Access control lists.
"acls": [
// Engineering users, plus the president, can access port 22 (ssh)
// and port 3389 (remote desktop protocol) on all servers, and all
// ports on git-server or ci-server.
{
"action": "accept",
"src": [
"group:engineering",
"president@example.com"
],
"dst": [
"*:22,3389",
"git-server:*",
"ci-server:*"
],
},
// Allow engineer users to access any port on a device tagged with
// tag:production.
{
"action": "accept",
"src": [
"group:engineers"
],
"dst": [
"tag:production:*"
],
},
// Allow servers in the my-subnet host and 192.168.1.0/24 to access hosts
// on both networks.
{
"action": "accept",
"src": [
"my-subnet",
"192.168.1.0/24"
],
"dst": [
"my-subnet:*",
"192.168.1.0/24:*"
],
},
// Allow every user of your network to access anything on the network.
// Comment out this section if you want to define specific ACL
// restrictions above.
{
"action": "accept",
"src": [
"*"
],
"dst": [
"*:*"
],
},
// All users in Montreal are allowed to access the Montreal web
// servers.
{
"action": "accept",
"src": [
"group:montreal-users"
],
"dst": [
"tag:montreal-webserver:80,443"
],
},
// Montreal web servers are allowed to make outgoing connections to
// the API servers, but only on https port 443.
// In contrast, this doesn't grant API servers the right to initiate
// any connections.
{
"action": "accept",
"src": [
"tag:montreal-webserver"
],
"dst": [
"tag:api-server:443"
],
},
],
// Declare tests to check functionality of ACL rules
"tests": [
{
"src": "user1@example.com",
"accept": [
"example-host-1:22",
"example-host-2:80"
],
"deny": [
"exapmle-host-2:100"
],
},
{
"src": "user2@example.com",
"accept": [
"100.60.3.4:22"
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/acl_policy_invalid.hujson")
c.Assert(err, check.NotNil)
}
func (s *Suite) TestBasicRule(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"subnet-1",
"192.168.1.0/24"
],
"dst": [
"*:22,3389",
"host-1:*",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_1.hujson")
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
@@ -569,27 +411,7 @@ func (s *Suite) TestValidTagInvalidUser(c *check.C) {
}
func (s *Suite) TestPortRange(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"subnet-1",
],
"dst": [
"host-1:5400-5500",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_range.hujson")
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
@@ -603,48 +425,7 @@ func (s *Suite) TestPortRange(c *check.C) {
}
func (s *Suite) TestProtocolParsing(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"Action": "accept",
"src": [
"*",
],
"proto": "tcp",
"dst": [
"host-1:*",
],
},
{
"Action": "accept",
"src": [
"*",
],
"proto": "udp",
"dst": [
"host-1:53",
],
},
{
"Action": "accept",
"src": [
"*",
],
"proto": "icmp",
"dst": [
"host-1:*",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_protocols.hujson")
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
@@ -658,27 +439,7 @@ func (s *Suite) TestProtocolParsing(c *check.C) {
}
func (s *Suite) TestPortWildcard(c *check.C) {
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"Action": "accept",
"src": [
"*",
],
"dst": [
"host-1:*",
],
},
],
}
`)
err := app.LoadACLPolicyFromBytes(acl, "hujson")
err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_wildcards.hujson")
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
@@ -694,19 +455,7 @@ func (s *Suite) TestPortWildcard(c *check.C) {
}
func (s *Suite) TestPortWildcardYAML(c *check.C) {
acl := []byte(`
---
hosts:
host-1: 100.100.100.100/32
subnet-1: 100.100.101.100/24
acls:
- action: accept
src:
- "*"
dst:
- host-1:*
`)
err := app.LoadACLPolicyFromBytes(acl, "yaml")
err := app.LoadACLPolicy("./tests/acls/acl_policy_basic_wildcards.yaml")
c.Assert(err, check.IsNil)
rules, err := app.aclPolicy.generateFilterRules([]Machine{}, false)
@@ -744,27 +493,9 @@ func (s *Suite) TestPortUser(c *check.C) {
}
app.db.Save(&machine)
acl := []byte(`
{
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"testuser",
],
"dst": [
"host-1:*",
],
},
],
}
`)
err = app.LoadACLPolicyFromBytes(acl, "hujson")
err = app.LoadACLPolicy(
"./tests/acls/acl_policy_basic_user_as_user.hujson",
)
c.Assert(err, check.IsNil)
machines, err := app.ListMachines()
@@ -807,33 +538,7 @@ func (s *Suite) TestPortGroup(c *check.C) {
}
app.db.Save(&machine)
acl := []byte(`
{
"groups": {
"group:example": [
"testuser",
],
},
"hosts": {
"host-1": "100.100.100.100",
"subnet-1": "100.100.101.100/24",
},
"acls": [
{
"action": "accept",
"src": [
"group:example",
],
"dst": [
"host-1:*",
],
},
],
}
`)
err = app.LoadACLPolicyFromBytes(acl, "hujson")
err = app.LoadACLPolicy("./tests/acls/acl_policy_basic_groups.hujson")
c.Assert(err, check.IsNil)
machines, err := app.ListMachines()
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"encoding/json"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"bytes"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"time"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"fmt"
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"time"
+4 -7
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"context"
@@ -21,7 +21,6 @@ import (
"github.com/gorilla/mux"
grpcMiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/patrickmn/go-cache"
zerolog "github.com/philip-bui/grpc-zerolog"
@@ -508,10 +507,8 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router {
router.HandleFunc("/windows", h.WindowsConfigMessage).Methods(http.MethodGet)
router.HandleFunc("/windows/tailscale.reg", h.WindowsRegConfig).
Methods(http.MethodGet)
// TODO(kristoffer): move swagger into a package
router.HandleFunc("/swagger", headscale.SwaggerUI).Methods(http.MethodGet)
router.HandleFunc("/swagger/v1/openapiv2.json", headscale.SwaggerAPIv1).
router.HandleFunc("/swagger", SwaggerUI).Methods(http.MethodGet)
router.HandleFunc("/swagger/v1/openapiv2.json", SwaggerAPIv1).
Methods(http.MethodGet)
if h.cfg.DERP.ServerEnabled {
@@ -761,7 +758,7 @@ func (h *Headscale) Serve() error {
if h.cfg.ACL.PolicyPath != "" {
aclPath := AbsolutePathFromConfigPath(h.cfg.ACL.PolicyPath)
err := h.LoadACLPolicyFromPath(aclPath)
err := h.LoadACLPolicy(aclPath)
if err != nil {
log.Error().Err(err).Msg("Failed to reload ACL policy")
}
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"net/netip"
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume $PWD/control_logs:/tmp/control \
golang:1 \
go run gotest.tools/gotestsum@latest -- ./... \
go test ./... \
-tags ts2019 \
-failfast \
-timeout 120m \
+2 -2
View File
@@ -5,8 +5,8 @@ import (
"strconv"
"time"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/prometheus/common/model"
"github.com/pterm/pterm"
"github.com/rs/zerolog/log"
@@ -83,7 +83,7 @@ var listAPIKeys = &cobra.Command{
}
tableData = append(tableData, []string{
strconv.FormatUint(key.GetId(), hscontrol.Base10),
strconv.FormatUint(key.GetId(), headscale.Base10),
key.GetPrefix(),
expiration,
key.GetCreatedAt().AsTime().Format(HeadscaleDateTimeFormat),
+2 -2
View File
@@ -3,8 +3,8 @@ package cli
import (
"fmt"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"google.golang.org/grpc/status"
@@ -93,7 +93,7 @@ var createNodeCmd = &cobra.Command{
return
}
if !hscontrol.NodePublicKeyRegex.Match([]byte(machineKey)) {
if !headscale.NodePublicKeyRegex.Match([]byte(machineKey)) {
err = errPreAuthKeyMalformed
ErrorOutput(
err,
+4 -4
View File
@@ -9,8 +9,8 @@ import (
"time"
survey "github.com/AlecAivazis/survey/v2"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"google.golang.org/grpc/status"
@@ -529,7 +529,7 @@ func nodesToPtables(
var machineKey key.MachinePublic
err := machineKey.UnmarshalText(
[]byte(hscontrol.MachinePublicKeyEnsurePrefix(machine.MachineKey)),
[]byte(headscale.MachinePublicKeyEnsurePrefix(machine.MachineKey)),
)
if err != nil {
machineKey = key.MachinePublic{}
@@ -537,7 +537,7 @@ func nodesToPtables(
var nodeKey key.NodePublic
err = nodeKey.UnmarshalText(
[]byte(hscontrol.NodePublicKeyEnsurePrefix(machine.NodeKey)),
[]byte(headscale.NodePublicKeyEnsurePrefix(machine.NodeKey)),
)
if err != nil {
return nil, err
@@ -596,7 +596,7 @@ func nodesToPtables(
}
nodeData := []string{
strconv.FormatUint(machine.Id, hscontrol.Base10),
strconv.FormatUint(machine.Id, headscale.Base10),
machine.Name,
machine.GetGivenName(),
machineKey.ShortString(),
+5 -5
View File
@@ -5,7 +5,7 @@ import (
"os"
"runtime"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
@@ -38,18 +38,18 @@ func initConfig() {
cfgFile = os.Getenv("HEADSCALE_CONFIG")
}
if cfgFile != "" {
err := hscontrol.LoadConfig(cfgFile, true)
err := headscale.LoadConfig(cfgFile, true)
if err != nil {
log.Fatal().Caller().Err(err).Msgf("Error loading config file %s", cfgFile)
}
} else {
err := hscontrol.LoadConfig("", false)
err := headscale.LoadConfig("", false)
if err != nil {
log.Fatal().Caller().Err(err).Msgf("Error loading config")
}
}
cfg, err := hscontrol.GetHeadscaleConfig()
cfg, err := headscale.GetHeadscaleConfig()
if err != nil {
log.Fatal().Caller().Err(err)
}
@@ -64,7 +64,7 @@ func initConfig() {
zerolog.SetGlobalLevel(zerolog.Disabled)
}
if cfg.Log.Format == hscontrol.JSONLogFormat {
if cfg.Log.Format == headscale.JSONLogFormat {
log.Logger = log.Output(os.Stdout)
}
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"net/netip"
"strconv"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"google.golang.org/grpc/status"
@@ -277,7 +277,7 @@ func routesToPtables(routes []*v1.Route) pterm.TableData {
continue
}
if prefix == hscontrol.ExitRouteV4 || prefix == hscontrol.ExitRouteV6 {
if prefix == headscale.ExitRouteV4 || prefix == headscale.ExitRouteV6 {
isPrimaryStr = "-"
} else {
isPrimaryStr = strconv.FormatBool(route.IsPrimary)
+2 -2
View File
@@ -4,8 +4,8 @@ import (
"fmt"
survey "github.com/AlecAivazis/survey/v2"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/pterm/pterm"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
@@ -21,7 +21,7 @@ func init() {
}
const (
errMissingParameter = hscontrol.Error("missing parameters")
errMissingParameter = headscale.Error("missing parameters")
)
var userCmd = &cobra.Command{
+9 -9
View File
@@ -8,8 +8,8 @@ import (
"os"
"reflect"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/rs/zerolog/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@@ -22,8 +22,8 @@ const (
SocketWritePermissions = 0o666
)
func getHeadscaleApp() (*hscontrol.Headscale, error) {
cfg, err := hscontrol.GetHeadscaleConfig()
func getHeadscaleApp() (*headscale.Headscale, error) {
cfg, err := headscale.GetHeadscaleConfig()
if err != nil {
return nil, fmt.Errorf(
"failed to load configuration while creating headscale instance: %w",
@@ -31,7 +31,7 @@ func getHeadscaleApp() (*hscontrol.Headscale, error) {
)
}
app, err := hscontrol.NewHeadscale(cfg)
app, err := headscale.NewHeadscale(cfg)
if err != nil {
return nil, err
}
@@ -39,8 +39,8 @@ func getHeadscaleApp() (*hscontrol.Headscale, error) {
// We are doing this here, as in the future could be cool to have it also hot-reload
if cfg.ACL.PolicyPath != "" {
aclPath := hscontrol.AbsolutePathFromConfigPath(cfg.ACL.PolicyPath)
err = app.LoadACLPolicyFromPath(aclPath)
aclPath := headscale.AbsolutePathFromConfigPath(cfg.ACL.PolicyPath)
err = app.LoadACLPolicy(aclPath)
if err != nil {
log.Fatal().
Str("path", aclPath).
@@ -53,7 +53,7 @@ func getHeadscaleApp() (*hscontrol.Headscale, error) {
}
func getHeadscaleCLIClient() (context.Context, v1.HeadscaleServiceClient, *grpc.ClientConn, context.CancelFunc) {
cfg, err := hscontrol.GetHeadscaleConfig()
cfg, err := headscale.GetHeadscaleConfig()
if err != nil {
log.Fatal().
Err(err).
@@ -74,7 +74,7 @@ func getHeadscaleCLIClient() (context.Context, v1.HeadscaleServiceClient, *grpc.
address := cfg.CLI.Address
// If the address is not set, we assume that we are on the server hosting hscontrol.
// If the address is not set, we assume that we are on the server hosting headscale.
if address == "" {
log.Debug().
Str("socket", cfg.UnixSocket).
@@ -98,7 +98,7 @@ func getHeadscaleCLIClient() (context.Context, v1.HeadscaleServiceClient, *grpc.
grpcOptions = append(
grpcOptions,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(hscontrol.GrpcSocketDialer),
grpc.WithContextDialer(headscale.GrpcSocketDialer),
)
} else {
// If we are not connecting to a local server, require an API key for authentication
+9 -9
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/spf13/viper"
"gopkg.in/check.v1"
)
@@ -50,7 +50,7 @@ func (*Suite) TestConfigFileLoading(c *check.C) {
}
// Load example config, it should load without validation errors
err = hscontrol.LoadConfig(cfgFile, true)
err = headscale.LoadConfig(cfgFile, true)
c.Assert(err, check.IsNil)
// Test that config file was interpreted correctly
@@ -64,7 +64,7 @@ func (*Suite) TestConfigFileLoading(c *check.C) {
c.Assert(viper.GetString("tls_letsencrypt_challenge_type"), check.Equals, "HTTP-01")
c.Assert(viper.GetStringSlice("dns_config.nameservers")[0], check.Equals, "1.1.1.1")
c.Assert(
hscontrol.GetFileMode("unix_socket_permission"),
headscale.GetFileMode("unix_socket_permission"),
check.Equals,
fs.FileMode(0o770),
)
@@ -93,7 +93,7 @@ func (*Suite) TestConfigLoading(c *check.C) {
}
// Load example config, it should load without validation errors
err = hscontrol.LoadConfig(tmpDir, false)
err = headscale.LoadConfig(tmpDir, false)
c.Assert(err, check.IsNil)
// Test that config file was interpreted correctly
@@ -107,7 +107,7 @@ func (*Suite) TestConfigLoading(c *check.C) {
c.Assert(viper.GetString("tls_letsencrypt_challenge_type"), check.Equals, "HTTP-01")
c.Assert(viper.GetStringSlice("dns_config.nameservers")[0], check.Equals, "1.1.1.1")
c.Assert(
hscontrol.GetFileMode("unix_socket_permission"),
headscale.GetFileMode("unix_socket_permission"),
check.Equals,
fs.FileMode(0o770),
)
@@ -137,10 +137,10 @@ func (*Suite) TestDNSConfigLoading(c *check.C) {
}
// Load example config, it should load without validation errors
err = hscontrol.LoadConfig(tmpDir, false)
err = headscale.LoadConfig(tmpDir, false)
c.Assert(err, check.IsNil)
dnsConfig, baseDomain := hscontrol.GetDNSConfig()
dnsConfig, baseDomain := headscale.GetDNSConfig()
c.Assert(dnsConfig.Nameservers[0].String(), check.Equals, "1.1.1.1")
c.Assert(dnsConfig.Resolvers[0].Addr, check.Equals, "1.1.1.1")
@@ -172,7 +172,7 @@ noise:
writeConfig(c, tmpDir, configYaml)
// Check configuration validation errors (1)
err = hscontrol.LoadConfig(tmpDir, false)
err = headscale.LoadConfig(tmpDir, false)
c.Assert(err, check.NotNil)
// check.Matches can not handle multiline strings
tmp := strings.ReplaceAll(err.Error(), "\n", "***")
@@ -201,6 +201,6 @@ tls_letsencrypt_hostname: example.com
tls_letsencrypt_challenge_type: TLS-ALPN-01
`)
writeConfig(c, tmpDir, configYaml)
err = hscontrol.LoadConfig(tmpDir, false)
err = headscale.LoadConfig(tmpDir, false)
c.Assert(err, check.IsNil)
}
+2 -2
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"errors"
@@ -175,7 +175,7 @@ func LoadConfig(path string, isFile bool) error {
viper.SetDefault("derp.server.enabled", false)
viper.SetDefault("derp.server.stun.enabled", true)
viper.SetDefault("unix_socket", "/var/run/headscale/headscale.sock")
viper.SetDefault("unix_socket", "/var/run/headscale.sock")
viper.SetDefault("unix_socket_permission", "0o770")
viper.SetDefault("grpc_listen_addr", ":50443")
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"context"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"context"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"context"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"fmt"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import (
"fmt"
-14
View File
@@ -1,14 +0,0 @@
# Headscale web interface
!!! warning "Community contributions"
This page contains community contributions. The projects listed here are not
maintained by the Headscale authors and are written by community members.
| Name | Repository Link | Description | Status |
| --------------- | ------------------------------------------------------- | ------------------------------------------------------------------------- | ------ |
| headscale-webui | [Github](https://github.com/ifargle/headscale-webui) | A simple Headscale web UI for small-scale deployments. | Alpha |
| headscale-ui | [Github](https://github.com/gurucomputing/headscale-ui) | A web frontend for the headscale Tailscale-compatible coordination server | Alpha |
| HeadscaleUi | [GitHub](https://github.com/simcu/headscale-ui) | A static headscale admin ui, no backend enviroment required | Alpha |
You can ask for support on our dedicated [Discord channel](https://discord.com/channels/896711691637780480/1105842846386356294).
+1 -1
View File
@@ -36,7 +36,7 @@
# 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.
vendorSha256 = "sha256-IOkbbFtE6+tNKnglE/8ZuNxhPSnloqM2sLgTvagMmnc=";
vendorSha256 = "sha256-cmDNYWYTgQp6CPgpL4d3TbkpAe7rhNAF+o8njJsgL7E=";
ldflags = [ "-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}" ];
};
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/apikey.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/device.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/headscale.proto
+51 -79
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc-gen-go-grpc v1.2.0
// - protoc (unknown)
// source: headscale/v1/headscale.proto
@@ -18,34 +18,6 @@ import (
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
HeadscaleService_GetUser_FullMethodName = "/headscale.v1.HeadscaleService/GetUser"
HeadscaleService_CreateUser_FullMethodName = "/headscale.v1.HeadscaleService/CreateUser"
HeadscaleService_RenameUser_FullMethodName = "/headscale.v1.HeadscaleService/RenameUser"
HeadscaleService_DeleteUser_FullMethodName = "/headscale.v1.HeadscaleService/DeleteUser"
HeadscaleService_ListUsers_FullMethodName = "/headscale.v1.HeadscaleService/ListUsers"
HeadscaleService_CreatePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/CreatePreAuthKey"
HeadscaleService_ExpirePreAuthKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpirePreAuthKey"
HeadscaleService_ListPreAuthKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListPreAuthKeys"
HeadscaleService_DebugCreateMachine_FullMethodName = "/headscale.v1.HeadscaleService/DebugCreateMachine"
HeadscaleService_GetMachine_FullMethodName = "/headscale.v1.HeadscaleService/GetMachine"
HeadscaleService_SetTags_FullMethodName = "/headscale.v1.HeadscaleService/SetTags"
HeadscaleService_RegisterMachine_FullMethodName = "/headscale.v1.HeadscaleService/RegisterMachine"
HeadscaleService_DeleteMachine_FullMethodName = "/headscale.v1.HeadscaleService/DeleteMachine"
HeadscaleService_ExpireMachine_FullMethodName = "/headscale.v1.HeadscaleService/ExpireMachine"
HeadscaleService_RenameMachine_FullMethodName = "/headscale.v1.HeadscaleService/RenameMachine"
HeadscaleService_ListMachines_FullMethodName = "/headscale.v1.HeadscaleService/ListMachines"
HeadscaleService_MoveMachine_FullMethodName = "/headscale.v1.HeadscaleService/MoveMachine"
HeadscaleService_GetRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetRoutes"
HeadscaleService_EnableRoute_FullMethodName = "/headscale.v1.HeadscaleService/EnableRoute"
HeadscaleService_DisableRoute_FullMethodName = "/headscale.v1.HeadscaleService/DisableRoute"
HeadscaleService_GetMachineRoutes_FullMethodName = "/headscale.v1.HeadscaleService/GetMachineRoutes"
HeadscaleService_DeleteRoute_FullMethodName = "/headscale.v1.HeadscaleService/DeleteRoute"
HeadscaleService_CreateApiKey_FullMethodName = "/headscale.v1.HeadscaleService/CreateApiKey"
HeadscaleService_ExpireApiKey_FullMethodName = "/headscale.v1.HeadscaleService/ExpireApiKey"
HeadscaleService_ListApiKeys_FullMethodName = "/headscale.v1.HeadscaleService/ListApiKeys"
)
// HeadscaleServiceClient is the client API for HeadscaleService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -92,7 +64,7 @@ func NewHeadscaleServiceClient(cc grpc.ClientConnInterface) HeadscaleServiceClie
func (c *headscaleServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) {
out := new(GetUserResponse)
err := c.cc.Invoke(ctx, HeadscaleService_GetUser_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetUser", in, out, opts...)
if err != nil {
return nil, err
}
@@ -101,7 +73,7 @@ func (c *headscaleServiceClient) GetUser(ctx context.Context, in *GetUserRequest
func (c *headscaleServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) {
out := new(CreateUserResponse)
err := c.cc.Invoke(ctx, HeadscaleService_CreateUser_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/CreateUser", in, out, opts...)
if err != nil {
return nil, err
}
@@ -110,7 +82,7 @@ func (c *headscaleServiceClient) CreateUser(ctx context.Context, in *CreateUserR
func (c *headscaleServiceClient) RenameUser(ctx context.Context, in *RenameUserRequest, opts ...grpc.CallOption) (*RenameUserResponse, error) {
out := new(RenameUserResponse)
err := c.cc.Invoke(ctx, HeadscaleService_RenameUser_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/RenameUser", in, out, opts...)
if err != nil {
return nil, err
}
@@ -119,7 +91,7 @@ func (c *headscaleServiceClient) RenameUser(ctx context.Context, in *RenameUserR
func (c *headscaleServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) {
out := new(DeleteUserResponse)
err := c.cc.Invoke(ctx, HeadscaleService_DeleteUser_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/DeleteUser", in, out, opts...)
if err != nil {
return nil, err
}
@@ -128,7 +100,7 @@ func (c *headscaleServiceClient) DeleteUser(ctx context.Context, in *DeleteUserR
func (c *headscaleServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) {
out := new(ListUsersResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ListUsers_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ListUsers", in, out, opts...)
if err != nil {
return nil, err
}
@@ -137,7 +109,7 @@ func (c *headscaleServiceClient) ListUsers(ctx context.Context, in *ListUsersReq
func (c *headscaleServiceClient) CreatePreAuthKey(ctx context.Context, in *CreatePreAuthKeyRequest, opts ...grpc.CallOption) (*CreatePreAuthKeyResponse, error) {
out := new(CreatePreAuthKeyResponse)
err := c.cc.Invoke(ctx, HeadscaleService_CreatePreAuthKey_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/CreatePreAuthKey", in, out, opts...)
if err != nil {
return nil, err
}
@@ -146,7 +118,7 @@ func (c *headscaleServiceClient) CreatePreAuthKey(ctx context.Context, in *Creat
func (c *headscaleServiceClient) ExpirePreAuthKey(ctx context.Context, in *ExpirePreAuthKeyRequest, opts ...grpc.CallOption) (*ExpirePreAuthKeyResponse, error) {
out := new(ExpirePreAuthKeyResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ExpirePreAuthKey_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ExpirePreAuthKey", in, out, opts...)
if err != nil {
return nil, err
}
@@ -155,7 +127,7 @@ func (c *headscaleServiceClient) ExpirePreAuthKey(ctx context.Context, in *Expir
func (c *headscaleServiceClient) ListPreAuthKeys(ctx context.Context, in *ListPreAuthKeysRequest, opts ...grpc.CallOption) (*ListPreAuthKeysResponse, error) {
out := new(ListPreAuthKeysResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ListPreAuthKeys_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ListPreAuthKeys", in, out, opts...)
if err != nil {
return nil, err
}
@@ -164,7 +136,7 @@ func (c *headscaleServiceClient) ListPreAuthKeys(ctx context.Context, in *ListPr
func (c *headscaleServiceClient) DebugCreateMachine(ctx context.Context, in *DebugCreateMachineRequest, opts ...grpc.CallOption) (*DebugCreateMachineResponse, error) {
out := new(DebugCreateMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_DebugCreateMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/DebugCreateMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -173,7 +145,7 @@ func (c *headscaleServiceClient) DebugCreateMachine(ctx context.Context, in *Deb
func (c *headscaleServiceClient) GetMachine(ctx context.Context, in *GetMachineRequest, opts ...grpc.CallOption) (*GetMachineResponse, error) {
out := new(GetMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_GetMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -182,7 +154,7 @@ func (c *headscaleServiceClient) GetMachine(ctx context.Context, in *GetMachineR
func (c *headscaleServiceClient) SetTags(ctx context.Context, in *SetTagsRequest, opts ...grpc.CallOption) (*SetTagsResponse, error) {
out := new(SetTagsResponse)
err := c.cc.Invoke(ctx, HeadscaleService_SetTags_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/SetTags", in, out, opts...)
if err != nil {
return nil, err
}
@@ -191,7 +163,7 @@ func (c *headscaleServiceClient) SetTags(ctx context.Context, in *SetTagsRequest
func (c *headscaleServiceClient) RegisterMachine(ctx context.Context, in *RegisterMachineRequest, opts ...grpc.CallOption) (*RegisterMachineResponse, error) {
out := new(RegisterMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_RegisterMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/RegisterMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -200,7 +172,7 @@ func (c *headscaleServiceClient) RegisterMachine(ctx context.Context, in *Regist
func (c *headscaleServiceClient) DeleteMachine(ctx context.Context, in *DeleteMachineRequest, opts ...grpc.CallOption) (*DeleteMachineResponse, error) {
out := new(DeleteMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_DeleteMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/DeleteMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -209,7 +181,7 @@ func (c *headscaleServiceClient) DeleteMachine(ctx context.Context, in *DeleteMa
func (c *headscaleServiceClient) ExpireMachine(ctx context.Context, in *ExpireMachineRequest, opts ...grpc.CallOption) (*ExpireMachineResponse, error) {
out := new(ExpireMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ExpireMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ExpireMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -218,7 +190,7 @@ func (c *headscaleServiceClient) ExpireMachine(ctx context.Context, in *ExpireMa
func (c *headscaleServiceClient) RenameMachine(ctx context.Context, in *RenameMachineRequest, opts ...grpc.CallOption) (*RenameMachineResponse, error) {
out := new(RenameMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_RenameMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/RenameMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -227,7 +199,7 @@ func (c *headscaleServiceClient) RenameMachine(ctx context.Context, in *RenameMa
func (c *headscaleServiceClient) ListMachines(ctx context.Context, in *ListMachinesRequest, opts ...grpc.CallOption) (*ListMachinesResponse, error) {
out := new(ListMachinesResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ListMachines_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ListMachines", in, out, opts...)
if err != nil {
return nil, err
}
@@ -236,7 +208,7 @@ func (c *headscaleServiceClient) ListMachines(ctx context.Context, in *ListMachi
func (c *headscaleServiceClient) MoveMachine(ctx context.Context, in *MoveMachineRequest, opts ...grpc.CallOption) (*MoveMachineResponse, error) {
out := new(MoveMachineResponse)
err := c.cc.Invoke(ctx, HeadscaleService_MoveMachine_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/MoveMachine", in, out, opts...)
if err != nil {
return nil, err
}
@@ -245,7 +217,7 @@ func (c *headscaleServiceClient) MoveMachine(ctx context.Context, in *MoveMachin
func (c *headscaleServiceClient) GetRoutes(ctx context.Context, in *GetRoutesRequest, opts ...grpc.CallOption) (*GetRoutesResponse, error) {
out := new(GetRoutesResponse)
err := c.cc.Invoke(ctx, HeadscaleService_GetRoutes_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetRoutes", in, out, opts...)
if err != nil {
return nil, err
}
@@ -254,7 +226,7 @@ func (c *headscaleServiceClient) GetRoutes(ctx context.Context, in *GetRoutesReq
func (c *headscaleServiceClient) EnableRoute(ctx context.Context, in *EnableRouteRequest, opts ...grpc.CallOption) (*EnableRouteResponse, error) {
out := new(EnableRouteResponse)
err := c.cc.Invoke(ctx, HeadscaleService_EnableRoute_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/EnableRoute", in, out, opts...)
if err != nil {
return nil, err
}
@@ -263,7 +235,7 @@ func (c *headscaleServiceClient) EnableRoute(ctx context.Context, in *EnableRout
func (c *headscaleServiceClient) DisableRoute(ctx context.Context, in *DisableRouteRequest, opts ...grpc.CallOption) (*DisableRouteResponse, error) {
out := new(DisableRouteResponse)
err := c.cc.Invoke(ctx, HeadscaleService_DisableRoute_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/DisableRoute", in, out, opts...)
if err != nil {
return nil, err
}
@@ -272,7 +244,7 @@ func (c *headscaleServiceClient) DisableRoute(ctx context.Context, in *DisableRo
func (c *headscaleServiceClient) GetMachineRoutes(ctx context.Context, in *GetMachineRoutesRequest, opts ...grpc.CallOption) (*GetMachineRoutesResponse, error) {
out := new(GetMachineRoutesResponse)
err := c.cc.Invoke(ctx, HeadscaleService_GetMachineRoutes_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/GetMachineRoutes", in, out, opts...)
if err != nil {
return nil, err
}
@@ -281,7 +253,7 @@ func (c *headscaleServiceClient) GetMachineRoutes(ctx context.Context, in *GetMa
func (c *headscaleServiceClient) DeleteRoute(ctx context.Context, in *DeleteRouteRequest, opts ...grpc.CallOption) (*DeleteRouteResponse, error) {
out := new(DeleteRouteResponse)
err := c.cc.Invoke(ctx, HeadscaleService_DeleteRoute_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/DeleteRoute", in, out, opts...)
if err != nil {
return nil, err
}
@@ -290,7 +262,7 @@ func (c *headscaleServiceClient) DeleteRoute(ctx context.Context, in *DeleteRout
func (c *headscaleServiceClient) CreateApiKey(ctx context.Context, in *CreateApiKeyRequest, opts ...grpc.CallOption) (*CreateApiKeyResponse, error) {
out := new(CreateApiKeyResponse)
err := c.cc.Invoke(ctx, HeadscaleService_CreateApiKey_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/CreateApiKey", in, out, opts...)
if err != nil {
return nil, err
}
@@ -299,7 +271,7 @@ func (c *headscaleServiceClient) CreateApiKey(ctx context.Context, in *CreateApi
func (c *headscaleServiceClient) ExpireApiKey(ctx context.Context, in *ExpireApiKeyRequest, opts ...grpc.CallOption) (*ExpireApiKeyResponse, error) {
out := new(ExpireApiKeyResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ExpireApiKey_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ExpireApiKey", in, out, opts...)
if err != nil {
return nil, err
}
@@ -308,7 +280,7 @@ func (c *headscaleServiceClient) ExpireApiKey(ctx context.Context, in *ExpireApi
func (c *headscaleServiceClient) ListApiKeys(ctx context.Context, in *ListApiKeysRequest, opts ...grpc.CallOption) (*ListApiKeysResponse, error) {
out := new(ListApiKeysResponse)
err := c.cc.Invoke(ctx, HeadscaleService_ListApiKeys_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, "/headscale.v1.HeadscaleService/ListApiKeys", in, out, opts...)
if err != nil {
return nil, err
}
@@ -454,7 +426,7 @@ func _HeadscaleService_GetUser_Handler(srv interface{}, ctx context.Context, dec
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_GetUser_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/GetUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).GetUser(ctx, req.(*GetUserRequest))
@@ -472,7 +444,7 @@ func _HeadscaleService_CreateUser_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_CreateUser_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/CreateUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).CreateUser(ctx, req.(*CreateUserRequest))
@@ -490,7 +462,7 @@ func _HeadscaleService_RenameUser_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_RenameUser_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/RenameUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).RenameUser(ctx, req.(*RenameUserRequest))
@@ -508,7 +480,7 @@ func _HeadscaleService_DeleteUser_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_DeleteUser_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/DeleteUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).DeleteUser(ctx, req.(*DeleteUserRequest))
@@ -526,7 +498,7 @@ func _HeadscaleService_ListUsers_Handler(srv interface{}, ctx context.Context, d
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ListUsers_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ListUsers",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ListUsers(ctx, req.(*ListUsersRequest))
@@ -544,7 +516,7 @@ func _HeadscaleService_CreatePreAuthKey_Handler(srv interface{}, ctx context.Con
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_CreatePreAuthKey_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/CreatePreAuthKey",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).CreatePreAuthKey(ctx, req.(*CreatePreAuthKeyRequest))
@@ -562,7 +534,7 @@ func _HeadscaleService_ExpirePreAuthKey_Handler(srv interface{}, ctx context.Con
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ExpirePreAuthKey_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ExpirePreAuthKey",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ExpirePreAuthKey(ctx, req.(*ExpirePreAuthKeyRequest))
@@ -580,7 +552,7 @@ func _HeadscaleService_ListPreAuthKeys_Handler(srv interface{}, ctx context.Cont
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ListPreAuthKeys_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ListPreAuthKeys",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ListPreAuthKeys(ctx, req.(*ListPreAuthKeysRequest))
@@ -598,7 +570,7 @@ func _HeadscaleService_DebugCreateMachine_Handler(srv interface{}, ctx context.C
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_DebugCreateMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/DebugCreateMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).DebugCreateMachine(ctx, req.(*DebugCreateMachineRequest))
@@ -616,7 +588,7 @@ func _HeadscaleService_GetMachine_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_GetMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/GetMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).GetMachine(ctx, req.(*GetMachineRequest))
@@ -634,7 +606,7 @@ func _HeadscaleService_SetTags_Handler(srv interface{}, ctx context.Context, dec
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_SetTags_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/SetTags",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).SetTags(ctx, req.(*SetTagsRequest))
@@ -652,7 +624,7 @@ func _HeadscaleService_RegisterMachine_Handler(srv interface{}, ctx context.Cont
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_RegisterMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/RegisterMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).RegisterMachine(ctx, req.(*RegisterMachineRequest))
@@ -670,7 +642,7 @@ func _HeadscaleService_DeleteMachine_Handler(srv interface{}, ctx context.Contex
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_DeleteMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/DeleteMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).DeleteMachine(ctx, req.(*DeleteMachineRequest))
@@ -688,7 +660,7 @@ func _HeadscaleService_ExpireMachine_Handler(srv interface{}, ctx context.Contex
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ExpireMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ExpireMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ExpireMachine(ctx, req.(*ExpireMachineRequest))
@@ -706,7 +678,7 @@ func _HeadscaleService_RenameMachine_Handler(srv interface{}, ctx context.Contex
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_RenameMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/RenameMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).RenameMachine(ctx, req.(*RenameMachineRequest))
@@ -724,7 +696,7 @@ func _HeadscaleService_ListMachines_Handler(srv interface{}, ctx context.Context
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ListMachines_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ListMachines",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ListMachines(ctx, req.(*ListMachinesRequest))
@@ -742,7 +714,7 @@ func _HeadscaleService_MoveMachine_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_MoveMachine_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/MoveMachine",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).MoveMachine(ctx, req.(*MoveMachineRequest))
@@ -760,7 +732,7 @@ func _HeadscaleService_GetRoutes_Handler(srv interface{}, ctx context.Context, d
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_GetRoutes_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/GetRoutes",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).GetRoutes(ctx, req.(*GetRoutesRequest))
@@ -778,7 +750,7 @@ func _HeadscaleService_EnableRoute_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_EnableRoute_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/EnableRoute",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).EnableRoute(ctx, req.(*EnableRouteRequest))
@@ -796,7 +768,7 @@ func _HeadscaleService_DisableRoute_Handler(srv interface{}, ctx context.Context
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_DisableRoute_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/DisableRoute",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).DisableRoute(ctx, req.(*DisableRouteRequest))
@@ -814,7 +786,7 @@ func _HeadscaleService_GetMachineRoutes_Handler(srv interface{}, ctx context.Con
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_GetMachineRoutes_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/GetMachineRoutes",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).GetMachineRoutes(ctx, req.(*GetMachineRoutesRequest))
@@ -832,7 +804,7 @@ func _HeadscaleService_DeleteRoute_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_DeleteRoute_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/DeleteRoute",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).DeleteRoute(ctx, req.(*DeleteRouteRequest))
@@ -850,7 +822,7 @@ func _HeadscaleService_CreateApiKey_Handler(srv interface{}, ctx context.Context
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_CreateApiKey_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/CreateApiKey",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).CreateApiKey(ctx, req.(*CreateApiKeyRequest))
@@ -868,7 +840,7 @@ func _HeadscaleService_ExpireApiKey_Handler(srv interface{}, ctx context.Context
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ExpireApiKey_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ExpireApiKey",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ExpireApiKey(ctx, req.(*ExpireApiKeyRequest))
@@ -886,7 +858,7 @@ func _HeadscaleService_ListApiKeys_Handler(srv interface{}, ctx context.Context,
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: HeadscaleService_ListApiKeys_FullMethodName,
FullMethod: "/headscale.v1.HeadscaleService/ListApiKeys",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HeadscaleServiceServer).ListApiKeys(ctx, req.(*ListApiKeysRequest))
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/machine.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/preauthkey.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/routes.proto
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.29.1
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: headscale/v1/user.proto
+1 -1
View File
@@ -1,5 +1,5 @@
// nolint
package hscontrol
package headscale
import (
"context"
+1 -1
View File
@@ -1,4 +1,4 @@
package hscontrol
package headscale
import "testing"
@@ -1,6 +1,6 @@
//go:build ts2019
package hscontrol
package headscale
import (
"net/http"
@@ -1,6 +1,6 @@
//go:build !ts2019
package hscontrol
package headscale
import "github.com/gorilla/mux"
+44 -44
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/tsic"
"github.com/stretchr/testify/assert"
@@ -45,7 +45,7 @@ var veryLargeDestination = []string{
"208.0.0.0/4:*",
}
func aclScenario(t *testing.T, policy *hscontrol.ACLPolicy, clientsPerUser int) *Scenario {
func aclScenario(t *testing.T, policy *headscale.ACLPolicy, clientsPerUser int) *Scenario {
t.Helper()
scenario, err := NewScenario()
assert.NoError(t, err)
@@ -92,7 +92,7 @@ func TestACLHostsInNetMapTable(t *testing.T) {
// they can access minus one (them self).
tests := map[string]struct {
users map[string]int
policy hscontrol.ACLPolicy
policy headscale.ACLPolicy
want map[string]int
}{
// Test that when we have no ACL, each client netmap has
@@ -102,8 +102,8 @@ func TestACLHostsInNetMapTable(t *testing.T) {
"user1": 2,
"user2": 2,
},
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"*"},
@@ -123,8 +123,8 @@ func TestACLHostsInNetMapTable(t *testing.T) {
"user1": 2,
"user2": 2,
},
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -149,8 +149,8 @@ func TestACLHostsInNetMapTable(t *testing.T) {
"user1": 2,
"user2": 2,
},
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -186,8 +186,8 @@ func TestACLHostsInNetMapTable(t *testing.T) {
"user1": 2,
"user2": 2,
},
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -214,8 +214,8 @@ func TestACLHostsInNetMapTable(t *testing.T) {
"user1": 2,
"user2": 2,
},
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -282,8 +282,8 @@ func TestACLAllowUser80Dst(t *testing.T) {
IntegrationSkip(t)
scenario := aclScenario(t,
&hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
&headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -338,11 +338,11 @@ func TestACLDenyAllPort80(t *testing.T) {
IntegrationSkip(t)
scenario := aclScenario(t,
&hscontrol.ACLPolicy{
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-acl-test": {"user1", "user2"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"group:integration-acl-test"},
@@ -387,8 +387,8 @@ func TestACLAllowUserDst(t *testing.T) {
IntegrationSkip(t)
scenario := aclScenario(t,
&hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
&headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -445,8 +445,8 @@ func TestACLAllowStarDst(t *testing.T) {
IntegrationSkip(t)
scenario := aclScenario(t,
&hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
&headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"user1"},
@@ -504,11 +504,11 @@ func TestACLNamedHostsCanReachBySubnet(t *testing.T) {
IntegrationSkip(t)
scenario := aclScenario(t,
&hscontrol.ACLPolicy{
Hosts: hscontrol.Hosts{
&headscale.ACLPolicy{
Hosts: headscale.Hosts{
"all": netip.MustParsePrefix("100.64.0.0/24"),
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
// Everyone can curl test3
{
Action: "accept",
@@ -603,16 +603,16 @@ func TestACLNamedHostsCanReach(t *testing.T) {
IntegrationSkip(t)
tests := map[string]struct {
policy hscontrol.ACLPolicy
policy headscale.ACLPolicy
}{
"ipv4": {
policy: hscontrol.ACLPolicy{
Hosts: hscontrol.Hosts{
policy: headscale.ACLPolicy{
Hosts: headscale.Hosts{
"test1": netip.MustParsePrefix("100.64.0.1/32"),
"test2": netip.MustParsePrefix("100.64.0.2/32"),
"test3": netip.MustParsePrefix("100.64.0.3/32"),
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
// Everyone can curl test3
{
Action: "accept",
@@ -629,13 +629,13 @@ func TestACLNamedHostsCanReach(t *testing.T) {
},
},
"ipv6": {
policy: hscontrol.ACLPolicy{
Hosts: hscontrol.Hosts{
policy: headscale.ACLPolicy{
Hosts: headscale.Hosts{
"test1": netip.MustParsePrefix("fd7a:115c:a1e0::1/128"),
"test2": netip.MustParsePrefix("fd7a:115c:a1e0::2/128"),
"test3": netip.MustParsePrefix("fd7a:115c:a1e0::3/128"),
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
// Everyone can curl test3
{
Action: "accept",
@@ -854,11 +854,11 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
IntegrationSkip(t)
tests := map[string]struct {
policy hscontrol.ACLPolicy
policy headscale.ACLPolicy
}{
"ipv4": {
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"100.64.0.1"},
@@ -868,8 +868,8 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
},
},
"ipv6": {
policy: hscontrol.ACLPolicy{
ACLs: []hscontrol.ACL{
policy: headscale.ACLPolicy{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"fd7a:115c:a1e0::1"},
@@ -879,12 +879,12 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
},
},
"hostv4cidr": {
policy: hscontrol.ACLPolicy{
Hosts: hscontrol.Hosts{
policy: headscale.ACLPolicy{
Hosts: headscale.Hosts{
"test1": netip.MustParsePrefix("100.64.0.1/32"),
"test2": netip.MustParsePrefix("100.64.0.2/32"),
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"test1"},
@@ -894,12 +894,12 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
},
},
"hostv6cidr": {
policy: hscontrol.ACLPolicy{
Hosts: hscontrol.Hosts{
policy: headscale.ACLPolicy{
Hosts: headscale.Hosts{
"test1": netip.MustParsePrefix("fd7a:115c:a1e0::1/128"),
"test2": netip.MustParsePrefix("fd7a:115c:a1e0::2/128"),
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"test1"},
@@ -909,12 +909,12 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
},
},
"group": {
policy: hscontrol.ACLPolicy{
policy: headscale.ACLPolicy{
Groups: map[string][]string{
"group:one": {"user1"},
"group:two": {"user2"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"group:one"},
+4 -4
View File
@@ -14,7 +14,7 @@ import (
"testing"
"time"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/hsic"
"github.com/ory/dockertest/v3"
@@ -213,14 +213,14 @@ func (s *AuthOIDCScenario) CreateHeadscaleEnv(
return nil
}
func (s *AuthOIDCScenario) runMockOIDC(accessTTL time.Duration) (*hscontrol.OIDCConfig, error) {
func (s *AuthOIDCScenario) runMockOIDC(accessTTL time.Duration) (*headscale.OIDCConfig, error) {
port, err := dockertestutil.RandomFreeHostPort()
if err != nil {
log.Fatalf("could not find an open port: %s", err)
}
portNotation := fmt.Sprintf("%d/tcp", port)
hash, _ := hscontrol.GenerateRandomStringDNSSafe(hsicOIDCMockHashLength)
hash, _ := headscale.GenerateRandomStringDNSSafe(hsicOIDCMockHashLength)
hostname := fmt.Sprintf("hs-oidcmock-%s", hash)
@@ -287,7 +287,7 @@ func (s *AuthOIDCScenario) runMockOIDC(accessTTL time.Duration) (*hscontrol.OIDC
log.Printf("headscale mock oidc is ready for tests at %s", hostEndpoint)
return &hscontrol.OIDCConfig{
return &headscale.OIDCConfig{
Issuer: fmt.Sprintf(
"http://%s/oidc",
net.JoinHostPort(s.mockOIDC.GetIPInNetwork(s.network), strconv.Itoa(port)),
-986
View File
@@ -532,989 +532,3 @@ func TestEnablingRoutes(t *testing.T) {
}
}
}
func TestApiKeyCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
count := 5
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
"user1": 0,
"user2": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
assert.NoError(t, err)
headscale, err := scenario.Headscale()
assert.NoError(t, err)
keys := make([]string, count)
for idx := 0; idx < count; idx++ {
apiResult, err := headscale.Execute(
[]string{
"headscale",
"apikeys",
"create",
"--expiration",
"24h",
"--output",
"json",
},
)
assert.Nil(t, err)
assert.NotEmpty(t, apiResult)
keys[idx] = apiResult
}
assert.Len(t, keys, 5)
var listedAPIKeys []v1.ApiKey
err = executeAndUnmarshal(headscale,
[]string{
"headscale",
"apikeys",
"list",
"--output",
"json",
},
&listedAPIKeys,
)
assert.Nil(t, err)
assert.Len(t, listedAPIKeys, 5)
assert.Equal(t, uint64(1), listedAPIKeys[0].Id)
assert.Equal(t, uint64(2), listedAPIKeys[1].Id)
assert.Equal(t, uint64(3), listedAPIKeys[2].Id)
assert.Equal(t, uint64(4), listedAPIKeys[3].Id)
assert.Equal(t, uint64(5), listedAPIKeys[4].Id)
assert.NotEmpty(t, listedAPIKeys[0].Prefix)
assert.NotEmpty(t, listedAPIKeys[1].Prefix)
assert.NotEmpty(t, listedAPIKeys[2].Prefix)
assert.NotEmpty(t, listedAPIKeys[3].Prefix)
assert.NotEmpty(t, listedAPIKeys[4].Prefix)
assert.True(t, listedAPIKeys[0].Expiration.AsTime().After(time.Now()))
assert.True(t, listedAPIKeys[1].Expiration.AsTime().After(time.Now()))
assert.True(t, listedAPIKeys[2].Expiration.AsTime().After(time.Now()))
assert.True(t, listedAPIKeys[3].Expiration.AsTime().After(time.Now()))
assert.True(t, listedAPIKeys[4].Expiration.AsTime().After(time.Now()))
assert.True(
t,
listedAPIKeys[0].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)),
)
assert.True(
t,
listedAPIKeys[1].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)),
)
assert.True(
t,
listedAPIKeys[2].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)),
)
assert.True(
t,
listedAPIKeys[3].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)),
)
assert.True(
t,
listedAPIKeys[4].Expiration.AsTime().Before(time.Now().Add(time.Hour*26)),
)
expiredPrefixes := make(map[string]bool)
// Expire three keys
for idx := 0; idx < 3; idx++ {
_, err := headscale.Execute(
[]string{
"headscale",
"apikeys",
"expire",
"--prefix",
listedAPIKeys[idx].Prefix,
},
)
assert.Nil(t, err)
expiredPrefixes[listedAPIKeys[idx].Prefix] = true
}
var listedAfterExpireAPIKeys []v1.ApiKey
err = executeAndUnmarshal(headscale,
[]string{
"headscale",
"apikeys",
"list",
"--output",
"json",
},
&listedAfterExpireAPIKeys,
)
assert.Nil(t, err)
for index := range listedAfterExpireAPIKeys {
if _, ok := expiredPrefixes[listedAfterExpireAPIKeys[index].Prefix]; ok {
// Expired
assert.True(
t,
listedAfterExpireAPIKeys[index].Expiration.AsTime().Before(time.Now()),
)
} else {
// Not expired
assert.False(
t,
listedAfterExpireAPIKeys[index].Expiration.AsTime().Before(time.Now()),
)
}
}
err = scenario.Shutdown()
assert.NoError(t, err)
}
func TestNodeTagCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
"user1": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
assert.NoError(t, err)
headscale, err := scenario.Headscale()
assert.NoError(t, err)
machineKeys := []string{
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
}
machines := make([]*v1.Machine, len(machineKeys))
assert.Nil(t, err)
for index, machineKey := range machineKeys {
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--user",
"user1",
"--key",
machineKey,
"--output",
"json",
},
)
assert.Nil(t, err)
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"--user",
"user1",
"register",
"--key",
machineKey,
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
machines[index] = &machine
}
assert.Len(t, machines, len(machineKeys))
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"tag",
"-i", "1",
"-t", "tag:test",
"--output", "json",
},
&machine,
)
assert.Nil(t, err)
assert.Equal(t, []string{"tag:test"}, machine.ForcedTags)
// try to set a wrong tag and retrieve the error
type errOutput struct {
Error string `json:"error"`
}
var errorOutput errOutput
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"tag",
"-i", "2",
"-t", "wrong-tag",
"--output", "json",
},
&errorOutput,
)
assert.Nil(t, err)
assert.Contains(t, errorOutput.Error, "tag must start with the string 'tag:'")
// Test list all nodes after added seconds
resultMachines := make([]*v1.Machine, len(machineKeys))
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output", "json",
},
&resultMachines,
)
assert.Nil(t, err)
found := false
for _, machine := range resultMachines {
if machine.ForcedTags != nil {
for _, tag := range machine.ForcedTags {
if tag == "tag:test" {
found = true
}
}
}
}
assert.Equal(
t,
true,
found,
"should find a machine with the tag 'tag:test' in the list of machines",
)
err = scenario.Shutdown()
assert.NoError(t, err)
}
func TestNodeCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
"machine-user": 0,
"other-user": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
assert.NoError(t, err)
headscale, err := scenario.Headscale()
assert.NoError(t, err)
// Randomly generated machine keys
machineKeys := []string{
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
}
machines := make([]*v1.Machine, len(machineKeys))
assert.Nil(t, err)
for index, machineKey := range machineKeys {
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--user",
"machine-user",
"--key",
machineKey,
"--output",
"json",
},
)
assert.Nil(t, err)
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"--user",
"machine-user",
"register",
"--key",
machineKey,
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
machines[index] = &machine
}
assert.Len(t, machines, len(machineKeys))
// Test list all nodes after added seconds
var listAll []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAll,
)
assert.Nil(t, err)
assert.Len(t, listAll, 5)
assert.Equal(t, uint64(1), listAll[0].Id)
assert.Equal(t, uint64(2), listAll[1].Id)
assert.Equal(t, uint64(3), listAll[2].Id)
assert.Equal(t, uint64(4), listAll[3].Id)
assert.Equal(t, uint64(5), listAll[4].Id)
assert.Equal(t, "machine-1", listAll[0].Name)
assert.Equal(t, "machine-2", listAll[1].Name)
assert.Equal(t, "machine-3", listAll[2].Name)
assert.Equal(t, "machine-4", listAll[3].Name)
assert.Equal(t, "machine-5", listAll[4].Name)
otherUserMachineKeys := []string{
"nodekey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e",
"nodekey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584",
}
otherUserMachines := make([]*v1.Machine, len(otherUserMachineKeys))
assert.Nil(t, err)
for index, machineKey := range otherUserMachineKeys {
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name",
fmt.Sprintf("otherUser-machine-%d", index+1),
"--user",
"other-user",
"--key",
machineKey,
"--output",
"json",
},
)
assert.Nil(t, err)
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"--user",
"other-user",
"register",
"--key",
machineKey,
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
otherUserMachines[index] = &machine
}
assert.Len(t, otherUserMachines, len(otherUserMachineKeys))
// Test list all nodes after added otherUser
var listAllWithotherUser []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAllWithotherUser,
)
assert.Nil(t, err)
// All nodes, machines + otherUser
assert.Len(t, listAllWithotherUser, 7)
assert.Equal(t, uint64(6), listAllWithotherUser[5].Id)
assert.Equal(t, uint64(7), listAllWithotherUser[6].Id)
assert.Equal(t, "otherUser-machine-1", listAllWithotherUser[5].Name)
assert.Equal(t, "otherUser-machine-2", listAllWithotherUser[6].Name)
// Test list all nodes after added otherUser
var listOnlyotherUserMachineUser []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--user",
"other-user",
"--output",
"json",
},
&listOnlyotherUserMachineUser,
)
assert.Nil(t, err)
assert.Len(t, listOnlyotherUserMachineUser, 2)
assert.Equal(t, uint64(6), listOnlyotherUserMachineUser[0].Id)
assert.Equal(t, uint64(7), listOnlyotherUserMachineUser[1].Id)
assert.Equal(
t,
"otherUser-machine-1",
listOnlyotherUserMachineUser[0].Name,
)
assert.Equal(
t,
"otherUser-machine-2",
listOnlyotherUserMachineUser[1].Name,
)
// Delete a machines
_, err = headscale.Execute(
[]string{
"headscale",
"nodes",
"delete",
"--identifier",
// Delete the last added machine
"4",
"--output",
"json",
"--force",
},
)
assert.Nil(t, err)
// Test: list main user after machine is deleted
var listOnlyMachineUserAfterDelete []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--user",
"machine-user",
"--output",
"json",
},
&listOnlyMachineUserAfterDelete,
)
assert.Nil(t, err)
assert.Len(t, listOnlyMachineUserAfterDelete, 4)
err = scenario.Shutdown()
assert.NoError(t, err)
}
func TestNodeExpireCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
"machine-expire-user": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
assert.NoError(t, err)
headscale, err := scenario.Headscale()
assert.NoError(t, err)
// Randomly generated machine keys
machineKeys := []string{
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
}
machines := make([]*v1.Machine, len(machineKeys))
for index, machineKey := range machineKeys {
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--user",
"machine-expire-user",
"--key",
machineKey,
"--output",
"json",
},
)
assert.Nil(t, err)
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"--user",
"machine-expire-user",
"register",
"--key",
machineKey,
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
machines[index] = &machine
}
assert.Len(t, machines, len(machineKeys))
var listAll []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAll,
)
assert.Nil(t, err)
assert.Len(t, listAll, 5)
assert.True(t, listAll[0].Expiry.AsTime().IsZero())
assert.True(t, listAll[1].Expiry.AsTime().IsZero())
assert.True(t, listAll[2].Expiry.AsTime().IsZero())
assert.True(t, listAll[3].Expiry.AsTime().IsZero())
assert.True(t, listAll[4].Expiry.AsTime().IsZero())
for idx := 0; idx < 3; idx++ {
_, err := headscale.Execute(
[]string{
"headscale",
"nodes",
"expire",
"--identifier",
fmt.Sprintf("%d", listAll[idx].Id),
},
)
assert.Nil(t, err)
}
var listAllAfterExpiry []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAllAfterExpiry,
)
assert.Nil(t, err)
assert.Len(t, listAllAfterExpiry, 5)
assert.True(t, listAllAfterExpiry[0].Expiry.AsTime().Before(time.Now()))
assert.True(t, listAllAfterExpiry[1].Expiry.AsTime().Before(time.Now()))
assert.True(t, listAllAfterExpiry[2].Expiry.AsTime().Before(time.Now()))
assert.True(t, listAllAfterExpiry[3].Expiry.AsTime().IsZero())
assert.True(t, listAllAfterExpiry[4].Expiry.AsTime().IsZero())
err = scenario.Shutdown()
assert.NoError(t, err)
}
func TestNodeRenameCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
"machine-rename-command": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
assert.NoError(t, err)
headscale, err := scenario.Headscale()
assert.NoError(t, err)
// Randomly generated machine keys
machineKeys := []string{
"nodekey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
"nodekey:8bc13285cee598acf76b1824a6f4490f7f2e3751b201e28aeb3b07fe81d5b4a1",
"nodekey:f08305b4ee4250b95a70f3b7504d048d75d899993c624a26d422c67af0422507",
"nodekey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
"nodekey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
}
machines := make([]*v1.Machine, len(machineKeys))
assert.Nil(t, err)
for index, machineKey := range machineKeys {
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--user",
"machine-rename-command",
"--key",
machineKey,
"--output",
"json",
},
)
assert.Nil(t, err)
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"--user",
"machine-rename-command",
"register",
"--key",
machineKey,
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
machines[index] = &machine
}
assert.Len(t, machines, len(machineKeys))
var listAll []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAll,
)
assert.Nil(t, err)
assert.Len(t, listAll, 5)
assert.Contains(t, listAll[0].GetGivenName(), "machine-1")
assert.Contains(t, listAll[1].GetGivenName(), "machine-2")
assert.Contains(t, listAll[2].GetGivenName(), "machine-3")
assert.Contains(t, listAll[3].GetGivenName(), "machine-4")
assert.Contains(t, listAll[4].GetGivenName(), "machine-5")
for idx := 0; idx < 3; idx++ {
_, err := headscale.Execute(
[]string{
"headscale",
"nodes",
"rename",
"--identifier",
fmt.Sprintf("%d", listAll[idx].Id),
fmt.Sprintf("newmachine-%d", idx+1),
},
)
assert.Nil(t, err)
}
var listAllAfterRename []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAllAfterRename,
)
assert.Nil(t, err)
assert.Len(t, listAllAfterRename, 5)
assert.Equal(t, "newmachine-1", listAllAfterRename[0].GetGivenName())
assert.Equal(t, "newmachine-2", listAllAfterRename[1].GetGivenName())
assert.Equal(t, "newmachine-3", listAllAfterRename[2].GetGivenName())
assert.Contains(t, listAllAfterRename[3].GetGivenName(), "machine-4")
assert.Contains(t, listAllAfterRename[4].GetGivenName(), "machine-5")
// Test failure for too long names
result, err := headscale.Execute(
[]string{
"headscale",
"nodes",
"rename",
"--identifier",
fmt.Sprintf("%d", listAll[4].Id),
"testmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaachine12345678901234567890",
},
)
assert.Nil(t, err)
assert.Contains(t, result, "not be over 63 chars")
var listAllAfterRenameAttempt []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&listAllAfterRenameAttempt,
)
assert.Nil(t, err)
assert.Len(t, listAllAfterRenameAttempt, 5)
assert.Equal(t, "newmachine-1", listAllAfterRenameAttempt[0].GetGivenName())
assert.Equal(t, "newmachine-2", listAllAfterRenameAttempt[1].GetGivenName())
assert.Equal(t, "newmachine-3", listAllAfterRenameAttempt[2].GetGivenName())
assert.Contains(t, listAllAfterRenameAttempt[3].GetGivenName(), "machine-4")
assert.Contains(t, listAllAfterRenameAttempt[4].GetGivenName(), "machine-5")
err = scenario.Shutdown()
assert.NoError(t, err)
}
func TestNodeMoveCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
"old-user": 0,
"new-user": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
assert.NoError(t, err)
headscale, err := scenario.Headscale()
assert.NoError(t, err)
// Randomly generated machine key
machineKey := "nodekey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa"
_, err = headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name",
"nomad-machine",
"--user",
"old-user",
"--key",
machineKey,
"--output",
"json",
},
)
assert.Nil(t, err)
var machine v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"--user",
"old-user",
"register",
"--key",
machineKey,
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
assert.Equal(t, uint64(1), machine.Id)
assert.Equal(t, "nomad-machine", machine.Name)
assert.Equal(t, machine.User.Name, "old-user")
machineID := fmt.Sprintf("%d", machine.Id)
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"move",
"--identifier",
machineID,
"--user",
"new-user",
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
assert.Equal(t, machine.User.Name, "new-user")
var allNodes []v1.Machine
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
&allNodes,
)
assert.Nil(t, err)
assert.Len(t, allNodes, 1)
assert.Equal(t, allNodes[0].Id, machine.Id)
assert.Equal(t, allNodes[0].User, machine.User)
assert.Equal(t, allNodes[0].User.Name, "new-user")
moveToNonExistingNSResult, err := headscale.Execute(
[]string{
"headscale",
"nodes",
"move",
"--identifier",
machineID,
"--user",
"non-existing-user",
"--output",
"json",
},
)
assert.Nil(t, err)
assert.Contains(
t,
moveToNonExistingNSResult,
"User not found",
)
assert.Equal(t, machine.User.Name, "new-user")
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"move",
"--identifier",
machineID,
"--user",
"old-user",
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
assert.Equal(t, machine.User.Name, "old-user")
err = executeAndUnmarshal(
headscale,
[]string{
"headscale",
"nodes",
"move",
"--identifier",
machineID,
"--user",
"old-user",
"--output",
"json",
},
&machine,
)
assert.Nil(t, err)
assert.Equal(t, machine.User.Name, "old-user")
err = scenario.Shutdown()
assert.NoError(t, err)
}
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"net/url"
"testing"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/tsic"
@@ -110,7 +110,7 @@ func (s *EmbeddedDERPServerScenario) CreateHeadscaleEnv(
return err
}
hash, err := hscontrol.GenerateRandomStringDNSSafe(scenarioHashLength)
hash, err := headscale.GenerateRandomStringDNSSafe(scenarioHashLength)
if err != nil {
return err
}
+6 -6
View File
@@ -22,8 +22,8 @@ import (
"time"
"github.com/davecgh/go-spew/spew"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/integrationutil"
"github.com/ory/dockertest/v3"
@@ -59,7 +59,7 @@ type HeadscaleInContainer struct {
port int
extraPorts []string
hostPortBindings map[string][]string
aclPolicy *hscontrol.ACLPolicy
aclPolicy *headscale.ACLPolicy
env map[string]string
tlsCert []byte
tlsKey []byte
@@ -70,9 +70,9 @@ type HeadscaleInContainer struct {
// Headscale instance.
type Option = func(c *HeadscaleInContainer)
// WithACLPolicy adds a hscontrol.ACLPolicy policy to the
// WithACLPolicy adds a headscale.ACLPolicy policy to the
// HeadscaleInContainer instance.
func WithACLPolicy(acl *hscontrol.ACLPolicy) Option {
func WithACLPolicy(acl *headscale.ACLPolicy) Option {
return func(hsic *HeadscaleInContainer) {
// TODO(kradalby): Move somewhere appropriate
hsic.env["HEADSCALE_ACL_POLICY_PATH"] = aclPolicyPath
@@ -132,7 +132,7 @@ func WithHostPortBindings(bindings map[string][]string) Option {
// in the Docker container name.
func WithTestName(testName string) Option {
return func(hsic *HeadscaleInContainer) {
hash, _ := hscontrol.GenerateRandomStringDNSSafe(hsicHashLength)
hash, _ := headscale.GenerateRandomStringDNSSafe(hsicHashLength)
hostname := fmt.Sprintf("hs-%s-%s", testName, hash)
hsic.hostname = hostname
@@ -167,7 +167,7 @@ func New(
network *dockertest.Network,
opts ...Option,
) (*HeadscaleInContainer, error) {
hash, err := hscontrol.GenerateRandomStringDNSSafe(hsicHashLength)
hash, err := headscale.GenerateRandomStringDNSSafe(hsicHashLength)
if err != nil {
return nil, err
}
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"sync"
"time"
"github.com/juanfont/headscale"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/tsic"
@@ -105,7 +105,7 @@ type Scenario struct {
// NewScenario creates a test Scenario which can be used to bootstraps a ControlServer with
// a set of Users and TailscaleClients.
func NewScenario() (*Scenario, error) {
hash, err := hscontrol.GenerateRandomStringDNSSafe(scenarioHashLength)
hash, err := headscale.GenerateRandomStringDNSSafe(scenarioHashLength)
if err != nil {
return nil, err
}
+16 -16
View File
@@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/tsic"
"github.com/stretchr/testify/assert"
@@ -57,18 +57,18 @@ func TestSSHOneUserAllToAll(t *testing.T) {
err = scenario.CreateHeadscaleEnv(spec,
[]tsic.Option{tsic.WithSSH()},
hsic.WithACLPolicy(
&hscontrol.ACLPolicy{
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"user1"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"*:*"},
},
},
SSHs: []hscontrol.SSH{
SSHs: []headscale.SSH{
{
Action: "accept",
Sources: []string{"group:integration-test"},
@@ -134,18 +134,18 @@ func TestSSHMultipleUsersAllToAll(t *testing.T) {
err = scenario.CreateHeadscaleEnv(spec,
[]tsic.Option{tsic.WithSSH()},
hsic.WithACLPolicy(
&hscontrol.ACLPolicy{
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"user1", "user2"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"*:*"},
},
},
SSHs: []hscontrol.SSH{
SSHs: []headscale.SSH{
{
Action: "accept",
Sources: []string{"group:integration-test"},
@@ -216,18 +216,18 @@ func TestSSHNoSSHConfigured(t *testing.T) {
err = scenario.CreateHeadscaleEnv(spec,
[]tsic.Option{tsic.WithSSH()},
hsic.WithACLPolicy(
&hscontrol.ACLPolicy{
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"user1"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"*:*"},
},
},
SSHs: []hscontrol.SSH{},
SSHs: []headscale.SSH{},
},
),
hsic.WithTestName("sshnoneconfigured"),
@@ -286,18 +286,18 @@ func TestSSHIsBlockedInACL(t *testing.T) {
err = scenario.CreateHeadscaleEnv(spec,
[]tsic.Option{tsic.WithSSH()},
hsic.WithACLPolicy(
&hscontrol.ACLPolicy{
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"user1"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"*:80"},
},
},
SSHs: []hscontrol.SSH{
SSHs: []headscale.SSH{
{
Action: "accept",
Sources: []string{"group:integration-test"},
@@ -364,19 +364,19 @@ func TestSSUserOnlyIsolation(t *testing.T) {
err = scenario.CreateHeadscaleEnv(spec,
[]tsic.Option{tsic.WithSSH()},
hsic.WithACLPolicy(
&hscontrol.ACLPolicy{
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:ssh1": {"useracl1"},
"group:ssh2": {"useracl2"},
},
ACLs: []hscontrol.ACL{
ACLs: []headscale.ACL{
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"*:*"},
},
},
SSHs: []hscontrol.SSH{
SSHs: []headscale.SSH{
{
Action: "accept",
Sources: []string{"group:ssh1"},
+2 -2
View File
@@ -12,7 +12,7 @@ import (
"time"
"github.com/cenkalti/backoff/v4"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale"
"github.com/juanfont/headscale/integration/dockertestutil"
"github.com/juanfont/headscale/integration/integrationutil"
"github.com/ory/dockertest/v3"
@@ -150,7 +150,7 @@ func New(
network *dockertest.Network,
opts ...Option,
) (*TailscaleInContainer, error) {
hash, err := hscontrol.GenerateRandomStringDNSSafe(tsicHashLength)
hash, err := headscale.GenerateRandomStringDNSSafe(tsicHashLength)
if err != nil {
return nil, err
}
File diff suppressed because it is too large Load Diff
+271
View File
@@ -0,0 +1,271 @@
// nolint
package headscale
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/netip"
"os"
"strconv"
"time"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
)
const (
headscaleNetwork = "headscale-test"
headscaleHostname = "headscale"
DOCKER_EXECUTE_TIMEOUT = 10 * time.Second
)
var (
errEnvVarEmpty = errors.New("getenv: environment variable empty")
IpPrefix4 = netip.MustParsePrefix("100.64.0.0/10")
IpPrefix6 = netip.MustParsePrefix("fd7a:115c:a1e0::/48")
tailscaleVersions = []string{
"head",
"unstable",
"1.38.4",
"1.36.2",
"1.34.2",
"1.32.3",
"1.30.2",
"1.28.0",
"1.26.2",
"1.24.2",
"1.22.2",
"1.20.4",
"1.18.2",
"1.16.2",
"1.14.3",
"1.12.3",
}
)
type ExecuteCommandConfig struct {
timeout time.Duration
}
type ExecuteCommandOption func(*ExecuteCommandConfig) error
func ExecuteCommandTimeout(timeout time.Duration) ExecuteCommandOption {
return ExecuteCommandOption(func(conf *ExecuteCommandConfig) error {
conf.timeout = timeout
return nil
})
}
func ExecuteCommand(
resource *dockertest.Resource,
cmd []string,
env []string,
options ...ExecuteCommandOption,
) (string, string, error) {
var stdout bytes.Buffer
var stderr bytes.Buffer
execConfig := ExecuteCommandConfig{
timeout: DOCKER_EXECUTE_TIMEOUT,
}
for _, opt := range options {
if err := opt(&execConfig); err != nil {
return "", "", fmt.Errorf("execute-command/options: %w", err)
}
}
type result struct {
exitCode int
err error
}
resultChan := make(chan result, 1)
// Run your long running function in it's own goroutine and pass back it's
// response into our channel.
go func() {
exitCode, err := resource.Exec(
cmd,
dockertest.ExecOptions{
Env: append(env, "HEADSCALE_LOG_LEVEL=disabled"),
StdOut: &stdout,
StdErr: &stderr,
},
)
resultChan <- result{exitCode, err}
}()
// Listen on our channel AND a timeout channel - which ever happens first.
select {
case res := <-resultChan:
if res.err != nil {
return stdout.String(), stderr.String(), res.err
}
if res.exitCode != 0 {
fmt.Println("Command: ", cmd)
fmt.Println("stdout: ", stdout.String())
fmt.Println("stderr: ", stderr.String())
return stdout.String(), stderr.String(), fmt.Errorf(
"command failed with: %s",
stderr.String(),
)
}
return stdout.String(), stderr.String(), nil
case <-time.After(execConfig.timeout):
return stdout.String(), stderr.String(), fmt.Errorf(
"command timed out after %s",
execConfig.timeout,
)
}
}
func DockerRestartPolicy(config *docker.HostConfig) {
// set AutoRemove to true so that stopped container goes away by itself on error *immediately*.
// when set to false, containers remain until the end of the integration test.
config.AutoRemove = false
config.RestartPolicy = docker.RestartPolicy{
Name: "no",
}
}
func DockerAllowLocalIPv6(config *docker.HostConfig) {
if config.Sysctls == nil {
config.Sysctls = make(map[string]string, 1)
}
config.Sysctls["net.ipv6.conf.all.disable_ipv6"] = "0"
}
func DockerAllowNetworkAdministration(config *docker.HostConfig) {
config.CapAdd = append(config.CapAdd, "NET_ADMIN")
config.Mounts = append(config.Mounts, docker.HostMount{
Type: "bind",
Source: "/dev/net/tun",
Target: "/dev/net/tun",
})
}
func getDockerBuildOptions(version string) *dockertest.BuildOptions {
var tailscaleBuildOptions *dockertest.BuildOptions
switch version {
case "head":
tailscaleBuildOptions = &dockertest.BuildOptions{
Dockerfile: "Dockerfile.tailscale-HEAD",
ContextDir: ".",
BuildArgs: []docker.BuildArg{},
}
case "unstable":
tailscaleBuildOptions = &dockertest.BuildOptions{
Dockerfile: "Dockerfile.tailscale",
ContextDir: ".",
BuildArgs: []docker.BuildArg{
{
Name: "TAILSCALE_VERSION",
Value: "*", // Installs the latest version https://askubuntu.com/a/824926
},
{
Name: "TAILSCALE_CHANNEL",
Value: "unstable",
},
},
}
default:
tailscaleBuildOptions = &dockertest.BuildOptions{
Dockerfile: "Dockerfile.tailscale",
ContextDir: ".",
BuildArgs: []docker.BuildArg{
{
Name: "TAILSCALE_VERSION",
Value: version,
},
{
Name: "TAILSCALE_CHANNEL",
Value: "stable",
},
},
}
}
return tailscaleBuildOptions
}
func getDNSNames(
headscale *dockertest.Resource,
) ([]string, error) {
listAllResult, _, err := ExecuteCommand(
headscale,
[]string{
"headscale",
"nodes",
"list",
"--output",
"json",
},
[]string{},
)
if err != nil {
return nil, err
}
var listAll []v1.Machine
err = json.Unmarshal([]byte(listAllResult), &listAll)
if err != nil {
return nil, err
}
hostnames := make([]string, len(listAll))
for index := range listAll {
hostnames[index] = listAll[index].GetGivenName()
}
return hostnames, nil
}
func GetEnvStr(key string) (string, error) {
v := os.Getenv(key)
if v == "" {
return v, errEnvVarEmpty
}
return v, nil
}
func GetEnvBool(key string) (bool, error) {
s, err := GetEnvStr(key)
if err != nil {
return false, err
}
v, err := strconv.ParseBool(s)
if err != nil {
return false, err
}
return v, nil
}
func GetFirstOrCreateNetwork(pool *dockertest.Pool, name string) (dockertest.Network, error) {
networks, err := pool.NetworksByName(name)
if err != nil || len(networks) == 0 {
if _, err := pool.CreateNetwork(name); err == nil {
// Create does not give us an updated version of the resource, so we need to
// get it again.
networks, err := pool.NetworksByName(name)
if err != nil {
return dockertest.Network{}, err
}
return networks[0], nil
}
}
return networks[0], nil
}
+3
View File
@@ -0,0 +1,3 @@
derp.yaml
*.sqlite
*.sqlite3
@@ -0,0 +1,56 @@
acl_policy_path: ""
cli:
insecure: false
timeout: 5s
db_path: /tmp/integration_test_db.sqlite3
db_ssl: false
db_type: sqlite3
derp:
auto_update_enabled: false
server:
enabled: false
stun:
enabled: true
update_frequency: 1m
urls:
- https://controlplane.tailscale.com/derpmap/default
dns_config:
override_local_dns: true
base_domain: headscale.net
domains: []
magic_dns: true
nameservers:
- 127.0.0.11
- 1.1.1.1
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
grpc_allow_insecure: false
grpc_listen_addr: :50443
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
listen_addr: 0.0.0.0:18080
log:
level: disabled
format: text
logtail:
enabled: false
metrics_listen_addr: 127.0.0.1:19090
oidc:
expiry: 180d
only_start_if_oidc_is_available: true
scope:
- openid
- profile
- email
strip_email_domain: true
use_expiry_from_token: false
private_key_path: private.key
noise:
private_key_path: noise_private.key
server_url: http://headscale:18080
tls_letsencrypt_cache_dir: /var/www/.cache
tls_letsencrypt_challenge_type: HTTP-01
unix_socket: /var/run/headscale.sock
unix_socket_permission: "0o770"
randomize_client_port: false
+31
View File
@@ -0,0 +1,31 @@
log:
level: trace
acl_policy_path: ""
db_type: sqlite3
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
dns_config:
override_local_dns: true
base_domain: headscale.net
magic_dns: true
domains: []
nameservers:
- 127.0.0.11
- 1.1.1.1
db_path: /tmp/integration_test_db.sqlite3
db_ssl: false
private_key_path: private.key
noise:
private_key_path: noise_private.key
listen_addr: 0.0.0.0:18080
metrics_listen_addr: 127.0.0.1:19090
server_url: http://headscale:18080
derp:
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: false
update_frequency: 1m
@@ -0,0 +1,55 @@
acl_policy_path: ""
cli:
insecure: false
timeout: 5s
db_path: /tmp/integration_test_db.sqlite3
db_ssl: false
db_type: sqlite3
derp:
auto_update_enabled: false
server:
enabled: false
stun:
enabled: true
update_frequency: 1m
urls:
- https://controlplane.tailscale.com/derpmap/default
dns_config:
override_local_dns: true
base_domain: headscale.net
domains: []
magic_dns: true
nameservers:
- 1.1.1.1
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 30s
grpc_allow_insecure: false
grpc_listen_addr: :50443
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
listen_addr: 0.0.0.0:18080
log:
level: disabled
format: text
logtail:
enabled: false
metrics_listen_addr: 127.0.0.1:19090
oidc:
expiry: 180d
only_start_if_oidc_is_available: true
scope:
- openid
- profile
- email
strip_email_domain: true
use_expiry_from_token: false
private_key_path: private.key
noise:
private_key_path: noise_private.key
server_url: http://headscale:18080
tls_letsencrypt_cache_dir: /var/www/.cache
tls_letsencrypt_challenge_type: HTTP-01
unix_socket: /var/run/headscale.sock
unix_socket_permission: "0o770"
randomize_client_port: false
+30
View File
@@ -0,0 +1,30 @@
log:
level: trace
acl_policy_path: ""
db_type: sqlite3
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 30s
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
dns_config:
override_local_dns: true
base_domain: headscale.net
magic_dns: true
domains: []
nameservers:
- 1.1.1.1
db_path: /tmp/integration_test_db.sqlite3
db_ssl: false
private_key_path: private.key
noise:
private_key_path: noise_private.key
listen_addr: 0.0.0.0:18080
metrics_listen_addr: 127.0.0.1:19090
server_url: http://headscale:18080
derp:
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: false
update_frequency: 1m
@@ -0,0 +1,56 @@
acl_policy_path: ""
cli:
insecure: false
timeout: 5s
db_path: /tmp/integration_test_db.sqlite3
db_ssl: false
db_type: sqlite3
derp:
auto_update_enabled: false
server:
enabled: false
stun:
enabled: true
update_frequency: 1m
urls:
- https://controlplane.tailscale.com/derpmap/default
dns_config:
override_local_dns: true
base_domain: headscale.net
domains: []
magic_dns: true
nameservers:
- 127.0.0.11
- 1.1.1.1
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
grpc_allow_insecure: false
grpc_listen_addr: :50443
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
listen_addr: 0.0.0.0:8080
log:
format: text
level: disabled
logtail:
enabled: false
metrics_listen_addr: 127.0.0.1:9090
oidc:
expiry: 180d
only_start_if_oidc_is_available: true
scope:
- openid
- profile
- email
strip_email_domain: true
use_expiry_from_token: false
private_key_path: private.key
noise:
private_key_path: noise_private.key
server_url: http://headscale:8080
tls_letsencrypt_cache_dir: /var/www/.cache
tls_letsencrypt_challenge_type: HTTP-01
unix_socket: /var/run/headscale.sock
unix_socket_permission: "0o770"
randomize_client_port: false
+30
View File
@@ -0,0 +1,30 @@
log:
level: trace
acl_policy_path: ""
db_type: sqlite3
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
dns_config:
override_local_dns: true
base_domain: headscale.net
magic_dns: true
domains: []
nameservers:
- 127.0.0.11
- 1.1.1.1
db_path: /tmp/integration_test_db.sqlite3
private_key_path: private.key
noise:
private_key_path: noise_private.key
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090
server_url: http://headscale:8080
derp:
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: false
update_frequency: 1m
@@ -0,0 +1,31 @@
log_level: trace
acl_policy_path: ""
db_type: sqlite3
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
dns_config:
base_domain: headscale.net
magic_dns: true
domains: []
nameservers:
- 1.1.1.1
db_path: /tmp/integration_test_db.sqlite3
private_key_path: private.key
noise:
private_key_path: noise_private.key
listen_addr: 0.0.0.0:443
server_url: https://headscale:443
tls_cert_path: "/etc/headscale/tls/server.crt"
tls_key_path: "/etc/headscale/tls/server.key"
tls_client_auth_mode: disabled
derp:
server:
enabled: true
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
stun_listen_addr: "0.0.0.0:3478"
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIC8jCCAdqgAwIBAgIULbu+UbSTMG/LtxooLLh7BgSEyqEwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJaGVhZHNjYWxlMCAXDTIyMDMwNTE2NDgwM1oYDzI1MjEx
MTA0MTY0ODAzWjAUMRIwEAYDVQQDDAloZWFkc2NhbGUwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDqcfpToLZUF0rlNwXkkt3lbyw4Cl4TJdx36o2PKaOK
U+tze/IjRsCWeMwrcR1o9TNZcxsD+c2J48D1WATuQJlMeg+2UJXGaTGRKkkbPMy3
5m7AFf/Q16UEOgm2NYjZaQ8faRGIMYURG/6sXmNeETJvBixpBev9yKJuVXgqHNS4
NpEkNwdOCuAZXrmw0HCbiusawJOay4tFvhH14rav8Uimonl8UTNVXufMzyUOuoaQ
TGflmzYX3hIoswRnTPlIWFoqObvx2Q8H+of3uQJXy0m8I6OrIoXLNxnqYMfFls79
9SYgVc2jPsCbh5fwyRbx2Hof7sIZ1K/mNgxJRG1E3ZiLAgMBAAGjOjA4MBQGA1Ud
EQQNMAuCCWhlYWRzY2FsZTALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUH
AwEwDQYJKoZIhvcNAQELBQADggEBANGlVN7NCsJaKz0k0nhlRGK+tcxn2p1PXN/i
Iy+JX8ahixPC4ocRwOhrXgb390ZXLLwq08HrWYRB/Wi1VUzCp5d8dVxvrR43dJ+v
L2EOBiIKgcu2C3pWW1qRR46/EoXUU9kSH2VNBvIhNufi32kEOidoDzxtQf6qVCoF
guUt1JkAqrynv1UvR/2ZRM/WzM/oJ8qfECwrwDxyYhkqU5Z5jCWg0C6kPIBvNdzt
B0eheWS+ZxVwkePTR4e17kIafwknth3lo+orxVrq/xC+OVM1bGrt2ZyD64ZvEqQl
w6kgbzBdLScAQptWOFThwhnJsg0UbYKimZsnYmjVEuN59TJv92M=
-----END CERTIFICATE-----
(Expires on Nov 4 16:48:03 2521 GMT)
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDqcfpToLZUF0rl
NwXkkt3lbyw4Cl4TJdx36o2PKaOKU+tze/IjRsCWeMwrcR1o9TNZcxsD+c2J48D1
WATuQJlMeg+2UJXGaTGRKkkbPMy35m7AFf/Q16UEOgm2NYjZaQ8faRGIMYURG/6s
XmNeETJvBixpBev9yKJuVXgqHNS4NpEkNwdOCuAZXrmw0HCbiusawJOay4tFvhH1
4rav8Uimonl8UTNVXufMzyUOuoaQTGflmzYX3hIoswRnTPlIWFoqObvx2Q8H+of3
uQJXy0m8I6OrIoXLNxnqYMfFls799SYgVc2jPsCbh5fwyRbx2Hof7sIZ1K/mNgxJ
RG1E3ZiLAgMBAAECggEBALu1Ni/u5Qy++YA8ZcN0s6UXNdhItLmv/q0kZuLQ+9et
CT8VZfFInLndTdsaXenDKLHdryunviFA8SV+q7P2lMbek+Xs735EiyMnMBFWxLIZ
FWNGOeQERGL19QCmLEOmEi2b+iWJQHlKaMWpbPXL3w11a+lKjIBNO4ALfoJ5QveZ
cGMKsJdm/mpqBvLeNeh2eAFk3Gp6sT1g80Ge8NkgyzFBNIqnut0eerM15kPTc6Qz
12JLaOXUuV3PrcB4PN4nOwrTDg88GDNOQtc1Pc9r4nOHyLfr8X7QEtj1wXSwmOuK
d6ynMnAmoxVA9wEnupLbil1bzohRzpsTpkmDruYaBEECgYEA/Z09I8D6mt2NVqIE
KyvLjBK39ijSV9r3/lvB2Ple2OOL5YQEd+yTrIFy+3zdUnDgD1zmNnXjmjvHZ9Lc
IFf2o06AF84QLNB5gLPdDQkGNFdDqUxljBrfAfE3oANmPS/B0SijMGOOOiDO2FtO
xl1nfRr78mswuRs9awoUWCdNRKUCgYEA7KaTYKIQW/FEjw9lshp74q5vbn6zoXF5
7N8VkwI+bBVNvRbM9XZ8qhfgRdu9eXs5oL/N4mSYY54I8fA//pJ0Z2vpmureMm1V
mL5WBUmSD9DIbAchoK+sRiQhVmNMBQC6cHMABA7RfXvBeGvWrm9pKCS6ZLgLjkjp
PsmAcaXQcW8CgYEA2inAxljjOwUK6FNGsrxhxIT1qtNC3kCGxE+6WSNq67gSR8Vg
8qiX//T7LEslOB3RIGYRwxd2St7RkgZZRZllmOWWWuPwFhzf6E7RAL2akLvggGov
kG4tGEagSw2hjVDfsUT73ExHtMk0Jfmlsg33UC8+PDLpHtLH6qQpDAwC8+ECgYEA
o+AqOIWhvHmT11l7O915Ip1WzvZwYADbxLsrDnVEUsZh4epTHjvh0kvcY6PqTqCV
ZIrOANNWb811Nkz/k8NJVoD08PFp0xPBbZeIq/qpachTsfMyRzq/mobUiyUR9Hjv
ooUQYr78NOApNsG+lWbTNBhS9wI4BlzZIECbcJe5g4MCgYEAndRoy8S+S0Hx/S8a
O3hzXeDmivmgWqn8NVD4AKOovpkz4PaIVVQbAQkiNfAx8/DavPvjEKAbDezJ4ECV
j7IsOWtDVI7pd6eF9fTcECwisrda8aUoiOap8AQb48153Vx+g2N4Vy3uH0xJs4cz
TDALZPOBg8VlV+HEFDP43sp9Bf0=
-----END PRIVATE KEY-----
@@ -0,0 +1,21 @@
log_level: trace
acl_policy_path: ""
db_type: sqlite3
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
db_path: /tmp/integration_test_db.sqlite3
private_key_path: private.key
noise:
private_key_path: noise_private.key
listen_addr: 0.0.0.0:8443
server_url: https://headscale-oidc:8443
tls_cert_path: "/etc/headscale/tls/server.crt"
tls_key_path: "/etc/headscale/tls/server.key"
derp:
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: true
update_frequency: 1m
+22
View File
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIC8jCCAdqgAwIBAgIULbu+UbSTMG/LtxooLLh7BgSEyqEwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJaGVhZHNjYWxlMCAXDTIyMDMwNTE2NDgwM1oYDzI1MjEx
MTA0MTY0ODAzWjAUMRIwEAYDVQQDDAloZWFkc2NhbGUwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDqcfpToLZUF0rlNwXkkt3lbyw4Cl4TJdx36o2PKaOK
U+tze/IjRsCWeMwrcR1o9TNZcxsD+c2J48D1WATuQJlMeg+2UJXGaTGRKkkbPMy3
5m7AFf/Q16UEOgm2NYjZaQ8faRGIMYURG/6sXmNeETJvBixpBev9yKJuVXgqHNS4
NpEkNwdOCuAZXrmw0HCbiusawJOay4tFvhH14rav8Uimonl8UTNVXufMzyUOuoaQ
TGflmzYX3hIoswRnTPlIWFoqObvx2Q8H+of3uQJXy0m8I6OrIoXLNxnqYMfFls79
9SYgVc2jPsCbh5fwyRbx2Hof7sIZ1K/mNgxJRG1E3ZiLAgMBAAGjOjA4MBQGA1Ud
EQQNMAuCCWhlYWRzY2FsZTALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUH
AwEwDQYJKoZIhvcNAQELBQADggEBANGlVN7NCsJaKz0k0nhlRGK+tcxn2p1PXN/i
Iy+JX8ahixPC4ocRwOhrXgb390ZXLLwq08HrWYRB/Wi1VUzCp5d8dVxvrR43dJ+v
L2EOBiIKgcu2C3pWW1qRR46/EoXUU9kSH2VNBvIhNufi32kEOidoDzxtQf6qVCoF
guUt1JkAqrynv1UvR/2ZRM/WzM/oJ8qfECwrwDxyYhkqU5Z5jCWg0C6kPIBvNdzt
B0eheWS+ZxVwkePTR4e17kIafwknth3lo+orxVrq/xC+OVM1bGrt2ZyD64ZvEqQl
w6kgbzBdLScAQptWOFThwhnJsg0UbYKimZsnYmjVEuN59TJv92M=
-----END CERTIFICATE-----
(Expires on Nov 4 16:48:03 2521 GMT)
+28
View File
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDqcfpToLZUF0rl
NwXkkt3lbyw4Cl4TJdx36o2PKaOKU+tze/IjRsCWeMwrcR1o9TNZcxsD+c2J48D1
WATuQJlMeg+2UJXGaTGRKkkbPMy35m7AFf/Q16UEOgm2NYjZaQ8faRGIMYURG/6s
XmNeETJvBixpBev9yKJuVXgqHNS4NpEkNwdOCuAZXrmw0HCbiusawJOay4tFvhH1
4rav8Uimonl8UTNVXufMzyUOuoaQTGflmzYX3hIoswRnTPlIWFoqObvx2Q8H+of3
uQJXy0m8I6OrIoXLNxnqYMfFls799SYgVc2jPsCbh5fwyRbx2Hof7sIZ1K/mNgxJ
RG1E3ZiLAgMBAAECggEBALu1Ni/u5Qy++YA8ZcN0s6UXNdhItLmv/q0kZuLQ+9et
CT8VZfFInLndTdsaXenDKLHdryunviFA8SV+q7P2lMbek+Xs735EiyMnMBFWxLIZ
FWNGOeQERGL19QCmLEOmEi2b+iWJQHlKaMWpbPXL3w11a+lKjIBNO4ALfoJ5QveZ
cGMKsJdm/mpqBvLeNeh2eAFk3Gp6sT1g80Ge8NkgyzFBNIqnut0eerM15kPTc6Qz
12JLaOXUuV3PrcB4PN4nOwrTDg88GDNOQtc1Pc9r4nOHyLfr8X7QEtj1wXSwmOuK
d6ynMnAmoxVA9wEnupLbil1bzohRzpsTpkmDruYaBEECgYEA/Z09I8D6mt2NVqIE
KyvLjBK39ijSV9r3/lvB2Ple2OOL5YQEd+yTrIFy+3zdUnDgD1zmNnXjmjvHZ9Lc
IFf2o06AF84QLNB5gLPdDQkGNFdDqUxljBrfAfE3oANmPS/B0SijMGOOOiDO2FtO
xl1nfRr78mswuRs9awoUWCdNRKUCgYEA7KaTYKIQW/FEjw9lshp74q5vbn6zoXF5
7N8VkwI+bBVNvRbM9XZ8qhfgRdu9eXs5oL/N4mSYY54I8fA//pJ0Z2vpmureMm1V
mL5WBUmSD9DIbAchoK+sRiQhVmNMBQC6cHMABA7RfXvBeGvWrm9pKCS6ZLgLjkjp
PsmAcaXQcW8CgYEA2inAxljjOwUK6FNGsrxhxIT1qtNC3kCGxE+6WSNq67gSR8Vg
8qiX//T7LEslOB3RIGYRwxd2St7RkgZZRZllmOWWWuPwFhzf6E7RAL2akLvggGov
kG4tGEagSw2hjVDfsUT73ExHtMk0Jfmlsg33UC8+PDLpHtLH6qQpDAwC8+ECgYEA
o+AqOIWhvHmT11l7O915Ip1WzvZwYADbxLsrDnVEUsZh4epTHjvh0kvcY6PqTqCV
ZIrOANNWb811Nkz/k8NJVoD08PFp0xPBbZeIq/qpachTsfMyRzq/mobUiyUR9Hjv
ooUQYr78NOApNsG+lWbTNBhS9wI4BlzZIECbcJe5g4MCgYEAndRoy8S+S0Hx/S8a
O3hzXeDmivmgWqn8NVD4AKOovpkz4PaIVVQbAQkiNfAx8/DavPvjEKAbDezJ4ECV
j7IsOWtDVI7pd6eF9fTcECwisrda8aUoiOap8AQb48153Vx+g2N4Vy3uH0xJs4cz
TDALZPOBg8VlV+HEFDP43sp9Bf0=
-----END PRIVATE KEY-----

Some files were not shown because too many files have changed in this diff Show More