From cbdd8746fcf59c28fd865cb52efe6178c0324ab6 Mon Sep 17 00:00:00 2001 From: Richard Case Date: Mon, 12 Jul 2021 16:57:01 +0100 Subject: [PATCH] feat: added initial provider interface Signed-off-by: Richard Case --- .github/workflows/lint.yml | 12 ++ .github/workflows/test.yml | 12 ++ .golangci.yml | 5 +- Makefile | 15 ++- go.mod | 9 +- go.sum | 36 ++++++ hack/tools/go.mod | 1 + hack/tools/go.sum | 3 + hack/tools/tools.go | 1 + pkg/provider/config.go | 4 - pkg/provider/machine.go | 122 ++++++++++++------ pkg/provider/mock/gen.go | 3 + pkg/provider/mock/mock.go | 169 +++++++++++++++++++++++++ pkg/provider/provider.go | 56 +++++++- pkg/provider/registry/errors.go | 12 ++ pkg/provider/registry/registry.go | 64 ++++++++++ pkg/provider/registry/registry_test.go | 107 ++++++++++++++++ pkg/provider/runtime.go | 9 ++ 18 files changed, 580 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/test.yml delete mode 100644 pkg/provider/config.go create mode 100644 pkg/provider/mock/gen.go create mode 100644 pkg/provider/mock/mock.go create mode 100644 pkg/provider/registry/errors.go create mode 100644 pkg/provider/registry/registry.go create mode 100644 pkg/provider/registry/registry_test.go create mode 100644 pkg/provider/runtime.go diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..feeeb036 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,12 @@ +name: lint + +on: [pull_request] + +jobs: + lint: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Lint + run: make lint \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..3b853f0c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,12 @@ +name: test + +on: [pull_request] + +jobs: + test: + name: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Test + run: make test \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index 7c608cdb..8ff89dc2 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,6 +2,8 @@ run: timeout: 10m tests: false allow-parallel-runners: true + skip-dirs: + - pkg/provider/mock issues: max-same-issues: 0 @@ -26,4 +28,5 @@ linters: - gochecknoinits - wsl - tagliatelle - - exhaustivestruct \ No newline at end of file + - exhaustivestruct + - godox # remove in the future \ No newline at end of file diff --git a/Makefile b/Makefile index 8725e6d4..6bace5eb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - # Build Information build_date := $(shell date +%Y-%m-%dT%H:%M:%SZ) git_commit := $(shell git rev-parse --short HEAD) @@ -23,20 +22,20 @@ $(TOOLS_BIN_DIR): $(TOOLS_SHARE_DIR): mkdir -p $@ - # Binaries GOLANGCI_LINT := $(TOOLS_BIN_DIR)/golangci-lint GINKGO := $(TOOLS_BIN_DIR)/ginkgo BUF := $(TOOLS_BIN_DIR)/buf +MOCKGEN:= $(TOOLS_BIN_DIR)/mockgen .DEFAULT_GOAL := help ##@ Generate .PHONY: generate -generate: $(BUF) ## Generate code - $(BUF) generate - +generate: $(BUF) $(MOCKGEN) ## Generate code + go generate ./... + ##@ Linting .PHONY: lint @@ -45,6 +44,10 @@ lint: $(GOLANGCI_LINT) ## Lint ##@ Testing +.PHONY: test +test: ## Run unit tests + go test ./... + .PHONY: test-e2e test-e2e: ## Run e2e tests go test -timeout 30m -p 1 -v -tags=e2e ./test/e2e/... @@ -61,6 +64,8 @@ $(GOLANGCI_LINT): hack/tools/go.mod # Get and build golangci-lint $(GINKGO): hack/tools/go.mod # Get and build gginkgo cd $(TOOLS_DIR); go build -tags=tools -o $(subst hack/tools/,,$@) github.com/onsi/ginkgo/ginkgo +$(MOCKGEN): hack/tools/go.mod # Get and build mockgen + cd $(TOOLS_DIR); go build -tags=tools -o $(subst hack/tools/,,$@) github.com/golang/mock/mockgen BUF_TARGET := buf-Linux-x86_64.tar.gz diff --git a/go.mod b/go.mod index dba0b65c..7b33424d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,13 @@ module github.com/weaveworks/reignite go 1.16 require ( + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator v9.31.0+incompatible // indirect + github.com/golang/mock v1.6.0 // indirect github.com/gruntwork-io/terratest v0.36.3 // indirect - github.com/onsi/gomega v1.13.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/onsi/gomega v1.14.0 // indirect + go.uber.org/atomic v1.8.0 // indirect + go.uber.org/multierr v1.7.0 // indirect + go.uber.org/zap v1.18.1 // indirect ) diff --git a/go.sum b/go.sum index 01810987..454a4837 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,7 @@ github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.38.28 h1:2ZzgEupSluR18ClxUnHwXKyuADheZpMblXRAsHqF0tI= github.com/aws/aws-sdk-go v1.38.28/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -155,6 +156,12 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= +github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -172,6 +179,8 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -274,6 +283,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -318,6 +329,7 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -325,6 +337,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI= +github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= @@ -387,6 +401,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -399,6 +415,7 @@ github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59b github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= @@ -408,8 +425,17 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4= +go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -438,6 +464,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -445,6 +472,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -472,6 +500,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -487,6 +516,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -521,8 +551,10 @@ golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -558,6 +590,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -565,6 +598,7 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201110201400-7099162a900a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -637,6 +671,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/hack/tools/go.mod b/hack/tools/go.mod index 6e894dd8..b1fb4022 100644 --- a/hack/tools/go.mod +++ b/hack/tools/go.mod @@ -3,6 +3,7 @@ module github.com/weaveworks/reignite/hack/tools go 1.16 require ( + github.com/golang/mock v1.6.0 // indirect github.com/golangci/golangci-lint v1.41.1 github.com/onsi/ginkgo v1.16.4 ) diff --git a/hack/tools/go.sum b/hack/tools/go.sum index 3262d9c0..2119dc3b 100644 --- a/hack/tools/go.sum +++ b/hack/tools/go.sum @@ -204,6 +204,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -924,6 +926,7 @@ golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= diff --git a/hack/tools/tools.go b/hack/tools/tools.go index f5ba569e..5031bb47 100644 --- a/hack/tools/tools.go +++ b/hack/tools/tools.go @@ -3,6 +3,7 @@ package tools import ( + _ "github.com/golang/mock/mockgen" _ "github.com/golangci/golangci-lint/cmd/golangci-lint" _ "github.com/onsi/ginkgo/ginkgo" ) diff --git a/pkg/provider/config.go b/pkg/provider/config.go deleted file mode 100644 index ee28de79..00000000 --- a/pkg/provider/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package provider - -type RuntimeOptions struct { -} diff --git a/pkg/provider/machine.go b/pkg/provider/machine.go index 3f6291b4..1de2b8df 100644 --- a/pkg/provider/machine.go +++ b/pkg/provider/machine.go @@ -1,71 +1,109 @@ package provider -type VirtualMachine struct { - ID string - VirtualMachineSpec +// Machine represents a microvm machine that is created via a provider. +type Machine struct { + // ID is the unique identifier for a machine. + ID string `json:"id" validate:"required"` + + // MachineSpec is the spec of the machine. + MachineSpec `json:",inline" validate:"required"` } -type VirtualMachineSpec struct { - Kernel KernelSpec // Required - InitrdImage Image // Optional - VCPU uint64 // Required - MemoryInMb uint64 // Required - NetworkInterfaces []NetworkInterface // Min len 1 - Drives []Drive // Min len 1 +// MachineSpec represents the specification of a microvm machine. +type MachineSpec struct { + // Kernel specifies the kernel and its argments to use. + Kernel KernelSpec `json:"kernel" validate:"required"` + // InitrdImage is an optional initial ramdisk to use. + InitrdImage ContainerImage `json:"initrd_image,omitempty"` + // VCPU specifies how many vcpu the machine will be allocated. + VCPU uint64 `json:"vcpu" validate:"required,gt=0"` + // MemoryInMb is the amount of memory in megabytes that the machine will be allocated. + MemoryInMb uint64 `json:"memory_inmb" validate:"required,gt=0"` + // NetworkInterfaces specifies the network interfaces attached to the machine. + NetworkInterfaces []NetworkInterface `json:"network_interfaces" validate:"required"` + // Volumes specifies the volumes to be attached to the the machine. + Volumes []Volume `json:"volumes" validate:"required"` } +// KernelSpec is the specification of the kernel and its arguments. type KernelSpec struct { - Image Image - CmdLine string + // Image is the container image to use for the kernel. + Image ContainerImage `json:"image" validate:"required"` + // CmdLine are the args to use for the kernel cmdline. + CmdLine string `json:"cmdline,omitempty"` } -type Image string +// ContainerImage represents the address of a OCI image. +type ContainerImage string +// NetworkInterface represents a network interface for the microvm. type NetworkInterface struct { - AllowMetadataRequests bool - GuestMAC string - HostDeviceName string - GuestIfaceID string - //TODO: Rate limiting - //TODO: CNI - CNI *CNIConfig + // AllowMetadataRequests indicates that this interface can be used for metadata requests. + // TODO: we may hide this within the firecracker plugin. + AllowMetadataRequests bool `json:"allow_mmds,omitempty"` + // GuestMAC allows the specifying of a specifi MAC address to use for the interface. If + // not supplied a autogenerated MAC address will be used. + GuestMAC string `json:"guest_mac,omitempty"` + // HostDeviceName is the name of the network interface to use from the host. This will be + // a tuntap or macvtap interface. + HostDeviceName string `json:"host_device_name" validate:"required"` + // GuestDeviceName is the name of the network interface to create in the microvm. If this + // is not supplied than a device name will be assigned automatically. + GuestDeviceName string `json:"guest_device_name,omitempty"` + // TODO: add rate limiting. + // TODO: add CNI. } -type Drive struct { - ID string - IsRootDevice bool - ReadOnly bool - MountPoint string - Source DriveSource - PartitionID string - Size DriveSize - //TODO: rate limiting +// Volume represents a volume to be attached to a microvm machine. +type Volume struct { + // ID is the uinique identifier of the volume. + ID string `json:"id" validate:"required"` + // IsRoot specifies that the volume is to be used as the root volume. A machine + // must have a root volume. + IsRoot bool `json:"is_root" validate:"required"` + // IsReadOnly specifies that the volume is to be mounted readonly. + IsReadOnly bool `json:"is_read_only,omitempty"` + // MountPoint is the mount point for the volume in the microvm. + MountPoint string `json:"mount_point" validate:"required"` + // Source is where the volume will be sourced from. + Source VolumeSource `json:"source" validate:"required"` + // PartitionID is the uuid of the boot partition. + PartitionID string `json:"partition_id,omitempty"` + // Size is the size to resize this volume to. + Size VolumeSize `json:"size,omitempty"` + // TODO: add rate limiting. } -type DriveSource struct { - Container *ContainerDriveSource - HostPath *HostPathDriveSource - //CSI *CSIDriveSource +// VolumeSource is the source of a volume. Based loosely on the volumes in Kubernetes Pod specs. +type VolumeSource struct { + // Container is used to specify a source of a volume as a OCI container. + Container *ContainerVolumeSource `json:"container,omitempty"` + // HostPath is used to specify a source of a volume as a file/device on the host. + HostPath *HostPathVolumeSource `json:"host_path,omitempty"` + // TODO: add CSI. } -type ContainerDriveSource struct { - Image Image +// ContainerDriveSource represents the details of a volume coming from a OCI image. +type ContainerVolumeSource struct { + // Image is the OCI image to use. + Image ContainerImage `json:"image" validate:"required"` } -type HostPathDriveSource struct { +// HostPathVolumeSource represents the details of a volume coming from a file/device on the host. +type HostPathVolumeSource struct { + // Path on the host of the file/device to use as a source for a volume. Path string + // Type is the type of file/device on the host. Type HostPathType } +// HostPathType is a type representing the different type of files/devices. type HostPathType string const ( + // HostPathRawFile represents a file on the host to use as a source for a volume. It should be a raw fs. HostPathRawFile HostPathType = "RawFile" ) -type DriveSize uint64 - -type CNIConfig struct { - CNIPath string - CNIConfigDir string -} +// DriVolumeSizeveSize is a type used to represent the size of a volume. +type VolumeSize uint64 diff --git a/pkg/provider/mock/gen.go b/pkg/provider/mock/gen.go new file mode 100644 index 00000000..880753ba --- /dev/null +++ b/pkg/provider/mock/gen.go @@ -0,0 +1,3 @@ +package mock + +//go:generate ../../../hack/tools/bin/mockgen -destination mock.go -package mock github.com/weaveworks/reignite/pkg/provider MicrovmProvider diff --git a/pkg/provider/mock/mock.go b/pkg/provider/mock/mock.go new file mode 100644 index 00000000..8e05bbb8 --- /dev/null +++ b/pkg/provider/mock/mock.go @@ -0,0 +1,169 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/weaveworks/reignite/pkg/provider (interfaces: MicrovmProvider) + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + provider "github.com/weaveworks/reignite/pkg/provider" +) + +// MockMicrovmProvider is a mock of MicrovmProvider interface. +type MockMicrovmProvider struct { + ctrl *gomock.Controller + recorder *MockMicrovmProviderMockRecorder +} + +// MockMicrovmProviderMockRecorder is the mock recorder for MockMicrovmProvider. +type MockMicrovmProviderMockRecorder struct { + mock *MockMicrovmProvider +} + +// NewMockMicrovmProvider creates a new mock instance. +func NewMockMicrovmProvider(ctrl *gomock.Controller) *MockMicrovmProvider { + mock := &MockMicrovmProvider{ctrl: ctrl} + mock.recorder = &MockMicrovmProviderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMicrovmProvider) EXPECT() *MockMicrovmProviderMockRecorder { + return m.recorder +} + +// Capabilities mocks base method. +func (m *MockMicrovmProvider) Capabilities() provider.Capabilities { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Capabilities") + ret0, _ := ret[0].(provider.Capabilities) + return ret0 +} + +// Capabilities indicates an expected call of Capabilities. +func (mr *MockMicrovmProviderMockRecorder) Capabilities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Capabilities", reflect.TypeOf((*MockMicrovmProvider)(nil).Capabilities)) +} + +// CreateVM mocks base method. +func (m *MockMicrovmProvider) CreateVM(arg0 context.Context, arg1 *provider.CreateVMInput) (*provider.CreateVMOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateVM", arg0, arg1) + ret0, _ := ret[0].(*provider.CreateVMOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateVM indicates an expected call of CreateVM. +func (mr *MockMicrovmProviderMockRecorder) CreateVM(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateVM", reflect.TypeOf((*MockMicrovmProvider)(nil).CreateVM), arg0, arg1) +} + +// DeleteVM mocks base method. +func (m *MockMicrovmProvider) DeleteVM(arg0 context.Context, arg1 *provider.DeleteVMInput) (*provider.DeleteVMOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteVM", arg0, arg1) + ret0, _ := ret[0].(*provider.DeleteVMOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteVM indicates an expected call of DeleteVM. +func (mr *MockMicrovmProviderMockRecorder) DeleteVM(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVM", reflect.TypeOf((*MockMicrovmProvider)(nil).DeleteVM), arg0, arg1) +} + +// ListVMs mocks base method. +func (m *MockMicrovmProvider) ListVMs(arg0 context.Context, arg1 *provider.ListVMsInput) (*provider.ListVMsOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListVMs", arg0, arg1) + ret0, _ := ret[0].(*provider.ListVMsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListVMs indicates an expected call of ListVMs. +func (mr *MockMicrovmProviderMockRecorder) ListVMs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListVMs", reflect.TypeOf((*MockMicrovmProvider)(nil).ListVMs), arg0, arg1) +} + +// Name mocks base method. +func (m *MockMicrovmProvider) Name() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Name") + ret0, _ := ret[0].(string) + return ret0 +} + +// Name indicates an expected call of Name. +func (mr *MockMicrovmProviderMockRecorder) Name() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockMicrovmProvider)(nil).Name)) +} + +// PauseVM mocks base method. +func (m *MockMicrovmProvider) PauseVM(arg0 context.CancelFunc, arg1 *provider.PauseVMInput) (*provider.PauseVMOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PauseVM", arg0, arg1) + ret0, _ := ret[0].(*provider.PauseVMOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PauseVM indicates an expected call of PauseVM. +func (mr *MockMicrovmProviderMockRecorder) PauseVM(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PauseVM", reflect.TypeOf((*MockMicrovmProvider)(nil).PauseVM), arg0, arg1) +} + +// ResumeVM mocks base method. +func (m *MockMicrovmProvider) ResumeVM(arg0 context.Context, arg1 *provider.ResumeVMInput) (*provider.ResumeVMOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ResumeVM", arg0, arg1) + ret0, _ := ret[0].(*provider.ResumeVMOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ResumeVM indicates an expected call of ResumeVM. +func (mr *MockMicrovmProviderMockRecorder) ResumeVM(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResumeVM", reflect.TypeOf((*MockMicrovmProvider)(nil).ResumeVM), arg0, arg1) +} + +// StartVM mocks base method. +func (m *MockMicrovmProvider) StartVM(arg0 context.Context, arg1 *provider.StartVMInput) (*provider.StartVMOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StartVM", arg0, arg1) + ret0, _ := ret[0].(*provider.StartVMOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StartVM indicates an expected call of StartVM. +func (mr *MockMicrovmProviderMockRecorder) StartVM(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartVM", reflect.TypeOf((*MockMicrovmProvider)(nil).StartVM), arg0, arg1) +} + +// StopVM mocks base method. +func (m *MockMicrovmProvider) StopVM(arg0 context.Context, arg1 *provider.StopVMInput) (*provider.StopVMOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StopVM", arg0, arg1) + ret0, _ := ret[0].(*provider.StopVMOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StopVM indicates an expected call of StopVM. +func (mr *MockMicrovmProviderMockRecorder) StopVM(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopVM", reflect.TypeOf((*MockMicrovmProvider)(nil).StopVM), arg0, arg1) +} diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 86b5623d..23120285 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -2,64 +2,106 @@ package provider import "context" +// Factory is a factory function that is used to create an instance of the provider. +type Factory func(ctx context.Context, runtime *Runtime) (MicrovmProvider, error) + +// MicrovmProvider is the interface that a microvm plugin needs to implement. type MicrovmProvider interface { + // Name is the name of the provider. Name() string + // Capabilities returns a list of the capabilities the provider supports. + Capabilities() Capabilities - SetupProvider(ctx context.Context, runtime *RuntimeOptions) error - + // CreateVM will create a new microvm. CreateVM(ctx context.Context, input *CreateVMInput) (*CreateVMOutput, error) + // StartVM will start a created microvm. StartVM(ctx context.Context, input *StartVMInput) (*StartVMOutput, error) + // PauseVM will pause a started microvm. PauseVM(ctx context.CancelFunc, input *PauseVMInput) (*PauseVMOutput, error) + // ResumeVM will resume a paused microvm. ResumeVM(ctx context.Context, input *ResumeVMInput) (*ResumeVMOutput, error) + // StopVM will stop a paused or running microvm. StopVM(ctx context.Context, input *StopVMInput) (*StopVMOutput, error) + // DeleteVM will delete a VM and its runtime state. DeleteVM(ctx context.Context, input *DeleteVMInput) (*DeleteVMOutput, error) + // ListVMs will return a list of the microvms. ListVMs(ctx context.Context, input *ListVMsInput) (*ListVMsOutput, error) } +// Capabaility represents a capability of a provider. +type Capability string + +// Capability represents a list of capabilities. +type Capabilities []Capability + +// CreateVMInput is the input to CreateVM. type CreateVMInput struct { - ID string // optional - Spec VirtualMachineSpec + // ID the optional ID to use for the microvm. + ID string `json:"id,omitempty"` + // Spec is the specification of the microvm to create. + Spec MachineSpec `json:"spec" validate:"required"` } +// CreateVMOutput is the output from CreateVM. type CreateVMOutput struct { - VM *VirtualMachine + // VM is the details of the newly created microvm. + VM *Machine } +// StartVMInput is the input to StartVM. type StartVMInput struct { + // ID is the identifier of the microvm to start. ID string } +// StartVMOutput is the putput of StartVM. type StartVMOutput struct{} +// PauseVMInput is the input to PauseVM. type PauseVMInput struct { + // ID is the identifier of the microvm to pause. ID string } +// PauseVMOutput is the output of PauseVM. type PauseVMOutput struct{} +// ResumeVMInput is the input to ResumeVM. type ResumeVMInput struct { + // ID is the identifier of the microvm to resume. ID string } +// ResumeVMOutput is the output of ResumeVM. type ResumeVMOutput struct{} +// StopVMInput is the input to StopVM. type StopVMInput struct { + // ID is the identifier of the microvm to stop. ID string } +// StopVMOutput is the output of StopVM. type StopVMOutput struct{} +// DeleteVMInput is the input to DeleteVM. type DeleteVMInput struct { + // ID is the identifier of the microvm to delete. ID string } +// DeleteVMOutput is the output of DeleteVM. type DeleteVMOutput struct{} +// ListVMsInput is the input to ListVMs. type ListVMsInput struct { - MaxResults int // Optional, max results + // MaxResults is the maximum number of details to return. + MaxResults int } +// ListVMsOutput is the output of ListVMs. type ListVMsOutput struct { - VMS []VirtualMachine + // VMS is the list of VMs managed by this provider. + VMS []Machine } diff --git a/pkg/provider/registry/errors.go b/pkg/provider/registry/errors.go new file mode 100644 index 00000000..cefa6dc8 --- /dev/null +++ b/pkg/provider/registry/errors.go @@ -0,0 +1,12 @@ +package registry + +import "errors" + +var ( + // ErrDuplicatePlugin is an error for when plugin registration has been called multiple + // time for a plugin with the same name. + ErrDuplicatePlugin = errors.New("plugin with the same name has already been registered") + + // ErrPluginNotFound is an error when a plugin isn't found with a supplied name. + ErrPluginNotFound = errors.New("plugin not found") +) diff --git a/pkg/provider/registry/registry.go b/pkg/provider/registry/registry.go new file mode 100644 index 00000000..d8687116 --- /dev/null +++ b/pkg/provider/registry/registry.go @@ -0,0 +1,64 @@ +package registry + +import ( + "context" + "fmt" + "sync" + + "github.com/weaveworks/reignite/pkg/provider" +) + +var ( + pluginsLock sync.RWMutex + plugins = map[string]provider.Factory{} +) + +// RegisterProvider will register a provider plugin with the registry. +func RegisterProvider(name string, factory provider.Factory) error { + pluginsLock.Lock() + defer pluginsLock.Unlock() + + if _, exists := plugins[name]; exists { + return ErrDuplicatePlugin + } + + plugins[name] = factory + + return nil +} + +// GetPluginInstance will create a new instance of a plugin with the supplied name and runtime +// environment. When creating the instance the factory function for the plugin is called. +func GetPluginInstance(ctx context.Context, name string, runtime *provider.Runtime) (provider.MicrovmProvider, error) { + pluginsLock.RLock() + defer pluginsLock.RUnlock() + + if factoryFunc, exists := plugins[name]; exists { + return factoryFunc(ctx, runtime) + } + + return nil, fmt.Errorf("getting plugin %s: %w", name, ErrPluginNotFound) +} + +// ListPlugins returns a list of the plugin names that have been registered. +func ListPlugins() []string { + pluginsLock.RLock() + defer pluginsLock.RUnlock() + + names := make([]string, len(plugins)) + i := 0 + for name := range plugins { + names[i] = name + i++ + } + + return names +} + +// Reset will remove the registered plugins. +func Reset() { + pluginsLock.Lock() + defer pluginsLock.Unlock() + + plugins = map[string]provider.Factory{} +} diff --git a/pkg/provider/registry/registry_test.go b/pkg/provider/registry/registry_test.go new file mode 100644 index 00000000..934fd27d --- /dev/null +++ b/pkg/provider/registry/registry_test.go @@ -0,0 +1,107 @@ +package registry_test + +import ( + "context" + "fmt" + "testing" + + "github.com/golang/mock/gomock" + . "github.com/onsi/gomega" + + "github.com/weaveworks/reignite/pkg/provider" + mock_provider "github.com/weaveworks/reignite/pkg/provider/mock" + "github.com/weaveworks/reignite/pkg/provider/registry" +) + +func TestRegistry_RegisterProvider(t *testing.T) { + RegisterTestingT(t) + t.Cleanup(registry.Reset) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + err := registry.RegisterProvider("prov1", mockRegisterPluginFactor(false, ctrl)) + Expect(err).NotTo(HaveOccurred()) +} + +func TestRegistry_RegisterProviderDuplicate(t *testing.T) { + RegisterTestingT(t) + t.Cleanup(registry.Reset) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + providerName := "prov1" + + err := registry.RegisterProvider(providerName, mockRegisterPluginFactor(false, ctrl)) + Expect(err).NotTo(HaveOccurred()) + + err = registry.RegisterProvider(providerName, mockRegisterPluginFactor(false, ctrl)) + Expect(err).To(HaveOccurred()) +} + +func TestRegistry_GetInstance(t *testing.T) { + RegisterTestingT(t) + t.Cleanup(registry.Reset) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + providerName := "prov1" + factoryCalled := false + + err := registry.RegisterProvider(providerName, func(ctx context.Context, runtime *provider.Runtime) (provider.MicrovmProvider, error) { + factoryCalled = true + return mock_provider.NewMockMicrovmProvider(ctrl), nil + }) + Expect(err).NotTo(HaveOccurred()) + + p, err := registry.GetPluginInstance(context.TODO(), providerName, &provider.Runtime{}) + Expect(err).NotTo(HaveOccurred()) + Expect(p).NotTo(BeNil()) + Expect(factoryCalled).To(BeTrue()) +} + +func TestRegistry_GetInstanceNotExist(t *testing.T) { + RegisterTestingT(t) + t.Cleanup(registry.Reset) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + providerName := "prov1" + + p, err := registry.GetPluginInstance(context.TODO(), providerName, &provider.Runtime{}) + Expect(err).To(HaveOccurred()) + Expect(p).To(BeNil()) +} + +func TestRegistry_ListAllEmpty(t *testing.T) { + RegisterTestingT(t) + t.Cleanup(registry.Reset) + + registered := registry.ListPlugins() + Expect(registered).To(HaveLen(0)) +} + +func TestRegistry_ListAllNotEmpty(t *testing.T) { + RegisterTestingT(t) + t.Cleanup(registry.Reset) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + err := registry.RegisterProvider("prov1", mockRegisterPluginFactor(false, ctrl)) + Expect(err).NotTo(HaveOccurred()) + + err = registry.RegisterProvider("prov2", mockRegisterPluginFactor(false, ctrl)) + Expect(err).NotTo(HaveOccurred()) + + registered := registry.ListPlugins() + Expect(registered).To(HaveLen(2)) +} + +func mockRegisterPluginFactor(shouldFailCreate bool, ctrl *gomock.Controller) provider.Factory { + return func(ctx context.Context, runtime *provider.Runtime) (provider.MicrovmProvider, error) { + if shouldFailCreate { + return nil, fmt.Errorf("some error occured") + } + + return mock_provider.NewMockMicrovmProvider(ctrl), nil + } +} diff --git a/pkg/provider/runtime.go b/pkg/provider/runtime.go new file mode 100644 index 00000000..f5013595 --- /dev/null +++ b/pkg/provider/runtime.go @@ -0,0 +1,9 @@ +package provider + +import "go.uber.org/zap" + +// Runetime represents the provider runtime environment. +type Runtime struct { + Logger *zap.SugaredLogger + StatePath string +}