Merge pull request #218 from mercedes-benz/introduce_golangci_config

Introduce golangci config and `make help`
This commit is contained in:
Gabriel 2024-02-22 19:39:49 +02:00 committed by GitHub
commit cffb4f23d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
105 changed files with 826 additions and 733 deletions

View file

@ -30,10 +30,8 @@ jobs:
with:
go-version: 'stable'
- uses: actions/checkout@v3
- uses: golangci/golangci-lint-action@v3
with:
skip-cache: true
args: --timeout=8m --build-tags testing
- name: make lint
run: make golangci-lint && GOLANGCI_LINT_EXTRA_ARGS="--timeout=8m --build-tags testing" make lint
- name: Verify go vendor, go modules and gofmt
run: |
sudo apt-get install -y jq

40
.golangci.yml Normal file
View file

@ -0,0 +1,40 @@
# SPDX-License-Identifier: MIT
linters:
disable-all: true
fast: false
enable:
- gci
- goconst
- gocritic
- gocyclo
- gofmt
- gofumpt
- goimports
- godox
- govet
- gosec
- gosimple
- importas
- ineffassign
- loggercheck
- misspell
- nakedret
- nilerr
- predeclared
- promlinter
- revive
- staticcheck
- unconvert
- unused
- wastedassign
- whitespace
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/cloudbase/garm)
goimports:
local-prefixes: github.com/cloudbase/garm

View file

@ -10,47 +10,49 @@ VERSION ?= $(shell git describe --tags --match='v[0-9]*' --dirty --always)
GARM_REF ?= $(shell git rev-parse --abbrev-ref HEAD)
GO ?= go
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
default: build
##@ Build
.PHONY : build-static test install-lint-deps lint go-test fmt fmtcheck verify-vendor verify create-release-files release
build-static:
build-static: ## Build garm statically
@echo Building garm
docker build --tag $(IMAGE_TAG) -f Dockerfile.build-static .
docker run --rm -e USER_ID=$(USER_ID) -e GARM_REF=$(GARM_REF) -e USER_GROUP=$(USER_GROUP) -v $(PWD)/build:/build/output:z $(IMAGE_TAG) /build-static.sh
@echo Binaries are available in $(PWD)/build
create-release-files:
./scripts/make-release.sh
release: build-static create-release-files
clean:
clean: ## Clean up build artifacts
@rm -rf ./bin ./build ./release
build:
.PHONY: build
build: ## Build garm
@echo Building garm ${VERSION}
$(shell mkdir -p ./bin)
@$(GO) build -ldflags "-s -w -X main.Version=${VERSION}" -tags osusergo,netgo,sqlite_omit_load_extension -o bin/garm ./cmd/garm
@$(GO) build -ldflags "-s -w -X github.com/cloudbase/garm/cmd/garm-cli/cmd.Version=${VERSION}" -tags osusergo,netgo,sqlite_omit_load_extension -o bin/garm-cli ./cmd/garm-cli
@echo Binaries are available in $(PWD)/bin
test: verify go-test
test: verify go-test ## Run tests
install-lint-deps:
@$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
##@ Release
create-release-files:
./scripts/make-release.sh
lint:
@golangci-lint run --timeout=8m --build-tags testing
release: build-static create-release-files ## Create a release
go-test:
@$(GO) test -race -mod=vendor -tags testing -v $(TEST_ARGS) -timeout=15m -parallel=4 -count=1 ./...
##@ Lint / Verify
.PHONY: lint
lint: golangci-lint $(GOLANGCI_LINT) ## Run linting.
$(GOLANGCI_LINT) run -v --build-tags testing $(GOLANGCI_LINT_EXTRA_ARGS)
fmt:
@$(GO) fmt $$(go list ./...)
fmtcheck:
@gofmt -l -s $$(go list ./... | sed 's|github.com/cloudbase/garm/||g') | grep ".*\.go"; if [ "$$?" -eq 0 ]; then echo "gofmt check failed; please run gofmt -w -s"; exit 1;fi
.PHONY: lint-fix
lint-fix: golangci-lint $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linte
GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date
$(eval TMPDIR := $(shell mktemp -d))
@ -59,4 +61,32 @@ verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date
@diff -r -u -q ${ROOTDIR} ${TMPDIR}/garm >/dev/null 2>&1; if [ "$$?" -ne 0 ];then echo "please run: go mod tidy && go mod vendor"; exit 1; fi
@rm -rf ${TMPDIR}
verify: verify-vendor lint fmtcheck
verify: verify-vendor lint fmtcheck ## Run all verify-* targets
##@ Development
go-test: ## Run tests
@$(GO) test -race -mod=vendor -tags testing -v $(TEST_ARGS) -timeout=15m -parallel=4 -count=1 ./...
fmt: ## Run go fmt against code.
@$(GO) fmt $$(go list ./...)
##@ Build Dependencies
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
## Tool Versions
GOLANGCI_LINT_VERSION ?= v1.56.2
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. If wrong version is installed, it will be overwritten.
$(GOLANGCI_LINT): $(LOCALBIN)
test -s $(LOCALBIN)/golangci-lint && $(LOCALBIN)/golangci-lint --version | grep -q $(GOLANGCI_LINT_VERSION) || \
GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)

View file

