Compare commits

..

2 Commits

Author SHA1 Message Date
Juan Font Alonso
5539ef1f8f Reduce the number of containers 2022-08-04 21:36:38 +02:00
Juan Font Alonso
100f7190f3 Temporary fix integration tests with dedicated Dockerfile 2022-07-31 10:44:09 +02:00
11 changed files with 98 additions and 71 deletions

View File

@@ -11,11 +11,6 @@ jobs:
with: with:
fetch-depth: 2 fetch-depth: 2
- name: Set Swap Space
uses: pierotofy/set-swap-space@master
with:
swap-size-gb: 10
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
uses: tj-actions/changed-files@v14.1 uses: tj-actions/changed-files@v14.1
@@ -30,29 +25,11 @@ jobs:
- uses: cachix/install-nix-action@v16 - uses: cachix/install-nix-action@v16
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
- name: Run CLI integration tests - name: Run Integration tests
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
uses: nick-fields/retry@v2 uses: nick-fields/retry@v2
with: with:
timeout_minutes: 240 timeout_minutes: 240
max_attempts: 5 max_attempts: 5
retry_on: error retry_on: error
command: nix develop --command -- make test_integration_cli command: nix develop --command -- make test_integration
- name: Run Embedded DERP server integration tests
if: steps.changed-files.outputs.any_changed == 'true'
uses: nick-fields/retry@v2
with:
timeout_minutes: 240
max_attempts: 5
retry_on: error
command: nix develop --command -- make test_integration_derp
- name: Run general integration tests
if: steps.changed-files.outputs.any_changed == 'true'
uses: nick-fields/retry@v2
with:
timeout_minutes: 240
max_attempts: 5
retry_on: error
command: nix develop --command -- make test_integration_general

View File

@@ -1,5 +1,5 @@
# Builder image # Builder image
FROM docker.io/golang:1.18.0-bullseye AS build FROM --platform=$BUILDPLATFORM docker.io/golang:1.18.0-bullseye AS build
ARG VERSION=dev ARG VERSION=dev
ENV GOPATH /go ENV GOPATH /go
WORKDIR /go/src/headscale WORKDIR /go/src/headscale
@@ -8,9 +8,8 @@ COPY go.mod go.sum /go/src/headscale/
RUN go mod download RUN go mod download
COPY . . COPY . .
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /go/bin/headscale -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale
RUN strip /go/bin/headscale
RUN test -e /go/bin/headscale RUN test -e /go/bin/headscale
# Production image # Production image

View File

@@ -1,5 +1,5 @@
# Builder image # Builder image
FROM docker.io/golang:1.18.0-alpine AS build FROM --platform=$BUILDPLATFORM docker.io/golang:1.18.0-alpine AS build
ARG VERSION=dev ARG VERSION=dev
ENV GOPATH /go ENV GOPATH /go
WORKDIR /go/src/headscale WORKDIR /go/src/headscale
@@ -10,8 +10,8 @@ RUN go mod download
COPY . . COPY . .
RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale ARG TARGETOS TARGETARCH
RUN strip /go/bin/headscale RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /go/bin/headscale -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale
RUN test -e /go/bin/headscale RUN test -e /go/bin/headscale
# Production image # Production image

View File

@@ -1,5 +1,5 @@
# Builder image # Builder image
FROM docker.io/golang:1.18.0-bullseye AS build FROM --platform=$BUILDPLATFORM docker.io/golang:1.18.0-bullseye AS build
ARG VERSION=dev ARG VERSION=dev
ENV GOPATH /go ENV GOPATH /go
WORKDIR /go/src/headscale WORKDIR /go/src/headscale
@@ -9,6 +9,7 @@ RUN go mod download
COPY . . COPY . .
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale
RUN test -e /go/bin/headscale RUN test -e /go/bin/headscale

View File

@@ -0,0 +1,21 @@
# Builder image
FROM docker.io/golang:1.18.0-bullseye AS build
ARG VERSION=dev
ENV GOPATH /go
WORKDIR /go/src/headscale
COPY go.mod go.sum /go/src/headscale/
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /go/bin/headscale -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale
RUN test -e /go/bin/headscale
# Production image
FROM gcr.io/distroless/base-debian11
COPY --from=build /go/bin/headscale /bin/headscale
ENV TZ UTC
EXPOSE 8080/tcp
CMD ["headscale"]

View File

@@ -24,16 +24,14 @@ dev: lint test build
test: test:
@go test -coverprofile=coverage.out ./... @go test -coverprofile=coverage.out ./...
test_integration: test_integration_cli test_integration_derp test_integration_general test_integration:
go test -failfast -tags integration -timeout 30m -count=1 ./...
test_integration_cli: test_integration_cli:
go test -failfast -tags integration_cli,integration -timeout 30m -count=1 ./... go test -tags integration -v integration_cli_test.go integration_common_test.go
test_integration_derp: test_integration_derp:
go test -failfast -tags integration_derp,integration -timeout 30m -count=1 ./... go test -tags integration -v integration_embedded_derp_test.go integration_common_test.go
test_integration_general:
go test -failfast -tags integration_general,integration -timeout 30m -count=1 ./...
coverprofile_func: coverprofile_func:
go tool cover -func=coverage.out go tool cover -func=coverage.out

