Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move github credentials to the database #243

Merged
merged 27 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
90870c1
Use database for github creds
gabriel-samfira Apr 15, 2024
032d40f
Fix tests
gabriel-samfira Apr 16, 2024
3e60a48
Preload credentials endpoint and remove extra code
gabriel-samfira Apr 17, 2024
9c1ffe8
Enforce same endpoint when updating credentials
gabriel-samfira Apr 17, 2024
4610f83
List credentials from db
gabriel-samfira Apr 17, 2024
257fb0b
Take into account legacy config
gabriel-samfira Apr 17, 2024
77ecb16
Add github endpoint API endpoint and CLI code
gabriel-samfira Apr 18, 2024
eadbe78
Add github credentials API and cli code
gabriel-samfira Apr 19, 2024
208a4ee
Ensure github endpoint
gabriel-samfira Apr 19, 2024
eb14564
Deny deleting the default github.com endpoint
gabriel-samfira Apr 19, 2024
e8ea711
Fix tests post-rebase
gabriel-samfira Apr 22, 2024
8b5584f
Add some e2e boilerplate
gabriel-samfira Apr 24, 2024
f5682e6
Work around actions/runner-images#7210
gabriel-samfira Apr 24, 2024
c2b974d
Create clone creds for repo update
gabriel-samfira Apr 24, 2024
1256473
Fetch credentials from DB
gabriel-samfira Apr 24, 2024
ccf5105
Add github endpoint operations e2e test
gabriel-samfira Apr 24, 2024
39a5e14
Add more e2e GH endpoint tests
gabriel-samfira Apr 25, 2024
0128f59
Add some credentials e2e tests
gabriel-samfira Apr 25, 2024
87943db
Fix lint and add integration tests logging
gabriel-samfira Apr 27, 2024
349ba1f
Fix nil pointer dereference
gabriel-samfira Apr 27, 2024
402c8b7
Use different creds than the default ones
gabriel-samfira Apr 27, 2024
2b1414d
Add some unit tests
gabriel-samfira Apr 28, 2024
2a3d524
Add more unit tests
gabriel-samfira Apr 29, 2024
8726cb9
Move the name check before tx
gabriel-samfira May 7, 2024
75eb45c
Update database/sql/sql.go
gabriel-samfira May 7, 2024
27e74ef
Add DB migration test
gabriel-samfira May 7, 2024
b3e2c58
Update docs
gabriel-samfira May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Golang
uses: actions/setup-go@v3
Expand All @@ -20,7 +20,9 @@ jobs:
uses: canonical/setup-lxd@v0.1.1

- name: Install dependencies
run: sudo apt-get -qq update && sudo apt-get -qq install -y apg coreutils make
run: |
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
sudo apt-get -qq update && sudo apt-get -qq install -y apg coreutils make

- name: Set up ngrok
id: ngrok
Expand All @@ -43,6 +45,7 @@ jobs:
echo "GARM_PASSWORD=$GARM_PASSWORD" >> $GITHUB_ENV
echo "REPO_WEBHOOK_SECRET=$REPO_WEBHOOK_SECRET" >> $GITHUB_ENV
echo "ORG_WEBHOOK_SECRET=$ORG_WEBHOOK_SECRET" >> $GITHUB_ENV
echo "GARM_CHECKOUT_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV

- name: Create logs directory
if: always()
Expand All @@ -52,7 +55,7 @@ jobs:
run: |
set -o pipefail
set -o errexit
make integration 2>&1 | tee /artifacts-logs/e2e.log
make integration 2>&1
env:
GARM_BASE_URL: ${{ steps.ngrok.outputs.tunnel-url }}
ORG_NAME: gsamfira
Expand All @@ -66,6 +69,7 @@ jobs:
run: |
sudo systemctl status garm@runner || true
sudo journalctl --no-pager 2>&1 > /artifacts-logs/system.log
sudo journalctl -u garm@runner --no-pager 2>&1 > /artifacts-logs/garm.log

- name: Upload GARM and e2e logs
if: always()
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export SHELLOPTS:=$(if $(SHELLOPTS),$(SHELLOPTS):)pipefail:errexit

.ONESHELL:

GEN_PASSWORD=$(shell (apg -n1 -m32))
GEN_PASSWORD=$(shell (/usr/bin/apg -n1 -m32))
IMAGE_TAG = garm-build