@ -22,18 +22,18 @@ import (
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/apiserver/params"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/metrics"
runnerParams "github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner"
"github.com/cloudbase/garm/runner" //nolint:typecheck
wsWriter "github.com/cloudbase/garm/websocket"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
)
func NewAPIController(r *runner.Runner, authenticator *auth.Authenticator, hub *wsWriter.Hub) (*APIController, error) {
@ -107,19 +107,21 @@ func (a *APIController) handleWorkflowJobEvent(ctx context.Context, w http.Respo
hookType := r.Header.Get("X-Github-Hook-Installation-Target-Type")
if err := a.r.DispatchWorkflowJob(hookType, signature, body); err != nil {
if errors.Is(err, gErrors.ErrNotFound) {
switch {
case errors.Is(err, gErrors.ErrNotFound):
metrics.WebhooksReceived.WithLabelValues(
"false", // label: valid
"owner_unknown", // label: reason
).Inc()
slog.With(slog.Any("error", err)).ErrorContext(ctx, "got not found error from DispatchWorkflowJob. webhook not meant for us?")
return
} else if strings.Contains(err.Error(), "signature") { // TODO: check error type
case strings.Contains(err.Error(), "signature"):
// nolint:golangci-lint,godox TODO: check error type
metrics.WebhooksReceived.WithLabelValues(
"false", // label: valid
"signature_invalid", // label: reason
).Inc()
} else {
default:
metrics.WebhooksReceived.WithLabelValues(
"false", // label: valid
"unknown", // label: reason
@ -182,6 +184,7 @@ func (a *APIController) WSHandler(writer http.ResponseWriter, req *http.Request)
return
}
// nolint:golangci-lint,godox
// TODO (gsamfira): Handle ExpiresAt. Right now, if a client uses
// a valid token to authenticate, and keeps the websocket connection
// open, it will allow that client to stream logs via websockets

View file

@ -19,11 +19,11 @@ import (
"log/slog"
"net/http"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux"
)
// swagger:route POST /enterprises enterprises CreateEnterprise
@ -165,7 +165,6 @@ func (a *APIController) DeleteEnterpriseHandler(w http.ResponseWriter, r *http.R
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /enterprises/{enterpriseID} enterprises UpdateEnterprise
@ -318,7 +317,6 @@ func (a *APIController) ListEnterprisePoolsHandler(w http.ResponseWriter, r *htt
if err := json.NewEncoder(w).Encode(pools); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
// swagger:route GET /enterprises/{enterpriseID}/pools/{poolID} enterprises pools GetEnterprisePool
@ -414,7 +412,6 @@ func (a *APIController) DeleteEnterprisePoolHandler(w http.ResponseWriter, r *ht
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /enterprises/{enterpriseID}/pools/{poolID} enterprises pools UpdateEnterprisePool

View file

@ -20,11 +20,11 @@ import (
"net/http"
"strconv"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux"
)
// swagger:route GET /pools/{poolID}/instances instances ListPoolInstances

View file

@ -20,8 +20,9 @@ import (
"log/slog"
"net/http"
"github.com/cloudbase/garm/apiserver/params"
"github.com/gorilla/mux"
"github.com/cloudbase/garm/apiserver/params"
)
func (a *APIController) InstanceGithubRegistrationTokenHandler(w http.ResponseWriter, r *http.Request) {

View file

@ -20,11 +20,11 @@ import (
"net/http"
"strconv"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux"
)
// swagger:route POST /organizations organizations CreateOrg
@ -174,7 +174,6 @@ func (a *APIController) DeleteOrgHandler(w http.ResponseWriter, r *http.Request)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /organizations/{orgID} organizations UpdateOrg
@ -423,7 +422,6 @@ func (a *APIController) DeleteOrgPoolHandler(w http.ResponseWriter, r *http.Requ
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /organizations/{orgID}/pools/{poolID} organizations pools UpdateOrgPool

View file

@ -19,11 +19,11 @@ import (
"log/slog"
"net/http"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux"
)
// swagger:route GET /pools pools ListPools
@ -37,7 +37,6 @@ func (a *APIController) ListAllPoolsHandler(w http.ResponseWriter, r *http.Reque
ctx := r.Context()
pools, err := a.r.ListAllPools(ctx)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "listing pools")
handleError(ctx, w, err)

View file

@ -20,11 +20,11 @@ import (
"net/http"
"strconv"
"github.com/gorilla/mux"
gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/apiserver/params"
runnerParams "github.com/cloudbase/garm/params"
"github.com/gorilla/mux"
)
// swagger:route POST /repositories repositories CreateRepo
@ -173,7 +173,6 @@ func (a *APIController) DeleteRepoHandler(w http.ResponseWriter, r *http.Request
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /repositories/{repoID} repositories UpdateRepo
@ -422,7 +421,6 @@ func (a *APIController) DeleteRepoPoolHandler(w http.ResponseWriter, r *http.Req
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// swagger:route PUT /repositories/{repoID}/pools/{poolID} repositories pools UpdateRepoPool

View file

@ -49,7 +49,7 @@ import (
_ "expvar" // Register the expvar handlers
"log/slog"
"net/http"
_ "net/http/pprof" // Register the pprof handlers
_ "net/http/pprof" //nolint:golangci-lint,gosec // Register the pprof handlers
"github.com/felixge/httpsnoop"
"github.com/gorilla/mux"
@ -87,7 +87,6 @@ func requestLogger(h http.Handler) http.Handler {
// gathers metrics from the upstream handlers
metrics := httpsnoop.CaptureMetrics(h, w, r)
//prints log and metrics
slog.Info(
"access_log",
slog.String("method", r.Method),

View file

@ -18,16 +18,16 @@ import (
"context"
"time"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/nbutton23/zxcvbn-go"
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/nbutton23/zxcvbn-go"
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
)
func NewAuthenticator(cfg config.JWTAuth, store common.Store) *Authenticator {
@ -58,6 +58,7 @@ func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) {
claims := JWTClaims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: expires,
// nolint:golangci-lint,godox
// TODO: make this configurable
Issuer: "garm",
},
@ -78,7 +79,6 @@ func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) {
// GetJWTMetricsToken returns a JWT token that can be used to read metrics.
// This token is not tied to a user, no user is stored in the db.
func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error) {
if !IsAdmin(ctx) {
return "", runnerErrors.ErrUnauthorized
}
@ -87,6 +87,7 @@ func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error)
if err != nil {
return "", errors.Wrap(err, "generating random string")
}
// nolint:golangci-lint,godox
// TODO: currently this is the same TTL as the normal Token
// maybe we should make this configurable
// it's usually pretty nasty if the monitoring fails because the token expired
@ -97,6 +98,7 @@ func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error)
claims := JWTClaims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: expires,
// nolint:golangci-lint,godox
// TODO: make this configurable
Issuer: "garm",
},

View file

@ -22,15 +22,15 @@ import (
"strings"
"time"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/config"
dbCommon "github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/pkg/errors"
)
// InstanceJWTClaims holds JWT claims
@ -111,6 +111,7 @@ func (amw *instanceMiddleware) claimsToContext(ctx context.Context, claims *Inst
// Middleware implements the middleware interface
func (amw *instanceMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// nolint:golangci-lint,godox
// TODO: Log error details when authentication fails
ctx := r.Context()
authorizationHeader := r.Header.Get("authorization")
@ -132,7 +133,6 @@ func (amw *instanceMiddleware) Middleware(next http.Handler) http.Handler {
}
return []byte(amw.cfg.Secret), nil
})
if err != nil {
invalidAuthResponse(ctx, w)
return

View file

@ -22,12 +22,12 @@ import (
"net/http"
"strings"
jwt "github.com/golang-jwt/jwt/v5"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
apiParams "github.com/cloudbase/garm/apiserver/params"
"github.com/cloudbase/garm/config"
dbCommon "github.com/cloudbase/garm/database/common"
jwt "github.com/golang-jwt/jwt/v5"
)
// JWTClaims holds JWT claims
@ -87,6 +87,7 @@ func invalidAuthResponse(ctx context.Context, w http.ResponseWriter) {
// Middleware implements the middleware interface
func (amw *jwtMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// nolint:golangci-lint,godox
// TODO: Log error details when authentication fails
ctx := r.Context()
authorizationHeader := r.Header.Get("authorization")
@ -108,7 +109,6 @@ func (amw *jwtMiddleware) Middleware(next http.Handler) http.Handler {
}
return []byte(amw.cfg.Secret), nil
})
if err != nil {
invalidAuthResponse(ctx, w)
return

View file

@ -6,9 +6,9 @@ import (
"net/http"
"strings"
"github.com/cloudbase/garm/config"
jwt "github.com/golang-jwt/jwt/v5"
"github.com/cloudbase/garm/config"
)
type MetricsMiddleware struct {
@ -23,7 +23,6 @@ func NewMetricsMiddleware(cfg config.JWTAuth) (*MetricsMiddleware, error) {
func (m *MetricsMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
authorizationHeader := r.Header.Get("authorization")
if authorizationHeader == "" {
@ -44,7 +43,6 @@ func (m *MetricsMiddleware) Middleware(next http.Handler) http.Handler {
}
return []byte(m.cfg.Secret), nil
})
if err != nil {
invalidAuthResponse(ctx, w)
return

View file

@ -17,10 +17,11 @@ package cmd
import (
"fmt"
apiClientControllerInfo "github.com/cloudbase/garm/client/controller_info"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientControllerInfo "github.com/cloudbase/garm/client/controller_info"
"github.com/cloudbase/garm/params"
)
var infoCmd = &cobra.Command{
@ -36,7 +37,7 @@ var infoShowCmd = &cobra.Command{
Short: "Show information",
Long: `Show information about the current controller.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}

View file

@ -17,11 +17,11 @@ package cmd
import (
"fmt"
apiClientCreds "github.com/cloudbase/garm/client/credentials"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientCreds "github.com/cloudbase/garm/client/credentials"
"github.com/cloudbase/garm/params"
)
// credentialsCmd represents the credentials command
@ -34,7 +34,7 @@ config file.
Currently, github personal tokens are configured statically in the config file
of the garm service. This command lists the names of those credentials,
which in turn can be used to define pools of runners withing repositories.`,
which in turn can be used to define pools of runners within repositories.`,
Run: nil,
}
@ -44,9 +44,9 @@ func init() {
Use: "list",
Aliases: []string{"ls"},
Short: "List configured github credentials",
Long: `List the names of the github personal access tokens availabe to the garm.`,
Long: `List the names of the github personal access tokens available to the garm.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}

View file

@ -17,11 +17,11 @@ package cmd
import (
"fmt"
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
"github.com/cloudbase/garm/params"
)
var (
@ -50,7 +50,7 @@ var enterpriseAddCmd = &cobra.Command{
Short: "Add enterprise",
Long: `Add a new enterprise to the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -76,7 +76,7 @@ var enterpriseListCmd = &cobra.Command{
Short: "List enterprises",
Long: `List all configured enterprises that are currently managed.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -96,7 +96,7 @@ var enterpriseShowCmd = &cobra.Command{
Short: "Show details for one enterprise",
Long: `Displays detailed information about a single enterprise.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -123,7 +123,7 @@ var enterpriseDeleteCmd = &cobra.Command{
Short: "Removes one enterprise",
Long: `Delete one enterprise from the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -147,7 +147,7 @@ var enterpriseUpdateCmd = &cobra.Command{
Short: "Update enterprise",
Long: `Update enterprise credentials or webhook secret.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -175,7 +175,6 @@ var enterpriseUpdateCmd = &cobra.Command{
}
func init() {
enterpriseAddCmd.Flags().StringVar(&enterpriseName, "name", "", "The name of the enterprise")
enterpriseAddCmd.Flags().StringVar(&enterpriseWebhookSecret, "webhook-secret", "", "The webhook secret for this enterprise")
enterpriseAddCmd.Flags().StringVar(&enterpriseCreds, "credentials", "", "Credentials name. See credentials list.")

View file

@ -18,15 +18,15 @@ import (
"fmt"
"strings"
"github.com/cloudbase/garm/cmd/garm-cli/common"
"github.com/cloudbase/garm/cmd/garm-cli/config"
"github.com/cloudbase/garm/params"
apiClientFirstRun "github.com/cloudbase/garm/client/first_run"
apiClientLogin "github.com/cloudbase/garm/client/login"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/pkg/errors"
"github.com/spf13/cobra"
apiClientFirstRun "github.com/cloudbase/garm/client/first_run"
apiClientLogin "github.com/cloudbase/garm/client/login"
"github.com/cloudbase/garm/cmd/garm-cli/common"
"github.com/cloudbase/garm/cmd/garm-cli/config"
"github.com/cloudbase/garm/params"
)
// initCmd represents the init command
@ -45,7 +45,7 @@ Example usage:
garm-cli init --name=dev --url=https://runner.example.com --username=admin --password=superSecretPassword
`,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if cfg != nil {
if cfg.HasManager(loginProfileName) {
return fmt.Errorf("a manager with name %s already exists in your local config", loginProfileName)
@ -66,7 +66,7 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
url := strings.TrimSuffix(loginURL, "/")
initApiClient(url, "")
initAPIClient(url, "")
response, err := apiCli.FirstRun.FirstRun(newUserReq, authToken)
if err != nil {

View file

@ -18,11 +18,12 @@ import (
"fmt"
"strings"
apiClientJobs "github.com/cloudbase/garm/client/jobs"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientJobs "github.com/cloudbase/garm/client/jobs"
"github.com/cloudbase/garm/params"
)
// runnerCmd represents the runner command
@ -40,7 +41,7 @@ var jobsListCmd = &cobra.Command{
Short: "List jobs",
Long: `List all jobs currently recorded in the system.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}

View file

@ -11,11 +11,11 @@ import (
"os/signal"
"time"
"github.com/cloudbase/garm-provider-common/util"
apiParams "github.com/cloudbase/garm/apiserver/params"
"github.com/gorilla/websocket"
"github.com/spf13/cobra"
"github.com/cloudbase/garm-provider-common/util"
apiParams "github.com/cloudbase/garm/apiserver/params"
)
var logCmd = &cobra.Command{
@ -23,7 +23,7 @@ var logCmd = &cobra.Command{
SilenceUsage: true,
Short: "Stream garm log",
Long: `Stream all garm logging to the terminal.`,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)

View file

@ -17,8 +17,9 @@ package cmd
import (
"fmt"
apiClientMetricToken "github.com/cloudbase/garm/client/metrics_token"
"github.com/spf13/cobra"
apiClientMetricToken "github.com/cloudbase/garm/client/metrics_token"
)
// orgPoolCmd represents the pool command
@ -35,7 +36,7 @@ var metricsTokenCreateCmd = &cobra.Command{
Short: "Create a metrics token",
Long: `Create a metrics token.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}

View file

@ -17,12 +17,12 @@ package cmd
import (
"fmt"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"github.com/cloudbase/garm-provider-common/util"
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)
var (
@ -62,7 +62,7 @@ var orgWebhookInstallCmd = &cobra.Command{
Short: "Install webhook",
Long: `Install webhook for an organization.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -92,7 +92,7 @@ var orgHookInfoShowCmd = &cobra.Command{
Short: "Show webhook info",
Long: `Show webhook info for an organization.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -120,7 +120,7 @@ var orgWebhookUninstallCmd = &cobra.Command{
Short: "Uninstall webhook",
Long: `Uninstall webhook for an organization.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -148,7 +148,7 @@ var orgAddCmd = &cobra.Command{
Short: "Add organization",
Long: `Add a new organization to the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -199,7 +199,7 @@ var orgUpdateCmd = &cobra.Command{
Short: "Update organization",
Long: `Update organization credentials or webhook secret.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -232,7 +232,7 @@ var orgListCmd = &cobra.Command{
Short: "List organizations",
Long: `List all configured organizations that are currently managed.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -252,7 +252,7 @@ var orgShowCmd = &cobra.Command{
Short: "Show details for one organization",
Long: `Displays detailed information about a single organization.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -279,7 +279,7 @@ var orgDeleteCmd = &cobra.Command{
Short: "Removes one organization",
Long: `Delete one organization from the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -300,7 +300,6 @@ var orgDeleteCmd = &cobra.Command{
}
func init() {
orgAddCmd.Flags().StringVar(&orgName, "name", "", "The name of the organization")
orgAddCmd.Flags().StringVar(&orgWebhookSecret, "webhook-secret", "", "The webhook secret for this organization")
orgAddCmd.Flags().StringVar(&orgCreds, "credentials", "", "Credentials name. See credentials list.")

View file

@ -20,18 +20,16 @@ import (
"os"
"strings"
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
apiClientPools "github.com/cloudbase/garm/client/pools"
apiClientRepos "github.com/cloudbase/garm/client/repositories"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/pkg/errors"
"github.com/spf13/cobra"
commonParams "github.com/cloudbase/garm-provider-common/params"
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
apiClientPools "github.com/cloudbase/garm/client/pools"
apiClientRepos "github.com/cloudbase/garm/client/repositories"
"github.com/cloudbase/garm/params"
)
var (
@ -141,7 +139,7 @@ var poolShowCmd = &cobra.Command{
Short: "Show details for a runner",
Long: `Displays a detailed view of a single runner.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -171,7 +169,7 @@ var poolDeleteCmd = &cobra.Command{
Short: "Delete pool by ID",
Long: `Delete one pool by referencing it's ID, regardless of repo or org.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -199,7 +197,7 @@ var poolAddCmd = &cobra.Command{
Short: "Add pool",
Long: `Add a new pool to a repository or organization.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -381,8 +379,8 @@ explicitly remove them using the runner delete command.
func init() {
poolListCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "List all pools within this repository.")
poolListCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "List all pools withing this organization.")
poolListCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "List all pools withing this enterprise.")
poolListCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "List all pools within this organization.")
poolListCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "List all pools within this enterprise.")
poolListCmd.Flags().BoolVarP(&poolAll, "all", "a", false, "List all pools, regardless of org or repo.")
poolListCmd.MarkFlagsMutuallyExclusive("repo", "org", "all", "enterprise")
@ -421,8 +419,8 @@ func init() {
poolAddCmd.MarkFlagRequired("tags") //nolint
poolAddCmd.Flags().StringVarP(&poolRepository, "repo", "r", "", "Add the new pool within this repository.")
poolAddCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "Add the new pool withing this organization.")
poolAddCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "Add the new pool withing this enterprise.")
poolAddCmd.Flags().StringVarP(&poolOrganization, "org", "o", "", "Add the new pool within this organization.")
poolAddCmd.Flags().StringVarP(&poolEnterprise, "enterprise", "e", "", "Add the new pool within this enterprise.")
poolAddCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise")
poolAddCmd.MarkFlagsMutuallyExclusive("extra-specs-file", "extra-specs")
@ -453,13 +451,13 @@ func asRawMessage(data []byte) (json.RawMessage, error) {
return nil, errors.Wrap(err, "decoding extra specs")
}
var asRawJson json.RawMessage
var asRawJSON json.RawMessage
var err error
asRawJson, err = json.Marshal(unmarshaled)
asRawJSON, err = json.Marshal(unmarshaled)
if err != nil {
return nil, errors.Wrap(err, "marshaling json")
}
return asRawJson, nil
return asRawJSON, nil
}
func formatPools(pools []params.Pool) {
@ -475,13 +473,14 @@ func formatPools(pools []params.Pool) {
var belongsTo string
var level string
if pool.RepoID != "" && pool.RepoName != "" {
switch {
case pool.RepoID != "" && pool.RepoName != "":
belongsTo = pool.RepoName
level = "repo"
} else if pool.OrgID != "" && pool.OrgName != "" {
case pool.OrgID != "" && pool.OrgName != "":
belongsTo = pool.OrgName
level = "org"
} else if pool.EnterpriseID != "" && pool.EnterpriseName != "" {
case pool.EnterpriseID != "" && pool.EnterpriseName != "":
belongsTo = pool.EnterpriseName
level = "enterprise"
}
@ -505,13 +504,14 @@ func formatOnePool(pool params.Pool) {
var belongsTo string
var level string
if pool.RepoID != "" && pool.RepoName != "" {
switch {
case pool.RepoID != "" && pool.RepoName != "":
belongsTo = pool.RepoName
level = "repo"
} else if pool.OrgID != "" && pool.OrgName != "" {
case pool.OrgID != "" && pool.OrgName != "":
belongsTo = pool.OrgName
level = "org"
} else if pool.EnterpriseID != "" && pool.EnterpriseName != "" {
case pool.EnterpriseID != "" && pool.EnterpriseName != "":
belongsTo = pool.EnterpriseName
level = "enterprise"
}
@ -532,7 +532,7 @@ func formatOnePool(pool params.Pool) {
t.AppendRow(table.Row{"Enabled", pool.Enabled})
t.AppendRow(table.Row{"Runner Prefix", pool.GetRunnerPrefix()})
t.AppendRow(table.Row{"Extra specs", string(pool.ExtraSpecs)})
t.AppendRow(table.Row{"GitHub Runner Group", string(pool.GitHubRunnerGroup)})
t.AppendRow(table.Row{"GitHub Runner Group", pool.GitHubRunnerGroup})
if len(pool.Instances) > 0 {
for _, instance := range pool.Instances {

View file

@ -18,13 +18,13 @@ import (
"fmt"
"strings"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientLogin "github.com/cloudbase/garm/client/login"
"github.com/cloudbase/garm/cmd/garm-cli/common"
"github.com/cloudbase/garm/cmd/garm-cli/config"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)
var (
@ -55,7 +55,7 @@ This command will list all currently defined profiles in the local configuration
file of the garm client.
`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -76,7 +76,7 @@ var profileDeleteCmd = &cobra.Command{
Short: "Delete profile",
Long: `Delete a profile from the local CLI configuration.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -101,7 +101,7 @@ var poolSwitchCmd = &cobra.Command{
Short: "Switch to a different profile",
Long: `Switch the CLI to a different profile.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -132,7 +132,7 @@ var profileAddCmd = &cobra.Command{
Short: "Add profile",
Long: `Create a profile for a new garm installation.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if cfg != nil {
if cfg.HasManager(loginProfileName) {
return fmt.Errorf("a manager with name %s already exists in your local config", loginProfileName)
@ -145,7 +145,7 @@ var profileAddCmd = &cobra.Command{
url := strings.TrimSuffix(loginURL, "/")
initApiClient(url, "")
initAPIClient(url, "")
newLoginParamsReq := apiClientLogin.NewLoginParams()
newLoginParamsReq.Body = params.PasswordLoginParams{
@ -180,7 +180,7 @@ This command will refresh the bearer token associated with an already defined ga
installation, by performing a login.
`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}

View file

@ -17,11 +17,11 @@ package cmd
import (
"fmt"
apiClientProviders "github.com/cloudbase/garm/client/providers"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientProviders "github.com/cloudbase/garm/client/providers"
"github.com/cloudbase/garm/params"
)
// providerCmd represents the provider command
@ -45,7 +45,7 @@ func init() {
Short: "List all configured providers",
Long: `List all cloud providers configured with the service.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}

View file

@ -17,12 +17,12 @@ package cmd
import (
"fmt"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"github.com/cloudbase/garm-provider-common/util"
apiClientRepos "github.com/cloudbase/garm/client/repositories"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)
var (
@ -63,7 +63,7 @@ var repoWebhookInstallCmd = &cobra.Command{
Short: "Install webhook",
Long: `Install webhook for a repository.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -93,7 +93,7 @@ var repoHookInfoShowCmd = &cobra.Command{
Short: "Show webhook info",
Long: `Show webhook info for a repository.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -121,7 +121,7 @@ var repoWebhookUninstallCmd = &cobra.Command{
Short: "Uninstall webhook",
Long: `Uninstall webhook for a repository.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -149,7 +149,7 @@ var repoAddCmd = &cobra.Command{
Short: "Add repository",
Long: `Add a new repository to the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -200,9 +200,9 @@ var repoListCmd = &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List repositories",
Long: `List all configured respositories that are currently managed.`,
Long: `List all configured repositories that are currently managed.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
if needsInit {
return errNeedsInitError
}
@ -222,7 +222,7 @@ var repoUpdateCmd = &cobra.Command{
Short: "Update repository",
Long: `Update repository credentials or webhook secret.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -255,7 +255,7 @@ var repoShowCmd = &cobra.Command{
Short: "Show details for one repository",
Long: `Displays detailed information about a single repository.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -282,7 +282,7 @@ var repoDeleteCmd = &cobra.Command{
Short: "Removes one repository",
Long: `Delete one repository from the manager.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -303,7 +303,6 @@ var repoDeleteCmd = &cobra.Command{
}
func init() {
repoAddCmd.Flags().StringVar(&repoOwner, "owner", "", "The owner of this repository")
repoAddCmd.Flags().StringVar(&repoName, "name", "", "The name of the repository")
repoAddCmd.Flags().StringVar(&repoWebhookSecret, "webhook-secret", "", "The webhook secret for this repository")

View file

@ -19,14 +19,14 @@ import (
"net/url"
"os"
"github.com/go-openapi/runtime"
openapiRuntimeClient "github.com/go-openapi/runtime/client"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClient "github.com/cloudbase/garm/client"
"github.com/cloudbase/garm/cmd/garm-cli/config"
"github.com/cloudbase/garm/params"
"github.com/go-openapi/runtime"
"github.com/jedib0t/go-pretty/v6/table"
openapiRuntimeClient "github.com/go-openapi/runtime/client"
"github.com/spf13/cobra"
)
var Version string
@ -60,24 +60,24 @@ func Execute() {
}
}
func initApiClient(baseUrl, token string) {
baseUrlParsed, err := url.Parse(baseUrl)
func initAPIClient(baseURL, token string) {
baseURLParsed, err := url.Parse(baseURL)
if err != nil {
fmt.Printf("Failed to parse base url %s: %s", baseUrl, err)
fmt.Printf("Failed to parse base url %s: %s", baseURL, err)
os.Exit(1)
}
apiPath, err := url.JoinPath(baseUrlParsed.Path, apiClient.DefaultBasePath)
apiPath, err := url.JoinPath(baseURLParsed.Path, apiClient.DefaultBasePath)
if err != nil {
fmt.Printf("Failed to join base url path %s with %s: %s", baseUrlParsed.Path, apiClient.DefaultBasePath, err)
fmt.Printf("Failed to join base url path %s with %s: %s", baseURLParsed.Path, apiClient.DefaultBasePath, err)
os.Exit(1)
}
if debug {
os.Setenv("SWAGGER_DEBUG", "true")
}
transportCfg := apiClient.DefaultTransportConfig().
WithHost(baseUrlParsed.Host).
WithHost(baseURLParsed.Host).
WithBasePath(apiPath).
WithSchemes([]string{baseUrlParsed.Scheme})
WithSchemes([]string{baseURLParsed.Scheme})
apiCli = apiClient.NewHTTPClientWithConfig(nil, transportCfg)
authToken = openapiRuntimeClient.BearerToken(token)
}
@ -98,7 +98,7 @@ func initConfig() {
mgr = cfg.Managers[0]
}
}
initApiClient(mgr.BaseURL, mgr.Token)
initAPIClient(mgr.BaseURL, mgr.Token)
}
func formatOneHookInfo(hook params.HookInfo) {

View file

@ -18,14 +18,14 @@ import (
"fmt"
"os"
"github.com/cloudbase/garm/params"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
apiClientEnterprises "github.com/cloudbase/garm/client/enterprises"
apiClientInstances "github.com/cloudbase/garm/client/instances"
apiClientOrgs "github.com/cloudbase/garm/client/organizations"
apiClientRepos "github.com/cloudbase/garm/client/repositories"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"github.com/cloudbase/garm/params"
)
var (
@ -139,7 +139,7 @@ var runnerShowCmd = &cobra.Command{
Short: "Show details for a runner",
Long: `Displays a detailed view of a single runner.`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -178,7 +178,7 @@ NOTE: An active runner cannot be removed from Github. You will have
to either cancel the workflow or wait for it to finish.
`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, args []string) error {
if needsInit {
return errNeedsInitError
}
@ -199,8 +199,8 @@ to either cancel the workflow or wait for it to finish.
func init() {
runnerListCmd.Flags().StringVarP(&runnerRepository, "repo", "r", "", "List all runners from all pools within this repository.")
runnerListCmd.Flags().StringVarP(&runnerOrganization, "org", "o", "", "List all runners from all pools withing this organization.")
runnerListCmd.Flags().StringVarP(&runnerEnterprise, "enterprise", "e", "", "List all runners from all pools withing this enterprise.")
runnerListCmd.Flags().StringVarP(&runnerOrganization, "org", "o", "", "List all runners from all pools within this organization.")
runnerListCmd.Flags().StringVarP(&runnerEnterprise, "enterprise", "e", "", "List all runners from all pools within this enterprise.")
runnerListCmd.Flags().BoolVarP(&runnerAll, "all", "a", false, "List all runners, regardless of org or repo.")
runnerListCmd.MarkFlagsMutuallyExclusive("repo", "org", "enterprise", "all")

View file

@ -25,7 +25,7 @@ var versionCmd = &cobra.Command{
Use: "version",
SilenceUsage: true,
Short: "Print version and exit",
Run: func(cmd *cobra.Command, args []string) {
Run: func(_ *cobra.Command, _ []string) {
fmt.Println(Version)
},
}

View file

@ -39,7 +39,6 @@ func PromptPassword(label string) (string, error) {
Mask: '*',
}
result, err := prompt.Run()
if err != nil {
return "", err
}
@ -59,7 +58,6 @@ func PromptString(label string) (string, error) {
Validate: validate,
}
result, err := prompt.Run()
if err != nil {
return "", err
}

View file

@ -12,7 +12,6 @@ import (
func getHomeDir() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", errors.Wrap(err, "fetching home dir")
}

View file

@ -28,6 +28,11 @@ import (
"syscall"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/pkg/errors"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/apiserver/controllers"
"github.com/cloudbase/garm/apiserver/routers"
@ -36,16 +41,11 @@ import (
"github.com/cloudbase/garm/database"
"github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/metrics"
"github.com/cloudbase/garm/runner"
"github.com/cloudbase/garm/runner" //nolint:typecheck
runnerMetrics "github.com/cloudbase/garm/runner/metrics"
garmUtil "github.com/cloudbase/garm/util"
"github.com/cloudbase/garm/util/appdefaults"
"github.com/cloudbase/garm/websocket"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)
var (
@ -98,7 +98,7 @@ func setupLogging(ctx context.Context, logCfg config.Logging, hub *websocket.Hub
}
}()
var writers []io.Writer = []io.Writer{
writers := []io.Writer{
logWriter,
}
@ -140,7 +140,6 @@ func setupLogging(ctx context.Context, logCfg config.Logging, hub *websocket.Hub
Handler: han,
}
slog.SetDefault(slog.New(wrapped))
}
func main() {
@ -154,7 +153,7 @@ func main() {
cfg, err := config.NewConfig(*conf)
if err != nil {
log.Fatalf("Fetching config: %+v", err)
log.Fatalf("Fetching config: %+v", err) //nolint:gocritic
}
logCfg := cfg.GetLoggingConfig()
@ -241,6 +240,8 @@ func main() {
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS", "DELETE"})
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})
// nolint:golangci-lint,gosec
// G112: Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server
srv := &http.Server{
Addr: cfg.APIServer.BindAddress(),
// Pass our instance of gorilla/mux in.

View file

@ -26,15 +26,18 @@ import (
"time"
"github.com/BurntSushi/toml"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/util/appdefaults"
zxcvbn "github.com/nbutton23/zxcvbn-go"
"github.com/pkg/errors"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/util/appdefaults"
)
type DBBackendType string
type LogLevel string
type LogFormat string
type (
DBBackendType string
LogLevel string
LogFormat string
)
const (
// MySQLBackend represents the MySQL DB backend
@ -120,7 +123,7 @@ func (c *Config) Validate() error {
if err := provider.Validate(); err != nil {
return errors.Wrap(err, "validating provider")
}
providerNames[provider.Name] += 1
providerNames[provider.Name]++
}
for name, count := range providerNames {
@ -543,6 +546,7 @@ func (d *timeToLive) Duration() time.Duration {
slog.With(slog.Any("error", err)).Error("failed to parse duration")
return appdefaults.DefaultJWTTTL
}
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): should we have a minimum TTL?
if duration < appdefaults.DefaultJWTTTL {
return appdefaults.DefaultJWTTTL

View file

@ -20,11 +20,13 @@ import (
"testing"
"time"
"github.com/cloudbase/garm/util/appdefaults"
"github.com/stretchr/testify/require"
"github.com/cloudbase/garm/util/appdefaults"
)
var (
// nolint: golangci-lint,gosec
EncryptionPassphrase = "bocyasicgatEtenOubwonIbsudNutDom"
WeakEncryptionPassphrase = "1234567890abcdefghijklmnopqrstuv"
)
@ -392,7 +394,6 @@ func TestGormParams(t *testing.T) {
require.Nil(t, err)
require.Equal(t, MySQLBackend, dbType)
require.Equal(t, "test:test@tcp(127.0.0.1)/garm?charset=utf8&parseTime=True&loc=Local&timeout=5s", uri)
}
func TestSQLiteConfig(t *testing.T) {

View file

@ -20,9 +20,9 @@ import (
"path/filepath"
"strings"
"github.com/cloudbase/garm-provider-common/util/exec"
"github.com/pkg/errors"
"github.com/cloudbase/garm-provider-common/util/exec"
)
// External represents the config for an external provider.

View file

@ -31,7 +31,8 @@ func getDefaultExternalConfig(t *testing.T) External {
}
t.Cleanup(func() { os.RemoveAll(dir) })
err = os.WriteFile(filepath.Join(dir, "garm-external-provider"), []byte{}, 0755)
// nolint:golangci-lint,gosec
err = os.WriteFile(filepath.Join(dir, "garm-external-provider"), []byte{}, 0o755)
if err != nil {
t.Fatalf("failed to write file: %s", err)
}

View file

@ -28,7 +28,7 @@ type RepoStore interface {
DeleteRepository(ctx context.Context, repoID string) error
UpdateRepository(ctx context.Context, repoID string, param params.UpdateEntityParams) (params.Repository, error)
CreateRepositoryPool(ctx context.Context, repoId string, param params.CreatePoolParams) (params.Pool, error)
CreateRepositoryPool(ctx context.Context, repoID string, param params.CreatePoolParams) (params.Pool, error)
GetRepositoryPool(ctx context.Context, repoID, poolID string) (params.Pool, error)
DeleteRepositoryPool(ctx context.Context, repoID, poolID string) error
@ -47,7 +47,7 @@ type OrgStore interface {
DeleteOrganization(ctx context.Context, orgID string) error
UpdateOrganization(ctx context.Context, orgID string, param params.UpdateEntityParams) (params.Organization, error)
CreateOrganizationPool(ctx context.Context, orgId string, param params.CreatePoolParams) (params.Pool, error)
CreateOrganizationPool(ctx context.Context, orgID string, param params.CreatePoolParams) (params.Pool, error)
GetOrganizationPool(ctx context.Context, orgID, poolID string) (params.Pool, error)
DeleteOrganizationPool(ctx context.Context, orgID, poolID string) error
UpdateOrganizationPool(ctx context.Context, orgID, poolID string, param params.UpdatePoolParams) (params.Pool, error)
@ -77,6 +77,7 @@ type EnterpriseStore interface {
type PoolStore interface {
// Probably a bad idea without some king of filter or at least pagination
// nolint:golangci-lint,godox
// TODO: add filter/pagination
ListAllPools(ctx context.Context) ([]params.Pool, error)
GetPoolByID(ctx context.Context, poolID string) (params.Pool, error)
@ -104,6 +105,8 @@ type InstanceStore interface {
UpdateInstance(ctx context.Context, instanceID string, param params.UpdateInstanceParams) (params.Instance, error)
// Probably a bad idea without some king of filter or at least pagination
//
// nolint:golangci-lint,godox
// TODO: add filter/pagination
ListAllInstances(ctx context.Context) ([]params.Instance, error)

View file

@ -0,0 +1,7 @@
package sql
const (
wrongPassphrase = "wrong-passphrase"
webhookSecret = "webhook-secret"
falseString = "false"
)

View file

@ -15,12 +15,12 @@
package sql
import (
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) ControllerInfo() (params.ControllerInfo, error) {

View file

@ -19,11 +19,11 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/stretchr/testify/suite"
garmTesting "github.com/cloudbase/garm/internal/testing" //nolint:typecheck
)
type CtrlTestSuite struct {

View file

@ -3,17 +3,17 @@ package sql
import (
"context"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes"
"gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) CreateEnterprise(ctx context.Context, name, credentialsName, webhookSecret string) (params.Enterprise, error) {
func (s *sqlDatabase) CreateEnterprise(_ context.Context, name, credentialsName, webhookSecret string) (params.Enterprise, error) {
if webhookSecret == "" {
return params.Enterprise{}, errors.New("creating enterprise: missing secret")
}
@ -66,7 +66,7 @@ func (s *sqlDatabase) GetEnterpriseByID(ctx context.Context, enterpriseID string
return param, nil
}
func (s *sqlDatabase) ListEnterprises(ctx context.Context) ([]params.Enterprise, error) {
func (s *sqlDatabase) ListEnterprises(_ context.Context) ([]params.Enterprise, error) {
var enterprises []Enterprise
q := s.conn.Find(&enterprises)
if q.Error != nil {
@ -181,8 +181,8 @@ func (s *sqlDatabase) CreateEnterprisePool(ctx context.Context, enterpriseID str
return params.Pool{}, errors.Wrap(q.Error, "adding pool")
}
for _, tt := range tags {
if err := s.conn.Model(&newPool).Association("Tags").Append(&tt); err != nil {
for i := range tags {
if err := s.conn.Model(&newPool).Association("Tags").Append(&tags[i]); err != nil {
return params.Pool{}, errors.Wrap(err, "saving tag")
}
}
@ -224,7 +224,7 @@ func (s *sqlDatabase) UpdateEnterprisePool(ctx context.Context, enterpriseID, po
return s.updatePool(pool, param)
}
func (s *sqlDatabase) FindEnterprisePoolByTags(ctx context.Context, enterpriseID string, tags []string) (params.Pool, error) {
func (s *sqlDatabase) FindEnterprisePoolByTags(_ context.Context, enterpriseID string, tags []string) (params.Pool, error) {
pool, err := s.findPoolByTags(enterpriseID, params.EnterprisePool, tags)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool")
@ -267,7 +267,7 @@ func (s *sqlDatabase) ListEnterpriseInstances(ctx context.Context, enterpriseID
return ret, nil
}
func (s *sqlDatabase) getEnterprise(ctx context.Context, name string) (Enterprise, error) {
func (s *sqlDatabase) getEnterprise(_ context.Context, name string) (Enterprise, error) {
var enterprise Enterprise
q := s.conn.Where("name = ? COLLATE NOCASE", name)
@ -281,7 +281,7 @@ func (s *sqlDatabase) getEnterprise(ctx context.Context, name string) (Enterpris
return enterprise, nil
}
func (s *sqlDatabase) getEnterpriseByID(ctx context.Context, id string, preload ...string) (Enterprise, error) {
func (s *sqlDatabase) getEnterpriseByID(_ context.Context, id string, preload ...string) (Enterprise, error) {
u, err := uuid.Parse(id)
if err != nil {
return Enterprise{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")

View file

@ -22,17 +22,16 @@ import (
"sort"
"testing"
"github.com/cloudbase/garm/params"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/stretchr/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
)
type EnterpriseTestFixtures struct {
@ -105,7 +104,7 @@ func (s *EnterpriseTestSuite) SetupTest() {
SkipInitializeWithVersion: true,
}
gormConfig := &gorm.Config{}
if flag.Lookup("test.v").Value.String() == "false" {
if flag.Lookup("test.v").Value.String() == falseString {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
gormConn, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)
@ -183,7 +182,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterpriseInvalidDBPassphrase() {
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
}
// make sure we use a 'sqlDatabase' struct with a wrong 'cfg.Passphrase'
cfg.Passphrase = "wrong-passphrase" // it must have a size different than 32
cfg.Passphrase = wrongPassphrase // it must have a size different than 32
sqlDB := &sqlDatabase{
conn: conn,
cfg: cfg,
@ -322,7 +321,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseInvalidEnterpriseID() {
}
func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBEncryptErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `enterprises` WHERE id = ? AND `enterprises`.`deleted_at` IS NULL ORDER BY `enterprises`.`id` LIMIT 1")).
@ -355,8 +354,8 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBSaveErr() {
}
func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBDecryptingErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.Fixtures.UpdateRepoParams.WebhookSecret = "webhook-secret"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.UpdateRepoParams.WebhookSecret = webhookSecret
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `enterprises` WHERE id = ? AND `enterprises`.`deleted_at` IS NULL ORDER BY `enterprises`.`id` LIMIT 1")).

View file

@ -18,15 +18,15 @@ import (
"context"
"encoding/json"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes"
"gorm.io/gorm"
"gorm.io/gorm/clause"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) marshalAndSeal(data interface{}) ([]byte, error) {
@ -92,7 +92,7 @@ func (s *sqlDatabase) CreateInstance(ctx context.Context, poolID string, param p
return s.sqlToParamsInstance(newInstance)
}
func (s *sqlDatabase) getInstanceByID(ctx context.Context, instanceID string) (Instance, error) {
func (s *sqlDatabase) getInstanceByID(_ context.Context, instanceID string) (Instance, error) {
u, err := uuid.Parse(instanceID)
if err != nil {
return Instance{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
@ -128,7 +128,7 @@ func (s *sqlDatabase) getPoolInstanceByName(ctx context.Context, poolID string,
return instance, nil
}
func (s *sqlDatabase) getInstanceByName(ctx context.Context, instanceName string, preload ...string) (Instance, error) {
func (s *sqlDatabase) getInstanceByName(_ context.Context, instanceName string, preload ...string) (Instance, error) {
var instance Instance
q := s.conn
@ -184,7 +184,7 @@ func (s *sqlDatabase) DeleteInstance(ctx context.Context, poolID string, instanc
return nil
}
func (s *sqlDatabase) ListInstanceEvents(ctx context.Context, instanceID string, eventType params.EventType, eventLevel params.EventLevel) ([]params.StatusMessage, error) {
func (s *sqlDatabase) ListInstanceEvents(_ context.Context, instanceID string, eventType params.EventType, eventLevel params.EventLevel) ([]params.StatusMessage, error) {
var events []InstanceStatusUpdate
query := s.conn.Model(&InstanceStatusUpdate{}).Where("instance_id = ?", instanceID)
if eventLevel != "" {
@ -296,7 +296,7 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceID string, par
return s.sqlToParamsInstance(instance)
}
func (s *sqlDatabase) ListPoolInstances(ctx context.Context, poolID string) ([]params.Instance, error) {
func (s *sqlDatabase) ListPoolInstances(_ context.Context, poolID string) ([]params.Instance, error) {
u, err := uuid.Parse(poolID)
if err != nil {
return nil, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
@ -319,7 +319,7 @@ func (s *sqlDatabase) ListPoolInstances(ctx context.Context, poolID string) ([]p
return ret, nil
}
func (s *sqlDatabase) ListAllInstances(ctx context.Context) ([]params.Instance, error) {
func (s *sqlDatabase) ListAllInstances(_ context.Context) ([]params.Instance, error) {
var instances []Instance
q := s.conn.Model(&Instance{}).Find(&instances)

View file

@ -22,18 +22,16 @@ import (
"sort"
"testing"
commonParams "github.com/cloudbase/garm-provider-common/params"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"github.com/stretchr/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
commonParams "github.com/cloudbase/garm-provider-common/params"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
)
type InstancesTestFixtures struct {
@ -131,7 +129,7 @@ func (s *InstancesTestSuite) SetupTest() {
SkipInitializeWithVersion: true,
}
gormConfig := &gorm.Config{}
if flag.Lookup("test.v").Value.String() == "false" {
if flag.Lookup("test.v").Value.String() == falseString {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
gormConn, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)

View file

@ -5,13 +5,14 @@ import (
"encoding/json"
"log/slog"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm"
"gorm.io/gorm/clause"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params"
)
var _ common.JobsStore = &sqlDatabase{}
@ -54,7 +55,7 @@ func sqlWorkflowJobToParamsJob(job WorkflowJob) (params.Job, error) {
}
func (s *sqlDatabase) paramsJobToWorkflowJob(ctx context.Context, job params.Job) (WorkflowJob, error) {
asJson, err := json.Marshal(job.Labels)
asJSON, err := json.Marshal(job.Labels)
if err != nil {
return WorkflowJob{}, errors.Wrap(err, "marshaling labels")
}
@ -76,7 +77,7 @@ func (s *sqlDatabase) paramsJobToWorkflowJob(ctx context.Context, job params.Job
RepoID: job.RepoID,
OrgID: job.OrgID,
EnterpriseID: job.EnterpriseID,
Labels: asJson,
Labels: asJSON,
LockedBy: job.LockedBy,
}
@ -92,7 +93,7 @@ func (s *sqlDatabase) paramsJobToWorkflowJob(ctx context.Context, job params.Job
return workflofJob, nil
}
func (s *sqlDatabase) DeleteJob(ctx context.Context, jobID int64) error {
func (s *sqlDatabase) DeleteJob(_ context.Context, jobID int64) error {
q := s.conn.Delete(&WorkflowJob{}, jobID)
if q.Error != nil {
if errors.Is(q.Error, gorm.ErrRecordNotFound) {
@ -103,7 +104,7 @@ func (s *sqlDatabase) DeleteJob(ctx context.Context, jobID int64) error {
return nil
}
func (s *sqlDatabase) LockJob(ctx context.Context, jobID int64, entityID string) error {
func (s *sqlDatabase) LockJob(_ context.Context, jobID int64, entityID string) error {
entityUUID, err := uuid.Parse(entityID)
if err != nil {
return errors.Wrap(err, "parsing entity id")
@ -136,7 +137,7 @@ func (s *sqlDatabase) LockJob(ctx context.Context, jobID int64, entityID string)
return nil
}
func (s *sqlDatabase) BreakLockJobIsQueued(ctx context.Context, jobID int64) error {
func (s *sqlDatabase) BreakLockJobIsQueued(_ context.Context, jobID int64) error {
var workflowJob WorkflowJob
q := s.conn.Clauses(clause.Locking{Strength: "UPDATE"}).Preload("Instance").Where("id = ? and status = ?", jobID, params.JobStatusQueued).First(&workflowJob)
@ -160,7 +161,7 @@ func (s *sqlDatabase) BreakLockJobIsQueued(ctx context.Context, jobID int64) err
return nil
}
func (s *sqlDatabase) UnlockJob(ctx context.Context, jobID int64, entityID string) error {
func (s *sqlDatabase) UnlockJob(_ context.Context, jobID int64, entityID string) error {
var workflowJob WorkflowJob
q := s.conn.Clauses(clause.Locking{Strength: "UPDATE"}).Where("id = ?", jobID).First(&workflowJob)
@ -250,7 +251,7 @@ func (s *sqlDatabase) CreateOrUpdateJob(ctx context.Context, job params.Job) (pa
}
// ListJobsByStatus lists all jobs for a given status.
func (s *sqlDatabase) ListJobsByStatus(ctx context.Context, status params.JobStatus) ([]params.Job, error) {
func (s *sqlDatabase) ListJobsByStatus(_ context.Context, status params.JobStatus) ([]params.Job, error) {
var jobs []WorkflowJob
query := s.conn.Model(&WorkflowJob{}).Preload("Instance").Where("status = ?", status)
@ -270,7 +271,7 @@ func (s *sqlDatabase) ListJobsByStatus(ctx context.Context, status params.JobSta
}
// ListEntityJobsByStatus lists all jobs for a given entity type and id.
func (s *sqlDatabase) ListEntityJobsByStatus(ctx context.Context, entityType params.PoolType, entityID string, status params.JobStatus) ([]params.Job, error) {
func (s *sqlDatabase) ListEntityJobsByStatus(_ context.Context, entityType params.PoolType, entityID string, status params.JobStatus) ([]params.Job, error) {
u, err := uuid.Parse(entityID)
if err != nil {
return nil, err
@ -306,7 +307,7 @@ func (s *sqlDatabase) ListEntityJobsByStatus(ctx context.Context, entityType par
return ret, nil
}
func (s *sqlDatabase) ListAllJobs(ctx context.Context) ([]params.Job, error) {
func (s *sqlDatabase) ListAllJobs(_ context.Context) ([]params.Job, error) {
var jobs []WorkflowJob
query := s.conn.Model(&WorkflowJob{})
@ -329,7 +330,7 @@ func (s *sqlDatabase) ListAllJobs(ctx context.Context) ([]params.Job, error) {
}
// GetJobByID gets a job by id.
func (s *sqlDatabase) GetJobByID(ctx context.Context, jobID int64) (params.Job, error) {
func (s *sqlDatabase) GetJobByID(_ context.Context, jobID int64) (params.Job, error) {
var job WorkflowJob
query := s.conn.Model(&WorkflowJob{}).Preload("Instance").Where("id = ?", jobID)
@ -344,7 +345,7 @@ func (s *sqlDatabase) GetJobByID(ctx context.Context, jobID int64) (params.Job,
}
// DeleteCompletedJobs deletes all completed jobs.
func (s *sqlDatabase) DeleteCompletedJobs(ctx context.Context) error {
func (s *sqlDatabase) DeleteCompletedJobs(_ context.Context) error {
query := s.conn.Model(&WorkflowJob{}).Where("status = ?", params.JobStatusCompleted)
if err := query.Unscoped().Delete(&WorkflowJob{}); err.Error != nil {

View file

@ -17,13 +17,13 @@ package sql
import (
"time"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes"
"gorm.io/gorm"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/params"
)
type Base struct {
@ -33,9 +33,9 @@ type Base struct {
DeletedAt gorm.DeletedAt `gorm:"index"`
}
func (b *Base) BeforeCreate(tx *gorm.DB) error {
emptyId := uuid.UUID{}
if b.ID != emptyId {
func (b *Base) BeforeCreate(_ *gorm.DB) error {
emptyID := uuid.UUID{}
if b.ID != emptyID {
return nil
}
newID, err := uuid.NewRandom()

View file

@ -18,17 +18,17 @@ import (
"context"
"fmt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes"
"gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) CreateOrganization(ctx context.Context, name, credentialsName, webhookSecret string) (params.Organization, error) {
func (s *sqlDatabase) CreateOrganization(_ context.Context, name, credentialsName, webhookSecret string) (params.Organization, error) {
if webhookSecret == "" {
return params.Organization{}, errors.New("creating org: missing secret")
}
@ -70,7 +70,7 @@ func (s *sqlDatabase) GetOrganization(ctx context.Context, name string) (params.
return param, nil
}
func (s *sqlDatabase) ListOrganizations(ctx context.Context) ([]params.Organization, error) {
func (s *sqlDatabase) ListOrganizations(_ context.Context) ([]params.Organization, error) {
var orgs []Organization
q := s.conn.Find(&orgs)
if q.Error != nil {
@ -146,12 +146,12 @@ func (s *sqlDatabase) GetOrganizationByID(ctx context.Context, orgID string) (pa
return param, nil
}
func (s *sqlDatabase) CreateOrganizationPool(ctx context.Context, orgId string, param params.CreatePoolParams) (params.Pool, error) {
func (s *sqlDatabase) CreateOrganizationPool(ctx context.Context, orgID string, param params.CreatePoolParams) (params.Pool, error) {
if len(param.Tags) == 0 {
return params.Pool{}, runnerErrors.NewBadRequestError("no tags specified")
}
org, err := s.getOrgByID(ctx, orgId)
org, err := s.getOrgByID(ctx, orgID)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching org")
}
@ -175,7 +175,7 @@ func (s *sqlDatabase) CreateOrganizationPool(ctx context.Context, orgId string,
newPool.ExtraSpecs = datatypes.JSON(param.ExtraSpecs)
}
_, err = s.getOrgPoolByUniqueFields(ctx, orgId, newPool.ProviderName, newPool.Image, newPool.Flavor)
_, err = s.getOrgPoolByUniqueFields(ctx, orgID, newPool.ProviderName, newPool.Image, newPool.Flavor)
if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.Pool{}, errors.Wrap(err, "creating pool")
@ -198,8 +198,8 @@ func (s *sqlDatabase) CreateOrganizationPool(ctx context.Context, orgId string,
return params.Pool{}, errors.Wrap(q.Error, "adding pool")
}
for _, tt := range tags {
if err := s.conn.Model(&newPool).Association("Tags").Append(&tt); err != nil {
for i := range tags {
if err := s.conn.Model(&newPool).Association("Tags").Append(&tags[i]); err != nil {
return params.Pool{}, errors.Wrap(err, "saving tag")
}
}
@ -249,7 +249,7 @@ func (s *sqlDatabase) DeleteOrganizationPool(ctx context.Context, orgID, poolID
return nil
}
func (s *sqlDatabase) FindOrganizationPoolByTags(ctx context.Context, orgID string, tags []string) (params.Pool, error) {
func (s *sqlDatabase) FindOrganizationPoolByTags(_ context.Context, orgID string, tags []string) (params.Pool, error) {
pool, err := s.findPoolByTags(orgID, params.OrganizationPool, tags)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool")
@ -284,7 +284,7 @@ func (s *sqlDatabase) UpdateOrganizationPool(ctx context.Context, orgID, poolID
return s.updatePool(pool, param)
}
func (s *sqlDatabase) getPoolByID(ctx context.Context, poolID string, preload ...string) (Pool, error) {
func (s *sqlDatabase) getPoolByID(_ context.Context, poolID string, preload ...string) (Pool, error) {
u, err := uuid.Parse(poolID)
if err != nil {
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
@ -308,7 +308,7 @@ func (s *sqlDatabase) getPoolByID(ctx context.Context, poolID string, preload ..
return pool, nil
}
func (s *sqlDatabase) getOrgByID(ctx context.Context, id string, preload ...string) (Organization, error) {
func (s *sqlDatabase) getOrgByID(_ context.Context, id string, preload ...string) (Organization, error) {
u, err := uuid.Parse(id)
if err != nil {
return Organization{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
@ -332,7 +332,7 @@ func (s *sqlDatabase) getOrgByID(ctx context.Context, id string, preload ...stri
return org, nil
}
func (s *sqlDatabase) getOrg(ctx context.Context, name string) (Organization, error) {
func (s *sqlDatabase) getOrg(_ context.Context, name string) (Organization, error) {
var org Organization
q := s.conn.Where("name = ? COLLATE NOCASE", name)

View file

@ -22,16 +22,16 @@ import (
"sort"
"testing"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
"github.com/stretchr/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
)
type OrgTestFixtures struct {
@ -104,7 +104,7 @@ func (s *OrgTestSuite) SetupTest() {
SkipInitializeWithVersion: true,
}
gormConfig := &gorm.Config{}
if flag.Lookup("test.v").Value.String() == "false" {
if flag.Lookup("test.v").Value.String() == falseString {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
gormConn, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)
@ -182,7 +182,7 @@ func (s *OrgTestSuite) TestCreateOrganizationInvalidDBPassphrase() {
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
}
// make sure we use a 'sqlDatabase' struct with a wrong 'cfg.Passphrase'
cfg.Passphrase = "wrong-passphrase" // it must have a size different than 32
cfg.Passphrase = wrongPassphrase // it must have a size different than 32
sqlDB := &sqlDatabase{
conn: conn,
cfg: cfg,
@ -321,7 +321,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationInvalidOrgID() {
}
func (s *OrgTestSuite) TestUpdateOrganizationDBEncryptErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `organizations` WHERE id = ? AND `organizations`.`deleted_at` IS NULL ORDER BY `organizations`.`id` LIMIT 1")).
@ -354,8 +354,8 @@ func (s *OrgTestSuite) TestUpdateOrganizationDBSaveErr() {
}
func (s *OrgTestSuite) TestUpdateOrganizationDBDecryptingErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.Fixtures.UpdateRepoParams.WebhookSecret = "webhook-secret"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.UpdateRepoParams.WebhookSecret = webhookSecret
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `organizations` WHERE id = ? AND `organizations`.`deleted_at` IS NULL ORDER BY `organizations`.`id` LIMIT 1")).

View file

@ -18,15 +18,21 @@ import (
"context"
"fmt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) ListAllPools(ctx context.Context) ([]params.Pool, error) {
const (
entityTypeEnterpriseName = "enterprise_id"
entityTypeOrgName = "org_id"
entityTypeRepoName = "repo_id"
)
func (s *sqlDatabase) ListAllPools(_ context.Context) ([]params.Pool, error) {
var pools []Pool
q := s.conn.Model(&Pool{}).
@ -72,7 +78,7 @@ func (s *sqlDatabase) DeletePoolByID(ctx context.Context, poolID string) error {
return nil
}
func (s *sqlDatabase) getEntityPool(ctx context.Context, entityType params.PoolType, entityID, poolID string, preload ...string) (Pool, error) {
func (s *sqlDatabase) getEntityPool(_ context.Context, entityType params.PoolType, entityID, poolID string, preload ...string) (Pool, error) {
if entityID == "" {
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "missing entity id")
}
@ -92,11 +98,11 @@ func (s *sqlDatabase) getEntityPool(ctx context.Context, entityType params.PoolT
var fieldName string
switch entityType {
case params.RepositoryPool:
fieldName = "repo_id"
fieldName = entityTypeRepoName
case params.OrganizationPool:
fieldName = "org_id"
fieldName = entityTypeOrgName
case params.EnterprisePool:
fieldName = "enterprise_id"
fieldName = entityTypeEnterpriseName
default:
return Pool{}, fmt.Errorf("invalid entityType: %v", entityType)
}
@ -106,7 +112,6 @@ func (s *sqlDatabase) getEntityPool(ctx context.Context, entityType params.PoolT
err = q.Model(&Pool{}).
Where(condition, u, entityID).
First(&pool).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return Pool{}, errors.Wrap(runnerErrors.ErrNotFound, "finding pool")
@ -117,7 +122,7 @@ func (s *sqlDatabase) getEntityPool(ctx context.Context, entityType params.PoolT
return pool, nil
}
func (s *sqlDatabase) listEntityPools(ctx context.Context, entityType params.PoolType, entityID string, preload ...string) ([]Pool, error) {
func (s *sqlDatabase) listEntityPools(_ context.Context, entityType params.PoolType, entityID string, preload ...string) ([]Pool, error) {
if _, err := uuid.Parse(entityID); err != nil {
return nil, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")
}
@ -132,11 +137,11 @@ func (s *sqlDatabase) listEntityPools(ctx context.Context, entityType params.Poo
var fieldName string
switch entityType {
case params.RepositoryPool:
fieldName = "repo_id"
fieldName = entityTypeRepoName
case params.OrganizationPool:
fieldName = "org_id"
fieldName = entityTypeOrgName
case params.EnterprisePool:
fieldName = "enterprise_id"
fieldName = entityTypeEnterpriseName
default:
return nil, fmt.Errorf("invalid entityType: %v", entityType)
}
@ -147,7 +152,6 @@ func (s *sqlDatabase) listEntityPools(ctx context.Context, entityType params.Poo
Where(condition, entityID).
Omit("extra_specs").
Find(&pools).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return []Pool{}, nil
@ -170,11 +174,11 @@ func (s *sqlDatabase) findPoolByTags(id string, poolType params.PoolType, tags [
var fieldName string
switch poolType {
case params.RepositoryPool:
fieldName = "repo_id"
fieldName = entityTypeRepoName
case params.OrganizationPool:
fieldName = "org_id"
fieldName = entityTypeOrgName
case params.EnterprisePool:
fieldName = "enterprise_id"
fieldName = entityTypeEnterpriseName
default:
return nil, fmt.Errorf("invalid poolType: %v", poolType)
}
@ -210,7 +214,7 @@ func (s *sqlDatabase) findPoolByTags(id string, poolType params.PoolType, tags [
return ret, nil
}
func (s *sqlDatabase) FindPoolsMatchingAllTags(ctx context.Context, entityType params.PoolType, entityID string, tags []string) ([]params.Pool, error) {
func (s *sqlDatabase) FindPoolsMatchingAllTags(_ context.Context, entityType params.PoolType, entityID string, tags []string) ([]params.Pool, error) {
if len(tags) == 0 {
return nil, runnerErrors.NewBadRequestError("missing tags")
}

View file

@ -21,15 +21,15 @@ import (
"regexp"
"testing"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
"github.com/stretchr/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
)
type PoolsTestFixtures struct {
@ -99,7 +99,7 @@ func (s *PoolsTestSuite) SetupTest() {
SkipInitializeWithVersion: true,
}
gormConfig := &gorm.Config{}
if flag.Lookup("test.v").Value.String() == "false" {
if flag.Lookup("test.v").Value.String() == falseString {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
gormConn, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)

View file

@ -18,17 +18,17 @@ import (
"context"
"fmt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
"github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes"
"gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) CreateRepository(ctx context.Context, owner, name, credentialsName, webhookSecret string) (params.Repository, error) {
func (s *sqlDatabase) CreateRepository(_ context.Context, owner, name, credentialsName, webhookSecret string) (params.Repository, error) {
if webhookSecret == "" {
return params.Repository{}, errors.New("creating repo: missing secret")
}
@ -70,7 +70,7 @@ func (s *sqlDatabase) GetRepository(ctx context.Context, owner, name string) (pa
return param, nil
}
func (s *sqlDatabase) ListRepositories(ctx context.Context) ([]params.Repository, error) {
func (s *sqlDatabase) ListRepositories(_ context.Context) ([]params.Repository, error) {
var repos []Repository
q := s.conn.Find(&repos)
if q.Error != nil {
@ -146,12 +146,12 @@ func (s *sqlDatabase) GetRepositoryByID(ctx context.Context, repoID string) (par
return param, nil
}
func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoId string, param params.CreatePoolParams) (params.Pool, error) {
func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoID string, param params.CreatePoolParams) (params.Pool, error) {
if len(param.Tags) == 0 {
return params.Pool{}, runnerErrors.NewBadRequestError("no tags specified")
}
repo, err := s.getRepoByID(ctx, repoId)
repo, err := s.getRepoByID(ctx, repoID)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching repo")
}
@ -175,7 +175,7 @@ func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoId string, p
newPool.ExtraSpecs = datatypes.JSON(param.ExtraSpecs)
}
_, err = s.getRepoPoolByUniqueFields(ctx, repoId, newPool.ProviderName, newPool.Image, newPool.Flavor)
_, err = s.getRepoPoolByUniqueFields(ctx, repoID, newPool.ProviderName, newPool.Image, newPool.Flavor)
if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.Pool{}, errors.Wrap(err, "creating pool")
@ -198,8 +198,8 @@ func (s *sqlDatabase) CreateRepositoryPool(ctx context.Context, repoId string, p
return params.Pool{}, errors.Wrap(q.Error, "adding pool")
}
for _, tt := range tags {
if err := s.conn.Model(&newPool).Association("Tags").Append(&tt); err != nil {
for i := range tags {
if err := s.conn.Model(&newPool).Association("Tags").Append(&tags[i]); err != nil {
return params.Pool{}, errors.Wrap(err, "saving tag")
}
}
@ -249,7 +249,7 @@ func (s *sqlDatabase) DeleteRepositoryPool(ctx context.Context, repoID, poolID s
return nil
}
func (s *sqlDatabase) FindRepositoryPoolByTags(ctx context.Context, repoID string, tags []string) (params.Pool, error) {
func (s *sqlDatabase) FindRepositoryPoolByTags(_ context.Context, repoID string, tags []string) (params.Pool, error) {
pool, err := s.findPoolByTags(repoID, params.RepositoryPool, tags)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool")
@ -285,7 +285,7 @@ func (s *sqlDatabase) UpdateRepositoryPool(ctx context.Context, repoID, poolID s
return s.updatePool(pool, param)
}
func (s *sqlDatabase) getRepo(ctx context.Context, owner, name string) (Repository, error) {
func (s *sqlDatabase) getRepo(_ context.Context, owner, name string) (Repository, error) {
var repo Repository
q := s.conn.Where("name = ? COLLATE NOCASE and owner = ? COLLATE NOCASE", name, owner).
@ -321,7 +321,7 @@ func (s *sqlDatabase) getRepoPoolByUniqueFields(ctx context.Context, repoID stri
return pool[0], nil
}
func (s *sqlDatabase) getRepoByID(ctx context.Context, id string, preload ...string) (Repository, error) {
func (s *sqlDatabase) getRepoByID(_ context.Context, id string, preload ...string) (Repository, error) {
u, err := uuid.Parse(id)
if err != nil {
return Repository{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id")

View file

@ -22,15 +22,15 @@ import (
"sort"
"testing"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
"github.com/stretchr/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
)
type RepoTestFixtures struct {
@ -115,7 +115,7 @@ func (s *RepoTestSuite) SetupTest() {
SkipInitializeWithVersion: true,
}
gormConfig := &gorm.Config{}
if flag.Lookup("test.v").Value.String() == "false" {
if flag.Lookup("test.v").Value.String() == falseString {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
gormConn, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)
@ -197,7 +197,7 @@ func (s *RepoTestSuite) TestCreateRepositoryInvalidDBPassphrase() {
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
}
// make sure we use a 'sqlDatabase' struct with a wrong 'cfg.Passphrase'
cfg.Passphrase = "wrong-passphrase" // it must have a size different than 32
cfg.Passphrase = wrongPassphrase // it must have a size different than 32
sqlDB := &sqlDatabase{
conn: conn,
cfg: cfg,
@ -296,7 +296,7 @@ func (s *RepoTestSuite) TestListRepositoriesDBFetchErr() {
}
func (s *RepoTestSuite) TestListRepositoriesDBDecryptingErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `repositories` WHERE `repositories`.`deleted_at` IS NULL")).
@ -360,7 +360,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryInvalidRepoID() {
}
func (s *RepoTestSuite) TestUpdateRepositoryDBEncryptErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `repositories` WHERE id = ? AND `repositories`.`deleted_at` IS NULL ORDER BY `repositories`.`id` LIMIT 1")).
@ -392,8 +392,8 @@ func (s *RepoTestSuite) TestUpdateRepositoryDBSaveErr() {
}
func (s *RepoTestSuite) TestUpdateRepositoryDBDecryptingErr() {
s.StoreSQLMocked.cfg.Passphrase = "wrong-passphrase"
s.Fixtures.UpdateRepoParams.WebhookSecret = "webhook-secret"
s.StoreSQLMocked.cfg.Passphrase = wrongPassphrase
s.Fixtures.UpdateRepoParams.WebhookSecret = webhookSecret
s.Fixtures.SQLMock.
ExpectQuery(regexp.QuoteMeta("SELECT * FROM `repositories` WHERE id = ? AND `repositories`.`deleted_at` IS NULL ORDER BY `repositories`.`id` LIMIT 1")).

View file

@ -18,12 +18,12 @@ import (
"context"
"fmt"
"github.com/pkg/errors"
"gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
"github.com/pkg/errors"
"gorm.io/gorm"
)
func (s *sqlDatabase) getUserByUsernameOrEmail(user string) (User, error) {
@ -56,7 +56,7 @@ func (s *sqlDatabase) getUserByID(userID string) (User, error) {
return dbUser, nil
}
func (s *sqlDatabase) CreateUser(ctx context.Context, user params.NewUserParams) (params.User, error) {
func (s *sqlDatabase) CreateUser(_ context.Context, user params.NewUserParams) (params.User, error) {
if user.Username == "" || user.Email == "" {
return params.User{}, runnerErrors.NewBadRequestError("missing username or email")
}
@ -83,13 +83,13 @@ func (s *sqlDatabase) CreateUser(ctx context.Context, user params.NewUserParams)
return s.sqlToParamsUser(newUser), nil
}
func (s *sqlDatabase) HasAdminUser(ctx context.Context) bool {
func (s *sqlDatabase) HasAdminUser(_ context.Context) bool {
var user User
q := s.conn.Model(&User{}).Where("is_admin = ?", true).First(&user)
return q.Error == nil
}
func (s *sqlDatabase) GetUser(ctx context.Context, user string) (params.User, error) {
func (s *sqlDatabase) GetUser(_ context.Context, user string) (params.User, error) {
dbUser, err := s.getUserByUsernameOrEmail(user)
if err != nil {
return params.User{}, errors.Wrap(err, "fetching user")
@ -97,7 +97,7 @@ func (s *sqlDatabase) GetUser(ctx context.Context, user string) (params.User, er
return s.sqlToParamsUser(dbUser), nil
}
func (s *sqlDatabase) GetUserByID(ctx context.Context, userID string) (params.User, error) {
func (s *sqlDatabase) GetUserByID(_ context.Context, userID string) (params.User, error) {
dbUser, err := s.getUserByID(userID)
if err != nil {
return params.User{}, errors.Wrap(err, "fetching user")
@ -105,7 +105,7 @@ func (s *sqlDatabase) GetUserByID(ctx context.Context, userID string) (params.Us
return s.sqlToParamsUser(dbUser), nil
}
func (s *sqlDatabase) UpdateUser(ctx context.Context, user string, param params.UpdateUserParams) (params.User, error) {
func (s *sqlDatabase) UpdateUser(_ context.Context, user string, param params.UpdateUserParams) (params.User, error) {
dbUser, err := s.getUserByUsernameOrEmail(user)
if err != nil {
return params.User{}, errors.Wrap(err, "fetching user")

View file

@ -21,14 +21,15 @@ import (
"regexp"
"testing"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
"github.com/stretchr/testify/suite"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
)
type UserTestFixtures struct {
@ -90,7 +91,7 @@ func (s *UserTestSuite) SetupTest() {
SkipInitializeWithVersion: true,
}
gormConfig := &gorm.Config{}
if flag.Lookup("test.v").Value.String() == "false" {
if flag.Lookup("test.v").Value.String() == falseString {
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
}
gormConn, err := gorm.Open(mysql.New(mysqlConfig), gormConfig)

View file

@ -18,14 +18,13 @@ import (
"encoding/json"
"fmt"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
"github.com/pkg/errors"
"gorm.io/datatypes"
"gorm.io/gorm"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"
)
func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, error) {

View file

@ -23,14 +23,13 @@ import (
"sort"
"testing"
"github.com/cloudbase/garm/config"
"github.com/stretchr/testify/require"
"github.com/cloudbase/garm/config"
)
var (
encryptionPassphrase = "bocyasicgatEtenOubwonIbsudNutDom"
)
//nolint:golangci-lint,gosec
var encryptionPassphrase = "bocyasicgatEtenOubwonIbsudNutDom"
func GetTestSqliteDBConfig(t *testing.T) config.Database {
dir, err := os.MkdirTemp("", "garm-config-test")

View file

@ -4,10 +4,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
var (
GarmHealth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: metricsNamespace,
Name: "health",
Help: "Health of the garm",
}, []string{"metadata_url", "callback_url", "webhook_url", "controller_webhook_url", "controller_id"})
)
var GarmHealth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: metricsNamespace,
Name: "health",
Help: "Health of the garm",
}, []string{"metadata_url", "callback_url", "webhook_url", "controller_webhook_url", "controller_id"})

View file

@ -4,15 +4,17 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
const metricsNamespace = "garm"
const metricsRunnerSubsystem = "runner"
const metricsPoolSubsystem = "pool"
const metricsProviderSubsystem = "provider"
const metricsOrganizationSubsystem = "organization"
const metricsRepositorySubsystem = "repository"
const metricsEnterpriseSubsystem = "enterprise"
const metricsWebhookSubsystem = "webhook"
const metricsGithubSubsystem = "github"
const (
metricsNamespace = "garm"
metricsRunnerSubsystem = "runner"
metricsPoolSubsystem = "pool"
metricsProviderSubsystem = "provider"
metricsOrganizationSubsystem = "organization"
metricsRepositorySubsystem = "repository"
metricsEnterpriseSubsystem = "enterprise"
metricsWebhookSubsystem = "webhook"
metricsGithubSubsystem = "github"
)
// RegisterMetrics registers all the metrics
func RegisterMetrics() error {

View file

@ -4,11 +4,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
var (
ProviderInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: metricsNamespace,
Subsystem: metricsProviderSubsystem,
Name: "info",
Help: "Info of the organization",
}, []string{"name", "type", "description"})
)
var ProviderInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: metricsNamespace,
Subsystem: metricsProviderSubsystem,
Name: "info",
Help: "Info of the organization",
}, []string{"name", "type", "description"})

View file

@ -2,11 +2,9 @@ package metrics
import "github.com/prometheus/client_golang/prometheus"
var (
WebhooksReceived = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: metricsNamespace,
Subsystem: metricsWebhookSubsystem,
Name: "received",
Help: "The total number of webhooks received",
}, []string{"valid", "reason"})
)
var WebhooksReceived = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: metricsNamespace,
Subsystem: metricsWebhookSubsystem,
Name: "received",
Help: "The total number of webhooks received",
}, []string{"valid", "reason"})

View file

@ -22,12 +22,11 @@ import (
"fmt"
"time"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/util/appdefaults"
"github.com/google/go-github/v57/github"
"github.com/google/uuid"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/util/appdefaults"
)
type (
@ -287,11 +286,12 @@ func (p *Pool) RunnerTimeout() uint {
}
func (p *Pool) PoolType() PoolType {
if p.RepoID != "" {
switch {
case p.RepoID != "":
return RepositoryPool
} else if p.OrgID != "" {
case p.OrgID != "":
return OrganizationPool
} else if p.EnterpriseID != "" {
case p.EnterpriseID != "":
return EnterprisePool
}
return ""
@ -437,7 +437,7 @@ func (g GithubCredentials) RootCertificateBundle() (CertificateBundle, error) {
ret := map[string][]byte{}
var block *pem.Block
var rest []byte = g.CABundle
rest := g.CABundle
for {
block, rest = pem.Decode(rest)
if block == nil {

View file

@ -18,9 +18,8 @@ import (
"encoding/json"
"fmt"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
)
const DefaultRunnerPrefix = "garm"

View file

@ -161,12 +161,12 @@ func (_m *Provider) Start(ctx context.Context, instance string) error {
}
// Stop provides a mock function with given fields: ctx, instance, force
func (_m *Provider) Stop(ctx context.Context, instance string, force bool) error {
ret := _m.Called(ctx, instance, force)
func (_m *Provider) Stop(ctx context.Context, instance string) error {
ret := _m.Called(ctx, instance)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, bool) error); ok {
r0 = rf(ctx, instance, force)
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, instance)
} else {
r0 = ret.Error(0)
}

View file

@ -61,7 +61,7 @@ type PoolManager interface {
ForceDeleteRunner(runner params.Instance) error
// DeleteRunner will attempt to remove a runner from the pool. If forceRemove is true, any error
// received from the provider will be ignored and we will procede to remove the runner from the database.
// received from the provider will be ignored and we will proceed to remove the runner from the database.
// An error received while attempting to remove from GitHub (other than 404) will still stop the deletion
// process. This can happen if the runner is already processing a job. At which point, you can simply cancel
// the job in github. Doing so will prompt GARM to reap the runner automatically.

View file

@ -34,7 +34,7 @@ type Provider interface {
// RemoveAllInstances will remove all instances created by this provider.
RemoveAllInstances(ctx context.Context) error
// Stop shuts down the instance.
Stop(ctx context.Context, instance string, force bool) error
Stop(ctx context.Context, instance string) error
// Start boots up an instance.
Start(ctx context.Context, instance string) error
// DisableJITConfig tells us if the provider explicitly disables JIT configuration and

9
runner/common_test.go Normal file
View file

@ -0,0 +1,9 @@
package runner
const (
// nolint: gosec
notExistingCredentialsName = "not-existent-creds-name"
// nolint: gosec
invalidCredentialsName = "invalid-creds-name"
notExistingProviderName = "not-existent-provider-name"
)

View file

@ -6,13 +6,13 @@ import (
"log/slog"
"strings"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/util/appdefaults"
"github.com/pkg/errors"
)
func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterpriseParams) (enterprise params.Enterprise, err error) {
@ -130,12 +130,12 @@ func (r *Runner) DeleteEnterprise(ctx context.Context, enterpriseID string) erro
}
if len(pools) > 0 {
poolIds := []string{}
poolIDs := []string{}
for _, pool := range pools {
poolIds = append(poolIds, pool.ID)
poolIDs = append(poolIDs, pool.ID)
}
return runnerErrors.NewBadRequestError("enterprise has pools defined (%s)", strings.Join(poolIds, ", "))
return runnerErrors.NewBadRequestError("enterprise has pools defined (%s)", strings.Join(poolIDs, ", "))
}
if err := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); err != nil {
@ -233,6 +233,7 @@ func (r *Runner) DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID
return runnerErrors.ErrUnauthorized
}
// nolint:golangci-lint,godox
// TODO: dedup instance count verification
pool, err := r.store.GetEnterprisePool(ctx, enterpriseID, poolID)
if err != nil {
@ -244,6 +245,7 @@ func (r *Runner) DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID
return errors.Wrap(err, "fetching instances")
}
// nolint:golangci-lint,godox
// TODO: implement a count function
if len(instances) > 0 {
runnerIDs := []string{}

View file

@ -19,19 +19,19 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/database"
dbCommon "github.com/cloudbase/garm/database/common"
garmTesting "github.com/cloudbase/garm/internal/testing"
garmTesting "github.com/cloudbase/garm/internal/testing" //nolint:typecheck
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
runnerCommonMocks "github.com/cloudbase/garm/runner/common/mocks"
runnerMocks "github.com/cloudbase/garm/runner/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)
type EnterpriseTestFixtures struct {
@ -184,7 +184,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterpriseEmptyParams() {
}
func (s *EnterpriseTestSuite) TestCreateEnterpriseMissingCredentials() {
s.Fixtures.CreateEnterpriseParams.CredentialsName = "not-existent-creds-name"
s.Fixtures.CreateEnterpriseParams.CredentialsName = notExistingCredentialsName
_, err := s.Runner.CreateEnterprise(s.Fixtures.AdminContext, s.Fixtures.CreateEnterpriseParams)
@ -309,7 +309,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseErrUnauthorized() {
}
func (s *EnterpriseTestSuite) TestUpdateEnterpriseInvalidCreds() {
s.Fixtures.UpdateRepoParams.CredentialsName = "invalid-creds-name"
s.Fixtures.UpdateRepoParams.CredentialsName = invalidCredentialsName
_, err := s.Runner.UpdateEnterprise(s.Fixtures.AdminContext, s.Fixtures.StoreEnterprises["test-enterprise-1"].ID, s.Fixtures.UpdateRepoParams)
@ -371,7 +371,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolErrNotFound() {
}
func (s *EnterpriseTestSuite) TestCreateEnterprisePoolFetchPoolParamsFailed() {
s.Fixtures.CreatePoolParams.ProviderName = "not-existent-provider-name"
s.Fixtures.CreatePoolParams.ProviderName = notExistingProviderName
s.Fixtures.PoolMgrCtrlMock.On("GetEnterprisePoolManager", mock.AnythingOfType("params.Enterprise")).Return(s.Fixtures.PoolMgrMock, nil)

View file

@ -9,11 +9,12 @@ import (
"log/slog"
"strings"
"github.com/pkg/errors"
"github.com/cloudbase/garm-provider-common/defaults"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params"
"github.com/pkg/errors"
)
var systemdUnitTemplate = `[Unit]
@ -73,7 +74,7 @@ func (r *Runner) GetRunnerServiceName(ctx context.Context) (string, error) {
case params.OrganizationPool:
serviceName = fmt.Sprintf(tpl, pool.OrgName, instance.Name)
case params.RepositoryPool:
serviceName = fmt.Sprintf(tpl, strings.Replace(pool.RepoName, "/", "-", -1), instance.Name)
serviceName = fmt.Sprintf(tpl, strings.ReplaceAll(pool.RepoName, "/", "-"), instance.Name)
}
return serviceName, nil
}

View file

@ -5,12 +5,11 @@ import (
"strconv"
"github.com/cloudbase/garm/metrics"
"github.com/cloudbase/garm/runner"
"github.com/cloudbase/garm/runner" //nolint:typecheck
)
// CollectOrganizationMetric collects the metrics for the enterprise objects
func CollectEnterpriseMetric(ctx context.Context, r *runner.Runner) error {
// reset metrics
metrics.EnterpriseInfo.Reset()
metrics.EnterprisePoolManagerStatus.Reset()

View file

@ -1,14 +1,11 @@
package metrics
import (
"context"
"github.com/cloudbase/garm/metrics"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner"
)
func CollectHealthMetric(ctx context.Context, r *runner.Runner, controllerInfo params.ControllerInfo) error {
func CollectHealthMetric(controllerInfo params.ControllerInfo) error {
metrics.GarmHealth.WithLabelValues(
controllerInfo.MetadataURL, // label: metadata_url
controllerInfo.CallbackURL, // label: callback_url

View file

@ -10,7 +10,6 @@ import (
// CollectInstanceMetric collects the metrics for the runner instances
// reflecting the statuses and the pool they belong to.
func CollectInstanceMetric(ctx context.Context, r *runner.Runner) error {
// reset metrics
metrics.InstanceStatus.Reset()
@ -32,29 +31,26 @@ func CollectInstanceMetric(ctx context.Context, r *runner.Runner) error {
poolNames := make(map[string]poolInfo)
for _, pool := range pools {
if pool.EnterpriseName != "" {
switch {
case pool.OrgName != "":
poolNames[pool.ID] = poolInfo{
Name: pool.EnterpriseName,
Type: string(pool.PoolType()),
ProviderName: pool.ProviderName,
Name: pool.OrgName,
Type: string(pool.PoolType()),
}
} else if pool.OrgName != "" {
case pool.EnterpriseName != "":
poolNames[pool.ID] = poolInfo{
Name: pool.OrgName,
Type: string(pool.PoolType()),
ProviderName: pool.ProviderName,
Name: pool.EnterpriseName,
Type: string(pool.PoolType()),
}
} else {
default:
poolNames[pool.ID] = poolInfo{
Name: pool.RepoName,
Type: string(pool.PoolType()),
ProviderName: pool.ProviderName,
Name: pool.RepoName,
Type: string(pool.PoolType()),
}
}
}
for _, instance := range instances {
metrics.InstanceStatus.WithLabelValues(
instance.Name, // label: name
string(instance.Status), // label: status

View file

@ -82,7 +82,7 @@ func collectMetrics(ctx context.Context, r *runner.Runner, controllerInfo params
}
slog.DebugContext(ctx, "collecting health metrics")
err = CollectHealthMetric(ctx, r, controllerInfo)
err = CollectHealthMetric(controllerInfo)
if err != nil {
return err
}

View file

@ -10,7 +10,6 @@ import (
// CollectOrganizationMetric collects the metrics for the organization objects
func CollectOrganizationMetric(ctx context.Context, r *runner.Runner) error {
// reset metrics
metrics.OrganizationInfo.Reset()
metrics.OrganizationPoolManagerStatus.Reset()

View file

@ -11,7 +11,6 @@ import (
// CollectPoolMetric collects the metrics for the pool objects
func CollectPoolMetric(ctx context.Context, r *runner.Runner) error {
// reset metrics
metrics.PoolInfo.Reset()
metrics.PoolStatus.Reset()
@ -31,17 +30,18 @@ func CollectPoolMetric(ctx context.Context, r *runner.Runner) error {
poolNames := make(map[string]poolInfo)
for _, pool := range pools {
if pool.EnterpriseName != "" {
poolNames[pool.ID] = poolInfo{
Name: pool.EnterpriseName,
Type: string(pool.PoolType()),
}
} else if pool.OrgName != "" {
switch {
case pool.OrgName != "":
poolNames[pool.ID] = poolInfo{
Name: pool.OrgName,
Type: string(pool.PoolType()),
}
} else {
case pool.EnterpriseName != "":
poolNames[pool.ID] = poolInfo{
Name: pool.EnterpriseName,
Type: string(pool.PoolType()),
}
default:
poolNames[pool.ID] = poolInfo{
Name: pool.RepoName,
Type: string(pool.PoolType()),

View file

@ -8,7 +8,6 @@ import (
)
func CollectProviderMetric(ctx context.Context, r *runner.Runner) error {
// reset metrics
metrics.ProviderInfo.Reset()

View file

@ -9,7 +9,6 @@ import (
)
func CollectRepositoryMetric(ctx context.Context, r *runner.Runner) error {
// reset metrics
metrics.EnterpriseInfo.Reset()
metrics.EnterprisePoolManagerStatus.Reset()

View file

@ -20,13 +20,13 @@ import (
"log/slog"
"strings"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/util/appdefaults"
"github.com/pkg/errors"
)
func (r *Runner) CreateOrganization(ctx context.Context, param params.CreateOrgParams) (org params.Organization, err error) {
@ -144,12 +144,12 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
}
if len(pools) > 0 {
poolIds := []string{}
poolIDs := []string{}
for _, pool := range pools {
poolIds = append(poolIds, pool.ID)
poolIDs = append(poolIDs, pool.ID)
}
return runnerErrors.NewBadRequestError("org has pools defined (%s)", strings.Join(poolIds, ", "))
return runnerErrors.NewBadRequestError("org has pools defined (%s)", strings.Join(poolIDs, ", "))
}
if !keepWebhook && r.config.Default.EnableWebhookManagement {
@ -159,6 +159,7 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
}
if err := poolMgr.UninstallWebhook(ctx); err != nil {
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): Should we error out here?
slog.With(slog.Any("error", err)).ErrorContext(
ctx, "failed to uninstall webhook",
@ -261,6 +262,7 @@ func (r *Runner) DeleteOrgPool(ctx context.Context, orgID, poolID string) error
return runnerErrors.ErrUnauthorized
}
// nolint:golangci-lint,godox
// TODO: dedup instance count verification
pool, err := r.store.GetOrganizationPool(ctx, orgID, poolID)
if err != nil {
@ -272,6 +274,7 @@ func (r *Runner) DeleteOrgPool(ctx context.Context, orgID, poolID string) error
return errors.Wrap(err, "fetching instances")
}
// nolint:golangci-lint,godox
// TODO: implement a count function
if len(instances) > 0 {
runnerIDs := []string{}

View file

@ -19,6 +19,9 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/config"
@ -29,9 +32,6 @@ import (
"github.com/cloudbase/garm/runner/common"
runnerCommonMocks "github.com/cloudbase/garm/runner/common/mocks"
runnerMocks "github.com/cloudbase/garm/runner/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)
type OrgTestFixtures struct {
@ -184,7 +184,7 @@ func (s *OrgTestSuite) TestCreateOrganizationEmptyParams() {
}
func (s *OrgTestSuite) TestCreateOrganizationMissingCredentials() {
s.Fixtures.CreateOrgParams.CredentialsName = "not-existent-creds-name"
s.Fixtures.CreateOrgParams.CredentialsName = notExistingCredentialsName
_, err := s.Runner.CreateOrganization(s.Fixtures.AdminContext, s.Fixtures.CreateOrgParams)
@ -309,7 +309,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationErrUnauthorized() {
}
func (s *OrgTestSuite) TestUpdateOrganizationInvalidCreds() {
s.Fixtures.UpdateRepoParams.CredentialsName = "invalid-creds-name"
s.Fixtures.UpdateRepoParams.CredentialsName = invalidCredentialsName
_, err := s.Runner.UpdateOrganization(s.Fixtures.AdminContext, s.Fixtures.StoreOrgs["test-org-1"].ID, s.Fixtures.UpdateRepoParams)
@ -371,7 +371,7 @@ func (s *OrgTestSuite) TestCreateOrgPoolErrNotFound() {
}
func (s *OrgTestSuite) TestCreateOrgPoolFetchPoolParamsFailed() {
s.Fixtures.CreatePoolParams.ProviderName = "not-existent-provider-name"
s.Fixtures.CreatePoolParams.ProviderName = notExistingProviderName
s.Fixtures.PoolMgrCtrlMock.On("GetOrgPoolManager", mock.AnythingOfType("params.Organization")).Return(s.Fixtures.PoolMgrMock, nil)

View file

@ -4,10 +4,11 @@ import (
"net/url"
"strings"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)
func validateHookRequest(controllerID, baseURL string, allHooks []*github.Hook, req *github.Hook) error {

View file

@ -10,6 +10,9 @@ import (
"strings"
"sync"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
dbCommon "github.com/cloudbase/garm/database/common"
@ -17,9 +20,6 @@ import (
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/util"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
)
// test that we implement PoolManager
@ -77,7 +77,8 @@ type enterprise struct {
mux sync.Mutex
}
func (r *enterprise) findRunnerGroupByName(ctx context.Context, name string) (*github.EnterpriseRunnerGroup, error) {
func (e *enterprise) findRunnerGroupByName(name string) (*github.EnterpriseRunnerGroup, error) {
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): implement caching
opts := github.ListEnterpriseRunnerGroupOptions{
ListOptions: github.ListOptions{
@ -90,7 +91,7 @@ func (r *enterprise) findRunnerGroupByName(ctx context.Context, name string) (*g
"ListOrganizationRunnerGroups", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
runnerGroups, ghResp, err := r.ghcEnterpriseCli.ListRunnerGroups(r.ctx, r.cfg.Name, &opts)
runnerGroups, ghResp, err := e.ghcEnterpriseCli.ListRunnerGroups(e.ctx, e.cfg.Name, &opts)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListOrganizationRunnerGroups", // label: operation
@ -115,10 +116,10 @@ func (r *enterprise) findRunnerGroupByName(ctx context.Context, name string) (*g
return nil, errors.Wrap(runnerErrors.ErrNotFound, "runner group not found")
}
func (r *enterprise) GetJITConfig(ctx context.Context, instance string, pool params.Pool, labels []string) (jitConfigMap map[string]string, runner *github.Runner, err error) {
func (e *enterprise) GetJITConfig(ctx context.Context, instance string, pool params.Pool, labels []string) (jitConfigMap map[string]string, runner *github.Runner, err error) {
var rg int64 = 1
if pool.GitHubRunnerGroup != "" {
runnerGroup, err := r.findRunnerGroupByName(ctx, pool.GitHubRunnerGroup)
runnerGroup, err := e.findRunnerGroupByName(pool.GitHubRunnerGroup)
if err != nil {
return nil, nil, fmt.Errorf("failed to find runner group: %w", err)
}
@ -129,6 +130,7 @@ func (r *enterprise) GetJITConfig(ctx context.Context, instance string, pool par
Name: instance,
RunnerGroupID: rg,
Labels: labels,
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): Should we make this configurable?
WorkFolder: github.String("_work"),
}
@ -136,7 +138,7 @@ func (r *enterprise) GetJITConfig(ctx context.Context, instance string, pool par
"GenerateEnterpriseJITConfig", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
jitConfig, resp, err := r.ghcEnterpriseCli.GenerateEnterpriseJITConfig(ctx, r.cfg.Name, &req)
jitConfig, resp, err := e.ghcEnterpriseCli.GenerateEnterpriseJITConfig(ctx, e.cfg.Name, &req)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"GenerateEnterpriseJITConfig", // label: operation
@ -155,7 +157,7 @@ func (r *enterprise) GetJITConfig(ctx context.Context, instance string, pool par
"RemoveRunner", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
_, innerErr := r.ghcEnterpriseCli.RemoveRunner(r.ctx, r.cfg.Name, runner.GetID())
_, innerErr := e.ghcEnterpriseCli.RemoveRunner(e.ctx, e.cfg.Name, runner.GetID())
if innerErr != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"RemoveRunner", // label: operation
@ -164,7 +166,7 @@ func (r *enterprise) GetJITConfig(ctx context.Context, instance string, pool par
}
slog.With(slog.Any("error", innerErr)).ErrorContext(
ctx, "failed to remove runner",
"runner_id", runner.GetID(), "organization", r.cfg.Name)
"runner_id", runner.GetID(), "organization", e.cfg.Name)
}
}()
@ -181,23 +183,23 @@ func (r *enterprise) GetJITConfig(ctx context.Context, instance string, pool par
return ret, jitConfig.Runner, nil
}
func (r *enterprise) GithubCLI() common.GithubClient {
return r.ghcli
func (e *enterprise) GithubCLI() common.GithubClient {
return e.ghcli
}
func (e *enterprise) PoolType() params.PoolType {
return params.EnterprisePool
}
func (r *enterprise) GetRunnerInfoFromWorkflow(job params.WorkflowJob) (params.RunnerInfo, error) {
if err := r.ValidateOwner(job); err != nil {
func (e *enterprise) GetRunnerInfoFromWorkflow(job params.WorkflowJob) (params.RunnerInfo, error) {
if err := e.ValidateOwner(job); err != nil {
return params.RunnerInfo{}, errors.Wrap(err, "validating owner")
}
metrics.GithubOperationCount.WithLabelValues(
"GetWorkflowJobByID", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
workflow, ghResp, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Repository.Owner.Login, job.Repository.Name, job.WorkflowJob.ID)
workflow, ghResp, err := e.ghcli.GetWorkflowJobByID(e.ctx, job.Repository.Owner.Login, job.Repository.Name, job.WorkflowJob.ID)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"GetWorkflowJobByID", // label: operation
@ -218,29 +220,29 @@ func (r *enterprise) GetRunnerInfoFromWorkflow(job params.WorkflowJob) (params.R
return params.RunnerInfo{}, fmt.Errorf("failed to find runner name from workflow")
}
func (r *enterprise) UpdateState(param params.UpdatePoolStateParams) error {
r.mux.Lock()
defer r.mux.Unlock()
func (e *enterprise) UpdateState(param params.UpdatePoolStateParams) error {
e.mux.Lock()
defer e.mux.Unlock()
r.cfg.WebhookSecret = param.WebhookSecret
e.cfg.WebhookSecret = param.WebhookSecret
if param.InternalConfig != nil {
r.cfgInternal = *param.InternalConfig
e.cfgInternal = *param.InternalConfig
}
ghc, ghcEnterprise, err := util.GithubClient(r.ctx, r.GetGithubToken(), r.cfgInternal.GithubCredentialsDetails)
ghc, ghcEnterprise, err := util.GithubClient(e.ctx, e.GetGithubToken(), e.cfgInternal.GithubCredentialsDetails)
if err != nil {
return errors.Wrap(err, "getting github client")
}
r.ghcli = ghc
r.ghcEnterpriseCli = ghcEnterprise
e.ghcli = ghc
e.ghcEnterpriseCli = ghcEnterprise
return nil
}
func (r *enterprise) GetGithubToken() string {
return r.cfgInternal.OAuth2Token
func (e *enterprise) GetGithubToken() string {
return e.cfgInternal.OAuth2Token
}
func (r *enterprise) GetGithubRunners() ([]*github.Runner, error) {
func (e *enterprise) GetGithubRunners() ([]*github.Runner, error) {
opts := github.ListOptions{
PerPage: 100,
}
@ -251,7 +253,7 @@ func (r *enterprise) GetGithubRunners() ([]*github.Runner, error) {
"ListRunners", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
runners, ghResp, err := r.ghcEnterpriseCli.ListRunners(r.ctx, r.cfg.Name, &opts)
runners, ghResp, err := e.ghcEnterpriseCli.ListRunners(e.ctx, e.cfg.Name, &opts)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListRunners", // label: operation
@ -271,14 +273,14 @@ func (r *enterprise) GetGithubRunners() ([]*github.Runner, error) {
return allRunners, nil
}
func (r *enterprise) FetchTools() ([]commonParams.RunnerApplicationDownload, error) {
r.mux.Lock()
defer r.mux.Unlock()
func (e *enterprise) FetchTools() ([]commonParams.RunnerApplicationDownload, error) {
e.mux.Lock()
defer e.mux.Unlock()
metrics.GithubOperationCount.WithLabelValues(
"ListRunnerApplicationDownloads", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
tools, ghResp, err := r.ghcEnterpriseCli.ListRunnerApplicationDownloads(r.ctx, r.cfg.Name)
tools, ghResp, err := e.ghcEnterpriseCli.ListRunnerApplicationDownloads(e.ctx, e.cfg.Name)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListRunnerApplicationDownloads", // label: operation
@ -301,16 +303,16 @@ func (r *enterprise) FetchTools() ([]commonParams.RunnerApplicationDownload, err
return ret, nil
}
func (r *enterprise) FetchDbInstances() ([]params.Instance, error) {
return r.store.ListEnterpriseInstances(r.ctx, r.id)
func (e *enterprise) FetchDbInstances() ([]params.Instance, error) {
return e.store.ListEnterpriseInstances(e.ctx, e.id)
}
func (r *enterprise) RemoveGithubRunner(runnerID int64) (*github.Response, error) {
func (e *enterprise) RemoveGithubRunner(runnerID int64) (*github.Response, error) {
metrics.GithubOperationCount.WithLabelValues(
"RemoveRunner", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
ghResp, err := r.ghcEnterpriseCli.RemoveRunner(r.ctx, r.cfg.Name, runnerID)
ghResp, err := e.ghcEnterpriseCli.RemoveRunner(e.ctx, e.cfg.Name, runnerID)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"RemoveRunner", // label: operation
@ -321,30 +323,29 @@ func (r *enterprise) RemoveGithubRunner(runnerID int64) (*github.Response, error
return ghResp, nil
}
func (r *enterprise) ListPools() ([]params.Pool, error) {
pools, err := r.store.ListEnterprisePools(r.ctx, r.id)
func (e *enterprise) ListPools() ([]params.Pool, error) {
pools, err := e.store.ListEnterprisePools(e.ctx, e.id)
if err != nil {
return nil, errors.Wrap(err, "fetching pools")
}
return pools, nil
}
func (r *enterprise) GithubURL() string {
return fmt.Sprintf("%s/enterprises/%s", r.cfgInternal.GithubCredentialsDetails.BaseURL, r.cfg.Name)
func (e *enterprise) GithubURL() string {
return fmt.Sprintf("%s/enterprises/%s", e.cfgInternal.GithubCredentialsDetails.BaseURL, e.cfg.Name)
}
func (r *enterprise) JwtToken() string {
return r.cfgInternal.JWTSecret
func (e *enterprise) JwtToken() string {
return e.cfgInternal.JWTSecret
}
func (r *enterprise) GetGithubRegistrationToken() (string, error) {
func (e *enterprise) GetGithubRegistrationToken() (string, error) {
metrics.GithubOperationCount.WithLabelValues(
"CreateRegistrationToken", // label: operation
metricsLabelEnterpriseScope, // label: scope
).Inc()
tk, ghResp, err := r.ghcEnterpriseCli.CreateRegistrationToken(r.ctx, r.cfg.Name)
tk, ghResp, err := e.ghcEnterpriseCli.CreateRegistrationToken(e.ctx, e.cfg.Name)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"CreateRegistrationToken", // label: operation
@ -358,49 +359,49 @@ func (r *enterprise) GetGithubRegistrationToken() (string, error) {
return *tk.Token, nil
}
func (r *enterprise) String() string {
return r.cfg.Name
func (e *enterprise) String() string {
return e.cfg.Name
}
func (r *enterprise) WebhookSecret() string {
return r.cfg.WebhookSecret
func (e *enterprise) WebhookSecret() string {
return e.cfg.WebhookSecret
}
func (r *enterprise) FindPoolByTags(labels []string) (params.Pool, error) {
pool, err := r.store.FindEnterprisePoolByTags(r.ctx, r.id, labels)
func (e *enterprise) FindPoolByTags(labels []string) (params.Pool, error) {
pool, err := e.store.FindEnterprisePoolByTags(e.ctx, e.id, labels)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching suitable pool")
}
return pool, nil
}
func (r *enterprise) GetPoolByID(poolID string) (params.Pool, error) {
pool, err := r.store.GetEnterprisePool(r.ctx, r.id, poolID)
func (e *enterprise) GetPoolByID(poolID string) (params.Pool, error) {
pool, err := e.store.GetEnterprisePool(e.ctx, e.id, poolID)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool")
}
return pool, nil
}
func (r *enterprise) ValidateOwner(job params.WorkflowJob) error {
if !strings.EqualFold(job.Enterprise.Slug, r.cfg.Name) {
func (e *enterprise) ValidateOwner(job params.WorkflowJob) error {
if !strings.EqualFold(job.Enterprise.Slug, e.cfg.Name) {
return runnerErrors.NewBadRequestError("job not meant for this pool manager")
}
return nil
}
func (r *enterprise) ID() string {
return r.id
func (e *enterprise) ID() string {
return e.id
}
func (r *enterprise) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
func (e *enterprise) InstallHook(_ context.Context, _ *github.Hook) (params.HookInfo, error) {
return params.HookInfo{}, fmt.Errorf("not implemented")
}
func (r *enterprise) UninstallHook(ctx context.Context, url string) error {
func (e *enterprise) UninstallHook(_ context.Context, _ string) error {
return fmt.Errorf("not implemented")
}
func (r *enterprise) GetHookInfo(ctx context.Context) (params.HookInfo, error) {
func (e *enterprise) GetHookInfo(_ context.Context) (params.HookInfo, error) {
return params.HookInfo{}, fmt.Errorf("not implemented")
}

View file

@ -17,11 +17,11 @@ package pool
import (
"context"
"github.com/google/go-github/v57/github"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/google/go-github/v57/github"
)
type poolHelper interface {

View file

@ -24,6 +24,9 @@ import (
"strings"
"sync"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
dbCommon "github.com/cloudbase/garm/database/common"
@ -31,9 +34,6 @@ import (
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/util"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
)
// test that we implement PoolManager
@ -89,7 +89,8 @@ type organization struct {
mux sync.Mutex
}
func (r *organization) findRunnerGroupByName(ctx context.Context, name string) (*github.RunnerGroup, error) {
func (o *organization) findRunnerGroupByName(name string) (*github.RunnerGroup, error) {
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): implement caching
opts := github.ListOrgRunnerGroupOptions{
ListOptions: github.ListOptions{
@ -102,7 +103,7 @@ func (r *organization) findRunnerGroupByName(ctx context.Context, name string) (
"ListOrganizationRunnerGroups", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
runnerGroups, ghResp, err := r.ghcli.ListOrganizationRunnerGroups(r.ctx, r.cfg.Name, &opts)
runnerGroups, ghResp, err := o.ghcli.ListOrganizationRunnerGroups(o.ctx, o.cfg.Name, &opts)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListOrganizationRunnerGroups", // label: operation
@ -127,10 +128,10 @@ func (r *organization) findRunnerGroupByName(ctx context.Context, name string) (
return nil, errors.Wrap(runnerErrors.ErrNotFound, "runner group not found")
}
func (r *organization) GetJITConfig(ctx context.Context, instance string, pool params.Pool, labels []string) (jitConfigMap map[string]string, runner *github.Runner, err error) {
func (o *organization) GetJITConfig(ctx context.Context, instance string, pool params.Pool, labels []string) (jitConfigMap map[string]string, runner *github.Runner, err error) {
var rg int64 = 1
if pool.GitHubRunnerGroup != "" {
runnerGroup, err := r.findRunnerGroupByName(ctx, pool.GitHubRunnerGroup)
runnerGroup, err := o.findRunnerGroupByName(pool.GitHubRunnerGroup)
if err != nil {
return nil, nil, fmt.Errorf("failed to find runner group: %w", err)
}
@ -141,6 +142,7 @@ func (r *organization) GetJITConfig(ctx context.Context, instance string, pool p
Name: instance,
RunnerGroupID: rg,
Labels: labels,
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): Should we make this configurable?
WorkFolder: github.String("_work"),
}
@ -148,7 +150,7 @@ func (r *organization) GetJITConfig(ctx context.Context, instance string, pool p
"GenerateOrgJITConfig", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
jitConfig, resp, err := r.ghcli.GenerateOrgJITConfig(ctx, r.cfg.Name, &req)
jitConfig, resp, err := o.ghcli.GenerateOrgJITConfig(ctx, o.cfg.Name, &req)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"GenerateOrgJITConfig", // label: operation
@ -167,7 +169,7 @@ func (r *organization) GetJITConfig(ctx context.Context, instance string, pool p
"RemoveOrganizationRunner", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
_, innerErr := r.ghcli.RemoveOrganizationRunner(r.ctx, r.cfg.Name, runner.GetID())
_, innerErr := o.ghcli.RemoveOrganizationRunner(o.ctx, o.cfg.Name, runner.GetID())
if innerErr != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"RemoveOrganizationRunner", // label: operation
@ -176,7 +178,7 @@ func (r *organization) GetJITConfig(ctx context.Context, instance string, pool p
}
slog.With(slog.Any("error", innerErr)).ErrorContext(
ctx, "failed to remove runner",
"runner_id", runner.GetID(), "organization", r.cfg.Name)
"runner_id", runner.GetID(), "organization", o.cfg.Name)
}
}()
@ -193,23 +195,23 @@ func (r *organization) GetJITConfig(ctx context.Context, instance string, pool p
return ret, runner, nil
}
func (r *organization) GithubCLI() common.GithubClient {
return r.ghcli
func (o *organization) GithubCLI() common.GithubClient {
return o.ghcli
}
func (o *organization) PoolType() params.PoolType {
return params.OrganizationPool
}
func (r *organization) GetRunnerInfoFromWorkflow(job params.WorkflowJob) (params.RunnerInfo, error) {
if err := r.ValidateOwner(job); err != nil {
func (o *organization) GetRunnerInfoFromWorkflow(job params.WorkflowJob) (params.RunnerInfo, error) {
if err := o.ValidateOwner(job); err != nil {
return params.RunnerInfo{}, errors.Wrap(err, "validating owner")
}
metrics.GithubOperationCount.WithLabelValues(
"GetWorkflowJobByID", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
workflow, ghResp, err := r.ghcli.GetWorkflowJobByID(r.ctx, job.Organization.Login, job.Repository.Name, job.WorkflowJob.ID)
workflow, ghResp, err := o.ghcli.GetWorkflowJobByID(o.ctx, job.Organization.Login, job.Repository.Name, job.WorkflowJob.ID)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"GetWorkflowJobByID", // label: operation
@ -230,28 +232,28 @@ func (r *organization) GetRunnerInfoFromWorkflow(job params.WorkflowJob) (params
return params.RunnerInfo{}, fmt.Errorf("failed to find runner name from workflow")
}
func (r *organization) UpdateState(param params.UpdatePoolStateParams) error {
r.mux.Lock()
defer r.mux.Unlock()
func (o *organization) UpdateState(param params.UpdatePoolStateParams) error {
o.mux.Lock()
defer o.mux.Unlock()
r.cfg.WebhookSecret = param.WebhookSecret
o.cfg.WebhookSecret = param.WebhookSecret
if param.InternalConfig != nil {
r.cfgInternal = *param.InternalConfig
o.cfgInternal = *param.InternalConfig
}
ghc, _, err := util.GithubClient(r.ctx, r.GetGithubToken(), r.cfgInternal.GithubCredentialsDetails)
ghc, _, err := util.GithubClient(o.ctx, o.GetGithubToken(), o.cfgInternal.GithubCredentialsDetails)
if err != nil {
return errors.Wrap(err, "getting github client")
}
r.ghcli = ghc
o.ghcli = ghc
return nil
}
func (r *organization) GetGithubToken() string {
return r.cfgInternal.OAuth2Token
func (o *organization) GetGithubToken() string {
return o.cfgInternal.OAuth2Token
}
func (r *organization) GetGithubRunners() ([]*github.Runner, error) {
func (o *organization) GetGithubRunners() ([]*github.Runner, error) {
opts := github.ListOptions{
PerPage: 100,
}
@ -262,7 +264,7 @@ func (r *organization) GetGithubRunners() ([]*github.Runner, error) {
"ListOrganizationRunners", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
runners, ghResp, err := r.ghcli.ListOrganizationRunners(r.ctx, r.cfg.Name, &opts)
runners, ghResp, err := o.ghcli.ListOrganizationRunners(o.ctx, o.cfg.Name, &opts)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListOrganizationRunners", // label: operation
@ -283,14 +285,14 @@ func (r *organization) GetGithubRunners() ([]*github.Runner, error) {
return allRunners, nil
}
func (r *organization) FetchTools() ([]commonParams.RunnerApplicationDownload, error) {
r.mux.Lock()
defer r.mux.Unlock()
func (o *organization) FetchTools() ([]commonParams.RunnerApplicationDownload, error) {
o.mux.Lock()
defer o.mux.Unlock()
metrics.GithubOperationCount.WithLabelValues(
"ListOrganizationRunnerApplicationDownloads", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
tools, ghResp, err := r.ghcli.ListOrganizationRunnerApplicationDownloads(r.ctx, r.cfg.Name)
tools, ghResp, err := o.ghcli.ListOrganizationRunnerApplicationDownloads(o.ctx, o.cfg.Name)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListOrganizationRunnerApplicationDownloads", // label: operation
@ -313,17 +315,17 @@ func (r *organization) FetchTools() ([]commonParams.RunnerApplicationDownload, e
return ret, nil
}
func (r *organization) FetchDbInstances() ([]params.Instance, error) {
return r.store.ListOrgInstances(r.ctx, r.id)
func (o *organization) FetchDbInstances() ([]params.Instance, error) {
return o.store.ListOrgInstances(o.ctx, o.id)
}
func (r *organization) RemoveGithubRunner(runnerID int64) (*github.Response, error) {
func (o *organization) RemoveGithubRunner(runnerID int64) (*github.Response, error) {
metrics.GithubOperationCount.WithLabelValues(
"RemoveRunner", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
ghResp, err := r.ghcli.RemoveOrganizationRunner(r.ctx, r.cfg.Name, runnerID)
ghResp, err := o.ghcli.RemoveOrganizationRunner(o.ctx, o.cfg.Name, runnerID)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"RemoveRunner", // label: operation
@ -335,29 +337,28 @@ func (r *organization) RemoveGithubRunner(runnerID int64) (*github.Response, err
return ghResp, nil
}
func (r *organization) ListPools() ([]params.Pool, error) {
pools, err := r.store.ListOrgPools(r.ctx, r.id)
func (o *organization) ListPools() ([]params.Pool, error) {
pools, err := o.store.ListOrgPools(o.ctx, o.id)
if err != nil {
return nil, errors.Wrap(err, "fetching pools")
}
return pools, nil
}
func (r *organization) GithubURL() string {
return fmt.Sprintf("%s/%s", r.cfgInternal.GithubCredentialsDetails.BaseURL, r.cfg.Name)
func (o *organization) GithubURL() string {
return fmt.Sprintf("%s/%s", o.cfgInternal.GithubCredentialsDetails.BaseURL, o.cfg.Name)
}
func (r *organization) JwtToken() string {
return r.cfgInternal.JWTSecret
func (o *organization) JwtToken() string {
return o.cfgInternal.JWTSecret
}
func (r *organization) GetGithubRegistrationToken() (string, error) {
func (o *organization) GetGithubRegistrationToken() (string, error) {
metrics.GithubOperationCount.WithLabelValues(
"CreateOrganizationRegistrationToken", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
tk, ghResp, err := r.ghcli.CreateOrganizationRegistrationToken(r.ctx, r.cfg.Name)
tk, ghResp, err := o.ghcli.CreateOrganizationRegistrationToken(o.ctx, o.cfg.Name)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"CreateOrganizationRegistrationToken", // label: operation
@ -372,42 +373,42 @@ func (r *organization) GetGithubRegistrationToken() (string, error) {
return *tk.Token, nil
}
func (r *organization) String() string {
return r.cfg.Name
func (o *organization) String() string {
return o.cfg.Name
}
func (r *organization) WebhookSecret() string {
return r.cfg.WebhookSecret
func (o *organization) WebhookSecret() string {
return o.cfg.WebhookSecret
}
func (r *organization) FindPoolByTags(labels []string) (params.Pool, error) {
pool, err := r.store.FindOrganizationPoolByTags(r.ctx, r.id, labels)
func (o *organization) FindPoolByTags(labels []string) (params.Pool, error) {
pool, err := o.store.FindOrganizationPoolByTags(o.ctx, o.id, labels)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching suitable pool")
}
return pool, nil
}
func (r *organization) GetPoolByID(poolID string) (params.Pool, error) {
pool, err := r.store.GetOrganizationPool(r.ctx, r.id, poolID)
func (o *organization) GetPoolByID(poolID string) (params.Pool, error) {
pool, err := o.store.GetOrganizationPool(o.ctx, o.id, poolID)
if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool")
}
return pool, nil
}
func (r *organization) ValidateOwner(job params.WorkflowJob) error {
if !strings.EqualFold(job.Organization.Login, r.cfg.Name) {
func (o *organization) ValidateOwner(job params.WorkflowJob) error {
if !strings.EqualFold(job.Organization.Login, o.cfg.Name) {
return runnerErrors.NewBadRequestError("job not meant for this pool manager")
}
return nil
}
func (r *organization) ID() string {
return r.id
func (o *organization) ID() string {
return o.id
}
func (r *organization) listHooks(ctx context.Context) ([]*github.Hook, error) {
func (o *organization) listHooks(ctx context.Context) ([]*github.Hook, error) {
opts := github.ListOptions{
PerPage: 100,
}
@ -417,7 +418,7 @@ func (r *organization) listHooks(ctx context.Context) ([]*github.Hook, error) {
"ListOrgHooks", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
hooks, ghResp, err := r.ghcli.ListOrgHooks(ctx, r.cfg.Name, &opts)
hooks, ghResp, err := o.ghcli.ListOrgHooks(ctx, o.cfg.Name, &opts)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"ListOrgHooks", // label: operation
@ -437,13 +438,13 @@ func (r *organization) listHooks(ctx context.Context) ([]*github.Hook, error) {
return allHooks, nil
}
func (r *organization) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
allHooks, err := r.listHooks(ctx)
func (o *organization) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
allHooks, err := o.listHooks(ctx)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "listing hooks")
}
if err := validateHookRequest(r.cfgInternal.ControllerID, r.cfgInternal.BaseWebhookURL, allHooks, req); err != nil {
if err := validateHookRequest(o.cfgInternal.ControllerID, o.cfgInternal.BaseWebhookURL, allHooks, req); err != nil {
return params.HookInfo{}, errors.Wrap(err, "validating hook request")
}
@ -452,7 +453,7 @@ func (r *organization) InstallHook(ctx context.Context, req *github.Hook) (param
metricsLabelOrganizationScope, // label: scope
).Inc()
hook, _, err := r.ghcli.CreateOrgHook(ctx, r.cfg.Name, req)
hook, _, err := o.ghcli.CreateOrgHook(ctx, o.cfg.Name, req)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"CreateOrgHook", // label: operation
@ -466,7 +467,7 @@ func (r *organization) InstallHook(ctx context.Context, req *github.Hook) (param
metricsLabelOrganizationScope, // label: scope
).Inc()
if _, err := r.ghcli.PingOrgHook(ctx, r.cfg.Name, hook.GetID()); err != nil {
if _, err := o.ghcli.PingOrgHook(ctx, o.cfg.Name, hook.GetID()); err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"PingOrgHook", // label: operation
metricsLabelOrganizationScope, // label: scope
@ -477,8 +478,8 @@ func (r *organization) InstallHook(ctx context.Context, req *github.Hook) (param
return hookToParamsHookInfo(hook), nil
}
func (r *organization) UninstallHook(ctx context.Context, url string) error {
allHooks, err := r.listHooks(ctx)
func (o *organization) UninstallHook(ctx context.Context, url string) error {
allHooks, err := o.listHooks(ctx)
if err != nil {
return errors.Wrap(err, "listing hooks")
}
@ -489,7 +490,7 @@ func (r *organization) UninstallHook(ctx context.Context, url string) error {
"DeleteOrgHook", // label: operation
metricsLabelOrganizationScope, // label: scope
).Inc()
_, err = r.ghcli.DeleteOrgHook(ctx, r.cfg.Name, hook.GetID())
_, err = o.ghcli.DeleteOrgHook(ctx, o.cfg.Name, hook.GetID())
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"DeleteOrgHook", // label: operation
@ -503,15 +504,15 @@ func (r *organization) UninstallHook(ctx context.Context, url string) error {
return nil
}
func (r *organization) GetHookInfo(ctx context.Context) (params.HookInfo, error) {
allHooks, err := r.listHooks(ctx)
func (o *organization) GetHookInfo(ctx context.Context) (params.HookInfo, error) {
allHooks, err := o.listHooks(ctx)
if err != nil {
return params.HookInfo{}, errors.Wrap(err, "listing hooks")
}
for _, hook := range allHooks {
hookInfo := hookToParamsHookInfo(hook)
if strings.EqualFold(hookInfo.URL, r.cfgInternal.ControllerWebhookURL) {
if strings.EqualFold(hookInfo.URL, o.cfgInternal.ControllerWebhookURL) {
return hookInfo, nil
}
}

View file

@ -25,19 +25,18 @@ import (
"sync"
"time"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/google/go-github/v57/github"
"github.com/google/uuid"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/auth"
dbCommon "github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/google/go-github/v57/github"
"github.com/google/uuid"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)
var (
@ -55,6 +54,8 @@ var (
const (
// maxCreateAttempts is the number of times we will attempt to create an instance
// before we give up.
//
// nolint:golangci-lint,godox
// TODO: make this configurable(?)
maxCreateAttempts = 5
@ -245,7 +246,7 @@ func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
return errors.Wrap(err, "updating runner")
}
// Set triggeredBy here so we break the lock on any potential queued job.
triggeredBy = jobIdFromLabels(instance.AditionalLabels)
triggeredBy = jobIDFromLabels(instance.AditionalLabels)
// A runner has picked up the job, and is now running it. It may need to be replaced if the pool has
// a minimum number of idle runners configured.
@ -262,14 +263,14 @@ func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
return nil
}
func jobIdFromLabels(labels []string) int64 {
func jobIDFromLabels(labels []string) int64 {
for _, lbl := range labels {
if strings.HasPrefix(lbl, jobLabelPrefix) {
jobId, err := strconv.ParseInt(lbl[len(jobLabelPrefix):], 10, 64)
jobID, err := strconv.ParseInt(lbl[len(jobLabelPrefix):], 10, 64)
if err != nil {
return 0
}
return jobId
return jobID
}
}
return 0
@ -413,7 +414,7 @@ func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runne
}
defer r.keyMux.Unlock(instance.Name, false)
switch commonParams.InstanceStatus(instance.Status) {
switch instance.Status {
case commonParams.InstancePendingCreate,
commonParams.InstancePendingDelete, commonParams.InstancePendingForceDelete:
// this instance is in the process of being created or is awaiting deletion.
@ -571,7 +572,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
continue
}
switch commonParams.InstanceStatus(dbInstance.Status) {
switch dbInstance.Status {
case commonParams.InstancePendingDelete, commonParams.InstanceDeleting:
// already marked for deletion or is in the process of being deleted.
// Let consolidate take care of it.
@ -645,7 +646,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
// Removed in the meantime?
if resp != nil && resp.StatusCode == http.StatusNotFound {
slog.DebugContext(
r.ctx, "runner dissapeared from github",
r.ctx, "runner disappeared from github",
"runner_name", dbInstance.Name)
} else {
return errors.Wrap(err, "removing runner from github")
@ -670,14 +671,14 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
r.ctx, "instance is online but github reports runner as offline",
"runner_name", dbInstance.Name)
return nil
} else {
slog.InfoContext(
r.ctx, "instance was found in stopped state; starting",
"runner_name", dbInstance.Name)
//start the instance
if err := provider.Start(r.ctx, dbInstance.ProviderID); err != nil {
return errors.Wrapf(err, "starting instance %s", dbInstance.ProviderID)
}
}
slog.InfoContext(
r.ctx, "instance was found in stopped state; starting",
"runner_name", dbInstance.Name)
if err := provider.Start(r.ctx, dbInstance.ProviderID); err != nil {
return errors.Wrapf(err, "starting instance %s", dbInstance.ProviderID)
}
return nil
})
@ -1144,6 +1145,7 @@ func (r *basePoolManager) scaleDownOnePool(ctx context.Context, pool params.Pool
// up by a runner, they are most likely stale and can be removed. For now, we can simply
// remove jobs older than 10 minutes.
//
// nolint:golangci-lint,godox
// TODO: should probably allow aditional filters to list functions. Would help to filter by date
// instead of returning a bunch of results and filtering manually.
queued, err := r.store.ListEntityJobsByStatus(r.ctx, r.helper.PoolType(), r.helper.ID(), params.JobStatusQueued)
@ -1196,7 +1198,6 @@ func (r *basePoolManager) ensureIdleRunnersForOnePool(pool params.Pool) error {
existingInstances, err := r.store.ListPoolInstances(r.ctx, pool.ID)
if err != nil {
return fmt.Errorf("failed to ensure minimum idle workers for pool %s: %w", pool.ID, err)
}
if uint(len(existingInstances)) >= pool.MaxRunners {
@ -1223,7 +1224,7 @@ func (r *basePoolManager) ensureIdleRunnersForOnePool(pool params.Pool) error {
if uint(projectedInstanceCount) > pool.MaxRunners {
// ensure we don't go above max workers
delta := projectedInstanceCount - int(pool.MaxRunners)
required = required - delta
required -= delta
}
}
@ -1278,6 +1279,7 @@ func (r *basePoolManager) retryFailedInstancesForOnePool(ctx context.Context, po
slog.DebugContext(
ctx, "attempting to clean up any previous instance",
"runner_name", instance.Name)
// nolint:golangci-lint,godox
// NOTE(gabriel-samfira): this is done in parallel. If there are many failed instances
// this has the potential to create many API requests to the target provider.
// TODO(gabriel-samfira): implement request throttling.
@ -1297,6 +1299,7 @@ func (r *basePoolManager) retryFailedInstancesForOnePool(ctx context.Context, po
slog.DebugContext(
ctx, "cleanup of previously failed instance complete",
"runner_name", instance.Name)
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): Incrementing CreateAttempt should be done within a transaction.
// It's fairly safe to do here (for now), as there should be no other code path that updates
// an instance in this state.
@ -1506,6 +1509,7 @@ func (r *basePoolManager) deletePendingInstances() error {
}
func (r *basePoolManager) addPendingInstances() error {
// nolint:golangci-lint,godox
// TODO: filter instances by status.
instances, err := r.helper.FetchDbInstances()
if err != nil {
@ -1772,6 +1776,7 @@ func (r *basePoolManager) consumeQueuedJobs() error {
// was spawned. Unlock it and try again. A different job may have picked up
// the runner.
if err := r.store.UnlockJob(r.ctx, job.ID, r.ID()); err != nil {
// nolint:golangci-lint,godox
// TODO: Implament a cache? Should we return here?
slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to unlock job",
@ -1781,6 +1786,7 @@ func (r *basePoolManager) consumeQueuedJobs() error {
}
if job.LockedBy.String() == r.ID() {
// nolint:golangci-lint,godox
// Job is locked by us. We must have already attepted to create a runner for it. Skip.
// TODO(gabriel-samfira): create an in-memory state of existing runners that we can easily
// check for existing pending or idle runners. If we can't find any, attempt to allocate another

View file

@ -24,6 +24,9 @@ import (
"strings"
"sync"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
dbCommon "github.com/cloudbase/garm/database/common"
@ -31,9 +34,6 @@ import (
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/util"
"github.com/google/go-github/v57/github"
"github.com/pkg/errors"
)
// test that we implement PoolManager
@ -91,12 +91,15 @@ type repository struct {
mux sync.Mutex
}
// nolint:golint,revive
// pool is used in enterprise and organzation
func (r *repository) GetJITConfig(ctx context.Context, instance string, pool params.Pool, labels []string) (jitConfigMap map[string]string, runner *github.Runner, err error) {
req := github.GenerateJITConfigRequest{
Name: instance,
// At the repository level we only have the default runner group.
RunnerGroupID: 1,
Labels: labels,
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): Should we make this configurable?
WorkFolder: github.String("_work"),
}
@ -314,7 +317,6 @@ func (r *repository) GetGithubRegistrationToken() (string, error) {
metricsLabelRepositoryScope, // label: scope
).Inc()
tk, ghResp, err := r.ghcli.CreateRegistrationToken(r.ctx, r.cfg.Owner, r.cfg.Name)
if err != nil {
metrics.GithubOperationFailedCount.WithLabelValues(
"CreateRegistrationToken", // label: operation

View file

@ -18,11 +18,11 @@ import (
"context"
"fmt"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params"
"github.com/pkg/errors"
)
func (r *Runner) ListAllPools(ctx context.Context) ([]params.Pool, error) {
@ -110,13 +110,14 @@ func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params
var newPool params.Pool
if pool.RepoID != "" {
switch {
case pool.RepoID != "":
newPool, err = r.store.UpdateRepositoryPool(ctx, pool.RepoID, poolID, param)
} else if pool.OrgID != "" {
case pool.OrgID != "":
newPool, err = r.store.UpdateOrganizationPool(ctx, pool.OrgID, poolID, param)
} else if pool.EnterpriseID != "" {
case pool.EnterpriseID != "":
newPool, err = r.store.UpdateEnterprisePool(ctx, pool.EnterpriseID, poolID, param)
} else {
default:
return params.Pool{}, fmt.Errorf("pool not found to a repo, org or enterprise")
}

View file

@ -19,6 +19,8 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/config"
@ -27,7 +29,6 @@ import (
garmTesting "github.com/cloudbase/garm/internal/testing"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/stretchr/testify/suite"
)
type PoolTestFixtures struct {
@ -207,7 +208,7 @@ func (s *PoolTestSuite) TestTestUpdatePoolByIDInvalidPoolID() {
func (s *PoolTestSuite) TestTestUpdatePoolByIDRunnerBootstrapTimeoutFailed() {
// this is already created in `SetupTest()`
var RunnerBootstrapTimeout uint = 0
var RunnerBootstrapTimeout uint // default is 0
s.Fixtures.UpdatePoolParams.RunnerBootstrapTimeout = &RunnerBootstrapTimeout
_, err := s.Runner.UpdatePoolByID(s.Fixtures.AdminContext, s.Fixtures.Pools[0].ID, s.Fixtures.UpdatePoolParams)

View file

@ -7,18 +7,16 @@ import (
"log/slog"
"os/exec"
"github.com/cloudbase/garm-provider-common/execution"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/pkg/errors"
garmErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/execution"
commonParams "github.com/cloudbase/garm-provider-common/params"
garmExec "github.com/cloudbase/garm-provider-common/util/exec"
"github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/metrics"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/pkg/errors"
)
var _ common.Provider = (*external)(nil)
@ -52,7 +50,7 @@ type external struct {
environmentVariables []string
}
func (e *external) validateResult(ctx context.Context, inst commonParams.ProviderInstance) error {
func (e *external) validateResult(inst commonParams.ProviderInstance) error {
if inst.ProviderID == "" {
return garmErrors.NewProviderError("missing provider ID")
}
@ -106,7 +104,7 @@ func (e *external) CreateInstance(ctx context.Context, bootstrapParams commonPar
return commonParams.ProviderInstance{}, garmErrors.NewProviderError("failed to decode response from binary: %s", err)
}
if err := e.validateResult(ctx, param); err != nil {
if err := e.validateResult(param); err != nil {
metrics.InstanceOperationFailedCount.WithLabelValues(
"CreateInstance", // label: operation
e.cfg.Name, // label: provider
@ -145,7 +143,6 @@ func (e *external) DeleteInstance(ctx context.Context, instance string) error {
).Inc()
return garmErrors.NewProviderError("provider binary %s returned error: %s", e.execPath, err)
}
}
return nil
}
@ -160,6 +157,7 @@ func (e *external) GetInstance(ctx context.Context, instance string) (commonPara
}
asEnv = append(asEnv, e.environmentVariables...)
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): handle error types. Of particular interest is to
// know when the error is ErrNotFound.
metrics.InstanceOperationCount.WithLabelValues(
@ -184,7 +182,7 @@ func (e *external) GetInstance(ctx context.Context, instance string) (commonPara
return commonParams.ProviderInstance{}, garmErrors.NewProviderError("failed to decode response from binary: %s", err)
}
if err := e.validateResult(ctx, param); err != nil {
if err := e.validateResult(param); err != nil {
metrics.InstanceOperationFailedCount.WithLabelValues(
"GetInstance", // label: operation
e.cfg.Name, // label: provider
@ -230,7 +228,7 @@ func (e *external) ListInstances(ctx context.Context, poolID string) ([]commonPa
ret := make([]commonParams.ProviderInstance, len(param))
for idx, inst := range param {
if err := e.validateResult(ctx, inst); err != nil {
if err := e.validateResult(inst); err != nil {
metrics.InstanceOperationFailedCount.WithLabelValues(
"ListInstances", // label: operation
e.cfg.Name, // label: provider
@ -268,7 +266,7 @@ func (e *external) RemoveAllInstances(ctx context.Context) error {
}
// Stop shuts down the instance.
func (e *external) Stop(ctx context.Context, instance string, force bool) error {
func (e *external) Stop(ctx context.Context, instance string) error {
asEnv := []string{
fmt.Sprintf("GARM_COMMAND=%s", execution.StopInstanceCommand),
fmt.Sprintf("GARM_CONTROLLER_ID=%s", e.controllerID),

View file

@ -18,12 +18,12 @@ import (
"context"
"log/slog"
"github.com/pkg/errors"
"github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/runner/providers/external"
"github.com/pkg/errors"
)
// LoadProvidersFromConfig loads all providers from the config and populates

View file

@ -20,13 +20,13 @@ import (
"log/slog"
"strings"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/util/appdefaults"
"github.com/pkg/errors"
)
func (r *Runner) CreateRepository(ctx context.Context, param params.CreateRepoParams) (repo params.Repository, err error) {
@ -143,12 +143,12 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
}
if len(pools) > 0 {
poolIds := []string{}
poolIDs := []string{}
for _, pool := range pools {
poolIds = append(poolIds, pool.ID)
poolIDs = append(poolIDs, pool.ID)
}
return runnerErrors.NewBadRequestError("repo has pools defined (%s)", strings.Join(poolIds, ", "))
return runnerErrors.NewBadRequestError("repo has pools defined (%s)", strings.Join(poolIDs, ", "))
}
if !keepWebhook && r.config.Default.EnableWebhookManagement {
@ -158,6 +158,7 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
}
if err := poolMgr.UninstallWebhook(ctx); err != nil {
// nolint:golangci-lint,godox
// TODO(gabriel-samfira): Should we error out here?
slog.With(slog.Any("error", err)).ErrorContext(
ctx, "failed to uninstall webhook",
@ -270,6 +271,7 @@ func (r *Runner) DeleteRepoPool(ctx context.Context, repoID, poolID string) erro
return errors.Wrap(err, "fetching instances")
}
// nolint:golangci-lint,godox
// TODO: implement a count function
if len(instances) > 0 {
runnerIDs := []string{}

View file

@ -19,6 +19,9 @@ import (
"fmt"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/config"
@ -29,9 +32,6 @@ import (
"github.com/cloudbase/garm/runner/common"
runnerCommonMocks "github.com/cloudbase/garm/runner/common/mocks"
runnerMocks "github.com/cloudbase/garm/runner/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)
type RepoTestFixtures struct {
@ -185,7 +185,7 @@ func (s *RepoTestSuite) TestCreateRepositoryEmptyParams() {
}
func (s *RepoTestSuite) TestCreateRepositoryMissingCredentials() {
s.Fixtures.CreateRepoParams.CredentialsName = "not-existent-creds-name"
s.Fixtures.CreateRepoParams.CredentialsName = notExistingCredentialsName
_, err := s.Runner.CreateRepository(s.Fixtures.AdminContext, s.Fixtures.CreateRepoParams)
@ -312,7 +312,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryErrUnauthorized() {
}
func (s *RepoTestSuite) TestUpdateRepositoryInvalidCreds() {
s.Fixtures.UpdateRepoParams.CredentialsName = "invalid-creds-name"
s.Fixtures.UpdateRepoParams.CredentialsName = invalidCredentialsName
_, err := s.Runner.UpdateRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, s.Fixtures.UpdateRepoParams)
@ -374,7 +374,7 @@ func (s *RepoTestSuite) TestCreateRepoPoolErrNotFound() {
}
func (s *RepoTestSuite) TestCreateRepoPoolFetchPoolParamsFailed() {
s.Fixtures.CreatePoolParams.ProviderName = "not-existent-provider-name"
s.Fixtures.CreatePoolParams.ProviderName = notExistingProviderName
s.Fixtures.PoolMgrCtrlMock.On("GetRepoPoolManager", mock.AnythingOfType("params.Repository")).Return(s.Fixtures.PoolMgrMock, nil)

View file

@ -17,7 +17,7 @@ package runner
import (
"context"
"crypto/hmac"
"crypto/sha1"
"crypto/sha1" //nolint:golangci-lint,gosec // sha1 is used for github webhooks
"crypto/sha256"
"encoding/hex"
"encoding/json"
@ -29,9 +29,14 @@ import (
"sync"
"time"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/google/uuid"
"github.com/juju/clock"
"github.com/juju/retry"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/config"
@ -40,21 +45,15 @@ import (
"github.com/cloudbase/garm/runner/common"
"github.com/cloudbase/garm/runner/pool"
"github.com/cloudbase/garm/runner/providers"
"golang.org/x/sync/errgroup"
"github.com/google/uuid"
"github.com/juju/clock"
"github.com/juju/retry"
"github.com/pkg/errors"
)
func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store) (*Runner, error) {
ctrlId, err := db.ControllerInfo()
ctrlID, err := db.ControllerInfo()
if err != nil {
return nil, errors.Wrap(err, "fetching controller info")
}
providers, err := providers.LoadProvidersFromConfig(ctx, cfg, ctrlId.ControllerID.String())
providers, err := providers.LoadProvidersFromConfig(ctx, cfg, ctrlID.ControllerID.String())
if err != nil {
return nil, errors.Wrap(err, "loading providers")
}
@ -66,7 +65,7 @@ func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store) (*Runn
}
poolManagerCtrl := &poolManagerCtrl{
controllerID: ctrlId.ControllerID.String(),
controllerID: ctrlID.ControllerID.String(),
config: cfg,
credentials: creds,
repositories: map[string]common.PoolManager{},
@ -80,7 +79,7 @@ func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store) (*Runn
poolManagerCtrl: poolManagerCtrl,
providers: providers,
credentials: creds,
controllerID: ctrlId.ControllerID,
controllerID: ctrlID.ControllerID,
}
if err := runner.loadReposOrgsAndEnterprises(); err != nil {
@ -118,7 +117,7 @@ func (p *poolManagerCtrl) CreateRepoPoolManager(ctx context.Context, repo params
return poolManager, nil
}
func (p *poolManagerCtrl) UpdateRepoPoolManager(ctx context.Context, repo params.Repository) (common.PoolManager, error) {
func (p *poolManagerCtrl) UpdateRepoPoolManager(_ context.Context, repo params.Repository) (common.PoolManager, error) {
p.mux.Lock()
defer p.mux.Unlock()
@ -184,7 +183,7 @@ func (p *poolManagerCtrl) CreateOrgPoolManager(ctx context.Context, org params.O
return poolManager, nil
}
func (p *poolManagerCtrl) UpdateOrgPoolManager(ctx context.Context, org params.Organization) (common.PoolManager, error) {
func (p *poolManagerCtrl) UpdateOrgPoolManager(_ context.Context, org params.Organization) (common.PoolManager, error) {
p.mux.Lock()
defer p.mux.Unlock()
@ -250,7 +249,7 @@ func (p *poolManagerCtrl) CreateEnterprisePoolManager(ctx context.Context, enter
return poolManager, nil
}
func (p *poolManagerCtrl) UpdateEnterprisePoolManager(ctx context.Context, enterprise params.Enterprise) (common.PoolManager, error) {
func (p *poolManagerCtrl) UpdateEnterprisePoolManager(_ context.Context, enterprise params.Enterprise) (common.PoolManager, error) {
p.mux.Lock()
defer p.mux.Unlock()
@ -627,34 +626,34 @@ func (r *Runner) Wait() error {
return errors.Wrap(err, "fetch enterprise pool managers")
}
for poolId, repo := range repos {
for poolID, repo := range repos {
wg.Add(1)
go func(id string, poolMgr common.PoolManager) {
defer wg.Done()
if err := poolMgr.Wait(); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(r.ctx, "timed out waiting for pool manager to exit", "pool_id", id, "pool_mgr_id", poolMgr.ID())
}
}(poolId, repo)
}(poolID, repo)
}
for poolId, org := range orgs {
for poolID, org := range orgs {
wg.Add(1)
go func(id string, poolMgr common.PoolManager) {
defer wg.Done()
if err := poolMgr.Wait(); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(r.ctx, "timed out waiting for pool manager to exit", "pool_id", id)
}
}(poolId, org)
}(poolID, org)
}
for poolId, enterprise := range enterprises {
for poolID, enterprise := range enterprises {
wg.Add(1)
go func(id string, poolMgr common.PoolManager) {
defer wg.Done()
if err := poolMgr.Wait(); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(r.ctx, "timed out waiting for pool manager to exit", "pool_id", id)
}
}(poolId, enterprise)
}(poolID, enterprise)
}
wg.Wait()
@ -904,7 +903,8 @@ func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params
var poolMgr common.PoolManager
if pool.RepoID != "" {
switch {
case pool.RepoID != "":
repo, err := r.store.GetRepositoryByID(ctx, pool.RepoID)
if err != nil {
return nil, errors.Wrap(err, "fetching repo")
@ -913,7 +913,7 @@ func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params
if err != nil {
return nil, errors.Wrapf(err, "fetching pool manager for repo %s", pool.RepoName)
}
} else if pool.OrgID != "" {
case pool.OrgID != "":
org, err := r.store.GetOrganizationByID(ctx, pool.OrgID)
if err != nil {
return nil, errors.Wrap(err, "fetching org")
@ -922,7 +922,7 @@ func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params
if err != nil {
return nil, errors.Wrapf(err, "fetching pool manager for org %s", pool.OrgName)
}
} else if pool.EnterpriseID != "" {
case pool.EnterpriseID != "":
enterprise, err := r.store.GetEnterpriseByID(ctx, pool.EnterpriseID)
if err != nil {
return nil, errors.Wrap(err, "fetching enterprise")

View file

@ -4,10 +4,11 @@ import (
"log/slog"
"net/url"
"github.com/cloudbase/garm/client"
"github.com/cloudbase/garm/params"
"github.com/go-openapi/runtime"
openapiRuntimeClient "github.com/go-openapi/runtime/client"
"github.com/cloudbase/garm/client"
"github.com/cloudbase/garm/params"
)
var (
@ -16,18 +17,18 @@ var (
)
func InitClient(baseURL string) {
garmUrl, err := url.Parse(baseURL)
garmURL, err := url.Parse(baseURL)
if err != nil {
panic(err)
}
apiPath, err := url.JoinPath(garmUrl.Path, client.DefaultBasePath)
apiPath, err := url.JoinPath(garmURL.Path, client.DefaultBasePath)
if err != nil {
panic(err)
}
transportCfg := client.DefaultTransportConfig().
WithHost(garmUrl.Host).
WithHost(garmURL.Host).
WithBasePath(apiPath).
WithSchemes([]string{garmUrl.Scheme})
WithSchemes([]string{garmURL.Scheme})
cli = client.NewHTTPClientWithConfig(nil, transportCfg)
}

View file

@ -1,6 +1,8 @@
package e2e
import (
"github.com/go-openapi/runtime"
"github.com/cloudbase/garm/client"
clientControllerInfo "github.com/cloudbase/garm/client/controller_info"
clientCredentials "github.com/cloudbase/garm/client/credentials"
@ -14,7 +16,6 @@ import (
clientProviders "github.com/cloudbase/garm/client/providers"
clientRepositories "github.com/cloudbase/garm/client/repositories"
"github.com/cloudbase/garm/params"
"github.com/go-openapi/runtime"
)
// ///////////

View file

@ -44,7 +44,7 @@ func GetControllerInfo() *params.ControllerInfo {
if err := appendCtrlInfoToGitHubEnv(&controllerInfo); err != nil {
panic(err)
}
if err := printJsonResponse(controllerInfo); err != nil {
if err := printJSONResponse(controllerInfo); err != nil {
panic(err)
}
return &controllerInfo

View file

@ -10,7 +10,7 @@ import (
)
func waitInstanceStatus(name string, status commonParams.InstanceStatus, runnerStatus params.RunnerStatus, timeout time.Duration) (*params.Instance, error) {
var timeWaited time.Duration = 0
var timeWaited time.Duration // default is 0
var instance *params.Instance
slog.Info("Waiting for instance to reach desired status", "instance", name, "desired_status", status, "desired_runner_status", runnerStatus)
@ -27,7 +27,7 @@ func waitInstanceStatus(name string, status commonParams.InstanceStatus, runnerS
timeWaited += 5 * time.Second
}
if err := printJsonResponse(*instance); err != nil {
if err := printJSONResponse(*instance); err != nil {
return nil, err
}
return nil, fmt.Errorf("timeout waiting for instance %s status to reach status %s and runner status %s", name, status, runnerStatus)
@ -41,7 +41,7 @@ func DeleteInstance(name string, forceRemove bool) {
}
func WaitInstanceToBeRemoved(name string, timeout time.Duration) error {
var timeWaited time.Duration = 0
var timeWaited time.Duration // default is 0
var instance *params.Instance
slog.Info("Waiting for instance to be removed", "instance_name", name)
@ -52,9 +52,9 @@ func WaitInstanceToBeRemoved(name string, timeout time.Duration) error {
}
instance = nil
for _, i := range instances {
if i.Name == name {
instance = &i
for k, v := range instances {
if v.Name == name {
instance = &instances[k]
break
}
}
@ -68,14 +68,14 @@ func WaitInstanceToBeRemoved(name string, timeout time.Duration) error {
timeWaited += 5 * time.Second
}
if err := printJsonResponse(*instance); err != nil {
if err := printJSONResponse(*instance); err != nil {
return err
}
return fmt.Errorf("instance %s was not removed within the timeout", name)
}
func WaitPoolInstances(poolID string, status commonParams.InstanceStatus, runnerStatus params.RunnerStatus, timeout time.Duration) error {
var timeWaited time.Duration = 0
var timeWaited time.Duration // default is 0
pool, err := getPool(cli, authToken, poolID)
if err != nil {
@ -103,7 +103,7 @@ func WaitPoolInstances(poolID string, status commonParams.InstanceStatus, runner
"runner_status", runnerStatus,
"desired_instance_count", instancesCount,
"pool_instance_count", len(poolInstances))
if instancesCount == int(pool.MinIdleRunners) && instancesCount == len(poolInstances) {
if int(pool.MinIdleRunners) == len(poolInstances) {
return nil
}
time.Sleep(5 * time.Second)

View file

@ -54,7 +54,7 @@ func ValidateJobLifecycle(label string) {
}
func waitLabelledJob(label string, timeout time.Duration) (*params.Job, error) {
var timeWaited time.Duration = 0
var timeWaited time.Duration // default is 0
var jobs params.Jobs
var err error
@ -75,14 +75,14 @@ func waitLabelledJob(label string, timeout time.Duration) (*params.Job, error) {
timeWaited += 5 * time.Second
}
if err := printJsonResponse(jobs); err != nil {
if err := printJSONResponse(jobs); err != nil {
return nil, err
}
return nil, fmt.Errorf("failed to wait job with label %s", label)
}
func waitJobStatus(id int64, status params.JobStatus, timeout time.Duration) (*params.Job, error) {
var timeWaited time.Duration = 0
var timeWaited time.Duration // default is 0
var job *params.Job
slog.Info("Waiting for job to reach status", "job_id", id, "status", status)
@ -93,9 +93,9 @@ func waitJobStatus(id int64, status params.JobStatus, timeout time.Duration) (*p
}
job = nil
for _, j := range jobs {
if j.ID == id {
job = &j
for k, v := range jobs {
if v.ID == id {
job = &jobs[k]
break
}
}
@ -116,7 +116,7 @@ func waitJobStatus(id int64, status params.JobStatus, timeout time.Duration) (*p
timeWaited += 5 * time.Second
}
if err := printJsonResponse(*job); err != nil {
if err := printJSONResponse(*job); err != nil {
return nil, err
}
return nil, fmt.Errorf("timeout waiting for job %d to reach status %s", id, status)

View file

@ -116,7 +116,7 @@ func dumpOrgInstancesDetails(orgID string) error {
if err != nil {
return err
}
if err := printJsonResponse(org); err != nil {
if err := printJSONResponse(org); err != nil {
return err
}
@ -132,7 +132,7 @@ func dumpOrgInstancesDetails(orgID string) error {
return err
}
slog.Info("Instance info", "instance_name", instance.Name)
if err := printJsonResponse(instance); err != nil {
if err := printJSONResponse(instance); err != nil {
return err
}
}

View file

@ -9,7 +9,7 @@ import (
)
func waitPoolNoInstances(id string, timeout time.Duration) error {
var timeWaited time.Duration = 0
var timeWaited time.Duration // default is 0
var pool *params.Pool
var err error
@ -37,7 +37,7 @@ func dumpPoolInstancesDetails(poolID string) error {
if err != nil {
return err
}
if err := printJsonResponse(pool); err != nil {
if err := printJSONResponse(pool); err != nil {
return err
}
for _, instance := range pool.Instances {
@ -46,7 +46,7 @@ func dumpPoolInstancesDetails(poolID string) error {
return err
}
slog.Info("Instance details", "instance_name", instance.Name)
if err := printJsonResponse(instanceDetails); err != nil {
if err := printJSONResponse(instanceDetails); err != nil {
return err
}
}

Some files were not shown because too many files have changed in this diff Show more