View File

@@ -0,0 +1,32 @@
# Build docker from scratch
The Dockerfiles included in the repository are using the [buildx plugin](https://docs.docker.com/buildx/working-with-buildx/). This plugin is includes in docker newer than Docker-ce CLI 19.03.2. The plugin is used to be able to build different container arches. Building the Dockerfiles without buildx is not possible.
# Build native
To build the container on the native arch you can just use:
```
$ sudo docker buildx build -t headscale:custom-arch .
```
For example: This will build a amd64(x86_64) container if your hostsystem is amd64(x86_64). Or a arm64 container on a arm64 hostsystem (raspberry pi4).
# Build cross platform
To build a arm64 container on a amd64 hostsystem you could use:
```
$ sudo docker buildx build --platform linux/arm64 -t headscale:custom-arm64 .
```
**Import: Currently arm32 build are not supported as there is a problem with a library used by headscale. Hopefully this will be fixed soon.**
# Build multiple arches
To build multiple archres you could use:
```
$ sudo docker buildx create --use
$ sudo docker buildx build --platform linux/amd64,linux/arm64 .
```

View File

@@ -1,4 +1,5 @@
//go:build integration_cli //go:build integration
// +build integration
package headscale package headscale
@@ -49,7 +50,7 @@ func (s *IntegrationCLITestSuite) SetupTest() {
} }
headscaleBuildOptions := &dockertest.BuildOptions{ headscaleBuildOptions := &dockertest.BuildOptions{
Dockerfile: "Dockerfile", Dockerfile: "Dockerfile.tmp-integration",
ContextDir: ".", ContextDir: ".",
} }
@@ -72,22 +73,21 @@ func (s *IntegrationCLITestSuite) SetupTest() {
s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "") s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "")
} }
fmt.Println("Creating headscale container for CLI tests") fmt.Println("Creating headscale container")
if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil {
s.headscale = *pheadscale s.headscale = *pheadscale
} else { } else {
s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "") s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "")
} }
fmt.Println("Created headscale container for CLI tests") fmt.Println("Created headscale container")
fmt.Println("Waiting for headscale to be ready for CLI tests") fmt.Println("Waiting for headscale to be ready")
hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp")) hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp"))
if err := s.pool.Retry(func() error { if err := s.pool.Retry(func() error {
url := fmt.Sprintf("http://%s/health", hostEndpoint) url := fmt.Sprintf("http://%s/health", hostEndpoint)
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
fmt.Printf("headscale for CLI test is not ready: %s\n", err)
return err return err
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
@@ -102,7 +102,7 @@ func (s *IntegrationCLITestSuite) SetupTest() {
// https://github.com/stretchr/testify/issues/849 // https://github.com/stretchr/testify/issues/849
return // fmt.Errorf("Could not connect to headscale: %s", err) return // fmt.Errorf("Could not connect to headscale: %s", err)
} }
fmt.Println("headscale container is ready for CLI tests") fmt.Println("headscale container is ready")
} }
func (s *IntegrationCLITestSuite) TearDownTest() { func (s *IntegrationCLITestSuite) TearDownTest() {

View File

@@ -1,4 +1,5 @@
//go:build integration //go:build integration
// +build integration
package headscale package headscale
@@ -19,7 +20,6 @@ import (
) )
const ( const (
headscaleHostname = "headscale-derp"
DOCKER_EXECUTE_TIMEOUT = 10 * time.Second DOCKER_EXECUTE_TIMEOUT = 10 * time.Second
) )
@@ -30,10 +30,9 @@ var (
IpPrefix6 = netaddr.MustParseIPPrefix("fd7a:115c:a1e0::/48") IpPrefix6 = netaddr.MustParseIPPrefix("fd7a:115c:a1e0::/48")
tailscaleVersions = []string{ tailscaleVersions = []string{
// "head", "head",
// "unstable", "unstable",
"1.28.0", "1.26.0",
"1.26.2",
"1.24.2", "1.24.2",
"1.22.2", "1.22.2",
"1.20.4", "1.20.4",

View File

@@ -1,4 +1,4 @@
//go:build integration_derp //go:build integration
package headscale package headscale
@@ -28,8 +28,9 @@ import (
) )
const ( const (
namespaceName = "derpnamespace" headscaleHostname = "headscale-derp"
totalContainers = 3 namespaceName = "derpnamespace"
totalContainers = 3
) )
type IntegrationDERPTestSuite struct { type IntegrationDERPTestSuite struct {
@@ -103,7 +104,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
} }
headscaleBuildOptions := &dockertest.BuildOptions{ headscaleBuildOptions := &dockertest.BuildOptions{
Dockerfile: "Dockerfile", Dockerfile: "Dockerfile.tmp-integration",
ContextDir: ".", ContextDir: ".",
} }
@@ -133,15 +134,15 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "") s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "")
} }
log.Println("Creating headscale container for DERP integration tests") log.Println("Creating headscale container")
if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil {
s.headscale = *pheadscale s.headscale = *pheadscale
} else { } else {
s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "") s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "")
} }
log.Println("Created headscale container for embedded DERP tests") log.Println("Created headscale container to test DERP")
log.Println("Creating tailscale containers for embedded DERP tests") log.Println("Creating tailscale containers")
for i := 0; i < totalContainers; i++ { for i := 0; i < totalContainers; i++ {
version := tailscaleVersions[i%len(tailscaleVersions)] version := tailscaleVersions[i%len(tailscaleVersions)]
@@ -153,7 +154,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
s.tailscales[hostname] = *container s.tailscales[hostname] = *container
} }
log.Println("Waiting for headscale to be ready for embedded DERP tests") log.Println("Waiting for headscale to be ready")
hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8443/tcp")) hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8443/tcp"))
if err := s.pool.Retry(func() error { if err := s.pool.Retry(func() error {
@@ -163,7 +164,6 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
client := &http.Client{Transport: insecureTransport} client := &http.Client{Transport: insecureTransport}
resp, err := client.Get(url) resp, err := client.Get(url)
if err != nil { if err != nil {
fmt.Printf("headscale for embedded DERP tests is not ready: %s\n", err)
return err return err
} }
@@ -179,7 +179,7 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
// https://github.com/stretchr/testify/issues/849 // https://github.com/stretchr/testify/issues/849
return // fmt.Errorf("Could not connect to headscale: %s", err) return // fmt.Errorf("Could not connect to headscale: %s", err)
} }
log.Println("headscale container is ready for embedded DERP tests") log.Println("headscale container is ready")
log.Printf("Creating headscale namespace: %s\n", namespaceName) log.Printf("Creating headscale namespace: %s\n", namespaceName)
result, err := ExecuteCommand( result, err := ExecuteCommand(

View File

@@ -1,4 +1,5 @@
//go:build integration_general //go:build integration
// +build integration
package headscale package headscale
@@ -52,7 +53,7 @@ func TestIntegrationTestSuite(t *testing.T) {
s.namespaces = map[string]TestNamespace{ s.namespaces = map[string]TestNamespace{
"thisspace": { "thisspace": {
count: 10, count: 5,
tailscales: make(map[string]dockertest.Resource), tailscales: make(map[string]dockertest.Resource),
}, },
"otherspace": { "otherspace": {
@@ -227,7 +228,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
} }
headscaleBuildOptions := &dockertest.BuildOptions{ headscaleBuildOptions := &dockertest.BuildOptions{
Dockerfile: "Dockerfile", Dockerfile: "Dockerfile.tmp-integration",
ContextDir: ".", ContextDir: ".",
} }
@@ -250,15 +251,15 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "") s.FailNow(fmt.Sprintf("Could not remove existing container before building test: %s", err), "")
} }
log.Println("Creating headscale container for core integration tests") log.Println("Creating headscale container")
if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil { if pheadscale, err := s.pool.BuildAndRunWithBuildOptions(headscaleBuildOptions, headscaleOptions, DockerRestartPolicy); err == nil {
s.headscale = *pheadscale s.headscale = *pheadscale
} else { } else {
s.FailNow(fmt.Sprintf("Could not start headscale container for core integration tests: %s", err), "") s.FailNow(fmt.Sprintf("Could not start headscale container: %s", err), "")
} }
log.Println("Created headscale container for core integration tests") log.Println("Created headscale container")
log.Println("Creating tailscale containers for core integration tests") log.Println("Creating tailscale containers")
for namespace, scales := range s.namespaces { for namespace, scales := range s.namespaces {
for i := 0; i < scales.count; i++ { for i := 0; i < scales.count; i++ {
version := tailscaleVersions[i%len(tailscaleVersions)] version := tailscaleVersions[i%len(tailscaleVersions)]
@@ -272,7 +273,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
} }
} }
log.Println("Waiting for headscale to be ready for core integration tests") log.Println("Waiting for headscale to be ready")
hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp")) hostEndpoint := fmt.Sprintf("localhost:%s", s.headscale.GetPort("8080/tcp"))
if err := s.pool.Retry(func() error { if err := s.pool.Retry(func() error {
@@ -280,7 +281,6 @@ func (s *IntegrationTestSuite) SetupSuite() {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
fmt.Printf("headscale for core integration test is not ready: %s\n", err)
return err return err
} }
@@ -296,7 +296,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
// https://github.com/stretchr/testify/issues/849 // https://github.com/stretchr/testify/issues/849
return // fmt.Errorf("Could not connect to headscale: %s", err) return // fmt.Errorf("Could not connect to headscale: %s", err)
} }
log.Println("headscale container is ready for core integration tests") log.Println("headscale container is ready")
for namespace, scales := range s.namespaces { for namespace, scales := range s.namespaces {
log.Printf("Creating headscale namespace: %s\n", namespace) log.Printf("Creating headscale namespace: %s\n", namespace)