From 0451b4282b179f97f10b03ad4ad5f3c480d105d0 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 09:28:39 -0400 Subject: [PATCH 01/51] learning github actions --- .github/workflows/learn-github-actions.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/workflows/learn-github-actions.yml diff --git a/.github/workflows/learn-github-actions.yml b/.github/workflows/learn-github-actions.yml new file mode 100644 index 00000000..9ae5b894 --- /dev/null +++ b/.github/workflows/learn-github-actions.yml @@ -0,0 +1,10 @@ +name: learn-github-actions +on: [push] +jobs: + check-bats-version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + - run: npm install -g bats + - run: bats -v From e11017a4c342c0bcd2f1d0853b910d3c907ffbe0 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 13:51:13 +0000 Subject: [PATCH 02/51] pubish docker --- .github/workflows/publish-docker.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/publish-docker.yml diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml new file mode 100644 index 00000000..21d7c53b --- /dev/null +++ b/.github/workflows/publish-docker.yml @@ -0,0 +1,13 @@ +name: Publish Docker +on: [push] +jobs: build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Publish to Registry + with: + name: nusak/netmaker + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + default_branch: arm_docker + platforms: linux/amd64, linux/arm64 From a29b5b8495ad1cf250f1c85ad760703c7e0b5d5b Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 13:53:36 +0000 Subject: [PATCH 03/51] pubish docker --- .github/workflows/publish-docker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 21d7c53b..c827b688 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,6 +1,7 @@ name: Publish Docker on: [push] -jobs: build: +jobs: + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@master From 3bcfcf83f2d04058197c450f41ccbfee75c5daad Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 13:57:34 +0000 Subject: [PATCH 04/51] fixt uses --- .github/workflows/learn-github-actions.yml | 10 ---------- .github/workflows/publish-docker.yml | 1 + 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 .github/workflows/learn-github-actions.yml diff --git a/.github/workflows/learn-github-actions.yml b/.github/workflows/learn-github-actions.yml deleted file mode 100644 index 9ae5b894..00000000 --- a/.github/workflows/learn-github-actions.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: learn-github-actions -on: [push] -jobs: - check-bats-version: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - - run: npm install -g bats - - run: bats -v diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index c827b688..a2d4a013 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -6,6 +6,7 @@ jobs: steps: - uses: actions/checkout@master - name: Publish to Registry + uses: elgohr/Publish-Docker-Github-Actions@master with: name: nusak/netmaker username: ${{ secrets.DOCKER_USERNAME }} From 87ae4ddbefc1e5762d5aa03e8772e078932acbc1 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 18:29:20 +0000 Subject: [PATCH 05/51] docker git action --- .github/workflows/publish-docker.yml | 43 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index a2d4a013..2c4423fa 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,15 +1,34 @@ name: Publish Docker -on: [push] -jobs: - build: + +on: + push: + branches: + - 'arm-docker' +jobs: + docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - - name: Publish to Registry - uses: elgohr/Publish-Docker-Github-Actions@master - with: - name: nusak/netmaker - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - default_branch: arm_docker - platforms: linux/amd64, linux/arm64 + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64, linux/arm7 + push: true + tags: nusak/netmaker:latest + From cdfba2c5c6cb774eb1c45b6b130dc7bb743291cf Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 18:35:38 +0000 Subject: [PATCH 06/51] rm arm7 --- .github/workflows/publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 2c4423fa..31beab1b 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -28,7 +28,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64, linux/arm64, linux/arm7 + platforms: linux/amd64, linux/arm64 push: true tags: nusak/netmaker:latest From 2ba67d0a6087335037597ebe68a2530eb95b95c2 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:24:20 +0000 Subject: [PATCH 07/51] more events and tags --- .github/workflows/publish-docker.yml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 31beab1b..fcea75df 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -4,6 +4,13 @@ on: push: branches: - 'arm-docker' + - 'develop' + - 'main' + tags: + - 'v*.*.*' + pull_request: + branches: + - 'main' jobs: docker: runs-on: ubuntu-latest @@ -11,6 +18,22 @@ jobs: - name: Checkout uses: actions/checkout@v2 + - + name: Docker Meta + id: meta + uses: crazy-max/ghaction-docker-meta@v2 + with: + #list of images to use as base name for tags + images: | + nusak/netmaker + # generate Docker tags based on following events/attributes + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -29,6 +52,7 @@ jobs: with: context: . platforms: linux/amd64, linux/arm64 - push: true - tags: nusak/netmaker:latest + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.output.tags }} + labels: ${{ steps.meta.output.labels }} From ec7f308521e17a402c272cee089c08953cf0d90a Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:26:51 +0000 Subject: [PATCH 08/51] fixed yml file --- .github/workflows/publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index fcea75df..4db1845a 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -24,7 +24,7 @@ jobs: uses: crazy-max/ghaction-docker-meta@v2 with: #list of images to use as base name for tags - images: | + images: nusak/netmaker # generate Docker tags based on following events/attributes tags: | From ca6754946bb0dd3724e7cd40220908c053bd625a Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:31:35 +0000 Subject: [PATCH 09/51] simplified workflow --- .github/workflows/publish-docker.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 4db1845a..837e8e00 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -23,17 +23,8 @@ jobs: id: meta uses: crazy-max/ghaction-docker-meta@v2 with: - #list of images to use as base name for tags images: nusak/netmaker - # generate Docker tags based on following events/attributes - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=sha - name: Set up QEMU uses: docker/setup-qemu-action@v1 From 476a19d68695849f885987dc9bcfd039ac4471d5 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:39:40 +0000 Subject: [PATCH 10/51] simplified workflow --- .github/workflows/publish-docker.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 837e8e00..b6938fd1 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -31,6 +31,10 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 + with: + context: + platforms: linux/amd64, linux/arm64 + tags: ${{ steps.meta.output.tags }} - name: Login to DockerHub uses: docker/login-action@v1 From e684979a64731b5ffcdc947c905e6b1d388efac2 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:45:28 +0000 Subject: [PATCH 11/51] fix missing tags --- .github/workflows/publish-docker.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index b6938fd1..9b684f8c 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -25,6 +25,9 @@ jobs: with: images: nusak/netmaker + tags: | + type=ref,event=branch + type=ref,event=pr - name: Set up QEMU uses: docker/setup-qemu-action@v1 From dc839339e646db5bf7f88a2cccdb6e7e26ad0687 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:47:12 +0000 Subject: [PATCH 12/51] another fix to yml --- .github/workflows/publish-docker.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 9b684f8c..660f5d7e 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -34,10 +34,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - with: - context: - platforms: linux/amd64, linux/arm64 - tags: ${{ steps.meta.output.tags }} - name: Login to DockerHub uses: docker/login-action@v1 From 4e6e2b1f9d336f142720b7386fbd5695f4ab3f6a Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 19:57:32 +0000 Subject: [PATCH 13/51] another fix to yml --- .github/workflows/publish-docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 660f5d7e..374d9d9c 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -28,6 +28,7 @@ jobs: tags: | type=ref,event=branch type=ref,event=pr + type=ref,event=push - name: Set up QEMU uses: docker/setup-qemu-action@v1 From 956e6f01ca2d69c0660e1a8657219c4fed1b3ab8 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 20:10:44 +0000 Subject: [PATCH 14/51] fixing yml --- .github/workflows/publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 374d9d9c..ff2dc062 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -28,7 +28,7 @@ jobs: tags: | type=ref,event=branch type=ref,event=pr - type=ref,event=push + type=sha - name: Set up QEMU uses: docker/setup-qemu-action@v1 From 5667a3a083fe07b90b738e58c51645e75d8db509 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 20:14:18 +0000 Subject: [PATCH 15/51] another try --- .github/workflows/publish-docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index ff2dc062..36e49a86 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -8,6 +8,7 @@ on: - 'main' tags: - 'v*.*.*' + - latest pull_request: branches: - 'main' From fbd061ac87236ece9dcb6c2fd18f1149e6bf5ddb Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 20:25:29 +0000 Subject: [PATCH 16/51] tags --- .github/workflows/publish-docker.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 36e49a86..a534656a 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -30,6 +30,7 @@ jobs: type=ref,event=branch type=ref,event=pr type=sha + type=edge,branch=develop - name: Set up QEMU uses: docker/setup-qemu-action@v1 From c499575c514ed9a2487754f4ac1869f16bace250 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 21:15:04 +0000 Subject: [PATCH 17/51] remove ghaction-docker-meta --- .github/workflows/publish-docker.yml | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index a534656a..861b2924 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -5,13 +5,7 @@ on: branches: - 'arm-docker' - 'develop' - - 'main' - tags: - - 'v*.*.*' - - latest - pull_request: - branches: - - 'main' + - jobs: docker: runs-on: ubuntu-latest @@ -19,18 +13,6 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - - name: Docker Meta - id: meta - uses: crazy-max/ghaction-docker-meta@v2 - with: - images: - nusak/netmaker - tags: | - type=ref,event=branch - type=ref,event=pr - type=sha - type=edge,branch=develop - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -49,7 +31,5 @@ jobs: with: context: . platforms: linux/amd64, linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.output.tags }} - labels: ${{ steps.meta.output.labels }} - + push: true + tags: nusak/netmaker:dev From 4dd6c4d1966cea2218b39c6e6e9b2a719df28b69 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 21:22:49 +0000 Subject: [PATCH 18/51] separate actions for dev & master --- .github/workflows/publish-docker-latest.yml | 33 +++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/publish-docker-latest.yml diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml new file mode 100644 index 00000000..43f4f847 --- /dev/null +++ b/.github/workflows/publish-docker-latest.yml @@ -0,0 +1,33 @@ +name: Publish Docker + +on: + push: + branches: + - 'master' +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: nusak/netmaker:latest From b225f9f939007be04de2959157ce3a2b0c9c45e4 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 17:29:19 -0400 Subject: [PATCH 19/51] Arm docker (#1) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master Co-authored-by: Matthew R Kasun --- .github/workflows/publish-docker-latest.yml | 33 +++++++++++++++++++ .github/workflows/publish-docker.yml | 35 +++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 .github/workflows/publish-docker-latest.yml create mode 100644 .github/workflows/publish-docker.yml diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml new file mode 100644 index 00000000..43f4f847 --- /dev/null +++ b/.github/workflows/publish-docker-latest.yml @@ -0,0 +1,33 @@ +name: Publish Docker + +on: + push: + branches: + - 'master' +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: nusak/netmaker:latest diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml new file mode 100644 index 00000000..861b2924 --- /dev/null +++ b/.github/workflows/publish-docker.yml @@ -0,0 +1,35 @@ +name: Publish Docker + +on: + push: + branches: + - 'arm-docker' + - 'develop' + - +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: nusak/netmaker:dev From 088f2684df0cabd5e043c3870ddcf0964ff544cf Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 6 Apr 2021 17:36:22 -0400 Subject: [PATCH 20/51] Github actions for docker builds (#2) * Get Group api test * Initial Group Tests * Most Delete Group Tests * Group Tests Complete * Refactor tests and move to test dir * Refactor tests and move to test dir * changed wirecat --> netmaker. Changed defaults to be more sensible * putting netmaker default port 1 above WG port to avoid conflicts with preexisting setups * fixed client side for multinet and added group filter to query params server side. * fixed client side for multinet and added group filter to query params server side. * cleaned up netclient uninstall for multiple networks * added access token for ease of configuration * added access token for ease of configuration * peer update functionality * auto delete timestamp works * Arm docker (#1) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master Co-authored-by: Matthew R Kasun Co-authored-by: Matthew R Kasun Co-authored-by: afeiszli Co-authored-by: Alex <31018251+afeiszli@users.noreply.github.com> --- .github/workflows/publish-docker-latest.yml | 33 ++ .github/workflows/publish-docker.yml | 35 ++ controllers/authGrpc.go | 2 +- controllers/common.go | 48 +- controllers/groupHttpController.go | 89 ++- controllers/nodeGrpcController.go | 2 + controllers/nodeHttpController.go | 18 +- controllers/userHttpController.go | 12 +- docker-compose.yml | 2 +- docs/API.md | 2 +- docs/GETTING_STARTED.md | 6 +- docs/ROADMAP.md | 2 +- functions/helpers.go | 45 +- group_test.go | 620 +++++++++++++++++++ grpc/node.pb.go | 122 ++-- grpc/node.proto | 2 + main.go | 85 +++ models/group.go | 9 +- models/node.go | 11 +- models/structs.go | 10 + mongoconn/mongoconn.go | 4 +- netclient/config/config.go | 50 +- netclient/functions/auth.go | 24 +- netclient/functions/common.go | 287 ++++++--- netclient/functions/local.go | 117 ++-- netclient/main.go | 41 +- test/api_test.go | 197 +++++++ test/config/environments/dev.yaml | 14 + test/group_test.go | 621 ++++++++++++++++++++ user_test.go => test/user_test.go | 107 ---- 30 files changed, 2244 insertions(+), 373 deletions(-) create mode 100644 .github/workflows/publish-docker-latest.yml create mode 100644 .github/workflows/publish-docker.yml create mode 100644 group_test.go create mode 100644 test/api_test.go create mode 100644 test/config/environments/dev.yaml create mode 100644 test/group_test.go rename user_test.go => test/user_test.go (70%) diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml new file mode 100644 index 00000000..43f4f847 --- /dev/null +++ b/.github/workflows/publish-docker-latest.yml @@ -0,0 +1,33 @@ +name: Publish Docker + +on: + push: + branches: + - 'master' +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: nusak/netmaker:latest diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml new file mode 100644 index 00000000..861b2924 --- /dev/null +++ b/.github/workflows/publish-docker.yml @@ -0,0 +1,35 @@ +name: Publish Docker + +on: + push: + branches: + - 'arm-docker' + - 'develop' + - +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: nusak/netmaker:dev diff --git a/controllers/authGrpc.go b/controllers/authGrpc.go index 2b5a75d8..9f053c0a 100644 --- a/controllers/authGrpc.go +++ b/controllers/authGrpc.go @@ -121,7 +121,7 @@ func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest) return nil, err } else { //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved). - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) var err = collection.FindOne(ctx, bson.M{ "macaddress": macaddress}).Decode(&result) diff --git a/controllers/common.go b/controllers/common.go index 81fdc2a4..d43fa7d8 100644 --- a/controllers/common.go +++ b/controllers/common.go @@ -21,7 +21,7 @@ func GetPeersList(groupName string) ([]models.PeersResponse, error) { var peers []models.PeersResponse //Connection mongoDB with mongoconn class - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -121,6 +121,7 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) { //Question: Is there a better way of doing this than a bunch of "if" statements? probably... //Eventually, lets have a better way to check if any of the fields are filled out... queryMac := node.MacAddress + queryGroup := node.Group notifygroup := false if nodechange.Address != "" { @@ -136,6 +137,9 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) { if nodechange.ListenPort != 0 { node.ListenPort = nodechange.ListenPort } + if nodechange.ExpirationDateTime != 0 { + node.ExpirationDateTime = nodechange.ExpirationDateTime + } if nodechange.PreUp != "" { node.PreUp = nodechange.PreUp } @@ -174,16 +178,17 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) { } if nodechange.PublicKey != "" { node.PublicKey = nodechange.PublicKey + node.KeyUpdateTimeStamp = time.Now().Unix() notifygroup = true } //collection := mongoconn.ConnectDB() - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // Create filter - filter := bson.M{"macaddress": queryMac} + filter := bson.M{"macaddress": queryMac, "group": queryGroup} node.SetLastModified() @@ -194,6 +199,8 @@ func UpdateNode(nodechange models.Node, node models.Node) (models.Node, error) { {"password", node.Password}, {"listenport", node.ListenPort}, {"publickey", node.PublicKey}, + {"keyupdatetimestamp", node.KeyUpdateTimeStamp}, + {"expdatetime", node.ExpirationDateTime}, {"endpoint", node.Endpoint}, {"postup", node.PostUp}, {"preup", node.PreUp}, @@ -228,7 +235,7 @@ func DeleteNode(macaddress string, group string) (bool, error) { deleted := false - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") filter := bson.M{"macaddress": macaddress, "group": group} @@ -254,7 +261,7 @@ func GetNode(macaddress string, group string) (models.Node, error) { var node models.Node - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -306,7 +313,7 @@ func CreateNode(node models.Node, groupName string) (models.Node, error) { node.SetDefaultName() node.SetLastCheckIn() node.SetLastPeerUpdate() - + node.KeyUpdateTimeStamp = time.Now().Unix() //Create a JWT for the node tokenString, _ := functions.CreateJWT(node.MacAddress, groupName) @@ -317,7 +324,7 @@ func CreateNode(node models.Node, groupName string) (models.Node, error) { } // connect db - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -365,7 +372,9 @@ func NodeCheckIn(node models.Node, groupName string) (models.CheckInResponse, er grouplm := parentgroup.GroupLastModified peerslm := parentgroup.NodesLastModified - peerlistlm := parentnode.LastPeerUpdate + gkeyupdate := parentgroup.KeyUpdateTimeStamp + nkeyupdate := parentnode.KeyUpdateTimeStamp + peerlistlm := parentnode.LastPeerUpdate parentnodelm := parentnode.LastModified parentnodelastcheckin := parentnode.LastCheckIn @@ -379,23 +388,20 @@ func NodeCheckIn(node models.Node, groupName string) (models.CheckInResponse, er if peerlistlm < peerslm { response.NeedPeerUpdate = true } - /* - if postchanges { - parentnode, err = UpdateNode(node, parentnode) - if err != nil{ - err = fmt.Errorf("%w; Couldnt Update Node: ", err) - return response, err - } else { - response.NodeUpdated = true - } + if nkeyupdate < gkeyupdate { + response.NeedKeyUpdate = true } - */ + if time.Now().Unix() > parentnode.ExpirationDateTime { + response.NeedDelete = true + _, err = DeleteNode(node.MacAddress, groupName) + } else { err = TimestampNode(parentnode, true, false, false) if err != nil{ err = fmt.Errorf("%w; Couldnt Timestamp Node: ", err) return response, err } + } response.Success = true return response, err @@ -405,7 +411,7 @@ func SetGroupNodesLastModified(groupName string) error { timestamp := time.Now().Unix() - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -441,12 +447,12 @@ func TimestampNode(node models.Node, updatecheckin bool, updatepeers bool, updat node.SetLastPeerUpdate() } - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // Create filter - filter := bson.M{"macaddress": node.MacAddress} + filter := bson.M{"macaddress": node.MacAddress, "group": node.Group} // prepare update model. update := bson.D{ diff --git a/controllers/groupHttpController.go b/controllers/groupHttpController.go index df85d3a4..44c0b980 100644 --- a/controllers/groupHttpController.go +++ b/controllers/groupHttpController.go @@ -3,6 +3,7 @@ package controller import ( "gopkg.in/go-playground/validator.v9" "github.com/gravitl/netmaker/models" + "encoding/base64" "github.com/gravitl/netmaker/functions" "github.com/gravitl/netmaker/mongoconn" "time" @@ -20,6 +21,7 @@ import ( func groupHandlers(r *mux.Router) { r.HandleFunc("/api/groups", securityCheck(http.HandlerFunc(getGroups))).Methods("GET") r.HandleFunc("/api/groups", securityCheck(http.HandlerFunc(createGroup))).Methods("POST") + r.HandleFunc("/api/groups/{groupname}/keyupdate", securityCheck(http.HandlerFunc(keyUpdate))).Methods("POST") r.HandleFunc("/api/groups/{groupname}", securityCheck(http.HandlerFunc(getGroup))).Methods("GET") r.HandleFunc("/api/groups/{groupname}/numnodes", securityCheck(http.HandlerFunc(getGroupNodeNumber))).Methods("GET") r.HandleFunc("/api/groups/{groupname}", securityCheck(http.HandlerFunc(updateGroup))).Methods("PUT") @@ -147,7 +149,7 @@ func getGroupNodeNumber(w http.ResponseWriter, r *http.Request) { //maybe a functions/ folder and then a node.go, group.go, keys.go, misc.go func GetGroupNodeNumber(groupName string) (int, error){ - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -175,7 +177,7 @@ func getGroup(w http.ResponseWriter, r *http.Request) { var group models.Group - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -192,6 +194,59 @@ func getGroup(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(group) } +func keyUpdate(w http.ResponseWriter, r *http.Request) { + + w.Header().Set("Content-Type", "application/json") + + var params = mux.Vars(r) + + var group models.Group + + group, err := functions.GetParentGroup(params["groupname"]) + if err != nil { + return + } + + group.KeyUpdateTimeStamp = time.Now().Unix() + + collection := mongoconn.Client.Database("netmaker").Collection("groups") + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + filter := bson.M{"nameid": params["groupname"]} + + // prepare update model. + update := bson.D{ + {"$set", bson.D{ + {"addressrange", group.AddressRange}, + {"displayname", group.DisplayName}, + {"defaultlistenport", group.DefaultListenPort}, + {"defaultpostup", group.DefaultPostUp}, + {"defaultpreup", group.DefaultPreUp}, + {"defaultkeepalive", group.DefaultKeepalive}, + {"keyupdatetimestamp", group.KeyUpdateTimeStamp}, + {"defaultsaveconfig", group.DefaultSaveConfig}, + {"defaultinterface", group.DefaultInterface}, + {"nodeslastmodified", group.NodesLastModified}, + {"grouplastmodified", group.GroupLastModified}, + {"allowmanualsignup", group.AllowManualSignUp}, + {"defaultcheckininterval", group.DefaultCheckInInterval}, + }}, + } + + errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&group) + + defer cancel() + + if errN != nil { + mongoconn.GetError(errN, w) + fmt.Println(errN) + return + } + + json.NewEncoder(w).Encode(group) +} + //Update a group func updateGroup(w http.ResponseWriter, r *http.Request) { @@ -285,7 +340,7 @@ func updateGroup(w http.ResponseWriter, r *http.Request) { haschange = true } - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -355,7 +410,7 @@ func deleteGroup(w http.ResponseWriter, r *http.Request) { return } - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") filter := bson.M{"nameid": params["groupname"]} @@ -404,9 +459,10 @@ func createGroup(w http.ResponseWriter, r *http.Request) { group.SetDefaults() group.SetNodesLastModified() group.SetGroupLastModified() + group.KeyUpdateTimeStamp = time.Now().Unix() - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -454,11 +510,23 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) { if accesskey.Uses == 0 { accesskey.Uses = 1 } + gconf, errG := functions.GetGlobalConfig() + if errG != nil { + mongoconn.GetError(errG, w) + return + } + + + network := params["groupname"] + address := gconf.ServerGRPC + gconf.PortGRPC + + accessstringdec := address + "." + network + "." + accesskey.Value + accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec)) group.AccessKeys = append(group.AccessKeys, accesskey) - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -495,9 +563,9 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) { var params = mux.Vars(r) var group models.Group - var keys []models.DisplayKey - - collection := mongoconn.Client.Database("wirecat").Collection("groups") + //var keys []models.DisplayKey + var keys []models.AccessKey + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -522,6 +590,7 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(keys) } + //delete key. Has to do a little funky logic since it's not a collection item func deleteAccessKey(w http.ResponseWriter, r *http.Request) { @@ -549,7 +618,7 @@ func deleteAccessKey(w http.ResponseWriter, r *http.Request) { } } - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) diff --git a/controllers/nodeGrpcController.go b/controllers/nodeGrpcController.go index 32a008e2..df84e7b9 100644 --- a/controllers/nodeGrpcController.go +++ b/controllers/nodeGrpcController.go @@ -171,7 +171,9 @@ func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq) Checkinresponse: &nodepb.CheckInResponse{ Success: checkinresponse.Success, Needpeerupdate: checkinresponse.NeedPeerUpdate, + Needdelete: checkinresponse.NeedDelete, Needconfigupdate: checkinresponse.NeedConfigUpdate, + Needkeyupdate: checkinresponse.NeedKeyUpdate, Nodemessage: checkinresponse.NodeMessage, Ispending: checkinresponse.IsPending, }, diff --git a/controllers/nodeHttpController.go b/controllers/nodeHttpController.go index 2abba74b..16d0b0e4 100644 --- a/controllers/nodeHttpController.go +++ b/controllers/nodeHttpController.go @@ -67,7 +67,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) { } else { //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved). - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) var err = collection.FindOne(ctx, bson.M{ "macaddress": authRequest.MacAddress, "ispending": false }).Decode(&result) @@ -237,7 +237,7 @@ func getPeerList(w http.ResponseWriter, r *http.Request) { var params = mux.Vars(r) //Connection mongoDB with mongoconn class - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -291,7 +291,7 @@ func getGroupNodes(w http.ResponseWriter, r *http.Request) { var nodes []models.ReturnNode var params = mux.Vars(r) - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -343,7 +343,7 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) { var nodes []models.ReturnNode - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -404,11 +404,11 @@ func checkIn(w http.ResponseWriter, r *http.Request) { //Retrieves node with DB Call which is inefficient. Let's just get the time and set it. //node = functions.GetNodeByMacAddress(params["group"], params["macaddress"]) - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - filter := bson.M{"macaddress": params["macaddress"]} + filter := bson.M{"macaddress": params["macaddress"], "group": params["group"]} //old code was inefficient, this is all we need. time := time.Now().String() @@ -463,7 +463,7 @@ func getLastModified(w http.ResponseWriter, r *http.Request) { var group models.Group var params = mux.Vars(r) - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -565,12 +565,12 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) { return } - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // Create filter - filter := bson.M{"macaddress": params["macaddress"]} + filter := bson.M{"macaddress": params["macaddress"], "group": params["group"]} node.SetLastModified() diff --git a/controllers/userHttpController.go b/controllers/userHttpController.go index d166baa4..9691eaea 100644 --- a/controllers/userHttpController.go +++ b/controllers/userHttpController.go @@ -60,7 +60,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { } else { //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved). - collection := mongoconn.Client.Database("wirecat").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) var err = collection.FindOne(ctx, bson.M{ "username": authRequest.UserName }).Decode(&result) @@ -179,7 +179,7 @@ func authorizeUser(next http.Handler) http.HandlerFunc { func HasAdmin() (bool, error){ - collection := mongoconn.Client.Database("wirecat").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -217,7 +217,7 @@ func GetUser(username string) (models.User, error) { var user models.User - collection := mongoconn.Client.Database("wirecat").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -265,7 +265,7 @@ func CreateUser(user models.User) (models.User, error) { } // connect db - collection := mongoconn.Client.Database("wirecat").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) // insert our node to the node db. @@ -336,7 +336,7 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) { user.Password = userchange.Password } //collection := mongoconn.ConnectDB() - collection := mongoconn.Client.Database("wirecat").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -416,7 +416,7 @@ func DeleteUser(user string) (bool, error) { deleted := false - collection := mongoconn.Client.Database("wirecat").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") filter := bson.M{"username": user} diff --git a/docker-compose.yml b/docker-compose.yml index f4d6dfd7..25eecd25 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,7 +16,7 @@ services: container_name: netmaker depends_on: - mongodb - image: gravitl/netmaker:v0.1 + image: gravitl/netmaker:v0.1-hotfix ports: - "8081:8081" - "50051:50051" diff --git a/docs/API.md b/docs/API.md index 097e1d2b..882d520e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -35,7 +35,7 @@ **Authenticate User:** "/users/authenticate", "POST" *note: users API does not use /api/ because of a weird bug. Will fix in future release. -**note: Only able to create Admin at this time. The "user" is only used by the [user interface](https://github.com/falconcat-inc/WireCat-UI) to authenticate the single admin user. +**note: Only able to create Admin at this time. The "user" is only used by the [user interface](https://github.com/gravitl/netmaker-ui) to authenticate the single admin user. ### Files **Get File:** "/meshclient/files/{filename}", "GET" diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index a7fc98cc..34865b2c 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -2,8 +2,8 @@ ### Server Setup 1. Get yourself a linux server and make sure it has a public IP. 2. Deploy MongoDB `docker volume create mongovol && docker run -d --name mongodb -v mongovol:/data/db --network host -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=mongopass mongo --bind_ip 0.0.0.0 ` - 3. Pull this repo: `git clone https://github.com/falconcat-inc/WireCat.git` - 4. Switch to the directory and source the default env vars `cd WireCat && source defaultvars.sh` + 3. Pull this repo: `git clone https://github.com/gravitl/netmaker.git` + 4. Switch to the directory and source the default env vars `cd netmaker && source defaultvars.sh` 5. Run the server: `go run ./` ### Optional (For Testing): Create Groups and Nodes @@ -13,7 +13,7 @@ 4. Create Nodes: `./test/nodescreate.sh` 5. Check to see if nodes were created: `curl -H "authorization: Bearer secretkey" localhost:8081/api/skynet/nodes | jq` ### UI Setup -Please see [this repo](https://github.com/falconcat-inc/WireCat-UI) for instructions on setting up your UI. +Please see [this repo](https://github.com/gravitl/netmaker-ui) for instructions on setting up your UI. ### Agent Setup diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index a7c54b8d..97e606dd 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -71,7 +71,7 @@ - [ ] "Read Only" mode for nodes (can't update their settings centrally, only read) **Agent:** - - [ ] Do system calls instead of direct comma[this repo](https://github.com/falconcat-inc/WireCat-UI)nds + - [ ] Do system calls instead of direct commands [this repo](https://github.com/gravitl/netmaker-ui) - [ ] Add a prompt for easy setup - [ ] Make it work as a sidecar container!!! diff --git a/functions/helpers.go b/functions/helpers.go index 1cf60fd3..1c5461dd 100644 --- a/functions/helpers.go +++ b/functions/helpers.go @@ -29,7 +29,7 @@ func IsFieldUnique(group string, field string, value string) bool { var node models.Node isunique := true - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) filter := bson.M{field: value, "group": group} @@ -51,7 +51,7 @@ func IsFieldUnique(group string, field string, value string) bool { func GroupExists(name string) (bool, error) { - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -78,7 +78,7 @@ func GroupExists(name string) (bool, error) { func UpdateGroupNodeAddresses(groupName string) error { //Connection mongoDB with mongoconn class - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -158,7 +158,7 @@ func IsGroupDisplayNameUnique(name string) bool { func ListGroups() []models.Group{ var groups []models.Group - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -222,7 +222,7 @@ func GetParentGroup(groupname string) (models.Group, error) { var group models.Group - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -275,7 +275,7 @@ func GetNodeObj(id primitive.ObjectID) models.Node { var node models.Node - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) filter := bson.M{"_id": id} @@ -329,7 +329,7 @@ func GetNodeByMacAddress(group string, macaddress string) (models.Node, error) { filter := bson.M{"macaddress": macaddress, "group": group} - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -377,6 +377,31 @@ func UniqueAddress(groupName string) (string, error){ return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1 } +//pretty simple get +func GetGlobalConfig() ( models.GlobalConfig, error) { + + filter := bson.M{} + + var globalconf models.GlobalConfig + + collection := mongoconn.Client.Database("netmaker").Collection("config") + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + err := collection.FindOne(ctx, filter).Decode(&globalconf) + + defer cancel() + + if err != nil { + fmt.Println(err) + fmt.Println("Could not get global config") + return globalconf, err + } + return globalconf, err +} + + + //generate an access key value func GenKey() string { @@ -420,7 +445,7 @@ func IsIPUnique(group string, ip string) bool { isunique := true - collection := mongoconn.Client.Database("wirecat").Collection("nodes") + collection := mongoconn.Client.Database("netmaker").Collection("nodes") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) filter := bson.M{"address": ip, "group": group} @@ -465,7 +490,7 @@ func DecrimentKey(groupName string, keyvalue string) { } } - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -490,7 +515,7 @@ func DeleteKey(group models.Group, i int) { group.AccessKeys = append(group.AccessKeys[:i], group.AccessKeys[i+1:]...) - collection := mongoconn.Client.Database("wirecat").Collection("groups") + collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) diff --git a/group_test.go b/group_test.go new file mode 100644 index 00000000..4e4aead8 --- /dev/null +++ b/group_test.go @@ -0,0 +1,620 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "testing" + + "github.com/gravitl/netmaker/models" + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/mongo" +) + +var Groups []models.Group + +func TestCreateGroup(t *testing.T) { + group := models.Group{} + group.NameID = "skynet" + group.AddressRange = "10.71.0.0/16" + t.Run("CreateGroup", func(t *testing.T) { + response, err := api(t, group, http.MethodPost, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + }) + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, group, http.MethodPost, "http://localhost:8081/api/groups", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("BadName", func(t *testing.T) { + //issue #42 + t.Skip() + }) + t.Run("BadAddress", func(t *testing.T) { + //issue #42 + t.Skip() + }) + t.Run("DuplicateGroup", func(t *testing.T) { + //issue #42 + t.Skip() + }) +} + +func TestGetGroups(t *testing.T) { + t.Run("ValidToken", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + assert.Equal(t, http.StatusOK, response.StatusCode) + err = json.NewDecoder(response.Body).Decode(&Groups) + assert.Nil(t, err, err) + }) + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) +} + +func TestGetGroup(t *testing.T) { + t.Run("ValidToken", func(t *testing.T) { + var group models.Group + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + assert.Equal(t, http.StatusOK, response.StatusCode) + err = json.NewDecoder(response.Body).Decode(&group) + assert.Nil(t, err, err) + assert.Equal(t, "skynet", group.DisplayName) + }) + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("InvalidGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/badgroup", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) +} + +func TestGetGroupNodeNumber(t *testing.T) { + t.Run("ValidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/numnodes", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message int + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + //assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusOK, response.StatusCode) + }) + t.Run("InvalidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/numnodes", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("BadGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/badgroup/numnodes", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) +} + +func TestDeleteGroup(t *testing.T) { + t.Run("InvalidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("ValidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message mongo.DeleteResult + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + assert.Equal(t, int64(1), message.DeletedCount) + + }) + t.Run("BadGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/badgroup", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("NodesExist", func(t *testing.T) { + t.Skip() + }) + //Create Group for follow-on tests + createGroup(t) +} + +func TestCreateAccessKey(t *testing.T) { + key := models.AccessKey{} + key.Name = "skynet" + key.Uses = 10 + t.Run("MultiUse", func(t *testing.T) { + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + message, err := ioutil.ReadAll(response.Body) + assert.Nil(t, err, err) + assert.NotNil(t, message, message) + returnedkey := getKey(t, key.Name) + assert.Equal(t, key.Name, returnedkey.Name) + assert.Equal(t, key.Uses, returnedkey.Uses) + }) + deleteKey(t, "skynet", "skynet") + t.Run("ZeroUse", func(t *testing.T) { + //t.Skip() + key.Uses = 0 + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + message, err := ioutil.ReadAll(response.Body) + assert.Nil(t, err, err) + assert.NotNil(t, message, message) + returnedkey := getKey(t, key.Name) + assert.Equal(t, key.Name, returnedkey.Name) + assert.Equal(t, 1, returnedkey.Uses) + }) + t.Run("DuplicateAccessKey", func(t *testing.T) { + //t.Skip() + //this will fail + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + deleteKey(t, key.Name, "skynet") + }) + + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("BadGroup", func(t *testing.T) { + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/badgroup/keys", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) +} + +func TestDeleteKey(t *testing.T) { + t.Run("KeyValid", func(t *testing.T) { + //fails -- deletecount not returned + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet/keys/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message mongo.DeleteResult + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + assert.Equal(t, int64(1), message.DeletedCount) + }) + t.Run("InValidKey", func(t *testing.T) { + //fails -- status message not returned + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet/keys/badkey", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This key does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("KeyInValidGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/badgroup/keys/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("InvalidCredentials", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet/keys/skynet", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) +} + +func TestGetKeys(t *testing.T) { + createKey(t) + t.Run("Valid", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + var keys []models.AccessKey + err = json.NewDecoder(response.Body).Decode(&keys) + assert.Nil(t, err, err) + }) + //deletekeys + t.Run("InvalidGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/badgroup/keys", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("InvalidCredentials", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/keys", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) +} + +func TestUpdateGroup(t *testing.T) { + var returnedGroup models.Group + t.Run("UpdateNameID", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.NameID, returnedGroup.NameID) + }) + t.Run("NameIDInvalidCredentials", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "badkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + }) + t.Run("InvalidGroup", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/badgroup", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusNotFound, message.Code) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("UpdateNameIDTooLong", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat-skynet" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateAddress", func(t *testing.T) { + type Group struct { + AddressRange string + } + var group Group + group.AddressRange = "10.0.0.1/24" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.AddressRange, returnedGroup.AddressRange) + }) + t.Run("UpdateAddressInvalid", func(t *testing.T) { + type Group struct { + AddressRange string + } + var group Group + group.AddressRange = "10.0.0.1/36" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateDisplayName", func(t *testing.T) { + type Group struct { + DisplayName string + } + var group Group + group.DisplayName = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DisplayName, returnedGroup.DisplayName) + + }) + t.Run("UpdateDisplayNameInvalidName", func(t *testing.T) { + type Group struct { + DisplayName string + } + var group Group + //create name that is longer than 100 chars + name := "" + for i := 0; i < 101; i++ { + name = name + "a" + } + group.DisplayName = name + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DisplayName' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateInterface", func(t *testing.T) { + type Group struct { + DefaultInterface string + } + var group Group + group.DefaultInterface = "netmaker" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultInterface, returnedGroup.DefaultInterface) + + }) + t.Run("UpdateListenPort", func(t *testing.T) { + type Group struct { + DefaultListenPort int32 + } + var group Group + group.DefaultListenPort = 6000 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultListenPort, returnedGroup.DefaultListenPort) + }) + t.Run("UpdateListenPortInvalidPort", func(t *testing.T) { + type Group struct { + DefaultListenPort int32 + } + var group Group + group.DefaultListenPort = 1023 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DefaultListenPort' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdatePostUP", func(t *testing.T) { + type Group struct { + DefaultPostUp string + } + var group Group + group.DefaultPostUp = "sudo wg add-conf wc-netmaker /etc/wireguard/peers/conf" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultPostUp, returnedGroup.DefaultPostUp) + }) + t.Run("UpdatePreUP", func(t *testing.T) { + type Group struct { + DefaultPreUp string + } + var group Group + group.DefaultPreUp = "test string" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultPreUp, returnedGroup.DefaultPreUp) + }) + t.Run("UpdateKeepAlive", func(t *testing.T) { + type Group struct { + DefaultKeepalive int32 + } + var group Group + group.DefaultKeepalive = 60 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultKeepalive, returnedGroup.DefaultKeepalive) + }) + t.Run("UpdateKeepAliveTooBig", func(t *testing.T) { + type Group struct { + DefaultKeepAlive int32 + } + var group Group + group.DefaultKeepAlive = 1001 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DefaultKeepAlive' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateSaveConfig", func(t *testing.T) { + //causes panic + t.Skip() + type Group struct { + DefaultSaveConfig *bool + } + var group Group + value := false + group.DefaultSaveConfig = &value + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, *group.DefaultSaveConfig, *returnedGroup.DefaultSaveConfig) + }) + t.Run("UpdateManualSignUP", func(t *testing.T) { + t.Skip() + type Group struct { + AllowManualSignUp *bool + } + var group Group + value := true + group.AllowManualSignUp = &value + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, *group.AllowManualSignUp, *returnedGroup.AllowManualSignUp) + }) + t.Run("DefaultCheckInterval", func(t *testing.T) { + type Group struct { + DefaultCheckInInterval int32 + } + var group Group + group.DefaultCheckInInterval = 6000 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultCheckInInterval, returnedGroup.DefaultCheckInInterval) + }) + t.Run("DefaultCheckIntervalTooBig", func(t *testing.T) { + type Group struct { + DefaultCheckInInterval int32 + } + var group Group + group.DefaultCheckInInterval = 100001 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DefaultCheckInInterval' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("MultipleFields", func(t *testing.T) { + type Group struct { + DisplayName string + DefaultListenPort int32 + } + var group Group + group.DefaultListenPort = 7777 + group.DisplayName = "multi" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DisplayName, returnedGroup.DisplayName) + assert.Equal(t, group.DefaultListenPort, returnedGroup.DefaultListenPort) + }) +} diff --git a/grpc/node.pb.go b/grpc/node.pb.go index 3b25cc21..5bb25a63 100644 --- a/grpc/node.pb.go +++ b/grpc/node.pb.go @@ -311,6 +311,8 @@ type CheckInResponse struct { Needconfigupdate bool `protobuf:"varint,3,opt,name=needconfigupdate,proto3" json:"needconfigupdate,omitempty"` Nodemessage string `protobuf:"bytes,4,opt,name=nodemessage,proto3" json:"nodemessage,omitempty"` Ispending bool `protobuf:"varint,5,opt,name=ispending,proto3" json:"ispending,omitempty"` + Needkeyupdate bool `protobuf:"varint,6,opt,name=needkeyupdate,proto3" json:"needkeyupdate,omitempty"` + Needdelete bool `protobuf:"varint,7,opt,name=needdelete,proto3" json:"needdelete,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -376,6 +378,20 @@ func (m *CheckInResponse) GetIspending() bool { return false } +func (m *CheckInResponse) GetNeedkeyupdate() bool { + if m != nil { + return m.Needkeyupdate + } + return false +} + +func (m *CheckInResponse) GetNeeddelete() bool { + if m != nil { + return m.Needdelete + } + return false +} + type PeersResponse struct { Publickey string `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"` Endpoint string `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"` @@ -970,56 +986,58 @@ func init() { func init() { proto.RegisterFile("grpc/node.proto", fileDescriptor_d13bd996b67da4ef) } var fileDescriptor_d13bd996b67da4ef = []byte{ - // 813 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4d, 0x6f, 0xf3, 0x44, - 0x10, 0x56, 0xf2, 0x26, 0x4d, 0x32, 0x69, 0x9a, 0xbe, 0xdb, 0x16, 0xad, 0xac, 0xaa, 0x8a, 0x7c, - 0x40, 0x29, 0xa2, 0x49, 0x29, 0x12, 0xe2, 0x86, 0x44, 0x91, 0x10, 0x08, 0x2a, 0x64, 0xc4, 0x85, - 0xdb, 0xc6, 0x9e, 0xb8, 0x56, 0x9c, 0xdd, 0x8d, 0xd7, 0x4e, 0xd5, 0x5f, 0xc7, 0x89, 0x7f, 0xc4, - 0x91, 0x03, 0xda, 0x5d, 0x3b, 0xfe, 0x68, 0x48, 0xfb, 0xf6, 0x96, 0x79, 0x76, 0xbe, 0xe7, 0x99, - 0x89, 0x61, 0x1c, 0x26, 0xd2, 0x9f, 0x73, 0x11, 0xe0, 0x4c, 0x26, 0x22, 0x15, 0xa4, 0xa3, 0x7f, - 0xbb, 0x3f, 0xc3, 0xf1, 0x2f, 0x22, 0x8c, 0xb8, 0x87, 0x9b, 0x0c, 0x55, 0x4a, 0xae, 0x00, 0xd6, - 0xcc, 0x67, 0x41, 0x90, 0xa0, 0x52, 0xb4, 0x35, 0x69, 0x4d, 0x07, 0x5e, 0x05, 0x21, 0x0e, 0xf4, - 0x25, 0x53, 0xea, 0x49, 0x24, 0x01, 0x6d, 0x9b, 0xd7, 0x9d, 0xec, 0x7e, 0x05, 0xa3, 0xdc, 0x97, - 0x92, 0x82, 0x2b, 0x24, 0x13, 0x18, 0x32, 0xdf, 0x47, 0xa5, 0x52, 0xb1, 0x42, 0x9e, 0x7b, 0xab, - 0x42, 0xee, 0x3f, 0x1d, 0xe8, 0x3c, 0x88, 0x00, 0xc9, 0x09, 0xb4, 0xa3, 0x20, 0xd7, 0x68, 0x47, - 0x01, 0x21, 0xd0, 0xe1, 0x6c, 0x8d, 0x79, 0x0c, 0xf3, 0x9b, 0x50, 0xe8, 0x15, 0x89, 0x7d, 0x30, - 0x70, 0x21, 0xea, 0xac, 0xe3, 0x48, 0xa5, 0xc8, 0xa5, 0x48, 0x52, 0xda, 0x99, 0xb4, 0xa6, 0x5d, - 0xaf, 0x82, 0x90, 0x4b, 0x18, 0xc8, 0x6c, 0x11, 0x47, 0xfe, 0x0a, 0x9f, 0x69, 0xd7, 0xd8, 0x96, - 0x80, 0xae, 0x09, 0x79, 0x20, 0x45, 0xc4, 0x53, 0x7a, 0x64, 0x6b, 0x2a, 0xe4, 0x46, 0x3f, 0x7a, - 0x07, 0xfb, 0xd1, 0xaf, 0xf7, 0x43, 0x47, 0xd5, 0x3d, 0x0e, 0x13, 0x91, 0x49, 0x3a, 0xb0, 0x51, - 0x77, 0x80, 0x7e, 0x8d, 0x94, 0x44, 0x1e, 0x44, 0x3c, 0xa4, 0x30, 0x69, 0x4d, 0xfb, 0x5e, 0x09, - 0x90, 0xcf, 0xe0, 0x48, 0x0a, 0x95, 0x66, 0x92, 0x0e, 0x8d, 0x61, 0x2e, 0x91, 0x73, 0xe8, 0xca, - 0x04, 0x33, 0x49, 0x8f, 0x0d, 0x6c, 0x05, 0xed, 0x6b, 0x85, 0x28, 0x59, 0x1c, 0x6d, 0x91, 0x8e, - 0x4c, 0xf9, 0x25, 0xa0, 0x6b, 0x50, 0x6c, 0x8b, 0xbe, 0xe0, 0xcb, 0x28, 0xa4, 0x27, 0x26, 0x54, - 0x05, 0xd1, 0xd6, 0x76, 0x26, 0xba, 0x3b, 0x63, 0x9b, 0xe7, 0x0e, 0x30, 0x79, 0xf2, 0x14, 0x93, - 0x25, 0xf3, 0x91, 0x9e, 0xda, 0xd7, 0x1d, 0xa0, 0x47, 0x1c, 0x33, 0x95, 0xfa, 0x8f, 0xe8, 0xaf, - 0x22, 0x4e, 0x3f, 0xda, 0x11, 0x57, 0x20, 0xe2, 0xc2, 0xb1, 0x16, 0xd7, 0x22, 0x88, 0x96, 0x11, - 0x06, 0x94, 0x18, 0x95, 0x1a, 0x46, 0xa6, 0x30, 0xce, 0xd5, 0x8d, 0xe7, 0x2d, 0x8b, 0xe9, 0x99, - 0xa9, 0xa2, 0x09, 0x1b, 0x6f, 0xc2, 0x67, 0x71, 0x31, 0x91, 0xf3, 0xdc, 0x5b, 0x05, 0xd3, 0x39, - 0xe9, 0x6e, 0xf9, 0x8f, 0x8c, 0x87, 0xa8, 0xe8, 0x85, 0xcd, 0xa9, 0x02, 0xb9, 0x7f, 0xb5, 0x60, - 0x7c, 0xaf, 0x3d, 0xff, 0x54, 0x92, 0x95, 0x42, 0x4f, 0x65, 0xa6, 0x6a, 0x43, 0xc3, 0xbe, 0x57, - 0x88, 0xe4, 0x73, 0x38, 0xe1, 0x88, 0x81, 0x44, 0x4c, 0x32, 0x19, 0xb0, 0xd4, 0xb2, 0xb2, 0xef, - 0x35, 0x50, 0xf2, 0x05, 0x9c, 0x6a, 0xc4, 0x76, 0x35, 0xd7, 0xfc, 0x60, 0x34, 0x5f, 0xe0, 0x3a, - 0x47, 0x4d, 0x85, 0x35, 0x2a, 0xc5, 0x42, 0x34, 0x94, 0x1d, 0x78, 0x55, 0xa8, 0xce, 0x8f, 0x6e, - 0x83, 0x1f, 0xee, 0xdf, 0x2d, 0x18, 0xfd, 0x86, 0x98, 0xa8, 0x5d, 0xfe, 0xef, 0xe7, 0xf8, 0xfb, - 0xf7, 0xaa, 0x39, 0x8d, 0xde, 0x9e, 0x69, 0x1c, 0xe4, 0xa6, 0x3b, 0x87, 0xd1, 0x7d, 0x82, 0x2c, - 0x45, 0x7d, 0x05, 0x3c, 0xdc, 0x90, 0x2b, 0x30, 0x87, 0xc9, 0xcc, 0x60, 0x78, 0x07, 0x33, 0x73, - 0xb1, 0xcc, 0xa3, 0x3d, 0x58, 0x0d, 0x03, 0xf5, 0x16, 0x83, 0x3f, 0x4c, 0xcf, 0x3f, 0x21, 0x42, - 0xd5, 0xe0, 0xf5, 0x08, 0xf7, 0x30, 0xf4, 0x90, 0x05, 0xa5, 0xff, 0xc3, 0x27, 0xf4, 0x1c, 0xba, - 0xf6, 0x24, 0xd8, 0xdb, 0x66, 0x05, 0xf7, 0xa6, 0xea, 0xe4, 0xf5, 0x98, 0xbf, 0xc2, 0xe8, 0x07, - 0x8c, 0xb1, 0x5a, 0xd5, 0xe1, 0xa8, 0x97, 0x30, 0x30, 0x81, 0x1e, 0xca, 0xab, 0x5a, 0x02, 0xee, - 0x75, 0xdd, 0x9d, 0xfa, 0xff, 0x6d, 0xd0, 0xd5, 0xfe, 0x88, 0x69, 0xce, 0xbd, 0xf7, 0x56, 0xfb, - 0x6d, 0xd5, 0x89, 0x22, 0xd7, 0xd0, 0xd5, 0x7b, 0xa4, 0xf2, 0x72, 0xcf, 0x6c, 0xb9, 0x35, 0x7e, - 0x7b, 0x56, 0xc3, 0xfd, 0x12, 0x60, 0xb7, 0xb9, 0x9b, 0x37, 0xb4, 0xa9, 0xd4, 0x56, 0xe4, 0xbb, - 0xdd, 0x99, 0x49, 0x72, 0xaf, 0xb9, 0xe1, 0x85, 0x35, 0x6c, 0x9c, 0x04, 0xaf, 0xa9, 0x7d, 0xf7, - 0x6f, 0x1b, 0x86, 0xda, 0xfb, 0xef, 0x98, 0x6c, 0x23, 0x1f, 0xc9, 0x2d, 0x74, 0xcd, 0x3f, 0x1e, - 0x21, 0xd6, 0x41, 0xf5, 0xaf, 0xd4, 0x39, 0xab, 0x61, 0xf9, 0x96, 0x7e, 0x03, 0x50, 0xd2, 0x97, - 0xe4, 0x2a, 0xb5, 0x0d, 0x70, 0xf6, 0x80, 0x8a, 0xdc, 0x42, 0xbf, 0xa0, 0x07, 0xf9, 0x68, 0x15, - 0x2a, 0x9c, 0x73, 0x5e, 0x40, 0x4a, 0x47, 0x2a, 0x69, 0x5c, 0x44, 0xaa, 0x6d, 0x82, 0xb3, 0x07, - 0x34, 0x76, 0x25, 0x15, 0x0a, 0xbb, 0x1a, 0xd7, 0x9c, 0x3d, 0xa0, 0x22, 0x77, 0xd0, 0x2f, 0x46, - 0x5a, 0x64, 0x58, 0xe1, 0x89, 0xf3, 0x02, 0x52, 0xb7, 0x2d, 0x72, 0x03, 0xbd, 0xbc, 0xe7, 0xe4, - 0xb4, 0x31, 0x82, 0x8d, 0xd3, 0x44, 0xd4, 0xf7, 0xf3, 0x3f, 0x6f, 0x42, 0x21, 0xc2, 0x18, 0x67, - 0xa1, 0x88, 0x19, 0x0f, 0x67, 0x22, 0x09, 0xe7, 0xe6, 0x6b, 0x66, 0x91, 0x2d, 0xe7, 0xe9, 0xb3, - 0x44, 0x35, 0x5f, 0x71, 0xf1, 0xc4, 0xcd, 0x77, 0x8e, 0x5c, 0x2c, 0x8e, 0xcc, 0xe3, 0xd7, 0xff, - 0x05, 0x00, 0x00, 0xff, 0xff, 0x04, 0x8b, 0xcd, 0xc5, 0xfd, 0x08, 0x00, 0x00, + // 839 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0xe3, 0x44, + 0x14, 0x56, 0xb2, 0x49, 0xe3, 0x9c, 0x34, 0x6d, 0x77, 0xda, 0x45, 0x23, 0x6b, 0xb5, 0x8a, 0x2c, + 0x84, 0xb2, 0x88, 0x26, 0xa5, 0x48, 0x88, 0x3b, 0x24, 0x8a, 0x84, 0x40, 0xb0, 0x42, 0x46, 0xdc, + 0x70, 0x37, 0xb1, 0x4f, 0xbc, 0x56, 0x9c, 0x99, 0x89, 0xc7, 0xce, 0xaa, 0x0f, 0xc0, 0xa3, 0xf1, + 0x46, 0x5c, 0x72, 0x81, 0xe6, 0xc7, 0xf1, 0x4f, 0x43, 0xb7, 0xf4, 0x2e, 0xe7, 0x9b, 0xf3, 0x7f, + 0xbe, 0x73, 0x62, 0x38, 0x4f, 0x72, 0x19, 0x2d, 0xb9, 0x88, 0x71, 0x21, 0x73, 0x51, 0x08, 0x32, + 0xd0, 0xbf, 0x83, 0x9f, 0xe0, 0xf4, 0x67, 0x91, 0xa4, 0x3c, 0xc4, 0x5d, 0x89, 0xaa, 0x20, 0x6f, + 0x00, 0xb6, 0x2c, 0x62, 0x71, 0x9c, 0xa3, 0x52, 0xb4, 0x37, 0xeb, 0xcd, 0xc7, 0x61, 0x03, 0x21, + 0x3e, 0x78, 0x92, 0x29, 0xf5, 0x41, 0xe4, 0x31, 0xed, 0x9b, 0xd7, 0x83, 0x1c, 0x7c, 0x09, 0x53, + 0xe7, 0x4b, 0x49, 0xc1, 0x15, 0x92, 0x19, 0x4c, 0x58, 0x14, 0xa1, 0x52, 0x85, 0xd8, 0x20, 0x77, + 0xde, 0x9a, 0x50, 0xf0, 0xf7, 0x00, 0x06, 0xef, 0x44, 0x8c, 0xe4, 0x0c, 0xfa, 0x69, 0xec, 0x34, + 0xfa, 0x69, 0x4c, 0x08, 0x0c, 0x38, 0xdb, 0xa2, 0x8b, 0x61, 0x7e, 0x13, 0x0a, 0xa3, 0x2a, 0xb1, + 0x17, 0x06, 0xae, 0x44, 0x9d, 0x75, 0x96, 0xaa, 0x02, 0xb9, 0x14, 0x79, 0x41, 0x07, 0xb3, 0xde, + 0x7c, 0x18, 0x36, 0x10, 0xf2, 0x1a, 0xc6, 0xb2, 0x5c, 0x65, 0x69, 0xb4, 0xc1, 0x7b, 0x3a, 0x34, + 0xb6, 0x35, 0xa0, 0x6b, 0x42, 0x1e, 0x4b, 0x91, 0xf2, 0x82, 0x9e, 0xd8, 0x9a, 0x2a, 0xb9, 0xd3, + 0x8f, 0xd1, 0xa3, 0xfd, 0xf0, 0xda, 0xfd, 0xd0, 0x51, 0x75, 0x8f, 0x93, 0x5c, 0x94, 0x92, 0x8e, + 0x6d, 0xd4, 0x03, 0xa0, 0x5f, 0x53, 0x25, 0x91, 0xc7, 0x29, 0x4f, 0x28, 0xcc, 0x7a, 0x73, 0x2f, + 0xac, 0x01, 0xf2, 0x09, 0x9c, 0x48, 0xa1, 0x8a, 0x52, 0xd2, 0x89, 0x31, 0x74, 0x12, 0xb9, 0x82, + 0xa1, 0xcc, 0xb1, 0x94, 0xf4, 0xd4, 0xc0, 0x56, 0xd0, 0xbe, 0x36, 0x88, 0x92, 0x65, 0xe9, 0x1e, + 0xe9, 0xd4, 0x94, 0x5f, 0x03, 0xba, 0x06, 0xc5, 0xf6, 0x18, 0x09, 0xbe, 0x4e, 0x13, 0x7a, 0x66, + 0x42, 0x35, 0x10, 0x6d, 0x6d, 0x67, 0xa2, 0xbb, 0x73, 0x6e, 0xf3, 0x3c, 0x00, 0x26, 0x4f, 0x5e, + 0x60, 0xbe, 0x66, 0x11, 0xd2, 0x0b, 0xfb, 0x7a, 0x00, 0xf4, 0x88, 0x33, 0xa6, 0x8a, 0xe8, 0x3d, + 0x46, 0x9b, 0x94, 0xd3, 0x97, 0x76, 0xc4, 0x0d, 0x88, 0x04, 0x70, 0xaa, 0xc5, 0xad, 0x88, 0xd3, + 0x75, 0x8a, 0x31, 0x25, 0x46, 0xa5, 0x85, 0x91, 0x39, 0x9c, 0x3b, 0x75, 0xe3, 0x79, 0xcf, 0x32, + 0x7a, 0x69, 0xaa, 0xe8, 0xc2, 0xc6, 0x9b, 0x88, 0x58, 0x56, 0x4d, 0xe4, 0xca, 0x79, 0x6b, 0x60, + 0x3a, 0x27, 0xdd, 0xad, 0xe8, 0x3d, 0xe3, 0x09, 0x2a, 0xfa, 0xca, 0xe6, 0xd4, 0x80, 0x82, 0x3f, + 0xfb, 0x70, 0x7e, 0xa7, 0x3d, 0xff, 0x58, 0x93, 0x95, 0xc2, 0x48, 0x95, 0xa6, 0x6a, 0x43, 0x43, + 0x2f, 0xac, 0x44, 0xf2, 0x19, 0x9c, 0x71, 0xc4, 0x58, 0x22, 0xe6, 0xa5, 0x8c, 0x59, 0x61, 0x59, + 0xe9, 0x85, 0x1d, 0x94, 0x7c, 0x0e, 0x17, 0x1a, 0xb1, 0x5d, 0x75, 0x9a, 0x2f, 0x8c, 0xe6, 0x03, + 0x5c, 0xe7, 0xa8, 0xa9, 0xb0, 0x45, 0xa5, 0x58, 0x82, 0x86, 0xb2, 0xe3, 0xb0, 0x09, 0xb5, 0xf9, + 0x31, 0xec, 0xf2, 0xe3, 0x53, 0x98, 0x6a, 0x9f, 0x1b, 0xbc, 0x77, 0x81, 0x4e, 0x8c, 0x46, 0x1b, + 0xd4, 0x93, 0xd7, 0x40, 0x8c, 0x19, 0x16, 0x68, 0xd8, 0xeb, 0x85, 0x0d, 0x24, 0xf8, 0xab, 0x07, + 0xd3, 0x5f, 0x11, 0x73, 0x75, 0xe8, 0xc2, 0xf3, 0x37, 0xe5, 0xf9, 0xdb, 0xd9, 0x9d, 0xe9, 0xe8, + 0xc8, 0x4c, 0x1f, 0x65, 0x78, 0xb0, 0x84, 0xe9, 0x5d, 0x8e, 0xac, 0x40, 0x7d, 0x4b, 0x42, 0xdc, + 0x91, 0x37, 0x60, 0xce, 0x9b, 0x99, 0xe4, 0xe4, 0x16, 0x16, 0xe6, 0xee, 0x99, 0x47, 0x7b, 0xf6, + 0x3a, 0x06, 0xea, 0x29, 0x06, 0xbf, 0x9b, 0x9e, 0xfe, 0x8f, 0x08, 0x4d, 0x83, 0x8f, 0x47, 0xb8, + 0x83, 0x49, 0x88, 0x2c, 0xae, 0xfd, 0x3f, 0x7e, 0x88, 0xaf, 0x60, 0x68, 0x0f, 0x8b, 0xbd, 0x90, + 0x56, 0x08, 0xae, 0x9b, 0x4e, 0x3e, 0x1e, 0xf3, 0x17, 0x98, 0x7e, 0x6f, 0x98, 0xf0, 0xd4, 0xa8, + 0xaf, 0x61, 0x6c, 0x02, 0xbd, 0xab, 0x6f, 0x73, 0x0d, 0x04, 0x6f, 0xdb, 0xee, 0xd4, 0x7f, 0xef, + 0x94, 0xae, 0xf6, 0x07, 0x2c, 0x1c, 0xf7, 0x9e, 0x5b, 0xed, 0x37, 0x4d, 0x27, 0x8a, 0xbc, 0x85, + 0xa1, 0xde, 0x46, 0xe5, 0xca, 0xbd, 0xb4, 0xe5, 0xb6, 0xf8, 0x1d, 0x5a, 0x8d, 0xe0, 0x0b, 0x80, + 0xc3, 0xfe, 0xef, 0x9e, 0xd0, 0xa6, 0x5a, 0x5b, 0x91, 0x6f, 0x0f, 0xc7, 0x2a, 0x77, 0x5e, 0x9d, + 0xe1, 0x2b, 0x6b, 0xd8, 0x39, 0x2c, 0x61, 0x57, 0xfb, 0xf6, 0x9f, 0x3e, 0x4c, 0xb4, 0xf7, 0xdf, + 0x30, 0xdf, 0xa7, 0x11, 0x92, 0x1b, 0x18, 0x9a, 0xff, 0x4d, 0x42, 0xac, 0x83, 0xe6, 0x1f, 0xb2, + 0x7f, 0xd9, 0xc2, 0xdc, 0x96, 0x7e, 0x0d, 0x50, 0xd3, 0x97, 0x38, 0x95, 0xd6, 0x06, 0xf8, 0x47, + 0x40, 0x45, 0x6e, 0xc0, 0xab, 0xe8, 0x41, 0x5e, 0x5a, 0x85, 0x06, 0xe7, 0xfc, 0x07, 0x90, 0xd2, + 0x91, 0x6a, 0x1a, 0x57, 0x91, 0x5a, 0x9b, 0xe0, 0x1f, 0x01, 0x8d, 0x5d, 0x4d, 0x85, 0xca, 0xae, + 0xc5, 0x35, 0xff, 0x08, 0xa8, 0xc8, 0x2d, 0x78, 0xd5, 0x48, 0xab, 0x0c, 0x1b, 0x3c, 0xf1, 0x1f, + 0x40, 0xea, 0xa6, 0x47, 0xae, 0x61, 0xe4, 0x7a, 0x4e, 0x2e, 0x3a, 0x23, 0xd8, 0xf9, 0x5d, 0x44, + 0x7d, 0xb7, 0xfc, 0xe3, 0x3a, 0x11, 0x22, 0xc9, 0x70, 0x91, 0x88, 0x8c, 0xf1, 0x64, 0x21, 0xf2, + 0x64, 0x69, 0xbe, 0x89, 0x56, 0xe5, 0x7a, 0x59, 0xdc, 0x4b, 0x54, 0xcb, 0x0d, 0x17, 0x1f, 0xb8, + 0xf9, 0x5a, 0x92, 0xab, 0xd5, 0x89, 0x79, 0xfc, 0xea, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8b, + 0xd7, 0x8e, 0x6d, 0x43, 0x09, 0x00, 0x00, } diff --git a/grpc/node.proto b/grpc/node.proto index b96e03a5..b3bb3631 100644 --- a/grpc/node.proto +++ b/grpc/node.proto @@ -49,6 +49,8 @@ message CheckInResponse { bool needconfigupdate = 3; string nodemessage = 4; bool ispending = 5; + bool needkeyupdate = 6; + bool needdelete = 7; } message PeersResponse { diff --git a/main.go b/main.go index 5a77e327..7956e6b1 100644 --- a/main.go +++ b/main.go @@ -5,10 +5,17 @@ package main import ( "log" + "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/controllers" + "github.com/gravitl/netmaker/functions" "github.com/gravitl/netmaker/mongoconn" "github.com/gravitl/netmaker/config" + "go.mongodb.org/mongo-driver/bson" "fmt" + "time" + "net/http" + "errors" + "io/ioutil" "os" "net" "context" @@ -18,6 +25,10 @@ import ( nodepb "github.com/gravitl/netmaker/grpc" "google.golang.org/grpc" ) + +var ServerGRPC string +var PortGRPC string + //Start MongoDB Connection and start API Request Handler func main() { log.Println("Server starting...") @@ -59,6 +70,27 @@ func runGRPC(wg *sync.WaitGroup) { if os.Getenv("GRPC_PORT") != "" { grpcport = ":" + os.Getenv("GRPC_PORT") } + PortGRPC = grpcport + if os.Getenv("BACKEND_URL") == "" { + if config.Config.Server.Host == "" { + ServerGRPC, _ = getPublicIP() + } else { + ServerGRPC = config.Config.Server.Host + } + } else { + ServerGRPC = os.Getenv("BACKEND_URL") + } + fmt.Println("GRPC Server set to: " + ServerGRPC) + fmt.Println("GRPC Port set to: " + PortGRPC) + var gconf models.GlobalConfig + gconf.ServerGRPC = ServerGRPC + gconf.PortGRPC = PortGRPC + gconf.Name = "netmaker" + err := setGlobalConfig(gconf) + + if err != nil { + log.Fatalf("Unable to set global config: %v", err) + } listener, err := net.Listen("tcp", grpcport) @@ -108,6 +140,59 @@ func runGRPC(wg *sync.WaitGroup) { mongoconn.Client.Disconnect(context.TODO()) fmt.Println("MongoDB connection closed.") } +func setGlobalConfig(globalconf models.GlobalConfig) (error) { + + collection := mongoconn.Client.Database("netmaker").Collection("config") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + _, err := functions.GetGlobalConfig() + if err != nil { + _, err := collection.InsertOne(ctx, globalconf) + defer cancel() + if err != nil { + return err + } + } else { + filter := bson.M{"name": "netmaker"} + update := bson.D{ + {"$set", bson.D{ + {"servergrpc", globalconf.ServerGRPC}, + {"portgrpc", globalconf.PortGRPC}, + }}, + } + err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&globalconf) + } + return nil +} + + +func getPublicIP() (string, error) { + + iplist := []string{"https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"} + endpoint := "" + var err error + for _, ipserver := range iplist { + resp, err := http.Get(ipserver) + if err != nil { + continue + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusOK { + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + continue + } + endpoint = string(bodyBytes) + break + } + + } + if err == nil && endpoint == "" { + err = errors.New("Public Address Not Found.") + } + return endpoint, err +} + func authServerUnaryInterceptor() grpc.ServerOption { return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor) diff --git a/models/group.go b/models/group.go index 18827021..3787a2a3 100644 --- a/models/group.go +++ b/models/group.go @@ -19,6 +19,7 @@ type Group struct { DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,numeric,min=1024,max=65535"` DefaultPostUp string `json:"defaultpostup" bson:"defaultpostup"` DefaultPreUp string `json:"defaultpreup" bson:"defaultpreup"` + KeyUpdateTimeStamp int64 `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"` DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate: "omitempty,numeric,max=1000"` DefaultSaveConfig *bool `json:"defaultsaveconfig" bson:"defaultsaveconfig"` AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"` @@ -41,10 +42,10 @@ func(group *Group) SetDefaults(){ group.DisplayName = group.NameID } if group.DefaultInterface == "" { - group.DefaultInterface = "wc-" + group.NameID + group.DefaultInterface = "nm-" + group.NameID } if group.DefaultListenPort == 0 { - group.DefaultListenPort = 5555 + group.DefaultListenPort = 51821 } if group.DefaultPreUp == "" { @@ -57,12 +58,10 @@ func(group *Group) SetDefaults(){ group.DefaultKeepalive = 20 } if group.DefaultPostUp == "" { - postup := "sudo wg addconf " + group.DefaultInterface + " /etc/wireguard/peers.conf" - group.DefaultPostUp = postup } //Check-In Interval for Nodes, In Seconds if group.DefaultCheckInInterval == 0 { - group.DefaultCheckInInterval = 120 + group.DefaultCheckInInterval = 30 } if group.AllowManualSignUp == nil { signup := false diff --git a/models/node.go b/models/node.go index 02c9036c..34a43e53 100644 --- a/models/node.go +++ b/models/node.go @@ -31,6 +31,8 @@ type Node struct { AccessKey string `json:"accesskey" bson:"accesskey"` Interface string `json:"interface" bson:"interface"` LastModified int64 `json:"lastmodified" bson:"lastmodified"` + KeyUpdateTimeStamp int64 `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"` + ExpirationDateTime int64 `json:"expdatetime" bson:"expdatetime"` LastPeerUpdate int64 `json:"lastpeerupdate" bson:"lastpeerupdate"` LastCheckIn int64 `json:"lastcheckin" bson:"lastcheckin"` MacAddress string `json:"macaddress" bson:"macaddress" validate:"required,macaddress_valid,macaddress_unique"` @@ -49,7 +51,7 @@ func(node *Node) GetGroup() (Group, error){ var group Group collection := mongoconn.GroupDB - //collection := mongoconn.Client.Database("wirecat").Collection("groups") + //collection := mongoconn.Client.Database("netmaker").Collection("groups") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -81,6 +83,11 @@ func(node *Node) SetLastPeerUpdate(){ node.LastPeerUpdate = time.Now().Unix() } +func(node *Node) SetExpirationDateTime(){ + node.ExpirationDateTime = time.Unix(1<<63-62135596801, 999999999).Unix() +} + + func(node *Node) SetDefaultName(){ if node.Name == "" { nodeid := StringWithCharset(5, charset) @@ -96,6 +103,8 @@ func(node *Node) SetDefaults() { //TODO: Maybe I should make Group a part of the node struct. Then we can just query the Group object for stuff. parentGroup, _ := node.GetGroup() + node.ExpirationDateTime = time.Unix(1<<63-62135596801, 999999999).Unix() + if node.ListenPort == 0 { node.ListenPort = parentGroup.DefaultListenPort } diff --git a/models/structs.go b/models/structs.go index 370e465b..5b4fceb0 100644 --- a/models/structs.go +++ b/models/structs.go @@ -64,6 +64,7 @@ type SuccessResponse struct { type AccessKey struct { Name string `json:"name" bson:"name"` Value string `json:"value" bson:"value"` + AccessString string `json:"accessstring" bson:"accessstring"` Uses int `json:"uses" bson:"uses"` } @@ -72,10 +73,19 @@ type DisplayKey struct { Uses int `json:"uses" bson:"uses"` } +type GlobalConfig struct { + Name string `json:"name" bson:"name"` + PortGRPC string `json:"portgrpc" bson:"portgrpc"` + ServerGRPC string `json:"servergrpc" bson:"servergrpc"` +} + + type CheckInResponse struct{ Success bool `json:"success" bson:"success"` NeedPeerUpdate bool `json:"needpeerupdate" bson:"needpeerupdate"` NeedConfigUpdate bool `json:"needconfigupdate" bson:"needconfigupdate"` + NeedKeyUpdate bool `json:"needkeyupdate" bson:"needkeyupdate"` + NeedDelete bool `json:"needdelete" bson:"needdelete"` NodeMessage string `json:"nodemessage" bson:"nodemessage"` IsPending bool `json:"ispending" bson:"ispending"` } diff --git a/mongoconn/mongoconn.go b/mongoconn/mongoconn.go index 1e951d6a..f8f227bd 100644 --- a/mongoconn/mongoconn.go +++ b/mongoconn/mongoconn.go @@ -93,8 +93,8 @@ func ConnectDatabase() { log.Fatal(err) } - NodeDB = Client.Database("wirecat").Collection("nodes") - GroupDB = Client.Database("wirecat").Collection("groups") + NodeDB = Client.Database("netmaker").Collection("nodes") + GroupDB = Client.Database("netmaker").Collection("groups") log.Println("Database Connected.") } diff --git a/netclient/config/config.go b/netclient/config/config.go index 90820e86..935be2dc 100644 --- a/netclient/config/config.go +++ b/netclient/config/config.go @@ -3,18 +3,20 @@ package config import ( // "github.com/davecgh/go-spew/spew" "os" + "errors" "fmt" "log" "gopkg.in/yaml.v3" //homedir "github.com/mitchellh/go-homedir" ) -var Config *ClientConfig +//var Config *ClientConfig // Configurations exported type ClientConfig struct { Server ServerConfig `yaml:"server"` Node NodeConfig `yaml:"node"` + Network string } type ServerConfig struct { Address string `yaml:"address"` @@ -41,7 +43,11 @@ type NodeConfig struct { } //reading in the env file -func Write(config *ClientConfig) error{ +func Write(config *ClientConfig, network string) error{ + if network == "" { + err := errors.New("No network provided. Exiting.") + return err + } nofile := false //home, err := homedir.Dir() _, err := os.Stat("/etc/netclient") @@ -55,11 +61,11 @@ func Write(config *ClientConfig) error{ if err != nil { log.Fatal(err) } - file := fmt.Sprintf(home + "/.netconfig") + file := fmt.Sprintf(home + "/netconfig-" + network) f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) if err != nil { nofile = true - //fmt.Println("Could not access " + home + "/.netconfig, proceeding...") + //fmt.Println("Could not access " + home + "/netconfig, proceeding...") } defer f.Close() @@ -71,7 +77,7 @@ func Write(config *ClientConfig) error{ } } else { - newf, err := os.Create(home + "/.netconfig") + newf, err := os.Create(home + "/netconfig-" + network) err = yaml.NewEncoder(newf).Encode(config) defer newf.Close() if err != nil { @@ -82,7 +88,11 @@ func Write(config *ClientConfig) error{ return err } -func WriteServer(server string, accesskey string) error{ +func WriteServer(server string, accesskey string, network string) error{ + if network == "" { + err := errors.New("No network provided. Exiting.") + return err + } nofile := false //home, err := homedir.Dir() _, err := os.Stat("/etc/netclient") @@ -94,12 +104,12 @@ func WriteServer(server string, accesskey string) error{ } home := "/etc/netclient" - file := fmt.Sprintf(home + "/.netconfig") + file := fmt.Sprintf(home + "/netconfig-" + network) //f, err := os.Open(file) f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR, 0666) //f, err := ioutil.ReadFile(file) if err != nil { - fmt.Println("couldnt open netconfig") + fmt.Println("couldnt open netconfig-" + network) fmt.Println(err) nofile = true //err = nil @@ -111,7 +121,7 @@ func WriteServer(server string, accesskey string) error{ var cfg ClientConfig if !nofile { - fmt.Println("Writing to existing config file at " + home + "/.netconfig") + fmt.Println("Writing to existing config file at " + home + "/netconfig-" + network) decoder := yaml.NewDecoder(f) err = decoder.Decode(&cfg) //err = yaml.Unmarshal(f, &cfg) @@ -145,12 +155,12 @@ func WriteServer(server string, accesskey string) error{ return err } } else { - fmt.Println("Creating new config file at " + home + "/.netconfig") + fmt.Println("Creating new config file at " + home + "/netconfig-" + network) cfg.Server.Address = server cfg.Server.AccessKey = accesskey - newf, err := os.Create(home + "/.netconfig") + newf, err := os.Create(home + "/netconfig-" + network) err = yaml.NewEncoder(newf).Encode(cfg) defer newf.Close() if err != nil { @@ -168,7 +178,7 @@ func(config *ClientConfig) ReadConfig() { nofile := false //home, err := homedir.Dir() home := "/etc/netclient" - file := fmt.Sprintf(home + "/.netconfig") + file := fmt.Sprintf(home + "/netconfig-" + config.Network) //f, err := os.Open(file) f, err := os.OpenFile(file, os.O_RDONLY, 0666) if err != nil { @@ -194,12 +204,15 @@ func(config *ClientConfig) ReadConfig() { } } - -func readConfig() *ClientConfig { +func ReadConfig(network string) (*ClientConfig, error) { + if network == "" { + err := errors.New("No network provided. Exiting.") + return nil, err + } nofile := false //home, err := homedir.Dir() home := "/etc/netclient" - file := fmt.Sprintf(home + "/.netconfig") + file := fmt.Sprintf(home + "/netconfig-" + network) f, err := os.Open(file) if err != nil { nofile = true @@ -213,13 +226,14 @@ func readConfig() *ClientConfig { err = decoder.Decode(&cfg) if err != nil { fmt.Println("trouble decoding file") - log.Fatal(err) + return nil, err } } - return &cfg + return &cfg, err } - +/* func init() { Config = readConfig() } +*/ diff --git a/netclient/functions/auth.go b/netclient/functions/auth.go index 743d0a9b..8a4c30ee 100644 --- a/netclient/functions/auth.go +++ b/netclient/functions/auth.go @@ -14,17 +14,17 @@ import ( ) // CreateJWT func will used to create the JWT while signing in and signing out -func SetJWT(client nodepb.NodeServiceClient) (context.Context, error) { +func SetJWT(client nodepb.NodeServiceClient, network string) (context.Context, error) { //home, err := os.UserHomeDir() home := "/etc/netclient" - tokentext, err := ioutil.ReadFile(home + "/.nettoken") + tokentext, err := ioutil.ReadFile(home + "/nettoken") if err != nil { fmt.Println("Error reading token. Logging in to retrieve new token.") - err = AutoLogin(client) + err = AutoLogin(client, network) if err != nil { return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong with Auto Login: %v", err)) } - tokentext, err = ioutil.ReadFile(home + "/.nettoken") + tokentext, err = ioutil.ReadFile(home + "/nettoken") if err != nil { return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong: %v", err)) } @@ -38,13 +38,17 @@ func SetJWT(client nodepb.NodeServiceClient) (context.Context, error) { return ctx, nil } -func AutoLogin(client nodepb.NodeServiceClient) error { +func AutoLogin(client nodepb.NodeServiceClient, network string) error { //home, err := os.UserHomeDir() home := "/etc/netclient" - nodecfg := config.Config.Node - login := &nodepb.LoginRequest{ - Password: nodecfg.Password, - Macaddress: nodecfg.MacAddress, + //nodecfg := config.Config.Node + config, err := config.ReadConfig(network) + if err != nil { + return err + } + login := &nodepb.LoginRequest{ + Password: config.Node.Password, + Macaddress: config.Node.MacAddress, } // RPC call res, err := client.Login(context.TODO(), login) @@ -52,7 +56,7 @@ func AutoLogin(client nodepb.NodeServiceClient) error { return err } tokenstring := []byte(res.Accesstoken) - err = ioutil.WriteFile(home + "/.nettoken", tokenstring, 0644) + err = ioutil.WriteFile(home + "/nettoken", tokenstring, 0644) if err != nil { return err } diff --git a/netclient/functions/common.go b/netclient/functions/common.go index 2de1a1c2..b27d48f0 100644 --- a/netclient/functions/common.go +++ b/netclient/functions/common.go @@ -19,6 +19,7 @@ import ( nodepb "github.com/gravitl/netmaker/grpc" "golang.zx2c4.com/wireguard/wgctrl" "google.golang.org/grpc" + "encoding/base64" "google.golang.org/grpc/metadata" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" //homedir "github.com/mitchellh/go-homedir" @@ -28,8 +29,31 @@ var ( wcclient nodepb.NodeServiceClient ) -func Install(accesskey string, password string, server string, group string, noauto bool) error { +func Install(accesskey string, password string, server string, group string, noauto bool, accesstoken string) error { + + tserver := "" + tnetwork := "" + tkey := "" + + if accesstoken != "" && accesstoken != "badtoken" { + btoken, err := base64.StdEncoding.DecodeString(accesstoken) + if err != nil { + log.Fatalf("Something went wrong decoding your token: %v", err) + } + token := string(btoken) + tokenvals := strings.Split(token, ".") + tserver = tokenvals[0] + tnetwork = tokenvals[1] + tkey = tokenvals[2] + server = tserver + group = tnetwork + accesskey = tkey + fmt.Println("Decoded values from token:") + fmt.Println(" Server: " + tserver) + fmt.Println(" Network: " + tnetwork) + fmt.Println(" Key: " + tkey) + } wgclient, err := wgctrl.New() if err != nil { @@ -37,28 +61,38 @@ func Install(accesskey string, password string, server string, group string, noa } defer wgclient.Close() - nodecfg := config.Config.Node - servercfg := config.Config.Server + cfg, err := config.ReadConfig(group) + if err != nil { + log.Printf("No Config Yet. Will Write: %v", err) + } + nodecfg := cfg.Node + servercfg := cfg.Server fmt.Println("SERVER SETTINGS:") if server == "" { - if servercfg.Address == "" { + if servercfg.Address == "" && tserver == "" { log.Fatal("no server provided") } else { server = servercfg.Address } } + if tserver != "" { + server = tserver + } fmt.Println(" Server: " + server) if accesskey == "" { - if servercfg.AccessKey == "" { + if servercfg.AccessKey == "" && tkey == "" { fmt.Println("no access key provided.Proceeding anyway.") } else { accesskey = servercfg.AccessKey } } + if tkey != "" { + accesskey = tkey + } fmt.Println(" AccessKey: " + accesskey) - err = config.WriteServer(server, accesskey) + err = config.WriteServer(server, accesskey, group) if err != nil { fmt.Println("Error encountered while writing Server Config.") return err @@ -77,13 +111,16 @@ func Install(accesskey string, password string, server string, group string, noa fmt.Println(" Password: " + password) if group == "badgroup" { - if nodecfg.Group == "" { + if nodecfg.Group == "" && tnetwork == "" { //create error here log.Fatal("no group provided") } else { group = nodecfg.Group } } + if tnetwork != "" { + group = tnetwork + } fmt.Println(" Group: " + group) var macaddress string @@ -278,19 +315,19 @@ func Install(accesskey string, password string, server string, group string, noa fmt.Println("Awaiting approval from Admin before configuring WireGuard.") if !noauto { fmt.Println("Configuring Netmaker Service.") - err = ConfigureSystemD() + err = ConfigureSystemD(group) return err } } - peers, err := getPeers(node.Macaddress, node.Nodegroup, server) + peers, err := getPeers(node.Macaddress, group, server) if err != nil { return err } fmt.Println("retrived peers, setting wireguard config.") - err = storePrivKey(privkeystring) + err = storePrivKey(privkeystring, group) if err != nil { return err } @@ -299,7 +336,7 @@ func Install(accesskey string, password string, server string, group string, noa return err } if !noauto { - err = ConfigureSystemD() + err = ConfigureSystemD(group) } if err != nil { return err @@ -336,8 +373,16 @@ func getPublicIP() (string, error) { } func modConfig(node *nodepb.Node) error{ - modconfig := config.Config - modconfig.ReadConfig() + group := node.Nodegroup + if group == "" { + return errors.New("No Group Provided") + } + //modconfig := config.Config + modconfig, err := config.ReadConfig(group) + //modconfig.ReadConfig() + if err != nil { + return err + } nodecfg := modconfig.Node if node.Name != ""{ nodecfg.Name = node.Name @@ -376,7 +421,7 @@ func modConfig(node *nodepb.Node) error{ nodecfg.PostChanges = node.Postchanges } modconfig.Node = nodecfg - err := config.Write(modconfig) + err = config.Write(modconfig, group) return err } @@ -395,15 +440,7 @@ func getMacAddr() ([]string, error) { } return as, nil } -/* -func read(macaddress string, group string) error { - //this would be used for retrieving state as set by the server. -} -func checkLocalConfigChange() error { - -} -*/ func initWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig) error { @@ -417,8 +454,14 @@ func initWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig } wgclient, err := wgctrl.New() - modcfg := config.Config - modcfg.ReadConfig() + //modcfg := config.Config + //modcfg.ReadConfig() + modcfg, err := config.ReadConfig(node.Nodegroup) + if err != nil { + return err + } + + nodecfg := modcfg.Node fmt.Println("beginning local WG config") @@ -535,16 +578,86 @@ func initWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig return err } -func setWGConfig() error { - servercfg := config.Config.Server - nodecfg := config.Config.Node - node := getNode() +func setWGKeyConfig(network string, serveraddr string) error { + + ctx := context.Background() + var header metadata.MD + + var wcclient nodepb.NodeServiceClient + var requestOpts grpc.DialOption + requestOpts = grpc.WithInsecure() + conn, err := grpc.Dial(serveraddr, requestOpts) + if err != nil { + fmt.Printf("Cant dial GRPC server: %v", err) + return err + } + wcclient = nodepb.NewNodeServiceClient(conn) + + fmt.Println("Authenticating with GRPC Server") + ctx, err = SetJWT(wcclient, network) + if err != nil { + fmt.Printf("Failed to authenticate: %v", err) + return err + } + fmt.Println("Authenticated") + + + node := getNode(network) + + privatekey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + privkeystring := privatekey.String() + publickey := privatekey.PublicKey() + + node.Publickey = publickey.String() + + err = storePrivKey(privkeystring, network) + if err != nil { + return err + } + err = modConfig(&node) + if err != nil { + return err + } + + + postnode := getNode(network) + + req := &nodepb.UpdateNodeReq{ + Node: &postnode, + } + + _, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header)) + if err != nil { + return err + } + err = setWGConfig(network) + if err != nil { + return err + log.Fatalf("Error: %v", err) + } + + return err +} + + +func setWGConfig(network string) error { + + cfg, err := config.ReadConfig(network) + if err != nil { + return err + } + servercfg := cfg.Server + nodecfg := cfg.Node + node := getNode(network) peers, err := getPeers(node.Macaddress, nodecfg.Group, servercfg.Address) if err != nil { return err } - privkey, err := retrievePrivKey() + privkey, err := retrievePrivKey(network) if err != nil { return err } @@ -557,14 +670,14 @@ func setWGConfig() error { return err } -func storePrivKey(key string) error{ +func storePrivKey(key string, network string) error{ d1 := []byte(key) - err := ioutil.WriteFile("/root/.wckey", d1, 0644) + err := ioutil.WriteFile("/etc/netclient/wgkey-" + network, d1, 0644) return err } -func retrievePrivKey() (string, error) { - dat, err := ioutil.ReadFile("/root/.wckey") +func retrievePrivKey(network string) (string, error) { + dat, err := ioutil.ReadFile("/etc/netclient/wgkey-" + network) return string(dat), err } @@ -612,10 +725,14 @@ func getPrivateAddr() (string, error) { } -func CheckIn() error { - node := getNode() - nodecfg := config.Config.Node - servercfg := config.Config.Server +func CheckIn(network string) error { + node := getNode(network) + cfg, err := config.ReadConfig(network) + if err != nil { + return err + } + nodecfg := cfg.Node + servercfg := cfg.Server fmt.Println("Checking into server: " + servercfg.Address) setupcheck := true @@ -661,13 +778,17 @@ func CheckIn() error { return err log.Fatalf("Error: %v", err) } - err = setWGConfig() + err = setWGConfig(network) if err != nil { return err log.Fatalf("Error: %v", err) } - node = getNode() - nodecfg = config.Config.Node + node = getNode(network) + cfg, err := config.ReadConfig(network) + if err != nil { + return err + } + nodecfg = cfg.Node } @@ -683,7 +804,7 @@ func CheckIn() error { ctx := context.Background() fmt.Println("Authenticating with GRPC Server") - ctx, err = SetJWT(wcclient) + ctx, err = SetJWT(wcclient, network) if err != nil { fmt.Printf("Failed to authenticate: %v", err) return err @@ -702,7 +823,7 @@ func CheckIn() error { ) if err != nil { if checkinres != nil && checkinres.Checkinresponse.Ispending { - fmt.Println("Node is in pending status. Waiting for Admin approval of node before making furtherupdates.") + fmt.Println("Node is in pending status. Waiting for Admin approval of node before making further updates.") return nil } fmt.Printf("Unable to process Check In request: %v", err) @@ -710,11 +831,11 @@ func CheckIn() error { } fmt.Println("Checked in.") if checkinres.Checkinresponse.Ispending { - fmt.Println("Node is in pending status. Waiting for Admin approval of node before making furtherupdates.") + fmt.Println("Node is in pending status. Waiting for Admin approval of node before making further updates.") return err } - newinterface := getNode().Interface + newinterface := getNode(network).Interface readreq := &nodepb.ReadNodeReq{ Macaddress: node.Macaddress, Group: node.Nodegroup, @@ -736,7 +857,7 @@ func CheckIn() error { fmt.Println("ERROR DELETING INTERFACE: " + currentiface) } } - err = setWGConfig() + err = setWGConfig(network) } if checkinres.Checkinresponse.Needconfigupdate { @@ -756,7 +877,7 @@ func CheckIn() error { return err log.Fatalf("Error: %v", err) } - err = setWGConfig() + err = setWGConfig(network) if err != nil { return err log.Fatalf("Error: %v", err) @@ -765,7 +886,7 @@ func CheckIn() error { } else if nodecfg.PostChanges == "true" { fmt.Println("Node has requested to update remote config.") fmt.Println("Posting local config to remote server.") - postnode := getNode() + postnode := getNode(network) req := &nodepb.UpdateNodeReq{ Node: &postnode, @@ -781,29 +902,47 @@ func CheckIn() error { return err log.Fatalf("Error: %v", err) } - err = setWGConfig() + err = setWGConfig(network) if err != nil { return err log.Fatalf("Error: %v", err) } setupcheck = false } + if checkinres.Checkinresponse.Needkeyupdate { + fmt.Println("Server has requested that node update key pairs.") + fmt.Println("Proceeding to re-generate key pairs for Wiregard.") + err = setWGKeyConfig(network, servercfg.Address) + if err != nil { + return err + log.Fatalf("Unable to process reset keys request: %v", err) + } + setupcheck = false + } if checkinres.Checkinresponse.Needpeerupdate { fmt.Println("Server has requested that node update peer list.") fmt.Println("Updating peer list from remote server.") - err = setWGConfig() + err = setWGConfig(network) if err != nil { return err log.Fatalf("Unable to process Set Peers request: %v", err) } setupcheck = false } + if checkinres.Checkinresponse.Needdelete { + fmt.Println("This machine got the delete signal. Deleting.") + err := Remove(network) + if err != nil { + return err + log.Fatalf("Error: %v", err) + } + } if setupcheck { iface := nodecfg.Interface _, err := net.InterfaceByName(iface) if err != nil { fmt.Println("interface " + iface + " does not currently exist. Setting up WireGuard.") - err = setWGConfig() + err = setWGConfig(network) if err != nil { return err log.Fatalf("Error: %v", err) @@ -829,9 +968,13 @@ func needInterfaceUpdate(ctx context.Context, mac string, group string, iface st return iface != oldiface, oldiface, err } -func getNode() nodepb.Node { - modcfg := config.Config - modcfg.ReadConfig() +func getNode(network string) nodepb.Node { + + modcfg, err := config.ReadConfig(network) + if err != nil { + log.Fatalf("Error: %v", err) + } + nodecfg := modcfg.Node var node nodepb.Node @@ -856,10 +999,14 @@ func getNode() nodepb.Node { -func Remove() error { +func Remove(network string) error { //need to implement checkin on server side - servercfg := config.Config.Server - node := config.Config.Node + cfg, err := config.ReadConfig(network) + if err != nil { + return err + } + servercfg := cfg.Server + node := cfg.Node fmt.Println("Deleting remote node with MAC: " + node.MacAddress) @@ -875,7 +1022,7 @@ func Remove() error { ctx := context.Background() fmt.Println("Authenticating with GRPC Server") - ctx, err = SetJWT(wcclient) + ctx, err = SetJWT(wcclient, network) if err != nil { //return err log.Printf("Failed to authenticate: %v", err) @@ -900,11 +1047,11 @@ func Remove() error { } } } - err = WipeLocal() + err = WipeLocal(network) if err != nil { log.Printf("Unable to wipe local config: %v", err) } - err = RemoveSystemDServices() + err = RemoveSystemDServices(network) if err != nil { return err log.Printf("Unable to remove systemd services: %v", err) @@ -915,17 +1062,21 @@ func Remove() error { return nil } -func WipeLocal() error{ - nodecfg := config.Config.Node +func WipeLocal(network string) error{ + cfg, err := config.ReadConfig(network) + if err != nil { + return err + } + nodecfg := cfg.Node ifacename := nodecfg.Interface //home, err := homedir.Dir() home := "/etc/netclient" - err := os.Remove(home + "/.netconfig") + err = os.Remove(home + "/netconfig-" + network) if err != nil { fmt.Println(err) } - err = os.Remove(home + "/.nettoken") + err = os.Remove(home + "/nettoken") if err != nil { fmt.Println(err) } @@ -967,9 +1118,11 @@ func getPeers(macaddress string, group string, server string) ([]wgtypes.PeerCon //need to implement checkin on server side var peers []wgtypes.PeerConfig var wcclient nodepb.NodeServiceClient - modcfg := config.Config - modcfg.ReadConfig() - nodecfg := modcfg.Node + cfg, err := config.ReadConfig(group) + if err != nil { + log.Fatalf("Issue retrieving config for network: " + group + ". Please investigate: %v", err) + } + nodecfg := cfg.Node keepalive := nodecfg.KeepAlive keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s") if err != nil { @@ -992,7 +1145,7 @@ func getPeers(macaddress string, group string, server string) ([]wgtypes.PeerCon } ctx := context.Background() fmt.Println("Authenticating with GRPC Server") - ctx, err = SetJWT(wcclient) + ctx, err = SetJWT(wcclient, group) if err != nil { fmt.Println("Failed to authenticate.") return peers, err diff --git a/netclient/functions/local.go b/netclient/functions/local.go index b5ee2636..5e53568a 100644 --- a/netclient/functions/local.go +++ b/netclient/functions/local.go @@ -11,7 +11,16 @@ import ( "os/exec" ) -func ConfigureSystemD() error { + +func fileExists(f string) bool { + info, err := os.Stat(f) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + +func ConfigureSystemD(network string) error { /* path, err := os.Getwd() if err != nil { @@ -36,17 +45,20 @@ func ConfigureSystemD() error { return err } + if !fileExists("/usr/local/bin/netclient") { _, err = copy(binarypath, "/usr/local/bin/netclient") if err != nil { log.Println(err) return err } + } + if !fileExists("/etc/netclient/netclient") { _, err = copy(binarypath, "/etc/netclient/netclient") if err != nil { log.Println(err) return err } - + } systemservice := `[Unit] @@ -54,8 +66,8 @@ Description=Regularly checks for updates in peers and local config Wants=netclient.timer [Service] -Type=oneshot -ExecStart=/etc/netclient/netclient -c checkin +Type=simple +ExecStart=/etc/netclient/netclient -c checkin -n %i [Install] WantedBy=multi-user.target @@ -63,45 +75,62 @@ WantedBy=multi-user.target systemtimer := `[Unit] Description=Calls the Netmaker Mesh Client Service -Requires=netclient.service + +` +systemtimer = systemtimer + "Requires=netclient@"+network+".service" + +systemtimer = systemtimer + +` [Timer] -Unit=netclient.service + +` +systemtimer = systemtimer + "Unit=netclient@"+network+".service" + +systemtimer = systemtimer + +` + OnCalendar=*:*:0/30 [Install] WantedBy=timers.target ` + servicebytes := []byte(systemservice) timerbytes := []byte(systemtimer) - err = ioutil.WriteFile("/etc/systemd/system/netclient.service", servicebytes, 0644) + if !fileExists("/etc/systemd/system/netclient@.service") { + err = ioutil.WriteFile("/etc/systemd/system/netclient@.service", servicebytes, 0644) if err != nil { log.Println(err) return err } + } - err = ioutil.WriteFile("/etc/systemd/system/netclient.timer", timerbytes, 0644) + if !fileExists("/etc/systemd/system/netclient-"+network+".timer") { + err = ioutil.WriteFile("/etc/systemd/system/netclient-"+network+".timer", timerbytes, 0644) if err != nil { log.Println(err) return err } - + } sysExec, err := exec.LookPath("systemctl") cmdSysEnableService := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "enable", "netclient.service" }, + Args: []string{ sysExec, "enable", "netclient@.service" }, Stdout: os.Stdout, Stderr: os.Stdout, } + /* cmdSysStartService := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "start", "netclient.service"}, + Args: []string{ sysExec, "start", "netclient@.service"}, Stdout: os.Stdout, Stderr: os.Stdout, } + */ cmdSysDaemonReload := &exec.Cmd { Path: sysExec, Args: []string{ sysExec, "daemon-reload"}, @@ -110,25 +139,20 @@ WantedBy=timers.target } cmdSysEnableTimer := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "enable", "netclient.timer" }, + Args: []string{ sysExec, "enable", "netclient-"+network+".timer" }, Stdout: os.Stdout, Stderr: os.Stdout, } cmdSysStartTimer := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "start", "netclient.timer"}, + Args: []string{ sysExec, "start", "netclient-"+network+".timer"}, Stdout: os.Stdout, Stderr: os.Stdout, } err = cmdSysEnableService.Run() if err != nil { - fmt.Println("Error enabling netclient.service. Please investigate.") - fmt.Println(err) - } - err = cmdSysStartService.Run() - if err != nil { - fmt.Println("Error starting netclient.service. Please investigate.") + fmt.Println("Error enabling netclient@.service. Please investigate.") fmt.Println(err) } err = cmdSysDaemonReload.Run() @@ -143,24 +167,38 @@ WantedBy=timers.target } err = cmdSysStartTimer.Run() if err != nil { - fmt.Println("Error starting netclient.timer. Please investigate.") + fmt.Println("Error starting netclient-"+network+".timer. Please investigate.") fmt.Println(err) } return nil } -func RemoveSystemDServices() error { +func isOnlyService(network string) (bool, error) { + isonly := false + files, err := filepath.Glob("/etc/netclient/netconfig-*") + if err != nil { + return isonly, err + } + count := len(files) + if count == 0 { + isonly = true + } + return isonly, err + +} + +func RemoveSystemDServices(network string) error { sysExec, err := exec.LookPath("systemctl") - cmdSysStopService := &exec.Cmd { - Path: sysExec, - Args: []string{ sysExec, "stop", "netclient.service" }, - Stdout: os.Stdout, - Stderr: os.Stdout, - } + + fullremove, err := isOnlyService(network) + if err != nil { + fmt.Println(err) + } + cmdSysDisableService := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "disable", "netclient.service"}, + Args: []string{ sysExec, "disable", "netclient@.service"}, Stdout: os.Stdout, Stderr: os.Stdout, } @@ -178,40 +216,43 @@ func RemoveSystemDServices() error { } cmdSysStopTimer := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "stop", "netclient.timer" }, + Args: []string{ sysExec, "stop", "netclient-"+network+".timer" }, Stdout: os.Stdout, Stderr: os.Stdout, } cmdSysDisableTimer := &exec.Cmd { Path: sysExec, - Args: []string{ sysExec, "disable", "netclient.timer"}, + Args: []string{ sysExec, "disable", "netclient-"+network+".timer"}, Stdout: os.Stdout, Stderr: os.Stdout, } - err = cmdSysStopService.Run() + //err = cmdSysStopService.Run() if err != nil { - fmt.Println("Error stopping netclient.service. Please investigate.") + fmt.Println("Error stopping netclient@.service. Please investigate.") fmt.Println(err) } + if fullremove { err = cmdSysDisableService.Run() if err != nil { - fmt.Println("Error disabling netclient.service. Please investigate.") + fmt.Println("Error disabling netclient@.service. Please investigate.") fmt.Println(err) } + } err = cmdSysStopTimer.Run() if err != nil { - fmt.Println("Error stopping netclient.timer. Please investigate.") + fmt.Println("Error stopping netclient-"+network+".timer. Please investigate.") fmt.Println(err) } err = cmdSysDisableTimer.Run() if err != nil { - fmt.Println("Error disabling netclient.timer. Please investigate.") + fmt.Println("Error disabling netclient-"+network+".timer. Please investigate.") fmt.Println(err) } - - err = os.Remove("/etc/systemd/system/netclient.service") - err = os.Remove("/etc/systemd/system/netclient.timer") + if fullremove { + err = os.Remove("/etc/systemd/system/netclient@.service") + } + err = os.Remove("/etc/systemd/system/netclient-"+network+".timer") if err != nil { fmt.Println("Error removing file. Please investigate.") fmt.Println(err) diff --git a/netclient/main.go b/netclient/main.go index 7a17ccbe..c24e60e6 100644 --- a/netclient/main.go +++ b/netclient/main.go @@ -15,8 +15,8 @@ import ( const ( // name of the service - name = "wcdaemon" - description = "Wirecat Daemon Service" + name = "netclient" + description = "Netmaker Daemon Service" ) var password string @@ -35,8 +35,9 @@ var ( func main() { tpassword := flag.String("p", "changeme", "This node's password for accessing the server regularly") taccesskey := flag.String("k", "badkey", "an access key generated by the server and used for one-time access (install only)") + taccesstoken := flag.String("t", "badtoken", "an token generated by the server and used for one-time access (install only)") tserver := flag.String("s", "localhost:50051", "The location (including port) of the remote gRPC server.") - tgroup := flag.String("g", "badgroup", "The node group you are attempting to join.") + tnetwork := flag.String("n", "nonetwork", "The node group you are attempting to join.") tnoauto := flag.Bool("na", false, "No auto mode. If true, netmclient will not be installed as a system service and you will have to retrieve updates manually via checkin command.") tnoforward := flag.Bool("nf", false, "No Forward mode. If true, netclient will not check for IP forwarding. This may break functionality") command := flag.String("c", "required", "The command to run") @@ -75,6 +76,12 @@ func main() { os.Exit(1) log.Fatal("Exiting") case "install": + + if *taccesstoken == "badtoken" && (*tnetwork == "nonetwork" || *tnetwork == "") { + fmt.Println("Required, '-n'. No network provided. Exiting.") + os.Exit(1) + } + if !*tnoforward { forward := exec.Command("sysctl", "net.ipv4.ip_forward") out, err := forward.Output() @@ -93,25 +100,26 @@ func main() { } fmt.Println("Beginning agent installation.") - err := functions.Install(*taccesskey, *tpassword, *tserver, *tgroup, *tnoauto) + err := functions.Install(*taccesskey, *tpassword, *tserver, *tnetwork, *tnoauto, *taccesstoken) if err != nil { fmt.Println("Error installing: ", err) fmt.Println("Cleaning up (uninstall)") - err = functions.Remove() + err = functions.Remove(*tnetwork) if err != nil { fmt.Println("Error uninstalling: ", err) fmt.Println("Wiping local.") - err = functions.WipeLocal() + err = functions.WipeLocal(*tnetwork) if err != nil { fmt.Println("Error removing artifacts: ", err) } - err = functions.RemoveSystemDServices() + err = functions.RemoveSystemDServices(*tnetwork) if err != nil { fmt.Println("Error removing services: ", err) } } os.Exit(1) } + /* case "service-install": fmt.Println("Beginning service installation.") err := functions.ConfigureSystemD() @@ -126,16 +134,25 @@ func main() { fmt.Println("Error installing service: ", err) os.Exit(1) } + */ case "checkin": - fmt.Println("Beginning node check in.") - err := functions.CheckIn() + if *tnetwork == "nonetwork" || *tnetwork == "" { + fmt.Println("Required, '-n'. No network provided. Exiting.") + os.Exit(1) + } + fmt.Println("Beginning node check in for group " + *tnetwork) + err := functions.CheckIn(*tnetwork) if err != nil { fmt.Println("Error checking in: ", err) os.Exit(1) } case "remove": + if *tnetwork == "nonetwork" || *tnetwork == "" { + fmt.Println("Required, '-n'. No network provided. Exiting.") + os.Exit(1) + } fmt.Println("Beginning node cleanup.") - err := functions.Remove() + err := functions.Remove(*tnetwork) if err != nil { /* fmt.Println("Error uninstalling: ", err) @@ -152,6 +169,10 @@ func main() { fmt.Println("Error deleting node: ", err) os.Exit(1) } + default: + fmt.Println("You must select from the following commands: install|remove|checkin", err) + os.Exit(1) + } fmt.Println("Command " + *command + " Executed Successfully") } diff --git a/test/api_test.go b/test/api_test.go new file mode 100644 index 00000000..4d34fd94 --- /dev/null +++ b/test/api_test.go @@ -0,0 +1,197 @@ +package main + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "os" + "sync" + "testing" + "time" + + controller "github.com/gravitl/netmaker/controllers" + "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/mongoconn" + "github.com/stretchr/testify/assert" +) + +type databaseError struct { + Inner *int + Errors int +} + +//should be use models.SuccessResponse and models.SuccessfulUserLoginResponse +//rather than creating new type but having trouble decoding that way +type Auth struct { + Username string + AuthToken string +} +type Success struct { + Code int + Message string + Response Auth +} + +type AuthorizeTestCase struct { + testname string + name string + password string + code int + tokenExpected bool + errMessage string +} + +func TestMain(m *testing.M) { + mongoconn.ConnectDatabase() + var waitgroup sync.WaitGroup + waitgroup.Add(1) + go controller.HandleRESTRequests(&waitgroup) + //wait for http server to start + time.Sleep(time.Second * 1) + os.Exit(m.Run()) +} + +func adminExists(t *testing.T) bool { + response, err := http.Get("http://localhost:8081/users/hasadmin") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + var body bool + json.NewDecoder(response.Body).Decode(&body) + return body +} + +func api(t *testing.T, data interface{}, method, url, authorization string) (*http.Response, error) { + var request *http.Request + var err error + if data != "" { + payload, err := json.Marshal(data) + assert.Nil(t, err, err) + request, err = http.NewRequest(method, url, bytes.NewBuffer(payload)) + assert.Nil(t, err, err) + request.Header.Set("Content-Type", "application/json") + } else { + request, err = http.NewRequest(method, url, nil) + assert.Nil(t, err, err) + } + if authorization != "" { + request.Header.Set("Authorization", "Bearer "+authorization) + } + client := http.Client{} + return client.Do(request) +} + +func addAdmin(t *testing.T) { + var admin models.User + admin.UserName = "admin" + admin.Password = "password" + response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/createadmin", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) +} + +func authenticate(t *testing.T) (string, error) { + var admin models.User + admin.UserName = "admin" + admin.Password = "password" + response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/authenticate", "secretkey") + assert.Nil(t, err, err) + + var body Success + err = json.NewDecoder(response.Body).Decode(&body) + assert.Nil(t, err, err) + assert.NotEmpty(t, body.Response.AuthToken, "token not returned") + assert.Equal(t, "W1R3: Device admin Authorized", body.Message) + + return body.Response.AuthToken, nil +} + +func deleteAdmin(t *testing.T) { + if !adminExists(t) { + return + } + token, err := authenticate(t) + assert.Nil(t, err, err) + _, err = api(t, "", http.MethodDelete, "http://localhost:8081/users/admin", token) + assert.Nil(t, err, err) +} + +func createGroup(t *testing.T) { + group := models.Group{} + group.NameID = "skynet" + group.AddressRange = "10.71.0.0/16" + response, err := api(t, group, http.MethodPost, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) +} + +func createKey(t *testing.T) { + key := models.AccessKey{} + key.Name = "skynet" + key.Uses = 10 + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + message, err := ioutil.ReadAll(response.Body) + assert.Nil(t, err, err) + assert.NotNil(t, message, message) +} + +func getKey(t *testing.T, name string) models.AccessKey { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + var keys []models.AccessKey + err = json.NewDecoder(response.Body).Decode(&keys) + assert.Nil(t, err, err) + for _, key := range keys { + if key.Name == name { + return key + } + } + return models.AccessKey{} +} + +func deleteKey(t *testing.T, key, group string) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/"+group+"/keys/"+key, "secretkey") + assert.Nil(t, err, err) + //api does not return Deleted Count at this time + //defer response.Body.Close() + //var message mongo.DeleteResult + //err = json.NewDecoder(response.Body).Decode(&message) + //assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + //assert.Equal(t, int64(1), message.DeletedCount) +} + +func groupExists(t *testing.T) bool { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + assert.Equal(t, http.StatusOK, response.StatusCode) + err = json.NewDecoder(response.Body).Decode(&Groups) + assert.Nil(t, err, err) + if Groups == nil { + return false + } else { + return true + } +} + +func deleteGroups(t *testing.T) { + + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + assert.Equal(t, http.StatusOK, response.StatusCode) + err = json.NewDecoder(response.Body).Decode(&Groups) + assert.Nil(t, err, err) + for _, group := range Groups { + name := group.DisplayName + _, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/"+name, "secretkey") + assert.Nil(t, err, err) + } +} diff --git a/test/config/environments/dev.yaml b/test/config/environments/dev.yaml new file mode 100644 index 00000000..205f3771 --- /dev/null +++ b/test/config/environments/dev.yaml @@ -0,0 +1,14 @@ +server: + host: "localhost" + apiport: "8081" + grpcport: "50051" + masterkey: "secretkey" + allowedorigin: "*" + restbackend: true + agentbackend: true +mongoconn: + user: "mongoadmin" + pass: "mongopass" + host: "localhost" + port: "27017" + opts: '/?authSource=admin' diff --git a/test/group_test.go b/test/group_test.go new file mode 100644 index 00000000..5a3ceaaa --- /dev/null +++ b/test/group_test.go @@ -0,0 +1,621 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "testing" + + "github.com/gravitl/netmaker/models" + "github.com/stretchr/testify/assert" + "go.mongodb.org/mongo-driver/mongo" +) + +var Groups []models.Group + +func TestCreateGroup(t *testing.T) { + group := models.Group{} + group.NameID = "skynet" + group.AddressRange = "10.71.0.0/16" + deleteGroups(t) + t.Run("CreateGroup", func(t *testing.T) { + response, err := api(t, group, http.MethodPost, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + }) + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, group, http.MethodPost, "http://localhost:8081/api/groups", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("BadName", func(t *testing.T) { + //issue #42 + t.Skip() + }) + t.Run("BadAddress", func(t *testing.T) { + //issue #42 + t.Skip() + }) + t.Run("DuplicateGroup", func(t *testing.T) { + //issue #42 + t.Skip() + }) +} + +func TestGetGroups(t *testing.T) { + t.Run("ValidToken", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + assert.Equal(t, http.StatusOK, response.StatusCode) + err = json.NewDecoder(response.Body).Decode(&Groups) + assert.Nil(t, err, err) + }) + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) +} + +func TestGetGroup(t *testing.T) { + t.Run("ValidToken", func(t *testing.T) { + var group models.Group + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + assert.Equal(t, http.StatusOK, response.StatusCode) + err = json.NewDecoder(response.Body).Decode(&group) + assert.Nil(t, err, err) + assert.Equal(t, "skynet", group.DisplayName) + }) + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("InvalidGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/badgroup", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) +} + +func TestGetGroupNodeNumber(t *testing.T) { + t.Run("ValidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/numnodes", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message int + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + //assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusOK, response.StatusCode) + }) + t.Run("InvalidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/numnodes", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("BadGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/badgroup/numnodes", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) +} + +func TestDeleteGroup(t *testing.T) { + t.Run("InvalidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet", "badkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("ValidKey", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message mongo.DeleteResult + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + assert.Equal(t, int64(1), message.DeletedCount) + + }) + t.Run("BadGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/badgroup", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("NodesExist", func(t *testing.T) { + t.Skip() + }) + //Create Group for follow-on tests + createGroup(t) +} + +func TestCreateAccessKey(t *testing.T) { + key := models.AccessKey{} + key.Name = "skynet" + key.Uses = 10 + t.Run("MultiUse", func(t *testing.T) { + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + message, err := ioutil.ReadAll(response.Body) + assert.Nil(t, err, err) + assert.NotNil(t, message, message) + returnedkey := getKey(t, key.Name) + assert.Equal(t, key.Name, returnedkey.Name) + assert.Equal(t, key.Uses, returnedkey.Uses) + }) + deleteKey(t, "skynet", "skynet") + t.Run("ZeroUse", func(t *testing.T) { + //t.Skip() + key.Uses = 0 + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + message, err := ioutil.ReadAll(response.Body) + assert.Nil(t, err, err) + assert.NotNil(t, message, message) + returnedkey := getKey(t, key.Name) + assert.Equal(t, key.Name, returnedkey.Name) + assert.Equal(t, 1, returnedkey.Uses) + }) + t.Run("DuplicateAccessKey", func(t *testing.T) { + //t.Skip() + //this will fail + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + deleteKey(t, key.Name, "skynet") + }) + + t.Run("InvalidToken", func(t *testing.T) { + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/skynet/keys", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) + t.Run("BadGroup", func(t *testing.T) { + response, err := api(t, key, http.MethodPost, "http://localhost:8081/api/groups/badgroup/keys", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) +} + +func TestDeleteKey(t *testing.T) { + t.Run("KeyValid", func(t *testing.T) { + //fails -- deletecount not returned + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet/keys/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message mongo.DeleteResult + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + assert.Equal(t, int64(1), message.DeletedCount) + }) + t.Run("InValidKey", func(t *testing.T) { + //fails -- status message not returned + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet/keys/badkey", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This key does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("KeyInValidGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/badgroup/keys/skynet", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("InvalidCredentials", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/groups/skynet/keys/skynet", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) +} + +func TestGetKeys(t *testing.T) { + createKey(t) + t.Run("Valid", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/keys", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + var keys []models.AccessKey + err = json.NewDecoder(response.Body).Decode(&keys) + assert.Nil(t, err, err) + }) + //deletekeys + t.Run("InvalidGroup", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/badgroup/keys", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("InvalidCredentials", func(t *testing.T) { + response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/groups/skynet/keys", "badkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + }) +} + +func TestUpdateGroup(t *testing.T) { + var returnedGroup models.Group + t.Run("UpdateNameID", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.NameID, returnedGroup.NameID) + }) + t.Run("NameIDInvalidCredentials", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "badkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, message.Code) + assert.Equal(t, "W1R3: You are unauthorized to access this endpoint.", message.Message) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) + }) + t.Run("InvalidGroup", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/badgroup", "secretkey") + assert.Nil(t, err, err) + defer response.Body.Close() + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusNotFound, message.Code) + assert.Equal(t, "W1R3: This group does not exist.", message.Message) + assert.Equal(t, http.StatusNotFound, response.StatusCode) + }) + t.Run("UpdateNameIDTooLong", func(t *testing.T) { + type Group struct { + NameID string + } + var group Group + group.NameID = "wirecat-skynet" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateAddress", func(t *testing.T) { + type Group struct { + AddressRange string + } + var group Group + group.AddressRange = "10.0.0.1/24" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.AddressRange, returnedGroup.AddressRange) + }) + t.Run("UpdateAddressInvalid", func(t *testing.T) { + type Group struct { + AddressRange string + } + var group Group + group.AddressRange = "10.0.0.1/36" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateDisplayName", func(t *testing.T) { + type Group struct { + DisplayName string + } + var group Group + group.DisplayName = "wirecat" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DisplayName, returnedGroup.DisplayName) + + }) + t.Run("UpdateDisplayNameInvalidName", func(t *testing.T) { + type Group struct { + DisplayName string + } + var group Group + //create name that is longer than 100 chars + name := "" + for i := 0; i < 101; i++ { + name = name + "a" + } + group.DisplayName = name + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DisplayName' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateInterface", func(t *testing.T) { + type Group struct { + DefaultInterface string + } + var group Group + group.DefaultInterface = "netmaker" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultInterface, returnedGroup.DefaultInterface) + + }) + t.Run("UpdateListenPort", func(t *testing.T) { + type Group struct { + DefaultListenPort int32 + } + var group Group + group.DefaultListenPort = 6000 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultListenPort, returnedGroup.DefaultListenPort) + }) + t.Run("UpdateListenPortInvalidPort", func(t *testing.T) { + type Group struct { + DefaultListenPort int32 + } + var group Group + group.DefaultListenPort = 1023 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DefaultListenPort' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdatePostUP", func(t *testing.T) { + type Group struct { + DefaultPostUp string + } + var group Group + group.DefaultPostUp = "sudo wg add-conf wc-netmaker /etc/wireguard/peers/conf" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultPostUp, returnedGroup.DefaultPostUp) + }) + t.Run("UpdatePreUP", func(t *testing.T) { + type Group struct { + DefaultPreUp string + } + var group Group + group.DefaultPreUp = "test string" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultPreUp, returnedGroup.DefaultPreUp) + }) + t.Run("UpdateKeepAlive", func(t *testing.T) { + type Group struct { + DefaultKeepalive int32 + } + var group Group + group.DefaultKeepalive = 60 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultKeepalive, returnedGroup.DefaultKeepalive) + }) + t.Run("UpdateKeepAliveTooBig", func(t *testing.T) { + type Group struct { + DefaultKeepAlive int32 + } + var group Group + group.DefaultKeepAlive = 1001 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DefaultKeepAlive' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("UpdateSaveConfig", func(t *testing.T) { + //causes panic + t.Skip() + type Group struct { + DefaultSaveConfig *bool + } + var group Group + value := false + group.DefaultSaveConfig = &value + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, *group.DefaultSaveConfig, *returnedGroup.DefaultSaveConfig) + }) + t.Run("UpdateManualSignUP", func(t *testing.T) { + t.Skip() + type Group struct { + AllowManualSignUp *bool + } + var group Group + value := true + group.AllowManualSignUp = &value + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, *group.AllowManualSignUp, *returnedGroup.AllowManualSignUp) + }) + t.Run("DefaultCheckInterval", func(t *testing.T) { + type Group struct { + DefaultCheckInInterval int32 + } + var group Group + group.DefaultCheckInInterval = 6000 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DefaultCheckInInterval, returnedGroup.DefaultCheckInInterval) + }) + t.Run("DefaultCheckIntervalTooBig", func(t *testing.T) { + type Group struct { + DefaultCheckInInterval int32 + } + var group Group + group.DefaultCheckInInterval = 100001 + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + var message models.ErrorResponse + err = json.NewDecoder(response.Body).Decode(&message) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnprocessableEntity, message.Code) + assert.Equal(t, "W1R3: Field validation for 'DefaultCheckInInterval' failed.", message.Message) + assert.Equal(t, http.StatusUnprocessableEntity, response.StatusCode) + }) + t.Run("MultipleFields", func(t *testing.T) { + type Group struct { + DisplayName string + DefaultListenPort int32 + } + var group Group + group.DefaultListenPort = 7777 + group.DisplayName = "multi" + response, err := api(t, group, http.MethodPut, "http://localhost:8081/api/groups/skynet", "secretkey") + assert.Nil(t, err, err) + assert.Equal(t, http.StatusOK, response.StatusCode) + defer response.Body.Close() + err = json.NewDecoder(response.Body).Decode(&returnedGroup) + assert.Nil(t, err, err) + assert.Equal(t, group.DisplayName, returnedGroup.DisplayName) + assert.Equal(t, group.DefaultListenPort, returnedGroup.DefaultListenPort) + }) +} diff --git a/user_test.go b/test/user_test.go similarity index 70% rename from user_test.go rename to test/user_test.go index cd55f988..38ea4797 100644 --- a/user_test.go +++ b/test/user_test.go @@ -1,56 +1,14 @@ package main import ( - "bytes" "encoding/json" "net/http" - "os" - "sync" "testing" - "time" - controller "github.com/gravitl/netmaker/controllers" "github.com/gravitl/netmaker/models" - "github.com/gravitl/netmaker/mongoconn" "github.com/stretchr/testify/assert" ) -type databaseError struct { - Inner *int - Errors int -} - -//should be use models.SuccessResponse and models.SuccessfulUserLoginResponse -//rather than creating new type but having trouble decoding that way -type Auth struct { - Username string - AuthToken string -} -type Success struct { - Code int - Message string - Response Auth -} - -type AuthorizeTestCase struct { - testname string - name string - password string - code int - tokenExpected bool - errMessage string -} - -func TestMain(m *testing.M) { - mongoconn.ConnectDatabase() - var waitgroup sync.WaitGroup - waitgroup.Add(1) - go controller.HandleRESTRequests(&waitgroup) - //wait for http server to start - time.Sleep(time.Second * 1) - os.Exit(m.Run()) -} - func TestAdminCreation(t *testing.T) { var admin models.UserAuthParams var user models.User @@ -260,68 +218,3 @@ func TestAuthenticateUser(t *testing.T) { }) } } - -func adminExists(t *testing.T) bool { - response, err := http.Get("http://localhost:8081/users/hasadmin") - assert.Nil(t, err, err) - assert.Equal(t, http.StatusOK, response.StatusCode) - defer response.Body.Close() - var body bool - json.NewDecoder(response.Body).Decode(&body) - return body -} - -func api(t *testing.T, data interface{}, method, url, authorization string) (*http.Response, error) { - var request *http.Request - var err error - if data != "" { - payload, err := json.Marshal(data) - assert.Nil(t, err, err) - request, err = http.NewRequest(method, url, bytes.NewBuffer(payload)) - assert.Nil(t, err, err) - request.Header.Set("Content-Type", "application/json") - } else { - request, err = http.NewRequest(method, url, nil) - assert.Nil(t, err, err) - } - if authorization != "" { - request.Header.Set("Authorization", "Bearer "+authorization) - } - client := http.Client{} - return client.Do(request) -} - -func addAdmin(t *testing.T) { - var admin models.User - admin.UserName = "admin" - admin.Password = "password" - response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/createadmin", "secretkey") - assert.Nil(t, err, err) - assert.Equal(t, http.StatusOK, response.StatusCode) -} - -func authenticate(t *testing.T) (string, error) { - var admin models.User - admin.UserName = "admin" - admin.Password = "password" - response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/authenticate", "secretkey") - assert.Nil(t, err, err) - - var body Success - err = json.NewDecoder(response.Body).Decode(&body) - assert.Nil(t, err, err) - assert.NotEmpty(t, body.Response.AuthToken, "token not returned") - assert.Equal(t, "W1R3: Device admin Authorized", body.Message) - - return body.Response.AuthToken, nil -} - -func deleteAdmin(t *testing.T) { - if !adminExists(t) { - return - } - token, err := authenticate(t) - assert.Nil(t, err, err) - _, err = api(t, "", http.MethodDelete, "http://localhost:8081/users/admin", token) - assert.Nil(t, err, err) -} From 16738ca9cce7ec1b95f90dd4e279687344b14c24 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 10:33:50 -0400 Subject: [PATCH 21/51] update docker generation on pulls --- .github/workflows/publish-docker-latest.yml | 33 --------------------- .github/workflows/publish-docker.yml | 18 +++++++---- 2 files changed, 13 insertions(+), 38 deletions(-) delete mode 100644 .github/workflows/publish-docker-latest.yml diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml deleted file mode 100644 index 43f4f847..00000000 --- a/.github/workflows/publish-docker-latest.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Publish Docker - -on: - push: - branches: - - 'master' -jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: true - tags: nusak/netmaker:latest diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 861b2924..ecf765cc 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,16 +1,19 @@ name: Publish Docker on: - push: + pull_request: branches: - - 'arm-docker' - 'develop' - - + - 'master' jobs: docker: runs-on: ubuntu-latest steps: - - + - uses: FranzDiebold/github-env-vars-action@v2 + - name: Set Environment Variables + run: | + echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV + - name: Checkout uses: actions/checkout@v2 - @@ -32,4 +35,9 @@ jobs: context: . platforms: linux/amd64, linux/arm64 push: true - tags: nusak/netmaker:dev + tags: | + nusak/nusak:${{ env.CI_REF_NAME_SLUG }} + nusak/nusak:${{ env.BUILD_VER }} + + + From 0a792513fbe13ff9bd9cea75f4b61d6d66133770 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 10:38:11 -0400 Subject: [PATCH 22/51] fix repo name --- .github/workflows/publish-docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index ecf765cc..20b72f9f 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -36,8 +36,8 @@ jobs: platforms: linux/amd64, linux/arm64 push: true tags: | - nusak/nusak:${{ env.CI_REF_NAME_SLUG }} - nusak/nusak:${{ env.BUILD_VER }} + nusak/netmaker:${{ env.CI_REF_NAME_SLUG }} + nusak/netmaker:${{ env.BUILD_VER }} From a0c97447ad4beee599a8bead57c2c210361ec893 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 10:41:10 -0400 Subject: [PATCH 23/51] update docker image generation (#3) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master * update docker generation on pulls * fix repo name Co-authored-by: Matthew R Kasun --- .github/workflows/publish-docker.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 861b2924..526f5f90 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,16 +1,19 @@ name: Publish Docker on: - push: + pull_request: branches: - - 'arm-docker' - 'develop' - - + - 'master' jobs: docker: runs-on: ubuntu-latest steps: - - + - uses: FranzDiebold/github-env-vars-action@v2 + - name: Set Environment Variables + run: | + echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV + - name: Checkout uses: actions/checkout@v2 - @@ -32,4 +35,7 @@ jobs: context: . platforms: linux/amd64, linux/arm64 push: true - tags: nusak/netmaker:dev + tags: | + nusak/netmaker:${{ env.CI_REF_NAME_SLUG }} + nusak/netmaker:${{ env.BUILD_VER }} + From 314126c369910569ebf9345fdd3d491010186176 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 10:44:27 -0400 Subject: [PATCH 24/51] consolidate git actions --- .github/workflows/publish-docker-latest.yml | 33 --------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/publish-docker-latest.yml diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml deleted file mode 100644 index 43f4f847..00000000 --- a/.github/workflows/publish-docker-latest.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Publish Docker - -on: - push: - branches: - - 'master' -jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: true - tags: nusak/netmaker:latest From 5453fdc02af148e630db4c1a99a2cb003be18dbd Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 10:51:30 -0400 Subject: [PATCH 25/51] Develop (#4) * Get Group api test * Initial Group Tests * Most Delete Group Tests * Group Tests Complete * Refactor tests and move to test dir * Refactor tests and move to test dir * changed wirecat --> netmaker. Changed defaults to be more sensible * putting netmaker default port 1 above WG port to avoid conflicts with preexisting setups * fixed client side for multinet and added group filter to query params server side. * fixed client side for multinet and added group filter to query params server side. * cleaned up netclient uninstall for multiple networks * added access token for ease of configuration * added access token for ease of configuration * peer update functionality * auto delete timestamp works * Arm docker (#1) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master Co-authored-by: Matthew R Kasun * update docker image generation (#3) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master * update docker generation on pulls * fix repo name Co-authored-by: Matthew R Kasun * consolidate git actions Co-authored-by: Matthew R Kasun Co-authored-by: afeiszli Co-authored-by: Alex <31018251+afeiszli@users.noreply.github.com> --- .github/workflows/publish-docker.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 861b2924..98ab90fc 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,16 +1,19 @@ name: Publish Docker on: - push: + pull_request: branches: - - 'arm-docker' - 'develop' - - + - 'master' jobs: docker: runs-on: ubuntu-latest steps: - - + - uses: FranzDiebold/github-env-vars-action@v2 + - name: Set Environment Variables + run: | + echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV + - name: Checkout uses: actions/checkout@v2 - @@ -32,4 +35,8 @@ jobs: context: . platforms: linux/amd64, linux/arm64 push: true - tags: nusak/netmaker:dev + tags: | + nusak/netmaker:${{ env.CI_REF_NAME_SLUG }} + nusak/netmaker:${{ env.BUILD_VER }} + + From 9a846af332851a9f5ffee34b36254c71b7e0dd22 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 10:53:10 -0400 Subject: [PATCH 26/51] Update publish-docker.yml --- .github/workflows/publish-docker.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 98ab90fc..7bc3ddff 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -11,24 +11,24 @@ jobs: steps: - uses: FranzDiebold/github-env-vars-action@v2 - name: Set Environment Variables - run: | + run: | echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 - - + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - + - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - + - name: Build and push uses: docker/build-push-action@v2 with: From 1bfacb0cbaf47740acca6fbbf21731cdb50ebd8e Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 11:17:17 -0400 Subject: [PATCH 27/51] Delete publish-docker-latest.yml --- .github/workflows/publish-docker-latest.yml | 33 --------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/publish-docker-latest.yml diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml deleted file mode 100644 index 43f4f847..00000000 --- a/.github/workflows/publish-docker-latest.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Publish Docker - -on: - push: - branches: - - 'master' -jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: true - tags: nusak/netmaker:latest From 83c239ddc9a6acc15dc079f6ed09d08652f695ea Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 7 Apr 2021 11:24:39 -0400 Subject: [PATCH 28/51] github actions update (#5) * Get Group api test * Initial Group Tests * Most Delete Group Tests * Group Tests Complete * Refactor tests and move to test dir * Refactor tests and move to test dir * changed wirecat --> netmaker. Changed defaults to be more sensible * putting netmaker default port 1 above WG port to avoid conflicts with preexisting setups * fixed client side for multinet and added group filter to query params server side. * fixed client side for multinet and added group filter to query params server side. * cleaned up netclient uninstall for multiple networks * added access token for ease of configuration * added access token for ease of configuration * peer update functionality * auto delete timestamp works * Arm docker (#1) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master Co-authored-by: Matthew R Kasun * update docker image generation (#3) * learning github actions * pubish docker * pubish docker * fixt uses * docker git action * rm arm7 * more events and tags * fixed yml file * simplified workflow * simplified workflow * fix missing tags * another fix to yml * another fix to yml * fixing yml * another try * tags * remove ghaction-docker-meta * separate actions for dev & master * update docker generation on pulls * fix repo name Co-authored-by: Matthew R Kasun * consolidate git actions * Update publish-docker.yml * Delete publish-docker-latest.yml Co-authored-by: Matthew R Kasun Co-authored-by: afeiszli Co-authored-by: Alex <31018251+afeiszli@users.noreply.github.com> --- .github/workflows/publish-docker-latest.yml | 33 --------------------- .github/workflows/publish-docker.yml | 10 +++---- 2 files changed, 5 insertions(+), 38 deletions(-) delete mode 100644 .github/workflows/publish-docker-latest.yml diff --git a/.github/workflows/publish-docker-latest.yml b/.github/workflows/publish-docker-latest.yml deleted file mode 100644 index 43f4f847..00000000 --- a/.github/workflows/publish-docker-latest.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Publish Docker - -on: - push: - branches: - - 'master' -jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: true - tags: nusak/netmaker:latest diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 98ab90fc..7bc3ddff 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -11,24 +11,24 @@ jobs: steps: - uses: FranzDiebold/github-env-vars-action@v2 - name: Set Environment Variables - run: | + run: | echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 - - + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - + - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - + - name: Build and push uses: docker/build-push-action@v2 with: From 9edf655887705b7b67bf1242803b95e09e7538fe Mon Sep 17 00:00:00 2001 From: afeiszli Date: Thu, 8 Apr 2021 09:04:21 -0400 Subject: [PATCH 29/51] fixing some netclient bugs --- netclient-install.sh | 2 +- netclient/functions/common.go | 6 ++++++ netclient/functions/local.go | 13 ++++++++----- netclient/main.go | 5 +++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/netclient-install.sh b/netclient-install.sh index 81621aec..02ae02ae 100755 --- a/netclient-install.sh +++ b/netclient-install.sh @@ -7,7 +7,7 @@ set -e -wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.1/netclient +wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.1/netclient netclient chmod +x netclient sudo ./netclient -c install -s $SERVER_URL -g $NET_NAME -k $KEY rm -f netclient diff --git a/netclient/functions/common.go b/netclient/functions/common.go index 385bba75..a6fff8a3 100644 --- a/netclient/functions/common.go +++ b/netclient/functions/common.go @@ -79,6 +79,12 @@ func Install(accesskey string, password string, server string, group string, noa tnetwork := "" tkey := "" + if FileExists("/etc/systemd/system/netclient-"+group+".timer") || + FileExists("/etc/netclient/netconfig-"+group) { + err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for network " + group + ". To re-install, please remove by executing 'sudo netclient -c remove -n " + group + "'. Then re-run the install command.") + return err + } + if accesstoken != "" && accesstoken != "badtoken" { btoken, err := base64.StdEncoding.DecodeString(accesstoken) if err != nil { diff --git a/netclient/functions/local.go b/netclient/functions/local.go index 5e53568a..c2962655 100644 --- a/netclient/functions/local.go +++ b/netclient/functions/local.go @@ -12,7 +12,7 @@ import ( ) -func fileExists(f string) bool { +func FileExists(f string) bool { info, err := os.Stat(f) if os.IsNotExist(err) { return false @@ -45,14 +45,17 @@ func ConfigureSystemD(network string) error { return err } - if !fileExists("/usr/local/bin/netclient") { + if !FileExists("/usr/local/bin/netclient") { + os.Symlink("/etc/netclient/netclient","/usr/local/bin/netclient") + /* _, err = copy(binarypath, "/usr/local/bin/netclient") if err != nil { log.Println(err) return err } + */ } - if !fileExists("/etc/netclient/netclient") { + if !FileExists("/etc/netclient/netclient") { _, err = copy(binarypath, "/etc/netclient/netclient") if err != nil { log.Println(err) @@ -100,7 +103,7 @@ WantedBy=timers.target servicebytes := []byte(systemservice) timerbytes := []byte(systemtimer) - if !fileExists("/etc/systemd/system/netclient@.service") { + if !FileExists("/etc/systemd/system/netclient@.service") { err = ioutil.WriteFile("/etc/systemd/system/netclient@.service", servicebytes, 0644) if err != nil { log.Println(err) @@ -108,7 +111,7 @@ WantedBy=timers.target } } - if !fileExists("/etc/systemd/system/netclient-"+network+".timer") { + if !FileExists("/etc/systemd/system/netclient-"+network+".timer") { err = ioutil.WriteFile("/etc/systemd/system/netclient-"+network+".timer", timerbytes, 0644) if err != nil { log.Println(err) diff --git a/netclient/main.go b/netclient/main.go index b9568534..738ccbdb 100644 --- a/netclient/main.go +++ b/netclient/main.go @@ -110,6 +110,7 @@ func main() { fmt.Println("Beginning agent installation.") err := functions.Install(*taccesskey, *tpassword, *tserver, *tnetwork, *tnoauto, *taccesstoken, *tname) if err != nil { + if !strings.Contains(err.Error(), "ALREADY_INSTALLED") { fmt.Println("Error installing: ", err) fmt.Println("Cleaning up (uninstall)") err = functions.Remove(*tnetwork) @@ -126,6 +127,10 @@ func main() { } } os.Exit(1) + } else { + fmt.Println(err.Error()) + os.Exit(1) + } } /* case "service-install": From 99589f4f2ecc6ab51e98aa1ebf47efa1826b90cf Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 10:11:49 -0400 Subject: [PATCH 30/51] environment action --- .github/workflows/environment.yml | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/environment.yml diff --git a/.github/workflows/environment.yml b/.github/workflows/environment.yml new file mode 100644 index 00000000..f18e3ae7 --- /dev/null +++ b/.github/workflows/environment.yml @@ -0,0 +1,49 @@ +name: Demo + +on: [push, pull_request] + +jobs: + linux: + name: Linux Demo + runs-on: ubuntu-latest + steps: + - uses: FranzDiebold/github-env-vars-action@v2 + - name: Print environment variables exposed by this action + run: | + echo "CI_REPOSITORY_SLUG=$CI_REPOSITORY_SLUG" + echo "CI_REPOSITORY_OWNER=$CI_REPOSITORY_OWNER" + echo "CI_REPOSITORY_OWNER_SLUG=$CI_REPOSITORY_OWNER_SLUG" + echo "CI_REPOSITORY_NAME=$CI_REPOSITORY_NAME" + echo "CI_REPOSITORY_NAME_SLUG=$CI_REPOSITORY_NAME_SLUG" + echo "CI_REPOSITORY=$CI_REPOSITORY" + echo "CI_REF_SLUG=$CI_REF_SLUG" + echo "CI_ACTION_REF_NAME=$CI_ACTION_REF_NAME" + echo "CI_ACTION_REF_NAME_SLUG=$CI_ACTION_REF_NAME_SLUG" + echo "CI_REF_NAME=$CI_REF_NAME" + echo "CI_REF_NAME_SLUG=$CI_REF_NAME_SLUG" + echo "CI_REF=$CI_REF" + echo "CI_HEAD_REF_SLUG=$CI_HEAD_REF_SLUG" + echo "CI_HEAD_REF=$CI_HEAD_REF" + echo "CI_BASE_REF_SLUG=$CI_BASE_REF_SLUG" + echo "CI_BASE_REF=$CI_BASE_REF" + echo "CI_SHA_SHORT=$CI_SHA_SHORT" + echo "CI_SHA=$CI_SHA" + echo "CI_ACTOR=$CI_ACTOR" + echo "CI_EVENT_NAME=$CI_EVENT_NAME" + echo "CI_RUN_ID=$CI_RUN_ID" + echo "CI_RUN_NUMBER=$CI_RUN_NUMBER" + echo "CI_WORKFLOW=$CI_WORKFLOW" + echo "CI_ACTION=$CI_ACTION" + - name: Print environment variables exposed by GitHub + run: | + echo "GITHUB_ACTOR=$GITHUB_ACTOR" + echo "GITHUB_REPOSITORY=$GITHUB_REPOSITORY" + echo "GITHUB_SHA=$GITHUB_SHA" + echo "GITHUB_REF=$GITHUB_REF" + echo "GITHUB_HEAD_REF=$GITHUB_HEAD_REF" + echo "GITHUB_BASE_REF=$GITHUB_BASE_REF" + echo "GITHUB_EVENT_NAME=$GITHUB_EVENT_NAME" + echo "GITHUB_RUN_ID=$GITHUB_RUN_ID" + echo "GITHUB_RUN_NUMBER=$GITHUB_RUN_NUMBER" + echo "GITHUB_WORKFLOW=$GITHUB_WORKFLOW" + echo "GITHUB_ACTION=$GITHUB_ACTION" From af328195a45a00c8e49f758c9abb525ea9e56df0 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 10:24:33 -0400 Subject: [PATCH 31/51] environment action update --- .github/workflows/environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/environment.yml b/.github/workflows/environment.yml index f18e3ae7..672f4455 100644 --- a/.github/workflows/environment.yml +++ b/.github/workflows/environment.yml @@ -10,6 +10,7 @@ jobs: - uses: FranzDiebold/github-env-vars-action@v2 - name: Print environment variables exposed by this action run: | + set echo "CI_REPOSITORY_SLUG=$CI_REPOSITORY_SLUG" echo "CI_REPOSITORY_OWNER=$CI_REPOSITORY_OWNER" echo "CI_REPOSITORY_OWNER_SLUG=$CI_REPOSITORY_OWNER_SLUG" From 08dc2f83020cf5c28b591e5a192f0ca686554c7a Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 10:57:15 -0400 Subject: [PATCH 32/51] git actions refinement --- .github/workflows/publish-docker.yml | 89 ++++++++++++++-------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 33ccfd14..d8755615 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,48 +1,45 @@ name: Publish Docker -on: - pull_request: - branches: - - 'develop' - - 'master' -jobs: - docker: - runs-on: ubuntu-latest - steps: - - uses: FranzDiebold/github-env-vars-action@v2 - - name: Set Environment Variables - - run: | - - echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - - - name: Checkout - uses: actions/checkout@v2 - - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: true - tags: | - nusak/netmaker:${{ env.CI_REF_NAME_SLUG }} - nusak/netmaker:${{ env.BUILD_VER }} - - +on: + pull_request: + branches: + - 'develop' + - 'master' + docker: + runs-on: ubuntu-latest + steps: + - + uses: FranzDiebold/github-env-vars-action@v2 + name: Set Environment Variables + run: | + echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV + if [ ${{ CI_HED_REF }} = "master" ] + then + echo "TAG=latest" >>$GITHUB_ENV + else + echo "TAG=$CI_HEAD_REF" >> $GITHUB_ENV + done + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: false + tags: | + nusak/netmaker:${{ env.TAG }} From f8c023caa0d6a939a9f0ba9e76dc3e7059dbfe4d Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 11:14:10 -0400 Subject: [PATCH 33/51] Update publish-docker.yml --- .github/workflows/publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 8f8ca911..d8755615 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,5 +1,6 @@ name: Publish Docker +on: pull_request: branches: - 'develop' @@ -42,4 +43,3 @@ name: Publish Docker push: false tags: | nusak/netmaker:${{ env.TAG }} - From fd7601fbf5570e8ac0c664c780a323b7959b89e0 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 11:18:27 -0400 Subject: [PATCH 34/51] remove environment action --- .github/workflows/environment.yml | 50 ------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 .github/workflows/environment.yml diff --git a/.github/workflows/environment.yml b/.github/workflows/environment.yml deleted file mode 100644 index 672f4455..00000000 --- a/.github/workflows/environment.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Demo - -on: [push, pull_request] - -jobs: - linux: - name: Linux Demo - runs-on: ubuntu-latest - steps: - - uses: FranzDiebold/github-env-vars-action@v2 - - name: Print environment variables exposed by this action - run: | - set - echo "CI_REPOSITORY_SLUG=$CI_REPOSITORY_SLUG" - echo "CI_REPOSITORY_OWNER=$CI_REPOSITORY_OWNER" - echo "CI_REPOSITORY_OWNER_SLUG=$CI_REPOSITORY_OWNER_SLUG" - echo "CI_REPOSITORY_NAME=$CI_REPOSITORY_NAME" - echo "CI_REPOSITORY_NAME_SLUG=$CI_REPOSITORY_NAME_SLUG" - echo "CI_REPOSITORY=$CI_REPOSITORY" - echo "CI_REF_SLUG=$CI_REF_SLUG" - echo "CI_ACTION_REF_NAME=$CI_ACTION_REF_NAME" - echo "CI_ACTION_REF_NAME_SLUG=$CI_ACTION_REF_NAME_SLUG" - echo "CI_REF_NAME=$CI_REF_NAME" - echo "CI_REF_NAME_SLUG=$CI_REF_NAME_SLUG" - echo "CI_REF=$CI_REF" - echo "CI_HEAD_REF_SLUG=$CI_HEAD_REF_SLUG" - echo "CI_HEAD_REF=$CI_HEAD_REF" - echo "CI_BASE_REF_SLUG=$CI_BASE_REF_SLUG" - echo "CI_BASE_REF=$CI_BASE_REF" - echo "CI_SHA_SHORT=$CI_SHA_SHORT" - echo "CI_SHA=$CI_SHA" - echo "CI_ACTOR=$CI_ACTOR" - echo "CI_EVENT_NAME=$CI_EVENT_NAME" - echo "CI_RUN_ID=$CI_RUN_ID" - echo "CI_RUN_NUMBER=$CI_RUN_NUMBER" - echo "CI_WORKFLOW=$CI_WORKFLOW" - echo "CI_ACTION=$CI_ACTION" - - name: Print environment variables exposed by GitHub - run: | - echo "GITHUB_ACTOR=$GITHUB_ACTOR" - echo "GITHUB_REPOSITORY=$GITHUB_REPOSITORY" - echo "GITHUB_SHA=$GITHUB_SHA" - echo "GITHUB_REF=$GITHUB_REF" - echo "GITHUB_HEAD_REF=$GITHUB_HEAD_REF" - echo "GITHUB_BASE_REF=$GITHUB_BASE_REF" - echo "GITHUB_EVENT_NAME=$GITHUB_EVENT_NAME" - echo "GITHUB_RUN_ID=$GITHUB_RUN_ID" - echo "GITHUB_RUN_NUMBER=$GITHUB_RUN_NUMBER" - echo "GITHUB_WORKFLOW=$GITHUB_WORKFLOW" - echo "GITHUB_ACTION=$GITHUB_ACTION" From 5c24d48a14f4e4e8bf63a7129697db8385408f17 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 13:32:40 -0400 Subject: [PATCH 35/51] force-push --- .github/workflows/force-push | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/workflows/force-push diff --git a/.github/workflows/force-push b/.github/workflows/force-push new file mode 100644 index 00000000..e69de29b From 6503296a7708c55a3e3468c4ca3cbbbb1915322a Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 13:42:20 -0400 Subject: [PATCH 36/51] Update publish-docker.yml --- .github/workflows/publish-docker.yml | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 8f8ca911..e8a06e28 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,16 +1,17 @@ name: Publish Docker - pull_request: - branches: - - 'develop' - - 'master' +on: + pull_request: + branches: + - 'develop' + - 'master' +jobs: docker: runs-on: ubuntu-latest steps: - - - uses: FranzDiebold/github-env-vars-action@v2 - name: Set Environment Variables - run: | + - uses: FranzDiebold/github-env-vars-action@v2 + - name: Set Environment Variables + run: | echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV if [ ${{ CI_HED_REF }} = "master" ] then @@ -31,15 +32,15 @@ name: Publish Docker name: Login to DockerHub uses: docker/login-action@v1 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v2 with: - context: . - platforms: linux/amd64, linux/arm64 - push: false - tags: | - nusak/netmaker:${{ env.TAG }} + context: . + platforms: linux/amd64, linux/arm64 + push: false + tags: | + nusak/netmaker:${{ env.TAG }} From 4c60142e9e066f4e860bfaf2aa1f33b3770246e7 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 13:45:23 -0400 Subject: [PATCH 37/51] environment action update --- .github/workflows/force-push | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .github/workflows/force-push diff --git a/.github/workflows/force-push b/.github/workflows/force-push deleted file mode 100644 index e69de29b..00000000 From 5612a347a3728cadd01dfa9d78b30699c8d5836c Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 13:50:06 -0400 Subject: [PATCH 38/51] fix typo --- .github/workflows/publish-docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index d8755615..203f130c 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -13,7 +13,7 @@ on: name: Set Environment Variables run: | echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - if [ ${{ CI_HED_REF }} = "master" ] + if [ ${{ CI_HEAD_REF }} = "master" ] then echo "TAG=latest" >>$GITHUB_ENV else From 816e157fc1370135aeeed3e50371299b8ff66986 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 13:56:21 -0400 Subject: [PATCH 39/51] Update publish-docker.yml --- .github/workflows/publish-docker.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 203f130c..c5a3637d 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -9,15 +9,14 @@ on: runs-on: ubuntu-latest steps: - - uses: FranzDiebold/github-env-vars-action@v2 name: Set Environment Variables run: | echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - if [ ${{ CI_HEAD_REF }} = "master" ] + if ${{ github.head_ref }} = "master" ] then echo "TAG=latest" >>$GITHUB_ENV else - echo "TAG=$CI_HEAD_REF" >> $GITHUB_ENV + echo "TAG=${{ github.head_ref}} >> $GITHUB_ENV done - name: Checkout From 25e08b9027767a210bfa37d79156c69f44c78e04 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 14:25:05 -0400 Subject: [PATCH 40/51] try again --- .github/workflows/publish-docker.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 43307f1a..998681eb 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -14,11 +14,9 @@ jobs: run: | echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV if ${{ github.head_ref }} = "master" ] - then echo "TAG=latest" >>$GITHUB_ENV - else - echo "TAG=${{ github.head_ref}}" >> $GITHUB_ENV - done + if ${{ github.head_ref }} = "master" ] + echo "TAG=develop" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 From 893777b627dc88725e81a28e36ead198146dd355 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 14:47:33 -0400 Subject: [PATCH 41/51] fix yaml --- .github/workflows/publish-docker.yml | 83 +++++++++++++++------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 998681eb..6acc3a8e 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,43 +1,48 @@ name: Publish Docker -on: +on: pull_request: - branches: - - 'develop' - - 'master' + branches: + - 'develop' + - 'master' + push: + jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Set Environment Variables - run: | - echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - if ${{ github.head_ref }} = "master" ] - echo "TAG=latest" >>$GITHUB_ENV - if ${{ github.head_ref }} = "master" ] - echo "TAG=develop" >> $GITHUB_ENV - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: false - tags: | - nusak/netmaker:${{ env.TAG }} + docker: + runs-on: ubuntu-latest + steps: + - name: Set Environment Variables + run: | + echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV + if ${{ github.head_ref }} = "master" + echo "TAG=latest" >>$GITHUB_ENV + if ${{ github.head_ref }} = "develop" + echo "TAG=develop" >> $GITHUB_ENV + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: false + tags: | + nusak/netmaker:${{ env.TAG }} + if ${{ github.head_ref }} = "master" + nusak/netmaker:latest + if ${{ github.head_ref }} = "develop" + nusak/netmaker:latest From 2cd30084c3ecf393a35c8b1747df042a44223ec0 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 14:52:20 -0400 Subject: [PATCH 42/51] try again --- .github/workflows/publish-docker.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 6acc3a8e..390f9216 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -12,12 +12,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Environment Variables - run: | + run: echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - if ${{ github.head_ref }} = "master" - echo "TAG=latest" >>$GITHUB_ENV - if ${{ github.head_ref }} = "develop" - echo "TAG=develop" >> $GITHUB_ENV + if ${{ github.head_ref }} = "master" + echo "TAG=latest" >>$GITHUB_ENV + if ${{ github.head_ref }} = "develop" + echo "TAG=develop" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 From 2d6a3d6168f4491fd40054302d9026bfc810af6e Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 14:54:29 -0400 Subject: [PATCH 43/51] remove setup of env vars --- .github/workflows/publish-docker.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 390f9216..31ad3f19 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -11,13 +11,6 @@ jobs: docker: runs-on: ubuntu-latest steps: - - name: Set Environment Variables - run: - echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - if ${{ github.head_ref }} = "master" - echo "TAG=latest" >>$GITHUB_ENV - if ${{ github.head_ref }} = "develop" - echo "TAG=develop" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 From 1012fd3643d3d58314c1d30c6a4f1f6547011ee3 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 15:10:29 -0400 Subject: [PATCH 44/51] separate env steps for now --- .github/workflows/publish-docker.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 31ad3f19..f4bed220 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -11,6 +11,14 @@ jobs: docker: runs-on: ubuntu-latest steps: + - + name: Env Vars - Master + if: ${{ github.head_ref }} "master" + run: echo "TAG=latest" >> $GITHUB_ENV + - + name: Env Vars - Develop + if: ${{ github.head_ref }} "develop" + run: echo "TAG=develop" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 @@ -35,7 +43,3 @@ jobs: push: false tags: | nusak/netmaker:${{ env.TAG }} - if ${{ github.head_ref }} = "master" - nusak/netmaker:latest - if ${{ github.head_ref }} = "develop" - nusak/netmaker:latest From c27278158ee0161999964cab3d400041c78feda0 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 15:27:47 -0400 Subject: [PATCH 45/51] refinement --- .github/workflows/publish-docker.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index f4bed220..892981d1 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -11,14 +11,6 @@ jobs: docker: runs-on: ubuntu-latest steps: - - - name: Env Vars - Master - if: ${{ github.head_ref }} "master" - run: echo "TAG=latest" >> $GITHUB_ENV - - - name: Env Vars - Develop - if: ${{ github.head_ref }} "develop" - run: echo "TAG=develop" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v2 @@ -35,11 +27,22 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push + name: Build and push + if: ${{ github.head_ref }} "master" uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64, linux/arm64 push: false tags: | - nusak/netmaker:${{ env.TAG }} + nusak/netmaker:latest + - + name: Build and push + if: ${{ github.head_ref }} "develop" + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: false + tags: | + nusak/netmaker:develop From 6cd2bbcb94a98bb0011471ff05dc846bf142684f Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 15:34:09 -0400 Subject: [PATCH 46/51] another refinement --- .github/workflows/publish-docker.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 892981d1..9b1e386d 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -5,7 +5,6 @@ on: branches: - 'develop' - 'master' - push: jobs: docker: @@ -27,22 +26,22 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push if: ${{ github.head_ref }} "master" + name: Build and push uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64, linux/arm64 - push: false + push: true tags: | nusak/netmaker:latest - - name: Build and push if: ${{ github.head_ref }} "develop" + name: Build and push uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64, linux/arm64 - push: false + push: true tags: | nusak/netmaker:develop From 47cf914368b195ac8b9f4a1a248e0af4067437da Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 15:44:27 -0400 Subject: [PATCH 47/51] another refinement --- .github/workflows/publish-docker.yml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 9b1e386d..17b250ed 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -10,24 +10,19 @@ jobs: docker: runs-on: ubuntu-latest steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - - - name: Set up QEMU + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub + - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - + - name: Build and push latest if: ${{ github.head_ref }} "master" - name: Build and push uses: docker/build-push-action@v2 with: context: . @@ -35,9 +30,8 @@ jobs: push: true tags: | nusak/netmaker:latest - - + - name: Build and push develop if: ${{ github.head_ref }} "develop" - name: Build and push uses: docker/build-push-action@v2 with: context: . From 9ba874153faea0470b613d62adce01aaceab7040 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 15:57:35 -0400 Subject: [PATCH 48/51] missing = --- .github/workflows/publish-docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 17b250ed..15c7a51d 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -22,7 +22,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push latest - if: ${{ github.head_ref }} "master" + if: ${{ github.head_ref }} = "master" uses: docker/build-push-action@v2 with: context: . @@ -31,7 +31,7 @@ jobs: tags: | nusak/netmaker:latest - name: Build and push develop - if: ${{ github.head_ref }} "develop" + if: ${{ github.head_ref }} = "develop" uses: docker/build-push-action@v2 with: context: . From 14466c11062a0bab02485460a060539f9d5ca1e5 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 18:05:07 -0400 Subject: [PATCH 49/51] fixed github actions --- .github/workflows/publish-docker.yml | 45 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index b6e1f64e..804e8404 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,42 +1,41 @@ name: Publish Docker -on: +on: pull_request: - branches: - - 'develop' - - 'master' + branches: + - 'develop' + - 'master' + jobs: docker: runs-on: ubuntu-latest steps: - - uses: FranzDiebold/github-env-vars-action@v2 - - name: Set Environment Variables - run: | - echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - - - name: Set up QEMU + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push + - name: Build and push latest + if: github.base_ref == 'master' uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64, linux/arm64 push: true tags: | - gravitl/netmaker:${{ env.CI_REF_NAME_SLUG }} - gravitl/netmaker:${{ env.BUILD_VER }} - - + gravitl/netmaker:latest + - name: Build and push develop + if: github.base_ref == 'develop' + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: | + gravitl/netmaker:develop From 252817b7ca92dbcf2cbb5ed8030e615e7466a1a3 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 8 Apr 2021 18:21:35 -0400 Subject: [PATCH 50/51] fixed github actions --- .github/workflows/publish-docker.yml | 78 +++++++++++++--------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 43307f1a..0e2d7e5f 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -1,45 +1,41 @@ name: Publish Docker -on: +on: pull_request: - branches: - - 'develop' - - 'master' + branches: + - 'develop' + - 'master' + jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Set Environment Variables - run: | - echo "BUILD_VER=v0.0.$GITHUB_RUN_NUMBER" >> $GITHUB_ENV - if ${{ github.head_ref }} = "master" ] - then - echo "TAG=latest" >>$GITHUB_ENV - else - echo "TAG=${{ github.head_ref}}" >> $GITHUB_ENV - done - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64, linux/arm64 - push: false - tags: | - nusak/netmaker:${{ env.TAG }} + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push latest + if: github.base_ref == 'master' + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: | + nusak/netmaker:latest + - name: Build and push develop + if: github.base_ref == 'develop' + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64, linux/arm64 + push: true + tags: | + nusak/netmaker:develop From cee410d3f3df3aaf000b84b738e01da349f9826c Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 12 Apr 2021 14:19:44 +0000 Subject: [PATCH 51/51] adding line to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a4a0e3e4..c63b98f9 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ In future releases, we have plans to support other platforms such as Windows and **For more information, please read the docs, or check out the Quick Start below:** - [Getting Started](docs/GETTING_STARTED.md) + - [Troubleshooting](docs/TROUBLESHOOTING.md) - [API Documentation](docs/API.md) - [Product Roadmap](docs/ROADMAP.md) - [Contributing](docs/CONTRIBUTING.md)