refactor: kresify, fix linter and rename to Kubespan manager

Tried to limit the scope of changes.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
This commit is contained in:
Artem Chernyshev
2021-08-13 16:12:38 +03:00
parent d782452e86
commit 6454cfcb72
20 changed files with 1128 additions and 107 deletions

18
.codecov.yml Normal file
View File

@ -0,0 +1,18 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
codecov:
require_ci_to_pass: false
coverage:
status:
project:
default:
target: 50%
threshold: 0.5%
base: auto
if_ci_failed: success
patch: off
comment: false

35
.conform.yaml Normal file
View File

@ -0,0 +1,35 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
policies:
- type: commit
spec:
dco: true
gpg: false
spellcheck:
locale: US
maximumOfOneCommit: true
header:
length: 89
imperative: true
case: lower
invalidLastCharacters: .
body:
required: true
conventional:
types: ["chore","docs","perf","refactor","style","test","release"]
scopes: [".*"]
- type: license
spec:
skipPaths:
- .git/
includeSuffixes:
- .go
excludeSuffixes:
- .pb.go
- .pb.gw.go
header: |
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

13
.dockerignore Normal file
View File

@ -0,0 +1,13 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:32:42Z by kres 907039b.
**
!internal
!pkg
!cmd
!go.mod
!go.sum
!.golangci.yml
!README.md
!.markdownlint.json

340
.drone.yml Normal file
View File

