├── docs ├── debugout ├── source │ ├── _static │ │ ├── logo-square.png │ │ ├── wiki-button.png │ │ ├── paraglider-color-darkmode.png │ │ └── paraglider-color-lightmode.png │ ├── developers │ │ ├── contributing │ │ │ ├── contributing-issues.rst │ │ │ ├── known-issues.rst │ │ │ ├── building.rst │ │ │ └── writing-go.rst │ │ └── contributing.rst │ ├── overview │ │ ├── concepts.rst │ │ ├── howitworks.rst │ │ └── what-is-paraglider.rst │ ├── project │ │ ├── feature-status.rst │ │ └── roadmap.rst │ ├── examples │ │ └── tags.rst │ ├── conf.py │ └── index.rst ├── Makefile ├── requirements.txt └── make.bat ├── .github ├── CODEOWNERS ├── release.yml ├── workflows │ ├── functional-tests-approval.yaml │ ├── docs.yaml │ └── release.yml ├── dependabot.yml └── scripts │ ├── transform_test_results.py │ └── get_release_version.py ├── logo.png ├── governance ├── technical-charter.pdf ├── roles.md ├── tsc.md ├── role-changes.md ├── maintainers.md ├── tsc-procedures.md └── release-process.md ├── Makefile ├── .githooks └── prepare-commit-msg ├── .gitattributes ├── Dockerfile ├── .golangci.yaml ├── tools └── examples │ ├── vm-configs │ ├── gcp-vm.json │ ├── azure-vm-westus.json │ └── azure-vm-eastus.json │ ├── controller-configs │ └── config.yml │ └── cluster-configs │ └── gcp-cluster.json ├── .gitignore ├── cmd ├── glide │ └── main.go └── glided │ └── main.go ├── CONTRIBUTING.md ├── internal ├── cli │ ├── common │ │ ├── executor.go │ │ └── version.go │ ├── glide │ │ ├── server │ │ │ ├── server.go │ │ │ ├── get │ │ │ │ ├── get_test.go │ │ │ │ └── get.go │ │ │ └── set │ │ │ │ ├── set_test.go │ │ │ │ └── set.go │ │ ├── resource │ │ │ ├── resource.go │ │ │ ├── attach │ │ │ │ ├── attach_test.go │ │ │ │ └── attach.go │ │ │ └── create │ │ │ │ ├── create_test.go │ │ │ │ └── create.go │ │ ├── rule │ │ │ ├── rule.go │ │ │ ├── get │ │ │ │ ├── get_test.go │ │ │ │ └── get.go │ │ │ ├── delete │ │ │ │ ├── delete_test.go │ │ │ │ └── delete.go │ │ │ └── add │ │ │ │ ├── add_test.go │ │ │ │ └── add.go │ │ ├── namespace │ │ │ ├── namespace.go │ │ │ ├── get │ │ │ │ ├── get_test.go │ │ │ │ └── get.go │ │ │ ├── list │ │ │ │ ├── list_test.go │ │ │ │ └── list.go │ │ │ └── set │ │ │ │ ├── set_test.go │ │ │ │ └── set.go │ │ ├── tag │ │ │ ├── tag.go │ │ │ ├── list │ │ │ │ ├── list_test.go │ │ │ │ └── list.go │ │ │ ├── delete │ │ │ │ ├── delete_test.go │ │ │ │ └── delete.go │ │ │ ├── get │ │ │ │ ├── get_test.go │ │ │ │ └── get.go │ │ │ └── set │ │ │ │ ├── set_test.go │ │ │ │ └── set.go │ │ ├── config │ │ │ └── config.go │ │ └── root.go │ ├── glided │ │ ├── orchestrator │ │ │ └── orchestrator.go │ │ ├── az │ │ │ └── az.go │ │ ├── ibm │ │ │ └── ibm.go │ │ ├── gcp │ │ │ └── gcp.go │ │ ├── tagserv │ │ │ └── tagserv.go │ │ ├── kvserv │ │ │ └── kvserv.go │ │ ├── root.go │ │ └── startup │ │ │ └── startup.go │ └── invd │ │ └── ibm │ │ └── ibm.go └── version │ └── version.go ├── .devcontainer ├── postCreate.sh └── devcontainer.json ├── pkg ├── aws │ ├── clients.go │ ├── integration_test.go │ ├── plugin_test.go │ └── naming.go ├── kvstore │ ├── storepb │ │ └── storepb.proto │ ├── kvstore_test.go │ └── kvstore.go ├── azure │ ├── priority_utils_test.go │ ├── naming_test.go │ └── priority_utils.go ├── ibm │ ├── README.md │ └── vpc.go ├── orchestrator │ ├── config │ │ └── config.go │ └── orchestrator_utils.go ├── fake │ ├── kvstore │ │ └── fake_kvstore.go │ └── cloudplugin │ │ └── fake_cloud_plugin.go ├── utils │ └── utils_test.go ├── tag_service │ └── tagservicepb │ │ └── tagservice.proto └── gcp │ └── vpn.go ├── README.md ├── CODE-OF-CONDUCT.md └── GOVERNANCE.md /docs/debugout: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @paraglider-project/maintainers 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paraglider-project/paraglider/HEAD/logo.png -------------------------------------------------------------------------------- /governance/technical-charter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paraglider-project/paraglider/HEAD/governance/technical-charter.pdf -------------------------------------------------------------------------------- /docs/source/_static/logo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paraglider-project/paraglider/HEAD/docs/source/_static/logo-square.png -------------------------------------------------------------------------------- /docs/source/_static/wiki-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paraglider-project/paraglider/HEAD/docs/source/_static/wiki-button.png -------------------------------------------------------------------------------- /docs/source/_static/paraglider-color-darkmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paraglider-project/paraglider/HEAD/docs/source/_static/paraglider-color-darkmode.png -------------------------------------------------------------------------------- /docs/source/_static/paraglider-color-lightmode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paraglider-project/paraglider/HEAD/docs/source/_static/paraglider-color-lightmode.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ARROW := \033[34;1m=>\033[0m 2 | 3 | # order matters for these 4 | include build/help.mk build/version.mk build/build.mk build/test.mk build/install.mk build/debug.mk 5 | -------------------------------------------------------------------------------- /.githooks/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Add sign-off 4 | NAME="$(git config user.name)" 5 | EMAIL="$(git config user.email)" 6 | echo "" >> $1 7 | echo "Signed-off-by: $NAME <$EMAIL>" >> $1 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # text files use OS defaults on checkout, LF on checkin 2 | * text eol=auto 3 | 4 | # shell scripts always use LF 5 | *.sh text eol=lf 6 | 7 | # Denote all files that are truly binary and should not be modified. 8 | *.png binary 9 | *.jpg binary 10 | *.pdf binary 11 | -------------------------------------------------------------------------------- /governance/roles.md: -------------------------------------------------------------------------------- 1 | # Paraglider Committee Members 2 | 3 | ## TSC 4 | TSC membership is documented [here](tsc.md). 5 | 6 | ## MAC Liason 7 | Diego Vega 8 | 9 | ## TAC Liason 10 | TODO 11 | 12 | ## Release Manager 13 | Primary: Pravein Govindan Kannan 14 | 15 | Backup: Sean Kim 16 | 17 | ## Project Technical Lead 18 | Sarah McClure 19 | -------------------------------------------------------------------------------- /docs/source/developers/contributing/contributing-issues.rst: -------------------------------------------------------------------------------- 1 | .. _contributingissues: 2 | 3 | Contributing Issues 4 | ==================== 5 | 6 | You can open an issue `here `_. 7 | 8 | Please provide as much information as possible, including the version of the software you are using, the operating system, and the steps to reproduce the issue. 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.19 2 | 3 | # Populated during the build process, for example, with 'darwin_arm64' or 'linux_amd64'. 4 | ARG TARGETOS 5 | ARG TARGETARCH 6 | 7 | ENV TARGET_DIR=${TARGETOS}_${TARGETARCH} 8 | 9 | # Copy binary 10 | RUN mkdir -p /usr/local/bin 11 | COPY ./dist/$TARGET_DIR/release/glide /usr/local/bin/glide 12 | COPY ./dist/$TARGET_DIR/release/glided /usr/local/bin/glided 13 | 14 | ENTRYPOINT ["/usr/local/bin/glided", "startup", "config.yaml"] 15 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | 3 | changelog: 4 | exclude: 5 | labels: 6 | - ignore-for-release 7 | - dependencies 8 | - documentation 9 | categories: 10 | - title: Breaking Changes 🛠 11 | labels: 12 | - breaking-change 13 | - title: New Features 🎉 14 | labels: 15 | - enhancement 16 | - title: Bug Fixes 🐞 17 | labels: 18 | - bugfix 19 | - title: Other Changes 20 | labels: 21 | - "*" 22 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - goheader 4 | issues: 5 | exclude-rules: 6 | # Ignore test files which have unit/integration tags 7 | - path: _test\.go 8 | linters: 9 | - goheader 10 | linters-settings: 11 | # Settings for linter 'goheader' 12 | # 13 | # This is used to validate that all go files have the required copyright header. 14 | goheader: 15 | template-path: build/header.tmpl 16 | run: 17 | build-tags: 18 | - unit 19 | - integration 20 | -------------------------------------------------------------------------------- /tools/examples/vm-configs/gcp-vm.json: -------------------------------------------------------------------------------- 1 | { 2 | "instance_resource": { 3 | "disks": [{ 4 | "auto_delete": true, 5 | "boot": true, 6 | "initialize_params": { 7 | "disk_size_gb": 10, 8 | "source_image": "projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts" 9 | }, 10 | "type": "PERSISTENT" 11 | }], 12 | "machine_type": "zones/us-west1-a/machineTypes/f1-micro" 13 | }, 14 | "zone": "us-west1-a" 15 | } 16 | -------------------------------------------------------------------------------- /tools/examples/controller-configs/config.yml: -------------------------------------------------------------------------------- 1 | server: 2 | host: "localhost" 3 | port: 8080 4 | rpcPort: 8081 5 | 6 | cloudPlugins: 7 | - name: "gcp" 8 | host: "localhost" 9 | port: 10001 10 | - name: "azure" 11 | host: "localhost" 12 | port: 10002 13 | 14 | namespaces: 15 | default: 16 | - name: "azure" 17 | deployment: "/subscriptions//resourceGroups/" 18 | - name: "gcp" 19 | deployment: "projects/" 20 | 21 | tagService: 22 | host: "localhost" 23 | port: 6000 24 | -------------------------------------------------------------------------------- /tools/examples/vm-configs/azure-vm-westus.json: -------------------------------------------------------------------------------- 1 | { 2 | "location": "westus", 3 | "properties": { 4 | "hardwareProfile": { 5 | "vmSize": "Standard_B1s" 6 | }, 7 | "osProfile": { 8 | "adminPassword": "", 9 | "adminUsername": "", 10 | "computerName": "sample-compute" 11 | }, 12 | "storageProfile": { 13 | "imageReference": { 14 | "offer": "0001-com-ubuntu-minimal-jammy", 15 | "publisher": "canonical", 16 | "sku": "minimal-22_04-lts-gen2", 17 | "version": "latest" 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Compiled proto files 9 | *.pb.go 10 | *_grpc.pb.go 11 | 12 | # Test binary, built with `go test -c` 13 | *.test 14 | 15 | # Output of the go coverage tool, specifically when used with LiteIDE 16 | *.out 17 | 18 | # Logs 19 | *.log 20 | 21 | # Build Output 22 | bin/ 23 | dist/ 24 | main 25 | 26 | .vscode/ 27 | .DS_Store 28 | .idea/ 29 | __debug_bin 30 | __debug_bin.exe 31 | default.profraw 32 | 33 | # Editor backup files 34 | *~ 35 | *# 36 | 37 | # gomock files 38 | gomock_* 39 | 40 | # Key 41 | *key*.json 42 | *key*.csv 43 | 44 | # Sphinx 45 | docs/build/ 46 | 47 | # Python 48 | .venv/ 49 | -------------------------------------------------------------------------------- /tools/examples/vm-configs/azure-vm-eastus.json: -------------------------------------------------------------------------------- 1 | { 2 | "location": "eastus", 3 | "properties": { 4 | "hardwareProfile": { 5 | "vmSize": "Standard_B1s" 6 | }, 7 | "osProfile": { 8 | "adminPassword": "", 9 | "adminUsername": "", 10 | "computerName": "sample-compute" 11 | }, 12 | "storageProfile": { 13 | "imageReference": { 14 | "offer": "0001-com-ubuntu-minimal-jammy", 15 | "publisher": "canonical", 16 | "sku": "minimal-22_04-lts-gen2", 17 | "version": "latest" 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /governance/tsc.md: -------------------------------------------------------------------------------- 1 | # Paraglider Technical Steering Committee (TSC) 2 | The Technical Steering Committee (TSC) is in charge of making high-level technical decisions for Paraglider. 3 | 4 | ## Technical Steering Committee Members 5 | 6 | **Sarah McClure**
7 | UC Berkeley 8 | 9 | **Diego Vega**
10 | Microsoft 11 | 12 | **Sylvia Ratnasamy**
13 | UC Berkeley 14 | 15 | **Deepak Bansal**
16 | Microsoft 17 | 18 | **Pravein Govindan Kannan**
19 | IBM Research 20 | 21 | **Ashok Narayanan**
22 | Snyk 23 | 24 | **Anees Shaikh**
25 | Google 26 | 27 | **Sean Kim**
28 | Independent 29 | 30 | ### Contact Info 31 | You can contact the TSC at paraglider-tsc [at] lists.paragliderproject.io. 32 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.16 2 | Babel==2.16.0 3 | beautifulsoup4==4.12.3 4 | certifi==2024.8.30 5 | charset-normalizer==3.4.0 6 | docutils==0.21.2 7 | furo==2024.8.6 8 | idna==3.10 9 | imagesize==1.4.1 10 | importlib_metadata==8.5.0 11 | Jinja2==3.1.4 12 | MarkupSafe==2.1.5 13 | packaging==24.1 14 | Pygments==2.18.0 15 | requests==2.32.3 16 | snowballstemmer==2.2.0 17 | soupsieve==2.6 18 | Sphinx==7.4.7 19 | sphinx-basic-ng==1.0.0b2 20 | sphinx-copybutton==0.5.2 21 | sphinx_design==0.6.1 22 | sphinxcontrib-applehelp==2.0.0 23 | sphinx-copybutton==0.5.2 24 | sphinxcontrib-devhelp==2.0.0 25 | sphinxcontrib-htmlhelp==2.1.0 26 | sphinxcontrib-jsmath==1.0.1 27 | sphinxcontrib-mermaid==0.9.2 28 | sphinxcontrib-qthelp==2.0.0 29 | sphinxcontrib-serializinghtml==2.0.0 30 | urllib3==2.2.3 31 | zipp==3.20.2 32 | -------------------------------------------------------------------------------- /cmd/glide/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | cli "github.com/paraglider-project/paraglider/internal/cli/glide" 21 | ) 22 | 23 | func main() { 24 | cli.Execute() 25 | } 26 | -------------------------------------------------------------------------------- /cmd/glided/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | cli "github.com/paraglider-project/paraglider/internal/cli/glided" 21 | ) 22 | 23 | func main() { 24 | cli.Execute() 25 | } 26 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Paraglider 2 | 3 | Welcome to the Paraglider repo! 4 | 5 | ## Current Status 6 | The Paraglider project is in its prototype phase. We are excited to work with the community to continue to work on it. Please let us know what you think about the project and let us know when you find bugs or would like to request a new feature (see our [Issues Guide](docs/source/developers/contributing/contributing-issues.rst)). Paraglider is not yet ready for production deployments. 7 | 8 | ## Guidelines 9 | Please refer to our full [contributor guidelines](docs/source/developers/contributing.rst) for more information. 10 | 11 | ## Contact Us 12 | If you have questions or other concerns and would like to contact the maintainers, please join our [discord](https://discordapp.com/channels/1116864463832891502/11168644638328915074). 13 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /internal/cli/common/executor.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "io" 21 | 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | type CommandExecutor interface { 26 | Validate(cmd *cobra.Command, args []string) error 27 | Execute(cmd *cobra.Command, args []string) error 28 | SetOutput(w io.Writer) 29 | } 30 | -------------------------------------------------------------------------------- /docs/source/developers/contributing/known-issues.rst: -------------------------------------------------------------------------------- 1 | .. _knownissues: 2 | 3 | Known Issues 4 | ------------- 5 | 6 | ``gopls`` Linting Issue in Testing Files on Package Declaration Line 7 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 8 | You may see the following error from ``gopls`` in the ``*_test.go`` files. 9 | 10 | This file is within module ".", which is not included in your workspace. 11 | To fix this problem, you can add a go.work file that uses this directory. 12 | See the documentation for more information on setting up your workspace: 13 | https://github.com/golang/tools/blob/master/gopls/doc/workspace.md. 14 | 15 | 16 | This is due to a known issue within ``gopls`` (https://github.com/golang/go/issues/29202). 17 | You can work around this in VS Code by specifying the following in your ``settings.json``. 18 | 19 | .. code-block:: json 20 | 21 | "go.buildTags": "unit,integration,multicloud" 22 | -------------------------------------------------------------------------------- /.devcontainer/postCreate.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Redis (not using dev container features as there are problems with Apple Silicon and homebrew which ghcr.io/devcontainers-contrib/features/redis-homebrew:1 relies on) 4 | # See the following links for more information 5 | # - https://github.com/microsoft/vscode-dev-containers/issues/1492#issuecomment-1423265928 6 | # - https://github.com/meaningful-ooo/devcontainer-features/issues/28 7 | curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg 8 | echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list 9 | sudo apt-get update 10 | sudo apt-get -y install redis 11 | 12 | set -ex 13 | go install gotest.tools/gotestsum@latest 14 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 15 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 16 | -------------------------------------------------------------------------------- /pkg/aws/clients.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "github.com/aws/aws-sdk-go-v2/aws" 21 | "github.com/aws/aws-sdk-go-v2/service/ec2" 22 | ) 23 | 24 | type awsClients struct { 25 | ec2Client *ec2.Client 26 | } 27 | 28 | func (c *awsClients) getOrCreateEc2Client(cfg aws.Config, optFns ...func(*ec2.Options)) *ec2.Client { 29 | if c.ec2Client == nil { 30 | c.ec2Client = ec2.NewFromConfig(cfg, optFns...) 31 | } 32 | return c.ec2Client 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Paraglider 2 | 3 | ![Discord](https://img.shields.io/discord/1116864463832891502?logo=discord&logoColor=white&logoSize=20&label=Discord&labelColor=7289DA&color=17cf48&link=https%3A%2F%2Fdiscord.gg%2FKrZGbfZ7wm) 4 | 5 | Paraglider is a cross-cloud control plane for configuring networking. 6 | 7 | ![Paraglider Logo](logo.png) 8 | 9 | ## Current status 10 | 11 | Paraglider is in the prototype phase, and we're currently building it with a small cross-industry team. 12 | 13 | ## Contributing 14 | 15 | See the [contributing guide](https://paragliderproject.io/developers/contributing) for ways to contribute and instructions. 16 | 17 | ## Code of Conduct 18 | 19 | This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. 20 | For more information, see the [Contributor Covenant Code of Conduct 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). 21 | 22 | ## Technical Charter 23 | 24 | See the [technical charter](./technical-charter.pdf) for the governance structure of the project. 25 | -------------------------------------------------------------------------------- /docs/source/overview/concepts.rst: -------------------------------------------------------------------------------- 1 | .. _concepts: 2 | 3 | Concepts 4 | ========== 5 | 6 | Overview 7 | -------------------- 8 | 9 | Paraglider takes an "endpoint-centric" view of networking: all non-networking resources should simply define their high-level networking intents and the rest should be deployed automatically -- making the network *invisible*. 10 | 11 | Core Concepts 12 | 13 | * **Endpoint**: Any resource in a cloud network (eg, a VM) 14 | * **Permit List**: A list associated with an endpoint which defines the allowed traffic for that endpoint 15 | * **Tags**: Strings associated with an endpoint or group of endpoint which can be referred to in permit lists and commands 16 | * **Namespaces**: A Paraglider deployment controlled by a Paraglider controller separated (both in infrastructure and in control plane) from other namespaces under the same controller 17 | 18 | Use 19 | ---- 20 | 21 | To use Paraglider, a tenant would run the Paraglider Controller and use the Paraglider API to create cloud deployments. 22 | This task largely consists of creating endpoints and modifying their permit lists to enable connectivity between them. 23 | -------------------------------------------------------------------------------- /governance/role-changes.md: -------------------------------------------------------------------------------- 1 | # Role Changes 2 | 3 | ## Removal from a Project Role 4 | A person may voluntarily resign from a project role by making a public announcement to the TSC. 5 | A person in a project role who is disruptive, or has been inactive on that project for an extended period (e.g., six or more months), or is not abiding by the project charter or code of conduct may have his or her role status revoked by the TSC. 6 | Disputes are resolved by TSC voting (majority). 7 | 8 | # Role Changes Process 9 | 1. Open an issue in the repo describing the necessary change. 10 | 2. Create a pull request (PR) in the repo, making the necessary change to the CODEOWNERS or governance documentation file. This PR must be linked to the issue. 11 | 3. Add an item about the maintainer change to the agenda for the next Paraglider TSC meeting. 12 | 4. Discuss the change in the meeting. 13 | 5. If the TSC approves (by majority vote of all present TSC members or their proxies), merge the PR. If they do not approve, close the PR without merging or continue the discussion with the TSC as necessary. 14 | NO MAINTAINER CHANGES ARE VALID WITHOUT TSC APPROVAL. 15 | -------------------------------------------------------------------------------- /internal/cli/common/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/paraglider-project/paraglider/internal/version" 23 | "github.com/spf13/cobra" 24 | ) 25 | 26 | func NewVersionCommand() *cobra.Command { 27 | return &cobra.Command{ 28 | Use: "version", 29 | Short: "Display the version of the Paraglider CLI", 30 | Args: cobra.NoArgs, 31 | RunE: func(cmd *cobra.Command, args []string) error { 32 | fmt.Fprintln(cmd.OutOrStderr(), version.VersionString(version.NewVersionInfo())) 33 | return nil 34 | }, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /internal/cli/glide/server/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package server 18 | 19 | import ( 20 | "github.com/paraglider-project/paraglider/internal/cli/glide/server/get" 21 | "github.com/paraglider-project/paraglider/internal/cli/glide/server/set" 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | func NewCommand() *cobra.Command { 26 | cmd := &cobra.Command{ 27 | Use: "server", 28 | Short: "Configure server config", 29 | } 30 | 31 | getCmd, _ := get.NewCommand() 32 | cmd.AddCommand(getCmd) 33 | setCmd, _ := set.NewCommand() 34 | cmd.AddCommand(setCmd) 35 | 36 | return cmd 37 | } 38 | -------------------------------------------------------------------------------- /governance/maintainers.md: -------------------------------------------------------------------------------- 1 | # Defining Paraglider Project Maintainers 2 | 3 | ## Finding all the Paraglider projects 4 | You can see all of the repositories associated with Paraglider by navigating to the top-level Paraglider organization on GitHub. 5 | 6 | ## Who are the current maintainers? 7 | The maintainers for each Paraglider project are contained in the CODEOWNERS file in the respective repository (note that the CODEOWNERS file may refer to a github team name, which is public under the Paraglider GitHub organization). 8 | 9 | ## Removing a maintainer from a project 10 | There are many reasons why a maintainer may need to leave a project. In the case that one does, please follow the steps [here](role-changes.md). 11 | 12 | ## Adding a maintainer for a project 13 | All projects should ideally have multiple maintainers (as listed in the relevant CODEOWNERS file(s)). 14 | There currently are no upper limits set on the number of maintainers for a Paraglider project. 15 | A project will have as many maintainers as it sees are useful for the functioning of the project and its community. 16 | To add a maintainer to a Paraglider project, please follow the steps for role changes [here](role-changes.md). 17 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/go 3 | { 4 | "name": "Go", 5 | "image": "mcr.microsoft.com/devcontainers/go:1.23", 6 | "features": { 7 | "ghcr.io/guiyomh/features/golangci-lint:0": { 8 | "version": "latest" 9 | }, 10 | "ghcr.io/jungaretti/features/make:1": {}, 11 | "ghcr.io/dhoeric/features/google-cloud-cli:1": { 12 | "version": "latest" 13 | }, 14 | "azure-cli": "latest", 15 | "ghcr.io/devcontainers/features/aws-cli": "latest", 16 | "ghcr.io/devcontainers-extra/features/protoc:1": "latest", 17 | "ghcr.io/devcontainers-extra/features/tmux-apt-get:1": "latest", 18 | "ghcr.io/devcontainers/features/python:1": {"version": "3.11"} 19 | }, 20 | 21 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 22 | // "forwardPorts": [], 23 | 24 | "postCreateCommand": "./.devcontainer/postCreate.sh" 25 | 26 | // Configure tool-specific properties. 27 | // "customizations": {}, 28 | 29 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 30 | // "remoteUser": "root" 31 | } 32 | -------------------------------------------------------------------------------- /internal/cli/glide/resource/resource.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package resource 18 | 19 | import ( 20 | "github.com/paraglider-project/paraglider/internal/cli/glide/resource/attach" 21 | "github.com/paraglider-project/paraglider/internal/cli/glide/resource/create" 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | func NewCommand() *cobra.Command { 26 | cmd := &cobra.Command{ 27 | Use: "resource", 28 | Short: "Perform operations on resources", 29 | } 30 | 31 | createCmd, _ := create.NewCommand() 32 | cmd.AddCommand(createCmd) 33 | 34 | attachCmd, _ := attach.NewCommand() 35 | cmd.AddCommand(attachCmd) 36 | 37 | return cmd 38 | } 39 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Paraglider Project Code of Conduct 2 | The Paraglider Project encourages all contributors and users to be welcoming, inclusive, and supportive. We do not condone disrespectful or rude behavior of any sort. 3 | 4 | Please read the [LF Projects Code of Conduct](https://lfprojects.org/policies/code-of-conduct/) before participating in the Paraglider Project community. Everyone who participates in the Paraglider Project and its community spaces (GitHub, Discord, mailing list, in person, and otherwise) agrees to abide by this [Code of Conduct](https://lfprojects.org/policies/code-of-conduct/). 5 | 6 | To report incidents or to appeal reports of incidents, send email to the Manager of LF Projects, Mike Dolan (manager@lfprojects.org). Please include any available relevant information, including links to any publicly accessible material relating to the matter. Every effort will be taken to ensure a safe and collegial environment in which to collaborate on matters relating to the Paraglider Project. In order to protect the community, Paraglider reserves the right to take appropriate action, potentially including the removal of an individual from any and all participation in the project. Paraglider will work towards an equitable resolution in the event of a misunderstanding. 7 | -------------------------------------------------------------------------------- /.github/workflows/functional-tests-approval.yaml: -------------------------------------------------------------------------------- 1 | name: Functional Tests Approval 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release/* 8 | tags: 9 | - v* 10 | paths-ignore: 11 | - '.devcontainer/**' 12 | - '.githooks/**' 13 | - 'docs/**' 14 | - '**.md' 15 | - '**.rst' 16 | pull_request: 17 | branches: 18 | - main 19 | - features/* 20 | - release/* 21 | paths-ignore: 22 | - '.devcontainer/**' 23 | - '.githooks/**' 24 | - 'docs/**' 25 | - '**.md' 26 | - '**.rst' 27 | 28 | jobs: 29 | functional-tests-approval: 30 | name: Functional Tests Approval 31 | runs-on: ubuntu-latest 32 | environment: functional-tests 33 | steps: 34 | - name: Save commit SHA 35 | run: | 36 | mkdir -p ./commit_sha 37 | if [ "${{ github.event_name }}" == "pull_request" ]; then 38 | echo ${{ github.event.pull_request.head.sha }} > ./commit_sha/commit_sha 39 | elif [ "${{ github.event_name }}" == "push" ]; then 40 | echo $GITHUB_SHA > ./commit_sha/commit_sha 41 | fi 42 | - uses: actions/upload-artifact@v4 43 | with: 44 | name: commit_sha 45 | path: commit_sha/ 46 | -------------------------------------------------------------------------------- /internal/cli/glide/server/get/get_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package get 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/stretchr/testify/assert" 27 | ) 28 | 29 | func TestServerGetExecute(t *testing.T) { 30 | err := config.ReadOrCreateConfig() 31 | assert.Nil(t, err) 32 | 33 | cmd, executor := NewCommand() 34 | executor.cliSettings = config.CliSettings{ServerAddr: "serverAddr"} 35 | var b bytes.Buffer 36 | executor.writer = &b 37 | 38 | err = executor.Execute(cmd, []string{}) 39 | 40 | assert.Nil(t, err) 41 | assert.Contains(t, b.String(), "serverAddr") 42 | } 43 | -------------------------------------------------------------------------------- /internal/cli/glide/server/set/set_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package set 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestServerSetExecute(t *testing.T) { 29 | err := config.ReadOrCreateConfig() 30 | assert.Nil(t, err) 31 | 32 | newAddr := "serverAddrAfter" 33 | cmd, executor := NewCommand() 34 | executor.cliSettings = &config.CliSettings{ServerAddr: "serverAddrBefore"} 35 | 36 | err = executor.Execute(cmd, []string{newAddr}) 37 | 38 | assert.Nil(t, err) 39 | assert.Equal(t, newAddr, executor.cliSettings.ServerAddr) 40 | } 41 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/rule.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rule 18 | 19 | import ( 20 | "github.com/paraglider-project/paraglider/internal/cli/glide/rule/add" 21 | "github.com/paraglider-project/paraglider/internal/cli/glide/rule/delete" 22 | "github.com/paraglider-project/paraglider/internal/cli/glide/rule/get" 23 | 24 | "github.com/spf13/cobra" 25 | ) 26 | 27 | func NewCommand() *cobra.Command { 28 | cmd := &cobra.Command{ 29 | Use: "rule", 30 | Short: "Perform operations on rules", 31 | } 32 | 33 | addCmd, _ := add.NewCommand() 34 | cmd.AddCommand(addCmd) 35 | deleteCmd, _ := delete.NewCommand() 36 | cmd.AddCommand(deleteCmd) 37 | getCmd, _ := get.NewCommand() 38 | cmd.AddCommand(getCmd) 39 | 40 | return cmd 41 | } 42 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/namespace.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package namespace 18 | 19 | import ( 20 | "github.com/paraglider-project/paraglider/internal/cli/glide/namespace/get" 21 | "github.com/paraglider-project/paraglider/internal/cli/glide/namespace/list" 22 | "github.com/paraglider-project/paraglider/internal/cli/glide/namespace/set" 23 | 24 | "github.com/spf13/cobra" 25 | ) 26 | 27 | func NewCommand() *cobra.Command { 28 | cmd := &cobra.Command{ 29 | Use: "namespace", 30 | Short: "Perform operations on the namespace", 31 | } 32 | 33 | getCmd, _ := get.NewCommand() 34 | cmd.AddCommand(getCmd) 35 | setCmd, _ := set.NewCommand() 36 | cmd.AddCommand(setCmd) 37 | listCmd, _ := list.NewCommand() 38 | cmd.AddCommand(listCmd) 39 | 40 | return cmd 41 | } 42 | -------------------------------------------------------------------------------- /GOVERNANCE.md: -------------------------------------------------------------------------------- 1 | # Paraglider Project Governance 2 | This document contains governance documentation for the Paraglider Project. 3 | 4 | ## Top-Level Governance 5 | 6 | * [Project Charter](governance/technical-charter.pdf) 7 | * [Technical Steering Committee](governance/tsc.md) 8 | * [TSC Procedures](governance/tsc-procedures.md) 9 | 10 | An initial TSC has been established per above. TSC eligibility is defined per above and aligns with the Technical Charter. Maintainer is defined below. TSC Chair, TAC representative, and MAC liaison roles are assigned through nomination, then TSC voting. Additional roles, including Project Technical Leads (PTLs) may be defined as project needs arise. 11 | 12 | The TSC membership is [here](governance/tsc.md). The TSC represents the top-level decision-making body for the project. 13 | Additional project roles, as needed, are filled by TSC voting (majority). 14 | 15 | 16 | ## Code of Conduct 17 | [Paraglider Code of Conduct](CODE-OF-CONDUCT.md) 18 | 19 | ## Diversity & Inclusivity 20 | The community follows and abides by the Diversity & Inclusivity initiatives set forth by the Linux Foundation. 21 | 22 | ## Project Roles and Processes for Role Changes 23 | * [Maintainers](governance/maintainers.md) 24 | * [Other Project Roles](governance/roles.md) 25 | * [Change Process](governance/role-changes.md) 26 | 27 | ## Release Process 28 | [Release Process](governance/release-process.md) 29 | -------------------------------------------------------------------------------- /docs/source/project/feature-status.rst: -------------------------------------------------------------------------------- 1 | .. _feature-status: 2 | 3 | Feature Status 4 | -------------- 5 | 6 | .. role:: raw-html(raw) 7 | :format: html 8 | 9 | This pages lists important information about the status of the features in each plugin. 10 | 11 | Features with flags to enable/disable them are listed with :octicon:`gear;1em;sd-text-info`. 12 | 13 | .. list-table:: 14 | :widths: 10 15 20 20 25 20 15 | :header-rows: 1 16 | 17 | * - Cloud 18 | - VMs 19 | - Kubernetes Clusters :octicon:`gear;1em;sd-text-info` 20 | - Managed Services :octicon:`gear;1em;sd-text-info` 21 | - Multicloud Connections 22 | - Resource Attachment :octicon:`gear;1em;sd-text-info` 23 | 24 | * - Azure 25 | - :bdg-success:`Supported` 26 | - :bdg-info:`Initial` 27 | - :bdg-info:`Initial` 28 | - :bdg-success:`Supported` :raw-html:`
` with GCP 29 | - :bdg-info:`Initial` 30 | 31 | * - GCP 32 | - :bdg-success:`Supported` 33 | - :bdg-info:`Initial` 34 | - :bdg-info:`Initial` 35 | - :bdg-success:`Supported` :raw-html:`
` with Azure and IBM 36 | - :bdg-warning:`In Progress` 37 | 38 | * - IBM 39 | - :bdg-success:`Supported` 40 | - :bdg-success:`Supported` 41 | - :bdg-info:`Initial` 42 | - :bdg-success:`Supported` :raw-html:`
` with GCP 43 | - :bdg-danger:`Unsupported` 44 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: "Docs" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release/* 8 | tags: 9 | - v* 10 | paths: 11 | docs/** 12 | pull_request: 13 | branches: 14 | - main 15 | - features/* 16 | - release/* 17 | paths: 18 | - docs/** 19 | - .github/workflows/docs.yaml 20 | 21 | env: 22 | # Python 23 | PYTHONVER: '3.11' 24 | 25 | jobs: 26 | build: 27 | runs-on: ubuntu-latest 28 | permissions: 29 | contents: write 30 | pull-requests: write 31 | steps: 32 | - name: Check out repo 33 | uses: actions/checkout@v4 34 | - name: Set up Python ${{ env.PYTHONVER}} 35 | uses: actions/setup-python@v5 36 | with: 37 | python-version: ${{ env.PYTHONVER }} 38 | - name: Build docs 39 | working-directory: ./docs 40 | run: | 41 | pip install -r requirements.txt 42 | make html 43 | - name: Preview docs 44 | uses: rossjrw/pr-preview-action@v1 45 | if: github.event_name == 'pull_request' 46 | with: 47 | source-dir: ./docs/build/html 48 | - name: Deploy docs 49 | uses: JamesIves/github-pages-deploy-action@v4 50 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 51 | with: 52 | clean-exclude: pr-preview/ 53 | folder: docs/build/html 54 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/tag.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package tag 18 | 19 | import ( 20 | "github.com/paraglider-project/paraglider/internal/cli/glide/tag/delete" 21 | "github.com/paraglider-project/paraglider/internal/cli/glide/tag/get" 22 | "github.com/paraglider-project/paraglider/internal/cli/glide/tag/list" 23 | "github.com/paraglider-project/paraglider/internal/cli/glide/tag/set" 24 | "github.com/spf13/cobra" 25 | ) 26 | 27 | func NewCommand() *cobra.Command { 28 | cmd := &cobra.Command{ 29 | Use: "tag", 30 | Short: "Perform operations on tags", 31 | } 32 | 33 | deleteCmd, _ := delete.NewCommand() 34 | cmd.AddCommand(deleteCmd) 35 | getCmd, _ := get.NewCommand() 36 | cmd.AddCommand(getCmd) 37 | setCmd, _ := set.NewCommand() 38 | cmd.AddCommand(setCmd) 39 | listCmd, _ := list.NewCommand() 40 | cmd.AddCommand(listCmd) 41 | 42 | return cmd 43 | } 44 | -------------------------------------------------------------------------------- /internal/cli/glided/orchestrator/orchestrator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package orchestrator 18 | 19 | import ( 20 | "github.com/spf13/cobra" 21 | 22 | "github.com/paraglider-project/paraglider/pkg/orchestrator" 23 | ) 24 | 25 | func NewCommand() *cobra.Command { 26 | executor := &executor{} 27 | return &cobra.Command{ 28 | Use: "orch ", 29 | Aliases: []string{"orch"}, 30 | Short: "Starts the orch server with given config file", 31 | Args: cobra.ExactArgs(1), 32 | PreRunE: executor.Validate, 33 | RunE: executor.Execute, 34 | } 35 | } 36 | 37 | type executor struct { 38 | } 39 | 40 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 41 | return nil 42 | } 43 | 44 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 45 | orchestrator.SetupWithFile(args[0], true) 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | groups: 13 | gomod-all: 14 | patterns: 15 | - "*" 16 | update-types: 17 | - "minor" 18 | - "patch" 19 | - package-ecosystem: "devcontainers" 20 | directory: "/" 21 | schedule: 22 | interval: "monthly" 23 | groups: 24 | devcontainers-all: 25 | patterns: 26 | - "*" 27 | update-types: 28 | - "minor" 29 | - "patch" 30 | - package-ecosystem: "pip" 31 | directory: "/" 32 | schedule: 33 | interval: "monthly" 34 | groups: 35 | pip-all: 36 | patterns: 37 | - "*" 38 | update-types: 39 | - "minor" 40 | - "patch" 41 | - package-ecosystem: "github-actions" 42 | directory: "/" 43 | schedule: 44 | interval: "monthly" 45 | groups: 46 | github-actions-all: 47 | patterns: 48 | - "*" 49 | update-types: 50 | - "minor" 51 | - "patch" 52 | -------------------------------------------------------------------------------- /pkg/kvstore/storepb/storepb.proto: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | syntax = "proto3"; 18 | package tagservicepb; 19 | 20 | option go_package="github.com/paraglider-project/paraglider/pkg/kvstore/storepb"; 21 | 22 | service KVStore { 23 | rpc Set(SetRequest) returns (SetResponse) {} 24 | rpc Get(GetRequest) returns (GetResponse) {} 25 | rpc Delete(DeleteRequest) returns (DeleteResponse) {} 26 | } 27 | 28 | message SetRequest { 29 | string key = 1; 30 | string value = 2; 31 | string cloud = 3; 32 | string namespace = 4; 33 | } 34 | 35 | message SetResponse { 36 | } 37 | 38 | message GetRequest { 39 | string key = 1; 40 | string cloud = 2; 41 | string namespace = 3; 42 | } 43 | 44 | message GetResponse { 45 | string value = 1; 46 | } 47 | 48 | message DeleteRequest { 49 | string key = 1; 50 | string cloud = 2; 51 | string namespace = 3; 52 | } 53 | 54 | message DeleteResponse { 55 | } 56 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/get/get_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package get 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestNamespaceGetExecute(t *testing.T) { 31 | server := &fake.FakeOrchestratorRESTServer{} 32 | serverAddr := server.SetupFakeOrchestratorRESTServer() 33 | 34 | err := config.ReadOrCreateConfig() 35 | assert.Nil(t, err) 36 | 37 | cmd, executor := NewCommand() 38 | var output bytes.Buffer 39 | executor.writer = &output 40 | executor.cliSettings = config.CliSettings{ActiveNamespace: "default", ServerAddr: serverAddr} 41 | 42 | err = executor.Execute(cmd, []string{}) 43 | 44 | assert.Nil(t, err) 45 | assert.Contains(t, output.String(), executor.cliSettings.ActiveNamespace) 46 | } 47 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/list/list_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package list 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestNamespaceListExecute(t *testing.T) { 31 | server := &fake.FakeOrchestratorRESTServer{} 32 | serverAddr := server.SetupFakeOrchestratorRESTServer() 33 | 34 | err := config.ReadOrCreateConfig() 35 | assert.Nil(t, err) 36 | 37 | cmd, executor := NewCommand() 38 | var output bytes.Buffer 39 | executor.writer = &output 40 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr} 41 | 42 | err = executor.Execute(cmd, []string{}) 43 | 44 | assert.Nil(t, err) 45 | for namespace := range fake.GetFakeNamespaces() { 46 | assert.Contains(t, output.String(), namespace) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/get/get_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package get 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestRuleGetExecute(t *testing.T) { 31 | server := &fake.FakeOrchestratorRESTServer{} 32 | serverAddr := server.SetupFakeOrchestratorRESTServer() 33 | 34 | err := config.ReadOrCreateConfig() 35 | assert.Nil(t, err) 36 | 37 | cmd, executor := NewCommand() 38 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr, ActiveNamespace: fake.Namespace} 39 | var output bytes.Buffer 40 | executor.writer = &output 41 | 42 | args := []string{fake.CloudName, "uri"} 43 | err = executor.Execute(cmd, args) 44 | 45 | assert.Nil(t, err) 46 | assert.Contains(t, output.String(), fake.GetFakePermitListRules()[0].Name) 47 | } 48 | -------------------------------------------------------------------------------- /internal/cli/glide/resource/attach/attach_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package attach 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestResourceAttachExecute(t *testing.T) { 31 | server := &fake.FakeOrchestratorRESTServer{} 32 | serverAddr := server.SetupFakeOrchestratorRESTServer() 33 | 34 | err := config.ReadOrCreateConfig() 35 | assert.Nil(t, err) 36 | 37 | cmd, executor := NewCommand() 38 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr, ActiveNamespace: fake.Namespace} 39 | 40 | var output bytes.Buffer 41 | executor.writer = &output 42 | 43 | args := []string{fake.CloudName, "resourceID"} 44 | err = executor.Execute(cmd, args) 45 | 46 | assert.Nil(t, err) 47 | assert.Contains(t, output.String(), "resourceID") 48 | } 49 | -------------------------------------------------------------------------------- /internal/cli/glided/az/az.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package az 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/spf13/cobra" 24 | 25 | az "github.com/paraglider-project/paraglider/pkg/azure" 26 | ) 27 | 28 | func NewCommand() *cobra.Command { 29 | executor := &executor{} 30 | return &cobra.Command{ 31 | Use: "az ", 32 | Aliases: []string{"az"}, 33 | Short: "Starts the Azure plugin server on given port", 34 | Args: cobra.ExactArgs(2), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | } 39 | 40 | type executor struct { 41 | port int 42 | } 43 | 44 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 45 | var err error 46 | e.port, err = strconv.Atoi(args[0]) 47 | if err != nil { 48 | return fmt.Errorf("invalid port") 49 | } 50 | return nil 51 | } 52 | 53 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 54 | az.Setup(e.port, args[1]) 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /pkg/azure/priority_utils_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package azure 20 | 21 | import ( 22 | "testing" 23 | 24 | armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestGetNextAvailabilityPriority(t *testing.T) { 29 | var reservedPriorities = make(map[int32]*armnetwork.SecurityRule) 30 | var start int32 = minPriority 31 | var end int32 = maxPriority 32 | var lowestPriority bool = true 33 | var priority int32 34 | 35 | t.Run("TestGetNextLowestAvailabilityPriority", func(t *testing.T) { 36 | priority = getNextAvailablePriority(reservedPriorities, start, end, lowestPriority) 37 | assert.Equal(t, int32(minPriority), priority) 38 | }) 39 | 40 | t.Run("TestGetNextHighestAvailabilityPriority", func(t *testing.T) { 41 | priority = getNextAvailablePriority(reservedPriorities, start, end, !lowestPriority) 42 | assert.Equal(t, int32(maxPriority), priority) 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /internal/cli/glided/ibm/ibm.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ibm 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/spf13/cobra" 24 | 25 | ibm "github.com/paraglider-project/paraglider/pkg/ibm" 26 | ) 27 | 28 | func NewCommand() *cobra.Command { 29 | executor := &executor{} 30 | return &cobra.Command{ 31 | Use: "ibm ", 32 | Aliases: []string{"ibm"}, 33 | Short: "Starts the IBM plugin server on given port", 34 | Args: cobra.ExactArgs(2), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | } 39 | 40 | type executor struct { 41 | port int 42 | } 43 | 44 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 45 | var err error 46 | e.port, err = strconv.Atoi(args[0]) 47 | if err != nil { 48 | return fmt.Errorf("invalid port") 49 | } 50 | return nil 51 | } 52 | 53 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 54 | ibm.Setup(e.port, args[1]) 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /internal/cli/invd/ibm/ibm.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ibm 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/spf13/cobra" 24 | 25 | ibm "github.com/paraglider-project/paraglider/pkg/ibm" 26 | ) 27 | 28 | func NewCommand() *cobra.Command { 29 | executor := &executor{} 30 | return &cobra.Command{ 31 | Use: "ibm ", 32 | Aliases: []string{"ibm"}, 33 | Short: "Starts the IBM plugin server on given port", 34 | Args: cobra.ExactArgs(2), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | } 39 | 40 | type executor struct { 41 | port int 42 | } 43 | 44 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 45 | var err error 46 | e.port, err = strconv.Atoi(args[0]) 47 | if err != nil { 48 | return fmt.Errorf("invalid port") 49 | } 50 | return nil 51 | } 52 | 53 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 54 | ibm.Setup(e.port, args[1]) 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /internal/cli/glided/gcp/gcp.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package gcp 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/spf13/cobra" 24 | 25 | gcp "github.com/paraglider-project/paraglider/pkg/gcp" 26 | ) 27 | 28 | func NewCommand() *cobra.Command { 29 | executor := &executor{} 30 | return &cobra.Command{ 31 | Use: "gcp ", 32 | Aliases: []string{"gcp"}, 33 | Short: "Starts the GCP plugin server with given config file", 34 | Args: cobra.ExactArgs(2), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | } 39 | 40 | type executor struct { 41 | port int 42 | } 43 | 44 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 45 | var err error 46 | e.port, err = strconv.Atoi(args[0]) 47 | if err != nil { 48 | return fmt.Errorf("invalid port") 49 | } 50 | return nil 51 | } 52 | 53 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 54 | gcp.Setup(e.port, args[1]) 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/list/list_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package list 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestTagListExecute(t *testing.T) { 31 | server := &fake.FakeOrchestratorRESTServer{} 32 | serverAddr := server.SetupFakeOrchestratorRESTServer() 33 | 34 | err := config.ReadOrCreateConfig() 35 | assert.Nil(t, err) 36 | 37 | cmd, executor := NewCommand() 38 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr} 39 | var output bytes.Buffer 40 | executor.writer = &output 41 | 42 | // list the tags 43 | err = executor.Execute(cmd, nil) 44 | 45 | assert.Nil(t, err) 46 | assert.Contains(t, output.String(), fake.ListFakeTagMapping()[0].Name) 47 | assert.Contains(t, output.String(), fake.ListFakeTagMapping()[1].Name) 48 | assert.Contains(t, output.String(), fake.ListFakeTagMapping()[2].Name) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/ibm/README.md: -------------------------------------------------------------------------------- 1 | # IBM Plugin 2 | 3 | ### Authentication 4 | 5 | To use IBM services set the environment variable `PARAGLIDER_IBM_API_KEY` with your API key. 6 | Create a new API key via the [web console](https://cloud.ibm.com/iam/apikeys), or by executing the following command: 7 | 8 | ``` 9 | ibmcloud iam api-key-create pgkey 10 | ``` 11 | 12 | ### Instance Keys 13 | Upon invoking `CreateResource`, local SSH keys will be created automatically in `~/.ibm/keys` and be registered on the IBM VPC platform in the specified region. The keys will be associated with the newly launched instance. 14 | New invocations of `CreateResource` will reuse the created keys and register the public key only if a key matching its value doesn't already exist in the region. 15 | 16 | ### Quotas 17 | To maximize flexibility in the deployment's scale we recommend increasing the quota of the following resources by opening a ticket with cloud support: 18 | - VPCs. 19 | - Global Transit Gateway connections by disabling (setting to 0) all non VPC connections. 20 | A user may further increase the number of connections by reducing the number of Global Transit Gateways per region. 21 | e.g., currently reducing the quota for TGW per region from 5 to 3 will raise max connections quota from 25 to 43. 22 | 23 | ### Testing 24 | Tests require setting environment variable `PARAGLIDER_IBM_RESOURCE_GROUP_ID`. 25 | The testing suit associates deployed resources with the specified resource ID. 26 | Users may choose a resource group from [IBM's web console](https://cloud.ibm.com/account/resource-groups). 27 | *Note* - all paraglider resources are automatically scheduled for removal post testing, unless `INVISINETS_TEST_PERSIST` is set to 1. 28 | -------------------------------------------------------------------------------- /internal/cli/glide/server/get/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package get 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | "github.com/spf13/cobra" 25 | 26 | common "github.com/paraglider-project/paraglider/internal/cli/common" 27 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 28 | ) 29 | 30 | func NewCommand() (*cobra.Command, *executor) { 31 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 32 | cmd := &cobra.Command{ 33 | Use: "get", 34 | Short: "Get current server config", 35 | Args: cobra.ExactArgs(0), 36 | PreRunE: executor.Validate, 37 | RunE: executor.Execute, 38 | } 39 | return cmd, executor 40 | } 41 | 42 | type executor struct { 43 | common.CommandExecutor 44 | writer io.Writer 45 | cliSettings config.CliSettings 46 | } 47 | 48 | func (e *executor) SetOutput(w io.Writer) { 49 | e.writer = w 50 | } 51 | 52 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 53 | return nil 54 | } 55 | 56 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 57 | fmt.Fprintln(e.writer, "Server address: ", e.cliSettings.ServerAddr) 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/get/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package get 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/spf13/cobra" 27 | ) 28 | 29 | func NewCommand() (*cobra.Command, *executor) { 30 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 31 | cmd := &cobra.Command{ 32 | Use: "get", 33 | Short: "Get active namespace", 34 | Args: cobra.ExactArgs(0), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | return cmd, executor 39 | } 40 | 41 | type executor struct { 42 | common.CommandExecutor 43 | writer io.Writer 44 | cliSettings config.CliSettings 45 | } 46 | 47 | func (e *executor) SetOutput(w io.Writer) { 48 | e.writer = w 49 | } 50 | 51 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 52 | return nil 53 | } 54 | 55 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 56 | fmt.Fprintf(e.writer, "Active namespace: %s\n", e.cliSettings.ActiveNamespace) 57 | 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/list/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package list 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/spf13/cobra" 28 | ) 29 | 30 | func NewCommand() (*cobra.Command, *executor) { 31 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 32 | cmd := &cobra.Command{ 33 | Use: "list", 34 | Short: "List tags with their mappings", 35 | Args: cobra.NoArgs, 36 | RunE: executor.Execute, 37 | } 38 | return cmd, executor 39 | } 40 | 41 | type executor struct { 42 | common.CommandExecutor 43 | writer io.Writer 44 | cliSettings config.CliSettings 45 | } 46 | 47 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 48 | 49 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 50 | tagMappings, err := c.ListTags() 51 | if err != nil { 52 | return err 53 | } 54 | // Print the tags 55 | for i, tagMap := range tagMappings { 56 | fmt.Fprintf(e.writer, "%d). %v\n", i, tagMap) 57 | } 58 | return nil 59 | } 60 | -------------------------------------------------------------------------------- /internal/cli/glided/tagserv/tagserv.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package tagserv 18 | 19 | import ( 20 | "strconv" 21 | 22 | "github.com/spf13/cobra" 23 | 24 | tagservice "github.com/paraglider-project/paraglider/pkg/tag_service" 25 | ) 26 | 27 | func NewCommand() *cobra.Command { 28 | executor := &executor{} 29 | return &cobra.Command{ 30 | Use: "tagserv ", 31 | Aliases: []string{"tagserv"}, 32 | Short: "Starts the tag server on given ports", 33 | Args: cobra.ExactArgs(3), 34 | PreRunE: executor.Validate, 35 | RunE: executor.Execute, 36 | } 37 | } 38 | 39 | type executor struct { 40 | dbPort int 41 | serverPort int 42 | clearKeys bool 43 | } 44 | 45 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 46 | var err error 47 | e.dbPort, err = strconv.Atoi(args[0]) 48 | if err != nil { 49 | return err 50 | } 51 | e.serverPort, err = strconv.Atoi(args[1]) 52 | if err != nil { 53 | return err 54 | } 55 | e.clearKeys, err = strconv.ParseBool(args[2]) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 64 | tagservice.Setup(e.dbPort, e.serverPort, e.clearKeys) 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /internal/cli/glided/kvserv/kvserv.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kvserv 18 | 19 | import ( 20 | "strconv" 21 | 22 | "github.com/spf13/cobra" 23 | 24 | tagservice "github.com/paraglider-project/paraglider/pkg/tag_service" 25 | ) 26 | 27 | func NewCommand() *cobra.Command { 28 | executor := &executor{} 29 | return &cobra.Command{ 30 | Use: "kvserv ", 31 | Aliases: []string{"kvserv"}, 32 | Short: "Starts the key-value store server on given ports", 33 | Args: cobra.ExactArgs(3), 34 | PreRunE: executor.Validate, 35 | RunE: executor.Execute, 36 | } 37 | } 38 | 39 | type executor struct { 40 | dbPort int 41 | serverPort int 42 | clearKeys bool 43 | } 44 | 45 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 46 | var err error 47 | e.dbPort, err = strconv.Atoi(args[0]) 48 | if err != nil { 49 | return err 50 | } 51 | e.serverPort, err = strconv.Atoi(args[1]) 52 | if err != nil { 53 | return err 54 | } 55 | e.clearKeys, err = strconv.ParseBool(args[2]) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 64 | tagservice.Setup(e.dbPort, e.serverPort, e.clearKeys) 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /internal/cli/glide/server/set/set.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package set 18 | 19 | import ( 20 | "io" 21 | "os" 22 | 23 | common "github.com/paraglider-project/paraglider/internal/cli/common" 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | func NewCommand() (*cobra.Command, *executor) { 29 | executor := &executor{writer: os.Stdout, cliSettings: &config.ActiveConfig.Settings} 30 | cmd := &cobra.Command{ 31 | Use: "set ", 32 | Short: "Set the server config", 33 | Args: cobra.ExactArgs(1), 34 | PreRunE: executor.Validate, 35 | RunE: executor.Execute, 36 | } 37 | return cmd, executor 38 | } 39 | 40 | type executor struct { 41 | common.CommandExecutor 42 | writer io.Writer 43 | cliSettings *config.CliSettings 44 | } 45 | 46 | func (e *executor) SetOutput(w io.Writer) { 47 | e.writer = w 48 | } 49 | 50 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 51 | // TODO @smcclure20: Validate it is a valid address to some extent 52 | return nil 53 | } 54 | 55 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 56 | e.cliSettings.ServerAddr = args[0] 57 | err := config.SaveActiveConfig() 58 | if err != nil { 59 | return err 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /.github/scripts/transform_test_results.py: -------------------------------------------------------------------------------- 1 | # parse an xml file and transform it into a junit xml file 2 | # that can be used by the github actions junit reporter 3 | # Path: .github/scripts/transform-test-results.py 4 | 5 | import re 6 | import sys 7 | import xml.etree.ElementTree 8 | 9 | def main(): 10 | if len(sys.argv) != 4: 11 | print("Usage: transform-test-results.py ") 12 | sys.exit(1) 13 | 14 | repository_root = sys.argv[1] 15 | input_file = sys.argv[2] 16 | output_file = sys.argv[3] 17 | 18 | print(f"Processing {input_file}") 19 | pattern = re.compile(r"\tError Trace:\t(.*):(\d+)") 20 | et = xml.etree.ElementTree.parse(input_file) 21 | for testcase in et.findall('./testsuite/testcase'): 22 | failure = testcase.find('./failure') 23 | if failure is None: 24 | continue 25 | 26 | # Extract file name by matching regex pattern in the text 27 | # it will look like \tError Trace:\tfilename:line 28 | match = pattern.search(failure.text) 29 | if match is None: 30 | continue 31 | 32 | file = match.group(1) 33 | line = match.group(2) 34 | 35 | # The filename will contain the fully-qualified path, and we need to turn that into 36 | # a relative path from the repository root 37 | if not file.startswith(repository_root): 38 | print(f"Could not find repository name in file path: {file}") 39 | continue 40 | 41 | file = file[len(repository_root) + 1:] 42 | 43 | testcase.attrib["file"] = file 44 | testcase.attrib["line"] = line 45 | failure.attrib["file"] = file 46 | failure.attrib["line"] = line 47 | 48 | 49 | # Write back to file 50 | print(f"Writing {output_file}") 51 | et.write(output_file) 52 | 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /pkg/orchestrator/config/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | type CloudDeployment struct { 20 | Name string `yaml:"name"` 21 | Deployment string `yaml:"deployment"` 22 | } 23 | 24 | type CloudPlugin struct { 25 | Name string `yaml:"name"` 26 | Host string `yaml:"host"` 27 | Port string `yaml:"port"` 28 | } 29 | 30 | type Server struct { 31 | Port string `yaml:"port"` 32 | Host string `yaml:"host"` 33 | RpcPort string `yaml:"rpcPort"` 34 | } 35 | 36 | type TagService struct { 37 | Port string `yaml:"port"` 38 | Host string `yaml:"host"` 39 | } 40 | 41 | type Config struct { 42 | Server Server `yaml:"server"` 43 | TagService TagService `yaml:"tagService"` 44 | 45 | KVStore struct { 46 | Port string `yaml:"port"` 47 | Host string `yaml:"host"` 48 | } `yaml:"kvStore"` 49 | 50 | Namespaces map[string][]CloudDeployment `yaml:"namespaces"` 51 | AddressSpace []string `yaml:"addressSpace"` 52 | CloudPlugins []CloudPlugin `yaml:"cloudPlugins"` 53 | FeatureFlags map[string]FeatureFlags `yaml:"featureFlags"` 54 | } 55 | 56 | type FeatureFlags struct { 57 | AttachResourceEnabled bool `yaml:"attachResourceEnabled"` 58 | KubernetesClustersEnabled bool `yaml:"kubernetesClustersEnabled"` 59 | PrivateEndpointsEnabled bool `yaml:"privateEndpointsEnabled"` 60 | } 61 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/list/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package list 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/spf13/cobra" 28 | ) 29 | 30 | func NewCommand() (*cobra.Command, *executor) { 31 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 32 | cmd := &cobra.Command{ 33 | Use: "list", 34 | Short: "List all configured namespaces", 35 | Args: cobra.ExactArgs(0), 36 | PreRunE: executor.Validate, 37 | RunE: executor.Execute, 38 | } 39 | return cmd, executor 40 | } 41 | 42 | type executor struct { 43 | common.CommandExecutor 44 | writer io.Writer 45 | cliSettings config.CliSettings 46 | } 47 | 48 | func (e *executor) SetOutput(w io.Writer) { 49 | e.writer = w 50 | } 51 | 52 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 53 | return nil 54 | } 55 | 56 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 57 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 58 | namespaces, err := c.ListNamespaces() 59 | 60 | if err != nil { 61 | return err 62 | } 63 | 64 | fmt.Fprintf(e.writer, "Namespaces: %v", namespaces) 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/delete/delete_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package delete 20 | 21 | import ( 22 | "strings" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/require" 29 | ) 30 | 31 | func TestRuleDeleteValidate(t *testing.T) { 32 | err := config.ReadOrCreateConfig() 33 | assert.Nil(t, err) 34 | 35 | cmd, executor := NewCommand() 36 | 37 | args := []string{fake.CloudName, "uri"} 38 | rules := "name1,names2" 39 | err = cmd.Flags().Set("rules", rules) 40 | require.Nil(t, err) 41 | err = executor.Validate(cmd, args) 42 | 43 | assert.Nil(t, err) 44 | assert.Equal(t, executor.ruleNames, strings.Split(rules, ",")) 45 | } 46 | 47 | func TestRuleDeleteExecute(t *testing.T) { 48 | server := &fake.FakeOrchestratorRESTServer{} 49 | serverAddr := server.SetupFakeOrchestratorRESTServer() 50 | 51 | err := config.ReadOrCreateConfig() 52 | assert.Nil(t, err) 53 | 54 | cmd, executor := NewCommand() 55 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr, ActiveNamespace: fake.Namespace} 56 | executor.ruleNames = []string{"name1", "name2"} 57 | 58 | args := []string{fake.CloudName, "uri"} 59 | err = executor.Execute(cmd, args) 60 | 61 | assert.Nil(t, err) 62 | } 63 | -------------------------------------------------------------------------------- /internal/cli/glide/resource/create/create_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package create 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestResourceCreateValidate(t *testing.T) { 31 | err := config.ReadOrCreateConfig() 32 | assert.Nil(t, err) 33 | 34 | cmd, executor := NewCommand() 35 | 36 | args := []string{fake.CloudName, "uri", "not-a-file.json"} 37 | err = executor.Validate(cmd, args) 38 | 39 | assert.NotNil(t, err) 40 | 41 | // TODO @smcclure20: add more test cases 42 | } 43 | 44 | func TestResourceCreateExecute(t *testing.T) { 45 | server := &fake.FakeOrchestratorRESTServer{} 46 | serverAddr := server.SetupFakeOrchestratorRESTServer() 47 | 48 | err := config.ReadOrCreateConfig() 49 | assert.Nil(t, err) 50 | 51 | cmd, executor := NewCommand() 52 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr, ActiveNamespace: fake.Namespace} 53 | 54 | var output bytes.Buffer 55 | executor.writer = &output 56 | executor.description = []byte(`descriptionstring`) 57 | 58 | args := []string{fake.CloudName, "resourceName"} 59 | err = executor.Execute(cmd, args) 60 | 61 | assert.Nil(t, err) 62 | assert.Contains(t, output.String(), "resourceName") 63 | } 64 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/delete/delete_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package delete 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/require" 28 | ) 29 | 30 | func TestTagDeleteValidate(t *testing.T) { 31 | err := config.ReadOrCreateConfig() 32 | assert.Nil(t, err) 33 | 34 | cmd, executor := NewCommand() 35 | 36 | args := []string{"tag"} 37 | member := "child1" 38 | 39 | err = cmd.Flags().Set("member", member) 40 | require.Nil(t, err) 41 | 42 | err = executor.Validate(cmd, args) 43 | 44 | assert.Nil(t, err) 45 | assert.Equal(t, member, executor.member) 46 | } 47 | 48 | func TestTagDeleteExecute(t *testing.T) { 49 | server := &fake.FakeOrchestratorRESTServer{} 50 | serverAddr := server.SetupFakeOrchestratorRESTServer() 51 | 52 | err := config.ReadOrCreateConfig() 53 | assert.Nil(t, err) 54 | 55 | cmd, executor := NewCommand() 56 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr} 57 | 58 | // Delete entire tag 59 | args := []string{"tag"} 60 | err = executor.Execute(cmd, args) 61 | 62 | assert.Nil(t, err) 63 | 64 | // Delete members of tag 65 | executor.member = "child" 66 | err = executor.Execute(cmd, args) 67 | 68 | assert.Nil(t, err) 69 | } 70 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/set/set_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package set 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 26 | "github.com/stretchr/testify/assert" 27 | ) 28 | 29 | func TestNamespaceSetValidate(t *testing.T) { 30 | server := &fake.FakeOrchestratorRESTServer{} 31 | serverAddr := server.SetupFakeOrchestratorRESTServer() 32 | 33 | err := config.ReadOrCreateConfig() 34 | assert.Nil(t, err) 35 | 36 | cmd, executor := NewCommand() 37 | executor.cliSettings = &config.CliSettings{ServerAddr: serverAddr, ActiveNamespace: fake.Namespace} 38 | 39 | // Valid option 40 | for namespace := range fake.GetFakeNamespaces() { 41 | err = executor.Validate(cmd, []string{namespace}) 42 | assert.Nil(t, err) 43 | } 44 | 45 | // Invalid option 46 | err = executor.Validate(cmd, []string{"invalid-namespace"}) 47 | assert.NotNil(t, err) 48 | } 49 | 50 | func TestNamespaceSetExecute(t *testing.T) { 51 | err := config.ReadOrCreateConfig() 52 | assert.Nil(t, err) 53 | 54 | cmd, executor := NewCommand() 55 | executor.cliSettings = &config.CliSettings{ActiveNamespace: "default"} 56 | 57 | err = executor.Execute(cmd, []string{"new-namespace"}) 58 | 59 | assert.Nil(t, err) 60 | assert.Equal(t, "new-namespace", executor.cliSettings.ActiveNamespace) 61 | } 62 | -------------------------------------------------------------------------------- /internal/cli/glided/root.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | 23 | common "github.com/paraglider-project/paraglider/internal/cli/common" 24 | "github.com/paraglider-project/paraglider/internal/cli/glided/az" 25 | "github.com/paraglider-project/paraglider/internal/cli/glided/gcp" 26 | "github.com/paraglider-project/paraglider/internal/cli/glided/ibm" 27 | "github.com/paraglider-project/paraglider/internal/cli/glided/kvserv" 28 | "github.com/paraglider-project/paraglider/internal/cli/glided/orchestrator" 29 | "github.com/paraglider-project/paraglider/internal/cli/glided/startup" 30 | "github.com/paraglider-project/paraglider/internal/cli/glided/tagserv" 31 | "github.com/spf13/cobra" 32 | ) 33 | 34 | var rootCmd = &cobra.Command{ 35 | Use: "glided", 36 | Short: "Paraglider Server CLI", 37 | Long: `Paraglider Server CLI`, 38 | } 39 | 40 | func init() { 41 | rootCmd.AddCommand(az.NewCommand()) 42 | rootCmd.AddCommand(gcp.NewCommand()) 43 | rootCmd.AddCommand(ibm.NewCommand()) 44 | rootCmd.AddCommand(orchestrator.NewCommand()) 45 | rootCmd.AddCommand(tagserv.NewCommand()) 46 | rootCmd.AddCommand(kvserv.NewCommand()) 47 | rootCmd.AddCommand(startup.NewCommand()) 48 | rootCmd.AddCommand(common.NewVersionCommand()) 49 | } 50 | 51 | func Execute() { 52 | err := rootCmd.Execute() 53 | if err != nil { 54 | fmt.Fprintf(os.Stderr, "There was an error while executing your command: \n\n%s\n", err) 55 | os.Exit(1) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /pkg/aws/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | /* 4 | Copyright 2024 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package aws 20 | 21 | import ( 22 | "context" 23 | "testing" 24 | 25 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rpc" 26 | "github.com/paraglider-project/paraglider/pkg/paragliderpb" 27 | "github.com/paraglider-project/paraglider/pkg/utils" 28 | "github.com/stretchr/testify/require" 29 | ) 30 | 31 | func TestIntegration(t *testing.T) { 32 | accountId := GetAwsAccountId() 33 | namespace := SetupAwsTesting("test-integration") 34 | region := "us-east-2" 35 | defer TeardownAwsTesting(namespace, region) 36 | 37 | _, fakeOrchestratorServerAddr, err := fake.SetupFakeOrchestratorRPCServer(utils.AZURE) 38 | if err != nil { 39 | t.Fatal(err) 40 | } 41 | awsServer := &AwsPluginServer{orchestratorServerAddr: fakeOrchestratorServerAddr} 42 | instanceName := "paraglider-test-vm" 43 | instanceAvailabilityZone := "us-east-2a" 44 | testInstanceJson, err := getTestInstanceInputJson(instanceAvailabilityZone) 45 | if err != nil { 46 | t.Fatal(err) 47 | } 48 | req := ¶gliderpb.CreateResourceRequest{ 49 | Deployment: ¶gliderpb.ParagliderDeployment{ 50 | Id: accountId, 51 | Namespace: namespace, 52 | }, 53 | Name: instanceName, 54 | Description: testInstanceJson, 55 | } 56 | resp, err := awsServer.CreateResource(context.TODO(), req) 57 | require.NoError(t, err) 58 | require.NotNil(t, resp) 59 | require.Equal(t, instanceName, resp.Name) 60 | } 61 | -------------------------------------------------------------------------------- /governance/tsc-procedures.md: -------------------------------------------------------------------------------- 1 | # Technical Steering Committee (TSC) Procedures 2 | ## TSC Membership 3 | Membership changes to the Paraglider TSC is governed by the current list of TSC members with voting rights. 4 | TSC membership changes require a majority vote by the current TSC members in order to pass. 5 | For more details on TSC voting procedures please refer to the Paraglider Technical Charter "TSC Voting" section. 6 | 7 | ## Adding TSC Members 8 | In order to have a vote on adding a new member to the Paraglider TSC, a Github issue should be opened against the repository and tagged with the “governance” label. 9 | The title of the issue should be "TSC New Member - \" with a description on why this person should be added to the TSC. 10 | The opened github issue should then be referenced in the next TSC meeting which will determine a date to conduct a vote on the new membership. 11 | If a vote does not occur within a 1-month period from opening the issue the motion will be considered denied, and the issue will be closed. 12 | 13 | ## Removal of TSC Members 14 | To request removal of a TSC member open a github issue with the “governance” label and with the title TSC "Membership Removal - \". 15 | 16 | Existing TSC members can request their own removal from the Paraglider TSC at anytime and the issue will be taken up in the next weekly TSC meeting. The person will then be removed as a TSC member. 17 | If there is a proposed replacement for the member leaving, they should be mentioned in the removal issue. The proposed replacement member should open a new github issue and follow the Adding TSC Members section. 18 | 19 | Removal of a TSC member can be requested by other TSC members or from the community with a description on why they should be removed listed in the issue. 20 | Examples of reasons for removal could be lack of activity of that TSC member for a prolonged period of time. 21 | Requests for removal will be discussed in the next weekly TSC meeting and a date will be determined for a vote on the membership removal. 22 | 23 | Please DO NOT report Code of Conduct issues in the Github issue and instead follow the reporting procedures defined in the Paraglider Project Code of Conduct. 24 | 25 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/get/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package get 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/spf13/cobra" 28 | ) 29 | 30 | func NewCommand() (*cobra.Command, *executor) { 31 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 32 | cmd := &cobra.Command{ 33 | Use: "get ", 34 | Short: "Get rules of a resource permit list", 35 | Args: cobra.ExactArgs(2), 36 | PreRunE: executor.Validate, 37 | RunE: executor.Execute, 38 | } 39 | return cmd, executor 40 | } 41 | 42 | type executor struct { 43 | common.CommandExecutor 44 | writer io.Writer 45 | cliSettings config.CliSettings 46 | } 47 | 48 | func (e *executor) SetOutput(w io.Writer) { 49 | e.writer = w 50 | } 51 | 52 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 53 | return nil 54 | } 55 | 56 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 57 | // Get the rules from the server 58 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 59 | permitList, err := c.GetPermitList(e.cliSettings.ActiveNamespace, args[0], args[1]) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | // Print the rules 65 | fmt.Fprintf(e.writer, "Permit list for %s:\n", args[1]) 66 | for i, rule := range permitList { 67 | fmt.Fprintf(e.writer, "%d. %v\n", i, rule) 68 | } 69 | 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/delete/delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package delete 18 | 19 | import ( 20 | "io" 21 | "os" 22 | 23 | common "github.com/paraglider-project/paraglider/internal/cli/common" 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | "github.com/paraglider-project/paraglider/pkg/client" 26 | "github.com/spf13/cobra" 27 | ) 28 | 29 | func NewCommand() (*cobra.Command, *executor) { 30 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 31 | cmd := &cobra.Command{ 32 | Use: "delete [-member ]", 33 | Short: "Delete a tag", 34 | Args: cobra.ExactArgs(1), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | cmd.Flags().String("member", "", "The member to delete") 39 | return cmd, executor 40 | } 41 | 42 | type executor struct { 43 | common.CommandExecutor 44 | cliSettings config.CliSettings 45 | writer io.Writer 46 | member string 47 | } 48 | 49 | func (e *executor) SetOutput(w io.Writer) { 50 | e.writer = w 51 | } 52 | 53 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 54 | var err error 55 | e.member, err = cmd.Flags().GetString("member") 56 | if err != nil { 57 | return err 58 | } 59 | return nil 60 | } 61 | 62 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 63 | // Delete the tag from the server 64 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 65 | if e.member == "" { 66 | err := c.DeleteTag(args[0]) 67 | return err 68 | } else { 69 | err := c.DeleteTagMembers(args[0], e.member) 70 | return err 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/delete/delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package delete 18 | 19 | import ( 20 | "io" 21 | "os" 22 | 23 | common "github.com/paraglider-project/paraglider/internal/cli/common" 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | "github.com/paraglider-project/paraglider/pkg/client" 26 | "github.com/spf13/cobra" 27 | ) 28 | 29 | func NewCommand() (*cobra.Command, *executor) { 30 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 31 | cmd := &cobra.Command{ 32 | Use: "delete --rules ", 33 | Short: "Delete a rule from a resource permit list", 34 | Args: cobra.ExactArgs(2), 35 | PreRunE: executor.Validate, 36 | RunE: executor.Execute, 37 | } 38 | cmd.Flags().StringSlice("rules", []string{}, "The names of the rules to delete") 39 | return cmd, executor 40 | } 41 | 42 | type executor struct { 43 | common.CommandExecutor 44 | writer io.Writer 45 | cliSettings config.CliSettings 46 | ruleNames []string 47 | } 48 | 49 | func (e *executor) SetOutput(w io.Writer) { 50 | e.writer = w 51 | } 52 | 53 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 54 | var err error 55 | e.ruleNames, err = cmd.Flags().GetStringSlice("rules") 56 | if err != nil { 57 | return err 58 | } 59 | return nil 60 | } 61 | 62 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 63 | // Send the rules to the server 64 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 65 | err := c.DeletePermitListRules(e.cliSettings.ActiveNamespace, args[0], args[1], e.ruleNames) 66 | return err 67 | } 68 | -------------------------------------------------------------------------------- /internal/cli/glide/namespace/set/set.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package set 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/spf13/cobra" 28 | ) 29 | 30 | func NewCommand() (*cobra.Command, *executor) { 31 | executor := &executor{writer: os.Stdout, cliSettings: &config.ActiveConfig.Settings} 32 | cmd := &cobra.Command{ 33 | Use: "set", 34 | Short: "Set active namespace", 35 | Args: cobra.ExactArgs(1), 36 | PreRunE: executor.Validate, 37 | RunE: executor.Execute, 38 | } 39 | return cmd, executor 40 | } 41 | 42 | type executor struct { 43 | common.CommandExecutor 44 | writer io.Writer 45 | cliSettings *config.CliSettings 46 | } 47 | 48 | func (e *executor) SetOutput(w io.Writer) { 49 | e.writer = w 50 | } 51 | 52 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 53 | // Get all namespaces from the orchestrator and confirm that the given string is one of them 54 | c := &client.Client{ControllerAddress: e.cliSettings.ServerAddr} 55 | namespaces, err := c.ListNamespaces() 56 | 57 | if err != nil { 58 | return err 59 | } 60 | 61 | for namespace := range namespaces { 62 | if namespace == args[0] { 63 | return nil 64 | } 65 | } 66 | return fmt.Errorf("namespace %s does not exist", args[0]) 67 | } 68 | 69 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 70 | e.cliSettings.ActiveNamespace = args[0] 71 | err := config.SaveActiveConfig() 72 | if err != nil { 73 | return err 74 | } 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /docs/source/overview/howitworks.rst: -------------------------------------------------------------------------------- 1 | .. _howitworks: 2 | 3 | How It Works 4 | ===================== 5 | 6 | The Paraglider Controller uses public cloud APIs to deploy networking resources (eg, VPCs, subnets, security rules, VPN gateways) as necessary to match the high-level intents specified via the Paraglider API. 7 | 8 | Controller Design 9 | ^^^^^^^^^^^^^^^^^ 10 | 11 | .. mermaid:: 12 | 13 | graph TB 14 | UR[/User Request/] --> CC[Central Controller] 15 | 16 | subgraph " " 17 | CC[Orchestrator] 18 | CC --> AP[Azure Plugin] 19 | CC --> GP[GCP Plugin] 20 | CC --> IP[IBM Plugin] 21 | end 22 | 23 | subgraph " " 24 | CC --> TS[Tag Service] 25 | TS[Tag Service] --> DS1[(Tag Store)] 26 | end 27 | 28 | subgraph " " 29 | CC --> KV[KV Store Service] 30 | KV[KV Store Service] --> DS2[(KV Store)] 31 | end 32 | 33 | AP --> AC[Azure Cloud] 34 | GP --> GC[GCP Cloud] 35 | IP --> IC[IBM Cloud] 36 | 37 | **Overview** 38 | 39 | The Paraglider Controller consists of several microservices: a Central Controller, a Tag Service, a general-purpose KV store, and potentially multiple Cloud Plugins. Each service is described below. 40 | 41 | **Central Controller** 42 | 43 | The Central Controller accepts user requests and sends requests to the other microservices to complete these tasks. It is the central point of coordination for multi-service tasks. 44 | 45 | **Tag Service** 46 | 47 | The Tag Service is a light-weight service on top of a key-value store which stores data about the mappings between tags and the resources that reference them ("subscribers"). Subscribers must be tracked in order to push updates to permit lists when tag membership changes. 48 | 49 | **KV Store Service** 50 | 51 | The KV Store Service is a general-purpose key-value store that stores data for the plugins as needed. 52 | For example, to meet the Paraglider interface, a plugin may need to map between rule names and rule metadata that it cannot store in the cloud's rules themselves. 53 | The KV store can be used to close such gaps. 54 | 55 | **Cloud Plugins** 56 | 57 | Cloud Plugins implement the Paraglider Cloud Plugin Interface for their respective cloud. For more about the Paraglider Cloud Plugin Interface, see :ref:`plugin_interface`. 58 | -------------------------------------------------------------------------------- /pkg/fake/kvstore/fake_kvstore.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kvstore 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/paraglider-project/paraglider/pkg/kvstore/storepb" 26 | "google.golang.org/grpc" 27 | ) 28 | 29 | const ( 30 | ValidKey = "validKey" 31 | ValidValue = "value" 32 | ) 33 | 34 | type FakeKVStoreServer struct { 35 | storepb.UnimplementedKVStoreServer 36 | } 37 | 38 | func (s *FakeKVStoreServer) Get(c context.Context, req *storepb.GetRequest) (*storepb.GetResponse, error) { 39 | if req.Key == ValidKey { 40 | return &storepb.GetResponse{Value: ValidValue}, nil 41 | } 42 | return nil, fmt.Errorf("Get: Invalid key") 43 | } 44 | 45 | func (s *FakeKVStoreServer) Set(c context.Context, req *storepb.SetRequest) (*storepb.SetResponse, error) { 46 | if req.Key == ValidKey { 47 | return &storepb.SetResponse{}, nil 48 | } 49 | return nil, fmt.Errorf("Set: Invalid key") 50 | } 51 | 52 | func (s *FakeKVStoreServer) Delete(c context.Context, req *storepb.DeleteRequest) (*storepb.DeleteResponse, error) { 53 | if req.Key == ValidKey { 54 | return &storepb.DeleteResponse{}, nil 55 | } 56 | return nil, fmt.Errorf("Delete: Invalid key") 57 | } 58 | 59 | func NewFakeKVStoreServer() *FakeKVStoreServer { 60 | s := &FakeKVStoreServer{} 61 | return s 62 | } 63 | 64 | func SetupFakeTagServer(port int) { 65 | lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 66 | if err != nil { 67 | log.Fatalf("failed to listen: %v", err) 68 | } 69 | grpcServer := grpc.NewServer() 70 | storepb.RegisterKVStoreServer(grpcServer, NewFakeKVStoreServer()) 71 | go func() { 72 | if err := grpcServer.Serve(lis); err != nil { 73 | fmt.Println(err.Error()) 74 | } 75 | }() 76 | } 77 | -------------------------------------------------------------------------------- /pkg/orchestrator/orchestrator_utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package orchestrator 18 | 19 | import ( 20 | "github.com/seancfoley/ipaddress-go/ipaddr" 21 | 22 | paragliderpb "github.com/paraglider-project/paraglider/pkg/paragliderpb" 23 | ) 24 | 25 | // Private ASN ranges (RFC 6996) 26 | const ( 27 | MIN_PRIVATE_ASN_2BYTE uint32 = 64512 28 | MAX_PRIVATE_ASN_2BYTE uint32 = 65534 29 | MIN_PRIVATE_ASN_4BYTE uint32 = 4200000000 30 | MAX_PRIVATE_ASN_4BYTE uint32 = 4294967294 31 | ) 32 | 33 | func allocBlock(addressSpace *ipaddr.IPAddress, blockSize int64) *ipaddr.IPAddress { 34 | var allocator ipaddr.PrefixBlockAllocator[*ipaddr.IPAddress] 35 | allocator.AddAvailable(addressSpace) 36 | return allocator.AllocateSize(uint64(blockSize)) 37 | } 38 | 39 | func removeBlock(addressSpaces []*ipaddr.IPAddress, block *ipaddr.IPAddress) []*ipaddr.IPAddress { 40 | var blockList []*ipaddr.IPAddress 41 | for _, availSpace := range addressSpaces { 42 | result := availSpace.Subtract(block) 43 | for _, addr := range result { 44 | blockList = append(blockList, addr.SpanWithPrefixBlocks()...) 45 | } 46 | } 47 | return blockList 48 | } 49 | 50 | func findUnusedBlocks(addressSpace []string, usedAddressSpaces []*paragliderpb.AddressSpaceMapping) []*ipaddr.IPAddress { 51 | availBlocks := make([]*ipaddr.IPAddress, 0) 52 | for _, availSpace := range addressSpace { 53 | availBlocks = append(availBlocks, ipaddr.NewIPAddressString(availSpace).GetAddress()) 54 | } 55 | for _, usedAddress := range usedAddressSpaces { 56 | for _, block := range usedAddress.AddressSpaces { 57 | usedBlock := ipaddr.NewIPAddressString(block).GetAddress() 58 | availBlocks = removeBlock(availBlocks, usedBlock) 59 | } 60 | } 61 | 62 | return availBlocks 63 | } 64 | -------------------------------------------------------------------------------- /internal/cli/glide/config/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package config 18 | 19 | import ( 20 | "encoding/json" 21 | "os" 22 | "path/filepath" 23 | ) 24 | 25 | const ( 26 | DefaultConfigLocation = "/.paraglider/settings.json" 27 | DefaultServerAddr = "http://localhost:8080" 28 | DefaultNamespace = "default" 29 | ) 30 | 31 | var ( 32 | ActiveConfig *CliConfig 33 | ) 34 | 35 | type CliConfig struct { 36 | Settings CliSettings 37 | Path string 38 | } 39 | 40 | type CliSettings struct { 41 | ServerAddr string `json:"serverAddr"` 42 | ActiveNamespace string `json:"activeNamespace"` 43 | } 44 | 45 | func ReadOrCreateConfig() error { 46 | homeDir, err := os.UserHomeDir() 47 | if err != nil { 48 | return err 49 | } 50 | path := filepath.Join(homeDir, DefaultConfigLocation) 51 | newConfig := &CliConfig{Path: path} 52 | 53 | _, err = os.Stat(newConfig.Path) 54 | if os.IsNotExist(err) { 55 | parentDir := filepath.Dir(newConfig.Path) 56 | _, err := os.Stat(parentDir) 57 | if os.IsNotExist(err) { 58 | err := os.MkdirAll(parentDir, 0755) 59 | if err != nil { 60 | return err 61 | } 62 | } 63 | newConfig.Settings = CliSettings{ServerAddr: DefaultServerAddr, ActiveNamespace: DefaultNamespace} 64 | } else { 65 | data, err := os.ReadFile(newConfig.Path) 66 | if err != nil { 67 | return err 68 | } 69 | 70 | err = json.Unmarshal(data, &newConfig.Settings) 71 | if err != nil { 72 | return err 73 | } 74 | } 75 | 76 | ActiveConfig = newConfig 77 | return nil 78 | } 79 | 80 | func SaveActiveConfig() error { 81 | data, err := json.Marshal(&ActiveConfig.Settings) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | err = os.WriteFile(ActiveConfig.Path, data, 0644) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /internal/cli/glide/root.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cli 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "os" 23 | "os/signal" 24 | "syscall" 25 | 26 | common "github.com/paraglider-project/paraglider/internal/cli/common" 27 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 28 | "github.com/paraglider-project/paraglider/internal/cli/glide/namespace" 29 | "github.com/paraglider-project/paraglider/internal/cli/glide/resource" 30 | "github.com/paraglider-project/paraglider/internal/cli/glide/rule" 31 | "github.com/paraglider-project/paraglider/internal/cli/glide/server" 32 | "github.com/paraglider-project/paraglider/internal/cli/glide/tag" 33 | "github.com/spf13/cobra" 34 | ) 35 | 36 | var rootCmd = &cobra.Command{ 37 | Use: "glide", 38 | Short: "Paraglider CLI", 39 | Long: `Paraglider CLI`, 40 | } 41 | 42 | func init() { 43 | // Get current CLI configuration 44 | err := config.ReadOrCreateConfig() 45 | if err != nil { 46 | fmt.Fprintf(os.Stderr, "Error reading configuration: %s\n", err) 47 | os.Exit(1) 48 | } 49 | 50 | rootCmd.AddCommand(resource.NewCommand()) 51 | rootCmd.AddCommand(rule.NewCommand()) 52 | rootCmd.AddCommand(tag.NewCommand()) 53 | rootCmd.AddCommand(common.NewVersionCommand()) 54 | rootCmd.AddCommand(server.NewCommand()) 55 | rootCmd.AddCommand(namespace.NewCommand()) 56 | } 57 | 58 | func Execute() { 59 | // Cancel gracefully on SIGINT and SIGTERM. 60 | ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) 61 | defer cancel() 62 | 63 | err := rootCmd.ExecuteContext(ctx) 64 | if err != nil && err == ctx.Err() { 65 | fmt.Fprintln(os.Stderr, "Cancelled.") 66 | os.Exit(1) 67 | } else if err != nil { 68 | fmt.Fprintf(os.Stderr, "Whoops. There was an error while executing your command: \n\n%s\n", err) 69 | os.Exit(1) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Images and Binaries 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v**' 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | packages: write 14 | steps: 15 | - name: checkout 16 | uses: actions/checkout@v4 17 | - name: Set up Go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version-file: ./go.mod 21 | - name: Get protoc 22 | uses: arduino/setup-protoc@v3 23 | with: 24 | repo-token: ${{ secrets.GITHUB_TOKEN }} 25 | - name: Get protoc-gen-go 26 | run: | 27 | GOOS=$(go env GOHOSTOS) GOARCH=$(go env GOHOSTARCH) go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 28 | GOOS=$(go env GOHOSTOS) GOARCH=$(go env GOHOSTARCH) go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 29 | - name: Login to GitHub Container Registry 30 | uses: docker/login-action@v3 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.actor }} 34 | password: ${{ secrets.GITHUB_TOKEN }} 35 | - name: Build binaries for amd64 36 | run: GOARCH=amd64 make build 37 | - name: Build binaries for arm64 38 | run: GOARCH=arm64 make build 39 | - name: Tag and push Paraglider image with tag 'latest' and ${{ github.ref_name }} 40 | run: | 41 | docker buildx create --use --driver docker-container 42 | PLATFORMS=linux/amd64,linux/arm64 make push-image 43 | PLATFORMS=linux/amd64,linux/arm64 make push-image IMAGE_VERSION=${{ github.ref_name }} 44 | - name: Build and compress binaries 45 | run: | 46 | for pair in "linux:amd64" "linux:arm64" "darwin:amd64" "darwin:arm64" "windows:amd64" "windows:arm64"; do 47 | IFS=':' read -r os arch <<< "$pair" 48 | GOOS="$os" GOARCH="$arch" make build 49 | echo tar -czvf "paraglider-$os-$arch.tar.gz" --transform "s|dist/${os}_${arch}/release|paraglider/|" ./dist/"${os}_${arch}"/release 50 | tar -czvf "paraglider-$os-$arch.tar.gz" --transform "s|dist/${os}_${arch}/release|paraglider/|" ./dist/"${os}_${arch}"/release 51 | done 52 | - name: Upload binaries to release 53 | uses: svenstaro/upload-release-action@v2 54 | with: 55 | repo_token: ${{ secrets.GITHUB_TOKEN }} 56 | file: ./paraglider* 57 | tag: ${{ github.ref }} 58 | overwrite: true 59 | file_glob: true 60 | -------------------------------------------------------------------------------- /pkg/utils/utils_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package utils 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/stretchr/testify/require" 25 | ) 26 | 27 | // TODO @praveingk: Expand tests of SDK functions 28 | 29 | // Testing a function that returns true if cidr1 is a subset of cidr2, 30 | // i.e. all ips in cidr1 exist within cidr2 31 | func TestCIDRSubset(t *testing.T) { 32 | cidr1 := "10.10.10.8/29" // 10.10.10.8 - 10.10.10.151 33 | cidr2 := "10.10.10.0/24" // 10.10.10.0 - 10.10.10.255 34 | cidr3 := "192.50.64.0/17" // 192.50.0.0 - 192.50.127.255 35 | res1, err := IsCIDRSubset(cidr1, cidr2) 36 | require.NoError(t, err) 37 | res2, err := IsCIDRSubset(cidr2, cidr1) 38 | require.NoError(t, err) 39 | res3, err := IsCIDRSubset(cidr1, cidr1) 40 | require.NoError(t, err) 41 | res4, err := IsCIDRSubset(cidr3, cidr1) 42 | require.NoError(t, err) 43 | require.True(t, res1) 44 | require.False(t, res2) 45 | require.True(t, res3) 46 | require.False(t, res4) 47 | } 48 | 49 | // Testing a function that returns true if cidr1 and cidr2 overlap, 50 | // i.e. the CIDRs share at least one ip 51 | func TestCIDROverlap(t *testing.T) { 52 | cidr1 := "10.10.10.8/29" // 10.10.10.8 - 10.10.10.151 53 | cidr2 := "10.10.10.0/24" // 10.10.10.0 - 10.10.10.255 54 | cidr3 := "192.50.64.0/17" // 192.50.0.0 - 192.50.127.255 55 | res1, err := DoCIDROverlap(cidr1, cidr2) 56 | require.NoError(t, err) 57 | res2, err := DoCIDROverlap(cidr2, cidr1) 58 | require.NoError(t, err) 59 | res3, err := DoCIDROverlap(cidr1, cidr1) 60 | require.NoError(t, err) 61 | res4, err := DoCIDROverlap(cidr1, cidr3) 62 | require.NoError(t, err) 63 | res5, err := DoCIDROverlap(cidr2, cidr3) 64 | require.NoError(t, err) 65 | require.True(t, res1) 66 | require.True(t, res2) 67 | require.True(t, res3) 68 | require.False(t, res4) 69 | require.False(t, res5) 70 | } 71 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/get/get_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package get 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/require" 29 | ) 30 | 31 | func TestTagGetValidate(t *testing.T) { 32 | err := config.ReadOrCreateConfig() 33 | assert.Nil(t, err) 34 | 35 | cmd, executor := NewCommand() 36 | 37 | args := []string{"tag"} 38 | 39 | err = cmd.Flags().Set("resolve", "true") 40 | 41 | require.Nil(t, err) 42 | 43 | err = executor.Validate(cmd, args) 44 | 45 | assert.Nil(t, err) 46 | assert.True(t, executor.resolveFlag) 47 | } 48 | 49 | func TestTagGetExecute(t *testing.T) { 50 | server := &fake.FakeOrchestratorRESTServer{} 51 | serverAddr := server.SetupFakeOrchestratorRESTServer() 52 | 53 | err := config.ReadOrCreateConfig() 54 | assert.Nil(t, err) 55 | 56 | cmd, executor := NewCommand() 57 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr} 58 | var output bytes.Buffer 59 | executor.writer = &output 60 | executor.resolveFlag = false 61 | 62 | // Get the tag 63 | tagName := "tag1" 64 | args := []string{tagName} 65 | err = executor.Execute(cmd, args) 66 | 67 | assert.Nil(t, err) 68 | assert.Contains(t, output.String(), tagName) 69 | assert.Contains(t, output.String(), fake.GetFakeTagMapping(tagName).Name) 70 | assert.Contains(t, output.String(), fake.GetFakeTagMapping(tagName).ChildTags[0]) 71 | 72 | // Resolve the tag 73 | executor.resolveFlag = true 74 | err = executor.Execute(cmd, args) 75 | 76 | assert.Nil(t, err) 77 | assert.Contains(t, output.String(), tagName) 78 | assert.Contains(t, output.String(), fake.GetFakeTagMappingLeafTags(tagName)[0].Name) 79 | } 80 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package version 18 | 19 | import ( 20 | "fmt" 21 | ) 22 | 23 | // Values for these are injected by the build. 24 | var ( 25 | channel = "latest" 26 | release = "latest" 27 | version = "latest" 28 | commit = "unknown" 29 | ) 30 | 31 | // VersionInfo is used for a serializable representation of our versioning info. 32 | type VersionInfo struct { 33 | Channel string `json:"channel"` 34 | Commit string `json:"commit"` 35 | Release string `json:"release"` 36 | Version string `json:"version"` 37 | } 38 | 39 | // NewVersionInfo returns a new VersionInfo struct. 40 | func NewVersionInfo() VersionInfo { 41 | return VersionInfo{ 42 | Channel: Channel(), 43 | Commit: Commit(), 44 | Release: Release(), 45 | Version: Version(), 46 | } 47 | } 48 | 49 | // Channel returns the designated channel for assets. 50 | // 51 | // For a real release this will be the major.minor - for any other build it's the same 52 | // as Release(). 53 | func Channel() string { 54 | return channel 55 | } 56 | 57 | // Commit returns the full git SHA of the build. 58 | // 59 | // This should only be used for informational purposes. 60 | func Commit() string { 61 | return commit 62 | } 63 | 64 | // Release returns the semver release version of the build. 65 | // 66 | // This should only be used for informational purposes. 67 | func Release() string { 68 | return release 69 | } 70 | 71 | // Version returns the 'git describe' output of the build. 72 | // 73 | // This should only be used for informational purposes. 74 | func Version() string { 75 | return version 76 | } 77 | 78 | // VersionString returns a formatted string representation of the version from a list of supported 79 | func VersionString(v VersionInfo) string { 80 | format := "Release: %s \nVersion: %s\n\nCommit: %s\n" 81 | return fmt.Sprintf(format, v.Release, v.Version, v.Commit) 82 | 83 | } 84 | -------------------------------------------------------------------------------- /docs/source/examples/tags.rst: -------------------------------------------------------------------------------- 1 | .. _tagexample: 2 | 3 | Tag Example 4 | =========== 5 | 6 | Goals 7 | ------ 8 | * Create a tag for an IP address 9 | * Add a parent tag for the IP tag 10 | * Reference the parent tag in a resource's permit list 11 | * Add a new tag to the parent tag 12 | * See that the resource's permit list has been updated accordingly 13 | 14 | Installation 15 | ------------ 16 | 17 | .. code-block:: console 18 | 19 | $ git clone https://github.com/paraglider-project/paraglider 20 | $ cd paraglider 21 | $ make build install 22 | 23 | Controller Setup 24 | ---------------- 25 | 26 | .. code-block:: console 27 | 28 | $ glided startup 29 | 30 | You can find example configuration files in the ``tools/examples/controller-configs`` directory. 31 | 32 | .. note:: 33 | 34 | This example will create a VM in GCP. You can create the VM in whichever cloud you prefer. Make sure that your chosen cloud provider is configured in the controller configuration file. 35 | 36 | Steps 37 | ------ 38 | 39 | 1. Create a tag for an IP address with name `iptag` 40 | 41 | .. code-block:: console 42 | 43 | $ glide tag set iptag --ip 1.1.1.1 44 | 45 | 2. Assign `iptag` to a parent tag named `parenttag` 46 | 47 | .. code-block:: console 48 | 49 | $ glide tag set parenttag --children iptag 50 | 51 | 52 | 3. Resolve the parent tag down to list of names 53 | 54 | .. code-block:: console 55 | 56 | $ glide tag get parenttag --resolve 57 | 58 | 4. Create a resource name `vm1` 59 | 60 | .. code-block:: console 61 | 62 | $ glide resource create gcp vm1 63 | 64 | .. note:: 65 | 66 | You can find example configuration files in the ``tools/examples/vm-configs`` directory. 67 | 68 | 4. Add a rule referencing the parent tag to a resource 69 | 70 | .. code-block:: console 71 | 72 | $ glide rule add gcp vm1 --ping parenttag 73 | 74 | 5. Create a tag, `iptag2` 75 | 76 | .. code-block:: console 77 | 78 | $ glide tag set iptag2 --ip 2.2.2.2 79 | 80 | 6. Add `iptag2` to `parenttag` 81 | 82 | .. code-block:: console 83 | 84 | $ glide tag set parenttag --children iptag2 85 | 86 | 7. Get the permit list of the resource we added to 87 | 88 | .. code-block:: console 89 | 90 | $ glide rule get gcp vm1 91 | 92 | 8. Resolve the parent tag 93 | 94 | .. code-block:: console 95 | 96 | $ glide tag get parenttag --resolve 97 | -------------------------------------------------------------------------------- /internal/cli/glide/resource/attach/attach.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package attach 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/paraglider-project/paraglider/pkg/orchestrator" 28 | "github.com/spf13/cobra" 29 | ) 30 | 31 | func NewCommand() (*cobra.Command, *executor) { 32 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 33 | cmd := &cobra.Command{ 34 | Use: "attach ", 35 | Short: "Attach a resource to active namespace", 36 | Args: cobra.ExactArgs(2), 37 | PreRunE: executor.Validate, 38 | RunE: executor.Execute, 39 | } 40 | return cmd, executor 41 | } 42 | 43 | type executor struct { 44 | common.CommandExecutor 45 | writer io.Writer 46 | cliSettings config.CliSettings 47 | } 48 | 49 | func (e *executor) SetOutput(w io.Writer) { 50 | e.writer = w 51 | } 52 | 53 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 54 | return nil 55 | } 56 | 57 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 58 | fmt.Fprintf(e.writer, "Attaching resource to %s namespace\n", e.cliSettings.ActiveNamespace) 59 | paragliderClient := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 60 | 61 | resource := &orchestrator.ResourceID{Id: args[1]} 62 | resourceInfo, err := paragliderClient.AttachResource(e.cliSettings.ActiveNamespace, args[0], resource) 63 | if err != nil { 64 | fmt.Fprintf(e.writer, "Failed to attach resource: %v\n", err) 65 | return err 66 | } 67 | 68 | fmt.Fprintf(e.writer, "Resource Attached.\ntag: %s\nuri: %s\nip: %s\n", resourceInfo["name"], resourceInfo["uri"], resourceInfo["ip"]) 69 | 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/get/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package get 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/spf13/cobra" 28 | ) 29 | 30 | func NewCommand() (*cobra.Command, *executor) { 31 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 32 | cmd := &cobra.Command{ 33 | Use: "get [--resolve]", 34 | Short: "Get a tag", 35 | Args: cobra.ExactArgs(1), 36 | PreRunE: executor.Validate, 37 | RunE: executor.Execute, 38 | } 39 | cmd.Flags().Bool("resolve", false, "Resolve the tag to a list of IP addresses") 40 | return cmd, executor 41 | } 42 | 43 | type executor struct { 44 | common.CommandExecutor 45 | writer io.Writer 46 | cliSettings config.CliSettings 47 | resolveFlag bool 48 | } 49 | 50 | func (e *executor) SetOutput(w io.Writer) { 51 | e.writer = w 52 | } 53 | 54 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 55 | var err error 56 | e.resolveFlag, err = cmd.Flags().GetBool("resolve") 57 | if err != nil { 58 | return err 59 | } 60 | return nil 61 | } 62 | 63 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 64 | // Get the tag from the server 65 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 66 | 67 | if e.resolveFlag { 68 | tagMappings, err := c.ResolveTag(args[0]) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | // Print the tag 74 | fmt.Fprintf(e.writer, "Tag %s:\n %v\n", args[0], tagMappings) 75 | } else { 76 | tagMapping, err := c.GetTag(args[0]) 77 | if err != nil { 78 | return err 79 | } 80 | 81 | // Print the tag 82 | fmt.Fprintln(e.writer, tagMapping) 83 | } 84 | 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /governance/release-process.md: -------------------------------------------------------------------------------- 1 | # Release Management 2 | 3 | [Release manager(s)](roles.md) of stable releases are 4 | responsible for approving and merging backports, tagging stable releases, and 5 | sending announcements about them. 6 | 7 | # Release Process 8 | This section describes the release processes for tracking, preparing, and 9 | creating new Paraglider releases. This includes information around the release cycles 10 | and guides for developers responsible for preparing upcoming stable releases. 11 | 12 | ## Active Development 13 | 14 | Active development is happening on the `main` branch and the target is to 15 | release a new version approximately every 6 months. 16 | 17 | ## Release Tracking 18 | 19 | Feature work for upcoming releases is tracked through 20 | [GitHub Issues](https://github.com/paraglider-project/paraglider/issues). 21 | 22 | ## Steps to Create a New Release (TODO: Review this more closely) 23 | 1. Bump the version number according to [Semantic Versioning 2.0](https://semver.org/) 24 | for the following files: 25 | * [version.mk](../build/version.mk) 26 | 2. Create a new pull request for the version number changes. 27 | 3. Ensure that the artifacts are built and all checks pass. 28 | 4. Merge the PR upon successful review. 29 | 5. Clone the repo, and add a tag to the commit with the version number changes (e.g., "git tag v1.0.0", "git push --tags"). 30 | 6. This will initiate a release. 31 | 7. Navigate to "Releases" to view the release. 32 | 8. Edit the "Release title" and click on "Generate release notes" button to pull in all the PR changes since the last tagged release 33 | 9. All binaries/artefacts should already be attached to the release. 34 | 10. Click the "Publish release" button to post the release 35 | 36 | ## Stable Releases 37 | 38 | Stable releases of Paraglider include: 39 | 40 | * Stable releases begin at version 1.0.0. 41 | * Maintenance window (any version released in the last 12 months). 42 | * Stability fixes backported from the `main` branch (anything that can result in a crash). 43 | * Bug fixes deemed worthwhile by the maintainers. 44 | 45 | ## Backports 46 | 47 | The process of backporting can consist of the following steps: 48 | 49 | - Changes nominated by the change author and/or members of the Paraglider community are evaluated for backporting on a case-by-case basis 50 | - These changes require approval from both the release manager of the stable release and from the relevant code owners. 51 | - Once approved, these fixes can be backported from the `main` branch to an existing or previous stable branch by the branch's release manager. 52 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/add/add_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package add 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 25 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/require" 28 | ) 29 | 30 | func TestRuleAddValidate(t *testing.T) { 31 | err := config.ReadOrCreateConfig() 32 | assert.Nil(t, err) 33 | 34 | cmd, executor := NewCommand() 35 | 36 | // Resource name 37 | args := []string{fake.CloudName, "resourceName"} 38 | ruleFile := "not-a-file.json" 39 | tag := "tag" 40 | err = cmd.Flags().Set("rulefile", ruleFile) 41 | require.Nil(t, err) 42 | err = cmd.Flags().Set("ping", tag) 43 | require.Nil(t, err) 44 | err = cmd.Flags().Set("ssh", tag) 45 | require.Nil(t, err) 46 | err = executor.Validate(cmd, args) 47 | 48 | assert.Nil(t, err) 49 | assert.Equal(t, executor.ruleFile, ruleFile) 50 | assert.Equal(t, executor.pingTag, tag) 51 | assert.Equal(t, executor.sshTag, tag) 52 | 53 | // Tag 54 | args = []string{tag} 55 | err = executor.Validate(cmd, args) 56 | 57 | assert.Nil(t, err) 58 | assert.Equal(t, executor.ruleFile, ruleFile) 59 | assert.Equal(t, executor.pingTag, tag) 60 | assert.Equal(t, executor.sshTag, tag) 61 | } 62 | 63 | func TestRuleAddExecute(t *testing.T) { 64 | server := &fake.FakeOrchestratorRESTServer{} 65 | serverAddr := server.SetupFakeOrchestratorRESTServer() 66 | 67 | err := config.ReadOrCreateConfig() 68 | assert.Nil(t, err) 69 | 70 | cmd, executor := NewCommand() 71 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr, ActiveNamespace: fake.Namespace} 72 | executor.pingTag = "pingTag" 73 | executor.sshTag = "sshTag" 74 | 75 | // Resource name 76 | args := []string{fake.CloudName, "uri"} 77 | err = executor.Execute(cmd, args) 78 | 79 | assert.Nil(t, err) 80 | 81 | // Tag 82 | args = []string{"tag"} 83 | err = executor.Execute(cmd, args) 84 | 85 | assert.Nil(t, err) 86 | } 87 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | 9 | project = 'Paraglider' 10 | copyright = 'Paraglider a Series of LF Projects, LLC. For web site terms of use, trademark policy and other project policies please see https://lfprojects.org/.' 11 | author = 'Paraglider Authors' 12 | 13 | # -- General configuration --------------------------------------------------- 14 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 15 | 16 | extensions = [ 17 | 'sphinxcontrib.mermaid', 18 | 'sphinx_copybutton', 19 | 'sphinx_design', 20 | ] 21 | 22 | templates_path = ['_templates'] 23 | exclude_patterns = [] 24 | 25 | copybutton_prompt_text = "$ " 26 | 27 | # -- Options for HTML output ------------------------------------------------- 28 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 29 | 30 | html_theme = 'furo' 31 | html_static_path = ['_static'] 32 | html_show_sphinx = False 33 | html_favicon = '_static/logo-square.png' 34 | html_theme_options = { 35 | "sidebar_hide_name": True, 36 | "light_logo": "paraglider-color-lightmode.png", 37 | "dark_logo": "paraglider-color-darkmode.png", 38 | "footer_icons": [ 39 | { 40 | "name": "GitHub", 41 | "url": "https://github.com/paraglider-project/paraglider", 42 | "html": """ 43 | 44 | 45 | 46 | """, 47 | "class": "", 48 | }, 49 | ], 50 | "source_repository": "https://github.com/paraglider-project/paraglider/", 51 | "source_branch": "main", 52 | "source_directory": "docs/source", 53 | } 54 | -------------------------------------------------------------------------------- /pkg/azure/naming_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | package azure 19 | 20 | import ( 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | "github.com/stretchr/testify/require" 25 | ) 26 | 27 | func TestGetVnetFromSubnetId(t *testing.T) { 28 | subnetId := "/subscriptions/sub123/resourceGroups/rg123/providers/Microsoft.Network/virtualNetworks/vnet123/subnets/subnet123" 29 | expectedVnet := "vnet123" 30 | 31 | vnet := getVnetFromSubnetId(subnetId) 32 | assert.Equal(t, expectedVnet, vnet) 33 | } 34 | 35 | func TestGetResourceIDInfo(t *testing.T) { 36 | tests := []struct { 37 | name string 38 | resourceID string 39 | expectedInfo ResourceIDInfo 40 | expectError bool 41 | }{ 42 | { 43 | name: "ValidResourceIDWithVM", 44 | resourceID: "/subscriptions/sub123/resourceGroups/rg123/providers/Microsoft.Compute/virtualMachines/" + validVmName, 45 | expectedInfo: ResourceIDInfo{SubscriptionID: "sub123", ResourceGroupName: "rg123", ResourceName: validVmName}, 46 | expectError: false, 47 | }, 48 | { 49 | name: "ValidResourceIDWithoutVM", 50 | resourceID: "/subscriptions/sub123/resourceGroups/rg123", 51 | expectedInfo: ResourceIDInfo{SubscriptionID: "sub123", ResourceGroupName: "rg123", ResourceName: "rg123"}, 52 | expectError: false, 53 | }, 54 | { 55 | name: "InvalidFormatTooFewSegments", 56 | resourceID: "/subscriptions/sub123", 57 | expectedInfo: ResourceIDInfo{}, 58 | expectError: true, 59 | }, 60 | { 61 | name: "InvalidSegment", 62 | resourceID: "/subscriptions/sub123/invalidSegment/rg123/providers/Microsoft.Compute/virtualMachines/" + validVmName, 63 | expectedInfo: ResourceIDInfo{}, 64 | expectError: true, 65 | }, 66 | } 67 | 68 | for _, test := range tests { 69 | t.Run(test.name, func(t *testing.T) { 70 | info, err := getResourceIDInfo(test.resourceID) 71 | 72 | if test.expectError { 73 | require.Error(t, err) 74 | } else { 75 | require.NoError(t, err) 76 | require.Equal(t, test.expectedInfo, info) 77 | } 78 | }) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pkg/kvstore/kvstore_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package kvstore 20 | 21 | import ( 22 | "context" 23 | "testing" 24 | 25 | redismock "github.com/go-redis/redismock/v9" 26 | storepb "github.com/paraglider-project/paraglider/pkg/kvstore/storepb" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/require" 29 | ) 30 | 31 | func TestSet(t *testing.T) { 32 | db, mock := redismock.NewClientMock() 33 | server := NewKVStoreServer(db) 34 | 35 | key := "test" 36 | value := "value" 37 | cloud := "cloud" 38 | namespace := "namespace" 39 | 40 | mock.ExpectSet(GetFullKey(key, cloud, namespace), value, 0).SetVal("OK") 41 | resp, err := server.Set(context.Background(), &storepb.SetRequest{Key: key, Value: value, Cloud: cloud, Namespace: namespace}) 42 | 43 | require.Nil(t, err) 44 | require.NotNil(t, resp) 45 | 46 | if err := mock.ExpectationsWereMet(); err != nil { 47 | t.Error(err) 48 | } 49 | } 50 | 51 | func TestGet(t *testing.T) { 52 | db, mock := redismock.NewClientMock() 53 | server := NewKVStoreServer(db) 54 | 55 | key := "test" 56 | value := "value" 57 | cloud := "cloud" 58 | namespace := "namespace" 59 | 60 | mock.ExpectGet(GetFullKey(key, cloud, namespace)).SetVal(value) 61 | resp, err := server.Get(context.Background(), &storepb.GetRequest{Key: key, Cloud: cloud, Namespace: namespace}) 62 | 63 | require.Nil(t, err) 64 | require.NotNil(t, resp) 65 | assert.Equal(t, value, resp.Value) 66 | 67 | if err := mock.ExpectationsWereMet(); err != nil { 68 | t.Error(err) 69 | } 70 | } 71 | 72 | func TestDelete(t *testing.T) { 73 | db, mock := redismock.NewClientMock() 74 | server := NewKVStoreServer(db) 75 | 76 | key := "test" 77 | cloud := "cloud" 78 | namespace := "namespace" 79 | 80 | mock.ExpectDel(GetFullKey(key, cloud, namespace)).SetVal(0) 81 | resp, err := server.Delete(context.Background(), &storepb.DeleteRequest{Key: key, Cloud: cloud, Namespace: namespace}) 82 | 83 | require.Nil(t, err) 84 | require.NotNil(t, resp) 85 | 86 | if err := mock.ExpectationsWereMet(); err != nil { 87 | t.Error(err) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /docs/source/overview/what-is-paraglider.rst: -------------------------------------------------------------------------------- 1 | .. _whatisparaglider: 2 | 3 | What is Paraglider? 4 | ===================== 5 | 6 | Paraglider is a control plane for cloud networking resources designed to simplify the tenant networking experience. 7 | The Paraglider Controller exposes the Paraglider API to tenants and uses public cloud APIs to manage the tenant's cloud network. 8 | 9 | How is Paraglider different from other cloud networking solutions? 10 | -------------------------------------------------------------------- 11 | 12 | * Infrastructure as code solutions like Terraform might save you from directly invoking cloud provider APIs and allow you to use a unified language to define your network, but everything is still expressed in terms of the resources and properties supported by each cloud. You'll still assemble your network from low-level components like virtual networks, peerings, gateways, etc. 13 | * Service meshes and other application-layer solutions can simplify managing connectivity between services at the application layer, but often assume that someone else has set up the network-level connectivity for you. 14 | * Network-layer multicloud solutions like Aviatrix can simplify the process of creating IP-level connectivity between clouds, but still require you to work with low-level networking building blocks and do not expose a streamlined API like Paraglider. 15 | * Paraglider also offers cloud-agnostic constructs and transparently supports multi-region and multi-cloud connectivity, meaning that you use the same constructs whether you are establishing a connection within the same cloud and the same region, or across regions and across clouds. 16 | 17 | What's a Paraglider use case? 18 | ------------------------------------------------ 19 | Let's consider a very simple case: you have two applications running on different machines that should be able to send requests to one another. 20 | *How do you set up the network to accomplish this?* 21 | 22 | Depending on the cloud(s) you're using, issues like whether the hosts can be in the same network for administrative reasons, whether the hosts are in the same region, or if the hosts are in different clouds, will cause the answer to vary widely. 23 | 24 | For a specific example of the above, consider the case when these apps are in GCP and Azure. 25 | Assuming these apps are private, these two hosts will require setting up a VPN gateway between the networks, configuring the connection between the gateways, setting up routes, and more, depending on the exact setup. 26 | 27 | Paraglider provides the exact same interface for all the different cases listed above (single-network, multi-region, multi-cloud), and creates the network necessary to achieve just that higher level goal: connect the two hosts running the apps. 28 | -------------------------------------------------------------------------------- /pkg/azure/priority_utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package azure 18 | 19 | import ( 20 | armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" 21 | ) 22 | 23 | // setupMaps fills the reservedPrioritiesInbound and reservedPrioritiesOutbound maps with the priorities of the existing rules in the NSG 24 | // This is done to avoid priorities conflicts when creating new rules 25 | // Existing rules map is filled to ensure that rules that just need their contents updated do not get recreated with new priorities 26 | func setupMaps(reservedPrioritiesInbound map[int32]*armnetwork.SecurityRule, reservedPrioritiesOutbound map[int32]*armnetwork.SecurityRule, existingRulePriorities map[string]int32, nsg *armnetwork.SecurityGroup) error { 27 | for _, rule := range nsg.Properties.SecurityRules { 28 | if *rule.Properties.Direction == armnetwork.SecurityRuleDirectionInbound { 29 | reservedPrioritiesInbound[*rule.Properties.Priority] = rule 30 | } else if *rule.Properties.Direction == armnetwork.SecurityRuleDirectionOutbound { 31 | reservedPrioritiesOutbound[*rule.Properties.Priority] = rule 32 | } 33 | 34 | // skip rules that are added by default, because they may have different fields 35 | // such as port ranges which is not supported by Paraglider at the moment 36 | if existingRulePriorities == nil || *rule.Properties.Priority > maxPriority { 37 | continue 38 | } 39 | existingRulePriorities[*rule.Name] = *rule.Properties.Priority 40 | } 41 | return nil 42 | } 43 | 44 | // getNextAvailablePriority returns the next available priority number that is not used by other rules 45 | // If lowestAvailable is true, function returns the lowest available priority number; Otherwise it returns the highest available priority number. 46 | func getNextAvailablePriority(reservedPriorities map[int32]*armnetwork.SecurityRule, start int32, end int32, lowestAvailable bool) int32 { 47 | increment := int32(1) 48 | if !lowestAvailable { 49 | start, end = end, start 50 | increment = -1 51 | } 52 | 53 | i := start 54 | for ; i < end; i += increment { 55 | if reservedPriorities[i] == nil { 56 | reservedPriorities[i] = &armnetwork.SecurityRule{} 57 | break 58 | } 59 | } 60 | 61 | return i 62 | } 63 | -------------------------------------------------------------------------------- /docs/source/project/roadmap.rst: -------------------------------------------------------------------------------- 1 | .. _roadmap: 2 | 3 | Roadmap 4 | -------------- 5 | 6 | This pages lists some of the features that are planned for the future of Paraglider. 7 | 8 | Features 9 | ^^^^^^^^^^ 10 | .. card:: 11 | 12 | Get the IBM plugin caught up with the other plugins in feature completeness. 13 | +++ 14 | :bdg-warning:`Short-term` :bdg-link-muted:`Github Issue ` 15 | 16 | .. card:: 17 | 18 | Add support for additional resource types (e.g. specialized IaaS resources, PaaS resources, etc.). 19 | +++ 20 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 21 | 22 | .. card:: 23 | 24 | Support for brownfield scenarios like interop, or reverse engineering. 25 | +++ 26 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 27 | .. card:: 28 | 29 | Add support for network functions such as load balancers, firewalls, etc. 30 | +++ 31 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 32 | 33 | .. card:: 34 | 35 | Support for assigning public/static IP addresses. 36 | +++ 37 | :bdg-secondary:`As Needed` :bdg-link-muted:`Github Issue ` 38 | 39 | .. card:: 40 | 41 | Add plugins for other clouds. 42 | +++ 43 | :bdg-secondary:`As Needed` :bdg-link-muted:`Github Issue ` 44 | 45 | .. card:: 46 | 47 | Add support for Zero-Trust architecture with trusted identities. 48 | +++ 49 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 50 | 51 | Technical 52 | ^^^^^^^^^^ 53 | .. card:: 54 | 55 | Support asynchronous requests to the Paraglider controller. 56 | +++ 57 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 58 | 59 | .. card:: 60 | 61 | Improve provisioning latency for inter-cloud connectivity. 62 | +++ 63 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 64 | 65 | Integration 66 | ^^^^^^^^^^^^^^ 67 | .. card:: 68 | 69 | Integrate with k8s networking plugins. 70 | +++ 71 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 72 | 73 | .. card:: 74 | 75 | Infrastructure-as-code support (e.g., Terraform). 76 | +++ 77 | :bdg-primary:`Longer-term` :bdg-link-muted:`Github Issue ` 78 | -------------------------------------------------------------------------------- /docs/source/developers/contributing/building.rst: -------------------------------------------------------------------------------- 1 | .. _building: 2 | 3 | Building The Project 4 | ======================= 5 | 6 | Building the code 7 | ------------------------ 8 | Paraglider uses a Makefile to build the repository and automate most common repository tasks. 9 | 10 | You can run ``make`` (no additional arguments) to see the list of targets and their descriptions. 11 | 12 | You can build the repository with ``make build``. This will build all of the packages and executables. 13 | The first time you run ``make build`` it may take a few minutes because it will download and build dependencies. Subsequent builds will be faster because they can use cached output. 14 | 15 | The following command will build, run unit tests, and run linters. This command is handy for verifying that your local changes are working correctly. 16 | 17 | .. code-block:: console 18 | 19 | $ make build lint test 20 | 21 | Built binaries 22 | ^^^^^^^^^^^^^^^ 23 | There are two main binaries that are built by the repository: ``glide`` and ``glided``. These are the CLIs for the Paraglider client and server, respectively. 24 | See the :ref:`api` for more information on how to use these binaries. 25 | 26 | Installing the code 27 | ^^^^^^^^^^^^^^^^^^^^^ 28 | After building the code, you can run ``make install`` to install the binaries to your ``/usr/local/bin`` directory. This will allow you to run the binaries from anywhere on your system. 29 | 30 | Documentation 31 | ------------- 32 | 33 | All of our documentation is located in ``docs/``. We use `Sphinx `_ to generate our documents. 34 | 35 | Setup 36 | ^^^^^^^^^ 37 | 38 | .. code-block:: console 39 | 40 | $ python -m venv .venv 41 | $ source .venv/bin/activate 42 | $ pip install -r docs/requirements.txt 43 | 44 | Building 45 | ^^^^^^^^^^^ 46 | 47 | .. code-block:: console 48 | 49 | $ cd docs 50 | $ make html 51 | 52 | Viewing 53 | ^^^^^^^^^^^ 54 | 55 | .. code-block:: console 56 | 57 | $ python -m http.server 58 | 59 | Navigate to ``localhost:8000``. 60 | 61 | Troubleshooting and getting help 62 | --------------------------------- 63 | You might encounter error messages while running various ``make`` commands due to missing dependencies. Review the prerequisites listed above for installation instructions. 64 | 65 | If you get stuck working with the repository, please ask for help by `raising an issue on Github `_ or in our Discord (linked on our home page). 66 | We're always interested in ways to improve the tooling, so please feel free to report problems and suggest improvements. 67 | 68 | If you need to report an issue with the Makefile, we may ask you for a dump of the variables. You can see the state of all of the variables our Makefile defines with ``make dump``. The output will be quite large so you might want to redirect this to a file. 69 | 70 | -------------------------------------------------------------------------------- /internal/cli/glide/resource/create/create.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package create 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/paraglider-project/paraglider/pkg/paragliderpb" 28 | "github.com/spf13/cobra" 29 | ) 30 | 31 | func NewCommand() (*cobra.Command, *executor) { 32 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 33 | cmd := &cobra.Command{ 34 | Use: "create ", 35 | Short: "Create a resource in the active namespace", 36 | Args: cobra.ExactArgs(3), 37 | PreRunE: executor.Validate, 38 | RunE: executor.Execute, 39 | } 40 | cmd.Flags().String("uri", "", "Resource URI if necessary for creation") 41 | return cmd, executor 42 | } 43 | 44 | type executor struct { 45 | common.CommandExecutor 46 | writer io.Writer 47 | cliSettings config.CliSettings 48 | description []byte 49 | uri string 50 | } 51 | 52 | func (e *executor) SetOutput(w io.Writer) { 53 | e.writer = w 54 | } 55 | 56 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 57 | descriptionFile, err := os.Open(args[2]) 58 | if err != nil { 59 | return err 60 | } 61 | defer descriptionFile.Close() 62 | e.description, err = io.ReadAll(descriptionFile) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | e.uri, err = cmd.Flags().GetString("uri") 68 | if err != nil { 69 | return err 70 | } 71 | 72 | return nil 73 | } 74 | 75 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 76 | resource := ¶gliderpb.ResourceDescriptionString{Description: string(e.description)} 77 | 78 | fmt.Fprintf(e.writer, "Creating resource: %v\n", args[1]) 79 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 80 | resourceInfo, err := c.CreateResource(e.cliSettings.ActiveNamespace, args[0], args[1], resource) 81 | 82 | if err != nil { 83 | fmt.Fprintf(e.writer, "Failed to create resource: %v\n", err) 84 | return err 85 | } 86 | 87 | fmt.Fprintf(e.writer, "Resource Created.\ntag: %s\nuri: %s\nip: %s\n", resourceInfo["name"], resourceInfo["uri"], resourceInfo["ip"]) 88 | 89 | return nil 90 | } 91 | -------------------------------------------------------------------------------- /docs/source/developers/contributing/writing-go.rst: -------------------------------------------------------------------------------- 1 | .. _writinggo: 2 | 3 | Writing Good Go Code 4 | -------------------- 5 | 6 | Learning Go 7 | ^^^^^^^^^^^^^^^^^^^^ 8 | Go is a great language for newcomers! Due to its simple style and uncomplicated design, we find that new contributors can get *going* without a long learning process. 9 | 10 | For learning Go, we recommend the following resources: 11 | 12 | - `Tour of Go `_ 13 | - `Effective Go `_ 14 | - `Offical tutorials `_ 15 | 16 | We're happy to accept pull-requests and give code review feedback aimed at newbies. If you have programmed in other languages before, we are confident you can pick up Go and start contributing easily. 17 | 18 | Asking for help 19 | ^^^^^^^^^^^^^^^^^^^^ 20 | Get stuck while working on a change? Want to get advice on coding style or existing code? Please raise an issue or ask for help in our Discord (linked on our homepage). 21 | 22 | Getting productive 23 | ^^^^^^^^^^^^^^^^^^^^ 24 | You'll want to run the following command often: 25 | 26 | .. code-block:: console 27 | 28 | $ make build test lint 29 | 30 | This will build, run unit tests, and run linters to point out any problems. It's a good idea to run this if you're about to make a ``git commit``. 31 | 32 | Coding style 33 | ^^^^^^^^^^^^^^^^^^^^^^ 34 | We enforce coding style through using `gofmt `_. 35 | 36 | We stick to the usual philosophy of Go projects regarding styling, meaning that we prefer to avoid bikeshedding and debates about styling: 37 | 38 | gofmt isn't anybody's preferred style, but it's adequate for everybody. 39 | 40 | If you're using a modern editor with Go support, chances are it is already integrated with ``gofmt`` and this will mostly be automatic. 41 | If there's any question about how to style a piece of code, following the style of the surrounding code is a safe bet. 42 | 43 | We also *mostly* agree with `Google's Go Style Guide `_, but don't follow it strictly or enforce everything written there. 44 | If you're new to working on a Go project, this is a great read that will get you thinking critically about the small decisions you will make when writing Go code. 45 | 46 | Documentation 47 | ^^^^^^^^^^^^^^^^^^^^ 48 | One thing we do require is `godoc comments `_ on **exported** packages, types, variables, constants, and functions. We like this because it has two good effects: 49 | 50 | - Encourages you to minimize the exported surface-area, thus simplifying the design. 51 | - Requires you to document clearly the purpose code you expect other parts of the codebase to call. 52 | 53 | Right now we don't have automated enforcement of this rule, so expect it to come up in code review if you forget. 54 | 55 | Linting 56 | ^^^^^^^^^^^^^^^^^^^^ 57 | We run `golint-ci `_ as part of the pull-request process for static analysis. 58 | We don't have many customizations and mostly rely on the defaults. 59 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/set/set_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2023 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package set 20 | 21 | import ( 22 | "strings" 23 | "testing" 24 | 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | fake "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rest" 27 | "github.com/stretchr/testify/assert" 28 | "github.com/stretchr/testify/require" 29 | ) 30 | 31 | func TestTagSetValidate(t *testing.T) { 32 | args := []string{"tag"} 33 | 34 | err := config.ReadOrCreateConfig() 35 | assert.Nil(t, err) 36 | 37 | // Just children specified 38 | cmd, executor := NewCommand() 39 | children := []string{"child1", "child2"} 40 | err = cmd.Flags().Set("children", strings.Join(children, ",")) 41 | require.Nil(t, err) 42 | 43 | err = executor.Validate(cmd, args) 44 | 45 | assert.Nil(t, err) 46 | assert.Equal(t, children, executor.children) 47 | 48 | // Just the URI/IP specified 49 | cmd, executor = NewCommand() 50 | err = cmd.Flags().Set("uri", "uri") 51 | require.Nil(t, err) 52 | err = cmd.Flags().Set("ip", "ip") 53 | require.Nil(t, err) 54 | 55 | err = executor.Validate(cmd, args) 56 | 57 | assert.Nil(t, err) 58 | assert.Equal(t, "uri", executor.uri) 59 | assert.Equal(t, "ip", executor.ip) 60 | 61 | // Both children and URI/IP specified 62 | cmd, executor = NewCommand() 63 | children = []string{"child1", "child2"} 64 | err = cmd.Flags().Set("children", strings.Join(children, ",")) 65 | require.Nil(t, err) 66 | err = cmd.Flags().Set("uri", "uri") 67 | require.Nil(t, err) 68 | err = cmd.Flags().Set("ip", "ip") 69 | require.Nil(t, err) 70 | 71 | err = executor.Validate(cmd, args) 72 | 73 | assert.NotNil(t, err) 74 | } 75 | 76 | func TestTagSetExecute(t *testing.T) { 77 | server := &fake.FakeOrchestratorRESTServer{} 78 | serverAddr := server.SetupFakeOrchestratorRESTServer() 79 | 80 | err := config.ReadOrCreateConfig() 81 | assert.Nil(t, err) 82 | 83 | cmd, executor := NewCommand() 84 | executor.cliSettings = config.CliSettings{ServerAddr: serverAddr} 85 | 86 | // Just children set 87 | executor.children = []string{"child1", "child2"} 88 | args := []string{"tag"} 89 | 90 | err = executor.Execute(cmd, args) 91 | assert.Nil(t, err) 92 | 93 | // Just URI/IP set 94 | executor.children = []string{} 95 | executor.uri = "uri" 96 | executor.ip = "ip" 97 | 98 | err = executor.Execute(cmd, args) 99 | assert.Nil(t, err) 100 | } 101 | -------------------------------------------------------------------------------- /tools/examples/cluster-configs/gcp-cluster.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "projects//locations/us-central1-c", 3 | "cluster": { 4 | "name": "test-cluster-5", 5 | "master_auth": { 6 | "client_certificate_config": {} 7 | }, 8 | "addons_config": { 9 | "http_load_balancing": {}, 10 | "horizontal_pod_autoscaling": {}, 11 | "kubernetes_dashboard": { 12 | "disabled": true 13 | }, 14 | "dns_cache_config": {}, 15 | "gce_persistent_disk_csi_driver_config": { 16 | "enabled": true 17 | }, 18 | "gcs_fuse_csi_driver_config": {} 19 | }, 20 | "node_pools": [ 21 | { 22 | "name": "default-pool", 23 | "config": { 24 | "machine_type": "e2-micro", 25 | "disk_size_gb": 10, 26 | "oauth_scopes": [ 27 | "https://www.googleapis.com/auth/devstorage.read_only", 28 | "https://www.googleapis.com/auth/logging.write", 29 | "https://www.googleapis.com/auth/monitoring", 30 | "https://www.googleapis.com/auth/servicecontrol", 31 | "https://www.googleapis.com/auth/service.management.readonly", 32 | "https://www.googleapis.com/auth/trace.append" 33 | ], 34 | "metadata": { 35 | "disable-legacy-endpoints": "true" 36 | }, 37 | "image_type": "COS_CONTAINERD", 38 | "disk_type": "pd-balanced", 39 | "shielded_instance_config": { 40 | "enable_integrity_monitoring": true 41 | } 42 | }, 43 | "initial_node_count": 2, 44 | "autoscaling": {}, 45 | "management": { 46 | "auto_upgrade": true, 47 | "auto_repair": true 48 | }, 49 | "network_config": {}, 50 | "upgrade_settings": { 51 | "max_surge": 1 52 | } 53 | } 54 | ], 55 | "locations": [ 56 | "us-central1-c" 57 | ], 58 | "network_policy": {}, 59 | "ip_allocation_policy": { 60 | "use_ip_aliases": true 61 | }, 62 | "master_authorized_networks_config": {}, 63 | "autoscaling": {}, 64 | "default_max_pods_constraint": { 65 | "max_pods_per_node": 110 66 | }, 67 | "authenticator_groups_config": {}, 68 | "private_cluster_config": { 69 | "enable_private_nodes": true 70 | }, 71 | "shielded_nodes": { 72 | "enabled": true 73 | }, 74 | "notification_config": { 75 | "pubsub": {} 76 | }, 77 | "initial_cluster_version": "1.27.8-gke.1067004", 78 | "location": "us-central1-c", 79 | "logging_config": { 80 | }, 81 | "monitoring_config": { 82 | "managed_prometheus_config": { 83 | "enabled": true 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /pkg/kvstore/kvstore.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kvstore 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | storepb "github.com/paraglider-project/paraglider/pkg/kvstore/storepb" 26 | redis "github.com/redis/go-redis/v9" 27 | "google.golang.org/grpc" 28 | ) 29 | 30 | func GetFullKey(key string, cloud string, namespace string) string { 31 | return fmt.Sprintf("%s:%s:%s", namespace, cloud, key) 32 | } 33 | 34 | type kvStoreServer struct { 35 | storepb.UnimplementedKVStoreServer 36 | client *redis.Client 37 | } 38 | 39 | func NewKVStoreServer(client *redis.Client) *kvStoreServer { 40 | return &kvStoreServer{ 41 | client: client, 42 | } 43 | } 44 | 45 | func (s *kvStoreServer) Get(ctx context.Context, req *storepb.GetRequest) (*storepb.GetResponse, error) { 46 | value, err := s.client.Get(ctx, GetFullKey(req.Key, req.Cloud, req.Namespace)).Result() 47 | if err != nil { 48 | return nil, err 49 | } 50 | return &storepb.GetResponse{ 51 | Value: value, 52 | }, nil 53 | } 54 | 55 | func (s *kvStoreServer) Set(ctx context.Context, req *storepb.SetRequest) (*storepb.SetResponse, error) { 56 | err := s.client.Set(ctx, GetFullKey(req.Key, req.Cloud, req.Namespace), req.Value, 0).Err() 57 | if err != nil { 58 | return nil, err 59 | } 60 | return &storepb.SetResponse{}, nil 61 | } 62 | 63 | func (s *kvStoreServer) Delete(ctx context.Context, req *storepb.DeleteRequest) (*storepb.DeleteResponse, error) { 64 | err := s.client.Del(ctx, GetFullKey(req.Key, req.Cloud, req.Namespace)).Err() 65 | if err != nil { 66 | return nil, err 67 | } 68 | return &storepb.DeleteResponse{}, nil 69 | } 70 | 71 | // Setup and run the server 72 | func Setup(dbPort int, serverPort int, clearKeys bool) { 73 | client := redis.NewClient(&redis.Options{ 74 | Addr: fmt.Sprintf("localhost:%d", dbPort), 75 | Password: "", // no password set 76 | DB: 0, // use default DB 77 | }) 78 | if clearKeys { 79 | fmt.Printf("Flushed all keys.") 80 | client.FlushAll(context.Background()) 81 | } 82 | 83 | lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", serverPort)) 84 | if err != nil { 85 | log.Fatalf("failed to listen: %v", err) 86 | } 87 | var opts []grpc.ServerOption 88 | grpcServer := grpc.NewServer(opts...) 89 | storepb.RegisterKVStoreServer(grpcServer, NewKVStoreServer(client)) 90 | fmt.Printf("Serving KV Store at localhost:%d", serverPort) 91 | go func(){ 92 | err = grpcServer.Serve(lis) 93 | if err != nil { 94 | fmt.Println(err.Error()) 95 | } 96 | }() 97 | } 98 | -------------------------------------------------------------------------------- /pkg/tag_service/tagservicepb/tagservice.proto: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | syntax = "proto3"; 18 | package tagservicepb; 19 | 20 | option go_package="github.com/paraglider-project/paraglider/pkg/tag_service/tagservicepb"; 21 | 22 | service TagService { 23 | rpc SetTag(SetTagRequest) returns (SetTagResponse) {} 24 | rpc GetTag(GetTagRequest) returns (GetTagResponse) {} 25 | rpc ResolveTag(ResolveTagRequest) returns (ResolveTagResponse) {} 26 | rpc ListTags(ListTagsRequest) returns (ListTagsResponse) {} 27 | rpc DeleteTagMember(DeleteTagMemberRequest) returns (DeleteTagMemberResponse) {} 28 | rpc DeleteTag(DeleteTagRequest) returns (DeleteTagResponse) {} 29 | rpc Subscribe(SubscribeRequest) returns (SubscribeResponse) {} 30 | rpc Unsubscribe(UnsubscribeRequest) returns (UnsubscribeResponse) {} 31 | rpc GetSubscribers(GetSubscribersRequest) returns (GetSubscribersResponse) {} 32 | } 33 | 34 | message Subscription { 35 | string tag_name = 1; 36 | string subscriber = 2; 37 | } 38 | 39 | message TagMapping { 40 | string name = 1; 41 | repeated string child_tags = 2; 42 | optional string uri = 3; 43 | optional string ip = 4; 44 | } 45 | 46 | message SetTagRequest { 47 | TagMapping tag = 1; 48 | } 49 | 50 | message SetTagResponse { 51 | } 52 | 53 | message GetTagRequest { 54 | string tag_name = 1; 55 | } 56 | 57 | message GetTagResponse { 58 | TagMapping tag = 1; 59 | } 60 | 61 | message ResolveTagRequest { 62 | string tag_name = 1; 63 | } 64 | 65 | message ResolveTagResponse { 66 | repeated TagMapping tags = 1; 67 | } 68 | 69 | message ListTagsRequest { 70 | } 71 | 72 | message ListTagsResponse { 73 | repeated TagMapping tags = 1; 74 | } 75 | 76 | message DeleteTagMemberRequest { 77 | string parent_tag = 1; 78 | string child_tag = 2; 79 | } 80 | 81 | message DeleteTagMemberResponse { 82 | } 83 | 84 | message DeleteTagRequest { 85 | string tag_name = 1; 86 | } 87 | 88 | message DeleteTagResponse { 89 | } 90 | 91 | message SubscribeRequest { 92 | Subscription subscription = 1; 93 | } 94 | 95 | message SubscribeResponse { 96 | } 97 | 98 | message UnsubscribeRequest { 99 | Subscription subscription = 1; 100 | } 101 | 102 | message UnsubscribeResponse { 103 | } 104 | 105 | message GetSubscribersRequest { 106 | string tag_name = 1; 107 | } 108 | 109 | message GetSubscribersResponse { 110 | repeated string subscribers = 1; 111 | } 112 | -------------------------------------------------------------------------------- /internal/cli/glide/tag/set/set.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package set 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "os" 23 | 24 | common "github.com/paraglider-project/paraglider/internal/cli/common" 25 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 26 | "github.com/paraglider-project/paraglider/pkg/client" 27 | "github.com/paraglider-project/paraglider/pkg/tag_service/tagservicepb" 28 | "github.com/spf13/cobra" 29 | ) 30 | 31 | func NewCommand() (*cobra.Command, *executor) { 32 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 33 | cmd := &cobra.Command{ 34 | Use: "set [--children | --uri | --ip ]", 35 | Short: "Set a tag", 36 | Args: cobra.ExactArgs(1), 37 | PreRunE: executor.Validate, 38 | RunE: executor.Execute, 39 | } 40 | cmd.Flags().StringSlice("children", []string{}, "List of child tags") 41 | cmd.Flags().String("uri", "", "URI of the tag") 42 | cmd.Flags().String("ip", "", "IP of the tag") 43 | return cmd, executor 44 | } 45 | 46 | type executor struct { 47 | common.CommandExecutor 48 | writer io.Writer 49 | cliSettings config.CliSettings 50 | children []string 51 | uri string 52 | ip string 53 | } 54 | 55 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 56 | var err error 57 | e.children, err = cmd.Flags().GetStringSlice("children") 58 | if err != nil { 59 | return err 60 | } 61 | 62 | e.uri, err = cmd.Flags().GetString("uri") 63 | if err != nil { 64 | return err 65 | } 66 | 67 | e.ip, err = cmd.Flags().GetString("ip") 68 | if err != nil { 69 | return err 70 | } 71 | 72 | if len(e.children) == 0 && e.uri == "" && e.ip == "" { 73 | return fmt.Errorf("must specify at least one of --children, --uri, or --ip") 74 | } 75 | if len(e.children) > 0 && (e.uri != "" || e.ip != "") { 76 | return fmt.Errorf("cannot specify --children with --uri or --ip") 77 | } 78 | 79 | return nil 80 | } 81 | 82 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 83 | var uri *string 84 | var ip *string 85 | if e.uri == "" { 86 | uri = nil 87 | } else { 88 | uri = &e.uri 89 | } 90 | if e.ip == "" { 91 | ip = nil 92 | } else { 93 | ip = &e.ip 94 | } 95 | 96 | tagMapping := &tagservicepb.TagMapping{Name: args[0], ChildTags: e.children, Uri: uri, Ip: ip} 97 | 98 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 99 | err := c.SetTag(args[0], tagMapping) 100 | return err 101 | } 102 | -------------------------------------------------------------------------------- /pkg/gcp/vpn.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package gcp 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | ) 23 | 24 | const ( 25 | ikeVersion = 2 26 | ) 27 | 28 | // TODO @seankimkdy: replace these in the future to be not hardcoded 29 | var vpnRegion = "us-west1" // Must be var as this is changed during unit tests 30 | 31 | func getVpnGwName(namespace string) string { 32 | return getParagliderNamespacePrefix(namespace) + "-vpn-gw" 33 | } 34 | 35 | func getRouterName(namespace string) string { 36 | return getParagliderNamespacePrefix(namespace) + "-router" 37 | } 38 | 39 | // Returns a peer gateway name when connecting to another cloud 40 | func getPeerGwName(namespace string, cloud string) string { 41 | return getParagliderNamespacePrefix(namespace) + "-" + cloud + "-peer-gw" 42 | } 43 | 44 | // Returns a VPN tunnel name when connecting to another cloud 45 | func getVpnTunnelName(namespace string, cloud string, tunnelIdx int) string { 46 | return getParagliderNamespacePrefix(namespace) + "-" + cloud + "-tunnel-" + strconv.Itoa(tunnelIdx) 47 | } 48 | 49 | // Returns a VPN tunnel interface name when connecting to another cloud 50 | func getVpnTunnelInterfaceName(namespace string, cloud string, tunnelIdx int, interfaceIdx int) string { 51 | return getVpnTunnelName(namespace, cloud, tunnelIdx) + "-int-" + strconv.Itoa(interfaceIdx) 52 | } 53 | 54 | // Returns a BGP peer name 55 | func getBgpPeerName(cloud string, peerIdx int) string { 56 | return cloud + "-bgp-peer-" + strconv.Itoa(peerIdx) 57 | } 58 | 59 | // getNatName returns a NAT name 60 | func getNatName(namespace string) string { 61 | return getParagliderNamespacePrefix(namespace) + "-nat" 62 | } 63 | 64 | // getVpnGatewayUrl returns a fully qualified URL for a VPN Gateway 65 | func getVpnGatewayUrl(project, region, vpnGatewayName string) string { 66 | return computeUrlPrefix + fmt.Sprintf("projects/%s/regions/%s/vpnGateways/%s", project, region, vpnGatewayName) 67 | } 68 | 69 | // getRouterUrl returns a fully qualified URL for a router 70 | func getRouterUrl(project, region, routerName string) string { 71 | return computeUrlPrefix + fmt.Sprintf("projects/%s/regions/%s/routers/%s", project, region, routerName) 72 | } 73 | 74 | // getVpnTunnelUrl returns a fully qualified URL for a VPN Tunnel 75 | func getVpnTunnelUrl(project, region, vpnTunnelName string) string { 76 | return computeUrlPrefix + fmt.Sprintf("projects/%s/regions/%s/vpnTunnels/%s", project, region, vpnTunnelName) 77 | } 78 | 79 | // getPeerGatewayUrl returns a fully qualified URL for a peer gateway 80 | func getPeerGatewayUrl(project, peerGatewayName string) string { 81 | return computeUrlPrefix + fmt.Sprintf("projects/%s/global/externalVpnGateways/%s", project, peerGatewayName) 82 | } 83 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Paraglider! 2 | ====================================== 3 | 4 | .. raw:: html 5 | 6 |
7 | Star 8 | 9 | 10 | 11 | .. image:: https://img.shields.io/discord/1116864463832891502?logo=discord&logoColor=white&logoSize=auto&label=Discord&labelColor=7289DA&color=17cf48&link=https%3A%2F%2Fdiscord.gg%2FKrZGbfZ7wm 12 | :alt: Discord 13 | :target: https://discord.gg/KrZGbfZ7wm 14 | :height: 28px 15 | 16 | .. image:: ./_static/wiki-button.png 17 | :alt: Wiki 18 | :target: https://lf-networking.atlassian.net/wiki/spaces/PAR/overview?homepageId=15106050 19 | :height: 28px 20 | 21 | The Paraglider project aims to simplify the creation and management of single-cloud and multi-cloud networks. It reduces the need for developers and administrators to have detailed networking knowledge, hiding the complexity of components like virtual networks, access controls, load balancers, and inter-cloud connections. 22 | 23 | Paraglider provides high-level constructs for modeling connectivity, security, and key network functions. It also offers mechanisms for using semantically meaningful names and groups instead of IP-based constructs. The Paraglider configuration, expressed as connectivity requirements between networked resources (VMs, containers, PaaS resources, etc.), is translated into cloud-specific configurations through plugins tailored for each cloud platform. 24 | 25 | Ultimately, Paraglider delivers a unified cross-cloud control plane that streamlines cloud networking. 26 | 27 | Paraglider began as a research project at UC Berkeley in the NetSys Lab. The work was originally published in `HotOS `_ and `NSDI `_. 28 | Since publication, the design goals for the implementation have evolved to support private address spaces, but still match the simplified interface proposed in the papers. 29 | 30 | The project is now run by an cross-industry working group consisting of members from Microsoft, Google, IBM, and UC Berkeley. It is a Linux Foundation open-source project. 31 | 32 | Check out the `GitHub repository `_ for the latest code and issues. 33 | 34 | .. note:: 35 | This project is under active development. 36 | 37 | .. toctree:: 38 | :maxdepth: 1 39 | :caption: Overview 40 | 41 | overview/what-is-paraglider.rst 42 | overview/concepts.rst 43 | overview/howitworks.rst 44 | overview/api.rst 45 | overview/quickstart.rst 46 | 47 | .. toctree:: 48 | :maxdepth: 1 49 | :caption: Examples 50 | 51 | examples/controller-setup.rst 52 | examples/tags.rst 53 | examples/multicloud.rst 54 | 55 | .. toctree:: 56 | :maxdepth: 1 57 | :caption: Project Status 58 | 59 | project/feature-status.rst 60 | project/roadmap.rst 61 | 62 | .. toctree:: 63 | :maxdepth: 1 64 | :caption: Developers 65 | 66 | developers/contributing.rst 67 | developers/plugin-interface.rst 68 | 69 | -------------------------------------------------------------------------------- /.github/scripts/get_release_version.py: -------------------------------------------------------------------------------- 1 | # This script parses release version from Git references and set the parsed version to 2 | # environment variables, REL_VERSION and REL_CHANNEL. 3 | 4 | # We set the environment variable REL_CHANNEL based on the kind of build. This is used for 5 | # versioning of our assets. 6 | # 7 | # REL_CHANNEL is: 8 | # 'latest': for most builds 9 | # 'latest': for PR builds 10 | # '1.0.0-rc1' (the full version): for a tagged prerelease 11 | # '1.0' (major.minor): for a tagged release 12 | 13 | # You can test this script manually by setting some environment variables and running it: 14 | # touch env.txt summary.txt 15 | # export GITHUB_ENV="$(pwd)/env.txt" 16 | # export GITHUB_STEP_SUMMARY="$(pwd)/summary.txt" 17 | # export GITHUB_REF= 18 | # 19 | # Example pre-release tag: 20 | # export GITHUB_REF=refs/tags/v1.0.0-rc1 21 | # Example release tag: 22 | # export GITHUB_REF=refs/tags/v1.0.0 23 | # Example pull-request: 24 | # export GITHUB_REF=refs/pull/42/head 25 | # 26 | # Running the script will write the environment variables to env.txt and the summary to summary.txt 27 | 28 | from enum import Enum 29 | import os 30 | import re 31 | 32 | class BuildType(Enum): 33 | UNKNOWN = 1 34 | PULL_REQUEST = 2 35 | NORMAL = 3 36 | PRERELEASE = 4 37 | RELEASE = 5 38 | 39 | # From https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string 40 | # Group 'version' returns the whole version other named groups return the components: 41 | # major, minor, patch, prerelease, buildmetadata 42 | tag_ref_regex = r"^refs/tags/v(?P0|(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)$" 43 | pull_ref_regex = r"^refs/pull/(.*)/(.*)$" 44 | 45 | github_ref = os.getenv("GITHUB_REF") 46 | 47 | def decide_versions() -> tuple[BuildType, str, str]: 48 | if github_ref is None: 49 | return (BuildType.UNKNOWN, "latest", "latest") 50 | 51 | match = re.search(pull_ref_regex, github_ref) 52 | if match is not None: 53 | return (BuildType.PULL_REQUEST, "pr-{}".format(match.group(1)), "latest") 54 | 55 | match = re.search(tag_ref_regex, github_ref) 56 | if match is not None and match.group("prerelease") is not None: 57 | return (BuildType.PRERELEASE, match.group("version"), match.group("version")) 58 | elif match is not None: 59 | return (BuildType.RELEASE, match.group("version"), "{}.{}".format(match.group("major"), match.group("minor"))) 60 | 61 | # We end up here for a build of any other branch (eg: a build of main). 62 | return (BuildType.NORMAL, "latest", "latest") 63 | 64 | build_type, version, channel = decide_versions() 65 | with open(os.getenv("GITHUB_ENV"), "a") as github_env, open(os.getenv("GITHUB_STEP_SUMMARY"), "a") as github_step_summary: 66 | # Set environment variables for the build to use 67 | github_env.write("REL_VERSION={}\n".format(version)) 68 | github_env.write("REL_CHANNEL={}\n".format(channel)) 69 | 70 | summary = """This is a {} build based on ref '{}'. Setting: 71 | 72 | - REL_VERSION={} 73 | - REL_CHANNEL={}""".format(build_type, github_ref, version, channel) 74 | 75 | # Print description for debugging 76 | print(summary) 77 | github_step_summary.write(summary) -------------------------------------------------------------------------------- /pkg/aws/plugin_test.go: -------------------------------------------------------------------------------- 1 | //go:build unit 2 | 3 | /* 4 | Copyright 2024 The Paraglider Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package aws 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/aws/aws-sdk-go-v2/aws" 25 | "github.com/aws/aws-sdk-go-v2/service/ec2/types" 26 | orchestrator "github.com/paraglider-project/paraglider/pkg/fake/orchestrator/rpc" 27 | "github.com/paraglider-project/paraglider/pkg/paragliderpb" 28 | "github.com/paraglider-project/paraglider/pkg/utils" 29 | "github.com/stretchr/testify/require" 30 | ) 31 | 32 | func TestCreateResource(t *testing.T) { 33 | testCases := []struct { 34 | name string 35 | fakeServerState fakeServerState 36 | shouldError bool 37 | }{ 38 | { 39 | name: "FromScratch", 40 | fakeServerState: fakeServerState{}, 41 | shouldError: false, 42 | }, 43 | { 44 | name: "ExistingNetwork", 45 | fakeServerState: fakeServerState{ 46 | vpc: fakeVpc, 47 | subnet: fakeSubnet, 48 | }, 49 | shouldError: false, 50 | }, 51 | { 52 | name: "WrongAvailabilityZone", 53 | fakeServerState: fakeServerState{ 54 | vpc: fakeVpc, 55 | subnet: &types.Subnet{ 56 | SubnetId: aws.String(fakeSubnetId), 57 | AvailabilityZone: aws.String(fakeAvailabilityZone2), 58 | }, 59 | }, 60 | shouldError: true, 61 | }, 62 | } 63 | 64 | for _, testCase := range testCases { 65 | t.Run(testCase.name, func(t *testing.T) { 66 | // Setup test 67 | ctx, fakeAwsClients, err := setupTest(testCase.fakeServerState) 68 | if err != nil { 69 | t.Fatalf("unable to setup test: %v", err) 70 | } 71 | 72 | // Setup fake orchestrator and plugin 73 | _, fakeOrchestratorServerAddr, err := orchestrator.SetupFakeOrchestratorRPCServer(utils.AWS) 74 | if err != nil { 75 | t.Fatalf("unable to setup fake orchestrator: %v", err) 76 | } 77 | awsPluginServer := &AwsPluginServer{orchestratorServerAddr: fakeOrchestratorServerAddr} 78 | 79 | // Create instance 80 | testInstanceJson, err := getTestInstanceInputJson(fakeAvailabilityZone1) 81 | if err != nil { 82 | t.Fatalf("unable to get test instance JSON: %v", err) 83 | } 84 | createResourceReq := ¶gliderpb.CreateResourceRequest{ 85 | Deployment: ¶gliderpb.ParagliderDeployment{Namespace: fakeNamespace, Id: fakeAccountId}, 86 | Name: fakeInstanceName, 87 | Description: testInstanceJson, 88 | } 89 | createResourceResp, err := awsPluginServer._CreateResource(ctx, createResourceReq, fakeAwsClients) 90 | if testCase.shouldError { 91 | require.Error(t, err) 92 | } else { 93 | require.NoError(t, err) 94 | require.Equal(t, fakeInstanceName, createResourceResp.Name) 95 | require.Equal(t, getInstanceArn(createResourceReq.Deployment.Id, fakeRegion, fakeInstanceId), createResourceResp.Uri) 96 | require.Equal(t, fakeInstancePrivateIpAddress, createResourceResp.Ip) 97 | } 98 | }) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /pkg/aws/naming.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package aws 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/aws/aws-sdk-go-v2/aws" 23 | "github.com/aws/aws-sdk-go-v2/service/ec2/types" 24 | ) 25 | 26 | const ( 27 | paragliderPrefix = "para" // Prefix for all resources 28 | defaultSecurityGroupName = "default" // Default security group name as set by AWS 29 | ) 30 | 31 | // getDescribeFilter returns a filter for a resource to use for getting (e.g., Describe...). 32 | func getDescribeFilter(namespace string, name string) []types.Filter { 33 | return []types.Filter{ 34 | {Name: aws.String("tag:Name"), Values: []string{name}}, 35 | {Name: aws.String("tag:Namespace"), Values: []string{namespace}}, 36 | } 37 | } 38 | 39 | // getTagSpecificationsForCreateResource returns tag specifications for a resource to use for creating (e.g., Create...). 40 | func getTagSpecificationsForCreateResource(namespace string, name string, resourceType types.ResourceType) []types.TagSpecification { 41 | return []types.TagSpecification{ 42 | { 43 | ResourceType: resourceType, 44 | Tags: []types.Tag{ 45 | {Key: aws.String("Name"), Value: aws.String(name)}, 46 | {Key: aws.String("Namespace"), Value: aws.String(namespace)}, 47 | }, 48 | }, 49 | } 50 | } 51 | 52 | // getNameTag returns the value of the tag with key "Name" for a resource. 53 | func getNameTag(tags []types.Tag) string { 54 | for _, tag := range tags { 55 | if *tag.Key == "Name" { 56 | return *tag.Value 57 | } 58 | } 59 | return "" 60 | } 61 | 62 | // getRegionFromAvailabilityZone returns the region from an availability zone. 63 | func getRegionFromAvailabilityZone(availabilityZone string) string { 64 | return availabilityZone[:len(availabilityZone)-1] 65 | } 66 | 67 | // getNamespacePrefix returns the prefix for all resources within a specific namespace. 68 | func getNamespacePrefix(namespace string) string { 69 | return paragliderPrefix + "-" + namespace 70 | } 71 | 72 | // getVpcName returns the name of a VPC in namespace and region. 73 | func getVpcName(namespace string, region string) string { 74 | return fmt.Sprintf("%s-%s-%s", getNamespacePrefix(namespace), region, "vpc") 75 | } 76 | 77 | // getSubnetName returns the name of a subnet in a namespace and region. 78 | func getSubnetName(namespace string, region string) string { 79 | return fmt.Sprintf("%s-%s-%s", getNamespacePrefix(namespace), region, "subnet") 80 | } 81 | 82 | // getSecurityGroupName returns the name of a security group for instanceName in namespace. 83 | func getSecurityGroupName(namespace string, instanceName string) string { 84 | // Can't use an immutable field like ID since security group needs to be created before instance creation. 85 | return fmt.Sprintf("%s-%s-%s", getNamespacePrefix(namespace), instanceName, "sg") 86 | } 87 | 88 | // getInstanceArn returns the ARN of an instance. 89 | func getInstanceArn(accountId string, region string, instanceId string) string { 90 | return fmt.Sprintf("arn:aws:ec2:%s:%s:instance/%s", region, accountId, instanceId) 91 | } 92 | -------------------------------------------------------------------------------- /internal/cli/glided/startup/startup.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package startup 18 | 19 | import ( 20 | "os" 21 | "strconv" 22 | 23 | "github.com/spf13/cobra" 24 | yaml "gopkg.in/yaml.v2" 25 | 26 | az "github.com/paraglider-project/paraglider/pkg/azure" 27 | gcp "github.com/paraglider-project/paraglider/pkg/gcp" 28 | ibm "github.com/paraglider-project/paraglider/pkg/ibm" 29 | 30 | kvservice "github.com/paraglider-project/paraglider/pkg/kvstore" 31 | orchestrator "github.com/paraglider-project/paraglider/pkg/orchestrator" 32 | "github.com/paraglider-project/paraglider/pkg/orchestrator/config" 33 | tagservice "github.com/paraglider-project/paraglider/pkg/tag_service" 34 | ) 35 | 36 | func NewCommand() *cobra.Command { 37 | executor := &executor{} 38 | cmd := &cobra.Command{ 39 | Use: "startup ", 40 | Aliases: []string{"startup"}, 41 | Short: "Starts all the microservices with given config file", 42 | Args: cobra.ExactArgs(1), 43 | PreRunE: executor.Validate, 44 | RunE: executor.Execute, 45 | } 46 | cmd.Flags().Bool("clearkeys", false, "Clears all the keys in the redis database") 47 | return cmd 48 | } 49 | 50 | type executor struct { 51 | tagPort int 52 | kvPort int 53 | azPort int 54 | gcpPort int 55 | ibmPort int 56 | orchestratorAddr string 57 | clearKeys bool 58 | } 59 | 60 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 61 | // Read the config 62 | f, err := os.Open(args[0]) 63 | if err != nil { 64 | return err 65 | } 66 | defer f.Close() 67 | 68 | var cfg config.Config 69 | decoder := yaml.NewDecoder(f) 70 | err = decoder.Decode(&cfg) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | e.orchestratorAddr = cfg.Server.Host + ":" + cfg.Server.RpcPort 76 | 77 | e.tagPort, err = strconv.Atoi(cfg.TagService.Port) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | if cfg.KVStore.Port != "" { 83 | e.kvPort, err = strconv.Atoi(cfg.KVStore.Port) 84 | if err != nil { 85 | return err 86 | } 87 | } 88 | 89 | for _, cloud := range cfg.CloudPlugins { 90 | if cloud.Name == "gcp" { 91 | e.gcpPort, err = strconv.Atoi(cloud.Port) 92 | if err != nil { 93 | return err 94 | } 95 | } else if cloud.Name == "azure" { 96 | e.azPort, err = strconv.Atoi(cloud.Port) 97 | if err != nil { 98 | return err 99 | } 100 | } else if cloud.Name == "ibm" { 101 | e.ibmPort, err = strconv.Atoi(cloud.Port) 102 | if err != nil { 103 | return err 104 | } 105 | } 106 | } 107 | 108 | e.clearKeys, err = cmd.Flags().GetBool("clearkeys") 109 | if err != nil { 110 | return err 111 | } 112 | 113 | return nil 114 | } 115 | 116 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 117 | go func() { 118 | tagservice.Setup(6379, e.tagPort, e.clearKeys) 119 | }() 120 | 121 | go func() { 122 | kvservice.Setup(6379, e.kvPort, e.clearKeys) 123 | }() 124 | 125 | go func() { 126 | gcp.Setup(e.gcpPort, e.orchestratorAddr) 127 | }() 128 | 129 | go func() { 130 | az.Setup(e.azPort, e.orchestratorAddr) 131 | }() 132 | 133 | go func() { 134 | ibm.Setup(e.ibmPort, e.orchestratorAddr) 135 | }() 136 | 137 | orchestrator.SetupWithFile(args[0], false) 138 | 139 | return nil 140 | } 141 | -------------------------------------------------------------------------------- /docs/source/developers/contributing.rst: -------------------------------------------------------------------------------- 1 | .. _contributing: 2 | 3 | Contributing 4 | ======================================== 5 | 6 | Welcome to the Paraglider! We're currently building Paraglider with a small cross-industry team. 7 | 8 | This page gives an overview of how to contribute to the project. Please read over this document for some important basics. For specific topics, refer to the table of contents. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :caption: Contents: 13 | 14 | contributing/prerequisites.rst 15 | contributing/building.rst 16 | contributing/contributing-issues.rst 17 | contributing/writing-go.rst 18 | contributing/known-issues.rst 19 | 20 | Overview 21 | ---------- 22 | Paraglider provides a streamlined interface for users to manage their cloud network resources. 23 | Cloud customers interact with the Paraglider APIs exposed by the Paraglider controller. 24 | The controller is responsible for provisioning and updating the relevant cloud network resources based on the requests from the user. 25 | The controller includes plugins for each cloud it supports which are responsible for translating the Paraglider configuration to the cloud-specific configuration. 26 | For more information about the design and architecture, please refer to :ref:`howitworks`. 27 | 28 | Guidelines 29 | ------------------ 30 | We always welcome minor contributions like documentation improvements, typo corrections, bug fixes, and minor features in the form of pull requests. 31 | You are also welcome to `choose an existing issue `_, or `create an issue to work on `_. 32 | 33 | * But please work with the maintainers to ensure that what you're doing is in scope for the project before writing any code. 34 | * If you have any doubt whether a contribution would be valuable, feel free to ask. 35 | 36 | Developer Certificate of Origin 37 | --------------------------------- 38 | The Paraglider project follows the `Developer Certificate of Origin `_. This is a lightweight way for contributors to certify that they wrote or otherwise have the right to submit the code they are contributing to the project. 39 | 40 | Contributors sign-off that they adhere to these requirements by adding a Signed-off-by line to commit messages. 41 | 42 | .. code-block:: text 43 | 44 | This is my commit message 45 | 46 | Signed-off-by: Random J Developer 47 | 48 | We provide a Git Hook to automatically add this line to your commit messages. You can install it by running the following command after installing the repo. 49 | 50 | .. code-block:: console 51 | 52 | $ git config --local core.hooksPath .githooks/ 53 | 54 | If you'd like to do this manually, git has a ``-s`` command line option to append this automatically to your commit message: 55 | 56 | .. code-block:: console 57 | 58 | $ git commit -s -m 'This is my commit message' 59 | 60 | Visual Studio Code has a setting, git.alwaysSignOff to automatically add a Signed-off-by line to commit messages. Search for "sign-off" in VS Code settings to find it and enable it. 61 | 62 | 63 | Creating issues 64 | -------------------- 65 | Please create issues for needed work and bugs in the `repo `_. 66 | 67 | 68 | Sending pull requests 69 | ---------------------- 70 | Please send pull requests for all changes, even if they are urgent. 71 | 72 | Code of Conduct 73 | -------------------- 74 | 75 | This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. 76 | For more information, see the `Contributor Covenant Code of Conduct 2.1 `_. 77 | 78 | 79 | Troubleshooting and getting help 80 | --------------------------------- 81 | * Have a question? - Visit our Discord (linked on our homepage) to post your question and we'll get back to you ASAP 82 | * Found an issue? - Refer to :ref:`contributingissues` on filing a bug report 83 | * Have a proposal? - Refer to :ref:`contributingissues` for instructions on filing a feature request 84 | 85 | -------------------------------------------------------------------------------- /pkg/fake/cloudplugin/fake_cloud_plugin.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cloud_plugin 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/paraglider-project/paraglider/pkg/paragliderpb" 26 | "github.com/paraglider-project/paraglider/pkg/tag_service/tagservicepb" 27 | "google.golang.org/grpc" 28 | 29 | fake "github.com/paraglider-project/paraglider/pkg/fake/tagservice" 30 | ) 31 | 32 | const AddressSpaceAddress = "10.0.0.0/16" 33 | const Asn = 64512 34 | 35 | var BgpPeeringIpAddresses = []string{"169.254.21.1", "169.254.22.1"} 36 | var ExampleRule = ¶gliderpb.PermitListRule{Name: "example-rule", Tags: []string{fake.ValidTagName, "1.2.3.4"}, SrcPort: 1, DstPort: 1, Protocol: 1, Direction: paragliderpb.Direction_INBOUND} 37 | 38 | // Mock Cloud Plugin Server 39 | type fakeCloudPluginServer struct { 40 | paragliderpb.UnimplementedCloudPluginServer 41 | fake.FakeTagServiceServer 42 | } 43 | 44 | func (s *fakeCloudPluginServer) GetPermitList(c context.Context, req *paragliderpb.GetPermitListRequest) (*paragliderpb.GetPermitListResponse, error) { 45 | return ¶gliderpb.GetPermitListResponse{Rules: []*paragliderpb.PermitListRule{ExampleRule}}, nil 46 | } 47 | 48 | func (s *fakeCloudPluginServer) AddPermitListRules(c context.Context, req *paragliderpb.AddPermitListRulesRequest) (*paragliderpb.AddPermitListRulesResponse, error) { 49 | return ¶gliderpb.AddPermitListRulesResponse{}, nil 50 | } 51 | 52 | func (s *fakeCloudPluginServer) DeletePermitListRules(c context.Context, req *paragliderpb.DeletePermitListRulesRequest) (*paragliderpb.DeletePermitListRulesResponse, error) { 53 | return ¶gliderpb.DeletePermitListRulesResponse{}, nil 54 | } 55 | 56 | func (s *fakeCloudPluginServer) CreateResource(c context.Context, req *paragliderpb.CreateResourceRequest) (*paragliderpb.CreateResourceResponse, error) { 57 | return ¶gliderpb.CreateResourceResponse{Name: "resource_name", Uri: "resource_uri"}, nil 58 | } 59 | 60 | func (s *fakeCloudPluginServer) AttachResource(c context.Context, req *paragliderpb.AttachResourceRequest) (*paragliderpb.AttachResourceResponse, error) { 61 | return ¶gliderpb.AttachResourceResponse{Name: "resource_name", Uri: "resource_uri", Ip: "1.1.1.1"}, nil 62 | } 63 | 64 | func (s *fakeCloudPluginServer) GetUsedAddressSpaces(c context.Context, req *paragliderpb.GetUsedAddressSpacesRequest) (*paragliderpb.GetUsedAddressSpacesResponse, error) { 65 | resp := ¶gliderpb.GetUsedAddressSpacesResponse{ 66 | AddressSpaceMappings: []*paragliderpb.AddressSpaceMapping{ 67 | { 68 | AddressSpaces: []string{AddressSpaceAddress}, 69 | Cloud: "fakecloud", 70 | Namespace: "fakenamespace", 71 | }, 72 | }, 73 | } 74 | return resp, nil 75 | } 76 | 77 | func (s *fakeCloudPluginServer) GetUsedAsns(c context.Context, req *paragliderpb.GetUsedAsnsRequest) (*paragliderpb.GetUsedAsnsResponse, error) { 78 | return ¶gliderpb.GetUsedAsnsResponse{Asns: []uint32{Asn}}, nil 79 | } 80 | 81 | func (s *fakeCloudPluginServer) GetUsedBgpPeeringIpAddresses(c context.Context, req *paragliderpb.GetUsedBgpPeeringIpAddressesRequest) (*paragliderpb.GetUsedBgpPeeringIpAddressesResponse, error) { 82 | return ¶gliderpb.GetUsedBgpPeeringIpAddressesResponse{IpAddresses: BgpPeeringIpAddresses}, nil 83 | } 84 | 85 | func NewFakePluginServer() *fakeCloudPluginServer { 86 | s := &fakeCloudPluginServer{} 87 | return s 88 | } 89 | 90 | func SetupFakePluginServer(port int) { 91 | lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 92 | if err != nil { 93 | log.Fatalf("failed to listen: %v", err) 94 | } 95 | grpcServer := grpc.NewServer() 96 | paragliderpb.RegisterCloudPluginServer(grpcServer, NewFakePluginServer()) 97 | tagservicepb.RegisterTagServiceServer(grpcServer, fake.NewFakeTagServer()) 98 | go func() { 99 | if err := grpcServer.Serve(lis); err != nil { 100 | fmt.Println(err.Error()) 101 | } 102 | }() 103 | } 104 | -------------------------------------------------------------------------------- /internal/cli/glide/rule/add/add.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package add 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "io" 23 | "os" 24 | "strings" 25 | 26 | common "github.com/paraglider-project/paraglider/internal/cli/common" 27 | "github.com/paraglider-project/paraglider/internal/cli/glide/config" 28 | "github.com/paraglider-project/paraglider/pkg/client" 29 | "github.com/paraglider-project/paraglider/pkg/paragliderpb" 30 | "github.com/spf13/cobra" 31 | ) 32 | 33 | func NewCommand() (*cobra.Command, *executor) { 34 | executor := &executor{writer: os.Stdout, cliSettings: config.ActiveConfig.Settings} 35 | cmd := &cobra.Command{ 36 | Use: "add [ | ] [--rulefile ] [--ping ] [--ssh ]", 37 | Short: "Add a rule to a resource's permit list or to the permit list of every resource within a tag", 38 | Args: cobra.RangeArgs(1, 2), 39 | PreRunE: executor.Validate, 40 | RunE: executor.Execute, 41 | } 42 | cmd.Flags().String("rulefile", "", "The file containing the rules to add") 43 | cmd.Flags().String("ping", "", "IP/tag to allow ping to") 44 | cmd.Flags().String("ssh", "", "IP/tag to allow SSH to") 45 | return cmd, executor 46 | } 47 | 48 | type executor struct { 49 | common.CommandExecutor 50 | writer io.Writer 51 | cliSettings config.CliSettings 52 | ruleFile string 53 | pingTag string 54 | sshTag string 55 | } 56 | 57 | func (e *executor) SetOutput(w io.Writer) { 58 | e.writer = w 59 | } 60 | 61 | func (e *executor) Validate(cmd *cobra.Command, args []string) error { 62 | var err error 63 | e.ruleFile, err = cmd.Flags().GetString("rulefile") 64 | if err != nil { 65 | return err 66 | } 67 | e.pingTag, err = cmd.Flags().GetString("ping") 68 | if err != nil { 69 | return err 70 | } 71 | e.sshTag, err = cmd.Flags().GetString("ssh") 72 | if err != nil { 73 | return err 74 | } 75 | return nil 76 | } 77 | 78 | func (e *executor) Execute(cmd *cobra.Command, args []string) error { 79 | rules := []*paragliderpb.PermitListRule{} 80 | if e.ruleFile != "" { 81 | // Read the rules from the file 82 | ruleFile, err := os.Open(e.ruleFile) 83 | if err != nil { 84 | return err 85 | } 86 | defer ruleFile.Close() 87 | fileRules, err := io.ReadAll(ruleFile) 88 | if err != nil { 89 | return err 90 | } 91 | // Parse the rules 92 | err = json.Unmarshal(fileRules, &rules) 93 | if err != nil { 94 | return err 95 | } 96 | } 97 | if e.pingTag != "" { 98 | ruleName := getSafeRuleName(e.pingTag) 99 | // Add the rules to allow ping 100 | rules = append(rules, ¶gliderpb.PermitListRule{Name: "ping-in-" + ruleName, Tags: []string{e.pingTag}, Protocol: 1, Direction: 0, DstPort: -1, SrcPort: -1}) 101 | rules = append(rules, ¶gliderpb.PermitListRule{Name: "ping-out-" + ruleName, Tags: []string{e.pingTag}, Protocol: 1, Direction: 1, DstPort: -1, SrcPort: -1}) 102 | } 103 | if e.sshTag != "" { 104 | ruleName := getSafeRuleName(e.sshTag) 105 | // Add the rule to allow SSH 106 | rules = append(rules, ¶gliderpb.PermitListRule{Name: "ssh-in-" + ruleName, Tags: []string{e.sshTag}, Protocol: 6, Direction: 0, DstPort: 22, SrcPort: -1}) 107 | rules = append(rules, ¶gliderpb.PermitListRule{Name: "ssh-out-" + ruleName, Tags: []string{e.sshTag}, Protocol: 6, Direction: 1, DstPort: -1, SrcPort: 22}) 108 | } 109 | 110 | c := client.Client{ControllerAddress: e.cliSettings.ServerAddr} 111 | 112 | var err error 113 | if len(args) == 1 { 114 | err = c.AddPermitListRulesTag(args[0], rules) 115 | } else { 116 | fmt.Fprintf(e.writer, "Adding permit list rule\n") 117 | err = c.AddPermitListRules(e.cliSettings.ActiveNamespace, args[0], args[1], rules) 118 | } 119 | 120 | return err 121 | } 122 | 123 | func getSafeRuleName(ruleName string) string { 124 | ruleName = strings.ReplaceAll(ruleName, "/", "-") 125 | return strings.ReplaceAll(ruleName, ".", "-") 126 | } 127 | -------------------------------------------------------------------------------- /pkg/ibm/vpc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Paraglider Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ibm 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/IBM/vpc-go-sdk/vpcv1" 23 | 24 | utils "github.com/paraglider-project/paraglider/pkg/utils" 25 | ) 26 | 27 | const vpcType = "vpc" 28 | 29 | const SharedVPC = "shared" 30 | 31 | // CreateVPC creates a Paraglider VPC for a region resources are tagged. 32 | func (c *CloudClient) CreateVPC(tags []string, exclusive bool) (*vpcv1.VPC, error) { 33 | var prefixManagement string 34 | 35 | vpcName := generateResourceName(vpcType) 36 | 37 | if !exclusive { 38 | tags = append(tags, SharedVPC) 39 | } 40 | 41 | // Prefix Management is done when subnet are created separately 42 | prefixManagement = vpcv1.CreateVPCOptionsAddressPrefixManagementManualConst 43 | 44 | options := vpcv1.CreateVPCOptions{ 45 | Name: &vpcName, 46 | ResourceGroup: c.resourceGroup, 47 | AddressPrefixManagement: &prefixManagement, 48 | } 49 | 50 | vpc, response, err := c.vpcService.CreateVPC(&options) 51 | if err != nil { 52 | utils.Log.Println("Failed to create VPC with error:", err, 53 | "\nResponse:\n", response) 54 | return nil, err 55 | } 56 | err = c.attachTag(vpc.CRN, tags) 57 | if err != nil { 58 | utils.Log.Print("Failed to tag VPC with error:", err) 59 | return nil, err 60 | } 61 | utils.Log.Printf("Created VPC: %v with ID: %v", *vpc.Name, *vpc.ID) 62 | return vpc, nil 63 | } 64 | 65 | // TerminateVPC terminates a vpc, deleting its associated instances and subnets 66 | func (c *CloudClient) TerminateVPC(vpcID string) error { 67 | // Fetch instances of specified VPC 68 | instanceList, _, err := c.vpcService.ListInstances(&vpcv1.ListInstancesOptions{ 69 | VPCID: &vpcID, 70 | ResourceGroupID: c.resourceGroup.ID, 71 | }) 72 | if err != nil { 73 | return err 74 | } 75 | // TODO: execute instance deletion and polling concurrently 76 | // delete floating ips marked "recyclable" 77 | for _, instance := range instanceList.Instances { 78 | c.deleteFloatingIPsOfVM(&instance) 79 | // delete current VM 80 | _, err := c.vpcService.DeleteInstance( 81 | &vpcv1.DeleteInstanceOptions{ID: instance.ID}) 82 | if err != nil { 83 | return err 84 | } 85 | } 86 | // wait for instances deletion process to end 87 | for _, instance := range instanceList.Instances { 88 | if !c.waitForInstanceRemoval(*instance.ID) { 89 | return fmt.Errorf("failed to remove instance within the alloted time frame") 90 | } 91 | utils.Log.Printf("Deleted instance with ID: %v", *instance.ID) 92 | } 93 | 94 | err = c.DeleteSubnets(vpcID) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | // Delete VPC 100 | _, err = c.vpcService.DeleteVPC(&vpcv1.DeleteVPCOptions{ 101 | ID: &vpcID, 102 | }) 103 | if err != nil { 104 | return err 105 | } 106 | 107 | utils.Log.Printf("VPC %v deleted successfully", vpcID) 108 | return nil 109 | } 110 | 111 | // GetVPCByID returns vpc data of specified vpc 112 | func (c *CloudClient) GetVPCByID(vpcID string) (*vpcv1.VPC, error) { 113 | vpc, response, err := c.vpcService.GetVPC(&vpcv1.GetVPCOptions{ 114 | ID: &vpcID, 115 | }) 116 | if err != nil { 117 | utils.Log.Println("Failed to retrieve VPC, Error: ", err, "\nResponse\n", response) 118 | return nil, err 119 | } 120 | return vpc, nil 121 | } 122 | 123 | // returns CIDR of VPC 124 | func (c *CloudClient) GetVpcCIDR(vpcID string) ([]string, error) { 125 | // aggregate addresses of subnets in VPC 126 | subnets, err := c.GetSubnetsInVpcRegionBound(vpcID) 127 | if err != nil { 128 | utils.Log.Printf("error while aggregating addresses of subnets to fetch VPC's CIDR: %+v", err) 129 | return nil, err 130 | } 131 | var addresses = make([]string, len(subnets)) 132 | for i, subnet := range subnets { 133 | address, err := c.GetSubnetCIDR(*subnet.ID) 134 | if err != nil { 135 | utils.Log.Printf("error while fetching subnets CIDRs in VPC: %+v", err) 136 | return nil, err 137 | } 138 | addresses[i] = address 139 | } 140 | 141 | return addresses, nil 142 | } 143 | --------------------------------------------------------------------------------