USER_ID=$(shell ((docker --version | grep -q podman) && echo "0" || id -u))
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ The ```GARM``` configuration is a simple ```toml```. The sample config file in [
* [The default section](/doc/config_default.md)
* [Logging](/doc/config_logging.md)
* [Database](/doc/database.md)
* [Github credentials](/doc/github_credentials.md)
* [Providers](/doc/providers.md)
* [Metrics](/doc/config_metrics.md)
* [JWT authentication](/doc/config_jwt_auth.md)
Expand Down
21 changes: 0 additions & 21 deletions apiserver/controllers/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,27 +329,6 @@ func (a *APIController) FirstRunHandler(w http.ResponseWriter, r *http.Request)
}
}

// swagger:route GET /credentials credentials ListCredentials
//
// List all credentials.
//
// Responses:
// 200: Credentials
// 400: APIErrorResponse
func (a *APIController) ListCredentials(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
creds, err := a.r.ListCredentials(ctx)
if err != nil {
handleError(ctx, w, err)
return
}

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(creds); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

// swagger:route GET /providers providers ListProviders
//
// List all providers.
Expand Down
229 changes: 229 additions & 0 deletions apiserver/controllers/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package controllers

import (
"encoding/json"
"log/slog"
"math"
"net/http"
"strconv"

"github.com/gorilla/mux"

gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params"
)

// swagger:route GET /credentials credentials ListCredentials
// swagger:route GET /github/credentials credentials ListCredentials
//
// List all credentials.
//
// Responses:
// 200: Credentials
// 400: APIErrorResponse
func (a *APIController) ListCredentials(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
creds, err := a.r.ListCredentials(ctx)
if err != nil {
handleError(ctx, w, err)
return
}

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(creds); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

// swagger:route POST /github/credentials credentials CreateCredentials
//
// Create a GitHub credential.
//
// Parameters:
// + name: Body
// description: Parameters used when creating a GitHub credential.
// type: CreateGithubCredentialsParams
// in: body
// required: true
//
// Responses:
// 200: GithubCredentials
// 400: APIErrorResponse
func (a *APIController) CreateGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

var params params.CreateGithubCredentialsParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

cred, err := a.r.CreateGithubCredentials(ctx, params)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to create GitHub credential")
handleError(ctx, w, err)
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

// swagger:route GET /github/credentials/{id} credentials GetCredentials
//
// Get a GitHub credential.
//
// Parameters:
// + name: id
// description: ID of the GitHub credential.
// type: integer
// in: path
// required: true
//
// Responses:
// 200: GithubCredentials
// 400: APIErrorResponse
func (a *APIController) GetGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

cred, err := a.r.GetGithubCredentials(ctx, uint(id))
Fixed Show fixed Hide fixed
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get GitHub credential")
handleError(ctx, w, err)
return
}

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}

// swagger:route DELETE /github/credentials/{id} credentials DeleteCredentials
//
// Delete a GitHub credential.
//
// Parameters:
// + name: id
// description: ID of the GitHub credential.
// type: integer
// in: path
// required: true
//
// Responses:
// default: APIErrorResponse
func (a *APIController) DeleteGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

if err := a.r.DeleteGithubCredentials(ctx, uint(id)); err != nil {
Fixed Show fixed Hide fixed
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete GitHub credential")
handleError(ctx, w, err)
return
}

w.WriteHeader(http.StatusNoContent)
}

// swagger:route PUT /github/credentials/{id} credentials UpdateCredentials
//
// Update a GitHub credential.
//
// Parameters:
// + name: id
// description: ID of the GitHub credential.
// type: integer
// in: path
// required: true
// + name: Body
// description: Parameters used when updating a GitHub credential.
// type: UpdateGithubCredentialsParams
// in: body
// required: true
//
// Responses:
// 200: GithubCredentials
// 400: APIErrorResponse
func (a *APIController) UpdateGithubCredential(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
idParam, ok := vars["id"]
if !ok {
slog.ErrorContext(ctx, "missing id in request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

id, err := strconv.ParseUint(idParam, 10, 64)
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to parse id")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

if id > math.MaxUint {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "id is too large")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

var params params.UpdateGithubCredentialsParams
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
handleError(ctx, w, gErrors.ErrBadRequest)
return
}

cred, err := a.r.UpdateGithubCredentials(ctx, uint(id), params)
Fixed Show fixed Hide fixed
if err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to update GitHub credential")
handleError(ctx, w, err)
return
}

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(cred); err != nil {
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
}
}
Loading
Loading