@ -0,0 +1,340 @@
---
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:23:41Z by kres 907039b.
kind: pipeline
type: kubernetes
name: default
platform:
os: linux
arch: amd64
steps:
- name: setup-ci
pull: always
image: autonomy/build-container:latest
commands:
- sleep 5
- git fetch --tags
- install-ci-key
- docker buildx create --driver docker-container --platform linux/amd64 --name local --use unix:///var/outer-run/docker.sock
- docker buildx inspect --bootstrap
environment:
SSH_KEY:
from_secret: ssh_key
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
- name: base
pull: always
image: autonomy/build-container:latest
commands:
- make base
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- setup-ci
- name: unit-tests
pull: always
image: autonomy/build-container:latest
commands:
- make unit-tests
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- base
- name: unit-tests-race
pull: always
image: autonomy/build-container:latest
commands:
- make unit-tests-race
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- base
- name: coverage
pull: always
image: autonomy/build-container:latest
commands:
- make coverage
environment:
CODECOV_TOKEN:
from_secret: CODECOV_TOKEN
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- unit-tests
- name: kubespan-manager
pull: always
image: autonomy/build-container:latest
commands:
- make kubespan-manager
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- base
- name: lint
pull: always
image: autonomy/build-container:latest
commands:
- make lint
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- base
- name: image-kubespan-manager
pull: always
image: autonomy/build-container:latest
commands:
- make image-kubespan-manager
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
depends_on:
- kubespan-manager
- lint
- unit-tests
- name: push-kubespan-manager
pull: always
image: autonomy/build-container:latest
commands:
- docker login ghcr.io --username "$${GHCR_USERNAME}" --password "$${GHCR_PASSWORD}"
- make image-kubespan-manager
environment:
GHCR_PASSWORD:
from_secret: ghcr_token
GHCR_USERNAME:
from_secret: ghcr_username
PUSH: true
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
when:
event:
exclude:
- pull_request
depends_on:
- image-kubespan-manager
- name: push-kubespan-manager-latest
pull: always
image: autonomy/build-container:latest
commands:
- docker login ghcr.io --username "$${GHCR_USERNAME}" --password "$${GHCR_PASSWORD}"
- make image-kubespan-manager TAG=latest
environment:
GHCR_PASSWORD:
from_secret: ghcr_token
GHCR_USERNAME:
from_secret: ghcr_username
PUSH: true
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
when:
branch:
- master
event:
exclude:
- pull_request
depends_on:
- push-kubespan-manager
- name: release-notes
pull: always
image: autonomy/build-container:latest
commands:
- make release-notes
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
when:
event:
- tag
depends_on:
- unit-tests
- coverage
- kubespan-manager
- image-kubespan-manager
- lint
- name: release
pull: always
image: plugins/github-release
settings:
api_key:
from_secret: github_token
checksum:
- sha256
- sha512
draft: true
files:
- _out/*
note: _out/RELEASE_NOTES.md
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
when:
event:
- tag
depends_on:
- release-notes
services:
- name: docker
image: docker:19.03-dind
entrypoint:
- dockerd
commands:
- --dns=8.8.8.8
- --dns=8.8.4.4
- --mtu=1500
- --log-level=error
privileged: true
volumes:
- name: outer-docker-socket
path: /var/outer-run
- name: docker-socket
path: /var/run
- name: buildx
path: /root/.docker/buildx
- name: ssh
path: /root/.ssh
volumes:
- name: outer-docker-socket
host:
path: /var/ci-docker
- name: docker-socket
temp:
medium: memory
- name: buildx
temp:
medium: memory
- name: ssh
temp:
medium: memory
---
kind: pipeline
type: kubernetes
name: notify
platform:
os: linux
arch: amd64
clone:
disable: true
steps:
- name: slack
image: plugins/slack
settings:
channel: proj-talos-maintainers
link_names: true
template: "{{#if build.pull }}\n*{{#success build.status}}✓ Success{{else}}✕ Fail{{/success}}*: {{ repo.owner }}/{{ repo.name }} - <https://github.com/{{ repo.owner }}/{{ repo.name }}/pull/{{ build.pull }}|Pull Request #{{ build.pull }}>\n{{else}}\n*{{#success build.status}}✓ Success{{else}}✕ Fail{{/success}}: {{ repo.owner }}/{{ repo.name }} - Build #{{ build.number }}* (type: `{{ build.event }}`)\n{{/if}}\nCommit: <https://github.com/{{ repo.owner }}/{{ repo.name }}/commit/{{ build.commit }}|{{ truncate build.commit 8 }}>\nBranch: <https://github.com/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>\nAuthor: {{ build.author }}\n<{{ build.link }}|Visit build page>"
webhook:
from_secret: slack_webhook
when:
status:
- success
- failure
trigger:
status:
- success
- failure
depends_on:
- default
...

6
.gitignore vendored
View File

@ -1 +1,5 @@
/wglan-manager
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
_out

150
.golangci.yml Normal file
View File

@ -0,0 +1,150 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:32:42Z by kres 907039b.
# options for analysis running
run:
timeout: 10m
issues-exit-code: 1
tests: true
build-tags: []
skip-dirs: []
skip-dirs-use-default: true
skip-files: []
modules-download-mode: readonly
# output configuration options
output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true
uniq-by-line: true
path-prefix: ""
# all available settings of specific linters
linters-settings:
dogsled:
max-blank-identifiers: 2
dupl:
threshold: 150
errcheck:
check-type-assertions: true
check-blank: true
exhaustive:
default-signifies-exhaustive: false
funlen:
lines: 60
statements: 40
gci:
local-prefixes: github.com/talos-systems/kubespan-manager
gocognit:
min-complexity: 30
nestif:
min-complexity: 5
goconst:
min-len: 3
min-occurrences: 3
gocritic:
disabled-checks: []
gocyclo:
min-complexity: 20
godot:
check-all: false
godox:
keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
- NOTE
- OPTIMIZE # marks code that should be optimized before merging
- HACK # marks hack-arounds that should be removed before merging
gofmt:
simplify: true
goimports:
local-prefixes: github.com/talos-systems/kubespan-manager
golint:
min-confidence: 0.8
gomnd:
settings: {}
gomodguard: {}
govet:
check-shadowing: true
enable-all: true
depguard:
list-type: blacklist
include-go-root: false
lll:
line-length: 200
tab-width: 4
misspell:
locale: US
ignore-words: []
nakedret:
max-func-lines: 30
prealloc:
simple: true
range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default
nolintlint:
allow-unused: false
allow-leading-space: false
allow-no-explanation: []
require-explanation: false
require-specific: true
rowserrcheck: {}
testpackage:
unparam:
check-exported: false
unused:
check-exported: false
whitespace:
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
wsl:
strict-append: true
allow-assign-and-call: true
allow-multiline-assign: true
allow-cuddle-declarations: false
allow-trailing-comment: false
force-case-trailing-whitespace: 0
force-err-cuddling: false
allow-separated-leading-comment: false
gofumpt:
extra-rules: false
cyclop:
# the maximal code complexity to report
max-complexity: 20
linters:
enable-all: true
disable:
- gas
- typecheck
- gochecknoglobals
- gochecknoinits
- funlen
- godox
- gomnd
- goerr113
- nestif
- wrapcheck
- paralleltest
- exhaustivestruct
- forbidigo
disable-all: false
fast: false
issues:
exclude: []
exclude-rules: []
exclude-use-default: false
exclude-case-sensitive: false
max-issues-per-linter: 10
max-same-issues: 3
new: false
severity:
default-severity: error
case-sensitive: false

9
.markdownlint.json Normal file
View File

@ -0,0 +1,9 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
{
"MD013": false,
"MD033": false,
"default": true
}

View File

@ -1,12 +1,96 @@
FROM golang:alpine AS builder
ENV GO111MODULE on
RUN apk add --no-cache git
WORKDIR $GOPATH/src/github.com/talos-systems/wglan-manager
COPY . .
RUN go get -d -v
RUN go build -o /go/bin/web
# syntax = docker/dockerfile-upstream:1.2.0-labs
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:32:42Z by kres 907039b.
ARG TOOLCHAIN
# cleaned up specs and compiled versions
FROM scratch AS generate
FROM ghcr.io/talos-systems/ca-certificates:v0.3.0-12-g90722c3 AS image-ca-certificates
FROM ghcr.io/talos-systems/fhs:v0.3.0-12-g90722c3 AS image-fhs
# runs markdownlint
FROM node:14.8.0-alpine AS lint-markdown
RUN npm i -g markdownlint-cli@0.23.2
RUN npm i sentences-per-line@0.2.1
WORKDIR /src
COPY .markdownlint.json .
COPY ./README.md ./README.md
RUN markdownlint --ignore "CHANGELOG.md" --ignore "**/node_modules/**" --ignore '**/hack/chglog/**' --rules /node_modules/sentences-per-line/index.js .
# base toolchain image
FROM ${TOOLCHAIN} AS toolchain
RUN apk --update --no-cache add bash curl build-base protoc protobuf-dev
# build tools
FROM toolchain AS tools
ENV GO111MODULE on
ENV CGO_ENABLED 0
ENV GOPATH /go
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b /bin v1.38.0
ARG GOFUMPT_VERSION
RUN cd $(mktemp -d) \
&& go mod init tmp \
&& go get mvdan.cc/gofumpt/gofumports@${GOFUMPT_VERSION} \
&& mv /go/bin/gofumports /bin/gofumports
# tools and sources
FROM tools AS base
WORKDIR /src
COPY ./go.mod .
COPY ./go.sum .
RUN --mount=type=cache,target=/go/pkg go mod download
RUN --mount=type=cache,target=/go/pkg go mod verify
COPY ./internal ./internal
COPY ./pkg ./pkg
COPY ./cmd ./cmd
RUN --mount=type=cache,target=/go/pkg go list -mod=readonly all >/dev/null
# builds kubespan-manager-linux-amd64
FROM base AS kubespan-manager-linux-amd64-build
COPY --from=generate / /
WORKDIR /src/cmd/kubespan-manager
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg go build -ldflags "-s -w" -o /kubespan-manager-linux-amd64
# runs gofumpt
FROM base AS lint-gofumpt
RUN find . -name '*.pb.go' | xargs -r rm
RUN find . -name '*.pb.gw.go' | xargs -r rm
RUN FILES="$(gofumports -l -local github.com/talos-systems/kubespan-manager .)" && test -z "${FILES}" || (echo -e "Source code is not formatted with 'gofumports -w -local github.com/talos-systems/kubespan-manager .':\n${FILES}"; exit 1)
# runs golangci-lint
FROM base AS lint-golangci-lint
COPY .golangci.yml .
ENV GOGC 50
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/root/.cache/golangci-lint --mount=type=cache,target=/go/pkg golangci-lint run --config .golangci.yml
# runs unit-tests with race detector
FROM base AS unit-tests-race
ARG TESTPKGS
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg --mount=type=cache,target=/tmp CGO_ENABLED=1 go test -v -race -count 1 ${TESTPKGS}
# runs unit-tests
FROM base AS unit-tests-run
ARG TESTPKGS
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/go/pkg --mount=type=cache,target=/tmp go test -v -covermode=atomic -coverprofile=coverage.txt -coverpkg=${TESTPKGS} -count 1 ${TESTPKGS}
FROM scratch AS kubespan-manager-linux-amd64
COPY --from=kubespan-manager-linux-amd64-build /kubespan-manager-linux-amd64 /kubespan-manager-linux-amd64
FROM scratch AS unit-tests
COPY --from=unit-tests-run /src/coverage.txt /coverage.txt
FROM kubespan-manager-linux-${TARGETARCH} AS kubespan-manager
FROM scratch AS image-kubespan-manager
ARG TARGETARCH
COPY --from=kubespan-manager kubespan-manager-linux-${TARGETARCH} /kubespan-manager
COPY --from=image-fhs / /
COPY --from=image-ca-certificates / /
LABEL org.opencontainers.image.source https://github.com/talos-systems/wglan-manager
ENTRYPOINT ["/kubespan-manager"]
FROM alpine
RUN apk add --no-cache ca-certificates
COPY --from=builder /go/bin/web /go/bin/web
ENTRYPOINT ["/go/bin/web"]

154
Makefile Normal file
View File

@ -0,0 +1,154 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:32:42Z by kres 907039b.
# common variables
SHA := $(shell git describe --match=none --always --abbrev=8 --dirty)
TAG := $(shell git describe --tag --always --dirty)
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
ARTIFACTS := _out
REGISTRY ?= ghcr.io
USERNAME ?= talos-systems
REGISTRY_AND_USERNAME ?= $(REGISTRY)/$(USERNAME)
GOFUMPT_VERSION ?= abc0db2c416aca0f60ea33c23c76665f6e7ba0b6
GO_VERSION ?= 1.16
PROTOBUF_GO_VERSION ?= 1.25.0
GRPC_GO_VERSION ?= 1.1.0
GRPC_GATEWAY_VERSION ?= 2.4.0
TESTPKGS ?= ./...
KRES_IMAGE ?= ghcr.io/talos-systems/kres:latest
# docker build settings
BUILD := docker buildx build
PLATFORM ?= linux/amd64
PROGRESS ?= auto
PUSH ?= false
CI_ARGS ?=
COMMON_ARGS = --file=Dockerfile
COMMON_ARGS += --progress=$(PROGRESS)
COMMON_ARGS += --platform=$(PLATFORM)
COMMON_ARGS += --push=$(PUSH)
COMMON_ARGS += --build-arg=ARTIFACTS=$(ARTIFACTS)
COMMON_ARGS += --build-arg=SHA=$(SHA)
COMMON_ARGS += --build-arg=TAG=$(TAG)
COMMON_ARGS += --build-arg=USERNAME=$(USERNAME)
COMMON_ARGS += --build-arg=TOOLCHAIN=$(TOOLCHAIN)
COMMON_ARGS += --build-arg=GOFUMPT_VERSION=$(GOFUMPT_VERSION)
COMMON_ARGS += --build-arg=PROTOBUF_GO_VERSION=$(PROTOBUF_GO_VERSION)
COMMON_ARGS += --build-arg=GRPC_GO_VERSION=$(GRPC_GO_VERSION)
COMMON_ARGS += --build-arg=GRPC_GATEWAY_VERSION=$(GRPC_GATEWAY_VERSION)
COMMON_ARGS += --build-arg=TESTPKGS=$(TESTPKGS)
TOOLCHAIN ?= docker.io/golang:1.16-alpine
# help menu
export define HELP_MENU_HEADER
# Getting Started
To build this project, you must have the following installed:
- git
- make
- docker (19.03 or higher)
## Creating a Builder Instance
The build process makes use of experimental Docker features (buildx).
To enable experimental features, add 'experimental: "true"' to '/etc/docker/daemon.json' on
Linux or enable experimental features in Docker GUI for Windows or Mac.
To create a builder instance, run:
docker buildx create --name local --use
If you already have a compatible builder instance, you may use that instead.
## Artifacts
All artifacts will be output to ./$(ARTIFACTS). Images will be tagged with the
registry "$(REGISTRY)", username "$(USERNAME)", and a dynamic tag (e.g. $(IMAGE):$(TAG)).
The registry and username can be overridden by exporting REGISTRY, and USERNAME
respectively.
endef
all: unit-tests kubespan-manager image-kubespan-manager lint
.PHONY: clean
clean: ## Cleans up all artifacts.
@rm -rf $(ARTIFACTS)
target-%: ## Builds the specified target defined in the Dockerfile. The build result will only remain in the build cache.
@$(BUILD) --target=$* $(COMMON_ARGS) $(TARGET_ARGS) $(CI_ARGS) .
local-%: ## Builds the specified target defined in the Dockerfile using the local output type. The build result will be output to the specified local destination.
@$(MAKE) target-$* TARGET_ARGS="--output=type=local,dest=$(DEST) $(TARGET_ARGS)"
lint-golangci-lint: ## Runs golangci-lint linter.
@$(MAKE) target-$@
lint-gofumpt: ## Runs gofumpt linter.
@$(MAKE) target-$@
.PHONY: fmt
fmt: ## Formats the source code
@docker run --rm -it -v $(PWD):/src -w /src golang:$(GO_VERSION) \
bash -c "export GO111MODULE=on; export GOPROXY=https://proxy.golang.org; \
cd /tmp && go mod init tmp && go get mvdan.cc/gofumpt/gofumports@$(GOFUMPT_VERSION) && \
cd - && gofumports -w -local github.com/talos-systems/kubespan-manager ."
.PHONY: base
base: ## Prepare base toolchain
@$(MAKE) target-$@
.PHONY: unit-tests
unit-tests: ## Performs unit tests
@$(MAKE) local-$@ DEST=$(ARTIFACTS)
.PHONY: unit-tests-race
unit-tests-race: ## Performs unit tests with race detection enabled.
@$(MAKE) target-$@
.PHONY: coverage
coverage: ## Upload coverage data to codecov.io.
bash -c "bash <(curl -s https://codecov.io/bash) -f $(ARTIFACTS)/coverage.txt -X fix"
.PHONY: $(ARTIFACTS)/kubespan-manager-linux-amd64
$(ARTIFACTS)/kubespan-manager-linux-amd64:
@$(MAKE) local-kubespan-manager-linux-amd64 DEST=$(ARTIFACTS)
.PHONY: kubespan-manager-linux-amd64
kubespan-manager-linux-amd64: $(ARTIFACTS)/kubespan-manager-linux-amd64 ## Builds executable for kubespan-manager-linux-amd64.
.PHONY: kubespan-manager
kubespan-manager: kubespan-manager-linux-amd64
.PHONY: lint-markdown
lint-markdown: ## Runs markdownlint.
@$(MAKE) target-$@
.PHONY: lint
lint: lint-golangci-lint lint-gofumpt lint-markdown ## Run all linters for the project.
.PHONY: image-kubespan-manager
image-kubespan-manager: ## Builds image for kubespan-manager.
@$(MAKE) target-$@ TARGET_ARGS="--tag=$(REGISTRY)/$(USERNAME)/kubespan-manager:$(TAG)"
.PHONY: rekres
rekres:
@docker pull $(KRES_IMAGE)
@docker run --rm -v $(PWD):/src -w /src -e GITHUB_TOKEN $(KRES_IMAGE)
.PHONY: help
help: ## This help menu.
@echo "$$HELP_MENU_HEADER"
@grep -E '^[a-zA-Z%_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: release-notes
release-notes:
mkdir -p $(ARTIFACTS)
@ARTIFACTS=$(ARTIFACTS) ./hack/release.sh $@ $(ARTIFACTS)/RELEASE_NOTES.md $(TAG)

View File

@ -1,6 +1,11 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package main
import (
"errors"
"flag"
"log"
"net/http"
@ -8,15 +13,16 @@ import (
"time"
"github.com/gofiber/fiber/v2"
"github.com/talos-systems/wglan-manager/db"
"github.com/talos-systems/wglan-manager/types"
"go.uber.org/zap"
"github.com/talos-systems/kubespan-manager/internal/db"
"github.com/talos-systems/kubespan-manager/pkg/types"
)
var listenAddr = ":3000"
var devMode bool
const defaultPort = 5000
var (
listenAddr = ":3000"
devMode bool
)
var nodeDB db.DB
@ -25,31 +31,29 @@ func init() {
flag.BoolVar(&devMode, "debug", false, "enable debug mode")
}
//nolint:gocognit
func main() {
flag.Parse()
logger, err := zap.NewProduction()
if err != nil {
log.Fatalln("failed to initialise logger:", err)
log.Fatalln("failed to initialize logger:", err)
}
if os.Getenv("MODE") == "dev" {
devMode = true
logger, err = zap.NewDevelopment()
if err != nil {
log.Fatalln("failed to initialise development logger:", err)
log.Fatalln("failed to initialize development logger:", err)
}
}
defer logger.Sync() // nolint: errcheck
if os.Getenv("REDIS_ADDR") != "" {
nodeDB, err = db.NewRedis(os.Getenv("REDIS_ADDR"), logger)
if err != nil {
log.Fatalln("failed to connect to redis: %w", err)
}
} else {
nodeDB = db.New(logger)
}
@ -60,16 +64,22 @@ func main() {
cluster := c.Params("cluster")
if cluster == "" {
logger.Error("empty cluster for node list")
return c.SendStatus(http.StatusBadRequest)
}
list, err := nodeDB.List(c.Context(), cluster)
if len(list) < 1 {
logger.Warn("cluster not found",
zap.String("cluster", cluster),
zap.Error(err),
)
return c.SendStatus(http.StatusNotFound)
list, e := nodeDB.List(c.Context(), cluster)
if e != nil {
if errors.Is(e, db.ErrNotFound) {
logger.Warn("cluster not found",
zap.String("cluster", cluster),
zap.Error(err),
)
return c.SendStatus(http.StatusNotFound)
}
return c.SendStatus(http.StatusInternalServerError)
}
logger.Info("listing cluster nodes",
@ -78,13 +88,13 @@ func main() {
)
return c.JSON(list)
})
app.Get("/:cluster/:node", func(c *fiber.Ctx) error {
cluster := c.Params("cluster", "")
if cluster == "" {
logger.Error("empty cluster for node get")
return c.SendStatus(http.StatusBadRequest)
}
@ -93,17 +103,23 @@ func main() {
logger.Error("empty node for node get",
zap.String("cluster", c.Params("cluster", "")),
)
return c.SendStatus(http.StatusBadRequest)
}
n, err := nodeDB.Get(c.Context(), cluster, node)
if err != nil {
logger.Warn("node not found",
zap.String("cluster", cluster),
zap.String("node", node),
zap.Error(err),
)
return c.SendStatus(http.StatusNotFound)
n, e := nodeDB.Get(c.Context(), cluster, node)
if e != nil {
if errors.Is(e, db.ErrNotFound) {
logger.Warn("node not found",
zap.String("cluster", cluster),
zap.String("node", node),
zap.Error(err),
)
return c.SendStatus(http.StatusNotFound)
}
return c.SendStatus(http.StatusInternalServerError)
}
logger.Info("returning cluster node",
@ -121,12 +137,13 @@ func main() {
app.Put("/:cluster/:node", func(c *fiber.Ctx) error {
var addresses []*types.Address
if err := c.BodyParser(&addresses); err != nil {
if e := c.BodyParser(&addresses); e != nil {
logger.Error("failed to parse node PUT",
zap.String("cluster", c.Params("cluster", "")),
zap.String("node", c.Params("node", "")),
zap.Error(err),
)
return c.SendStatus(http.StatusBadRequest)
}
@ -146,6 +163,7 @@ func main() {
zap.Strings("addresses", addressToString(addresses)),
zap.Error(err),
)
return c.SendStatus(http.StatusInternalServerError)
}
@ -160,6 +178,7 @@ func main() {
zap.String("cluster", c.Params("cluster", "")),
zap.Error(err),
)
return c.SendStatus(http.StatusBadRequest)
}
@ -171,6 +190,7 @@ func main() {
zap.Strings("addresses", addressToString(n.Addresses)),
zap.Error(err),
)
return c.SendStatus(http.StatusInternalServerError)
}

2
go.mod
View File

@ -1,4 +1,4 @@
module github.com/talos-systems/wglan-manager
module github.com/talos-systems/kubespan-manager
go 1.16

View File

@ -0,0 +1,26 @@
<!-- THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. -->
<!-- -->
<!-- Generated on 2021-08-13T12:22:39Z by kres 907039b. -->
{{ range .Versions }}
<a name="{{ .Tag.Name }}"></a>
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }})
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
* {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
{{ end }}
{{ end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
{{ .Body }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}

View File

@ -0,0 +1,32 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
style: github
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://github.com/talos-systems/wglan-manager
options:
commits:
# filters:
# Type:
# - feat
# - fix
# - perf
# - refactor
commit_groups:
# title_maps:
# feat: Features
# fix: Bug Fixes
# perf: Performance Improvements
# refactor: Code Refactoring
header:
pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$"
pattern_maps:
- Type
- Scope
- Subject
notes:
keywords:
- BREAKING CHANGE

68
hack/release.sh Executable file
View File

@ -0,0 +1,68 @@
#!/bin/bash
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
#!/bin/bash
set -e
RELEASE_TOOL_IMAGE="ghcr.io/talos-systems/release-tool:latest"
function release-tool {
docker pull "${RELEASE_TOOL_IMAGE}" >/dev/null
docker run --rm -w /src -v "${PWD}":/src:ro "${RELEASE_TOOL_IMAGE}" -l -d -n -t "${1}" ./hack/release.toml
}
function changelog {
if [ "$#" -eq 1 ]; then
(release-tool ${1}; echo; cat CHANGELOG.md) > CHANGELOG.md- && mv CHANGELOG.md- CHANGELOG.md
else
echo 1>&2 "Usage: $0 changelog [tag]"
exit 1
fi
}
function release-notes {
release-tool "${2}" > "${1}"
}
function cherry-pick {
if [ $# -ne 2 ]; then
echo 1>&2 "Usage: $0 cherry-pick <commit> <branch>"
exit 1
fi
git checkout $2
git fetch
git rebase upstream/$2
git cherry-pick -x $1
}
function commit {
if [ $# -ne 1 ]; then
echo 1>&2 "Usage: $0 commit <tag>"
exit 1
fi
git commit -s -m "release($1): prepare release" -m "This is the official $1 release."
}
if declare -f "$1" > /dev/null
then
cmd="$1"
shift
$cmd "$@"
else
cat <<EOF
Usage:
commit: Create the official release commit message.
cherry-pick: Cherry-pick a commit into a release branch.
changelog: Update the specified CHANGELOG.
release-notes: Create release notes for GitHub release.
EOF
exit 1
fi

16
hack/release.toml Normal file
View File

@ -0,0 +1,16 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2021-08-13T12:22:39Z by kres 907039b.
# commit to be tagged for the new release
commit = "HEAD"
project_name = "wglan-manager"
github_repo = "talos-systems/wglan-manager"
match_deps = "^github.com/(talos-systems/[a-zA-Z0-9-]+)$"
# previous = -
# pre_release = true
# [notes]

View File

@ -1,30 +1,41 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package db contains state storage logic.
package db
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/talos-systems/wglan-manager/types"
"go.uber.org/zap"
"github.com/talos-systems/kubespan-manager/pkg/types"
)
// ErrNotFound means that record is not found in DB.
var ErrNotFound = errors.New("not found")
// AddressExpirationTimeout is the amount of time after which addresses of a node should be expired.
const AddressExpirationTimeout = 10 * time.Minute
// DB manager state persistent storage interface.
type DB interface {
// Add adds a set of known Endpoints to a node, creating the node, if it does not exist.
Add(ctx context.Context, cluster string, n *types.Node) error
// AddAddresses adds a set of addresses for a node.
AddAddresses(ctx context.Context, cluster string, id string, ep ...*types.Address) error
AddAddresses(ctx context.Context, cluster, id string, ep ...*types.Address) error
// Clean executes a database cleanup routine.
Clean()
// Get returns the details of the node.
Get(ctx context.Context, cluster string, id string) (*types.Node, error)
Get(ctx context.Context, cluster, id string) (*types.Node, error)
// List returns the set of Nodes for the given Cluster.
List(ctx context.Context, cluster string) ([]*types.Node, error)
@ -32,19 +43,19 @@ type DB interface {
type ramDB struct {
logger *zap.Logger
db map[string]map[string]*types.Node
mu sync.RWMutex
db map[string]map[string]*types.Node
mu sync.RWMutex
}
// New returns a new database.
func New(logger *zap.Logger) DB {
return &ramDB{
logger: logger,
db: make(map[string]map[string]*types.Node),
db: make(map[string]map[string]*types.Node),
}
}
// Add implements DB
// Add implements DB.
func (d *ramDB) Add(ctx context.Context, cluster string, n *types.Node) error {
d.mu.Lock()
defer d.mu.Unlock()
@ -66,7 +77,7 @@ func (d *ramDB) Add(ctx context.Context, cluster string, n *types.Node) error {
return nil
}
func (d *ramDB) AddAddresses(ctx context.Context, cluster string, id string, addresses ...*types.Address) error {
func (d *ramDB) AddAddresses(ctx context.Context, cluster, id string, addresses ...*types.Address) error {
d.mu.Lock()
defer d.mu.Unlock()
@ -85,6 +96,7 @@ func (d *ramDB) AddAddresses(ctx context.Context, cluster string, id string, add
return nil
}
// List implements DB.
func (d *ramDB) List(ctx context.Context, cluster string) (list []*types.Node, err error) {
c, ok := d.db[cluster]
if !ok {
@ -99,11 +111,15 @@ func (d *ramDB) List(ctx context.Context, cluster string) (list []*types.Node, e
}
}
if len(list) == 0 {
return nil, ErrNotFound
}
return list, nil
}
// Get implements DB
func (d *ramDB) Get(ctx context.Context, cluster string, id string) (*types.Node, error) {
// Get implements DB.
func (d *ramDB) Get(ctx context.Context, cluster, id string) (*types.Node, error) {
d.mu.RLock()
defer d.mu.Unlock()
@ -114,7 +130,7 @@ func (d *ramDB) Get(ctx context.Context, cluster string, id string) (*types.Node
n, ok := c[id]
if !ok {
return nil, fmt.Errorf("node %q in cluster %q not found", id, cluster)
return nil, ErrNotFound
}
return n, nil
@ -131,7 +147,6 @@ func (d *ramDB) Clean() {
var nodeDeleteList []string
for id, n := range c {
n.ExpireAddressesOlderThan(AddressExpirationTimeout)
if len(n.Addresses) < 1 {
@ -144,7 +159,7 @@ func (d *ramDB) Clean() {
delete(c, id)
}
if len(c) < 0 {
if len(c) == 0 {
clusterDeleteList = append(clusterDeleteList, clusterID)
}
}

View File

@ -1,3 +1,7 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package db
import (
@ -7,8 +11,9 @@ import (
"time"
"github.com/go-redis/redis/v8"
"github.com/talos-systems/wglan-manager/types"
"go.uber.org/zap"
"github.com/talos-systems/kubespan-manager/pkg/types"
)
const redisTTL = 12 * time.Minute
@ -19,8 +24,9 @@ type redisDB struct {
rc *redis.Client
}
// NewRedis creates new redis DB.
func NewRedis(addr string, logger *zap.Logger) (DB, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
rc := redis.NewClient(&redis.Options{
@ -32,7 +38,7 @@ func NewRedis(addr string, logger *zap.Logger) (DB, error) {
}
return &redisDB{
rc: rc,
rc: rc,
logger: logger,
}, nil
}
@ -53,7 +59,7 @@ func (d *redisDB) clusterAddressKey(cluster string, addr *types.Address) string
return fmt.Sprintf("cluster:%s:address:%s", cluster, addr.Name)
}
// Add implements db.DB
// Add implements db.DB.
func (d *redisDB) Add(ctx context.Context, cluster string, n *types.Node) error {
tx := d.rc.TxPipeline()
@ -77,8 +83,8 @@ func (d *redisDB) Add(ctx context.Context, cluster string, n *types.Node) error
return err
}
// AddAddresses implements db.DB
func (d *redisDB) AddAddresses(ctx context.Context, cluster string, id string, ep ...*types.Address) error {
// AddAddresses implements db.DB.
func (d *redisDB) AddAddresses(ctx context.Context, cluster, id string, ep ...*types.Address) error {
n, err := d.Get(ctx, cluster, id)
if err != nil {
return fmt.Errorf("failed to retrieve node %q from cluster %q: %w", id, cluster, err)
@ -89,19 +95,19 @@ func (d *redisDB) AddAddresses(ctx context.Context, cluster string, id string, e
return d.Add(ctx, cluster, n)
}
// Clean implements db.DB
// Clean implements db.DB.
func (d *redisDB) Clean() {
return // no-op
}
// Get implements db.DB
func (d *redisDB) Get(ctx context.Context, cluster string, id string) (*types.Node, error) {
// Get implements db.DB.
func (d *redisDB) Get(ctx context.Context, cluster, id string) (*types.Node, error) {
n := new(types.Node)
if err := d.rc.Get(ctx, d.clusterNodeKey(cluster, id)).Scan(n); err != nil {
if errors.Is(redis.Nil, err) {
return nil, err
return nil, ErrNotFound
}
return nil, fmt.Errorf("failed to parse node %q of cluster %q: %w", id, cluster, err)
}
@ -119,14 +125,18 @@ func (d *redisDB) Get(ctx context.Context, cluster string, id string) (*types.No
return n, nil
}
// List implements db.DB
// List implements db.DB.
func (d *redisDB) List(ctx context.Context, cluster string) ([]*types.Node, error) {
nodeList, err := d.rc.SMembers(ctx, d.clusterNodesKey(cluster)).Result()
if err != nil {
if errors.Is(redis.Nil, err) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("failed to get members of cluster %q: %w", cluster, err)
}
var ret []*types.Node
ret := make([]*types.Node, 0, len(nodeList))
for _, id := range nodeList {
n, err := d.Get(ctx, cluster, id)
@ -146,9 +156,9 @@ func (d *redisDB) List(ctx context.Context, cluster string) ([]*types.Node, erro
}
} else {
d.logger.Error("failed to get node listen in nodeList",
zap.String("node", id),
zap.String("cluster", cluster),
zap.Error(err),
zap.String("node", id),
zap.String("cluster", cluster),
zap.Error(err),
)
}
@ -158,5 +168,9 @@ func (d *redisDB) List(ctx context.Context, cluster string) ([]*types.Node, erro
ret = append(ret, n)
}
if len(ret) == 0 {
return nil, ErrNotFound
}
return ret, nil
}

View File

@ -1,27 +1,38 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package client implements http client for the manager API.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/talos-systems/wglan-manager/types"
"github.com/talos-systems/kubespan-manager/pkg/types"
)
// Add adds a Node to the Cluster database, updating it if it already exists.
func Add(rootURL, clusterID string, n *types.Node) error {
body := new(bytes.Buffer)
if err := json.NewEncoder(body).Encode(n); err != nil {
return fmt.Errorf("failed to encode Node information: %w", err)
}
resp, err := http.Post(fmt.Sprintf("%s/%s", rootURL, clusterID), "application/json", body); if err != nil {
req, err := http.NewRequestWithContext(context.TODO(), http.MethodPost, fmt.Sprintf("%s/%s", rootURL, clusterID), body)
if err != nil {
return fmt.Errorf("failed to post Node information: %w", err)
}
defer resp.Body.Close() // nolint: errcheck
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to post Node information: %w", err)
}
defer resp.Body.Close() //nolint:errcheck
if resp.StatusCode > 299 {
return fmt.Errorf("server rejected Node information: %s", resp.Status)
@ -31,14 +42,14 @@ func Add(rootURL, clusterID string, n *types.Node) error {
}
// AddAddresses adds a list of addresses to a node.
func AddAddresses(rootURL, clusterID string, id string, epList ... *types.Address) error {
func AddAddresses(rootURL, clusterID, id string, epList ...*types.Address) error {
buf := new(bytes.Buffer)
if err := json.NewEncoder(buf).Encode(epList); err != nil {
return fmt.Errorf("failed to encode known endpoints: %w", err)
}
req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/%s/%s", rootURL, clusterID, id), buf)
req, err := http.NewRequestWithContext(context.TODO(), http.MethodPut, fmt.Sprintf("%s/%s/%s", rootURL, clusterID, id), buf)
if err != nil {
return fmt.Errorf("failed to make PUT request: %w", err)
}
@ -47,23 +58,28 @@ func AddAddresses(rootURL, clusterID string, id string, epList ... *types.Addres
if err != nil {
return fmt.Errorf("failed to add endpoints to node %q/%q: %w", clusterID, id, err)
}
defer resp.Body.Close() //nolint:errcheck
if resp.StatusCode > 299 {
return fmt.Errorf("server rejected new endpoints for node %q/%q: %s", clusterID, id, resp.Status)
}
return nil
}
// Get returns the Node defined by the given public key, if and only if it exists within the given Cluster ID.
func Get(rootURL, clusterID string, publicKey string) (*types.Node, error) {
resp, err := http.Get(fmt.Sprintf("%s/%s/%s", rootURL, clusterID, publicKey))
func Get(rootURL, clusterID, publicKey string) (*types.Node, error) {
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, fmt.Sprintf("%s/%s/%s", rootURL, clusterID, publicKey), nil)
if err != nil {
return nil, fmt.Errorf("failed to request node %q/%q from server %q: %w", clusterID, publicKey, rootURL, err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to request node %q/%q from server %q: %w", clusterID, publicKey, rootURL, err)
}
defer resp.Body.Close() //nolint:errcheck
node := new(types.Node)
if err = json.NewDecoder(resp.Body).Decode(node); err != nil {
return nil, fmt.Errorf("failed to decode response from server: %w", err)
@ -73,13 +89,17 @@ func Get(rootURL, clusterID string, publicKey string) (*types.Node, error) {
}
// List returns the set of Nodes associated with the given Cluster ID.
func List(rootURL string, clusterID string) ([]*types.Node,error) {
resp, err := http.Get(fmt.Sprintf("%s/%s", rootURL, clusterID))
func List(rootURL, clusterID string) ([]*types.Node, error) {
req, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, fmt.Sprintf("%s/%s", rootURL, clusterID), nil)
if err != nil {
return nil, fmt.Errorf("failed to request list from server %q: %w", rootURL, err)
}
defer resp.Body.Close() // nolint: errcheck
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to request list from server %q: %w", rootURL, err)
}
defer resp.Body.Close() //nolint:errcheck
var list []*types.Node
if err = json.NewDecoder(resp.Body).Decode(&list); err != nil {
@ -87,6 +107,4 @@ func List(rootURL string, clusterID string) ([]*types.Node,error) {
}
return list, nil
}

View File

@ -1,3 +1,8 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package types contains all manager data types.
package types
import (
@ -12,22 +17,19 @@ import (
// Address describes an IP or DNS address with optional Port.
type Address struct {
// Name is the DNS name of this NodeAddress, if known.
Name string `json:"name,omitempty"`
// IP is the IP address of this NodeAddress, if known.
IP netaddr.IP `json:"ip,omitempty"`
// Port is the port number for this NodeAddress, if known.
Port uint16 `json:"port,omitempty"`
// LastReported indicates the time at which this address was last reported.
LastReported time.Time `json:"lastReported"`
// IP is the IP address of this NodeAddress, if known.
IP netaddr.IP `json:"ip,omitempty"`
// Name is the DNS name of this NodeAddress, if known.
Name string `json:"name,omitempty"`
// Port is the port number for this NodeAddress, if known.
Port uint16 `json:"port,omitempty"`
}
// EqualHost indicates whether two addresses have the same host portion, ignoring the ports.
func (a *Address) EqualHost(other *Address) bool {
if ! a.IP.IsZero() || ! other.IP.IsZero() {
if !a.IP.IsZero() || !other.IP.IsZero() {
return a.IP == other.IP
}
@ -67,7 +69,7 @@ func (a *Address) Endpoint(defaultPort uint16) (*net.UDPAddr, error) {
return net.ResolveUDPAddr(proto, fmt.Sprintf("%s:%d", addr, port))
}
// Node describes a Wireguard Peer
// Node describes a Wireguard Peer.
type Node struct {
// Name is the human-readable identifier of this Node.
// Usually, this is the kubernetes Node name.
@ -88,7 +90,7 @@ type Node struct {
}
// AddAddresses adds a set of addresses to a Node.
func (n *Node) AddAddresses(addresses ... *Address) {
func (n *Node) AddAddresses(addresses ...*Address) {
n.mu.Lock()
defer n.mu.Unlock()
@ -134,19 +136,17 @@ func (n *Node) ExpireAddressesOlderThan(maxAge time.Duration) {
continue
}
a = nil
}
n.Addresses = n.Addresses[:i]
}
// MarshalBinary implements encoding.BinaryMarshaler
// MarshalBinary implements encoding.BinaryMarshaler.
func (n *Node) MarshalBinary() ([]byte, error) {
return json.Marshal(n)
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (n *Node) UnmarshalBinary(data []byte) error {
*n = Node{}

View File

@ -1,18 +1,23 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package types_test
import (
"testing"
"time"
"github.com/talos-systems/wglan-manager/types"
"inet.af/netaddr"
"github.com/talos-systems/kubespan-manager/pkg/types"
)
func TestEncoderDecoder(t *testing.T) {
n := &types.Node{
Name: "tester",
ID: "IHOPEfmiUG1kE832FAxm77J5WP0O1ZHp9OwqbGowL1E=",
IP: netaddr.MustParseIP("2001:db8:1001::1"),
Name: "tester",
ID: "IHOPEfmiUG1kE832FAxm77J5WP0O1ZHp9OwqbGowL1E=",
IP: netaddr.MustParseIP("2001:db8:1001::1"),
Addresses: []*types.Address{
{
Name: "mynode.mydomain.com",